では早速作ってみましょうか。
Pythonを使って実装していきます。
アーキテクチャ
ハイパーパラメータ | 値 |
入力ニューロン数 | 784 |
隠れ層の数 | 1 |
隠れ層のニューロン数 | 50 |
出力ニューロン数 | 10 |
隠れ層の活性化関数 | シグモイド関数 |
出力層の活性化関数 | ソフトマックス関数 |
損失関数 | 交差エントロピー誤差 |
実際に解く問題
よくチュートリアルで使用される手書き文字のデータセットを使って、画像に移っている数字を識別するモデルを作成してみましょう!
データのロード
TensorFlowからデータをロードしましょう。(ない人はインストールしてね)
訓練用とテスト用に分割しておきます。
import tensorflow as tf
mnist = tf.keras.datasets.mnist
(x_train, y_train), (x_test, y_test) = mnist.load_data()
実際に中身を見てみると0~256の数値の2次元配列になっていることが分かります。(8bitグレースケール: 白「0」~黒「255」の256段階)
正解ラベルの方は正解の数値になっていますね。
データの前処理
前処理についてはあまり触れてませんでしたが、機械学習では必ず行われるものです。
機械学習ではデータが命なのでいかにきれいにするかが肝になってきます。
今回のデータはそもそも結構きれいなので、ニューラルネットワークに都合がよいように変換します。
具体的には以下のような処理を施します。
- 訓練データを0~1の間に押し込める(ニューラルネットワークでは0~1の数値が前提とされる)
- データを1次元に変換
- 正解ラベルをワンホットエンコーディング
では早速やっていきましょう
# 1次元に変換
x_train_fla=np.array([x.flatten() for x in x_train])
x_test_fla=np.array([x.flatten() for x in x_test])
x_train_fla.shape,x_train.shape
# ((60000, 784), (60000, 28, 28))
28かける28だった配列が1次元になっていますね。
# 0~1へ変換
x_train_fla_norm=x_train_fla/255.0
x_test_fla_norm=x_test_fla/255.0
x_train_fla_norm[0]
# こんな感じ [0. , 0. , 0.01176471, 0.07058824, 0.07058824,]
# One-Hot
num_classes = 10
y_train_one_hot = np.eye(num_classes)[y_train]
y_test_one_hot = np.eye(num_classes)[y_test]
y_train_one_hot[0],y_train[0]
# (array([0., 0., 0., 0., 0., 1., 0., 0., 0., 0.]), 5)
これで前処理は終了です。
ニューラルネットワークの実装
まずはネットワークの重みとバイアスの初期化です。
重みは0以外のランダムな小さな値を振り分けます。
# 実装
def init_network(input_size, hidden_size, output_size, weight_init_std=0.01):
# 重みの初期化
network={}
network['params']={}
network['params']['W1'] = weight_init_std * np.random.randn(input_size, hidden_size)
network['params']['b1'] = np.zeros(hidden_size)
network['params']['W2'] = weight_init_std * np.random.randn(hidden_size, output_size)
network['params']['b2'] = np.zeros(output_size)
return network
network=init_network(784, 50, 10, weight_init_std=0.01)
次に、予測の関数を作成しましょう。
これが実際のニューラルネットワークの計算を行う部分です。
隠れ層の活性化関数にはシグモイド関数を、出力層にはソフトマックス関数を設定しましょう。
# シグモイド関数
def sigmoid(x):
return 1 / (1+np.exp(-x))
# softmax
def softmax(a):
c=np.max(a)
exp_a=np.exp(a-c)
sum_exp_a=np.sum(exp_a)
y= exp_a/sum_exp_a
return y
def predict(network, x):
W1, W2 = network['params']['W1'], network['params']['W2']
b1, b2 = network['params']['b1'], network['params']['b2']
a1 = np.dot(x, W1) + b1
z1 = sigmoid(a1)
a2 = np.dot(z1, W2) + b2
y = softmax(a2)
return y
次は損失関数を実装しましょう。
交差エントロピー誤差を設定ましょう。
# 交差エントロピー誤差
def cross_entropy_error(y,t):
delta=1e-7
return -np.sum(t*np.log(y+delta))
def loss(network, x, t):
y = predict(network, x)
return cross_entropy_error(y, t)
次に勾配を計算する関数を作成しましょう。
ここまでで説明してきた項目が出そろってきましたね。
def numerical_gradient(f, x):
h = 1e-4 # 0.0001
grad = np.zeros_like(x)
it = np.nditer(x, flags=['multi_index'], op_flags=['readwrite'])
while not it.finished:
idx = it.multi_index
tmp_val = x[idx]
x[idx] = tmp_val + h
fxh1 = f(x) # f(x+h)
x[idx] = tmp_val - h
fxh2 = f(x) # f(x-h)
grad[idx] = (fxh1 - fxh2) / (2*h)
x[idx] = tmp_val # 値を元に戻す
it.iternext()
return grad
def numerical_gradient_calc(network, x, t):
loss_W = lambda W: loss(network,x, t)
grads = {}
grads['W1'] = numerical_gradient(loss_W, network['params']['W1'])
grads['b1'] = numerical_gradient(loss_W, network['params']['b1'])
grads['W2'] = numerical_gradient(loss_W, network['params']['W2'])
grads['b2'] = numerical_gradient(loss_W, network['params']['b2'])
return grads
長くなってきたので次回、実際に学習させていきましょう!
コメント
コメントを投稿