LoginSignup
1
2

More than 1 year has passed since last update.

深層学習Day1・2(E資格ラビットチャレンジレポート3)

Posted at

この記事はJDLA E資格認定講座のラビットチャレンジの成果レポートである。

深層学習Day1:1.入力層~中間層

 ●ディープラーニングとは、明示的なプログラムの代わりに多数の中間層を使い、入力値から目的とする出力値に変換するモデルを構築することである。
 ●入力層には説明変数xが入力され、説明変数に対して重みwを掛け合わせ、バイアスbを追加したものを中間層が受け取る。中間層では受け取った値に対して活性化関数を通すことで信号の強弱を調整し、結果を出力する。
         $ f(x)=w^Tx+b$

 ●ニューラルネットワークに何らかの入力をする部分
●入力、重みは行列で表すことができる。
 総入力:$u=Wx+b$
 内積を使うことで入力の重要度を表現することができる。また、傾きだけでは表現できないu方向のずれをバイアスで表現することができる。
●傾き、切片を学習させることがニューラルネットワークの肝である。

深層学習Day1:2.活性化関数

活性化関数とは、受け取った値を出力信号に変換する関数のことである。
●活性化関数には非線形関数が用いられる。線形関数を用いる場合、ニューラルネットワークの層を深くする意味がなくなってしまう。(線形のままだと非線形に対応できないため。)
●中間層で用いられる活性化関数は約10種類あるが、代表的な活性化関数は以下の通り。

 ①シグモイド関数
 0~1の間を滑らかに変化する関数。滑らかに上昇する曲線のため微分ができるため学習がうまく進めることができる。大きな値では変化が微小のため、勾配消失問題が起きることがある。シグモイド関数が使われたことにより、ニューラルネットワークがいろいろなことを学習できるようになった。

def sigmoid(x):
  return 1 / (1 + np.exp(-x))

 ②ステップ関数
あるところまで何も反応しない、あるところで一気に反応する。現在、活性化関数として用いられることは少ない。(on/offしかない。)線形分離可能なものしか学習できないため現在は使い道があまりない。

def step_function(x):
  if x > 0:
    return 1
  else:
    return 0

 ③ReLU関数
  現在最も使われている活性化関数。入力が0より小さければ0を出力し、0より大きければそのまま出力する。勾配消失問題の回避やスパース化に貢献することで良い成果。最も使われている関数。

def relu(x):
  return np.maximum(0, x)

 ※感想…当初、シグモイドもステップもReLUも定義上異なるが、なぜどのように違うのかが分からなかった。具体的なアルゴリズムでシグモイド関数等が使われている場面と理由を学習すると、使用する役割や目的が異なると当然道具も異なり使い分けるということが理解できた。

深層学習Day1:3.出力層

●出力層の役割
 ・分類問題においては各クラスの確率(アウトプット)を算出する。
 ・実際にニューラルネットワークを学習させる部分である。

●誤差関数
 ・出力と入力された訓練データを誤差関数に通すことで間違え度合いを表現することができる。
 ・2乗することで全ての値を正の値になるようにする。
 ・2分の1することで、誤差関数の微分が簡単になる。

 ○平均二乗誤差(MSE:Mean Squared Error)
 回帰問題の誤差関数

def mean_squared_error(y, d):
  return np.mean(np.square(y-d)) / 2

○クロスエントロピー誤差(交差エントロピー誤差)
 分類問題の誤差関数に使用。

def cross_entropy_error(d, y):
  if y.ndim == 1:
    d = d.reshape(1, d.size)
    y = y.reshape(1, y.size)

  if d.size == y.size:
    d = d.argmax(axis=1)

  batch_size = y.shape[0]
  return -np.sum(np.log(y[np.arange(batch_size), d] + 1e-7) / batch_size

●出力層の活性化関数
 ・活性化関数の意義
  ニューラルネットワークが複雑なデータ構造を表現できる理由の1つが非線形な活性化関数。非線形な活性化関数を導入しなければ、ニューラルネットワークにおいてどれほど層の数を増やしても全体としては線形関数の合成となる。その場合、ニューラルネットワークは線型モデルと同等となり、データの中に含まれる非線形性は捉えられない。
 ・ちなみに、決定木はツリーというデータ構造を用いてデータを学習させる機械学習手法であり、この手法でも非線形な構造を捉えることができる。
 ・中間層はしきい値の前後で信号の強弱を調整するが、出力層は信号の大きさ(比率)はそのままに変換する。
 ・分類の問題の場合は、出力層の出力は0〜1の範囲に限定して総和を1にする必要がある。
 ・恒等写像:回帰に利用する。何も変換しない関数である。
 ・シグモイド関数:二値分類に利用する。
 ・ソフトマックス関数:多クラス分類に利用される。

# ソフトマックス関数
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))

 ・誤差関数:回帰では二乗誤差を利用。二値分類、多クラス分類では交差エントロピーを利用。

深層学習Day1:4.勾配降下法

●勾配降下法
 ●深層学習では誤差$E(w)$を最小化するようなパラメータ$w$を見つけることであり、そのための手法がいくつかある。
 
 ①勾配降下法:勾配降下法では以下の式から重み$w$を調整する。
  $w^(t+1)=w^t−ϵ∇E$
学習率が大きすぎる場合は発散してしまうというリスクがある。
  また、学習率が小さすぎる場合は収束するまでに時間がかかることがある。


https://konchangakita.hatenablog.com/entry/2021/01/07/210000

 ②確率的勾配降下法(SGD)
  勾配降下法では全サンプルの平均誤差を用いるのに対して、確率的勾配降下法ではランダムに抽出したサンプルの誤差を用いて学習を行う。利点として、データが几長な場合、計算コストを削減したり、オンライン学習を行うことができる。オンライン学習とは最初に全てのデータを用意せず、リアルタイムで得られるデータを用いて学習することである。
 $w^(t+1)=w^t−ϵ∇E_n$

  ③ミニバッチ勾配降下法
確率的勾配降下法では、ランダムに抽出したサンプルを用いるのに対し、ミニバッチ勾配降下法では、ランダムに分割したデータの集合(ミニバッチ)に属するサンプルの平均誤差を用いる。分割するため並列計算ができるため、確率的勾配降下法のメリットを損なわず、計算資源を有効活用し高速で学習できる。

   $w^(t+1)=w^t−ϵ∇E_t$
    $E_t=1/N_t ∑E_n$

●誤差勾配の計算
 数値微分は順伝搬の計算を繰り返し行う必要があり負荷が大きいため、誤差逆伝播法を利用する。

深層学習Day1:5.誤差逆伝播法


※伝言ゲーム的イメージが分かりやすい図

 ●算出された誤差を出力層側から順に微分し、前の層、前の層へと伝播する。最小限の計算で各パラメータでの微分値を解析的に計算する手法。
 ●直接数値微分を計算すると計算量が非常に多く、時間がかかってしまう。誤差逆伝搬法では出力層から算出された誤差から微分していき、一つ前の層に伝播することを繰り返しす。最小限の計算で各パラメータでの微分地を解析的に計算する。


https://rikeiminimalist.blog.jp/archives/5995253.html

※誤差逆伝播法の理解がディープラーニングにおいては肝中の肝であると考える。この理解では、「ゼロから作るDeep Learning1」(斉藤康毅・オライリー)が順を追って丁寧に解説しており非常に分かりやすい。

深層学習Day2:1.勾配消失問題

 ●勾配消失問題とは、誤差逆伝搬法を用いた時、下位層に進むにつれて、勾配が緩やかになっていくため、パラメータの更新量が小さくなり、全体最適解に収束しなくなることである。活性化関数として用いられるシグモイド関数では微分の最大値が0.25であるため、勾配消失問題を引き起こすことがあった。
 ●勾配消失問題の解決策は以下の通り。
 ・活性化関数の選択
 ・重みの初期値設定
 ・バッチ正規化

 ※バッチ正規化はこの記事が分かりやすい

深層学習Day2:2.学習率最適化手法

 ●深層学習では学習を通して誤差を最小とするようなパラメータを発見することが目的となる。その際に勾配降下法を用いてパラメータを最適化するが、学習率の値が小さすぎると学習に時間がかかってしまうことや、学習率の値が大きすぎる場合、発散してしまい最適なパラメータを見つけることができない。こういった問題を解決するための最適化手法がある。
 

深層学習Day2:3.過学習

 ●過学習とは、訓練データの誤差が少なくなっているのに対し、テストデータの誤差が小さくならず、モデルの汎化性能が失われていることを示す。過学習を抑制する手法について説明する。

 ●L1正則化、L2正則化:
 過学習の原因として、ネットワークの自由度が高すぎることが上げられる。自由度が高すぎる場合、重要な重みが大きくなりすぎ、他の値が小さくなることで重みにばらつきが発生する。このばらつきを抑制するために重みに対し罰則を設けることを正則化という。

 ●ドロップアウト
  ノード数が多いことも過学習の要因であるため、ノードをランダムに削除することで毎回異なるモデルを学習させているようにすることでも過学習を抑制できる。

深層学習Day2:4.畳み込みニューラルネットワークの概念

 ●畳み込みニューラルネットワークとは主に画像認識に用いられるニューラルネットであり、音声認識等の時系列データにも利用されている。主に畳み込み層とプーリング層から構成されている。

(畳み込みニューラルネットワークの実装)

from google.colab import drive
drive.mount('/content/drive')

import sys
sys.path.append('/content/drive/MyDrive/DNN')

import pickle
import numpy as np
from collections import OrderedDict
from common import layers
from common import optimizer
from data.mnist import load_mnist
import matplotlib.pyplot as plt

# 画像データを2次元配列に変換
'''
input_data: 入力値
filter_h: フィルターの高さ
filter_w: フィルターの横幅
stride: ストライド
pad: パディング
'''
def im2col(input_data, filter_h, filter_w, stride=1, pad=0):
    # N: number, C: channel, H: height, W: width
    N, C, H, W = input_data.shape
    out_h = (H + 2 * pad - filter_h)//stride + 1
    out_w = (W + 2 * pad - filter_w)//stride + 1

    img = np.pad(input_data, [(0,0), (0,0), (pad, pad), (pad, pad)], 'constant')
    col = np.zeros((N, C, filter_h, filter_w, out_h, out_w))

    for y in range(filter_h):
        y_max = y + stride * out_h
        for x in range(filter_w):
            x_max = x + stride * out_w
            col[:, :, y, x, :, :] = img[:, :, y:y_max:stride, x:x_max:stride]

    col = col.transpose(0, 4, 5, 1, 2, 3) # (N, C, filter_h, filter_w, out_h, out_w) -> (N, filter_w, out_h, out_w, C, filter_h)    

    col = col.reshape(N * out_h * out_w, -1)
    return col

# im2colの処理確認
input_data = np.random.rand(2, 1, 4, 4)*100//1 # number, channel, height, widthを表す
print('========== input_data ===========\n', input_data)
print('==============================')
filter_h = 3
filter_w = 3
stride = 1
pad = 0
col = im2col(input_data, filter_h=filter_h, filter_w=filter_w, stride=stride, pad=pad)
print('============= col ==============\n', col)
print('==============================')

# 2次元配列を画像データに変換
def col2im(col, input_shape, filter_h, filter_w, stride=1, pad=0):
    # N: number, C: channel, H: height, W: width
    N, C, H, W = input_shape
    # 切り捨て除算    
    out_h = (H + 2 * pad - filter_h)//stride + 1
    out_w = (W + 2 * pad - filter_w)//stride + 1
    col = col.reshape(N, out_h, out_w, C, filter_h, filter_w).transpose(0, 3, 4, 5, 1, 2) # (N, filter_h, filter_w, out_h, out_w, C)

    img = np.zeros((N, C, H + 2 * pad + stride - 1, W + 2 * pad + stride - 1))
    for y in range(filter_h):
        y_max = y + stride * out_h
        for x in range(filter_w):
            x_max = x + stride * out_w
            img[:, :, y:y_max:stride, x:x_max:stride] += col[:, :, y, x, :, :]

    return img[:, :, pad:H + pad, pad:W + pad]

class Convolution:
    # W: フィルター, b: バイアス
    def __init__(self, W, b, stride=1, pad=0):
        self.W = W
        self.b = b
        self.stride = stride
        self.pad = pad

        # 中間データ(backward時に使用)
        self.x = None   
        self.col = None
        self.col_W = None

        # フィルター・バイアスパラメータの勾配
        self.dW = None
        self.db = None

    def forward(self, x):
        # FN: filter_number, C: channel, FH: filter_height, FW: filter_width
        FN, C, FH, FW = self.W.shape
        N, C, H, W = x.shape
        # 出力値のheight, width
        out_h = 1 + int((H + 2 * self.pad - FH) / self.stride)
        out_w = 1 + int((W + 2 * self.pad - FW) / self.stride)

        # xを行列に変換
        col = im2col(x, FH, FW, self.stride, self.pad)
        # フィルターをxに合わせた行列に変換
        col_W = self.W.reshape(FN, -1).T

        out = np.dot(col, col_W) + self.b
        # 計算のために変えた形式を戻す
        out = out.reshape(N, out_h, out_w, -1).transpose(0, 3, 1, 2)

        self.x = x
        self.col = col
        self.col_W = col_W

        return out

    def backward(self, dout):
        FN, C, FH, FW = self.W.shape
        dout = dout.transpose(0, 2, 3, 1).reshape(-1, FN)

        self.db = np.sum(dout, axis=0)
        self.dW = np.dot(self.col.T, dout)
        self.dW = self.dW.transpose(1, 0).reshape(FN, C, FH, FW)

        dcol = np.dot(dout, self.col_W.T)
        # dcolを画像データに変換
        dx = col2im(dcol, self.x.shape, FH, FW, self.stride, self.pad)

        return dx

class Pooling:
    def __init__(self, pool_h, pool_w, stride=1, pad=0):
        self.pool_h = pool_h
        self.pool_w = pool_w
        self.stride = stride
        self.pad = pad

        self.x = None
        self.arg_max = None

    def forward(self, x):
        N, C, H, W = x.shape
        out_h = int(1 + (H - self.pool_h) / self.stride)
        out_w = int(1 + (W - self.pool_w) / self.stride)

        # xを行列に変換
        col = im2col(x, self.pool_h, self.pool_w, self.stride, self.pad)
        # プーリングのサイズに合わせてリサイズ
        col = col.reshape(-1, self.pool_h*self.pool_w)

        # 行ごとに最大値を求める
        arg_max = np.argmax(col, axis=1)
        out = np.max(col, axis=1)
        # 整形
        out = out.reshape(N, out_h, out_w, C).transpose(0, 3, 1, 2)

        self.x = x
        self.arg_max = arg_max

        return out

    def backward(self, dout):
        dout = dout.transpose(0, 2, 3, 1)

        pool_size = self.pool_h * self.pool_w
        dmax = np.zeros((dout.size, pool_size))
        dmax[np.arange(self.arg_max.size), self.arg_max.flatten()] = dout.flatten()
        dmax = dmax.reshape(dout.shape + (pool_size,)) 

        dcol = dmax.reshape(dmax.shape[0] * dmax.shape[1] * dmax.shape[2], -1)
        dx = col2im(dcol, self.x.shape, self.pool_h, self.pool_w, self.stride, self.pad)

        return dx

class SimpleConvNet:
    # conv - relu - pool - affine - relu - affine - softmax
    def __init__(self, input_dim=(1, 28, 28), conv_param={'filter_num':30, 'filter_size':5, 'pad':0, 'stride':1},
                 hidden_size=100, output_size=10, weight_init_std=0.01):
        filter_num = conv_param['filter_num']        
        filter_size = conv_param['filter_size']
        filter_pad = conv_param['pad']
        filter_stride = conv_param['stride']
        input_size = input_dim[1]
        conv_output_size = (input_size - filter_size + 2 * filter_pad) / filter_stride + 1
        pool_output_size = int(filter_num * (conv_output_size / 2) * (conv_output_size / 2))

        # 重みの初期化
        self.params = {}
        self.params['W1'] = weight_init_std * np.random.randn(filter_num, input_dim[0], filter_size, filter_size)
        self.params['b1'] = np.zeros(filter_num)
        self.params['W2'] = weight_init_std * np.random.randn(pool_output_size, hidden_size)
        self.params['b2'] = np.zeros(hidden_size)
        self.params['W3'] = weight_init_std * np.random.randn(hidden_size, output_size)
        self.params['b3'] = np.zeros(output_size)

        # レイヤの生成
        self.layers = OrderedDict()
        self.layers['Conv1'] = layers.Convolution(self.params['W1'], self.params['b1'], conv_param['stride'], conv_param['pad'])
        self.layers['Relu1'] = layers.Relu()
        self.layers['Pool1'] = layers.Pooling(pool_h=2, pool_w=2, stride=2)
        self.layers['Affine1'] = layers.Affine(self.params['W2'], self.params['b2'])
        self.layers['Relu2'] = layers.Relu()
        self.layers['Affine2'] = layers.Affine(self.params['W3'], self.params['b3'])

        self.last_layer = layers.SoftmaxWithLoss()

    def predict(self, x):
        for key in self.layers.keys():
            x = self.layers[key].forward(x)
        return x

    def loss(self, x, d):
        y = self.predict(x)
        return self.last_layer.forward(y, d)

    def accuracy(self, x, d, batch_size=100):
        if d.ndim != 1 : d = np.argmax(d, axis=1)

        acc = 0.0

        for i in range(int(x.shape[0] / batch_size)):
            tx = x[i*batch_size:(i+1)*batch_size]
            td = d[i*batch_size:(i+1)*batch_size]
            y = self.predict(tx)
            y = np.argmax(y, axis=1)
            acc += np.sum(y == td) 

        return acc / x.shape[0]

    def gradient(self, x, d):
        # forward
        self.loss(x, d)

        # backward
        dout = 1
        dout = self.last_layer.backward(dout)
        layers = list(self.layers.values())

        layers.reverse()
        for layer in layers:
            dout = layer.backward(dout)

        # 設定
        grad = {}
        grad['W1'], grad['b1'] = self.layers['Conv1'].dW, self.layers['Conv1'].db
        grad['W2'], grad['b2'] = self.layers['Affine1'].dW, self.layers['Affine1'].db
        grad['W3'], grad['b3'] = self.layers['Affine2'].dW, self.layers['Affine2'].db

        return grad

from common import optimizer

# データの読み込み
(x_train, d_train), (x_test, d_test) = load_mnist(flatten=False)

print("データ読み込み完了")

# 処理に時間のかかる場合はデータを削減 
x_train, d_train = x_train[:5000], d_train[:5000]
x_test, d_test = x_test[:1000], d_test[:1000]


network = SimpleConvNet(input_dim=(1,28,28), conv_param = {'filter_num': 30, 'filter_size': 5, 'pad': 0, 'stride': 1},
                        hidden_size=100, output_size=10, weight_init_std=0.01)

optimizer = optimizer.Adam()

iters_num = 1000
train_size = x_train.shape[0]
batch_size = 100

train_loss_list = []
accuracies_train = []
accuracies_test = []

plot_interval=10



for i in range(iters_num):
    batch_mask = np.random.choice(train_size, batch_size)
    x_batch = x_train[batch_mask]
    d_batch = d_train[batch_mask]

    grad = network.gradient(x_batch, d_batch)
    optimizer.update(network.params, grad)

    loss = network.loss(x_batch, d_batch)
    train_loss_list.append(loss)

    if (i+1) % plot_interval == 0:
        accr_train = network.accuracy(x_train, d_train)
        accr_test = network.accuracy(x_test, d_test)
        accuracies_train.append(accr_train)
        accuracies_test.append(accr_test)

        print('Generation: ' + str(i+1) + '. 正答率(トレーニング) = ' + str(accr_train))
        print('                : ' + str(i+1) + '. 正答率(テスト) = ' + str(accr_test))               

lists = range(0, iters_num, plot_interval)
plt.plot(lists, accuracies_train, label="training set")
plt.plot(lists, accuracies_test,  label="test set")
plt.legend(loc="lower right")
plt.title("accuracy")
plt.xlabel("count")
plt.ylabel("accuracy")
plt.ylim(0, 1.0)
# グラフの表示
plt.show()

 訓練、テストともに200回くらいまで急激にaccuracyが上昇し、その後はほぼ横ばいになることが見て取れる。

深層学習Day2:5.最新のCNN

 ●AlexNet
 2012年にILSVRC(ImageNet Large Scale Visual Recognition Challenge)で優勝したモデル。このモデルの優勝から深層学習に注目が集まったと思われる。
AlexNetでは畳み込み層及びプーリング層(Max Pooling)が5層あり、全結合層が3層ある。初期に考案されたCNNに比べると層が深くなっているため、過学習の対策としてサイズ4096の全結合層の出力でドロップアウトを利用している。

●VGG-16
 13層の畳み込み層と3層の全結合層により構成される。畳み込み層とプーリング層を単純に何層も重ねただけであるにもかかわらず、高い予測精度を持つ。畳み込み層が16層であるものはVGG-19と呼ぶ。

 ●GoogleNet
・2014年に提案されたモデル。名前は最初期の「LeNet」に由来。
 ・22層で構成されており、従来手法とは異なる手法をいくつか用いている。異なるサイズの畳み込み層を並列につないだInceptionモジュールや、ネットワークを中間で分岐させ分類を行い、そこからも損失のフィードバックを得るAuxiliary Lossが使われている。さらに、全結合層を重ねる代わりにGlobal Average Pooling(GAP)を導入している。

※インセプションモジュール、GAPなどは1つ1つの理解自体がかなり時間がかかるものであり、この複合した姿を頭の中でつなげて全体像を描くのは困難。ただ、有名な手法であるため山のように解説サイトがあり、自分にあったものを探すと理解しやすい。私はこちらの動画が最高に理解しやすかった。(このあいしあさんの動画は他のものも抜群に理解しやすい。)

 ●ResNet
 shortcut connectionを用いた残差ブロックを導入し勾配消失問題に対処することで、152層まで層を増やすことに成功した。shortcut connectionは畳み込み層を重ねたものをまたぐように、入力値をそのまま伝える。

 ※これもこちらのあいしあさんの動画がリやいしやすい。

深層学習Day1の確認テスト

●確認テスト1
 ディープラーニングは、結局何をやろうとしているか2行以内で述べよ。また、次の中のどの値の最適化が最終目的か。また、次の中のどの値の最適化が最終目的か。

 ・入力値から求める出力値を出力するようなニューラルネットワークを構築すること。
 ・③重み[W], ④バイアス[b]

●確認テスト2
 次のネットワークを紙にかけ。
 入力層:2ノード1層
 中間層:3ノード1層
 出力層:1ノード1層

●確認テスト3
 この図式に動物分類の実例を入れてみよう。
 (図であるため本レポートでは省略)

●確認テスト4
 この数式をPythonで書け。
   $u=wx+b$

u = np.dot(x, W) + b

●確認テスト5
 1-1のファイルから中間層の出力を定義しているソースを抜き出せ。

z2 = functions.relu(u2)

●確認テスト6
 線形と非線形の違いを図にかいて簡易に説明せよ。
 
図のため本レポートでは省略(直線により構成される線形&非直線の非線形)

●確認テスト7
 配布されたソースコードより該当する箇所を抜き出せ。

z1 = functions.sigmoid(u)

●確認テスト8
 なぜ引き算でなく二乗するか述べよ。
 1/2はどういう意味をもつか述べよ。

 誤差を正の値にするため。
 微分の計算を楽にするため。(本質的な意味はない)

●確認テスト9
 ①~③の数式に該当するソースコードを示し、一行ずつ処理の説明をせよ。

# ソフトマックス関数
def softmax(x):
    if x.ndim == 2: # 次元が2のとき実行
        x = x.T   # xの転置
        x = x - np.max(x, axis=0) # オーバーフロー対策
        y = np.exp(x) / np.sum(np.exp(x), axis=0) # ソフトマックス関数の出力結果をyに代入
        return y.T

    x = x - np.max(x) # オーバーフロー対策
    return np.exp(x) / np.sum(np.exp(x)) #本質的な計算を行っている部分はここだけ

●確認テスト10
 ①~②の数式に該当するソースコードを示し、一行ずつ処理の説明をせよ。

# クロスエントロピー
def cross_entropy_error(d, y):
    if y.ndim == 1: # 次元が1の時実行
        d = d.reshape(1, d.size) # 1×dの要素数の行列に変換
        y = y.reshape(1, y.size) # 1×yの要素数の行列に変換

    # 教師データがone-hot-vectorの場合、正解ラベルのインデックスに変換
    if d.size == y.size:
        d = d.argmax(axis=1) # dが最大となるインデックスを取得

    batch_size = y.shape[0]
    return -np.sum(np.log(y[np.arange(batch_size), d] + 1e-7)) / batch_size # 1e-7を足すことで調整

●確認テスト11
 該当するソースコードを探してみよう。

# クロスエントロピー
network[key]  -= learning_rate * grad[key]

●確認テスト12
 オンライン学習とは何か2行まとめよ。

 新しい学習データを入手する都度パラメータを更新し、学習を進めること。

●確認テスト13
 この数式の意味を図に書いて説明せよ。
 省略($-\epsilon\Delta E$ずつ減る関係 )

●確認テスト14
 誤差逆伝搬法では不要な再帰的処理を避けることができる。既に行った計算結果を保持しているソースコードを抽出せよ。

#  出力層でのデルタ
delta2 = functions.d_sigmoid_with_loss(d, y)
#  b2の勾配
grad['b2'] = np.sum(delta2, axis=0)
#  W2の勾配
grad['W2'] = np.dot(z1.T, delta2)
#  中間層でのデルタ
delta1 = np.dot(delta2, W2.T) * functions.d_relu(z1)
# b1の勾配
grad['b1'] = np.sum(delta1, axis=0)
#  W1の勾配
grad['W1'] = np.dot(x.T, delta1)

●確認テスト15
 2つの空欄に該当するソースコードを探せ。

 ∂E/∂y/ ∂y/∂u

delta2 = functions.d_sigmoid_with_loss(d, y)

$ ∂E/∂y ∂y/∂u ∂u/∂w_(ji) $

grad['W2'] = np.dot(z1.T, delta2)

深層学習Day2の確認テスト

●確認テスト1
 連鎖率の原理を使い、$dz/dx$を求めよ。

  $z=t^2$
  $t=x+y$
  $dz/dx=dz/dt・dt/dx=2t×1=2(x+y)$

●確認テスト2
 シグモイド関数を微分した時、入力値が0の時に最大値をとる。その値として正しいものを選択しから選べ。
 (2) 0.25

●確認テスト3
 重みの初期値に0を設定すると、どのような問題が発生するか。完結に説明せよ。
 全ての重みが均一に更新されてしまい、正しく学習を行うことができない。

●確認テスト4
 一般的に考えられるバッチ正規化の効果を2点挙げよ。
 ・勾配消失問題が起こりづらくなる。
 ・計算を高速に行うことができる。

●確認テスト5
 モメンタム・AdaGrad・RMSPropの特徴をそれぞれ簡潔に説明せよ。

 ・モメンタム…局所最適解にならず、大域的最適解になる。最適値に達するまでの時間が早い。
 ・AdaGrad…勾配の緩やかなものでも最適値に近づくことができる。
 ・RMSProp…局所最適解にならず大域的最適解になる。ハイパーパラメータの調整が必要な場合が少ない。

●確認テスト6
 機械学習で使われる線形モデルの正則化は、モデルの重みを制限することで可能となる、線形モデルの正則化手法の中にリッジ回帰という手法があり、その特徴として正しい物を選択しなさい。
 (a) ハイパーパラメータを大きな値に設定すると、すべての重みが限りなく0に近づく。

●確認テスト7
 下図について、L1正則化を表しているグラフはどちらか答えよ。
 Lasso推定量のグラフ。

●確認テスト8
 サイズ6*6の入力画像を、サイズ2*2のフィルタで畳み込んだ時の出力画像のサイズを答えよ。なおストライドとパディングは1とする。
 (6 + 2*1 -2) / 1 + 1 = 7
 したがって、サイズは7*7

参考文献

 ●JDLA E資格シラバス最新版(2020)
 https://www.jdla.org/wp-content/uploads/2019/09/JDLA_E%E3%82%B7%E3%83%A9%E3%83%90%E3%82%B9_2020%E7%89%88.pdf
 ●「深層学習」(Ian Goodfellow,Yoshua Bengio,Aaron Courville,2016)
 ●「ゼロからつくるPyhon機械学習プログラミング入門」(八谷大岳・講談社)
 ●「ゼロから作るDeep Learning1」(斉藤康毅・オライリー)
 ●「Python機械学習プログラミング 達人データサイエンティストによる理論と実践」(インプレス)
 ●「徹底攻略ディープラーニングE資格問題集 第2版」(インプレス) 

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2