BETA

fastai動かしてみたLesson2②※殴り書き

投稿日:2019-04-23
最終更新:2019-04-27

fastai動かしてみたLesson2②

今回はこの講義

https://course.fast.ai/videos/?lesson=2

53分あたりから

ここから先は前半部分と比べて数学みたいな話になるけど、恐れる必要はない。

数学

テディベア検出器を作ったときは、テディベアの画像から数値を取り出し、関数を使って1つの数(画像上の数値)を3つの数(category)に変換した。

ここでは手書きの数字画像のピクセルのdigitを取り出し、適当な関数を使って10個の数(category)に変換する。

まず初めにしたの関数から考え始める

$$ (y = ax+b)$$
$$a:傾き、b:切片$$

この式は以下のように書き換えていくことができる

$$y = a_1x + a_2$$

さらに書き換えると、

$$y = a_1x + a_2×1$$

さらに、

$$y = a_1x_1 + a_2x_2$$
$$x_2 = 1$$

最終的に、

$$y_i = a_1 x_{i,1} + a_2 x_{i,2}$$

と書き換えることができる。これは、行列として書き換えることができ、

$$\vec{y} = X \vec{a}$$

とすることができる。

行列の計算の仕方は割愛。動画見るとよくわかります(68分あたり)。

Stochastic Gradient Descent(SGD):確率的勾配降下法

このグラフで線形回帰問題に取り組んでみよう。

数字は適当なので、x軸が温度、y軸がアイスの販売数とか、そんな風に考えておけばよい。

まず初めに、いくつかの合成(?)したデータを作る。

%matplotlib inline  

from fastai import *  
n=100  
x = torch.ones(n,2)   
x[:,0].uniform_(-1.,1)  
x[:5]  

tensor([[-0.1338, 1.0000],
[-0.4062, 1.0000],
[-0.3621, 1.0000],
[ 0.4551, 1.0000],
[-0.8161, 1.0000]])

基本的にこのデータを作成する方法は係数aによって行われる(?)

$$y_i = a_1 x_{i,1} + a_2 x_{i,2}$$

ここでは

$$a_1 = 3, a_2 = 2$$

として考える。

a = tensor(3., 2); a

3.のように数字に.をつけるとfloat型として考える。

$$x_{i,2} = 1$$

であるので、xはこのように書くことができる。

x = torch.ones(n, 2)  
x[:, 0].uniform(-1., 1)  
x[:5]  

tensor([[-0.1338, 1.0000],
[-0.4062, 1.0000],
[-0.3621, 1.0000],
[0.4551, 1.0000],
[-0.8161, 1.0000])

のようになる。

x = torch.ones(n, 2)  

はn×2で中身が1であるtensorを作る。

x[:, 0].uniform(-1., 1)  

xのすべての行の0番目の数を、-1~1のどれかにランダムに変更する

リストの中の0番目はx1で、1番目はx2を表している。

ここから、a=(3, 2)であるとわからないものと考えていく。

そもそもなぜaを求めるのか?

それはもし上記のランダムな100個の点にフィットするようなこれらの2つの値を見つけることができれば、任意の関数をピクセルの値から可能性に変換できるということにつながるからである。

このaを求める方法は、ResNet34に含まれる5億の値に対して、フィットするaを求めることと同じである。

Loss Function(損失関数)とは

ランダムな100個の点に対して、赤線(y=a1x1+a2x2)を適当に引いてみる。

点と赤線の間の距離を見て、より距離が短くなる方に近づけていき、最終的に黄色の線ようになる。

その距離を最小にする線$$y=a_1x_1+a_2x_2$$の中に係数aが含まれる。

これをPythonで書くとこうなる。

def mse(y_hat, y):  
    return ((y_hat-y)**2).mean()  

この考え方をMean Squared Error(MSE : 平均二乗誤差)という。

MSEはLoss Functionであり、どれぐらい赤線が良いものかを表すものである。

ここで、まず初めにa=(-1, 1)であると考えてみる。

a = tensor(-1., 1.)  

aを使ったランダムな推定を使って計算してみる。

[email protected]はxとaの掛け算である。

y_hat = [email protected]  
mse(y_hat, y)  

tensor(8.8945)

y_hatは予測値であり、y_hatとyを使ったMSEが損失である。

y_hatをさっきのグラフ上に表示する。オレンジ色の点。

ここから、より損失を小さくしてFitさせていく。

どうやってよくしていくかというと

$$y = a_1x_1 + a_2x_2$$
の傾き(a1)や切片(a2)を変化させていく事で、改善していく。

ここで、改善する関数を以下に示す。

def update():  
    y_hat = [email protected]  
    loss = mse(y, y_hat)  
    if t % 10 == 0: print(loss)  
    loss.backward()  
    with torch.no_grad():  
        a.sub_(lr * a.grad)  
        a.grad.zero_()  

予測値(y_hat)と損失(MSE)を求めた後、backward()で逆伝搬する。
そして、aの値を(a - 学習率×勾配)に更新する
最後に勾配を0にする(?)。
これを実際に動かしてみると、

lr = 1e-1  
for t in range(100):  
    update()  

tensor(8.8945, grad_fn=)
tensor(1.6115, grad_fn=)
tensor(0.5759, grad_fn=)
tensor(0.2435, grad_fn=)
tensor(0.1356, grad_fn=)
tensor(0.1006, grad_fn=)
tensor(0.0892, grad_fn=)
tensor(0.0855, grad_fn=)
tensor(0.0843, grad_fn=)
tensor(0.0839, grad_fn=)

になる。

最終的なy_hatはこうなる。

この後に上記のy=a1x1+a2x2を改善するアニメーションを簡単に作っていたので、動画の106分当たりを見てください。gifを貼るのがめんどくさい。

Lesson2はここまで。

今週中にLesson3を見てブログ書きます(4月23日)。

参考:
https://github.com/hiromis/notes/blob/master/Lesson2.md

技術ブログをはじめよう Qrunch(クランチ)は、プログラマの技術アプトプットに特化したブログサービスです
駆け出しエンジニアからエキスパートまで全ての方々のアウトプットを歓迎しております!
or 外部アカウントで 登録 / ログイン する
クランチについてもっと詳しく

この記事が掲載されているブログ

大学生の書きなぐりブログ 間違ってる事も書いてるので自己責任で勉強しましょう

よく一緒に読まれる記事

0件のコメント

ブログ開設 or ログイン してコメントを送ってみよう
目次をみる
技術ブログをはじめよう Qrunch(クランチ)は、プログラマの技術アプトプットに特化したブログサービスです
or 外部アカウントではじめる
10秒で技術ブログが作れます!