深層学習づくりの顛末(Python3のコード付き)

深層学習(ディープラーニング)つくる!って前の記事で言いましたが、結果書いてませんでしたね。

無事に一応形にはなりました。

まず結果です。3種類のお花の判別で、93.3パーセントの確率で正解を言えるようになりました。

(アイリスデータってやつです)

ニューラルネットワークって?

 こういうやつです。なんか、すごそう。

どう使ったの?

左に入力があって、入力からセルを伝って右に情報が流れてくって仕組みです。一番右に判別したいものがあり、どこのセルが光るかによって結果が出ます。

7エポック、120このサンプル、30個のテストデータでやりました。

結果

交差エントロピーが減少しました。前半でほとんど学習が終わりました。

右に行けば行くほど誤差が下がってることがわかると思います。

面白いこと

このオレンジ色の部分の重みの推移をグラフにすると、、、

こうなりました!

これは学習がどう進んだかを表すグラフなのですが、だんだんと一定の方向に値が移動しているのがわかると思います。そして、最終的にはほぼ一定値に収まっています。

収束してますね。。。すごい、、

プログラム

拙いプログラムを丸投げしておきます。

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure()
import math
np.set_printoptions(formatter={'float': '{: 0.3f}'.format}) #桁を揃える
df = pd.read_csv('fishersiris.csv', sep=',')
a_df = df.values
fisher_data = np.delete(a_df, 1, 1)
answer = np.zeros((fisher_data.shape[0], 3))
answer_data = fisher_data[:, 0]
# 正解データをベクトル化(one hot表現)
for i in range(answer_data.shape[0]):
   if answer_data[i] == 1:
       answer[i] = [1, 0, 0]
   elif answer_data[i] == 2:
       answer[i] = [0, 1, 0]
   elif answer_data[i] == 3:
       answer[i] = [0, 0, 1]
   else:
       print('lack of dim of output vector')
fisher_data = np.delete(fisher_data, 0 ,1)
#学習データの正規化
def normalize(x):
   x_min = np.min(x, axis = 0)
   x_max = np.max(x, axis = 0)
   return (x - x_min)/(x_max-x_min)
fisher_data_normalized = normalize(fisher_data)
#学習データとテストデータに分離(2/3は学習データ)
num_learn = (fisher_data_normalized.shape[0] // 5) * 4
fisher_data_learn = fisher_data_normalized[:num_learn, :]
answer_learn = answer[:num_learn, :]
fisher_data_test = fisher_data_normalized[num_learn:, :]
answer_test = answer[num_learn:, :]
# ここから深層学習
# 関数の定義
def sigmoid(x):
   x = np.where(x < 1e-9, 1e-9, x)
   return 1.0 / (1.0 + np.exp(-x))
def softmax(x):
   c = np.max(x)
   exp_a = np.exp(x - c)
   sum_exp_a = np.sum(exp_a)
   y = exp_a / sum_exp_a
   return y
def ReLU(x):
   return np.maximum(0, x)
def ReLU_deriv(x):
   x[x <= 0] = 0
   x[x > 0] = 1
   return x
def cross_entropy_error(d, z):
   delta = 1e-9
   return -np.sum(d * np.log(z + delta))
#エポック数
epoch = 7
#レイヤーの定義
class layer:
   err = 0
   def __init__(self, number):
       self.l = number
       self.u = np.zeros(self.l)
       self.z = np.zeros(self.l)
       self.delta = np.zeros(self.l)
       self.z_deriv = np.zeros(self.l)
       self.bias = np.ones(self.l)
   def connect(self, prev_layer):
       self.W = np.random.normal(0, 0.3, (self.l, prev_layer.l))
       self.err_derivedW = np.zeros((self.l, prev_layer.l))
       self.W_save = np.zeros((num_learn*epoch, self.l, prev_layer.l))
#入力層>全結合60(ReLU)>出力層3(Softmax)
#各層の定義
input = layer(4)
hidden = layer(60)
output = layer(3)
hidden.connect(input)
output.connect(hidden)
errs = np.zeros(fisher_data_learn.shape[0]*epoch)
#学習
for j in range(epoch):
   for i in range(fisher_data_learn.shape[0]):
       # ここにニューラルネットワークを記述
       input.u = fisher_data_learn[i, :]
       # 活性化
       input.z = ReLU(np.float64(input.u))
       # 順伝播
       hidden.u = np.dot(hidden.W, input.z) + hidden.bias
       hidden.u = np.float64(hidden.u)
       hidden.z = ReLU(hidden.u)
       output.u = np.dot(output.W, hidden.z) + output.bias
       output.u = np.float64(output.u)
       output.z = softmax(output.u)
       # 誤差計算
       output.err = cross_entropy_error(answer_learn[i], output.z)
       errs[i+j*fisher_data_learn.shape[0]] = output.err
       #print(input.z)
       #print(hidden.u)
       #print(hidden.z)
       #print(output.z)
       # デルタの計算
       output.delta = output.z - answer_learn[i]
       hidden.z_deriv = ReLU_deriv(hidden.u)
       hidden.delta = np.dot(output.W.T * hidden.z_deriv.reshape(-1,1),output.delta)
       # 誤差の重みによる微分を求める
       output.err_derivedW = np.outer(output.delta, hidden.z)
       output.W = output.W - 0.1 * output.err_derivedW
       hidden.err_derivedW = np.outer(hidden.delta, input.z)
       hidden.W = hidden.W - 0.1 * hidden.err_derivedW
       #あってるか確かめる
       output.z = np.where(output.z == np.amax(output.z),1,0)
       if np.allclose(output.z,answer_learn[i]):
           print('correct')
       else:
           print('false')
       output.W_save[i+j*num_learn] = output.W
       hidden.W_save[i + j * num_learn] = hidden.W
#テスト
correct_rate = 0
for i in range(fisher_data_test.shape[0]):
   # ここにニューラルネットワークを記述
   input.u = fisher_data_learn[i, :]
   # 活性化
   input.z = ReLU(np.float64(input.u))
   # 順伝播
   hidden.u = np.dot(hidden.W, input.z) + hidden.bias
   hidden.u = np.float64(hidden.u)
   hidden.z = ReLU(hidden.u)
   output.u = np.dot(output.W, hidden.z) + output.bias
   output.u = np.float64(output.u)
   output.z = softmax(output.u)
   # あってるか確かめる
   output.z = np.where(output.z == np.amax(output.z), 1, 0)
   if np.allclose(output.z, answer_learn[i]):
       correct_rate += 1
correct_rate/=fisher_data_test.shape[0]
print(correct_rate)
#学習曲線
#plt.plot(errs)
#plt.title("Cross Entropy Error")
#plt.xlabel("Learning")
#plt.ylabel("Cross Entropy Error")
plt.plot(hidden.W_save[:10,:,3])
plt.title("HiddenLayer W1j Weight Transition")
plt.xlabel("Learning")
plt.ylabel("Weight")
plt.show()

今度は畳み込みとLSTMもやりたいです。

畳み込みはクラス作ってる途中で重み行列がわけわからなくなって停滞中です。

時系列データから何やってるか予測できたら面白そうなので、LSTMっていうのをちゃんとやってみたいですが。

今はPHPを習得しているので他のNoteもご査収いただければ嬉しいです!

ではではー

この記事が気に入ったらサポートをしてみませんか?