CNN(畳み込みニューラルネットワーク)
hanamichi-sukusuku.hatenablog.com
上記ではMLPを使用することで比較的高い正解率を叩き出すことができた。しかし、CNN(畳み込みニューラルネットワークを利用することで、より高い精度を出すことができる。
CNNとは畳み込み層(convolution layers)とプーリング層(pooling layers)から構成されるニューラルネットワーク。画像データを解析する際に高い精度を出すことで有名だが、音声認識や顔検出、レコメンド機能や翻訳など様々な用途で利用されている。
引用:
CNNの仕組みとしては上記画像のような層を持ったネットワークになっている。
①フィルターを使用し、入力画像の全体に対して畳み込み層でフィルター処理を行う。
②処理した画像をプーリング層に流し込む。
③プーリング層で画像の解像度を下げる処理を行う。
④③の結果を用いて全結合層で結合することで、画像認識が可能、という流れ。
分析する画像が入力層に読み込まれた後、このデータをくまなくスキャンして、データの特微量を抽出するために使われるのがフィルターである。抽出された特微データは畳み込み層に送られ、そこで更に特徴の凝縮されたデータが作成されプーリング層、全結合層へと流れていく。
イメージとしては多層構造に加え、工夫された2つの隠れ層(畳み込み層、プーリング層)という構造が組み込まれたニューラルネットワークというイメージ。
MLP(多層パーセプトロン)のアルゴリズムを利用してMNISTの分類
実行結果
MLPとは
MLPとは多層パーセプトロン(multilayer perceptron)のことで、特徴としては入力層からデータを入力した後、複数の隠れ層を経て出力層に出力される。これをkerasで表すと
model.add()メソッドを用いて、複数の隠れ層を追加していくことでMLPの特徴を反映している。
MNISTデータの読み込みと一次元の配列に変換
モデルの構造を定義
今回ではmodel.add()でDropout()関数を使用していて、これはドロップアウト処理を加えるもの。ドロップアウトというのは入力値のうちいくらかをランダムに0にセットする機能。つまり、覚えたことを忘れることを意味するが、これにより過学習を防ぐことができる。そして、学習精度が上がる。Dropout(0.2)では20%の出力値がランダムに0に置き換わる。
モデルコンパイル
optimizer(最適化関数)にはRMSprop()を指定しているが、Dropout()関数を使用するときはこれを使った方がいいのかな?わからなかった。
学習の実行
model.fitのパラメーターにvalidation_dataという配列で評価データを与えるとmodel.fitの返り値のhistoryオブジェクトにepoch毎の訓練データでの評価とvalidation_dataでの評価とそれぞれの結果を残してくれる。
モデル評価
正解率の推移をプロット
ロスの推移をプロット
kerasで手書き数字の判定
実行結果
このプログラムではTensorFlowを用いて手書き数字の判定を行っていく。
MNISTデータの読み込み
MNISTのデータは、白黒画像の手書き数字のデータセットで、学習用の画像は6万枚、テスト用の画像は1万枚もの画像が用意されている。それぞれの画像は28✖️28ピクセル、グレースケールのデータ。グレースケールというのは0(白)~255(黒)の範囲の値で構成されている画像のこと。kerasには、機械学習で使える様々なデータセットが用意されており、MNISTデータもkerasのデータセットに含まれている。
よってfrom keras.datasets import mnistでmnistモジュールをインポートし、load_data()関数でMNISTデータを読み込む。それを学習用、テストように分割。
for文ではMNISTデータの中身を確認している。
range(0, 32)では0~31の値を順にiに格納している。
pyplot.subplot()では複数の描画を一つの画像に描くた目のもので、第一引数に行数、第二引数に列数、第三引数にどこに描画するかを指定している(左上から0)。
pyplot.imshow()で学習用のデータの一部を描画。
pyplot.show()で表示。
データを一次元に変換
X_trainのデータを確認してみると
三次元の配列であり、一つの画像が25✖️25個の二次元配列となっていることが確認できる。
画像一つが二次元なので28✖️28で784の一次元配列に変換するためreshape()の第一引数に-1を指定し、行数が1、列数が784の一次元配列にする。astype()でデータ型変換。float32では6桁で収まるときはこの方が早いらしい。それ以外はfloat64を指定する方が無難っぽい。255で割るのはモデルを学習させるときのために正規化する必要があるので色の最大値である255で全体を割ることで0.0~1.0の値で表現することができる。
ラベルデータ、ohe-hotベクトルに変換
以前はmap関数で変換したがkerasの機能を使って変換することができる。
keras.utils.to_categorical()で第一引数に処理するデータ、第二引数に10を指定しているがこれは例えば出力結果が「0.1,0,0,0,0,0,0.8,0,0.1,0」(0の確率10%。6の確率80%。10の確率10%)を得られるような形でone-hotベクトルに変換する。
モデルの構築
inpu_shape()では入力値が784なので28✖️28を格納したin_sizeを設定。
out_sizeでは10を指定しているが、0~9までの数字を判定するため出力のユニット数を10にしている。
学習と評価
fit()で学習。evaluate()で評価。
TensorFlowでアヤメ分類
実行結果
このプログラムではTensorFlowを用いてアヤメのデータを学習させて、その結果を出力するもの。
アヤメデータの読み込み
pandasモジュールはデータ処理の利用するライブラリーで、ここではcsvファイルを読み込むために使用。
pd.read_csv()でcsvファイルを指定し、エンコードの仕方を指定して出力。
アヤメデータをラベルと入力データに分離する
locを指定することでpd.read_csv()で取得したデータから任意の位置の要素を取得できる。
y_lanelsのiris_data.loc[:, "Name"]では全ての行から"Name"の列の要素を全て取得している。:で全ての行、"Name"でその列の要素を指定。
x_data =iris_data.loc.....では全ての行からそれぞれ指定した列の要素を取得している。
csvファイルの中身はこんな感じ。
ラベルデータをone-hotベクトルに直す
one-hotベクトルというのは、一つだけHigh(1)、他はLow(0)の状態で表現することである。TensorFlowではラベルデータをこのone-hotベクトルという形式で表す必要がある。
上記のコードではIris-setosaを[1, 0, 0]、Iris-versicolorを[0, 1, 0]、Iris-virginicaを[0, 0, 1]という形に変換している。
mapメソッドを使用して第一引数に関数(どんな処理をするか)、第二引数に処理したいデータを指定する。今回ではラムダを使用して引数で受け取った要素(Iris-setosaまたはris-versicolorまたはIris-virginica)をlabelsのキーに指定して、それに対応する値を返し新しいリストを作成している。
学習用とテスト用に分割する
モデルの定義
modelにSequentialを定義。
モデルの中にネットワーク(レイヤー)を追加していく。
model.add(Dense(10, activation='relu', input_shape=(4,)))ではユニット数が10、activationは活性化関数としてreluを指定、入力層としてDenseを使用する場合はinput_shapeで入力のパラメーターの数を指定する、今回はSepalLength,SepalWidth,PetalLength,PetalWidthの四次元なので(4,)を指定。
次のDenseでは出力値がIris-setosa、ris-versicolor、Iris-virginicaなので出力用としてユニット数3、activation='softmax'では出力した値の合計が1になるように出力されるように指定している。
モデルの構築
損失関数のlossにはcategorical_crossentropyを指定しており、クラス分類でよく使われる誤差関数の一つ。最適化の手法にはadamを指定しており、これは確率的勾配降下法の一つのアダム法を使って最適化を行うようにしている。metricsではモデルをどのように評価するのかを指定しており、今回は正解率を知りたいのでaccuracyを指定。
学習を実行
baych_sizeは一回に計算するデータの数のことで今回は20に設定。ただ、これを小さくすると使用するメモリー量が少なくなるが、小さくしすぎるとうまく動かなくなるので注意。
epochsは何回学習を繰り返すかの指定。
モデルを評価
model.evaluate()でモデル評価。
score[1]には正解率、scrore[0]には間違い度を表している。
TensorFlowでニューラルネットワークのモデルを視覚化
hanamichi-sukusuku.hatenablog.com
tensorflowにはニューラルネットワークのモデルを視覚化するための便利なツールも用意されており、今回はこれを利用して作成したデータを図で確認してみる。
上記のリンクで作成されているプログラムにコードを書き加えて、ニューラルネットワークのモデルを図で確認していく。
実行結果
モデル作成
モデルの学習の仕方を指定
モデルの概要を表示
summary()関数を使用すると、構築されたモデルの概要を表示することができる。
今回では単純なニューラルネットワークなので、上記のように簡単なモデルが表示されるが、モデルが複雑な時、モデルの概要を理解するのに図の出力が役に立つ。
図でモデルを出力
ここではモデルの図を外部に保存している。
上記の画像はファイルの中身。
このような形で視覚化することができる。
まとめ
・TensorFlowではディープラーニングを実践するライブラリーの中で人気が高い。
・TensorFlowではモデルを定義し構築(コンパイル)してから学習を行う。
・モデルを図で出力する機能が備わっている。
TensorFlowを使ってジャンケンデータを学習する
実行結果
hanamichi-sukusuku.hatenablog.com
このプログラムではTensorFlowを用いて上記で作成したジャンケンの勝敗データを学習させるプログラムである。
tensorflowとは
機械学習を行うライブラリーで、機械学習やディープラーニングが実践できるが、それだけでなく、汎用的な仕組みを提供している。今回はtensorflowの使い方に注目してプログラムを見ていく。
kerasとは
Pythonの深層学習(ディープラーニング)のライブラリである。
深層学習を行うときに、イチから全部作っていたら大変なので、使いやすいものを用意してある。
ニューラルネットワークとは
ニューラルネットワークとは、人の神経を模したネットワーク構造のことで、コンピューターに学習能力を持たせることにより、様々な問題を解決するためのアプローチができる。人間の脳の中には多数の神経細胞(ニューロン)が存在し、一つのニューロンは他の複数のニューロンから信号を受け取り、他のニューロンに対して信号を渡す。脳はこの信号の流れによって様々な情報を伝達している。この仕組みをコンピューターで再現したのがニューラルネットワークである。
ディープラーニングとは
ディープラーニングとは機械学習の一分野で、精度が良いことが特徴である。そして、もう少し具体的にいうとニューラルネットワークを3層以上重ねたものを、一般的にディープ・ニューラル・ネットワーク(DNN)とよび、このDNNを使った機械学習をディープラーニングという。ディープラーニングでは、大量のデータを学習することで、各ニューロン間の接続の重み付けのパラメーターを繰り返し調整する。この重みづけというのは単なる多数決で結果が決まるのではなく、例えばテレビを購入するかどうかを決定するときに、テレビが壊れているや資金が少ないなど要因によってテレビを購入する必要があるかどうかはそれぞれなので、テレビが壊れているならその部分の必要性(重み付け)は高いと設定し、資金が少ないならその必要性は低いと設定することで要因によってパラメーターの重み付けを変化させ最適な結果を出力するために重み付けが必要なのである。
保存したジャンケンデータを読み込む
作成したジャンケンの勝敗データを読み込み、学習用、テスト用に分ける。
janken-data.pklには
[[x_train,y_train],[x_test, y_test]]という形でそれぞれ~_trainが学習用データ、~_testがテスト用データとして格納されている。
モデルの構築
ここでは単純なニューラルネットワークのモデルを構築している。TensorFlowでは学習を行う前にどんなモデルを利用して、ニューラルネットワークを利用するのかを最初に指定し、モデルを構築(コンパイル)する必要がある。そのため、変数modelにネットワークの構造を指定し、compileメソッドで構築する。
kerasにおけるモデルには大きく分けて3種類のモデルがある。
Sequentialモデルでは、このような階層構造が直列につながっているような状態を表す。
tf.keras.layers.Dense(30, activation='relu', input_dim=2)では上記の画像のような層(レイヤー)をモデルに追加している。
Denseは全結合層のことで上記画像のように前の層の全ユニットの出力が次の層の全ユニットの入力となるのが全結合層である。
第一引数の30は出力数を表し、activation='relu'では活性化関数を表し、前の層からの出力をどのように変換するかという認識でいいと思う。reluは0以下なら0を返し、0より大きい場合はそのまま返すというもの。input_dimは入力層(input Layer)でDenseを追加した場合はinput_dimで入力パラメーターの数を指定する。[身長,体重,年齢]ならinput_dim=3のようになる、今回は2つなのでinput_dim=2。
tf.keras.layers.Dense(3, activation='softmax')では
活性化関数は、ユニットごとに個別に入力から出力を決めるのが基本ですが
softmaxは「全ユニットからの出力を、合計が1になるようにする」というもの。
例を挙げると
3ユニットからの出力[1, 2, 2]があった時に
これをsoftmaxに入力すると[0.2, 0.4, 0.4]というように出力してくれる。
だいたい分類モデルの最後の層に加えることが多いと思う。
「入力データからAかBかCか」という分類の問題でどれくらいの割合で
予想されているか出力したいときに手軽にできる。
機械学習は、結果の出力に大きい値やマイナスの値を出すことがある。
これらの値をsoftmax関数に入力すると、出力の合計が1になるように出力してくれる。
softmax関数は分類モデルの最後の層に加えることが多い。
「入力データから、AかBかCか判別」という分類の問題で
どれくらいの割合で予想されているか出力したいときに手軽にできる。
今回の場合でいくと
この部分の二次元配列で表現しているところは出力数3、activation='softmax'により合計が1になるように出力されている。
model.compile()では作成されたモデルがどのように学習するかの指定を行う。
引数はそれぞれ
optimizer:最適化関数
loss:損失関数(目的関数)
metrics:評価関数
optimizerでは機械学習をする上での最適化アルゴリズムを指定でき、様々なものがあるが今回はadamを指定。
lossは損失関数で、どれだけ正解から外れているかを計算する関数で、この値を小さくする方向に学習が進んでいくので目的関数とも呼ばれている。sparse_categorical_crossentropyでは正解ラベルのインデックスを整数で受け取ることができる。
metricsは評価関数でモデルの性能を測るために使われる。正解率を知りたいのでaccracyを指定。
学習と評価
作成したモデルをfit()で学習させる。epochsではニューラルネットワークで繰り返し学習を行う回数を指定している。学習経過に表示されるlossとaccuracyを参考に回数を決定する。
model.evaluate()ではテストデータを評価しており
この部分を表示している。verboseは詳細表示のしかたを指定するもので0だと表示しない、1だとプログレスバーで表示、2だとエポックごとに1行のログを表示する。
accracy: 1.000ということなのでちゃんとジャンケンのルールを学習している。
実際に勝負結果を出力してみる
predictの結果を見てみると
0.74.... , 0.13...., 0.11....のように予測結果を配列で返している。これは[あいこ, 負け, 勝ち]のそれぞれの値の確率を示すものである。確率が最も高いものが最も勝率の高い答えということになるので、argmaxメソッドを用いることで最も高い値を持つ要素の番号を得ることができる。つまり[0.74.... , 0.13...., 0.11....]なら0が返される。
ジャンケンの勝敗データ作成
このプログラムではジャンケンの勝敗データを作成し、データファイルに保存するもの。
ジャンケンの公式を定義
lambdaは無名関数。
lambda 引数: 返り値
という形で書く。
これを関数で表すと
def func(引数):
return 返り値
となる。
ジャンケンの結果の計算は(a-b+3)%3という簡単な式で計算することができる。
ランダムにデータ作成
random.randint()ではランダムに引数に指定した整数の値を取得する。引数は(開始値, 終了値)と指定する。
for文の中でrandom_hand()を呼び出しランダムに0~2までの値を変数a,bに格納。
a,bを引数にjudge()でジャンケンの公式に値を渡し、結果を変数resultに格納。
x_itemsにランダムに出力された0~2の値が格納されたa,bのデータ、y_itemsにジャンケンの結果を表す値を追加。これを3000回繰り返す。
データを学習用、テスト用に分割し保存
x_items[0:2000]でx_itemsに格納されているインデックス番号が0の要素から1999の要素までを範囲指定しx_trainに格納。
x_items[2000:]ではインデックス番号が2000から後の要素を全部範囲指定しx_testに格納。
最後にpickleで作成した学習用、テスト用データのオブジェクトを保存。