言葉の定義から
【Define and Run】
【Define by Run】
前回書いた以下の記事は【Define and Run】つまり静的ニューラルネットワークを設計しました
【深層学習入門】超実践!Chainerと深層学習でシステム解析する方法
今回は↑の記事と同じ課題で【Define by Run】つまり動的ニューラルネットワークを設計します!
!apt -y install libcusparse8.0 libnvrtc8.0 libnvtoolsext1
!ln -snf /usr/lib/x86_64-linux-gnu/libnvrtc-builtins.so.8.0 /usr/lib/x86_64-linux-gnu/libnvrtc-builtins.so
!pip install 'cupy-cuda80' 'chainer'
import math
import random
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from chainer import Chain, Variable
import chainer.functions as F
import chainer.links as L
from chainer import optimizers
オリジナルのネットワーク『MyChain』を作る!
Chainerで使える活性化関数のうち、前回も採用した”relu”と新たに”leaky_relu”を使ってみる。
”relu”と”leaky_relu”を可視化する↓
x = np.arange(-10, 10, 0.1)
x = Variable(np.array(x, dtype=np.float32))
y_r = F.relu(x)
y_lr = F.leaky_relu(x)
# グラフ出力
plt.plot(x.data, y_r.data)
plt.title("relu")
plt.xlabel("x axis")
plt.ylabel("y axis")
plt.grid(True)
plt.show()
plt.plot(x.data, y_lr.data)
plt.title("leaky_relu")
plt.xlabel("x axis")
plt.ylabel("y axis")
plt.grid(True)
plt.show()
今回は、活性化関数のみ動的にします。
実は活性化関数って、まだ謎が多くて「”relu”を使うとなぜ上手くいくのか?」という数学的な根拠があまりないらしい…
流れてきたデータが負数の場合はノイズになるので”relu”を使って除去すると良い…というのが定説
でも、負数を完全に除去するって…なんか勿体なくないですか?
うまく言えないけど、マイナスとはいえ完全になかったことにするなんて…
勉強で苦しいとき!マイナスからのスタート!そこから得られる情報だって必ずあると思うんだよなぁ
ということで、”leaky_relu”を使て、負数の情報も少しだけ順伝播させます(前のノードに流す)。
突然ですが…子供の成長スピードは早い!
最初は私を怖がっていたのに、安全な人だと学習すると、笑顔を見せてくれます。
子供なら、成長と同時に脳内のニューロンが増えたり・減ったり・変化したりすると思いますが…
大人になると身体的な成長が小さい(ほぼ無い?)ので、脳内のニューロン構造ってある程度、固定されてると思います。(←なんとなくね)
でも、お風呂でリラックスしているときにアイデアを閃くことがある!
これって、『いつもと違う活性化関数が働いたのかなぁ』とか考えてしまう!笑
みたいなことを、お風呂でリラックスしているときに閃いたので、実践する!!
class MyChain(Chain):
def __init__(self):
super(MyChain, self).__init__(
l1 = L.Linear(1, 100),
l2 = L.Linear(100, 50),
l3 = L.Linear(50, 1)
)
def predict(self, x, sw_func):
if sw_func == 1:
h1 = F.leaky_relu(self.l1(x))
h2 = F.leaky_relu(self.l2(h1))
else:
h1 = F.relu(self.l1(x))
h2 = F.relu(self.l2(h1))
return self.l3(h2)
# NNモデルを宣言
model = MyChain()
print(model)
# 実験データ用の配列
x = []
y = []
get_values = 0
for i in range(10):
get_values = random.random()
x.append([i])
y.append([get_values])
# データフレーム生成(列基準)
df = pd.DataFrame({'X': x,
'Y': y})
# グラフ出力
plt.plot(x, y)
plt.title("Training Data")
plt.xlabel("input_x axis")
plt.ylabel("output_y axis")
plt.grid(True)
df
x = Variable(np.array(x, dtype=np.float32))
y = Variable(np.array(y, dtype=np.float32))
# x.data
y.data
# print(x)
# print(y)
前回と同じ 8万回 学習させました!
0~1の範囲で乱数を生成し、
なんとなく、閃きを”leaky_relu”ということにし、たまにしか発生しないように設定しました。
rand_val = 0
sw_func = 0
log_sw = []
# 損失関数の計算(二乗誤差(MSE)を採用)
def forward(x, y, model):
# 活性化関数の切替
rand_val = np.random.random()
if rand_val > 0.8:
sw_func = 1
else:
sw_func = 0
log_sw.append([sw_func])
t = model.predict(x, sw_func)
loss = F.mean_squared_error(t, y)
return loss
# 最適化アルゴリズムにAdamを採用
optimizer = optimizers.Adam()
optimizer.setup(model)
# パラメータの学習を繰り返す
loss_list = []
step = []
for i in range(0, 80000): # 10000
loss = forward(x, y, model)
step.append(i)
loss_list.append(loss.data)
# print("loss: {}".format(loss.data))
optimizer.update(forward, x, y, model)
# 学習過程
plt.plot(step, loss_list)
plt.title("Training Data")
plt.xlabel("step")
plt.ylabel("loss")
plt.grid(True)
plt.show()
Lossが下がるところと活性化関数の切替を確認
# 学習過程グラフを一部拡大
plt.plot(step, loss_list)
plt.xlim([7000, 20000])
plt.ylim([0,0.1])
plt.title("Training Data")
plt.xlabel("step")
plt.ylabel("loss")
plt.grid(True)
plt.show()
# 活性化関数の切替
plt.plot(log_sw)
plt.xlim([0,50])
plt.ylim([0,1.5])
plt.title("Activation Function")
plt.xlabel("step")
plt.ylabel("Random")
plt.grid(True)
plt.show()
すごいノイズ乗ってるけど、1万回くらいでlossが急降下しています。
前回は、見られなかった現象…偶然の可能性もあるけど興味深いね!
活性化関数の切替も良い感じにランダムだ(まるで私の脳内のようだ!?)
# 教師データ(実験データ)
plt.plot(x.data, y.data)
plt.title("Training Data")
plt.xlabel("x axis")
plt.ylabel("y axis")
plt.grid(True)
plt.show()
# 推論結果
sw = 1
ym = model.predict(x, sw)
plt.plot(x.data, ym.data)
plt.title("Predict")
plt.xlabel("input x")
plt.ylabel("output ym")
plt.grid(True)
plt.show()
# 推論結果2
xt = [[0.5], [1.8], [2.3], [3.3], [4.5], [6.8], [7.2], [7.7], [8.0], [8.2]]
xt = Variable(np.array(xt, dtype=np.float32))
yt = model.predict(xt, sw)
plt.plot(xt.data, yt.data, "ro")
plt.title("Predict2")
plt.xlabel("input xt")
plt.ylabel("output yt")
plt.grid(True)
plt.show()
# グラフを重ねる
plt.plot(x.data, y.data)
plt.plot(x.data, ym.data)
plt.plot(xt.data, yt.data, "ro")
plt.title("comparison")
plt.xlabel("input")
plt.ylabel("output")
plt.grid(True)
plt.show()
n = [[5.5]]
n = Variable(np.array(n, dtype=np.float32))
yn = model.predict(n, sw)
print(yn)
活性化関数をreluに固定
# 教師データ(実験データ)
plt.plot(x.data, y.data)
plt.title("Training Data")
plt.xlabel("x axis")
plt.ylabel("y axis")
plt.grid(True)
plt.show()
# 推論結果
sw = 0
ym = model.predict(x, sw)
plt.plot(x.data, ym.data)
plt.title("Predict")
plt.xlabel("input x")
plt.ylabel("output ym")
plt.grid(True)
plt.show()
# 推論結果2
xt = [[0.5], [1.8], [2.3], [3.3], [4.5], [6.8], [7.2], [7.7], [8.0], [8.2]]
xt = Variable(np.array(xt, dtype=np.float32))
yt = model.predict(xt, sw)
plt.plot(xt.data, yt.data, "ro")
plt.title("Predict2")
plt.xlabel("input xt")
plt.ylabel("output yt")
plt.grid(True)
plt.show()
# グラフを重ねる
plt.plot(x.data, y.data)
plt.plot(x.data, ym.data)
plt.plot(xt.data, yt.data, "ro")
plt.title("comparison")
plt.xlabel("input")
plt.ylabel("output")
plt.grid(True)
plt.show()
n = [[5.5]]
n = Variable(np.array(n, dtype=np.float32))
yn = model.predict(n, sw)
print(yn)
推論結果❶❷を観測すると…
という結果が得られた。(僅差だけどね!)
この知見を踏まえ…
入力データに応じて、活性化関数をreluとleaky_reluを切り替える
# 教師データ(実験データ)
plt.plot(x.data, y.data)
plt.title("Training Data")
plt.xlabel("x axis")
plt.ylabel("y axis")
plt.grid(True)
plt.show()
# 推論結果
ym = model.predict(x, sw)
plt.plot(x.data, ym.data)
plt.title("Predict")
plt.xlabel("input x")
plt.ylabel("output ym")
plt.grid(True)
plt.show()
'''
# 推論結果2
xt = [[0.5], [1.8], [2.3], [3.3], [4.5], [6.8], [7.2], [7.7], [8.0], [8.2]]
xt = Variable(np.array(xt, dtype=np.float32))
yt = model.predict(xt, sw)
plt.plot(xt.data, yt.data, "ro")
plt.title("Predict2")
plt.xlabel("input xt")
plt.ylabel("output yt")
plt.grid(True)
plt.show()
'''
# 推論結果3 -入力値から活性化関数を変更-
# log_xi = []
# log_yi = []
sw_i = 0
for i in range(10):
tmp = random.uniform(0.0, 9.0)
xi = [[tmp]]
xi = Variable(np.array(xi, dtype=np.float32))
if xi.data > 5:
sw_i = 1
print('xi = {} ⇒ reluを選択'.format(xi))
else:
sw_i = 0
print('xi = {} ⇒ leaky_reluを選択'.format(xi))
yi = model.predict(xi, sw_i)
plt.plot(xi.data, yi.data, "bo")
# plt.title("Predict3")
# plt.xlabel("input xi")
# plt.ylabel("output yi")
# plt.grid(True)
# plt.show()
# グラフを重ねる
plt.plot(x.data, y.data)
plt.plot(x.data, ym.data)
# plt.plot(xt.data, yt.data, "ro")
# plt.plot(xi.data, yi.data, "go")
plt.title("comparison")
plt.xlabel("input")
plt.ylabel("output")
plt.grid(True)
plt.show()
n = [[5.5]]
n = Variable(np.array(n, dtype=np.float32))
yn = model.predict(n, sw)
print(yn)
ズルできないように、最後の入力値は乱数で与えてみたけど…
ちょっち怖いくらい精度良いですね!!笑
人生で初めて動的ニューラルネットワーク設計に挑戦してみましたが、深層学習の楽しさを再確認しました!!
今回は、活性化関数のみ動的にしましたが、ネットワーク構造(ノード数や層の深さ)も動的にできます。
学習時に活性化関数をランダムで切り替えましたが、ランダム以外の条件で切り替えても面白いかと
【Define by Run ポイント】
組み合わせは星の数ほどありそうですね!!
私 1人では、すべての組み合わせを試すのは不可能です…
でも、本記事を読んくれた人は、動的ニューラルネットワークの設計方法を習得できたと思う!!
私に代わって、自分オリジナルのモデル(MyChain)を作ってみてほしい!!
本記事を参考に…
なんて人が現れたディープラーニングお兄さんは最高に嬉しいです!!!!!
奥が深い深ーーい!深層学習を思いっきり楽しんで下さいな!
(完)