0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

機械学習の活性化関数の判定性能の比較実験をやってみました

Posted at

はじめに

この記事ではニューラルネットワークの
各種の活性化関数の判定性能の比較結果をまとめています。

対象者として、

  • 活性化関数のざっくりとした比較を知りたい人
  • どの活性化関数を採用するか検討してる人
  • 機械学習を始めようとしてる人
    などを想定してます。

活性化関数とは

あるニューロンの入力合計から、出力を決定するための関数です

ニューロン.JPG

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なのがダメなのか、いまいちな気がします

モデル

tanh.png

判定結果の表

判定結果 入力 期待値 期待値(数値) 結果 結果(数値)
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

tanh.JPG

sigmoid

概要

  • ReLUの登場前は採用事例が多かった
  • 出力範囲 0.0 ~ +1.0
y = \cfrac{1}{1 + e^{-x}}

結果

所感

往年の人気関数だけあって、正解数は多い
けど、期待値と判定結果のギャップが多いのが気になりますね

モデル

sigmoid.png

判定結果の表

判定結果 入力 期待値 期待値(数値) 結果 結果(数値)
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.JPG

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らしいけど、ここまで期待値と判定結果のギャップがあると採用するには微妙だな

モデル

hard_sigmoid.png

判定結果の表

判定結果 入力 期待値 期待値(数値) 結果 結果(数値)
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

hard_sigmoid.JPG

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)

結果

所感

本実験は選択じゃないので、不利なのはわかってたけど、
正解数も期待値と判定結果のギャップも善戦したんじゃないかと思います

モデル

softmax.png

判定結果の表

判定結果 入力 期待値 期待値(数値) 結果 結果(数値)
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

softmax.JPG

relu

概要

y = \left\{
  \begin{array}{cc}
    x & (x \gt 0) \\
    0 & (x \le 0)
  \end{array}
\right.

結果

所感

さすが人気の中間層に採用される関数だけあって、
正解数も期待値と判定結果のギャップも優れた結果をだしました
優先的に採用を検討したい関数ですね

モデル

relu.png

判定結果の表

判定結果 入力 期待値 期待値(数値) 結果 結果(数値)
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

relu.JPG

PReLU

概要

y = \left\{
  \begin{array}{cc}
    x & (x \gt 0) \\
    α*x & (x \le 0)
  \end{array}
\right.

αは学習によって動的に変わる

結果

所感

ReLUを改良しただけあって、最高の成績をだしました
期待値と判定結果のギャップもほぼ0なので、文句のつけようもありません
今、採用するなら最有力かな

モデル

PReLU.png

判定結果の表

入力 期待値 期待値(数値) 結果 結果(数値)
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

PReLU_g.PNG

まとめ

活性化関数 判定性能(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をデータの傾向で使い分けする感じでしょうか

まとめ.PNG

勾配法と損失関数について

  • 本実験では固定していますが勾配法と損失関数の組み合わせでも判定性能が変わるので、いろいろ試して見る必要があるかと思います

活性化関数の選び方

  • 実行時間と判定性能の兼ね合いで活性化関数を決めるとよいかと思います

モデルの調整について

  • 期待値とのギャップと正解数の比例関係をみると、まずは期待値とのギャップを小さくするような、
    活性化関数を選んでから、層や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


0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?