空飛ぶロボットのつくりかた

ロボットをつくるために必要な技術をまとめます。ロボットの未来についても考えたりします。

機械学習のお勉強(DeepLearning from 0)

参考図書

O'Reilly Japan - ゼロから作るDeep Learning

Deep Learning

end-to-endなmachine learningであり、入力から出力までを学習し、特徴量を抽出したり人が行う作業がない。

機械学習はデータが命。

  • 汎化能力が大事(誰かが書いた文字を認識でくできる)
  • 過学習、overfitting(ある人が書いた文字のみしか判断できない)👈シミュレーターなどを用いて集めたデータ等では起きやすい

パーセプトロン

簡単な実装

def AND(x1,x2):
    w1, w2, theta = 1, 1 ,1.5
    tmp = x1*w1 + x2*w2
    if tmp <= theta:
        return 0
    elif tmp > theta:
        return 1

w1=1,w2=1,theta=0.5でOR

w1=-1,w2=-1,theta=-1.5でNAND

が表現できる

重みとバイアスの導入

wが重み、bがバイアス

import numpy as np

def AND(x1,x2):
    x = np.array([x1,x2])
    w = np.array([1.0,1.0])
    b = -1.5
    tmp = np.sum(w*x) + b
    if tmp <= 0:
        return 0
    else:
        return 1

しかし、単層パーセプトロンではXORは表現できない

多層パーセプトロン

上記のANDど同様にOR,NANDを作ったとすると以下のように多層にすることでXORを表現することができる

def XOR(x1,x2):
    s1 = NAND(x1,x2)
    s2 = OR(x1,x2)
    y = AND(s1,s2)
    return y

1層目:x ⇒ 2層目:s ⇒ 3層目:y

ニューラルネットワーク

活性化関数

ステップ関数 👈パーセプトロン

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

シグモイド関数 👈ニューラルネットワーク

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

ReLU関数 👈ニューラルネットワーク

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

重要なことは非線形の関数であるということ。 線形関数では層を深くしても隠れ層のないネットワークになり、多層にする意味がなくなってしまう。

出力層の活性化関数

恒等関数 👈回帰問題に使用

def identity_function(x):
    return x

ソフトマックス関数 👈分類問題に使用

def softmax(a):
    exp_a = np.exp(a)
    sum_exp_a = np.sum(exp_a)
    y = exp_a / sum_exp_a
    
    return y
  • ソフトマックスの出力の総和は1になるという性質があり、この性質により出力を確率と解釈することができる。
  • 学習と推論のうち、学習の際にこの関数が関係してくる。

3層のニューラルネットワーク

def init_network():
    network = {}
    network['W1'] = np.array([[0.1,0.3,0.5],[0.2,0.4,0.6]])
    network['b1'] = np.array([0.1,0.2,0.3])
    network['W2'] = np.array([[0.1,0.4],[0.2,0.5],[0.3,0.6]])
    network['b2'] = np.array([0.1,0.2])
    network['W3'] = np.array([[0.1,0.3],[0.2,0.4]])
    network['b3'] = np.array([0.1,0.2])

    return network

def forword(network, x):
    W1, W2, W3 = network['W1'], network['W2'], network['W3']
    b1, b2, b3 = network['b1'], network['b2'], network['b3']

    a1 = np.dot(x, W1) + b1
    z1 = sigmoid(a1)
    a2 = np.dot(z1, W2) + b2
    z2 = sigmoid(a2)
    a3 = np.dot(z2, W3) + b3
    y = identity_function(a3)

    return y

network = init_network()
x = np.array([2.0,3.0])
y = forword(network,x)
print y #[ 0.32882937  0.72300564]

バッチ処理

一枚の画像データ784(28×28)を入力とするのではなく、百枚の画像データをまとめて100×784と入力するようなとき、このまとまりをバッチと呼ぶ。

このように行列計算(大きな配列)に落とし込むことで計算の高速化が可能。

学習

以下に述べる、損失関数、ミニバッチ、勾配、勾配降下法が重要である。

学習の手順(SGD:確率的勾配降下法

  1. ミニバッチ
  2. 勾配の算出
  3. パラメータの更新
  4. 繰り返す

損失関数

損失関数を設定するのは微分の役割が関係しています。

微分が0となりにくい性質があり、これはニューラルネットワークの学習において重要な性質である。

これによって、損失関数が小さくなるような重みとバイアスを探索(学習)することができる。

二乗和誤差
def mean_squared_error(y,t):
    return 0.5 * np.sum((y-t)**2)
  • one-hot表現

出力 = [0.3,0.6,0.1]👈ソフトマックス関数により総和 = 1

正解ラベル = [1,0,0]

交差エントロピー誤差
def cross_entropy_error(y, t):
    delta = 1e-7←発散防止
    return -np.sum(t * np.log(y+delta))

ミニバッチ学習

100000枚の写真から1000枚を無作為に選んで学習を行う。

np.random.choice(train_size, batch_size)

勾配

勾配(微分に負をかけたもの)が示す方向は関数の値を減らす方向になる。

↓数値微分。シンプルだが計算に時間がかかる。

def numerical_gradient(f,x):
    h = 1e-4 # 0.0001
    grad = np.zeros_like(x)

    for idx in range(x.size):
        tmp_val = x[idx]
        x[idx] = tmp_val + h
        fxh1 = f(x)

        x[idx] = tmp_val - h
        fxh2 = f(x)

        grad[idx] = (fxh1 - fxh2)/(2*h)
        x[idx] = tmp_val

    return grad

この勾配の計算を高速に求める手法として、誤差逆伝播法が存在する。

勾配降下法

勾配方向に一定距離だけ進み、そこで勾配を求め再度進む。これの繰り返しによって関数の値を減らす。

以下の式のlrは学習率(learning rate)はあらかじめ人が決める(試行錯誤的に決める)必要があり、ハイパーパラメータと呼ばれる。

このパラメータはバイアスや重みと異なり自動で決めることはできない、かつ、正しく学習するうえで重要。

def gradient_descent(f, init_x, lr = 0.01, step_num = 100):
    x = init_x
    
    for i in range(step_num):
        grad = numerical_gradient(f, x)
        x -= lr * grad
        
    return x

誤差逆伝播

学習の手順の勾配の算出で用いる。

 計算グラフ

局所的な計算の組み合わせで、複雑な計算を表現できる。微分を効率よく計算できる(チェインルールをうまく利用)。

  1. 計算グラフを構築
  2. 計算グラフ上で計算を左から右へ(順伝播)、右から左へ(逆伝播)進める
加算レイヤ
class AddLayer:
    def __init__(self):
        pass

    def forword(self, x, y):
        out = x + y
        return out

    def backward(self, dout):
        dx = dout * 1
        dy = dout * 1
        return dx, dy
乗算レイヤ
class MulLayer:
    def __init__(self):
        self.x = None
        self.y = None

    def forword(self, x, y):
        self.x = x
        self.y = y
        out = x * y

        return out

    def backward(self, dout):
        dx = dout * self.y
        dy = dout * self.x

        return dx, dy
ReLUレイヤ
class ReluLayer:
    def __init__(self):
        self.mask = None

    def forword(self, x):
        self.mask = (x <= 0)
        out = x.copy()
        out[self.mask] = 0

        return out

    def backward(self, dout):
        dout[self.mask] = 0
        dx = dout
        return dx
Sigmoidレイヤ
class Sigmoid:
    def __init__(self):
        self.out = None

    def forword(self, x):
        out = 1 / (1 + np.exp(-x))
        self.out = out

        return out

    def backward(self, dout):
        dx = dout * (1.0 - self.out) * self.out

        return dx
バッチ版Affinレイヤ

順伝播で行う行列の内積はアフィン変換と呼ばれる

class Affine:
    def __init__(self, W , b):
        self.W = W
        self.b = b
        self.x = None
        self.dW = None
        self.db = None
        
    def forword(self, x):
        self.x = x
        out = np.dot(x, self.W) + self.b
        
        return out
    
    def backward(self, dout):
        dx = np.dot(dout, self.W.T)
        self.dW = np.dot(self.x.T, dout)
        self.db = np.sum(dout, axis = 0)
        
        return dx
Softmax-with-Lossレイヤ(ソフトマックス関数と損失関数をまとめたレイヤ)

逆伝播の結果がびっくりするくらいキレイ。

逆にこうなるよう、交差エントロピー誤差がうまく設計されている。すばらしい。

class SoftmaxWithLoss:
    def __init__(self):
        self.loss = None
        self.y = None
        self.t = None
        
    def forword(self,x ,t):
        self.t = t
        self.y = softmax(x)
        self.loss = cross_entropy_error(self.y, self.t)
        
        return self.loss
    
    def backward(self, dout=1):
        batch_size = self.t.shape[0]
        dx = (self.y - self.t) / batch_size
        
        return dx
勾配確認

数値微分誤差逆伝播

→数値微分誤差逆伝播法の実装が正しいかを確認するために用いられることが多い

畳み込みニューラルネットワーク(CNN)

これまで、全結合層をAffineレイヤという名前で実装。

全結合層の問題点はデータの形状が無視されてしまうこと。例えば、画像28×28ピクセルの形状を784個のデータとして入力する。

これは、画像の空間的な相関関係を無視しているため、形状に関する情報を生かすことができない。

一方、畳み込み層は形状を維持する。CNNでは入出力データを特徴マップという。

層が深くなるにつれて、抽出される情報はより抽象化(犬や車など高度な情報へと変化)されていくといわれている。

畳み込み演算、フィルター(カーネル)演算

フィルターのウインドをスライドさせながら、それぞれで積和演算を行う。

このフィルターパラメータがこれまでの重みに対応する。バイアスも同様に存在する。

パディング

入力データの周囲に固定データ(0など)を埋めること。これによって出力サイズを調整することができる。

これによって空間の圧縮により、畳み込みができなくなってしますことを防ぐ。

ストライド

フィルターのウインドをスライドさせる間隔。

三次元データの畳み込み演算

入力データのチェンネル数とフィルター数は同じにすること。

フィルター自体を複数用意すると多チャンネルの特徴マップを出力することができる。

よってフィルターの重みデータは4次元のデータ(チャンネル数4、サイズ5×5、フィルター数20)としてあらわすことができる。

バッチ処理

各層を流れるデータは四次元データとなる。

チャンネル数、サイズに加え、バッチ数が付け加えられる。

プーリング層

縦、横方向の空間(サイズ)を小さくする演算。

  • Maxプーリング:対象領域から最大値をとる演算
  • Averageプーリング:対象領域の平均をとる演算

画像認識の分野では主にMaxプーリングが用いられる。

  1. 入力データを展開する
  2. 行ごとに最大値を求める
  3. 適切な出力サイズに整形する

層の深さに関して

簡単な文字認識などでは層は深くないほうが高精度

大規模画像認識のコンペなどでは層が深いものは上位

そして、層を深くするとパラメータを減らすことができる

しかし、層を深くしすぎると性能が劣ることもあった

ResNet

層を深くすることができる手法で、スキップ構造を導入している。

これによって層を深くすることに比例して性能を向上させることができる。

転移学習

学習済みの重みをベースに学習を行う。

課題

如何に畳み込み層の計算を速く行うか。

つまり、いかに速く効率的に積和演算を行うか。

Tips

  • Numpyとforループは相性が悪い。
  • im2col(image to column)という2次元の行列に変換するツールがある。

参考:

GitHub - oreilly-japan/deep-learning-from-scratch: 『ゼロから作る Deep Learning』のリポジトリ

The MIT License (MIT)
Copyright (c) 2016 Koki Saitoh
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

DeepLearningが分かった気になる「ゼロから作るDeepLearning」ざっくりまとめ - SSSSLIDE

今後調べたい理論

画像の特徴量抽出
  • SIFT
  • SURF
  • HOG
識別機
物体検出
  • Faster R-CNN

[1506.01497] Faster R-CNN: Towards Real-Time Object Detection with Region Proposal Networks

  • SegNet

SegNet

  • Deep Q-Network

DQN | DeepMind