ゼロから作るDeep Learning を読んだ。 以下に、私が書いた追加のサンプルソースを公開する。
https://github.com/Kanda-Motohiro/deep-learning-from-scratch/tree/kanda-andgate/extra
後で気が付いたが、以下にグラフや print 出力を貼っているが、ソースは変わり続けているので、いつのコミットかを書かないと再現しないのだな。
andgate.py
動かすと、
input=[0.0, 0.0] この入力で
predict=-0.2 これを出力して、
loss=0.03 ロスはこれ。
input=[1.0, 1.0] これは、 AND なので唯一、 1 になるケース。
predict=0.8 それなりに大きい出力を返す。
loss=0.018
W1
[[0.52738405] 最終的な重みとバイアスは、以下。
[0.55519332]]
b1
[-0.27730276]
100回の繰り返して、ロスが減少していく様子。
OR, NAND, XOR も同様。なお、1層なので、当然、 XOR は学習できない。
AND 以外の、 w1 * x1 + w2 * x2 + b = 0 のグラフが0から1に収まってくれないのはなんでだろう。
identity_one_layer.py, identity_two_layer.py
4次元のベクトルを恒等変換する。 xI = x
1 1 0 0 0 1
0 * 0 1 0 0 = 0
0 0 0 1 0 0
0 0 0 0 1 0
1層ネットワークで、
学習後の 推測。
input=[1.0, 0.0, 0.0, 0.0]
a1=[ 0.79325363 -0.26406409 -0.26546253 -0.24920298]
softmax=[0.48854969 0.16971549 0.16947832 0.17225649] 正解。
W1 重みベクトル
[[ 0.92819503 -0.30749332 -0.30904317 -0.29713467]
[-0.32130526 0.92911375 -0.30708626 -0.31458164]
[-0.30414914 -0.31541651 0.93164801 -0.29296934]
[-0.31180665 -0.30481498 -0.30119843 0.91427803]]
割ときれいに、対角線に1が立つ。当たり前だけど、期待通り。
二層ネットワークだと、
学習後の推測。
input=[1.0, 0.0, 0.0, 0.0]
a1=[-0.32139773 0.76345102 -0.5200014 -0.59970534]
sigmoid=[0.42033515 0.68210252 0.37285191 0.35441111]
a2=[ 0.4553785 -0.02834332 -0.2108171 -0.20765111]
softmax=[0.37801016 0.23303747 0.19416833 0.19478404] 正解は出ている。
重みベクトル
W1
[[-0.02494517 1.96448052 -0.81192024 -0.52285848]
[ 0.02434888 -0.23171951 0.33093825 -0.77796068]
[-0.95120518 -0.95126104 2.01236834 -1.12049305]
[ 0.70497191 -1.15652712 -1.73441391 2.00556323]]
W2
[[ 0.01769569 0.14736651 -0.91574167 0.75572746]
[ 2.19894864 -0.05918996 -0.90867497 -1.22953452]
[-0.87044909 0.47373558 2.36187422 -1.93707646]
[-0.47026186 -0.69078368 -1.12886358 2.27556755]]
どれが、正解に寄与しているのか、まったくわからん。
これは、きれいにできた時。
初期の重みは、本のままで、ガウス分布。
W1
[[0.01287018 0.01944651]
[0.01372363 0.00512813]]
b1
[0. 0.]
W2
[[0.0012104 ]
[0.00993569]]
b2
[0.]
i=0
input=[0.0, 0.0]
predict=0.004737091011884931
output=0.0
loss=1.12200156274405e-05
input=[1.0, 0.0]
predict=0.15488418333149928
output=1.0
loss=0.3571103717916334
input=[0.0, 1.0]
predict=0.28199557859812036
output=1.0
loss=0.25776517457632403
input=[1.0, 1.0]
predict=0.239891983699022
output=0.0
loss=0.02877408192152592
一万回後、割ときれいに、学習した。
i=9999
input=[0.0, 0.0]
predict=-4.794281638353937e-10
output=0.0
loss=1.1492568213928853e-19
input=[1.0, 0.0]
predict=1.0000000008134853
output=1.0
loss=3.3087914968760607e-19
input=[0.0, 1.0]
predict=1.0000000008299261
output=1.0
loss=3.4438868882003576e-19
input=[1.0, 1.0]
predict=-1.3943401988569804e-09
output=0.0
loss=9.720922950742618e-19
XOR
その時の重み。
W1
[[-3.61518426 -1.56970111]
[-3.53825093 -1.55647933]]
b1
[0.41587981 1.91532731]
W2
[[-3.38635072]
[ 3.17067968]]
b2
[-0.72382004]
なお、 Ian Goodfellow らの本の 6.1 に、 XOR の正解例がある。重みの初期値に正解を入れても、隠れユニットの出力に relu, sigmoid を使ったら離れていく。ま、そりゃそうだ。
xor の学習が、ワイルドに進まない時がある。イテレーションが同じでも平均二乗誤差が 0.1 くらいで下がらない。初期値に依存しているのか?
そのとおりです。以下の84枚目のスライドに、ロスと時間のグラフが、最初、フラットで、突然、下がる場合は、初期値がいいところにないことを疑え、とありました。
http://cs231n.stanford.edu/slides/2017/cs231n_2017_lecture6.pdf
少ないイテレーションで、正解を得ることが多くなった。本のオリジナルソースは、
params['W1'] = weight_init_std * np.random.randn
で、weight_init_std のデフォルトは、 0.01 だった。これは、MNIST に対しては良くても、今やっている xor は2ノードなので小さい。
1/sqrt(2) =~ 0.7 が適切。
commit 527421f
XOR: i=999
loss=0.00824243993741591
これが結果。0 1 1 0 がきれいに出ている。one hot 表現。
a2=
[[0.83665343 0.2020266 ]
[0.03173038 0.94538512]
[0.20563027 0.72069125]
[0.93820779 0.112546 ]]
W1
[[ 1.88731761 3.14720697]
[-1.84820979 -3.75849286]]
b1
[ 0.65061932 -2.32521664]
W2
[[ 1.93071635 -1.61724554]
[-2.18889228 1.94765676]]
b2
[-0.23719551 1.09136018]
4章の train_neuralnet.py は、numerical_gradient がコメントアウトされていて、gradient を使う方が有効。両方を動かして時間を測る。
時間がかかるので、繰り返し数は4にする。最後のグラフ描画はコメントアウトする。
numerical_gradient を使うと、7 分。
kanda_000@kanda-PC MINGW64 ~/git/deep-learning-from-scratch/ch04 (master)
$ time python train_neuralnet.py
[2.288107990544506, 2.294150890928364, 2.2908598289930953, 2.294232361642402]
real 7m0.489s
user 0m0.000s
sys 0m0.031s
gradient を使うと 1.5 秒。
$ time python train_neuralnet.py
[2.288006763510942, 2.2919219831117705, 2.2880881380185514, 2.3045696172245953]
real 0m1.558s
user 0m0.000s
sys 0m0.031s
プロファイルを取ると、行列の掛け算と、 sigmoid, softmax などが大きい。
C:\Users\kanda_000\git\deep-learning-from-scratch\ch04>python -m cProfile -o numerical_gradient.prof train_neuralnet.py
[2.2878350131415606, 2.293287429988916, 2.2986222148985327, 2.295381325719805]
numerical_gradient.prof% sort time
numerical_gradient.prof% stats 20
Tue Apr 30 11:45:19 2019 numerical_gradient.prof
8110913 function calls (8104438 primitive calls) in 435.653 seconds
Ordered by: internal time
List reduced from 2705 to 20 due to restriction <20>
ncalls tottime percall cumtime percall filename:lineno(function)
636168 301.627 0.000 301.627 0.000 {built-in method numpy.core.multiarray.dot}
318084 45.590 0.000 45.590 0.000 ..\common\functions.py:13(sigmoid)
318084 23.948 0.000 43.124 0.000 ..\common\functions.py:31(softmax)
318084 18.956 0.000 409.297 0.001 C:\Users\kanda_000\git\deep-learning-from-scratch\ch04\two_layer_net.py:18(predict)
954275 16.140 0.000 16.140 0.000 {method 'reduce' of 'numpy.ufunc' objects}
318084 11.100 0.000 20.944 0.000 ..\common\functions.py:46(cross_entropy_error)
954256 4.152 0.000 20.662 0.000 C:\Program Files\Python37\lib\site-packages\numpy\core\fromnumeric.py:64(_wrapreduction)
318084 2.857 0.000 2.857 0.000 {method 'argmax' of 'numpy.ndarray' objects}
16 2.123 0.133 434.257 27.141 ..\common\gradient.py:34(numerical_gradient)
318144 1.909 0.000 1.909 0.000 {built-in method numpy.core.multiarray.arange}
636168 1.764 0.000 12.484 0.000 C:\Program Files\Python37\lib\site-packages\numpy\core\fromnumeric.py:1821(sum)
318084 1.314 0.000 11.771 0.000 C:\Program Files\Python37\lib\site-packages\numpy\core\fromnumeric.py:2227(amax)
318084 1.207 0.000 431.448 0.001 C:\Users\kanda_000\git\deep-learning-from-scratch\ch04\two_layer_net.py:30(loss)
318080 0.567 0.000 432.008 0.001 C:\Users\kanda_000\git\deep-learning-from-scratch\ch04\two_layer_net.py:45(<lambda>)
663387 0.520 0.000 0.521 0.000 {built-in method builtins.isinstance}
955071 0.370 0.000 0.370 0.000 {method 'items' of 'dict' objects}
314 0.255 0.001 0.255 0.001 {method 'astype' of 'numpy.ndarray' objects}
1346 0.179 0.000 0.179 0.000 {built-in method nt.stat}
159040 0.125 0.000 0.125 0.000 {method 'iternext' of 'numpy.nditer' objects}
1 0.108 0.108 0.108 0.108 {built-in method _pickle.load}
ソースは、本のオリジナルの TwoLayerNet(input_size=784, hidden_size=50, output_size=10) を使った。
性能はお客さまの環境に依存します。
ローカルには、CPU が古くて動かなかった
C:\>pip install tensorflow
Successfully installed absl-py-0.7.1 astor-0.7.1 gast-0.2.2 grpcio-1.20.1 h5py-2.9.0 keras-applications-1.0.7 keras-preprocessing-1.0.9 markdown-3.1 mock-3.0.2 protobuf-3.7.1 tensorboard-1.13.1 tensorflow-1.13.1 tensorflow-estimator-1.13.0 termcolor-1.1.0 werkzeug-0.15.2 wheel-0.33.1
>>> import tensorflow as tf
ImportError: DLL load failed: ダイナミック リンク ライブラリ (DLL) 初期化ルーチ ンの実行に失敗しました。
Tensorflowを1.6以上にすると、CPUによっては実行できなくなる/tensorflowのバージョン指定インストールの方法
https://arakan-pgm-ai.hatenablog.com/entry/2018/06/21/090000
C:\>coreinfo
Coreinfo v3.31 - Dump information on system CPU and memory topology
AVX - Supports AVX intruction extensions
あら。ほんとに、これだわ。
C:\>pip install tensorflow==1.5.0
Collecting tensorflow==1.5.0
Could not find a version that satisfies the requirement tensorflow==1.5.0 (from versions: 1.13.0rc1, 1.13.0rc2, 1.13.1, 2.0.0a0)
https://github.com/tensorflow/tensorflow/releases/tag/v1.5.1
ソースしかない。
Google Colaboratory でできた
xortensorflow.ipynb を書いた。
pred=[[ 1.0000002e+00 5.9604645e-07] [-1.3113022e-06 9.9999654e-01] [-1.4305115e-06 9.9999666e-01] [ 1.0000025e+00 5.8412552e-06]] L1 weight, bias [array([[-5.405635 , 2.0685875], [-5.809467 , 2.0863163]], dtype=float32), array([ 1.0099111, -2.6031868], dtype=float32)] L2 weight, bias [array([[ 2.3288426, -2.3288226], [ 2.2566118, -2.2565825]], dtype=float32), array([-0.86215305, 1.8621372 ], dtype=float32)]
Successfully installed torch-1.1.0
Successfully installed torchvision-0.2.2.post3
>>> import torch
ModuleNotFoundError: No module named 'numpy.core._multiarray_umath'
C:\>pip3 install --upgrade numpy
Successfully installed numpy-1.16.3
SGD の代わりに Adam を使ったら、劇的に良くなった。今までも、これが効いたのかもしれない。
XOR: i=99
loss=0.000076
pred=tensor([[[ 1.0037, 0.0032], // 0, 1, 1, 0 がきれいに出ている。
[-0.0107, 0.9912],
[-0.0108, 0.9912],
[ 1.0108, 0.0088]]], grad_fn=<AddBackward0>)
L1 weight
tensor([[ 3.5042, 3.5066],
[-6.0890, -6.1215]])
bias
tensor([-5.3999, 1.4088])
L2 weight
tensor([[ 1.4730, 1.5112],
[-1.4167, -1.4690]])
bias
tensor([-0.2170, 1.1897])
が、まったく、わからん。層の数とかオプティマイザとか何も指定しないで、どうやって、動いている?他のフレームワークと違いすぎる。
https://weblab.t.u-tokyo.ac.jp/dl4us/ を、Google Colaboratory https://colab.research.google.com/notebooks/welcome.ipynb で動かした。ありがたい。
サンプルは keras を使うので、私のパソコンでは動かないけど、ホストランタイムを使えばいい。え、TPU も使えるの?
トラブルシュート
downloaded = drive.CreateFile({'id':hoge})
NameError: name 'hoge' is not defined # ま、そりゃそうでしょ。
ECG5000_TRAIN.arff と、ECG5000_TEST.arff の両方が、 zip ファイル中にあって、後者の方が大きいけど、これ、どれを使えばいいの?
あなたのパソコン ==> Google drive ==> Colaboratory カレントディレクトリ、と、ファイルを複写する必要がある。 id は、 pydrive で得る。
Google drive のあなたのフォルダに、ECG5000_TRAIN.arff をアップロードしたら、その id を得る。
https://pythonhosted.org/PyDrive/quickstart.htmlに従って、 drive.ListFile を実行する。
こんなかんじ
title: ECG5000_TRAIN.arff, id: 1GB38MbR4CtayswXhDIhstaaqXdQAzZie
それを指定して、Colaboratory 環境に持ってくる。
downloaded = drive.CreateFile({'id':'1GB38MbR4CtayswXhDIhstaaqXdQAzZie'})
downloaded.GetContentFile('ECG5000.arff') # この名前のファイルができる。
os.listdir(".")
['.config', 'adc.json', 'gdrive', 'ECG5000.arff', 'sample_data']
dataset, meta = arff.loadarff('ECG5000.arff')
できた。