```python=
#以下のソースコードではそのままでは動かない.何箇所が修正し,(1,2,3,4)に対する出力が1になるようなSoftmax回帰を実装せよ.
#softmax回帰なので,argmax(sofmax(出力)))が1になればよいことに注意.
import torch
from torch import nn,optim #optimを追加
class Net(nn.Module):
def __init__(self,input_size,output_size): #input_size,output_sizeを定義
super(Net, self).__init__()
self.input_size = input_size
self.output_size = output_size
self.l1 = nn.Linear(input_size,output_size) #l1を定義
def forward(self, x):
l1 = nn.Linear(4, 3) #出力を1に修正→3へ戻す
return l1(x)
net, x, y = Net(4,3), torch.tensor([1,2,3,4] ,dtype=torch.float32), torch.tensor([1]) #xをfloatへ。[]が余分に多いので削除。
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(net.parameters(),lr = 0.1) #学習率がないので(lr = 0.1)を追加
for epoc in range(100):
optimizer.zero_grad()
loss = criterion(net(x),y) #yも加えて、予測値と実際の値の損失を計算
loss.backward() #損失によるパラメータの微分
optimizer.step() #勾配を更新
```
実行すると、下記のエラーが出るのですが、わからずつまっております。損失を計算するときに、次元がおかしい?ということを言われていると思うのですが、yの次元が正しくないのでしょうか。
```
IndexError Traceback (most recent call last)
<ipython-input-7-23cf696f57ab> in <module>()
24 for epoc in range(100):
25 optimizer.zero_grad()
---> 26 loss = criterion(net(x),y) #yも加えて、予測値と実際の値の損失を計算
27 loss.backward() #損失によるパラメータの微分
28 optimizer.step() #勾配を更新
3 frames
/usr/local/lib/python3.6/dist-packages/torch/nn/functional.py in log_softmax(input, dim, _stacklevel, dtype)
1533 dim = _get_softmax_dim('log_softmax', input.dim(), _stacklevel)
1534 if dtype is None:
-> 1535 ret = input.log_softmax(dim)
1536 else:
1537 ret = input.log_softmax(dim, dtype=dtype)
IndexError: Dimension out of range (expected to be in range of [-1, 0], but got 1)
```
次元がおかしいのはそのとおりですね。クロスエントロピーは分類を行うので、例えば、3値分類の場合、3次元の出力が必要になります。
今はl1が(4,1)つまり、l1(x)が一次元になのっているので、1次元のものをどうやって分類するんだとなっています
l1(x)の入力の次元と出力の次元を合わせないといけない、ということでしょうか?
違いますね。 Softmax回帰を思い出してほしいのですが、
例えば、3値分類の場合、(0.1, 0.1, 0.8)と出力され、0.8が一番高いので、そのindexの2が答えと予測していました。
ですが、今の場合、出力が1次元なので、どんな値だとしても(3)も(-1)も(0.1)も確率に直すと(1)となるので、学習する話ではなくなっています。
こういう場合、PytorchのCrossEntropyはエラーとなり、上のような、エラーメッセージを出力します。
ありがとうございます、理解できました。
こちら、l1を(4,3)に直して実行しても同じエラーが出てしまい、
はい、同じエラーが出てしまいます。
同じエラーですか?
実際、他にも誤りがあり、(答えを言っていしまうと),CrossEntropyの仕様的には
`x = torch.tensor([[1,2,3,4]]).float()`としないといけないです。(もしくは出力に対し、`view(1,-1)`を実施
なぜかというと、CrossEntropyを実施する時、基本的に複数データを想定しているので、出力の最初のindexがデータの位置を表すんですよね。
今回の場合、net(x)[0]とy[0]を比較するので、今の出力だとnet(x)[0]が一次元になってしまいますね。。。
直したらエラーなく実行できたのですが、すみません
torch.tensor([1,2,3,4] ,dtype=torch.float32)
これだと、なぜ
xのshape(とnet(x)のshape)を見てほしいのですが、
__パターン1__
x = torch.tensor([1,2,3,4] ,dtype=torch.float32)の場合
net(x)は要素を3つ持つ一次元配列になります。
__パターン2__
x = torch.tensor([[1,2,3,4]] ,dtype=torch.float32)の場合
net(x)は1×3の多次元配列になります。
cross_entropyは極端なことをいうと
for i in len(y):
1. net(x)[i]とy[i]のクロスエントロピーの計算
2. それを足す
とするのですが、今の場合は正解データが一つなので、i=0の時だけ比較しています。
パターン1の場合、 net(x)[0]は配列ではなく一つのfloat型の要素になります。
パターン2の場合、net(x)[0]は要素3の一次元配列になります。
なので、エラーが起きません。
で大丈夫ですかね
ありがとうございます、一次元配列になっていたことに気づかなかったです、、、理解できました。
これは割とやらかすミスなので、今後も気をつけておいてくれると嬉しいです。
(CrossEntropyを楽に計算しようとした結果なのか、仕様が若干特殊なので。)
これで問題2はよさそうですね。問題3頑張りましょう。
確認遅れてすみません、、
気を付けたいと思います...!
ありがとうございます!
演習3なのですが、
```python=
#以下のソースコードではそのままでは動かない.何箇所が修正し,(1,2,3,4)に対する出力が1になるようなNNを実装せよ.(NNの出力であることに注意)
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.nn_list = [nn.Linear(4,4), nn.Linear(4, 3)]
def forward(self, x):
for l in nn_list:
x = nn.ReLU()(l(x))
return x #最後の,を削除
net, x, y = Net(), torch.tensor([[1,2,3,4], [2,3,10,1]]), torch.tensor([1, 2]) #[]を追加してx引数を1つにする。
criterion = nn.MSELoss() #MSElossへ変更
optimizer = torch.optim.SGD(net.parameters())
for i in range(100):
optimizer.zero_grad()
criterion(net(x), y).backward() #;を削除
optimizer.step()
```
下記のようなエラーが出て、パラメータのリストが空になっている?というのがよくわからないです
今net()のパラメータは何が出てほしいか想像できますかね?
入力と出力の次元が下記
[nn.Linear(4,4), nn.Linear(4, 3)]が
時間があれなので、結論を書くと
net()のパラメータはLinear(4,4),Linear(4, 3)の行列とバイアスです。
https://esa-pages.io/p/sharing/7890/posts/379/65afea3cf64813f6a47c-slides.html#/197
を思い出してほしいのですが、
nnのパラメータは
nn.Moduleクラスの変数になっているnn,Moduleクラス or Parameterクラスです。
例えば、nn.ModuleListはnn.Moduleの子クラスなので、この内部にあるparameterが設定されます。
ですが、今だと Linearは 配列の要素になっているので、Parameterにはならない状況です。
なので、 配列を単純にnn.ModuleListに直すだけでもこのエラー自体は解決します。
ValueError Traceback (most recent call last)
<ipython-input-37-2cb8970f7d7a> in <module>()
12 net, x, y = Net(), torch.tensor([[1,2,3,4], [2,3,10,1]]), torch.tensor([1, 2]) #[]を追加してx引数を1つにする。
13 criterion = nn.MSELoss() #MSElossへ変更
---> 14 optimizer = torch.optim.SGD(net.parameters())
15 for i in range(100):
16 optimizer.zero_grad()
1 frames
/usr/local/lib/python3.6/dist-packages/torch/optim/optimizer.py in __init__(self, params, defaults)
44 param_groups = list(params)
45 if len(param_groups) == 0:
---> 46 raise ValueError("optimizer got an empty parameter list")
47 if not isinstance(param_groups[0], dict):
48 param_groups = [{'params': param_groups}]
ValueError: optimizer got an empty parameter list
```