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

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

新規登録して質問してみよう
ただいま回答率
85.37%
人工知能

人工知能とは、言語の理解や推論、問題解決などの知的行動を人間に代わってコンピューターに行わせる技術のことです。

機械学習

機械学習は、データからパターンを自動的に発見し、そこから知能的な判断を下すためのコンピューターアルゴリズムを指します。人工知能における課題のひとつです。

Q&A

解決済

2回答

7990閲覧

pytorchの二値分類で、出力した確率を知りたい。

tutt

総合スコア16

人工知能

人工知能とは、言語の理解や推論、問題解決などの知的行動を人間に代わってコンピューターに行わせる技術のことです。

機械学習

機械学習は、データからパターンを自動的に発見し、そこから知能的な判断を下すためのコンピューターアルゴリズムを指します。人工知能における課題のひとつです。

0グッド

0クリップ

投稿2021/09/25 15:57

機械学習を勉強している者です。
pytorchのニューラルネットワークで二値分類を行おうと、先行事例を探していたところ、下記ブログを見つけました。
ワインの二値分類

この通りに実装し、無事に動いたのですが、分類結果0, 1 のそれぞれの確率がどうなっているかを見ようと、この様な実装を行いました。

python

1test_x, test_y = Variable(test_X), Variable(test_Y) 2y_pred_prob = model(test_x) 3print(y_pred_prob) 4 5#以下出力 6tensor([[ -8.1126, -2.6467], 7 [ -8.4808, -2.1014], 8 [ -8.5551, -1.9885], 9 [ -8.2549, -2.4324], 10 [ -5.4921, -6.5018], 11 [ -4.2638, -8.3200], 12 [ -6.6616, -4.7711], 13 [ -6.4839, -5.0384],

使っている出力の関数はlog_softmaxで、pytorchのドキュメント(log_softmaxについて)を調べたとところ、ソフトマックス関数をlogの中に入れているだけでした。

そこで、ただのソフトマックス関数に直せば、例えば0:0.9, 1:0.1の様な0, 1のラベルがそれぞれ何%の確率で予想しているかが出ると思い、下記の様にログを外したものを算出したところ、期待とは異なる値が返ってきました。

python

1x = [-8.1126, -2.6467] 2A1 = 2**x[0] 3A2 = 2**x[1] 4print('A1 : ', A1) 5print('A2 : ', A2) 6print('A1+A2: ', A1+A2) 7 8#以下出力 9A1 : 0.003612967518575162 10A2 : 0.15968492199325068 11A1+A2: 0.16329788951182583

予想ではA1+A2=1.0となると思ったのですが、上記の様になっております。何か考え方が違うと思うのですが、自力ではわかりませんでしたので、どこが違っているのかをご教示ください。

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

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

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

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

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

jbpb0

2021/09/25 23:06

質問内容とは違いますが > 使っている出力の関数はlog_softmax https://qiita.com/ground0state/items/8933f9ef54d6cd005a69 から抜粋 「torch.nn.CrossEntropyLoss()は、損失関数内でソフトマックス関数の処理をしたことになっているので、ロスを計算する際はニューラルネットワークの最後にソフトマックス関数を適用する必要はない。」 https://colab.research.google.com/github/YutaroOgawa/pytorch_tutorials_jp/blob/main/notebook/1_Learning%20PyTorch/1_4_cifar10_tutorial_jp.ipynb を見ても、ニューラルネットの定義にはソフトマックスは入ってません
guest

回答2

0

ベストアンサー

まず、この質問の内容とは直接は関係無いのですが、
PytorchのCrossEntropyLossの解説
とかに書かれてるように、「torch.nn.CrossEntropyLoss()」には「log_softmax」の計算も含まれてるので、「torch.nn.CrossEntropyLoss()」を使う場合はニューラルネットの定義側には「log_softmax」は不要です

なので、
PyTorchを用いてディープラーニングによるワイン分類をしてみた
のコードは、下記の修正をした方がいいです

python

1 return F.log_softmax(x, dim=0)

↓ 変更

python

1 return x

その上で、

python

1y_pred_prob = model(test_x).softmax(dim=1)

を計算したら、二つの合計が1.0になります
(それが確率かどうかは別にして)

 .
なお、toast-uzさんが回答に書いてるように、修正前の

python

1 return F.log_softmax(x, dim=0)

の「dim=0」は間違いで、「dim=1」が正しいです
そこを直して、

python

1y_pred_prob = torch.exp(model(test_x))

を計算しても、二つの合計は1.0になります
ただし、「log_softmax」を二重に計算するので、効率が悪くなると思います

投稿2021/09/26 01:48

編集2021/09/26 02:42
jbpb0

総合スコア7653

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

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

toast-uz

2021/09/26 01:59 編集

よく見たら、元記事はdim=0でした。モデルに書くか、外に書くかは関係無いようです。モデルに書くと、loss計算においてsofmaxを二重に適用していることになり、学習効率は悪くなるとは思います。
jbpb0

2021/09/26 02:04 編集

toast-uzさん 「log_softmax」をニューラルネット定義の外に出したのは、 https://qiita.com/ground0state/items/8933f9ef54d6cd005a69 とかに書かれてるように、「torch.nn.CrossEntropyLoss()」内に「log_softmax」が入ってるので、ニューラルネット定義側には不要だからです なので、ネットワーク定義を「torch.nn.CrossEntropyLoss()」使用時の正しい書き方に直した上で、質問者さんが要望してる「確率」(的なもの)が計算できるような回答にしました この質問の計算が合わない(合計を1.0にしたい)の回答としては、そこまでしなくてもいいとは思ったのですが、ついでに
toast-uz

2021/09/26 02:15 編集

あ、はい。元の質問文へのjbpb0様のコメントで、その点は理解しました。なので、私の上のコメントでも、jbpb0様の回答を、よりよいものとして位置づけています。ただし、今回の質問の根本は、そこ(モデルの中に書くか外に書くか)ではなく、元記事でdim=1をdim=0と間違えていることだと思います。jbpb0様の回答は、元記事をdim=1(正しい)としてしまっていますので、まずは元記事の間違いを指摘した上で、モデルの中外の話を追加されると、よくなると思います。 なお、精度への寄与という点では、質問から外れますが、私の回答に記述した標準化の欠如が、大きく影響を与えています。
jbpb0

2021/09/26 02:36

> jbpb0様の回答は、元記事をdim=1(正しい)としてしまっています あ、そこ間違ってると思って直して走らせた後に、戻すの忘れて引用して回答を書いてしまいました 回答を修正しました
guest

0

3つ間違いがあります。2つは参照している記事の間違い、1つは質問者様の間違いです。

  1. 記事では、log_sofmaxをdim=0で適用していまが、dim=1が正しいです。こうすることで、多値分類の分類クラス方向に正規化がされた値になります。

  2. これは質問とは直接関係ありませんが、記事では予めデータの標準化がされていません。そのため、精度が悪くなってしまっています。標準化をしてから学習すれば、かなり精度があがります。

  3. 質問者様がスケールをlogから修正する際に、底を2にしていますが、e(自然対数の底)を使うことが正しいです。

なお、分類問題の出力を「確率」と解釈するのは注意したほうがよいです。正解ラベル(0または1)に近い推論ができるように学習されただけで、確率的な意味を持つものではありません。

(元記事を実際に動かしてみましたが、特に、1と3は、jbpb0様のコメントをヒントに、気が付きました)

投稿2021/09/25 23:00

編集2021/09/26 02:01
toast-uz

総合スコア3266

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

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

jbpb0

2021/09/26 00:49

toast-uzさん import torch x = torch.randn(2, dtype=torch.float) lsm = torch.nn.functional.log_softmax(x, dim=0) sme = torch.exp(lsm) sm = torch.nn.functional.softmax(x, dim=0) print(x) print(lsm) print(sme) print(sm) print(torch.sum(sme)) print(torch.sum(sm)) を実行すると、「sme」と「sm」は同じになり、どちらも合計は1.0になります しかしながら、質問に書かれてる「y_pred_prob」の数値のペアを torch.exp(torch.tensor([-8.1126, -2.6467])) torch.sum(torch.exp(torch.tensor([-8.1126, -2.6467]))) の様に処理しても、合計は1.0にはなりません 上記の私のコードの「torch.nn.functional.log_softmax(x, dim=0)」と、質問者さんが参考にしてるWebページのニューラルネットの定義の「F.log_softmax(x, dim=0)」は、やってることが違うのでしょうか?
toast-uz

2021/09/26 01:47

あ、すみません。分かりました。解答修正します。
jbpb0

2021/09/26 02:13

> 記事では、log_sofmaxをdim=0で適用していまが、dim=1が正しい > logから修正する際に、底を2にしていますが、e(自然対数の底)を使うことが正しい を確認しました return F.log_softmax(x, dim=1) と変えて実行して、 y_pred_prob = torch.exp(model(test_x)) を計算したら、二つの合計が1.0になりました
tutt

2021/09/26 03:27

toast-uz様、jbpb0様 お二方ともアドバイスありがとうございました。どちらの回答も大変勉強になり、ベストアンサーをつけるのを迷いましたので、2つあるご回答にそれぞれ高評価をつけさせていただきました。 改めて、ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.37%

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

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

質問する

関連した質問