やみとものプログラミング日記

TOP ディープラーニング勉強記録

ディープラーニング勉強記録

この記事は書籍「ゼロから作るDeep Learning Pythonで学ぶディープラーニングの理論と実装」を参考にしています。
注意:個人的な勉強記録です。

ニューラルネットワークの学習手順

次の3ステップを繰り返す。

ステップ1(ミニバッチ)

訓練データの中からランダムに一部のデータを選び出す。(その選び出されたデータはミニバッチと言う)

ステップ2(勾配の算出)

ステップ1のミニバッチに対する勾配を求める。勾配はミニバッチの損失関数の値を最も減らす方向を示す。

ステップ3(パラメータの更新)

ネットワークの重みパラメータをステップ2で求めた勾配方向に微小量だけ更新する。

実装

補助的に必要な関数

import numpy as np

# TwoLayerNetクラス内で使うsigmoid関数の定義
def sigmoid(x):
    return 1 / (1 + np.exp(-x))  


# TwoLayerNetクラス内で使うsoftmax関数の定義
# 入力xを大小関係を維持したまま確率に変換する
def softmax(x):
    if x.ndim == 2:
        x = x.T
        x = x - np.max(x, axis=0)
        y = np.exp(x) / np.sum(np.exp(x), axis=0)
        return y.T 
    x = x - np.max(x) # オーバーフロー対策
    return np.exp(x) / np.sum(np.exp(x))


# TwoLayerNetクラス内で使うsigmoid_grad関数の定義
def sigmoid_grad(x):
    return (1.0 - sigmoid(x)) * sigmoid(x)

# TwoLayerNetクラス内で使うcross_entropy_error関数の定義
def cross_entropy_error(y, t):
    if y.ndim == 1:
        t = t.reshape(1, t.size)
        y = y.reshape(1, y.size)
        
    # 教師データがone-hot-vectorの場合、正解ラベルのインデックスに変換
    if t.size == y.size:
        t = t.argmax(axis=1)
             
    batch_size = y.shape[0]
    return -np.sum(np.log(y[np.arange(batch_size), t] + 1e-7)) / batch_size

ニューラルネットワーククラス(2層)

import numpy as np

class TwoLayerNet:
    def __init__(self, input_size, hidden_size, output_size, weight_init_std=0.01):
        # self.paramsは学習で更新するパラメータ
        self.params = {}
        self.params['W1'] = weight_init_std * np.random.randn(input_size, hidden_size)
        self.params['b1'] = np.zeros(hidden_size)
        self.params['W2'] = weight_init_std * np.random.randn(hidden_size, output_size)
        self.params['b2'] = np.zeros(output_size)
        
        
    # x 学習データのバッチ
    # t 教師データのバッチ
    def gradient(self, x, t):
        W1, W2 = self.params['W1'], self.params['W2']
        b1, b2 = self.params['b1'], self.params['b2']
        
        # gradsにはこのネットワークのパラメータW1, W2, b1, b2の勾配を入れるため辞書型
        grads = {}

        batch_num = x.shape[0]    # バッチのデータ数

        # forward
        a1 = np.dot(x, W1) + b1
        z1 = sigmoid(a1)
        a2 = np.dot(z1, W2) + b2
        y = softmax(a2)

        # backward
        # 以下では誤差逆伝播法によって導かれた計算式で勾配を効率的に計算する
        dy = (y - t) / batch_num
        grads['W2'] = np.dot(z1.T, dy)
        grads['b2'] = np.sum(dy, axis=0)

        dz1 = np.dot(dy, W2.T)
        da1 = sigmoid_grad(a1) * dz1
        grads['W1'] = np.dot(x.T, da1)
        grads['b1'] = np.sum(da1, axis=0)

        return grads
    
    
    
    def predict(self, x):
        W1, W2 = self.params['W1'], self.params['W2']
        b1, b2 = self.params['b1'], self.params['b2']

        a1 = np.dot(x, W1) + b1
        z1 = sigmoid(a1)
        a2 = np.dot(z1, W2) + b2
        y = softmax(a2)

        return y

    
    # x:入力データ, t:教師データ
    def loss(self, x, t):
        y = self.predict(x)

        return cross_entropy_error(y, t)
    
    
    def accuracy(self, x, t):
        y = self.predict(x)
        y = np.argmax(y, axis=1)
        t = np.argmax(t, axis=1)

        accuracy = np.sum(y == t) / float(x.shape[0])
        return accuracy

学習を行うコード

import numpy as np
from dataset.mnist import load_mnist


(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, one_hot_label=True)


# ハイパーパラメータ
iters_num = 10000    # 繰り返し回数
train_size = x_train.shape[0]    # 訓練データの個数
batch_size = 100  # 1バッチのサイズ
learning_rate = 0.1
# 1エポックあたりの繰り返し数(エポックとは学習において訓練データを全て使い切った時の回数)
iter_per_epoch = max(train_size / batch_size, 1)


network = TwoLayerNet(input_size=784, hidden_size=50, output_size=10)


# 次の3ステップを繰り返す
for i in range(iters_num):
    
    # ステップ1(ミニバッチ)
    # 訓練データの中からランダムに一部のデータを選び出す
    batch_mask = np.random.choice(train_size, batch_size)
    x_batch = x_train[batch_mask]    # ミニバッチ(データ)
    t_batch = t_train[batch_mask]     # ミニバッチ(教師データ)


    # ステップ2(勾配の算出)
    # ミニバッチに対する勾配を求める
    grad = network.gradient(x_batch, t_batch)


    # ステップ3(パラメータの更新)
    # ネットワークのパラメータを勾配方向に微小量だけ更新する
    for key in ("W1", "b1", "W2", "b2"):
        network.params[key] -= learning_rate * grad[key]
        
    
    # 学習経過の記録(lossを出力)
#     print(network.loss(x_batch, t_batch))

    # 1エポックごとに認識精度を計算
    if i % iter_per_epoch == 0:
        print(str(i * 100 / iters_num) + "%", network.accuracy(x_test, t_test) * 100)
今回の学習では94.5%程度の精度になった。

コメント

もしよろしければコメント下さい。

ハンドルネーム:
内容:

コメント一覧

最新記事

ディープラーニング勉強記録
numpy勉強記録
pythonでMySQL使う