覚え書きブログ

Pythonによる機械学習3(3/3)

<< Pythonによる機械学習3(2/3)

Pythonによる機械学習3(3/3)の目次】

演習2

以下の【シグモイド関数の計算】を実装し、lossとsigmoidメソッドを完成させましょう。

#------------------------------------
# 6) シグモイドの計算
# x: 入力データ(入力ベクトルの次元数×データ数のnumpy.array)
def sigmoid(self,x):
	return 【シグモイド関数の計算】
#------------------------------------

演習3

以下のupdateメソッド【self.W1の更新】および【self.W2の更新】の部分を実装し、最急降下法updateを完成させましょう。

#------------------------------------
# 3) 最急降下法によるパラメータの更新
# alpha: 学習率(スカラー)
# printLoss: 評価値の表示指示(真偽値)
def update(self, alpha=0.1,printEval=True):

	# 次のバッチ
	x, t = self.nextBatch(self.batchSize)
		
	# データ数
	dNum = x.shape[1]
		
	# 中間層の計算
	h = self.hidden(x)
		
	# 事後確率の予測と真値の差分
	predict = self.predict(x,h)
	predict_error =  predict - t
		
	# self.W1とW2の更新
	#【self.W1の更新】
	#【self.W2の更新】

	# 交差エントロピーとAccuracyを標準出力
	if printEval:
		# 交差エントロピーの記録
		self.losses = np.append(self.losses, self.loss(self.x[:,self.evalInd],self.t[:,self.evalInd]))
		# 正解率エントロピーの記録
		self.accuracies = np.append(self.accuracies, self.accuracy(self.x[:,self.evalInd],self.t[:,self.evalInd]))
		
		print("loss:{0:02.3f}, accuracy:{1:02.3f}".format(self.losses[-1],self.accuracies[-1]))
#------------------------------------

ニューラルネットワークの実行例

完成させたニューラルネットワークを、中間層の数(hDim)を20に設定して実行すると以下のような出力が得られます。

Training ite:1 loss:1.662, accuracy:0.233
Training ite:2 loss:1.524, accuracy:0.233
Training ite:3 loss:1.404, accuracy:0.233
Training ite:4 loss:1.302, accuracy:0.233
Training ite:5 loss:1.217, accuracy:0.200
...
Training ite:996 loss:0.121, accuracy:1.000
Training ite:997 loss:0.121, accuracy:1.000
Training ite:998 loss:0.121, accuracy:1.000
Training ite:999 loss:0.121, accuracy:1.000
Training ite:1000 loss:0.121, accuracy:1.000
Test loss:0.18161537447140794, accuracy:0.9266666666666666

線形モデルのロジスティックモデルでは分離できなかったカテゴリ1と3が、ニューラルネットワークでは以下のように分離できるようになっているのがわかります。
f:id:hirotaka_hachiya:20171125190333p:plain:w400
f:id:hirotaka_hachiya:20171125190353p:plain:w400
f:id:hirotaka_hachiya:20171125190410p:plain:w400

これは、ノード数20の中間層の導入により、入力層と中間層間のパラメータ \textbf{W}^1に基づき直線を20本引き、さらに、中間層と出力層間のパラメータ \textbf{W}^2により、各カテゴリごとに20本の直線を組み合わせることにより、複雑な境界線を引くことができるようになったことを意味します。

中間層のノード数と交差エントロピー損失の関係

ロジスティック回帰および中間層のノード数が1,5,10,50,100,200,300,500,800と異なるニューラルネットワークを同じデータで学習し、評価データに対する交差エントロピー損失をプロットして比較してみます。

ニューラルネットワークの中間層のノード数が1のときは、損失はロジスティック回帰と同じくらいのですが、ノード数を増やすことにより損失が一気に下がる(改善する)ことがわかります。しかしながら、ノード数が多い場合(例えば、500を超えた場合)、今度は逆に損失が上がる(悪化する)ことがわかります。これは過学習オーバーフィッティングと呼ばれる現象です。モデルの表現能力が高くなりすぎることにより、学習データのノイズに過度に適合してしまい、運用時のデータ(今回は評価データ)に対して十分に性能を発揮できない問題です。
f:id:hirotaka_hachiya:20171205090503p:plain

以下は、異なる中間層のノード数を用いて学習したニューラルネットワークの正解率のプロットです。
f:id:hirotaka_hachiya:20171205090740p:plain
交差エントロピーと同様に、中間層のノード数が1から増えるにつれて、正解率が上がっていきます。しかしながら、交差エントロピーほど顕著な差はでませんが、中間層のノード数が500を超えると、逆に正解率が徐々に下がる(悪化する)のがわかります。

以下に、中間層のノード数が800と50のときのカテゴリ1の事後確率を描画してみます。
【中間層のノード数が300(学習データと一緒にプロット)】
f:id:hirotaka_hachiya:20171205091015p:plain

【中間層のノード数が50(学習データと一緒にプロット)】
f:id:hirotaka_hachiya:20171205091132p:plain

中間層のノード数が800のときは、50のときと比べて境界線の形状が複雑になっていることがわかります。座標(x1,x2)=(1,-2)付近にあるカテゴリ1のノイズ(オレンジの〇が3つ)に対して、ノード数20のときは、顕著に反応せず滑らかな境界線が獲得されているのに対し、ノード数800のときは、過度に反応し、カテゴリ1の境界が大きく突き出し、下まで伸びているのがわかります。次に、中間層のノード数が800のと50ときのカテゴリ1の事後確率を、評価データと一緒に描画してみます。

【中間層のノード数が300(評価データと一緒にプロット)】
f:id:hirotaka_hachiya:20171205092445p:plain

【中間層のノード数が50(評価データと一緒にプロット)】
f:id:hirotaka_hachiya:20171205093423p:plain

中間ノード数が800のとき、座標(x1,x2)=(1,-2)付近のカテゴリ1の境界の突き出しにより、カテゴリ3のデータ(△)をカテゴリ1(〇)と誤分類していることがわかります。このように、学習データに過度に適合すると、評価データにおいて誤分類を起こしやすくなることがわかります。

宿題

1) 中間層のノード数が1,5,10,50,100,200,300,500,800と異なるニューラルネットワークを学習し、評価データ(myData.xTest,myData.tTest)に対する交差エントロピー損失および正解率をプロット(横軸:ノード数、縦軸:損失または正解率)するPythonスクリプトcompareClassifiers.pyを作りましょう。

なお、学習および評価データは、以下のスクリプトで生成したものを使ってください。

# 人工データの生成(難しい場合+ノイズあり)
myData = Data.artificial(300,500,mean1=[1,2],mean2=[-2,-1],mean3=[4,-2],mean3multi=[-2,4], cov=[[1,0],[0,1]],noiseMean=[1,-2])

作成したスクリプトおよび出力したグラフ画像を、Moodleにて提出してください。