とりあえずディープに行く~Chainer導入~
始めに言っときますが、
NVIDAとかGPUはラボにはあるけど、使いません。
AWSとか巷にあるけど使いません。
ってことで、ラボの普通のマシンで頑張ります。
きっと精度は悪いだろう。そんなことは気にしなし
今回の目標
今回は精度とかの話ではなくて、Deeplearningを使って何かしたいねぇから始まって
とりあえず、Chainer使ってなんか掴んでみよう。そんなスタンスです
ってことで、
Chainerを入れよう
しっかりGPU積んでいると、いろいろ設定が必要ですが、、、、
ubuntuではこれでまぁうまくいきました。
※すでにnumpyとかscipyとか入っていれば問題ないっぽい。
1 |
$ pip install --user chainer |
要は、それなりに解析とかやってきたマシンには簡単にはいるようです
一方の、Macは
1 2 3 4 |
sudo pip install six sudo pip install pillow sudo pip install h5py sudo easy_install --upgrade numpy |
という様に3つパッケージいれてnumpyのバージョンを無理やり上げました。(超大量のエラー吐き散らかしているが・・・)
一応これで、僕的には困らなかった。解析用にseabornとか入れるとかはまた別
そもそもニューラルネットってなんじゃっけ?
NNって難しいよなぁ。わかる。
解説するか?すこしな。俺もたまに忘れるから
数式は一切使わない。嫌いだもの。
ニューロンって何?
ニューロンはこんな感じではないけど、だいじなのは生物で習ったニューロンと同じで、
入力がいっぱいあって、合わせて一定の閾値超えると次に伝わるって仕組みな。確か、、、
それを模式化すると・・・
いろんな入力を受け付けて出力するけど、ある入力に対して重み付けをする。
出力の基準を関数に任してあげる。
式は z=(weight)*(input)+(bias) で z の和をとって、 (output) = func(sum(z))みたいなノリで
関数ってのhが活性化関数っていって、tanhやsigmoid、relus関数に基づいたりする。
で、こいつらニューロン(以下ノード)をまとめて層をつくるわけだ。
もちろん入力層は入力次元分だけ、出力層は出力次元分だけノードがある。
中間層は何層でもいいし、各層何ノードでもいい。でも、多くなるとその分計算量が・・・
ってなるから、マシンパワーで倒せるけど、ぶっちゃけ過学習が怖いところ
層を最初に作る。
weightとbias(なくてもいい)とか初期値をきめたら、とりあえずなんかそれっぽいものはできる。
プログラムのinitの部分のl1が入力、l2が中間、l3出力層。見ての通りひな型。
とりあえず入力して出力する。
当然誤差がヤバい。誤差関数を定義して修正しよう。
修正はそこらの機械学習と同じで、教師-予測の差を取る。それに基づいてweightとbiasを変えればいい。
これが、順伝搬。ちなみに交差エントロピーが誤差関数になったり、、、する
どうやって変えていくの?
ここで終わりからどんどん修正かければいいんじゃん?ってなる。辻褄をあわせていく感じ
でも、そのつじつま合わせが超絶だるい。
要は逆の動きをするので、いままで和を取ってきた身としては微分の嵐が吹き荒れる。
微分の連鎖律を駆使して頑張る、このへんの式は興味で・・・ってか一度手計算しとこうな。昔やったけど、たしか中間か最後かの2タイプの式。
これが、逆伝搬
めでたく、更新式ができました。
ガンガン修正します。修正方法は、少しずつだったり一括だったり・・・
で、何回も回す。一回をepochとかいう。だんだん損失関数とかaccuracyがよくなる。
一回にどれくらい更新するかってのははoptimizerてのがやってて、方法がいっぱいあるっぽい。
みんなadamだからadamだけども
はい。洗練されたニューラルネットの出来上がり
これで、かんせいだけど。
入力して、最も確率高い次元のところが答えとかかな?まぁ設定次第。
層の数、層の中のノード数、マシンパワーが精度と時間のボトルネックだよね・・・
Chainerの〇〇なところ
値は32bitすなわち、float32, int32の世界。numpyがfloat64なので変換は必須だし、カテゴリ変数はダミー変数にしないとね。
だから、結構データづくりがだるい。
結構思っていたよりかは敷居が高い。でも結果はいただける。
gpu使うとどうなんだろう?めんどいのかなぁ環境設定・・・コードはそんな変わらなそうだけど
最後にコード
あとはコメントアウトにしれっと書いたことは多分忘れちゃいそうなことな。写経に近い。
こんだけフレンドリーに書けば馬鹿な俺でも記憶の彼方にあってもイメージ掴み直せると思う。
こんどは、でかいのしっかりいれよー。テンソルはあと。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 |
# coding: utf-8 import matplotlib.pyplot as plt import numpy as np import pandas as pd from chainer import Chain, cuda, Variable, optimizers import chainer.functions as F # Setting batchsize = 20 # 確率的勾配降下法で学習させる際の1回分のバッチサイズ n_epoch = 20 # 学習の繰り返し回数 n_units = 1000 # 中間層内の数 N = 80 #学習データ数 def read_data_pd(): df = pd.read_csv('iris.csv', names = ['Sepal.Length','Sepal.Width','Petal.Length','Petal.Width','Species'], header=None, dtype = {'Sepal.Length':'float32','Sepal.Width':'float32','Petal.Length':'float32','Petal.Width':'float32','Species':'string'} ) #データの読み込み #### ダミー変数 #### df["Species"] = df["Species"].map( {"Iris-setosa": 0, "Iris-versicolor": 1, "Iris-virginica": 2} ).astype(int) #setosa・versicolor・virginica df[["Species"]]=df[["Species"]].astype(np.int32) #int32に変換 df = (df.reindex(np.random.permutation(df.index))).reset_index(drop=True) #シャッフル x_train = np.array(df.iloc[0:N,0:4].values) y_train = np.array(df.iloc[0:N,4].values) x_test = np.array(df.iloc[N:,0:4].values) y_test = np.array(df.iloc[N:,4].values) test_size = y_test.size return x_train,y_train,x_test,y_test,test_size def read_data_np(): data = np.genfromtxt('iris.csv',dtype = None,delimiter = ",") #CSV iris 読み込み x_train = [[line[0],line[1],line[2],line[3]] for line in data[:N]] y_train = [[line[4]] for line in data[:N]] x_test = [[line[0],line[1],line[2],line[3]] for line in data[N:]] y_test = [[line[4]] for line in data[N:]] test_size = y_test.size return x_train,y_train,x_test,y_test,test_size class chain_model(Chain): def __init__(self): # Prepare multi-layer perceptron model # 多層パーセプトロンモデルの設定 input_dim = 4 # 入力 4次元 output_dim = 3 # 出力 2次元 super(chain_model,self).__init__( l1=F.Linear(input_dim, n_units), l2=F.Linear(n_units, n_units), l3=F.Linear(n_units, output_dim) ) def forward_propagation(self, x_data, y_data, train=True): # Neural net architecture # ニューラルネットの構造 x, t = Variable(x_data), Variable(y_data) #それぞれをvariable型のオブジェクトに変換 h1 = F.dropout(F.relu(self.l1(x)), train=train) #l1 活性化関数としてRELU h2 = F.dropout(F.relu(self.l2(h1)), train=train) #l2 #dropout関数 #隠れ層をランダムに消す。過学習防止 # ratio: 0を出力する確率 # train: Falseの場合はxをそのまま返却する # return: ratioの確率で0を、1−ratioの確率で,x*(1/(1-ratio))の値を返す y = self.l3(h2) #l3 出力 # 多クラス分類なので誤差関数としてソフトマックス関数の # 交差エントロピー関数を用いて、誤差を導出 return F.softmax_cross_entropy(y, t), F.accuracy(y, t) def training (): x_train,y_train,x_test,y_test,test_size = read_data_pd() model = chain_model() optimizer = optimizers.Adam() #学習率とか周りとかの勾配降下 optimizer.setup(model) #optimizer.setup(model.collect_parameters()) を切り替え(非推奨) train_loss = [] train_acc = [] print "----- Learing LOOP -----" for epoch in xrange(1, n_epoch+1): perm = np.random.permutation(N) # array([3,2,4,5,1,0])みたいに入れ替え sum_accuracy = 0 sum_loss = 0 for i in xrange(0, N, batchsize): #バッチサイズごとに学習 x_batch = x_train[perm[i:i+batchsize]] y_batch = y_train[perm[i:i+batchsize]] optimizer.zero_grads() # 勾配を初期化 loss, acc = model.forward_propagation(x_batch, y_batch) # 順伝搬 loss.backward() # 誤差逆伝播で勾配を計算 optimizer.update() # 重みの更新 train_loss.append(loss.data) train_acc.append(acc.data) sum_loss += float(cuda.to_cpu(loss.data)) * batchsize #GPU不使用なので sum_accuracy += float(cuda.to_cpu(acc.data)) * batchsize print 'epoch = {}\t mean loss={}\t accuracy={}'.format(epoch ,sum_loss / N, sum_accuracy / N) return model def testing(model): print "----- Testing LOOP -----" #流れは同じ x_train,y_train,x_test,y_test,test_size = read_data_pd() sum_accuracy = 0 sum_loss = 0 test_loss = [] test_acc = [] for i in xrange(0, test_size, batchsize): x_batch = x_test[i:i+batchsize] y_batch = y_test[i:i+batchsize] loss, acc = model.forward_propagation(x_batch, y_batch, train=False) #テストなのでTRUE test_loss.append(loss.data) test_acc.append(acc.data) sum_loss += float(cuda.to_cpu(loss.data)) * batchsize sum_accuracy += float(cuda.to_cpu(acc.data)) * batchsize print 'test mean loss={}, accuracy={}'.format(sum_loss / test_size, sum_accuracy / test_size) drow_graph("test",test_acc) return def model_optional(model): # 学習したパラメーターを保存 l1_W = [] l2_W = [] l3_W = [] l1_W.append(model.l1.W) l2_W.append(model.l2.W) l3_W.append(model.l3.W) #将来的に保存処理? return def drow_graph(type,acc): # 精度と誤差をグラフ描画 plt.figure() plt.plot(range(len(acc)), acc) st = "acc : " + type plt.legend([st],loc=4) plt.title("Accuracy") plt.plot() plt.show() return if __name__ == '__main__': model = training() testing(model) model_optional(model) |