PyTorchで関数フィッティング

PyTorchが1.0になったらしいので、TensorFlowとJulia言語機械学習フレームワーク(Knet.jlとFlux.jl)しか触ったことがないけれども、見よう見まねでコードを書いてみる。

目的は、
「JuliaでTensorFlow その5: ニューラルネットワークの導入と深層学習」
https://qiita.com/cometscome_phys/items/45017aa9741c5fdc7eb9
「TensorFlowの高レベルAPIの使用方法：tf.layersの使い方と重みなどの取り出し方」
https://qiita.com/cometscome_phys/items/95ed1b89acc7829950dd

などで使っていた関数をPyTorchでも再現することである。

# バージョン
PyTorch: 1.0.0 
Python: 3.6.4

# 再現すべき関数

```python:test.py
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline

n = 10
x0 = np.linspace(-2.0, 2.0, n)
a0 = 3.0
a1 = 2.0
b0 = 1.0
y0 = np.zeros((n,1),dtype = 'Float32')
y0[:,0] = a0*x0+a1*x0**2 + b0 + 3*np.cos(20*x0)

plt.plot(x0,y0 )
plt.show()
plt.savefig("graph.png")
```

![Unknown.png](https://qiita-image-store.s3.amazonaws.com/0/246113/bb2c50d8-4795-0851-9644-8b8cb6c61694.png)

このグラフをフィッティングするにあたって、
インプットは多項式でとする（これまでの記事を参照）。
隠れ層が何もなければ多項式による線形回帰となる。インプットは

```python:test.py
def make_phi(x0,n,k):    
    phi = np.array([x0**j for j in range(k)])
    return phi.T

k = 4
phi = make_phi(x0,n,k)
print(phi[0,:])
d_input = k
d_middle = 10
```
で定義しておく。


# モデルの定義
PyTorchでは以下のようにモデルを定義する。

```python
import torch 
import torch.nn as nn 
import torch.nn.functional as F
from torch.autograd import Variable
import torch.optim as optim

class Net(nn.Module):
    def __init__(self,d_inp,d_middle,d_out):
        super(Net, self).__init__()
        self.fc1 = nn.Linear(d_inp,d_middle)
        self.fc2 = nn.Linear(d_middle, d_out)

    def forward(self, x):
        x = F.relu(self.fc1(x))
        x = self.fc2(x)        
        return x
```
ここで、モデルのニューラルネットワークのサイズを作成時に決められるようにしておいた。
これで、隠れ層一層のニューラルネットワークとなっている。
モデルは、

```python
d_out = 1
net = Net(d_input,d_middle,d_out)
```
で作られる。

# loss関数と最適化
次に、loss関数とその最適化を決める。
TensorFlowでは先にグラフを作っていたが、PyTorchでは先にグラフを作らない。

```python
learning_rate = 0.001

print(net)
params = list(net.parameters())
print(params)
```
これで、ネットワークがどのようになっているか、と、最適化すべきパラメータに何があるかがわかる。
インプットと正解データをテンソルとして用意するには、

```python
input = torch.from_numpy(phi[:,:])
target = torch.from_numpy(y0)
```
とすればよい。
そして、loss関数は平均二乗誤差：

```python
criterion = nn.MSELoss()
```
を選び、最適化にはADAM:

```python
optimizer = optim.Adam(net.parameters(), lr=learning_rate)
```
を使用することとする。

#学習

学習は、

```python
nt = 20000
for i in range(nt):
    optimizer.zero_grad() #勾配の初期化？　必要らしい
    output = net(input) #アウトプットの生成
    loss = criterion(output, target) #loss関数
    loss.backward() 
    optimizer.step()
    if i %1000 is 0:
        print(i,loss.item())

print(params[:])      
print('Finished Training')
ye = net(input).detach().numpy()
plt.plot(x0,y0 )
plt.plot(x0,ye,'o')
plt.show()
plt.savefig("graph_2.png")
```
となる。

得られた図は

![Unknown.png](https://qiita-image-store.s3.amazonaws.com/0/246113/5305653b-97f0-7805-2c65-7f1c49d175b3.png)



である。

#全体のコード

全体のコードは

```python
import numpy as np
import matplotlib.pyplot as plt
# %matplotlib inline   # Jupyter用

n = 10
x0 = np.linspace(-2.0, 2.0, n)
a0 = 3.0
a1 = 2.0
b0 = 1.0
y0 = np.zeros((n,1),dtype = 'Float32')
y0[:,0] = a0*x0+a1*x0**2 + b0 + 3*np.cos(20*x0)

plt.plot(x0,y0 )
#plt.show()
plt.savefig("graph.png")

def make_phi(x0,n,k):    
    phi = np.array([x0**j for j in range(k)],dtype = 'Float32')
    return phi.T

k = 4
phi = make_phi(x0,n,k)
print(phi[0,:])
d_input = k
d_middle = 10

import torch 
import torch.nn as nn 
import torch.nn.functional as F
from torch.autograd import Variable
import torch.optim as optim


learning_rate = 0.001


class Net(nn.Module):
    def __init__(self,d_inp,d_middle,d_out):
        super(Net, self).__init__()
        self.fc1 = nn.Linear(d_inp,d_middle)
        self.fc2 = nn.Linear(d_middle, d_out)

    def forward(self, x):
        x = F.relu(self.fc1(x))
        x = self.fc2(x)        
        return x

d_out = 1
net = Net(d_input,d_middle,d_out)
print(net)
params = list(net.parameters())
print(params)

input = torch.from_numpy(phi[:,:])
target = torch.from_numpy(y0)

criterion = nn.MSELoss()
optimizer = optim.Adam(net.parameters(), lr=learning_rate)

nt = 20000

for i in range(nt):
    optimizer.zero_grad()
    output = net(input)
    loss = criterion(output, target)
    loss.backward()
    optimizer.step()
    if i %1000 is 0:
        print(i,loss.item())

print(params[:])      
print('Finished Training')
ye = net(input).detach().numpy()
plt.plot(x0,y0 )
plt.plot(x0,ye,'o')
#plt.show()
plt.savefig("graph_2.png")

```
となる。