TIM Labs

fujiによるエントリー一覧

今回は、学習して、その結果をファイルにセーブする。

さて、学習結果なのだが、実際には model というDigitsChainクラスのオブジェクトの中に存在するので、このmodelをファイルにセーブすれば良いはずだ。
オブジェクトのセーブ、それもあれこれいっぱいデータが入っているはずのオブジェクトはどうやってセーブすれば良いだろうか?
Pythonには、オブジェクトをsave/loadするときに、オブジェクトを直列化してsaveするのが流儀であり、そのための仕組みが用意されている。

今回は、pickleを利用する。要するに、漬物(=pickle)にしてしまおうという訳だ。
詳しい説明はここではしないので、リンクを先を見るなどして自分で学習しよう。

import pickle
of = open('digitslearnt.pkl','wb')
pickle.dump(model,of)
of.close()
セーブは、たったこれだけで可能になる。 直列化してセーブしたデータの拡張子は".pkl"とする。
ファイル名とモード(バイナリの書き込みモード)でオープンし、そのファイルオブジェクトをofとしている。
次に、pickle.dumpで、セーブしたいオブジェクトと、ファイルオブジェクトを指定することで、ファイルに書き出してくれる。
最後にcloseする。

これだけだ。簡単過ぎる。

次回、別のプログラムで、この'digitslearnt.pkl'をロードしてテストしてみよう。
なので、テストデータもセーブしておこう。

of = open('digitstestdata.pkl','wb')
pickle.dump([xtest,yans],of)
of.close()
こんどは、2つのオブジェクトをセーブしないといけないので、リストにすることで、ひとつのオブジェクトに見えるようにした。 これで ".pkl" ファイルが2つできた。
Chainer$ ls -l *.pkl
-rw-rw-r-- 1 fuji fuji  20440  2月 15 15:56 digitslearnt.pkl
-rw-rw-r-- 1 fuji fuji 158385  2月 15 15:56 digitstestdata.pkl
今回は、ここまで。 次回、これらを読み込んで、テスト可能かどうか確かめよう。
Deep Learningを色々いじってきて、なんとなく学習出来ているのは分かったのだが、学習には結構時間が掛かる。そのため、一度学習した結果をファイルに出力しておき、必要になったときにファイルを読み込むことで学習することなく賢くして、使いたいものである。

ということで、学習結果(脳)のファイルへのsave/loadについて検討してみよう。

そのために、いままで利用してきたプログラムを使おう。

いままでのプログラムは、学習部分も、学習結果の判定のためのテスト部分も1つのファイルになっていたので、まずは2つの部分に分けようと思う。

このとき、学習結果が入っているオブジェクト(脳)は同じでなければならず、プログラムではそれを表すクラスが使われていた。
手書きデータの場合には、次のクラスがそれだ。

class DigitsChain(Chain):
    def __init__(self):
        super(DigitsChain, self).__init__(	
            l1=L.Linear(64,32),		# 1-2層
            l2=L.Linear(32,10),		# 2-3層
        )
        
    def __call__(self,x,y):
        return F.mean_squared_error(self.fwd(x), y)

    def fwd(self,x):
         h1 = F.sigmoid(self.l1(x))
         h2 = self.l2(h1)
         return h2
今までのファイルは、「学習&セーブ」と「ロード&テスト」の2つのファイルに別れる。
このとき、上記クラスは共通だから、これを"digitschain.py"という名前のファイルにする。

Pythonのモジュールは異常に簡単だ。 上のように、何でも良いから、.pyがついたファイルにしてしまえば、それだけでモジュールになってしまう。 他の言語のように、モジュールにするにはあれこれ宣言しないとダメとか全然ない。 そして、そのモジュールをインポートすれば使えるようになる。 記述フォーマットはいくつか種類があるが、モジュール名(=ファイル名)と、インポートする物を記述するのが次である。
from digitschain import DigitsChain
ということで、実際にimportしてみた。
>>> from digitschain import DigitsChain
Traceback (most recent call last):
  File "", line 1, in 
  File "/home/fuji/Study/Python/Chainer/digitschain.py", line 11, in 
    class DigitsChain(Chain):
NameError: name 'Chain' is not defined
>>> 
クラスだけのファイルはダメだった。
Chainというのは親クラスなので、
from chainer import Chain
の1行だけを加えたら、一応エラーは出なくなった。
L.やF.が使われているのにエラーにならないということは、メソッドを定義だけでは中身は検査されず、エラーにならないようだ。
でも、一応、おまじないを最初に全部加えておいた。
 
"digitschain.py"
# Define model

import numpy as np
import chainer
from chainer import cuda, Function, gradient_check, Variable 
from chainer import optimizers, serializers, utils
from chainer import Link, Chain, ChainList
import chainer.functions as F
import chainer.links as L

class DigitsChain(Chain):
    def __init__(self):
        super(DigitsChain, self).__init__(	
            l1=L.Linear(64,32),		# 1-2層
            l2=L.Linear(32,10),		# 2-3層
        )
        
    def __call__(self,x,y):
        return F.mean_squared_error(self.fwd(x), y)

    def fwd(self,x):
         h1 = F.sigmoid(self.l1(x))
         h2 = self.l2(h1)
         return h2
さて、次回は、これをimport して、学習内容をファイルに書き出すことをやってみよう。
前回、学習の進行状況をプリント出力できるようにしたのだが、数字の羅列を見るのは面倒なので、グラフとして見えるようにしよう。 そのために、学習ループの中で、リストresultに、[周回数,学習正解率,テスト正解率]を毎回追加するようにした。
# 学習ループ
result = []

for i in range(100000):
    x = Variable(xtrain)
    y = Variable(ytrain)
    model.zerograds()
    loss = model(x,y)		# lossを求める (forward)
    loss.backward()		# 微分(backward)
    optimizer.update()		# 調整
    if i % 100 == 0:
        lck = check(xtrain,trans,model)
        tck = check(xtest,yans,model)
        result.append([i,lck,tck])
        print("%6d   %6.4f   %6.4f" % (i,lck,tck))

lck = check(xtrain,trans,model)
tck = check(xtest,yans,model)
result.append([i,lck,tck])
print("%6d   %6.4f   %6.4f" % (i,lck,tck))
以上で集めたデータを、matplotlibで表示しやすいように分解し、表示するようにした。 グラフの内容をそのままpngのファイルとして出力もした。
# グラフ
import matplotlib.pyplot as plt
ilist = [d[0] for d in result]
lck   = [d[1] for d in result]
tck   = [d[2] for d in result]
plt.plot(ilist,lck,color="blue")
plt.plot(ilist,tck,color="red")
plt.savefig("digits0graph.png")
plt.show()

そして出力された画像がこれである。
digits0graph.png青が学習データでの成功率で、赤がテストデータでの成功率である。
最初、一気に .90位まで上昇し、その後、上昇ペースがどんどんゆっくりになっている。
青と赤の差が乖離誤差と呼ばれ、この差が激しくなると、過学習に陥っているという。
過学習とは、模擬試験には強いのだが本番はダメとか、練習の王者で本番ではメダルが取れないという感じとでも言えばよいだろうか。
とりあえず、前回で学習ができているらしいことが確認できた。
しかし、それは、延々と学習した後で、テストデータとして温存しておいたデータにより確認しただけだ。
途中の学習状態、つまり、成功率がどのように変化していくのかを見たい!

ということで、最後にあった成功率を求める部分を、関数としてまとめてみた。

# Testデータで学習成果を確認する
def check(data,answer,model):

    xt = Variable(data, volatile='on')	# 学習不要
    yy = model.fwd(xt)

    ans = yy.data
    nrow, ncol = ans.shape
    ok = sum([np.argmax(ans[i,:])==answer[i] for i in range(nrow)])
    return (ok * 1.0)/nrow	# 正解率
データ、正解、モデルを与えると、このモデルを使ってデータを評価し正解との一致率を返す。

この関数(クラス内でないので、メソッドとは言わない)は、テストデータによる評価に使えるのだが、この形式にデータを合わせさえすれば、学習データを用いた場合の正解率も計算できる。

ということであるが、学習データ(教師データ)の正解の形式が違っているので、リストtransに教師データの答えを入れた。
# 学習データ(xtrain,ytrain)とテストデータ(xtest,yans)に分ける
index  = np.arange(N)
xtrain = X[index[index % 3 != 0],:]
ytrain = Y2[index[index % 3 != 0],:]
trans  = Y[index[index % 3 != 0]]	# 追加
xtest  = X[index[index % 3 == 0],:]
yans   = Y[index[index % 3 == 0]]
必要な追加は済んだので、最後の部分を書き換えた。
# 学習ループ

for i in range(10000):
    x = Variable(xtrain)
    y = Variable(ytrain)
    model.zerograds()
    loss = model(x,y)		# lossを求める (forward)
    loss.backward()		# 微分(backward)
    optimizer.update()		# 調整
    if i % 1000 == 0:
        print("%6d   %6.4f   %6.4f" % (i,check(xtrain,trans,model),check(xtest,yans,model)))

print("%6d   %6.4f   %6.4f" % (i,check(xtrain,trans,model),check(xtest,yans,model)))

forループの制御変数iを、forループを抜けてからも使っている。
C言語ならエラーになるところだが、Pythonではそんなことはないのだ。

これで、こんな感じに動いた。
Chainer$ python3 digits0ck.py
     0   0.0751   0.0634
  1000   0.5601   0.5309
  2000   0.6820   0.6477
  3000   0.7821   0.7379
  4000   0.8297   0.7863
  5000   0.8706   0.8280
  6000   0.8890   0.8715
  7000   0.9040   0.8765
  8000   0.9124   0.8865
  9000   0.9249   0.8948
  9999   0.9316   0.9032
Chainer$ 

数字は、「繰り返し回数、教師データでの正解率、テストデータでの正解率」である。

まだまだ成功率上昇中なので、もっともっとループを繰り返してみた。

226000   0.9958   0.9666
227000   0.9958   0.9666
228000   0.9958   0.9699
229000   0.9958   0.9716

学習データでのテストは99.5%を超えて非常に高いが、テストデータでは 97%を超えるのがやっとであった。つまり、過学習状態になっているのが分かる。
これ以上学習させても、このモデルでは成績は微小な変動を繰り返すのみであった。
前回で、データを読み込み、DLのモデルを DigitsChainクラスとして定義した。
今回は、このDigitsChainクラスよりモデルを作り、読み込んでいたデータを使って、学習とテストをやってみる。

実際のプログラムは以下のようになる。
# 学習モデルの初期化

model = DigitsChain()           # モデルの生成
optimizer = optimizers.SGD()
optimizer.setup(model)

# 学習ループ

for i in range(10000):
    x = Variable(xtrain)
    y = Variable(ytrain)
    model.zerograds()
    loss = model(x,y)		# lossを求める (forward)
    loss.backward()		# 微分(backward)
    optimizer.update()		# 調整

# Testデータで学習成果を確認する

xt = Variable(xtest, volatile='on')	# 学習不要
yy = model.fwd(xt)

ans = yy.data
nrow, ncol = ans.shape
ok = sum([np.argmax(ans[i,:])==yans[i] for i in range(nrow)])
print( ok, "/", nrow, " = ", (ok * 1.0)/nrow )		# 正解率
これって、Irisのときと同一に見えるはずだ。 たった1行違うだけ。
model = DigitsChain()           # モデルの生成
つまり、粗い手書き文字用に作ったDigitsChainクラスのオブジェクトを作って、前と同じ変数modelに与えている。

今回の変更は1行、それ以前の変更も数行であり、全体で10行も変更していない。
というか、変更する必要がありそうなところが見つからない。

さて、とりあえず動かしてから考えよう。

Chainer$ python3 digits0.py
546 / 599  =  0.911519198664
Chainer$ 

テスト結果は91.15%の正解率で、ちゃんと動いているようだ。

IrisからDigitsへの変更は、同じクラス分けタイプのデータを使ってクラス分けしたので、僅かな変更で済んだ。
4種のデータからなるIrisと、8x8の画像データからなるDigitsが、ほぼ同じプログラムで動いてしまうのだ。
この適応性の高さは恐ろしいほどだ。

今回は、読み込んで、Irisのときと同様に、画像のデータをX、教師データをYに読み込む。
前回は、出力が3つだったが、今回は数字の0〜9までで10個に変わるのを考えて、以下のように書き換えた。
 
# digitsデータの読み込み
from sklearn import datasets
digits = datasets.load_digits()
X = digits.data.astype(np.float32)
Y = digits.target.astype(np.int)
N = Y.size
Y2 = np.zeros(10 * N).reshape(N,10).astype(np.float32)
for i in range(N):
    Y2[i,Y[i]] = 1.0
このデータを学習データとテストデータに分割する訳だが、データ数が150から1797に増加したので、2/3を学習データに、1/3をテストデータにしてみた。

# 学習データ(xtrain,ytrain)とテストデータ(xtest,yans)に分ける
index  = np.arange(N)
xtrain = X[index[index % 3 != 0],:]
ytrain = Y2[index[index % 3 != 0],:]
xtest  = X[index[index % 3 == 0],:]
yans   = Y[index[index % 3 == 0]]
次に、一番肝心なモデルについて変更する。
Irisのときのモデルのノード構成は、4-6-3 となっていた。中間層が6ノードである。

digitsのとき、入力ノードは8x8の画像なので、64になる。
出力ノードは、0〜9の各値に対してノードがあるので、10になる。
中間層のノードであるが、64と10から適当な値を考えるべきである。
しかし、ここではとりあえず、64の半分の32を与えてみる。

中間層のノード数が変わっても、プログラム中で変更するのは、たった2個所である。
中間層のノード数に名前を付けてしまえば、一箇所にすることも可能だ。

# Define model
class DigitsChain(Chain):
    def __init__(self):
        super(DigitsChain, self).__init__(	
            l1=L.Linear(64,32),		# 1-2層
            l2=L.Linear(32,10),		# 2-3層
        )
        
    def __call__(self,x,y):
        return F.mean_squared_error(self.fwd(x), y)

    def fwd(self,x):
         h1 = F.sigmoid(self.l1(x))
         h2 = self.l2(h1)
         return h2
これでほぼ準備は出来たはずなので、走らせるのは次回にしよう。
元々のプログラムはIrisのデータ用になっていて、そのデータに対して3層のニューラルネットワーク(NN)でDeep Learning をし、学習結果をテストするようになっていた。
このとき、次のような図をイメージするのだ。
この図は、
R for Deep Learning (I): Build Fully Connected Neural Network from Scratch
からのものだ。
あ、これはPythonではなく、RでNNをやる説明のようだ。まあいいか、言語なんて大差ない。

図にはデータの流れが示されていないが、データは左から入り、右に向いて流れていく。
3つの層を構成するノードはタテに並んだ丸で示され、左から、入力層、中間層、出力層になっている。

iris_network.png
この図を、次の『Chainerによる実践深層学習』のIrisのプログラムのうち、上の図に対応した部分だけを示す。

class IrisChain(Chain):
    def __init__(self):
        super(IrisChain, self).__init__(
            l1=L.Linear(4,6),
            l2=L.Linear(6,3),
        )
        
    def __call__(self,x,y):
        return F.mean_squared_error(self.fwd(x), y)

    def fwd(self,x):
         h1 = F.sigmoid(self.l1(x))
         h2 = self.l2(h1)
         return h2

このうち、今注目すべきは、以下の部分だけである。
            l1=L.Linear(4,6),              # 入力層→中間層
            l2=L.Linear(6,3),              # 中間層→出力層

数字が、上の図ときちんと対応しているのが分かるだろう。

入力層の4は、データが4種の値から構成されているからである。

中間層の6は、まあ適当に決めて良いのだが、詳しい説明は面倒なので省略する。

出力層の3は、Irisでは3種類の種の分類(クラス分け)をしたいので、3になっている。


ここまで理解したら、前回説明した8x8のめちゃくちゃ粗い手書き数字データの分類に挑戦してみよう。
ということで、次回につづく。
DLの最初に使われるデータ例が、ほとんどの場合、iris(アヤメ)のデータだ。
3種類のアヤメについて、花びらの長さと幅、がくの長さと幅のデータが、それぞれのアヤメの種類に対して50組ずつデータがあり、全体で150組のデータがある。
これから学習データとテストデータに分けて、学習後、テストデータによりアヤメの種類を正しく分類できるかようになっているか調べるのであった。

でも、これには飽きたので、他のデータで試したい。
そのためには、まず、アヤメのデータがどこに存在し、どのように利用されているかを調べないとダメだ。

from sklearn import datasets
iris = datasets.load_iris()
X = iris.data.astype(np.float32)
Y = iris.target
N = Y.size
Y2 = np.zeros(3 * N).reshape(N,3).astype(np.float32)
for i in range(N):
    Y2[i,Y[i]] = 1.0

この中で肝心なのは最初に1行で、datasetsをインポートし、その中からirisのデータを読み込んでいることが分かる。
そして、scikit-learnのサイトにたどりついた。


scikit-learn_top.png
この中のドキュメントに、それらしい情報があった。

5.2. Toy datasets

scikit-learn comes with a few small standard datasets that do not require to download any file from some external website.

load_boston([return_X_y]) Load and return the boston house-prices dataset (regression).
load_iris([return_X_y]) Load and return the iris dataset (classification).
load_diabetes([return_X_y]) Load and return the diabetes dataset (regression).
load_digits([n_class, return_X_y]) Load and return the digits dataset (classification).
load_linnerud([return_X_y]) Load and return the linnerud dataset (multivariate regression).

These datasets are useful to quickly illustrate the behavior of the various algorithms implemented in the scikit. They are however often too small to be representative of real world machine learning tasks.

この中のload_irisが呼び出されていたのだ。

これを他のものに変えて、元のプログラムをちょっとだけ変更して、動くかどうか確かめよう。

上の表のloadメソッドをクリックすると、それぞれの説明が現れる。説明から、iris to digits がclassificationのためのデータらしいので、とりあえず同じタイプのdigitsを使うことにしよう。

とりあえず、load_digitsに載っているサンプルでデータのロード表示をしてみよう

from sklearn.datasets import load_digits
>>> digits = load_digits()
>>> digits.data.shape
(1797, 64)
>>> import matplotlib.pyplot as plt
>>> plt.gray()
>>> plt.matshow(digits.images[0])
<matplotlib.image.axesimage object="" at="" 0x7f5c88085a90>
>>> plt.show()
データが1797個あり、1つのデータは64個のデータからなる。 matplotlibで最初のデータを表示している。 1つのデータは64個の値からなるのだが、実際は8x8の画像データであることが分かる。 実際に最初のデータの内容を以下のようにして数値で見ると、画像との対応がよく分かる。 scikit-learn_zero.png
>>> X = digits.data.astype(np.float32)
>>> X[0].reshape(8,8)
array([[  0.,   0.,   5.,  13.,   9.,   1.,   0.,   0.],
       [  0.,   0.,  13.,  15.,  10.,  15.,   5.,   0.],
       [  0.,   3.,  15.,   2.,   0.,  11.,   8.,   0.],
       [  0.,   4.,  12.,   0.,   0.,   8.,   8.,   0.],
       [  0.,   5.,   8.,   0.,   0.,   9.,   8.,   0.],
       [  0.,   4.,  11.,   0.,   1.,  12.,   7.,   0.],
       [  0.,   2.,  14.,   5.,  10.,  12.,   0.,   0.],
       [  0.,   0.,   6.,  13.,  10.,   0.,   0.,   0.]], dtype=float32)
>
これから、digitsのデータは1797個の画像データであることが分かる。

とりあえず、データの取得が出来たので、今回はここまで。
せっかくChainerについて書いているのだが、微分とか、まるで数学の基礎を説明していると読んでいて飽きるだろう。早くChainerでの Deep Learning の方法が知りたいであろう。

ということで、突然ではあるが、紹介した『Chainerによる実践深層学習』は、書籍中のプログラムも公開されているので、それを利用しながら話を進めようと思う。

最初に行う Deep Learning は、どこへ行ってもIrisの種の分類だ。
Python からとても簡単に使えるようになっているので、Chainerに限らず、多数の書籍の最初のDLのデータがIrisになっている。
だから、ここでも、そのままIrisのデータを用い、3種のIrisの種の分類をやってみる。

プログラム全体はここでは示さない。 『Chainerによる実践深層学習』
から、プログラムのアーカイブをダウンロードして見て欲しい。
今回は、その中から、 iris0.py という短い簡単なプログラムについて説明する。

以下に、そのプログラムの、初期化、学習ループ、学習結果の評価の部分だけを掲載する。
なお、適当に変更しているので、オリジナルとは若干違う。
また、Python 3で動くように、printのところは変更している。

# 学習モデルの初期化

model = IrisChain()
optimizer = optimizers.SGD()
optimizer.setup(model)

# 学習ループ

for i in range(10000):
    x = Variable(xtrain)
    y = Variable(ytrain)
    model.zerograds()
    loss = model(x,y)		# lossを求める (forward)
    loss.backward()		# 微分(backward)
    optimizer.update()		# 調整

# Testデータで学習成果を確認する

xt = Variable(xtest, volatile='on')	# 学習不要
yy = model.fwd(xt)

ans = yy.data
nrow, ncol = ans.shape
ok = sum([np.argmax(ans[i,:])==yans[i] for i in range(nrow)])
print( ok, "/", nrow, " = ", (ok * 1.0)/nrow )		# 正解率

実行してみよう。
Chainer$ python iris0.py
72 / 75  =  0.96
Chainer$ python iris0.py
68 / 75  =  0.906666666667
Chainer$ python iris0.py
70 / 75  =  0.933333333333
Chainer$ 
>>> 

こんな感じで、プログラムを走らせる度に、学習成果(テストデータの正解率)が異なった。 といっても、いずれも90%を超える正解率になっているので、かなり良い正解率といえるのではないだろうか。

今回は、Deep Learningでよく見る階層に分かれ、層間を多数の線で結んだ図を良く見るであろうが、それに対応するモデルの部分は示さなかった。
プログラムの意味を解説するよりも、プログラムを勝手に変更したり、別のデータを入れるとどんなことになるかなど、真面目に勉強したい人はさっさと書籍を読むであろうから、興味の向くまま勝手な実験を進め、紹介しようと思っている。
cossinx_1.pngどうやら微分ができることが分かった。
といっても、公式として覚えておくべきような簡単なものであった。
今回は、もうちょっと複雑なのをやって、本当に微分できているか確かめよう。
疑い深いのは重要なことである。

難しい式を急に用意しようと思っても、思いつかない。
そういう時は、何かの本のを利用しよう。
と思って背面の本箱を見たら、何とマセマの『微分積分』があった。マセマについては、そのうち紹介しよう。
p77の実践問題9の(2)の微分をしてみよう。
y = cos(sin(x))
以下、前回と同じで、式の部分が異なる。
まず、[-π,π] のの区間を20等分してxに入れる。
以下、前回と同じで、式の部分が異なる。
>>> x = Variable(np.array(np.linspace(-np.pi, np.pi, 21), dtype=np.float16))
>>> y = F.cos(F.sin(x))
>>> y.data
array([ 1.        ,  0.95263672,  0.83251953,  0.68994141,  0.58056641,
        0.54052734,  0.58056641,  0.68994141,  0.83203125,  0.95263672,
        1.        ,  0.95263672,  0.83203125,  0.68994141,  0.58056641,
        0.54052734,  0.58056641,  0.68994141,  0.83251953,  0.95263672,  1.        ], dtype=float16)
>>> y.grad = np.ones((21),dtype=np.float16)
>>> y.backward()
>>> x.grad
array([ -9.67502594e-04,  -2.88574219e-01,  -4.48486328e-01,
        -4.25537109e-01,  -2.51464844e-01,   4.06980515e-04,
         2.51464844e-01,   4.25537109e-01,   4.48730469e-01,
         2.89306641e-01,  -0.00000000e+00,  -2.89306641e-01,
        -4.48730469e-01,  -4.25537109e-01,  -2.51464844e-01,
        -4.06980515e-04,   2.51464844e-01,   4.25537109e-01,
         4.48486328e-01,   2.88574219e-01,   9.67502594e-04], dtype=float16)
これで、ちゃんと微分ができているような気がする。

それでは確認だ。
cos(sin(x))の微分を計算してみよう。
・・・ん、どうすれば良いのだろう。 微分を忘れた。
そういう時のために、ネットがある。
例えば、WolframAlphaを使えば、式だけ与えれば、微分だけでなく積分もしてくれる。

WolframAlphaによると、
cossinx_2.gif となる。 これ以外にも、ネット上にはこんな便利なモノがいっぱい転がっている。

これを元に、検算をしてみた。
>>> dy = - F.cos(x) * F.sin(F.sin(x))
>>> dy.data
array([ -9.67502594e-04,  -2.88574219e-01,  -4.48486328e-01,
        -4.25537109e-01,  -2.51464844e-01,   4.06980515e-04,
         2.51464844e-01,   4.25537109e-01,   4.48730469e-01,
         2.89306641e-01,  -0.00000000e+00,  -2.89306641e-01,
        -4.48730469e-01,  -4.25537109e-01,  -2.51464844e-01,
        -4.06980515e-04,   2.51464844e-01,   4.25537109e-01,
         4.48486328e-01,   2.88574219e-01,   9.67502594e-04], dtype=float16)
>>> x.grad - dy.data
array([ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,
        0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.], dtype=float16)
>>> np.max(np.abs(x.grad - dy.data))
0.0
複雑なのでもできるようだ。
この微分で重要なことは、普通のPythonの関数を使うのではなく、chainerで用意されている関数を使わないといけない。そのために、どの関数も F. となっている。

1変数関数をやってきたが、DLは多変数関数というか、超多変数関数を偏微分しないといけないのだ。
次は、そういうことをしようか、でもどうなるかは気分次第。

このアーカイブについて

このページには、fujiが最近書いたブログ記事が含まれています。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。