質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
NumPy

NumPyはPythonのプログラミング言語の科学的と数学的なコンピューティングに関する拡張モジュールです。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

2回答

7053閲覧

「ゼロから作るDeep Learning」のsoftmax関数の実装について

yakiniku_obake

総合スコア7

NumPy

NumPyはPythonのプログラミング言語の科学的と数学的なコンピューティングに関する拡張モジュールです。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

1グッド

1クリップ

投稿2018/04/27 17:26

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関数の実装方法の違いのみで、結果に差が出ていると思われます。

meg_👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答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

hayataka2049

総合スコア30933

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ベストアンサー

質問者様
はじめまして

興味ある機械学習のテーマなので取り上げていただき
ありがとうございます。

ぱっと見たところ、前の回答者様の回答は
即答ですが、本質のところを触れていない気がしました。

少し検証しました。

なお本は持っていませんが、数式処理などは
昔やっておりました。

追加で書いておきます
最初見たときに、この点に気がついていたのですが
あえて触れずに検証しました。

x.ndim == 2で定義されたsoftmax関数

exp関数の値の増大を考慮したsoftmax関数

どちらが定義された
計算処理により使うのにふさわしいのか
もしわかる方がいたら回答へコメントください。
本を見た方でもよろしいです。

ここまで追加 4月28日夜

前提

softmax関数 これはネットで定義もでていますが 念のため簡単に

「softmax関数は多くの次元からなる入力のうち、自分の値が他の値たちに比べて一番目立っているならば、その値が1に近づく関数である」

softmax関数を3Dグラフにプロット

検証

「その値が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
kawakawa2018

総合スコア1195

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hayataka2049

2018/04/28 10:16

えっと、私はバッチかなにかで(シチュエーションはよくわかりませんが)複数の出力層の結果をまとめて計算したかったんじゃないかなぁ・・・・と想像した次第で np.sum(a, axis=1)すればちゃんと[1. 1. 1.]になりますよ。質問者様のコードも同じshapeで返りはしますが、入力を行ごとに処理する機能がないので、それを想定して他のプログラムが動いていたら正しい結果になりません。 本のコードに差し替えたらちゃんと動いたということなので、きっとそうだろうと思いつつも、その本は読んだことがないし持っていないので「確認してみてください」と
kawakawa2018

2018/04/28 12:19

コメントありがとうございます。 なぜ自分の実装方法だと、数値微分・誤差逆伝播法それぞれで求めた勾配の差が大きくなるのか という3番目の疑問、その解決につながるかと思い、掲載された関数を調べました。 私の回答に追加する内容もあったのですが、 数学的な点にとどめておきます。 ありがとうございました。
yakiniku_obake

2018/04/28 12:57

コメントありがとうございます。 hayataka2049さんのおっしゃる通り、ミニバッチを利用するプログラムなので入力を行ごとに処理する昨日が必要であったようです。自分はその部分に気が付けませんでした。 お二方ともありがとうございました。
hayataka2049

2018/04/28 13:05 編集

質問は解決のようなのでよかったです。 それはそれで良いとして・・kawakawa2018さんの貼った画像の式は間違っています。本の関数(のndim=2でないときとndim=2のとき)、質問者様の書いた関数ともに計算の結果は同じです(入力フォーマットを質問者様のコードは1行ずつ(ベクトルで)、本のコードはベクトルと配列で入れて確認)。「自分(=質問者様)が書いたコード」の式の書き起こしでミスがあるようです。 もう一度、ご確認ください>kawakawa2018さん
kawakawa2018

2018/04/28 13:07

yakiniku_obakeさん わざわざコメントありがとうございました。 「ミニバッチを利用するプログラムなので入力を行ごとに処理する・・・」 こちらも知り合いに本の該当する内容を さっきみせてもらったので ?な部分(3つの疑問のうちの上の2うも含め)は 公開せずにとどめておきます。 こちらこそありがとうございました。
kawakawa2018

2018/04/28 13:11

hayataka2049さま ご指摘いただきありがとうございました。 確認するのに時間がかかりました。 ですがこれを見ている知り合いから コメントが来ていると聞いたので (自分では確認していませんが) 彼も計算の結果は同じ、とのことでした。 図も含め取り消しておきます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問