Pytorchチュートリアル【第3章 簡単なニューラルネットワーク】
記事ディレクトリ
第3章 シンプルなニューラルネットワーク
3.1 ニューラルネットワークの学習手順
一般的なニューラル ネットワークのトレーニング プロセスには、次の点が含まれます。
-
トレーニング可能なパラメータを使用してニューラル ネットワークを定義する
-
入力全体を反復処理します
-
ニューラルネットワークを介した入力の処理
-
損失(損失)の計算
-
勾配をニューラル ネットワークのパラメーターに逆伝播する
-
通常は単純な更新方法を使用して、ネットワークのパラメーターを更新します:weight = Weight - learning_rate *gradient
3.2 ニューラルネットワークの構築手順 ニューラルネットワークの構築
- クラスを定義してそれを継承する
torch.nn.Moulde
torch.nn
クラス内のコンポーネントとクラス内のコンポーネントを使用してtorch.nn.functional
ネットワーク構造を構築するforward
このクラスのメソッドを書き換えて、ネットワーク構造(活性化関数やプーリング層など)をさらに改良し、戻り値の出力を取得します。
まずは、使用する必要のあるtorch.nn
コンポーネントを簡単に紹介します。
torch.nn.Conv2d(in_channels, out_channels, kernel_size)
畳み込み演算を実行します。入力は(N, C in, H, W) (N, C_{in},H,W)です。( N 、Cで、H 、W )、出力は( N , C out , H , W ) (N,C_{out},H,W)( N 、Cあなたは_、H 、W ) (Conv2d)、画像サイズに対する畳み込みの影響は次のとおりです。
torch.nn.Linear(in_features, out_features)
アフィン マッピングを実行します。つまり、y = x AT + by=xA^T+by=× AT+b , (「線形」)torch.nn.Flatten(start_dim=1, end_dim=- 1)
、連続範囲をテンソルに平坦化します (詳細については平坦化を参照してください)。
使用する必要のあるtorch.nn.functional
コンポーネントを紹介します
-
torch.nn.functional.relu()
, 入力で Relu 活性化関数を使用します。具体的な操作は、各要素に対してReLU ( x ) = max ( 0 , x ) \text{ReLU}(x)=\max(0,x) を実行することです。ReLU ( × )=最大( 0 ,x )計算 (ReLu を) -
torch.nn.functional.softmax()
, 入力に Softmax 活性化関数を使用します。具体的な演算は、Softmax ( xi ) = exp ( xi ) ∑ j exp ( xj ) \text{Softmax}(x_i)=\frac{\exp(x_i ) を実行することです。 }{\sum_{j}\exp(x_j)}ソフトマックス( x私は)=∑je x p ( xj)e x p ( x私は)(詳細についてはソフトマックスを参照してください) -
torch.nn.functional.max_pool2d(input, kernel_size, stride)
、最大プーリング操作を実行します。入力はKaTeX 解析エラーです: 予期された 'EOF'、位置 28 で '_' を取得しました: …atch}, \text{in_̲channels}, iH,i…、詳細については Max_Pool2D を参照してください)
たとえば、次のコードでは、次のようなニューラル ネットワーク構造を構築する必要があります。
入力は[ バッチ , チャンネル , 高さ , 体重 ] [\text{バッチ},\text{チャンネル},\text{身長},\text{体重}]【バッチ、チャンネル、高さ、重み]ピクチャは、それぞれバッチ サイズ、チャネル数、画像の高さ、画像の幅を表します。バッチサイズを1 1とします。1の場合、この例は[ 1 , 1 , 32 , 32 ] [1,1,32,32][ 1 、1 、32 、32 ]、テンソルの変更プロセスは次のとおりです。
KaTeX 解析エラー: Expected 'EOF', got '_' at Position 74: …arrow{\text{max_̲pool}}[1,6,14,1…
import torch
import torch.nn as nn
import torch.nn.functional as F
class Net(nn.Module):
def __init__(self):
super(Net,self).__init__()
# 1 is input_channel 6 is output_channel
self.conv1 = nn.Conv2d(1, 6, 5)
self.conv2 = nn.Conv2d(6, 16, 5)
# affine function y = Wx + b
self.fc1 = nn.Linear(16 * 5 * 5, 120)
self.fc2 = nn.Linear(120, 84)
self.fc3 = nn.Linear(84, 10)
def forward(self,x):
# Max pooling over a (2,2) window
x = F.max_pool2d(F.relu(self.conv1(x)), (2,2))
# If the size is a square you can only specify a single number
x = F.max_pool2d(F.relu(self.conv2(x)), (2,2))
# flat the feature as a vector
x = x.view(-1, self.num_flat_features(x))
x = F.relu(self.fc1(x))
x = F.relu(self.fc2(x))
x = F.softmax(self.fc3(x), dim=1)
return x
def num_flat_features(self,x):
size = x.size()[1:] # all dimensions except the batch dimension
num_feature = 1
for s in size:
num_feature *= s
return num_feature
net = Net()
print(net)
または
class Net(nn.Module):
def __init__(self):
super(Net,self).__init__()
# 1 is input_channel 6 is output_channel
self.conv1 = nn.Conv2d(1, 6, 5)
self.conv2 = nn.Conv2d(6, 16, 5)
# affine function y = Wx + b
self.flat = nn.Flatten(1,-1) # flat the feature
self.fc1 = nn.Linear(16 * 5 * 5, 120)
self.fc2 = nn.Linear(120, 84)
self.fc3 = nn.Linear(84, 10)
def forward(self,x):
# Max pooling over a (2,2) window
x = F.max_pool2d(F.relu(self.conv1(x)), (2,2))
# If the size is a square you can only specify a single number
x = F.max_pool2d(F.relu(self.conv2(x)), (2,2))
# flat the feature as a vector
x = self.flat(x)
x = F.relu(self.fc1(x))
x = F.relu(self.fc2(x))
x = F.softmax(self.fc3(x), dim=1)
return x
net = Net()
print(net)
結果は次のようになります。ネットワーク構造を確認できます。
Net(
(conv1): Conv2d(1, 6, kernel_size=(5, 5), stride=(1, 1))
(conv2): Conv2d(6, 16, kernel_size=(5, 5), stride=(1, 1))
(fc1): Linear(in_features=400, out_features=120, bias=True)
(fc2): Linear(in_features=120, out_features=84, bias=True)
(fc3): Linear(in_features=84, out_features=10, bias=True)
)
モデルのトレーニング可能なパラメーターは、net.parameters()
以下を呼び出すことで返すことができます。
params = list(net.parameters())
print(len(params))
print(params[0].size()) # conv1's .weight
結果は次のとおりです
10
torch.Size([6, 1, 5, 5])
次に、いくつかの入力をカスタマイズしてネットワークの出力を取得します。
input = torch.randn(3, 1, 32, 32)
out = net(input)
print(out.data)
sum = 0
for i in out.data[0]:
sum += i.item()
print(sum)
出力は次のとおりです
tensor([[0.0996, 0.1000, 0.0907, 0.0946, 0.0930, 0.1067, 0.1044, 0.1119, 0.1073,
0.0918],
[0.0975, 0.1005, 0.0913, 0.0935, 0.0939, 0.1070, 0.1045, 0.1121, 0.1065,
0.0933],
[0.0968, 0.1009, 0.0896, 0.0978, 0.0903, 0.1107, 0.1055, 0.1130, 0.1043,
0.0913]])
0.9999999925494194
torch.nn.Module.zero_grad()
すべてのパラメータ勾配レジスタをゼロに設定します。
net.zero_grad() #把所有参数梯度缓存器置零,用随机的梯度来反向传播
out.backward(torch.randn_like(out))
net.conv1.bias.grad #查看Conv卷积层的偏置和权重一些参数的梯度
net.conv1.weight.grad
結果は次のとおりです
tensor([-0.0064, 0.0136, -0.0046, 0.0008, -0.0044, 0.0021])
...
3.3 逆伝播に損失関数を使用する 逆伝播に損失関数を使用する
これで終わりです
-
ニューラル ネットワークを定義する
-
入力を処理し、バックプロパゲーションを呼び出す
残り:
-
損失額の計算
-
ネットワーク内の重みを更新する
損失関数
損失関数は、モデル出力とターゲットという 1 組の入力を受け取り、出力がターゲットからどれだけ離れているかを評価する値を計算します。
nn パッケージには、いくつかの異なる損失関数があります (詳細については、損失関数を参照してください)。単純な損失関数は nn.MSELoss で、平均二乗誤差を計算します。
input = torch.randn(3, 1, 32, 32)
target = torch.randn(3, 10)
predict = net(input)
criterion = nn.MSELoss()
loss = criterion(predict, target)
print(loss)
print(loss.grad_fn.next_functions[0][0])
MSE 損失関数を計算し、その計算グラフを追跡することができました。
input -> conv2d -> relu -> maxpool2d -> conv2d -> relu -> maxpool2d
-> view -> linear -> relu -> linear -> relu -> linear -> sfotmax
-> MSELoss
-> loss
を使用するとloss.backward()
、計算グラフ全体が微分され、バックプロパゲーション損失を実装するには、 を使用するだけで済みますloss.backward()
。既存の勾配をクリアする必要があります。そうしないと、現在計算された勾配が履歴に保存された勾配とともに累積されてしまいます。
net.zero_grad() # zeroes the gradient buffers of all parameters
print('conv1.bias.grad before backward')
print(net.conv1.bias.grad)
loss.backward()
print('conv1.bias.grad after backward')
print(net.conv1.bias.grad)
結果は次のとおりです
conv1.bias.grad before backward
None
conv1.bias.grad after backward
tensor([-3.4418e-04, -1.0766e-04, 1.0913e-04, -5.5018e-05, 1.7342e-04,
-5.3316e-04])
3.4 NNのパラメータ更新 ニューラルネットワークパラメータの更新
3.4.1 手動更新 パラメータを手動で更新します
確率的勾配降下法を手動で実装してパラメータを更新できます (詳細については、第 6 章「確率的近似」を参照してください)。
wk + 1 = wk − ak ∇ wkf ( wk , xk ) \textcolor{red}{w_{k+1} = w_k - a_k \nabla_{w_k} f(w_k,x_k)}wk + 1=wk−あるk∇wkf ( wk、バツk)
learning_rate = 0.01
for f in net.parameters():
f.data.sub_(f.grad.data * learning_rate) #sub_() is in-place minus
3.4.2 自動更新 パラメータを自動更新します。
ただし、ニューラル ネットワークを使用している場合は、SGD、Nesterov-SGD、Adam、RMSProp などの別の更新ルールを使用する必要があります。torch.optim
これを可能にするために、すべてのメソッドを実装する小さなパッケージを構築しました。これを使用して上記の手動で実装されたコードを置き換えることができoptim.step()
、使い方は非常に簡単です。
import torch.optim as optim
# create your optimizer
optimizer = optim.SGD(net.parameters(), lr=0.01)
# in your training loop:
optimizer.zero_grad() # zero the gradient buffers
output = net(input)
loss = criterion(output, target)
loss.backward() # 计算梯度
optimizer.step() # Does the update