softmax関数の実装
「ゼロから作るDeep Learning」を読み進める中でsoftmax関数が登場しました。本の通り実装して、そのあとの誤差逆伝播法の章で勾配確認をしました。しかし、数値微分で求めた勾配と誤差逆伝播法で求めた勾配の差が本に書いてあるような小さな値になりませんでした。そこで提供されているソースコードを読み、自分のコードと見比べた結果、softmax関数の実装に違いがあり、提供されているソースコードの実装方法に合わせると、差は小さな値になりました。
自分が書いたソースコード
python
1def softmax(x): 2 c = np.max(x) 3 exp_a = np.exp(x - c) 4 sum_exp_a = np.sum(exp_a) 5 y = exp_a / sum_exp_a 6 return y
提供されているソースコード
python
1def softmax(x): 2 if x.ndim == 2: 3 x = x.T 4 x = x - np.max(x, axis=0) 5 y = np.exp(x) / np.sum(np.exp(x), axis=0) 6 return y.T 7 8 x = x - np.max(x) 9 return np.exp(x) / np.sum(np.exp(x))
自分が分からない部分
- なぜxが2次元の時のみ場合分けを行なっているのか
- なぜ行列の転置をとっているのか
- なぜ自分の実装方法だと、数値微分・誤差逆伝播法それぞれで求めた勾配の差が大きくなるのか
補足情報
softmax関数以外の部分は提供されているソースコードと同じでした。softmax関数の実装方法の違いのみで、結果に差が出ていると思われます。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

回答2件
0
やってることは単純で、複数のデータに対して同時に計算できる機能を付与しているだけに見えます。
python
1import numpy as np 2 3def softmax(x): 4 if x.ndim == 2: 5 x = x.T 6 x = x - np.max(x, axis=0) 7 y = np.exp(x) / np.sum(np.exp(x), axis=0) 8 return y.T 9 10 x = x - np.max(x) 11 return np.exp(x) / np.sum(np.exp(x)) 12 13a = np.random.rand(3, 10) 14print(softmax(a[0])) 15print(softmax(a[1])) 16print(softmax(a[2])) 17 18print(softmax(a)) 19 20""" # => 21[0.08629677 0.09433006 0.06536112 0.12163197 0.13861227 0.13997268 22 0.06971638 0.08295977 0.06633675 0.13478224] 23[0.0689522 0.1649164 0.08518756 0.08926251 0.10106928 0.07014795 24 0.08651658 0.07375167 0.16915227 0.09104358] 25[0.0640806 0.12950118 0.1455273 0.09357789 0.06604187 0.09396754 26 0.06749124 0.06936294 0.13728469 0.13316475] 27[[0.08629677 0.09433006 0.06536112 0.12163197 0.13861227 0.13997268 28 0.06971638 0.08295977 0.06633675 0.13478224] 29 [0.0689522 0.1649164 0.08518756 0.08926251 0.10106928 0.07014795 30 0.08651658 0.07375167 0.16915227 0.09104358] 31 [0.0640806 0.12950118 0.1455273 0.09357789 0.06604187 0.09396754 32 0.06749124 0.06936294 0.13728469 0.13316475]] 33"""
質問者様のコードはこの機能がありません。
その本は読んだことがありませんが、この機能が必要な実装になっているのでしょう。確認してみてください。
投稿2018/04/27 17:42
総合スコア30939
0
ベストアンサー
質問者様
はじめまして
興味ある機械学習のテーマなので取り上げていただき
ありがとうございます。
ぱっと見たところ、前の回答者様の回答は
即答ですが、本質のところを触れていない気がしました。
少し検証しました。
なお本は持っていませんが、数式処理などは
昔やっておりました。
追加で書いておきます
最初見たときに、この点に気がついていたのですが
あえて触れずに検証しました。
x.ndim == 2で定義されたsoftmax関数
と
exp関数の値の増大を考慮したsoftmax関数
どちらが定義された
計算処理により使うのにふさわしいのか
もしわかる方がいたら回答へコメントください。
本を見た方でもよろしいです。
ここまで追加 4月28日夜
前提
softmax関数 これはネットで定義もでていますが 念のため簡単に
「softmax関数は多くの次元からなる入力のうち、自分の値が他の値たちに比べて一番目立っているならば、その値が1に近づく関数である」
検証
「その値が1に近づく関数」とは、
その出力の総和が限りなく1に近づくことですね。読んでいてふと、
この質問への回答につながるsoftmax関数の実装が正しくなされているか、疑問になりました。
そもそも質問者様も回答者様も、softmax関数の正しさを書かれていないし
(たぶん)検証されていないことに気がつきました。
そこでソースを修正し、検証しました。print(np.sum(w))を追加し
総和が1に近づくか繰り返し実行してみました。
(hayataka2049様のコードを修正させていただきました)
検証コードと結果
Python
1import numpy as np 2 3# "softmax_div(a) 自分(=質問者様)が書いたソースコード:" 4def softmax_div(x): 5 c = np.max(x) 6 exp_a = np.exp(x - c) 7 sum_exp_a = np.sum(exp_a) 8 y = exp_a / sum_exp_a 9 return y 10 11# "softmax(a) 提供されているソースコード:" 12def softmax(x): 13 if x.ndim == 2: 14 x = x.T 15 x = x - np.max(x, axis=0) 16 y = np.exp(x) / np.sum(np.exp(x), axis=0) 17 return y.T 18 19 x = x - np.max(x) 20 return np.exp(x) / np.sum(np.exp(x)) 21 22a = np.random.rand(3, 10) 23 24# コメント化 25''' 26print(softmax(a[0])) 27print(softmax(a[1])) 28print(softmax(a[2])) 29''' 30# 以下を追加した 31print("softmax_div(a) 自分(=質問者様)が書いた:") 32w = softmax_div(a) 33print(w) 34print(np.sum(w)) 35 36print() 37 38print("softmax(a) 提供されているソースコード:") 39w = softmax(a) 40print(w) 41print(np.sum(w))
結果
C:\Users\user>python e:/source/python/deepleaning/deeplerning-2-org-kenyou.py softmax_div(a) 自分(=質問者様)が書いた: [[0.03035752 0.03223636 0.04946526 0.03804523 0.02138471 0.04998499 0.04621904 0.02339356 0.04671085 0.02184978] [0.02772051 0.03004919 0.04201874 0.02913666 0.02145075 0.03785042 0.04038547 0.04633219 0.02284208 0.02892747] [0.03141703 0.04352479 0.02580207 0.0373573 0.03624223 0.03936765 0.0274775 0.01959095 0.02887455 0.02398512]] 1.0 softmax(a) 提供されているソースコード: [[0.08440915 0.08963326 0.13753824 0.10578483 0.05946024 0.13898335 0.12851212 0.06504584 0.12987961 0.06075336] [0.08484655 0.09197412 0.12861035 0.08918108 0.06565615 0.11585202 0.12361128 0.14181291 0.06991473 0.0885408 ] [0.10016932 0.13877344 0.08226674 0.11910916 0.1155539 0.12551891 0.08760863 0.06246334 0.09206296 0.07647359]] 2.9999999999999996 C:\Users\user>python e:/source/python/deepleaning/deeplerning-2-org-kenyou.py softmax_div(a) 自分(=質問者様)が書いた: [[0.02244641 0.03607059 0.036551 0.04050203 0.0302181 0.02815483 0.0260633 0.02494414 0.04185455 0.02860929] [0.0351713 0.04592682 0.02549423 0.03278023 0.04404871 0.02969106 0.04318596 0.02143346 0.02316922 0.0524996 ] [0.04447867 0.02152701 0.02579055 0.04330732 0.0205996 0.04599201 0.04340829 0.03167898 0.02046959 0.03393317]] 0.9999999999999998 softmax(a) 提供されているソースコード: [[0.07116486 0.11435943 0.11588255 0.128409 0.09580448 0.08926303 0.08263197 0.07908375 0.13269708 0.09070386] [0.09952246 0.12995683 0.07213974 0.09275656 0.12464244 0.08401532 0.12220116 0.0606492 0.06556079 0.14855548] [0.1343015 0.06499991 0.0778735 0.13076466 0.06219965 0.13887097 0.13106954 0.09565338 0.06180709 0.10245979]][[0.07116486 0.11435943 0.11588255 0.128409 0.09580448 0.08926303 0.08263197 0.07908375 0.13269708 0.09070386] [0.09952246 0.12995683 0.07213974 0.09275656 0.12464244 0.08401532 0.12220116 0.0606492 0.06556079 0.14855548] [0.1343015 0.06499991 0.0778735 0.13076466 0.06219965 0.13887097 0.13106954 0.09565338 0.06180709 0.10245979]]Traceback (most recent call last): File "e:/source/python/deepleaning/deeplerning-2-org-kenyou.py", line 40, in <module> print(w) OSError: raw write() returned invalid length 700 (should have been between 0 and 350) C:\Users\user>python e:/source/python/deepleaning/deeplerning-2-org-kenyou.py softmax_div(a) 自分(=質問者様)が書いた: [[0.02344139 0.03701583 0.0271286 0.02228122 0.03144341 0.04527077 0.04512415 0.04652431 0.04619006 0.03796994] [0.035927 0.03004488 0.03251812 0.02316676 0.03450954 0.03274214 0.04416618 0.02085564 0.04461418 0.04214792] [0.02477391 0.02592403 0.03725747 0.04577268 0.0255545 0.02239439 0.01896394 0.03785329 0.02150075 0.03692301]] 0.9999999999999999 softmax(a) 提供されているソースコード: [[0.06468559 0.10214371 0.07486031 0.06148414 0.08676685 0.1249229 0.12451831 0.12838201 0.12745964 0.10477655] [0.1054529 0.08818771 0.09544717 0.06799906 0.10129239 0.09610471 0.12963654 0.06121546 0.13095152 0.12371254] [0.08343688 0.08731042 0.12548069 0.15415933 0.08606585 0.07542282 0.0638693 0.12748738 0.07241308 0.12435425]] 2.999999999999999 C:\Users\
エラーはとりあえず無視してください。
print(np.sum(w))の結果を見ると 提供されているソースコードではいつも3に近い値です。
たぶんですが提供されているソースコードの式に間違いがあると思います。あと何度も代入式(np.exp(x))を呼び出しています。 【訂正 4月28日夜】層の複数の値の合計?なので問題ないようです。
修正したほうがいいです。
ご指摘ありがとうございました。
投稿2018/04/28 09:18
編集2018/04/28 13:19総合スコア1195
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2018/04/28 13:05 編集

あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。