TensorFlow
実務では、numpyから作成するのではなく、Tensorflowなどのライブラリを用いて作成するのが一般的。
Tendorflowでは、numpyとは異なった書き方になるので注意が必要。
・インポートはnumpyと同様。
・定数の定義はtr.constant()を用いる。constant(数字, データ型, 配列形状)の順に定義する。
aでは数字1のみ定義、bでは、数字2でfloat型の3×2の配列、cでは、数字は連番(0~4)でfloat型の2×2の配列と定義している。
・Tensorflowでは、Tensorを用いており、Tensorを動作させるには、tr.Session()を定義してあげる必要がある。
そのため、tr,Session()を定義する前のprint()では、Tensorが動作しておらず、Tensorと表示されている。
tr.Session()を定義した後、sess.run(a)で動作していることがわかる。
次に、placeholderについて確認する。
placeholderは、後々に値を入れることができる箱のようなものを定義しているイメージ。
tf.placeholder()で定義する。
今回はtf.placeholder((dtype=tf.float32, shape=[None,3])と定義。
定数と同様に、Sessionを定義していないとTensorが動作していない。
X=np.random.rand(2,3)でランダムな2×3の配列を定義。
sess.run()でTensorを動作させる。
sess.run(x,feed_dect={x:X[0].reshape(1, -1)})
feed_dictでxにX[0]つまり、Xの配列の0番目を代入する。
.reshapr(1,-1)は、配列の形状を1×3に変形させている。
placeholderの定義では、shape=[None, 3]で〇×3で定義している。
それをreshape(1,-1)で〇の部分を1にしており、-1は定義している3を用いるという意味のため1×3の配列となる。
結果を確認すると、Xの0番目の配列が代入され、1×3の配列になっていることを確認。
placeholderは、学習時に、バッチごとに代入するときなどに使用される。
次に、variablesについて確認する。
variablesは、変数のイメージ。
tf.variables()で定義する。上記では、最初に1と定義している。
変数は、更新により値が変化していく。
更新式は、calc_op = x * a (変数×定数)
値の更新はtf.assign()を用いる。tf.assign(x, calc_op)は、
xをcalc_opの値に更新する処理。
変数を用いる際は、初めに変数を初期化(初期値に書き直す)する必要がある。
tf.global_variables_initializer()は変数を初期化するメソッド。
1回目のprint(sess.run(x))では、初期値の1であり、2回目はprint(sess.run(x))ではupdate_xにより、10に更新している。
3回目のprint(sess.run(x))では、update_xで2回目のx(10)と定数10の乗算の100に更新している。
線形回帰
線形回帰について確認する。
インポートに関しては、上記と同様。グラフ表示するために追加でmatplotlib.pyplotも実施。
iters_numで学習回数、plot_intervalで何学習ごとに誤差を表示するかを設定している。
次にデータの生成。xは、ランダムな数np.random.readn(n)で作成。個数はnつまり、100個のランダムな数を生成する。その数字を3*x+2の式に代入し、dを生成している。
このdは、3*x+2の直線上にしか存在しないので、わざとnoiseを加味して、直線上から上下に移動させる。
xを入力データ、dを出力データとして学習を行っていく。
ここまでは、numpyで生成する方法と大差ない。
入力データと出力データは、placeholderを用いる。
重みW・バイアスbはvariableで定義し、学習式をy=W*xt+bでこの重みWとバイアスbを学習で求める。
誤差は、平均2乗誤差で算出する。
tf.square()で2乗、tf.reduce_mean()で平均を算出する。
tf.tf.train.GradientDescentOptimizer()で学習率を定義し、
optimizer.minimize(loss)で誤差を最小を算出している。
学習の準備は以上となり、変数の初期化とSessionを開始する。
学習はfor文を用いて実施。iter_num=300なので300回学習を実施。
sess.runでtrainを呼び出し、xtにx_train、dtにd_trainを代入し、plot_interval時にプロットを行うfor文である。
結果を確認すると、W=3.07、d=1.94とd=3*x+2に近い値になっており、正しい予測ができていることがわかる。
[try]
①noiseの値を変更。
上記の演習のnoise値の倍0.6に変更し実施。
上記が変更箇所。
結果をみると、noise値が大きくなったことで、上下のばらつきが広がっている。それにより、予測結果もnoise値0.3時より精度が悪い結果になっていることを確認した。
②dの値を変更。
(1)Wを6に変更。
上記が変更箇所。
結果
(2)dを4に変更
上記が変更箇所。
結果
(1),(2)の結果共にdの式に近い予測ができていることを確認した。
y式とd式の形は同じで誤差であるnoise値を変更していないため、
演習と近い結果になったと考えられる。
①②より、上手に予測するためにはデータのnoise値を意識する必要がある。
非線形回帰
インポートやデータの生成は線形回帰と同様。
非線形としてdの式が線形回帰時と異なる。
d式より今回重みパラメータの数は4個なので、
W = tf.Variable(tf.random_normal([4, 1], stddev=0.01))
で4個の数を定義している。stddev=0.01は標準偏差0.01を表し、標準偏差0.01のランダムな初期値を定義している。
xtはxの3乗、2乗、1乗、0乗として4つの値を持つため、4つのplaceholder、dは解1個なので1つのplaceholderを用意している。
式はy = tf.matmul(xt,W)でy = tf.matmul()は乗算を行うメソッド。
学習の流れは、線形回帰と同様にxt,dtにx_train,d_trainを代入していくようになっている。
結果はw1=-0.4,w2=1.59,W3=-2.80,w4=0.99とd式に近い予測になっていることがわかる。
[try]
①noise値を変更。
noise値を演習の10倍である0.5に変更
上記が変更箇所。
結果
線形回帰と同様にnoise値が大きくなることで上下のばらつきが広がっている。
②dの値を変更
演習時よりWを適当な値に変更。
上記が変更箇所。
結果
結果より、線形回帰と同様にWの値を変えても、noise値が小さいと正しく予測できていることが確認できた。
演習問題
上記が作成したプログラムで結果予測はできているが、データの生成時にx = np.random.rand(n)のため、0から1の範囲でしか点をとらないため一部のみ点プロットされたグラフになっている。
mnist
補填部分について
x = tf.placeholder(tf.float32, [None, 784])
784はデータセットが28×28=784であるため。
d = tf.placeholder(tf.float32, [None, 10])
分類は0から9の10種の分類のため。
W = tf.Variable(tf.random_normal([784, 10], stddev=0.01))
Wは784の数値から10個の値を出すので784×10のシェイプ。初期値は標準偏差0.01
b = tf.Variable(tf.zeros([10]))
10個の出力のため。
y = tf.nn.softmax(tf.matmul(x, W) + b)
xとWの乗算にbを足した値をソフトマックス関数に代入。
誤差は分類のためクロスエントロピーを用いて算出している。
for文内のx_batch, d_batchでmnistのtrainデータのバッチが代入される。
mnistの学習100回で精度約87%まで上がっていくことが確認できる。
上記で、d_batdhの0番目のデータとx_batdhの大きさ、画像の確認を実施。
3層の分類でmnistを実施。
1層時よりも精度向上を目指すことが目的。
3層構造なので隠れ層を2つ(hidden_layer_size_1=600,hidden_layer_size_2=300)を用意。
これにより、784の入力から隠れ層1 600個 隠れ層2 300を通して10の出力を行うニューラルネットワークが作成される。
隠れ層を含む3層の構造なので重みWとバイアスbも3つずつ用意が必要。
層を進むことでデータ数が変化するためWはせれに合わせてshapeで形を変えさせる必要がある。
結果は、精度約90%と1層時よりも精度向上していることが確認できる。
[try]
①隠れ層のサイズ変更
hidden_layer_size_1=400,hidden_layer_size_2=150に変更。
上記が変更箇所。
結果
隠れ層数が演習時より減少しているので、精度が下がっていることが確認できた。
隠れ層数と計算時間(精度)はトレードオフの関係なので都度調整が必要。
②optimizerを変更。
下記の4種類のoptimizerに変更及び3000回学習後の精度を下記の図にまとめた。
学習3000回の精度では、RMSPropOptimizerが一番精度が良い結果となった。
実務で比較するときは精度が頭打ちするまで学習を行い、比較を行う。
CNNの流れは、
conv - relu - pool - conv - relu - pool -
affin - relu - dropout - affin - softmaxの順に行う。
インポート及び、学習回数の定義は上記と同様。
MNISTのデータをplaceholderにxとして代入する。
そのXを28×28×1チャンネルの画像形式に変更しx_imageに代入。
W_conb1の5×5×1×32のウエイトの5×5は、CNNのフィルタサイズで、
1×32は、1チャンネルを32チャンネルに拡張する意味を持つ。
計算は、h_conv1 = tf.nn.relu(tf.nn.conv2d(x_image, W_conv1, strides=[1, 1, 1, 1], padding='SAME') + b_conv1)が行っている。
tf.nn.conv2d()で、x_imageでW_conv1で畳み込み演算を、ストライドは1でパディングはSAME(同じ)変わらないような設定をしている。その後バイアスb_conv1を加算し、ReLU関数に代入する。その出力を、
h_pool1 = tf.nn.max_pool(h_conv1, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')で
max_poolでksizeとストライド2×2のサイズで、パディングは同じに演算する。
2,3層目も同様な計算を行っている。その後、affin - relu - dropout - affin - softmax演算を行うことでCNN計算ができる。
精度は学習回数が増えるとともに精度が上がり約90%以上の精度があることを確認。
[try]
①ドロップアウト率を0に変更。
上記が変更箇所。
結果
結果から、約95%程度であり、ほぼ演習と同等の結果となった。
Keras演習
線形回帰
結果はTensorflow同様に線形回帰できている。コードは、Kerasの方がシンプルに書かれている。
Kerasの特徴
Tensorflowと異なり、W(重み)やb(バイアス)をplaceholderやVariablesを用いなくてもよい。
入力xや学習式dはTensorflowと同様に定義する。
次に、ノルムSequential()を用意。これが線形回帰モデルのベースとなる。Dense(全結合層)ネットワークを生成することになる。
これによって1層のネットワークが出来る。
model.summary()はモデルを表示する部分で上記の演習キャプチャ2枚目のようにサマリが表示される。
これを確認すると、1層のDence全結合ネットワークでoutput_Shape1パラメータの数2ということが確認できる。
モデルは、model.compile()で定義するだけで学習が可能。
Tensorflowでは、iossやoptimizerを定義する必要があった。
今回はmodel.compile(loss='mse', optimizer='sgd')
lossは、二乗誤差、optimizerは、隠れ付き勾配降下法を用いている。
単純パーセプトロン
上記の線形回帰と見比べると学習コード異なる部分。線形回帰ではfor文を用いていたが、今回はmodel.fit()を用いて学習を実施。
model.fit()では、epochsで学習回数を定義できる。
model.fit(X, T, epochs=30, model.fit(X, T, epochs=30, batch_size=1))は、学習回数30回、batch_size=1より、データ数4個なので30×4で120回のバッチのトレーニングを行う。
コードを動作させると、サマリが表示され、学習回数が増えるにつれ精度が上がっていることがわかる。
[try]
①np.random.seed(0)をnp.random.seed(1)に変更
上記が変更箇所。
結果
np.random.seed(0)から1に変更することで初期値が変化するので結果が上記の演習と異なっていることを確認。
②エポック数を100に変更
上記が変更箇所。
結果
バッチのトレーニング回数が演習の120回から100×4の400回に増加しているので誤差が小さく収束している結果となった。
③AND回路, XOR回路に変更
[1]AND回路
上記が変更箇所。
結果
AND回路もうまく学習できていることがわかる。
結果
XOR回路(排他的論理和)は層の全結合ネットワークでは線形しか表現できない。線形で表すことができない回路(直線で0,1を分けることができない)のため、誤差が生じてしまうことを確認した。
④OR回路にしてバッチサイズを10に変更
上記が変更箇所。
結果
バッチサイズが10に増加したことで、学習回数が減少するので、演習のときの計算時間2msより早くなっていることがわかる。
このようにバッチサイズを増やすことで1エポックにおける学習回数を減らすことができる。一般的にバッチサイズは2の倍数を用いる。
また、データ数が少ないとバッチサイズも小さく、データ数が多いとバッチサイズを大きくする。
⑤エポック数を300に変更しよう
上記が変更箇所。
結果
これは、②と同様でバッチのトレーニング回数が増えるので誤差が小さく収束している。
irisの分類
train_test_splitはデータを学習用データと検証用データに分類する。train_test_split(x, d, test_size=0.2)で検証用データ20%と設定しているので学習用データと検証用データは4:1の割合で分けられる。
モデルは上記と同様に定義している。入力層サイズ4、中間層サイズ12でReLU関数を通して、マトリックスサイズ3のソフトマックス関数を通す2層のニューラルネットワーク。
lossはsparse_categorical_crossentropyこれは、ターゲットが0,1,2に分かれているため。one_hotの形だとcategorical_entropyなどを用いる。
結果を確認すると、学習をこなすと、精度があがり、学習用データも検証用データでも同様なグラフの精度であることが確認できる。
[try]
①中間層の活性関数をsigmoidに変更
上記が変更箇所。
結果
結果ReLU関数のときよりも精度が良い。これは今回のirisデータが単純なため。データが複雑になるとシグモイド関数では勾配消失が発生する。
②SGDをimportしoptimizerをSGD(lr=0.1)に変更
上記が変更箇所。
結果
SGD(学習率を演習より高く)にしたことで学習速度、精度も早い段階で1.0に到達していることがわかる。
Kerasを用いることで活性化関数や学習率、optimizerを容易に実装及び変更することが可能である。
MNIST分類
data.mnistよりmnistデータをインポート。
もでるは、入力784、中間層512と512、出力10の3層ニューラルネットワーク。中間層ではRelu関数、出力はsoftmax関数を実施。
1回の学習で60000枚の画像を用いて学習をしていることが実行結果よりわかる。
[try]
①load_mnistのone_hot_labelをFalseに変更
上記が変更箇所。
結果
エラー表示する結果となった。
categorical_crossentropyは、one_hot時に用いるのでモデルの形状エラーがはっせいする。
②誤差関数をsparse_categorical_crossentropyに変更
①から上記のlossを変更。
結果
one_hot= Falseのままでsparse_categorical_crossentropyに変更すると正常に動作を開始し20回目で精度98%程度まで上がることを確認した。
③Adamの引数の値を変更
上記が変更箇所。
結果
学習率が高くなると計算速度が向上するが、体感としてはさほど変わらない感じだった。
学習率は、0.001の方が適切な感じ。すぐに学習率を変更したりして比較できるのもKerasの利点。
MNISTをCNN分類
実際にepoch=20で動作させていたが時間がかかりすぎたのでepoch=5に変更している。
CNNなので、28×28×1にサイズを変更(reshape)し、input_shapeを定義する。
Kerasでは、Conv2D, MaxPooling2Dを用いるだけで、convolution(畳み込み)ができる。
model.add(Conv2D(32, kernel_size=(3, 3),
activation='relu',
input_shape=input_shape))の
32は出力チャンネル数、kernel_size=(3, 3)がフィルタサイズ(3×3)を表している。
epoch数5だが、数精度は98%程度まで上がっている。
cifar10データセットを用いた学習
cifar10は、10種のラベル「飛行機、自動車、鳥、猫、鹿、犬、蛙、馬、船、トラック」の32x32ピクセルのカラー画像データのセット。
データ数は、60000枚で、トレーニングデータ数:50000枚、 テストデータ数:10000枚
各画像データは、0~255のRGBで書かれているので、正規化(255で割り0~1の範囲に変更)を行う。
ニューラルネットワークは上記のCNN同様にConv2D, MaxPooling2Dを用いたネットワーク。
結果は、学習精度99%でテスト精度65%と過学習的な結果となった。
やはりepoch数3では良い精度を得ることは難しい。
RNN
全講義で説明があったSimpleRNN, LSTM, GRUなどもKerasで用意されている。
今回はRNNを使用して2進数の足し算を実施する。
RNNで計算するために数字は2進数表記で足し算を行う。これは、2新数は過去の数値が繰り上がっていくこととしてとらえているため。
モデルはmodel.add()のinput_shape=[8, 2]は8byte×aとbのデータ時系列は8個の要素を表している。
精度は、1回目で94%、2回目以降は100%となっている。
[try]
①RNNの出力ノード数を128に変更
上記が変更箇所。
結果
出力ノードを変更したことで、output_shapeが変動している。
精度は100%で誤差の演習時より小さくなっており、精度向上している。
②RNNの出力活性化関数をsigmoidに変更
上記が変更箇所。
結果
結果はRelu関数と比較すると精度が落ちていることが確認できた。
③RNNの出力活性化関数をtanhに変更
上記が変更箇所。
結果
シグモイド関数よりは精度が良く、ReLU関数とほぼ同等の精度結果となった。
④最適化方法をadamに変更
上記が変更箇所。
結果
結果としてSDGよりも誤差が小さく精度向上していることがわかる。
⑤RNNの入力 Dropout を0.5に設定
上記が変更箇所。
結果
dropoutすることで計算速度が向上していることが体感できた。ただ、計算精度はかなり悪い。
⑥RNNの再帰 Dropout を0.3に設定
上記が変更箇所。
結果
汎化性能が向上するのだが、結果としては、⑤とほぼ同等な結果となった。
⑦RNNのunrollをTrueに設定
unrollとは、ネットワークを展開することを指す。展開するとメモリに集中傾向になるがその反面計算スピードが向上する。
上記が変更箇所。
結果
上記説明どおり、計算速度は向上していることを確認できた。精度は⑤より、やや上がった程度。
GRUのネットワーク実装方法
model.addのSimpleRNNをGRUに書き換えるだけでGRUネットワークを実装できる。
強化学習
強化学習:長期的に報酬を最大化できるように、環境の中で行動を選択するエージェントを作成することを目標とした機械学習分野のこと。
行動結果から与えられる報酬をもとにして行動を決定及び改善していく仕組み。
確認テスト(4-19)
強化学習に応用できそうな事例を考え、環境・エージェント・報酬を具体的に挙げよ。
事例:車の自動運転
環境:道路上、エージェント:運転手、報酬:アクセル・ブレーキ・ハンドル操作、報酬:安全な走行
探索と利用のトレードオフ
オセロや囲碁でこの場面ではこの手を打てば勝てるというデータ(知識)があれば、行動を予測、決定できるが、
上記の具体例の車の運転のようにどのようにハンドルを切れば安全な運転なのかデータはない。
そのため、強化学習では、データは不完全なものとし行動しながらデータを収集しそこから最適な行動を行うようにする。
よって、過去のデータのみで行動すれば、探索が行えずデータ収集のみを行えば、過去のデータを使用できないというトレードオフの関係が成り立つ。強化学習では探索と利用を適切に調整しなければならない。
強化学習と教師あり・なし学習の違い
教師あり・なし学習では、データのパターンを見つけ、予測することが目標。
強化学習では、よりよい報酬を得る行動を見つけることが目標。
のように、目標が異なる。
行動価値関数
状態価値関数と行動価値関数の2種類ある。
ある状態の価値に注目するのが状態価値関数、状態と価値を組み合わせた価値に注目するのは、行動価値関数である。
方策関数
方策ベースの強化学習において、ある状態でどのような行動を行うのか確率を与える関数である。
方策勾配法
方策をモデル化して最適化する手法
定義方法として平均報酬と割引報酬和がある。