---
# System prepended metadata

title: Untitled

---

```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頑張りましょう。

確認遅れてすみません、、
気を付けたいと思います...！
ありがとうございます！


演習３なのですが、
```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
```

