pit-rayの備忘録

開発中に得た知識を記事にしていくブログ

【Python】二次元配列に対応したソフトマックス関数

近頃、ディープラーニングに興味があり、そのアウトプットの一環としての記事になります。
特に新しい内容ではありません。
特に配列の基本が分かっていれば読む必要はありません。


では書きます。

ソフトマックス関数とは

ニューラルネットワークの入力層から得られたデータを、出力層にてどのように料理するかを決める活性化関数は主に二つあります。

活性化関数 処理
恒等関数 入力信号をそのまま出力
ソフトマックス関数 入力信号を正規化して出力

データを正規化するメリットは、そのデータを確率的に比較できる点が挙げられます。
例えば、対象のものが犬か猫か判別する場合、
( 犬, 猫 ) = ( 0.3, 4.5 )
このような入力信号の場合、これを正規化すると
( 犬, 猫 ) = ( 0.0625, 0.9375 )
これは犬の確率は6.25%で、猫の確率は93.75%だといえます。

このように正規化することで、データを確率的に見ることができます。
しかし、推論においてはデータの大小が分かれば判別できるため、一般的にはソフトマックス関数は使用しません。
一方学習においては、損失関数を適用するため、正規化したものが必要になります。

では早速ソフトマックス関数の実装を考えていきます。
まず、ソフトマックス関数は次の式で表されます。
  y _ k =  \displaystyle{ \frac{e^{a _ k} }{ \displaystyle{\sum_{i=1}^n e^{a _ i}}}}

k というのは、上の例でいうと猫や犬などのクラスインデックスです。
つまり、k 番目の出力を求める計算式を示しています。
このように指数関数を通したデータを用いて、正規化します。

一次元のソフトマックス関数を実装する

numpyを用いて実装すると次のようになります。

import numpy as np

def softmax( x ):
    return np.exp( x ) / np.sum( np.exp( x ) )

しかしこのような実装ではうまくいきません。
なぜなら、指数関数は簡単に桁が膨大になり、オーバーフローしやすいからです。

この対策として、データを定数の足し算として扱う方法があります。
先ほどのソフトマックス関数を少しだけ変形します。

\ \ \ \ y _ k =  \displaystyle{ \frac{e^{a _ k} }{ \displaystyle{\sum_{i=1}^n e^{a _ i}}}}
= \displaystyle{ \frac{Ce^{a _ k} }{ \displaystyle{C\sum_{i=1}^n e^{a _ i}}}}
= \displaystyle{ \frac{e^{a _ k+ \log C} }{ \displaystyle{\sum_{i=1}^n e^{a _ i + \log C }}}}
= \displaystyle{ \frac{e^{a _ k+ C'} }{ \displaystyle{\sum_{i=1}^n e^{a _ i + C' }}}}

よって、変数 a に同じ量だけ加算しても結果は変わりません。

今後は、それぞれの入力信号を最大の値で引き算したものをデータとして使っていきます。
Pythonで実装すると次のようになります。

import numpy as np

def softmax( x ):
    x = x - np.max( x ) #New
    return np.exp( x ) / np.sum( np.exp( x ) )

これが一次元配列に対するソフトマックス関数になります。

二次元に対応したソフトマックス関数を実装する

numpy.ndarrayのメンバであるndimで場合分けをします。

import numpy as np

def softmax( x ):
    if x.ndim == 2:
        x = x - np.max( x, axis = 1 )
        y = np.exp( x ) / np.sum( np.exp( x ), axis = 1 )
        return y

    x = x - np.max( x )
    return np.exp( x ) / np.sum( np.exp( x ) )

この実装は間違っています。
まずは次の図をご覧ください。
f:id:pit-ray:20190303195318j:plain:w250
これは二次元の場合のaxis(軸)の方向を示しています。
データはaxisが1の方向に並んでいます。


では、ほかの例に関して詳しく見ていきます。
maxメソッドをaxis = 1で実行すると次のようになります。
f:id:pit-ray:20190303195806j:plain:w300
上の例では、maxで得られる配列は( 5, 3 )という配列になります。
しかし、これを元の配列から引くと問題が生じます。
max配列は横に並ぶからです。

理想
f:id:pit-ray:20190401170720j:plain

実際
f:id:pit-ray:20190401170735j:plain

このようになってしまいます。

見てわかる通り、max関数を通す前に転置すればうまくいきます。
実際のコードは次のようになります。

import numpy as np

def softmax( x ):
    if x.ndim == 2:
        x = x.T
        x = x - np.max( x, axis = 0 )
        y = np.exp( x ) / np.sum( np.exp( x ), axis = 0 )
        return y.T

    x = x - np.max( x )
    return np.exp( x ) / np.sum( np.exp( x ) )

一度転置することでmaxで得られた横向きの配列が、元のデータに合うようにブロードキャストされます。
転置するのでデータは縦向きになり、axis = 0であることに注意しましょう。

他にmaxで得られた配列を転置でもいいかと思います。

以上が二次元配列に対応したソフトマックス関数になります。
maxで得られる形に注意しろというだけの中身のない記事でした。

参考文献

斎藤 康毅 『ゼロから作るDeep Learning ―Pythonで学ぶディープラーニングの理論と実装』

(はてなブログのtex構文を使ってみたかっただけ)

カラースキーム・テーマを他のテキストエディタ用に変換するツール【TeraPad, さくらエディタ対応】

今回は、テキストエディタの色設定を相互変換できるツールの紹介です。

C++学習の副産物として生まれたツールですので、対応エディタが非常に少ないですが、コメント等で対応希望のエディタ等がありましたら実装を検討します。

他にも対応OSやGUIの実装等の要望もありましたら実装いたします。
どうぞお気軽にお寄せください。

READMEは付属していません。

CUIアプリケーションですので、コマンドプロンプトやPowerShellなどで実行してください。

TxEditorCCTool

【対応OS】
Windows
※要望があれば、他OS用のアプリケーションも配布いたします。

【使い方】
〇/〇/tecc.exe 対象のファイル名 -fr 変換元エディタ -to 変換先エディタ -nm 出力ファイル名


〇/〇/tecc.exe
■ 最初の〇/〇/は、パスを示しています。
■ 絶対パスでも相対パスでも構いませんが、それぞれの環境にあった実行方法をご利用ください。
■ .exeは省略しても構いません。


対象のファイル名
■ これには、変換元となるファイル名を指定します(パスには対応していません)
■ ファイルはtecc.exeと同じ層のディレクトリに置いてください
■ 拡張子の有無は任意です


-fr 変換元エディタ -to 変換先エディタ
■以下の値を指定します

エディタ名
TeaPad TeraPad
さくらエディタ Sakura

※要望があれば他エディタも実装いたします


-nm 出力ファイル名
■ 省略可
■ デフォルトでは、読み込んだファイル名で出力されます(拡張子は異なる)
■ 拡張子の有無は任意です。

【実行例】
monokai.col(さくらエディタ)をmonokai2.tpc(TeraPad)として変換したい場合

C:/TxEditorCCTool/tecc.exe monokai.col -fr Sakura -to TeraPad -nm monokai2.tpc

【リンク】
TxEditorCCToolをダウンロードする

以上です。
コメントお待ちしております。