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

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

ただいまの
回答率

90.84%

  • Python

    5910questions

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

  • Python 3.x

    4443questions

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

  • NumPy

    326questions

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

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

受付中

回答 2

投稿

  • 評価
  • クリップ 1
  • VIEW 145

 softmax関数の実装

「ゼロから作るDeep Learning」を読み進める中でsoftmax関数が登場しました。本の通り実装して、そのあとの誤差逆伝播法の章で勾配確認をしました。しかし、数値微分で求めた勾配と誤差逆伝播法で求めた勾配の差が本に書いてあるような小さな値になりませんでした。そこで提供されているソースコードを読み、自分のコードと見比べた結果、softmax関数の実装に違いがあり、提供されているソースコードの実装方法に合わせると、差は小さな値になりました。

 自分が書いたソースコード

def softmax(x):
    c = np.max(x)
    exp_a = np.exp(x - c)
    sum_exp_a = np.sum(exp_a)
    y = exp_a / sum_exp_a
    return y

 提供されているソースコード

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))

 自分が分からない部分

  • なぜxが2次元の時のみ場合分けを行なっているのか
  • なぜ行列の転置をとっているのか
  • なぜ自分の実装方法だと、数値微分・誤差逆伝播法それぞれで求めた勾配の差が大きくなるのか

 補足情報

softmax関数以外の部分は提供されているソースコードと同じでした。softmax関数の実装方法の違いのみで、結果に差が出ていると思われます。

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

0

やってることは単純で、複数のデータに対して同時に計算できる機能を付与しているだけに見えます。

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))

a = np.random.rand(3, 10)
print(softmax(a[0]))
print(softmax(a[1]))
print(softmax(a[2]))

print(softmax(a))

""" # =>
[0.08629677 0.09433006 0.06536112 0.12163197 0.13861227 0.13997268
 0.06971638 0.08295977 0.06633675 0.13478224]
[0.0689522  0.1649164  0.08518756 0.08926251 0.10106928 0.07014795
 0.08651658 0.07375167 0.16915227 0.09104358]
[0.0640806  0.12950118 0.1455273  0.09357789 0.06604187 0.09396754
 0.06749124 0.06936294 0.13728469 0.13316475]
[[0.08629677 0.09433006 0.06536112 0.12163197 0.13861227 0.13997268
  0.06971638 0.08295977 0.06633675 0.13478224]
 [0.0689522  0.1649164  0.08518756 0.08926251 0.10106928 0.07014795
  0.08651658 0.07375167 0.16915227 0.09104358]
 [0.0640806  0.12950118 0.1455273  0.09357789 0.06604187 0.09396754
  0.06749124 0.06936294 0.13728469 0.13316475]]
"""

質問者様のコードはこの機能がありません。

その本は読んだことがありませんが、この機能が必要な実装になっているのでしょう。確認してみてください。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

質問者様
はじめまして

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

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

少し検証しました。

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

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

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

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

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

ここまで追加 4月28日夜

 前提

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

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

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

 検証

「その値が1に近づく関数」とは、
その出力の総和が限りなく1に近づくことですね。読んでいてふと、
この質問への回答につながるsoftmax関数の実装が正しくなされているか、疑問になりました。
そもそも質問者様も回答者様も、softmax関数の正しさを書かれていないし
(たぶん)検証されていないことに気がつきました。

そこでソースを修正し、検証しました。print(np.sum(w))を追加し
総和が1に近づくか繰り返し実行してみました。

(hayataka2049様のコードを修正させていただきました)

 検証コードと結果

import numpy as np

# "softmax_div(a) 自分(=質問者様)が書いたソースコード:"
def softmax_div(x):
    c = np.max(x)
    exp_a = np.exp(x - c)
    sum_exp_a = np.sum(exp_a)
    y = exp_a / sum_exp_a
    return y

# "softmax(a) 提供されているソースコード:"
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))

a = np.random.rand(3, 10)

# コメント化
'''
print(softmax(a[0]))
print(softmax(a[1]))
print(softmax(a[2]))
'''
# 以下を追加した
print("softmax_div(a) 自分(=質問者様)が書いた:")
w = softmax_div(a)
print(w)
print(np.sum(w))

print()

print("softmax(a) 提供されているソースコード:")
w = softmax(a)
print(w)
print(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 19:16

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

    キャンセル

  • 2018/04/28 21:19

    コメントありがとうございます。

    なぜ自分の実装方法だと、数値微分・誤差逆伝播法それぞれで求めた勾配の差が大きくなるのか という3番目の疑問、その解決につながるかと思い、掲載された関数を調べました。

    私の回答に追加する内容もあったのですが、
    数学的な点にとどめておきます。

    ありがとうございました。

    キャンセル

  • 2018/04/28 21:57

    コメントありがとうございます。

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

    お二方ともありがとうございました。

    キャンセル

  • 2018/04/28 22:05 編集

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

    キャンセル

  • 2018/04/28 22:07

    yakiniku_obakeさん
    わざわざコメントありがとうございました。

    「ミニバッチを利用するプログラムなので入力を行ごとに処理する・・・」

    こちらも知り合いに本の該当する内容を
    さっきみせてもらったので
    ?な部分(3つの疑問のうちの上の2うも含め)は
    公開せずにとどめておきます。

    こちらこそありがとうございました。

    キャンセル

  • 2018/04/28 22:11

    hayataka2049さま

    ご指摘いただきありがとうございました。
    確認するのに時間がかかりました。
    ですがこれを見ている知り合いから
    コメントが来ていると聞いたので

    (自分では確認していませんが)

    彼も計算の結果は同じ、とのことでした。
    図も含め取り消しておきます。

    キャンセル

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

  • ただいまの回答率 90.84%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

  • 解決済

    pythonでfor文の多重構造を作る

    前提・実現したいこと リストから数字を1つ取り出し、数字の数だけランダムな数字を発生させる。それらの数字の総和をとる。 この動作をリストの要素回行う。 最後にリストのそれぞれ

  • 解決済

    (Python)構文間違い

    構文間違い(SyntaxError: invalid syntax)と怒られましたけど、 どこが間違っているのかを教えてください。 コード: class michael:

  • 解決済

    Pythonでforループをベクトル演算に

    pythonはforループを回すより、リスト内包表記やベクトル演算に置き換えた方が早いと言われている様なのですが、下記の計算をベクトル演算に置き換えることは可能でしょうか?

  • 解決済

    二次元配列で、2番目の要素が最大のものをピックアップしたい

    二次元配列で、2番目の要素が最大のものをピックアップしたいです。 select_one配列に[[1, 3, 1], [1, 6, 6]] が入っています。 select_one[0

  • 解決済

    cythonでの型の付け方

    cythonのpyxファイルに型つけをしたいです import numpy as np def gaussian(x, mean, cov): A = 1. / ((

  • 解決済

    cythonの型定義

    cythonファイルに型を定義したいです もともとのpyxファイルと 自分で型を定義したときのコードをのせます gamma1.pyx from math import exp

  • 解決済

    測定データを積分関数でフィッティングしたいです。

    前提・実現したいこと scipy.optimizeのlastsqを用いたフィッティングについて質問です。 フィッティングする関数に、積分関数を使いたいと思ってます。 残渣を求める行

  • 解決済

    Pythonの階層クラスタを構成する葉を取得したい。

    Pythonの scipy.cluster.hierarchyで階層クラスタリングをすると、以下のようなリンケージ行列だけが返ってきますが、簡単にクラスタを構成する葉を取ってくるこ

同じタグがついた質問を見る

  • Python

    5910questions

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

  • Python 3.x

    4443questions

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

  • NumPy

    326questions

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