覚え書きブログ

Pythonによる機械学習3(ニューラルネット 2/3)

<< Pythonによるデータ解析3(ニューラルネット 1/3)

【Pythonによる機械学習3(ニューラルネット 2/3)の目次】

演習2(難しいデータに対するロジスティック回帰)

前回作成したロジスティック回帰を、多峰性のある難しいデータに対してかけてみましょう。

logisticRegression_template.pyのメインの人工データ生成の行を以下のように変更します。
【変更前】

# 人工データの生成(簡単な場合)
myData = Data.artificial(300,150,mean1=[1,2],mean2=[-2,-1],mean3=[2,-2],cov=[[1,-0.8],[-0.8,1]])

【変更後】

# 人工データの生成(難しい場合)
myData = Data.artificial(300,150,mean1=[1,2],mean2=[-2,-1],mean3=[4,-2],mean3multi=[-2,4],cov=[[1,0],[0,1]])

そして、以下のようにlogisticRegression_template.pyを実行します。

> python logisticRegression_template.py

学習したロジスティックモデルによる各カテゴリの事後確率の画像をmoodleに提出してください。

学習したロジスティックモデルによる各カテゴリの事後確率は以下のようになっており、カテゴリ1と3を分類することができていないことがわかります。
f:id:hirotaka_hachiya:20171125092223p:plain
f:id:hirotaka_hachiya:20171125092238p:plain
f:id:hirotaka_hachiya:20171125092253p:plain

また、交差エントロピー損失も十分に下がっていない(0.47くらいで止まっている)ことがわかります。
f:id:hirotaka_hachiya:20171125092151p:plain

これは、ロジスティックモデルでは、各カテゴリに1つの直線w_{cl}^T + b_c(xが3次元の場合は平面、4次元以上の場合は超平面)が割り当てられていますが、カテゴリ1と3の間はどのように直線を引いても、原理的を分類をすることができないためです。文章、画像およびセンサーなどの実際のデータは、このように線形では分類できない複雑な構造を持っている場合が多いと考えられます。

ニューラルネットワークのテンプレート

複雑な構造を持つデータに対応するために、ロジスティック回帰を3階層のニューラルネットワークに拡張していきます。ロジスティック回帰と同様に、 intelligentSystemTrainingフォルダにあるニューラルネットワークのテンプレートneuralNetwork_template.pyを用います。

neuralNetworkクラスには、以下のようなメソッドが定義されています。
1)__init__: 学習データおよびモデルパラメータW^1、W^2の初期化
3)update:最急降下法によるモデルパラメータの更新※未実装
5)predict: 事後確率の計算。
6)sigmoid: シグモイド関数※未実装
7)hidden: 中間層の計算

class neuralNetwork:
	#------------------------------------
	# 1) 学習データおよびモデルパラメータの初期化
	# x: 学習入力データ(入力ベクトルの次元数×データ数のnumpy.array)
	# t: one-hot学習カテゴリデータ(カテゴリ数×データ数のnumpy.array)
	# hDim: 中間層のノード数hDim(スカラー)
	# batchSize: 学習データのバッチサイズ(スカラー、0の場合は学習データサイズにセット)
	def __init__(self, x, t, hDim=20, batchSize=0):
		# デフォルトの初期化
		self.init(x,t)

		# モデルパラメータをランダムに初期化
		xDim = x.shape[0]	# 入力データの次元
		hDim = hDim			# 隠れ層のノード数
		tDim = t.shape[0]	# カテゴリ数
		
		self.W1 = np.random.normal(0.0, pow(hDim, -0.5), (xDim + 1, hDim))
		self.W2 = np.random.normal(0.0, pow(tDim, -0.5), (hDim + 1, tDim))

	#------------------------------------

	#------------------------------------
	# 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.validInd],self.t[:,self.validInd]))

			# 正解率エントロピーの記録
			self.accuracies = np.append(self.accuracies, self.accuracy(self.x[:,self.validInd],self.t[:,self.validInd]))
		
			print("loss:{0:02.3f}, accuracy:{1:02.3f}".format(self.losses[-1],self.accuracies[-1]))
	#------------------------------------
	
	#------------------------------------
	# 5) 事後確率の計算
	# x: 入力データ(入力ベクトルの次元数×データ数のnumpy.array)
	# h: 中間層のデータh(中間層のノード数×データ数のnumpy.array)
	def predict(self, x, h = []):
		if not len(h):
			h = self.hidden(x)
		return self.softmax(np.matmul(self.W2[:-1].T, h) + self.W2[-1][np.newaxis].T)
	#------------------------------------
	
	#------------------------------------
	# 6) シグモイドの計算
	# x: 入力データ(入力ベクトルの次元数×データ数のnumpy.array)
	def sigmoid(self,x):
		sigmoid = x		#【シグモイド関数の計算】
		return sigmoid
	#------------------------------------

	#------------------------------------
	# 7) 中間層
	# x: 入力データ(入力ベクトルの次元数×データ数のnumpy.array)
	def hidden(self, x):
		h = self.sigmoid(np.matmul(self.W1[:-1].T, x) + self.W1[-1][np.newaxis].T)
		return h
	#------------------------------------

メインおよび実行方法は、LogisticRegression_template.pyと基本的には同じです。

演習3(最適化対象のパラメータ数)

以下のように、中間層のノード数を20に設定(hDim=20)した場合、入力ベクトルxが2次元の3階層のニューラルネットワークには、最適化対象のパラメータはいくつあるか確認しましょう。

	# 2) 3階層のニューラルネットワークモデルの作成
	classifier = neuralNetwork(myData.xTrain, myData.tTrain,hDim=20)

入力層と中間層の間のパラメータW1と、中間層と出力層のパラメータW_2は、neuralNetworkクラスのコンストラクタにて以下のように設定されています。

	def __init__(self, x, t, hDim=20, batchSize=0):
		# デフォルトの初期化
		self.init(x,t,batchSize)

		# モデルパラメータをランダムに初期化
		xDim = x.shape[0]	# 入力データの次元
		hDim = hDim			# 隠れ層のノード数
		tDim = t.shape[0]	# カテゴリ数
		
		self.W1 = np.random.normal(0.0, pow(hDim, -0.5), (xDim + 1, hDim))
		self.W2 = np.random.normal(0.0, pow(tDim, -0.5), (hDim + 1, tDim))

適当な場所に「pdb.set_trace()」を設定し、確認してみましょう。
pdbで確認している様子がわかる出力のコピーをmoodleにて提出してください。

Pythonによる機械学習3(ニューラルネット 3/3)>>