ゼロから作るDeep LearningをJuliaで実装してみる (4)ソフトマックス関数

## :red_car: この記事の目的

本記事は、Deep Learningの入門書「ゼロから作るDeep Learning」を参考に、Juliaを用いて同書の内容を実装してみる、という試みです。

※これはあくまで筆者の一つの試みと提案で、**必ずしも内容が正解ではありません**のでご了承お願い致します。
また、より良いアドバイスや協力のご提案などありましたら、お気軽にお声がけ頂けますと幸いです。

## :red_car: 今回取り組むこと

本記事は、参考書の3.5章にあたります。
ソフトマックス関数を実装します。

#### ソフトマックス関数の定義

ソフトマックス関数の定義は以下となります。

$$
y_k = \frac{exp(a_k)}{\sum^{n}_{i=1}exp(a_i)}\quad(式1)
$$

exp(x)は指数関数で、ネイピア数eのx乗という意味です。
出力層はn個あり、k番目の出力を$y_k$とします。
k番目の入力信号は$a_k$で、分母は全ての入力信号の和となります。

#### ソフトマックス関数の実装

(式1)を実装してみます。
ここでは、入力パラメータaを一次元配列と想定しています。

```ruby:4_softmax_function
function softmax(a)
    exp_a = [exp(i) for i in a]                    # S01
    sum_exp_a = sum(exp_a)                         # S02
    y = [i / sum_exp_a for i in exp_a ]            # S03
    return reshape(y, 1, :)                        # S04
end
```

ソースの解説です。
・_S01_で配列aの各要素に指数関数exp()を適用した新たな配列exp_aを生成しています。ここではジェネレータ式を用いて配列をループさせながら、その出力を新たな配列としています。配列の各要素を一律に処理するmap()関数を使用することもできます。
・_S02_では配列exp_aの要素の和sum_exp_aを取得しています。
・_S03_は再びジェネレータ式を用いて、配列exp_aの各要素をsum_exp_aで割った計算を行い、配列yとして生成しています。
・_S04_で返り値をMatrix型に変換しています。ジェネレータ式ではVector型が得られるため、これをMatrix型に変換することで、行列計算をしやすくすることが目的です。

以上で参考書のsoftmax関数を実装することができました。
関数の実行結果は以下となりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399135/73e7f9d4-1091-7b60-8c33-81bb7e87c04b.png)

#### ソフトマックス関数(改善版)

参考書に倣い、指数関数の計算がオーバーフローしないように改善を行います。
$y_k$を求めるソフトマックス関数を(式2)ように定義します。

$$
y_k = \frac{exp(a_k + C')}{\sum^{n}_{i=1}exp(a_i + C')}\quad(式2)
$$

ここで、C'は入力値の最大値とします。
(式2)ではC'を足していますが、C'は定数なので負の値を取る事もできます。
これより、オーバーフロー対策版のソフトマックス関数を以下のように定義します。

```ruby:4_softmax_function
function softmax(a)
    c = maximum(a)                                  # S10
    exp_a = [exp(i - c) for i in a]                 # S11
    sum_exp_a = sum(exp_a)
    y = [i / sum_exp_a for i in exp_a ]
    return reshape(y, 1, :)
end
```

ソースの解説です。
・S10で入力配列aの要素のうち、最大の要素の値を取得しています。
・S11では、上記で求めたcを予め引いた値の指数を算出しています。

以下はこの関数の実行結果です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399135/95566383-b80b-96f9-1972-7446c82c26a4.png)

以上でソフトマックス関数の実装ができました。
次は、MNISTの手書き数字認識を行ってみたいと思います。


## :red_car: もくじ

[(1)論理回路](https://qiita.com/ttabata/items/f9253d5ef94ca3807f42)
[(2)活性化関数](https://qiita.com/ttabata/items/7d4b8d92e38df47cffbb)
[(3)3層ニューラルネットワークの実装](https://qiita.com/ttabata/items/4f50ec32c0276d21d966)
[(4)ソフトマックス関数](https://qiita.com/ttabata/items/21329897119f81a141e9)
[(5)MNIST手書き数字認識 その①画像表示](https://qiita.com/ttabata/items/6f7025f48fa52d465c81)
[(5)MNIST手書き数字認識 その②推論](https://qiita.com/ttabata/items/0781e1aacb11d9148053)

## :red_car: 関連情報

:paperclip: Julia早引きノート［01］変数・定数の使い方
https://qiita.com/ttabata/items/a1ada2c0cba03672e105

:paperclip: Julia - 公式ページ
https://julialang.org/

:paperclip: Julia - 日本語公式ドキュメント
https://julia-doc-ja.readthedocs.io/ja/latest/index.html

:paperclip: 初めてのJuliaとインストール (Windows & Linux)
https://qiita.com/ttlabo/items/b05bb43d06239f968035

## :red_car: 出典

■参考書
「ゼロから作るDeep Learning ～ Pythonで学ぶディープラーニングの理論と実装」
　斎藤康毅 著／オライリー・ジャパン
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399135/4a558c91-5e9c-9d6f-3673-d44fbb583103.png)

## :red_car: ご意見など

ご意見、間違い訂正などございましたらお寄せ下さい。