はじめに
この記事ではニューラルネットワークの
各種の活性化関数の判定性能の比較結果をまとめています。
対象者として、
- 活性化関数のざっくりとした比較を知りたい人
- どの活性化関数を採用するか検討してる人
- 機械学習を始めようとしてる人
などを想定してます。
活性化関数とは
あるニューロンの入力合計から、出力を決定するための関数です
y = f(\sum_{k=1}^{n} ω_i*x_i + b) \\
f(x)が活性化関数です
本記事で比較する活性化関数
- tanh
- sigmoid
- hard_sigmoid
- softmax
- ReLU
- PReLU
入力層と中間層に上記活性化関数をセットして判定結果の比較を行います
性能評価
実験環境
ツール | 学習回数 | 勾配法 | 損失関数 |
---|---|---|---|
keras | 100回 | Adam | mean_squared_error |
実験対象
マイヤーの三角形の判定を採用しました
https://qiita.com/Oldcastle/items/49e1abdc0dd9c0d628c4
入力データ
三角形の3辺の長さを与えます
判定結果
- 三角形なのか、
- 直角三角形なのか、
- 二等辺三角形なのか、
- 正三角形なのか
を判定します
評価方法
11種類の確認条件の正解数で活性化関数の性能評価を行います
評価条件
- 1 三角形を三角形と判定できるか?
- 2 大きい直角三角形を判定できるか?
- 3 小さい直角三角形を判定できるか?
- 4 大きい二等辺三角形を判定できるか?
- 5 小さい二等辺三角形を判定できるか?
- 6 大きい正三角形を判定できるか?
- 7 小さい正三角形を判定できるか?
- 8 三角形が成立しない3辺の長さ(短い)の時に三角形と判定しないか?
- 9 三角形が成立しない3辺の長さ(長い)の時に三角形と判定しないか?
- 10 1辺が0の場合に三角形と判定しないか?
- 11 1辺がマイナスの場合に三角形と判定しないか?
評価条件の採点方法
-
期待値と結果が完全一致の場合
→ 正解として、1点 とカウントします -
期待値と結果が、一致なし、もしくは、部分一致、の場合
→ 間違いとして、0点 とカウントします例
3辺の長さを3,4,5とした場合、
直角三角形と判断したら、"正解"とし、
ただの三角形と判断したら、"間違い"とし、
三角形ではないと判断したら、"間違い"とします
活性化関数毎の評価結果の合計点で判定性能を評価します
備考
活性化関数毎の得手不得手があるので、
この結果をもって活性化関数の優劣を判断することはできませんが、
判断の材料の1つにはなるかと考えています
tanh
概要
- 主に出力層で採用されることが多い
- 出力範囲 -1.0 ~ +1.0
y = \tanh x = \cfrac{e^x - e^{-x}}{e^x + e^{-x}}
結果
所感
出力層に現在でも採用される人気関数だけあって、正解数が多い
けど、中間層に採用しちゃうと、出力範囲が-1~+1なのがダメなのか、いまいちな気がします
モデル
判定結果の表
判定結果 | 入力 | 期待値 | 期待値(数値) | 結果 | 結果(数値) |
---|---|---|---|---|---|
0 | 間違い | 6.0,4.0,5.0 | ただの三角形 | 1,0,0,0,e=tri | 直角三角形,Righttriangle |
1 | 正解 | 6.0,8.0,10.0 | 直角三角形0 | 1,1,0,0,e=Right | 直角三角形,Righttriangle |
2 | 正解 | 3.0,4.0,5.0 | 直角三角形1 | 1,1,0,0,e=Right | 直角三角形,Righttriangle |
3 | 正解 | 8.0,8.0,10.0 | 二等辺三角形0 | 1,0,1,0,e=Iso | 二等辺三角形,Isoscelestriangle |
4 | 正解 | 4.0,4.0,5.0 | 二等辺三角形1 | 1,0,1,0,e=Iso | 二等辺三角形,Isoscelestriangle |
5 | 正解 | 8.0,8.0,8.0 | 正三角形0 | 1,0,1,1,e=Equ | 正三角形,Equilateraltriangle |
6 | 正解 | 2.0,2.0,2.0 | 正三角形1 | 1,0,1,1,e=Equ | 正三角形,Equilateraltriangle |
7 | 正解 | 4.0,4.0,9.0 | 三角形ではない0 | 0,0,0,0,e=No | 三角形ではない,no |
8 | 正解 | 2.0,2.0,5.0 | 三角形ではない1 | 0,0,0,0,e=No | 三角形ではない,no |
9 | 正解 | 4.0,0.0,9.0 | 三角形ではない2 | 0,0,0,0,e=No | 三角形ではない,no |
10 | 正解 | -1.0,4.0,5.0 | 三角形ではない3 | 0,0,0,0,e=No | 三角形ではない,no |
正解数 = 10 |
sigmoid
概要
- ReLUの登場前は採用事例が多かった
- 出力範囲 0.0 ~ +1.0
y = \cfrac{1}{1 + e^{-x}}
結果
所感
往年の人気関数だけあって、正解数は多い
けど、期待値と判定結果のギャップが多いのが気になりますね
モデル
判定結果の表
判定結果 | 入力 | 期待値 | 期待値(数値) | 結果 | 結果(数値) |
---|---|---|---|---|---|
0 | 間違い | 6.0,4.0,5.0 | ただの三角形 | 1,0,0,0,e=tri | 直角三角形,Righttriangle |
1 | 正解 | 6.0,8.0,10.0 | 直角三角形0 | 1,1,0,0,e=Right | 直角三角形,Righttriangle |
2 | 正解 | 3.0,4.0,5.0 | 直角三角形1 | 1,1,0,0,e=Right | 直角三角形,Righttriangle |
3 | 正解 | 8.0,8.0,10.0 | 二等辺三角形0 | 1,0,1,0,e=Iso | 二等辺三角形,Isoscelestriangle |
4 | 正解 | 4.0,4.0,5.0 | 二等辺三角形1 | 1,0,1,0,e=Iso | 二等辺三角形,Isoscelestriangle |
5 | 正解 | 8.0,8.0,8.0 | 正三角形0 | 1,0,1,1,e=Equ | 正三角形,Equilateraltriangle |
6 | 正解 | 2.0,2.0,2.0 | 正三角形1 | 1,0,1,1,e=Equ | 正三角形,Equilateraltriangle |
7 | 正解 | 4.0,4.0,9.0 | 三角形ではない0 | 0,0,0,0,e=No | 三角形ではない,no |
8 | 正解 | 2.0,2.0,5.0 | 三角形ではない1 | 0,0,0,0,e=No | 三角形ではない,no |
9 | 正解 | 4.0,0.0,9.0 | 三角形ではない2 | 0,0,0,0,e=No | 三角形ではない,no |
10 | 正解 | -1.0,4.0,5.0 | 三角形ではない3 | 0,0,0,0,e=No | 三角形ではない,no |
正解数 = 10 |
hard_sigmoid
概要
y = \left\{
\begin{array}{cc}
1 & (x \gt 2.5) \\
0.2x + 0.5 & (-2.5 \le x \le 2.5) \\
0 & (x \lt -2.5)
\end{array}
\right.
結果
所感
正解数は多いけど、期待値と判定結果のギャップが多い傾向にある気がします
高速化のsigmoidらしいけど、ここまで期待値と判定結果のギャップがあると採用するには微妙だな
モデル
判定結果の表
判定結果 | 入力 | 期待値 | 期待値(数値) | 結果 | 結果(数値) |
---|---|---|---|---|---|
0 | 正解 | 6.0,4.0,5.0 | ただの三角形 | 1,0,0,0,e=tri | ただの三角形,triangle |
1 | 間違い | 6.0,8.0,10.0 | 直角三角形0 | 1,1,0,0,e=Right | ただの三角形,triangle |
2 | 間違い | 3.0,4.0,5.0 | 直角三角形1 | 1,1,0,0,e=Right | ただの三角形,triangle |
3 | 正解 | 8.0,8.0,10.0 | 二等辺三角形0 | 1,0,1,0,e=Iso | 二等辺三角形,Isoscelestriangle |
4 | 正解 | 4.0,4.0,5.0 | 二等辺三角形1 | 1,0,1,0,e=Iso | 二等辺三角形,Isoscelestriangle |
5 | 間違い | 8.0,8.0,8.0 | 正三角形0 | 1,0,1,1,e=Equ | 二等辺三角形,Isoscelestriangle |
6 | 間違い | 2.0,2.0,2.0 | 正三角形1 | 1,0,1,1,e=Equ | 二等辺三角形,Isoscelestriangle |
7 | 正解 | 4.0,4.0,9.0 | 三角形ではない0 | 0,0,0,0,e=No | 三角形ではない,no |
8 | 正解 | 2.0,2.0,5.0 | 三角形ではない1 | 0,0,0,0,e=No | 三角形ではない,no |
9 | 正解 | 4.0,0.0,9.0 | 三角形ではない2 | 0,0,0,0,e=No | 三角形ではない,no |
10 | 正解 | -1.0,4.0,5.0 | 三角形ではない3 | 0,0,0,0,e=No | 三角形ではない,no |
正解数 = 7 |
softmax
概要
- 分類問題の出力層で採用が多い
- 出力範囲 0.0 ~ +1.0
y_i = \cfrac{e^{x_i}}{\displaystyle\sum_{k=1}^{n}{e^{x_k}}} \quad (i = 1, 2, \ldots, n)
結果
所感
本実験は選択じゃないので、不利なのはわかってたけど、
正解数も期待値と判定結果のギャップも善戦したんじゃないかと思います
モデル
判定結果の表
判定結果 | 入力 | 期待値 | 期待値(数値) | 結果 | 結果(数値) |
---|---|---|---|---|---|
0 | 正解 | 6.0,4.0,5.0 | ただの三角形 | 1,0,0,0,e=tri | ただの三角形,triangle |
1 | 正解 | 6.0,8.0,10.0 | 直角三角形0 | 1,1,0,0,e=Right | 直角三角形,Righttriangle |
2 | 間違い | 3.0,4.0,5.0 | 直角三角形1 | 1,1,0,0,e=Right | ただの三角形,triangle |
3 | 正解 | 8.0,8.0,10.0 | 二等辺三角形0 | 1,0,1,0,e=Iso | 二等辺三角形,Isoscelestriangle |
4 | 正解 | 4.0,4.0,5.0 | 二等辺三角形1 | 1,0,1,0,e=Iso | 二等辺三角形,Isoscelestriangle |
5 | 間違い | 8.0,8.0,8.0 | 正三角形0 | 1,0,1,1,e=Equ | 二等辺三角形,Isoscelestriangle |
6 | 正解 | 2.0,2.0,2.0 | 正三角形1 | 1,0,1,1,e=Equ | 正三角形,Equilateraltriangle |
7 | 正解 | 4.0,4.0,9.0 | 三角形ではない0 | 0,0,0,0,e=No | 三角形ではない,no |
8 | 正解 | 2.0,2.0,5.0 | 三角形ではない1 | 0,0,0,0,e=No | 三角形ではない,no |
9 | 正解 | 4.0,0.0,9.0 | 三角形ではない2 | 0,0,0,0,e=No | 三角形ではない,no |
10 | 正解 | -1.0,4.0,5.0 | 三角形ではない3 | 0,0,0,0,e=No | 三角形ではない,no |
正解数 = 9 |
relu
概要
y = \left\{
\begin{array}{cc}
x & (x \gt 0) \\
0 & (x \le 0)
\end{array}
\right.
結果
所感
さすが人気の中間層に採用される関数だけあって、
正解数も期待値と判定結果のギャップも優れた結果をだしました
優先的に採用を検討したい関数ですね
モデル
判定結果の表
判定結果 | 入力 | 期待値 | 期待値(数値) | 結果 | 結果(数値) |
---|---|---|---|---|---|
0 | 間違い | 6.0,4.0,5.0 | ただの三角形 | 1,0,0,0,e=tri | 直角三角形,Righttriangle |
1 | 正解 | 6.0,8.0,10.0 | 直角三角形0 | 1,1,0,0,e=Right | 直角三角形,Righttriangle |
2 | 正解 | 3.0,4.0,5.0 | 直角三角形1 | 1,1,0,0,e=Right | 直角三角形,Righttriangle |
3 | 正解 | 8.0,8.0,10.0 | 二等辺三角形0 | 1,0,1,0,e=Iso | 二等辺三角形,Isoscelestriangle |
4 | 正解 | 4.0,4.0,5.0 | 二等辺三角形1 | 1,0,1,0,e=Iso | 二等辺三角形,Isoscelestriangle |
5 | 正解 | 8.0,8.0,8.0 | 正三角形0 | 1,0,1,1,e=Equ | 正三角形,Equilateraltriangle |
6 | 正解 | 2.0,2.0,2.0 | 正三角形1 | 1,0,1,1,e=Equ | 正三角形,Equilateraltriangle |
7 | 正解 | 4.0,4.0,9.0 | 三角形ではない0 | 0,0,0,0,e=No | 三角形ではない,no |
8 | 正解 | 2.0,2.0,5.0 | 三角形ではない1 | 0,0,0,0,e=No | 三角形ではない,no |
9 | 正解 | 4.0,0.0,9.0 | 三角形ではない2 | 0,0,0,0,e=No | 三角形ではない,no |
10 | 正解 | -1.0,4.0,5.0 | 三角形ではない3 | 0,0,0,0,e=No | 三角形ではない,no |
正解数 = 10 |
PReLU
概要
y = \left\{
\begin{array}{cc}
x & (x \gt 0) \\
α*x & (x \le 0)
\end{array}
\right.
αは学習によって動的に変わる
結果
所感
ReLUを改良しただけあって、最高の成績をだしました
期待値と判定結果のギャップもほぼ0なので、文句のつけようもありません
今、採用するなら最有力かな
モデル
判定結果の表
入力 | 期待値 | 期待値(数値) | 結果 | 結果(数値) | |
---|---|---|---|---|---|
0 | 正解 | 6.0,4.0,5.0 | ただの三角形 | 1,0,0,0,e=tri | ただの三角形,triangle |
1 | 正解 | 6.0,8.0,10.0 | 直角三角形0 | 1,1,0,0,e=Right | 直角三角形,Righttriangle |
2 | 正解 | 3.0,4.0,5.0 | 直角三角形1 | 1,1,0,0,e=Right | 直角三角形,Righttriangle |
3 | 正解 | 8.0,8.0,10.0 | 二等辺三角形0 | 1,0,1,0,e=Iso | 二等辺三角形,Isoscelestriangle |
4 | 正解 | 4.0,4.0,5.0 | 二等辺三角形1 | 1,0,1,0,e=Iso | 二等辺三角形,Isoscelestriangle |
5 | 正解 | 8.0,8.0,8.0 | 正三角形0 | 1,0,1,1,e=Equ | 正三角形,Equilateraltriangle |
6 | 正解 | 2.0,2.0,2.0 | 正三角形1 | 1,0,1,1,e=Equ | 正三角形,Equilateraltriangle |
7 | 正解 | 4.0,4.0,9.0 | 三角形ではない0 | 0,0,0,0,e=No | 三角形ではない,no |
8 | 正解 | 2.0,2.0,5.0 | 三角形ではない1 | 0,0,0,0,e=No | 三角形ではない,no |
9 | 正解 | 4.0,0.0,9.0 | 三角形ではない2 | 0,0,0,0,e=No | 三角形ではない,no |
10 | 正解 | -1.0,4.0,5.0 | 三角形ではない3 | 0,0,0,0,e=No | 三角形ではない,no |
正解数 = 11 |
まとめ
活性化関数 | 判定性能(11点満点) | 期待値とのギャップ | 考察 |
---|---|---|---|
tanh | 10 | 1.021199 | 入力層の人気の活性化関数だけあって、判定性能は比較的良い結果をだしました。しかし、sigmoidと同様に最小値と最大値の付近の判定性能の鈍化があるように思いました。 |
softmax | 9 | 2.150410 | 分類の判定ではないので、不利な条件での実験となりました。そのため、判定性能が高くでませんでした。データの条件次第では性能を発揮するように思いました |
sigmoid | 10 | 1.257565 | 出力の範囲が-1~+1なので、最小値と最大値の付近の判定性能が鈍化したように思いました。標準化した訓練データであればもっと判定性能があがるかもしれません |
hard_sigmoid | 7 | 2.170923 | sigmoidと判定性能は同じ結果となりました。 |
ReLU | 10 | 0.914075 | 隠れ層の人気の活性化関数だけあって判定性能が高い結果となりました。この実験では入力データにマイナスを含むことが判定性能を少し悪化させたように思いました |
PReLU | 11 | 0.069040 | この実験では最高の判定性能を出す結果となりました。ReLUのマイナス対応版だけあってマイナスがあっても判定性能の悪化がなさそうです。隠れ層はReLUかPReLUをデータの傾向で使い分けする感じでしょうか |
勾配法と損失関数について
- 本実験では固定していますが勾配法と損失関数の組み合わせでも判定性能が変わるので、いろいろ試して見る必要があるかと思います
活性化関数の選び方
- 実行時間と判定性能の兼ね合いで活性化関数を決めるとよいかと思います
モデルの調整について
- 期待値とのギャップと正解数の比例関係をみると、まずは期待値とのギャップを小さくするような、
活性化関数を選んでから、層やdenseを調整したほうがよいかと思います
コード
# -*- coding: utf-8 -*-
import numpy as np
import os.path
import time
import csv
from tensorflow.keras.models import Sequential, model_from_json
from tensorflow.keras.layers import Dense, Activation, PReLU
from tensorflow.keras.utils import plot_model
from tensorflow.keras import backend as K
X_train = []
y_train = []
def normalize(in_v):
out = in_v
out = out / 10.0
return out
def secification(x,y,z):
in_data = [x,y,z]
in_data.sort()
# print("in_data:")
# print(in_data)
in1 = normalize(in_data[0])
in2 = normalize(in_data[1])
in3 = normalize(in_data[2])
d1 = in1 + in2
d2 = in2 + in3
d3 = in3 + in1
return in1,in2,in3,d1,d2,d3
def print_judge(in_d):
if in_d[0,0] > 0.9:
if in_d[0,1] > 0.9:
print('result_judge,Righttriangle')
return
if in_d[0,2] > 0.9:
if in_d[0,3] >0.9:
print('result_judge,Equilateraltriangle')
else:
print('result_judge,Isoscelestriangle')
return
print('result_judge,triangle')
else:
print('result_judge,no')
def judge_predict(model, in_str, x, y, z):
# print('------------------------')
print()
print("input," + str(x) + ',' + str(y) + ',' + str(z) + ',' + in_str)
v_test = [secification(x,y,z)]
print("input_val,%f,%f,%f,%f,%f,%f" %( v_test[0][0],v_test[0][1],v_test[0][2],v_test[0][3],v_test[0][4],v_test[0][5] ) )
classes = model.predict(v_test)
print("result_val,%f,%f,%f,%f" %( classes[0][0],classes[0][1],classes[0][2],classes[0][3] ) )
# print(classes)
print_judge(classes)
with open('../data/keras_triangle.csv') as f:
reader = csv.reader(f)
for row in reader:
# print(row)
r0 = float(row[0])
r1 = float(row[1])
r2 = float(row[2])
if float(row[5]) != 0.0 or float(row[6]) != 0.0:
# 二等辺三角形 正三角形
for i in range(100):
X_train.append(secification(r0,r1,r2))
y_train.append([float(row[3]),float(row[4]),float(row[5]),float(row[6]) ])
elif float(row[4]) !=0.0:
# 直角三角形
for i in range(1000):
X_train.append(secification(r0,r1,r2))
y_train.append([float(row[3]),float(row[4]),float(row[5]),float(row[6]) ])
else:
X_train.append(secification(r0,r1,r2))
y_train.append([float(row[3]),float(row[4]),float(row[5]),float(row[6]) ])
# print(X_train)
# print(y_train)
activate = ['PReLU','tanh', 'sigmoid', 'softmax', 'relu', 'hard_sigmoid']
for act in activate:
print('activate,' + act)
st_time = int(time.time() * 1000)
model = Sequential()
if act != 'PReLU':
model.add(Dense(units=6, activation=act))
model.add(Dense(units=36, activation= act ))
model.add(Dense(units=4, activation='tanh'))
else:
model.add(Dense(units=6))
model.add(PReLU())
model.add(Dense(units=36))
model.add(PReLU())
model.add(Dense(units=4))
model.add(PReLU())
model.compile(optimizer='Adam', loss='mean_squared_error')
model.fit(
X_train,
y_train,
epochs=100,
batch_size=32,
verbose=0 # log off
)
loss_and_metrics = model.evaluate(X_train, y_train, batch_size=32)
print('Test loss:', loss_and_metrics)
classes = model.predict(X_train, batch_size=32)
print(classes)
np.set_printoptions(precision=3)
judge_predict( model, "ok,1,0,0,0,e=tri", 6.0, 4.0, 5.0 )
judge_predict( model, "ok,1,1,0,0,e=Right", 6.0, 8.0, 10.0 )
judge_predict( model, "ok,1,1,0,0,e=Right", 3.0, 4.0, 5.0 )
judge_predict( model, "ok,1,0,1,0,e=Iso", 8.0, 8.0, 10.0 )
judge_predict( model, "ok,1,0,1,0,e=Iso", 4.0, 4.0, 5.0 )
judge_predict( model, "ok,1,0,1,1,e=Equ", 8.0, 8.0, 8.0 )
judge_predict( model, "ok,1,0,1,1,e=Equ", 2.0, 2.0, 2.0 )
judge_predict( model, "ng,0,0,0,0,e=No", 4.0, 4.0, 9.0 )
judge_predict( model, "ng,0,0,0,0,e=No", 2.0, 2.0, 5.0 )
judge_predict( model, "ng,0,0,0,0,e=No", 4.0, 0.0, 9.0 )
judge_predict( model, "ng,0,0,0,0,e=No", -1.0, 4.0, 5.0 )
ed_time = int(time.time() * 1000)
print("time,st = %d, ed = %d, t = %d ms" % (st_time, ed_time, ed_time-st_time) )
model.summary()
# モデルの概要図をファイル出力
png_file = act + ".png"
plot_model(model, to_file= png_file, show_shapes=True)
K.clear_session() # init