機械学習手書きデジタル認識(人工神経ネットワークPython実現)


本論文は「Python神経ネットワークプログラミング」の関連章節を参照してください.
今人気のあるマシン学習データ集は手書きデジタルデータ集(MNIST)です.
このウェブサイトは二つのCSVファイルを提供しています.
        練習セット:http://www.pjreddie.com/media/files/mnist_train.csv
        テストセット:http://www.pjreddie.com/media/files/mnist_test.csv
トレーニングセットには600個のマークサンプルがあります.テストセットには10000個のマークサンプルがあります.テスト用です.
 
以下のウェブサイトは二つの小さいデータセットを提供しています.私達はデバッグプログラムの過程で彼らを使うことができます.
        練習セット:https://raw.githubusercontent.com/makeyourownneuralnetwork/makeyourownneuralnetwork/master/mnist_dataset/mnist_トレイ100. csv
        テストセット:https://raw.githubusercontent.com/makeyourownneuralnetwork/makeyourownneuralnetwork/master/mnist_dataset/mnist_test_10.csv
 
ファイルを開くと、次のようになります.
机器学习 手写数字识别(人工神经网络 Python实现)_第1张图片
これは一例のデータで、最初の値はこの例のラベル(ここでは7)で、残りのデータは手書きのデジタル画像の各ピクセルポイントの色の値です.したがって、各値の取得範囲は0~255で、その数は28*28の784個です.
階調変化を用いて手書きの数字を表示します.Pythonコードは以下の通りです.
import numpy as np
from matplotlib import pyplot as plt

data_file = open('mnist_test_10.csv', 'r')
data_list = data_file.readlines()
data_file.close()
all_values = data_list[0].split(',')
image_array = np.array(all_values[1:]).astype(np.int).reshape((28, 28))
plt.imshow(image_array, cmap = 'Greys', interpolation = 'None')
plt.show()
机器学习 手写数字识别(人工神经网络 Python实现)_第2张图片
大丈夫です 階調表示で手書きの数字を見ることができます.
手書きの数字の識別方法の中で有名なK近隣(KNN)アルゴリズムは非常に簡単であり、識別効果も優れていますが、今日はこの方法を使用しません.神経ネットワークを使用します.
前のブログはすでに成熟した神経ネットワークモデルを構築しています.直接使用できます.今解決したい唯一の問題は、神経ネットワークの各層の結点個数です.
入力層、隠蔽層:入力層と隠蔽層の接合点数は同じ値をとり、各ピクセルポイントは一つの入力なので、28*28の合計784個があるはずです.
出力層:全部で10の中で可能な判断(0~9)があります.私達はコードの思想で10の結点を設定して、1に出力するその結点の位置は予測ラベルを表しています.すなわち[0,1,0,0,0,0,0,0,0,0,0,0,0]は予測1を表しています.
 
今はもう私たちの神経ネットワークを訓練し始めましたが、いくつかの細かい点に注意してください.
一:入力したデータ
私たちはデータをより小さい範囲(データのスケーリング)に調整したいです.ここではデータスケーリングがモデルトレーニングに与える影響を紹介しません.興味がある方は自分で関連記事を調べてください.
ここではデータを0.01~10の範囲に拡大して、0.01を最低点として選びます.0入力が重みの更新に影響がないことを避けます.
すべてのデータの取得範囲は0~255ですので、すべてのデータを255で割って0~1の入力となります.0.99で0~0.99の入力となり、最後に0.01を加えて、0.01~1.00の入力となります.
 
二:重みの初期化
次のレイヤーの接合点の始点を標準分散として使用して重みを初期化します.
 
三:歩幅
歩幅の選択は理論的には小さいほどいいですが、小さい歩幅ほど必要な訓練回数が多くなります.だから私達は適切な歩幅を選びたいです.トレーニング回数の下で最適になります.しかも変動は大きすぎません.
ここでは0.3のステップを選んで,ステップ長の選択には明確な方法がなく,実験で相対的に適切なステップサイズを決定するしかない.
 
 Pythonの実現を見てみましょう.
コードとデータセットはすでに私のリソースにアップロードされました.https://download.csdn.net/download/qq_4139888/11232343
 
ファイル読み込み:
def loaddataset(filename):
	fp = open(filename, 'r')
	dataset = []
	labelset = []
	for i in fp.readlines():
		a = i.strip().split(',')
		#       
		dataset.append([(int(j) / 255.0 * 0.99 + 0.01) for j in a[1:]])
		labelset.append(int(a[0]))
	return np.array(dataset), np.array(labelset)
 
 タブを変更([0,0,1,0,0,0,0,0,0,0,0,0]の形に変更):
活性化関数については、0,1の出力を生成することは不可能であり、大きな重みと飽和ネットワークの出現をもたらすので、0の代わりに0.01を使用し、0.99を使用します.
def adjustment_label(labelset):
	new_labelset = []
	for i in labelset:
		new_label = [0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01]
		new_label[i] = 0.99
		new_labelset.append(new_label)
	return new_labelset
 
 アクティブ関数のsigmoidはscipyライブラリの中のexpit(x)関数を使って、ネットでその運行速度が速くなると伝えています.結局60000サンプルです.私のコンピュータトレーニングは一回に少なくとも25分かかります.
import scipy.special as spc
def sigmoid(z):
	return spc.expit(z)
 
 パラメータ初期化:
def parameter_initialization(x, y, z):
	value1 = np.random.normal(0.0, pow(1, -0.5), (1, y))
	value2 = np.random.normal(0.0, pow(1, -0.5), (1, z))
	weight1 = np.random.normal(0.0, pow(x, -0.5), (x, y))
	weight2 = np.random.normal(0.0, pow(y, -0.5), (y, z))
	return weight1, weight2, value1, value2
 
トレーニングを開始する(トレーニングプロセスには何の修正も必要ではない):
def trainning(dataset, labelset, weight1, weight2, value1, value2, x):
	for i in range(len(dataset)):
		print(i)
		inputset = np.mat(dataset[i])
		outputset = np.mat(labelset[i])
		input1 = np.dot(inputset, weight1)
		output2 = sigmoid(input1 - value1)
		input2 = np.dot(output2, weight2)
		output3 = sigmoid(input2 - value2)
 
		a = np.multiply(output3, 1 - output3)
		g = np.multiply(a, outputset - output3)
		b = np.dot(g, np.transpose(weight2))
		c = np.multiply(output2, 1 - output2)
		e = np.multiply(b, c)
 
		value1_change = -x * e
		value2_change = -x * g
		weight1_change = x * np.dot(np.transpose(inputset), e)
		weight2_change = x * np.dot(np.transpose(output2), g)
 
		value1 += value1_change
		value2 += value2_change
		weight1 += weight1_change
		weight2 += weight2_change
	return weight1, weight2, value1, value2
 
テストプロセス:
10個の出力のうち0.5以上が0.5以上でない場合がありますので、予測ラベルとして10個の出力の中で最大の位置を探しています.
def testing(dataset, labelset, weight1, weight2, value1, value2):
	rightcount = 0
	for i in range(len(dataset)):
		inputset = np.mat(dataset[i])
		outputset = np.mat(labelset[i])
		input1 = np.dot(inputset, weight1)
		output2 = sigmoid(input1 - value1)
		input2 = np.dot(output2, weight2)
		output3 = sigmoid(input2 - value2)

		label = np.argmax(output3)
		if int(label) == int(labelset[i]):
			rightcount += 1

		print("    %d,     %d"%(labelset[i], label))
	print("    %f"%(rightcount / len(dataset)))
np.argmax()は、行ベクトルの最大値の位置を返します.
 
 私たちは訓練されたパラメータをファイル形式で保存してもいいです.その後は直接使ってもいいです.もう一回訓練する必要はないです.訓練されたパラメータファイルも私のリソースにアップロードします.
最後に私達のテストセットでの予測の正確性は次の通りです.
    0.953000
[Finished in 1005.7s]
結果はかなりいいです.適切に歩幅を小さくして、練習回数を増やして正確率を上げることができます.私は実現しません.