NLLLoss 損失関数のCクラスについて質問しています。
ドキュメントは述べています:
負の対数尤度損失。 Cクラスを使用して分類問題をトレーニングすると便利です。
基本的に、それ以降のすべては、Cクラスが何であるかを知っているかどうかに依存します。Cクラスとは何か知っていると思いましたが、ドキュメントは私にはあまり意味がありません。特に、それが_(N, C) where C = number of classes
_の予想される入力を記述する場合。 Cクラスがoutputのみを参照していると思ったので、ここで混乱します。私の理解では、Cクラスは分類のホットなベクトルの1つでした。チュートリアルでNLLLoss
がLogSoftmax
とペアになって分類の問題を解決することがよくあります。
次の例ではNLLLoss
を使用すると予想していました。
_# Some random training data
input = torch.randn(5, requires_grad=True)
print(input) # tensor([-1.3533, -1.3074, -1.7906, 0.3113, 0.7982], requires_grad=True)
# Build my NN (here it's just a LogSoftmax)
m = nn.LogSoftmax(dim=0)
# Train my NN with the data
output = m(input)
print(output) # tensor([-2.8079, -2.7619, -3.2451, -1.1432, -0.6564], grad_fn=<LogSoftmaxBackward>)
loss = nn.NLLLoss()
print(loss(output, torch.tensor([1, 0, 0])))
_
上記の場合、最終行で次のエラーが発生します。
ValueError:2つ以上のディメンションが必要です(1を取得)
このエラーは無視できます。私が何をしているのかはっきりと理解していないからです。ここで、上記のソースコードの意図を説明します。
_input = torch.randn(5, requires_grad=True)
_
トレーニングのために_[1, 0, 0]
_の1つのホットベクトルとペアにするランダム1D配列。私は10進数の1つのホットベクトルにバイナリビットをしようとしています。
_m = nn.LogSoftmax(dim=0)
_
LogSoftmax
のドキュメントには、出力は入力と同じ形状になると記載されていますが、LogSoftmax(dim=1)
の例しか見たことがありません。相対的な例が見つかりません。
_print(loss(output, torch.tensor([1, 0, 0])))
_
これで、NNの出力が得られました。分類_[1, 0, 0]
_による損失を知りたいのですが。この例では、どのデータが何であるかは重要ではありません。分類を表す1つのホットベクトルの損失が欲しいだけです。
この時点で、予想される出力および入力構造に関連する損失関数からのエラーを解決しようとすると、行き詰まります。出力と入力でview(...)
を使用して形状を修正しようとしましたが、それだけで他のエラーが発生します。
だから、これは私の元の質問に戻り、混乱を説明するためにドキュメントの例を示します:
_m = nn.LogSoftmax(dim=1)
loss = nn.NLLLoss()
input = torch.randn(3, 5, requires_grad=True)
train = torch.tensor([1, 0, 4])
print('input', input) # input tensor([[...],[...],[...]], requires_grad=True)
output = m(input)
print('train', output, train) # tensor([[...],[...],[...]],grad_fn=<LogSoftmaxBackward>) tensor([1, 0, 4])
x = loss(output, train)
_
繰り返しますが、LogSoftmax
データを見て、input
に_dim=1
_があるので混乱します。これは_3x5
_テンソルで、迷っています。
NLLLoss
関数の最初の入力に関するドキュメントは次のとおりです。
入力:(N、C)(N、C)ここで、C =クラスの数
入力はクラスの数によってグループ化されています?
したがって、テンソル入力の各rowは、各elementに関連付けられますトレーニングテンソル?
入力テンソルの2番目の次元を変更すると、何も壊れず、何が起こっているのか理解できません。
_input = torch.randn(3, 100, requires_grad=True)
# 3 x 100 still works?
_
だから私はここにCクラスが何であるか理解していません、そして私はCクラスが分類(ラベルのような)であり、NNの出力でのみ意味があると思いました.
NNの入力の形状は、分類に使用される1つのホットベクトルの形状から独立してはならないので、私の混乱を理解していただければ幸いです。
コード例とドキュメントの両方で、入力の形状は分類の数によって定義されると述べていますが、その理由はよくわかりません。
不足しているものを理解するためにドキュメントとチュートリアルを調査しようとしましたが、この点を超えることができなくなって数日後、私はこの質問をすることにしました。これは簡単に学ぶことができるものの1つになると思っていたので、それは謙虚でした。
基本的に、batch
の概念がありません。
要するに、損失へのすべての入力(およびネットワークを通過する入力)には、batch
次元(つまり、使用されるサンプルの数)が必要です。
それを分解して、段階的に:
各ステップは、明確にするために比較された各ステップになります(一番上のドキュメント、下の例)
_input = torch.randn(3, 5, requires_grad=True)
input = torch.randn(5, requires_grad=True)
_
最初のケース(ドキュメント)では、_5
_機能を持つ入力が作成され、_3
_サンプルが使用されます。あなたの場合、batch
次元(_5
_サンプル)しかないため、機能はありません必須。 _5
_機能を備えたサンプルを1つ用意するつもりなら、次のようにする必要があります。
_input = torch.randn(5, requires_grad=True)
_
LogSoftmax
は機能のディメンション全体で実行され、バッチ全体で実行されます。
m = nn.LogSoftmax(dim = 1)#機能に適用m = nn.LogSoftmax(dim = 0)#バッチに適用
サンプルは互いに独立しているため、通常、この操作には意味がありません。
これはマルチクラス分類であり、ベクトルの各要素はサンプルを表すため、必要な数の数値を渡すことができます(機能の数よりも小さい限り、ドキュメンテーションの例の場合、_5
_、つまり_[0-4]
_ 結構です )。
_train = torch.tensor([1, 0, 4])
train = torch.tensor([1, 0, 0])
_
私は、あなたがターゲットとしてワンホットベクターも渡したかったと思います。 PyTorchはmemory inefficientであるため、そのようには機能しません(クラスを正確に特定できるのに、すべてをワンホットエンコードとして格納するのはなぜですか(この場合、_0
_になります))。
すべての出力ノードを介してエラーを逆伝播するために、ニューラルネットワークの出力のみが1つのホットエンコードされます。ターゲットには必要ありません。
すべきではないこのタスクには_torch.nn.LogSoftmax
_を使用まったく最後のレイヤーとして_torch.nn.Linear
_を使用し、ターゲットで_torch.nn.CrossEntropyLoss
_を使用するだけです。
nn.NLLLoss()
のドキュメントが理想的とはほど遠いことに同意しますが、まず「クラス」が「カテゴリ」の同義語としてよく使用されることを明確にすることで、ここで問題を明確にできると思います機械学習のコンテキスト。
したがって、PyTorchがC
クラスについて話しているとき、それは実際には、ネットワークをトレーニングしようとしている個別のカテゴリの数を参照しています。したがって、「猫」と「犬」を分類しようとするカテゴリ型ニューラルネットワークの古典的な例では、C = 2
は猫または犬であるためです。
特にこの分類問題では、カテゴリの配列全体に1つの単一の真理値しかないことも保持します(画像は猫と犬の両方を表すことはできませんが、常にどちらか一方のみを表すことができます)。画像の対応するカテゴリをインデックスで簡単に示すことができるのはこのためです(0
は猫を示し、1
は犬を示すとしましょう)。これで、ネットワーク出力を必要なカテゴリと簡単に比較できます。
しかし、これが機能するためには、これらの損失値が(ネットワーク出力で)参照しているものも明確にする必要があります。これは、ネットワークが一般に予測を行うためです異なる出力ニューロンのソフトマックスを介して 、つまり、通常は複数の値を持っていることを意味します。幸い、PyTorchのnn.NLLLoss
はこれを自動的に行います。
上記のLogSoftmax
を使用した例では、実際には1つの出力値しか生成されません。これは、この例の重要なケースです。この方法では、基本的に何かが存在するかどうかの指示しかありませんが、分類の例で使用することはあまり意味がありません。回帰の場合はなおさらです(ただし、まったく異なる必要があります)。はじめに損失関数)。
最後に、重要なことですが、バッチ処理(複数のサンプルの同時計算)は通常、パフォーマンスを一致させるために必要なステップと見なされているため、通常、入力として2Dテンソルがあることも考慮する必要があります。バッチサイズ1を選択した場合でも、これは入力が次元(batch_size, input_dimensions)
であることが必要であり、その結果、形状(batch_size, number_of_categories)
の出力テンソルが必要です。
これは、オンラインで見つけたほとんどの例がdim=1
上でLogSoftmax()
を実行している理由を説明しています。これは、「dim=0
」であるバッチ軸ではなく、「配布中の軸」であるためです。
単に問題を修正したい場合、最も簡単な方法は、ランダムテンソルを追加の次元(torch.randn([1, 5], requires_grad=True)
)だけ拡張し、出力テンソル(print(loss(output, torch.tensor([1]))
)