記事ディレクトリ
ニューラルネットワーク
torch.nn
パッケージを使用してニューラルネットワークを構築できます。
前回の記事autograd
で学習したように、nn
パッケージはautograd
パッケージを使用してモデルを定義し、派生させます。1つにはnn.Module
、出力を返すためのさまざまなレイヤーとメソッドが含まれますforward(input)
。
たとえば、デジタル画像認識に使用されるネットワークを見ることができます:
[pic]
これは単純なフィードフォワードネットワークです。ネットワークは最初に入力を受け入れ、それを次の層に送信し、層ごとに送信し、最後に出力します。
ニューラルネットワークの一般的なトレーニングプロセスは次のとおりです。
- 学習可能なパラメーター(または重み)を含むニューラルネットワークを定義する
- 入力データセットを反復する
- ネットワーク経由で入力を処理する
- 損失(出力と正解の間の距離)を計算する
- 勾配をネットワークのパラメーターに逆伝播する
- 一般的に使用される単純なルールであるネットワークの重みを更新します。weight= weight-learning_rate * gradient
ネットワークを定義する
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 input image channel, 6 output channels, 3x3 square convolution
# kernel
self.conv1 = nn.Conv2d(1, 6, 3)
self.conv2 = nn.Conv2d(6, 16, 3)
# an affine operation: y = Wx + b
self.fc1 = nn.Linear(16 * 6 * 6, 120) # 6*6 from image dimension
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)
x = x.view(-1, self.num_flat_features(x))
x = F.relu(self.fc1(x))
x = F.relu(self.fc2(x))
x = self.fc3(x)
return x
def num_flat_features(self, x):
size = x.size()[1:] # all dimensions except the batch dimension
num_features = 1
for s in size:
num_features *= s
return num_features
net = Net()
print(net)
出力
Net(
(conv1): Conv2d(1, 6, kernel_size=(3, 3), stride=(1, 1))
(conv2): Conv2d(6, 16, kernel_size=(3, 3), stride=(1, 1))
(fc1): Linear(in_features=576, 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)
)
上記のクラスforward
で関数をbackward
定義し、autogradで自動的に定義されました。forward
関数では任意のテンソル演算を使用できます。
モデルのトレーニング可能なパラメーターは、次net.parameters()
によって検索されます。
params = list(net.parameters())
print(len(params))
print(params[0].size()) # conv1's .weight
# output:
# 10
# torch.Size([6, 1, 3, 3])
これで32x32入力を最初に試すことができます。このネットワーク(LeNet)の予想される入力は32x32 だからです。MNISTデータセットをトレーニングに使用する場合は、画像サイズを32x32に調整するよう注意する必要があります。
input = torch.randn(1, 1, 32, 32)
out = net(input)
print(out)
# output:
# tensor([[ 0.0399, -0.0856, 0.0668, 0.0915, 0.0453, -0.0680, -0.1024, # 0.0493, -0.1043, -0.1267]], grad_fn=<AddmmBackward>)
すべてのパラメーターのグラデーションキャッシュをクリアしてから、ランダムグラデーションの逆伝播を実行します。
net.zero_grad()
out.backward(torch.randn(1, 10))
ヒント:torch.nnはミニバッチのみをサポートします。torch.nnパッケージ全体は、単一のサンプルではなく、少量のバッチサンプルの入力のみをサポートします。
たとえば、nn.Conv2dは4次元テンソル、つまりnSamples x nChannels x高さx幅を受け入れます
別のサンプルの場合は、input.unsqueeze(0)を使用して、「偽の」バッチサイズディメンションを追加します。
要約:
torch.Tensor
-backward()
テンソルの勾配を保存しながら、などの自動導出操作をサポートする多次元配列。nn.Module
-ニューラルネットワークモジュール。これは、GPUへのパラメーターの移動、エクスポート、ロードなどの機能を使用して、パラメーターをカプセル化する便利な方法です。nn.Parameter
-テンソルの一種で、属性としてモジュールに割り当てられると、自動的にパラメーターとして登録されます。autograd.Function
-順方向および逆方向の伝播の自動導出の定義を実現し、各Tensorは少なくとも1つの関数ノードを作成します。これは、Tensorを作成した関数に接続され、その履歴をエンコードします
これまでに、次のことを学びました。
- ネットワークを定義する方法
- 入力を処理して逆方向に呼び出す
まだ学ぶ必要があるもの:
- 損失を計算する
- ネットワークの重みを更新する
損失関数
損失関数は、(出力、ターゲット)のペアを入力として受け入れ、ネットワークの出力がターゲット値とどれだけ異なるかを推定する値を計算します。
nnパッケージには多くの異なる損失関数があります。nn.MSELossは比較的単純なもので、出力とターゲットの平均二乗誤差を計算します。
output = net(input)
target = torch.randn(10) # 本例子中使用模拟数据
target = target.view(1, -1) # 使目标值与数据值形状一致
criterion = nn.MSELoss()
loss = criterion(output, target)
print(loss)
# tensor(1.0263, grad_fn=<MseLossBackward>)
これで、loss.grad_fn属性を使用して逆伝播プロセスを追跡すると、次のような計算図が表示されます。
input -> conv2d -> relu -> maxpool2d -> conv2d -> relu -> maxpool2d
-> view -> linear -> relu -> linear -> relu -> linear
-> MSELoss
-> loss
呼び出されるとloss.backward()
、グラフ全体が損失について区別されます。このグラフのrequires_grad
真であるすべてのテンソルは、それらの.grad
属性の勾配を累積します。
次の方法でいくつかのステップをたどることができます
print(loss.grad_fn) # MSELoss
print(loss.grad_fn.next_functions[0][0]) # Linear
print(loss.grad_fn.next_functions[0][0].next_functions[0][0]) # ReLU
# output:
# <MseLossBackward object at 0x7f8dac1b4550>
# <AddmmBackward object at 0x7f8dac1b4a90>
# <AccumulateGrad object at 0x7f8dac1b4a90>
バックプロップ
loss.backward()
重みをバックプロパゲートするために呼び出す必要があるだけです。最初に、既存の勾配をクリアする必要があります。そうしないと、勾配は既存の勾配で累積されます。
デモ時間:以下は、loss.backward()
逆伝播の前後のconv1レイヤーバイアスの勾配変化を表示するための呼び出しです
net.zero_grad() # 清零所有参数(parameter)的梯度缓存
print('conv1.bias.grad before backward')
print(net.conv1.bias.grad)
loss.backward()
print('conv1.bias.grad after backward')
print(net.conv1.bias.grad)
# output:
# conv1.bias.grad before backward
# tensor([0., 0., 0., 0., 0., 0.])
# conv1.bias.grad after backward
# tensor([ 0.0084, 0.0019, -0.0179, -0.0212, 0.0067, -0.0096])
重みを更新する
最も単純な更新規則は、確率的勾配降下法(SGD)です。
weight = weight - learning_rate * gradient
簡単な実装:
learning_rate = 0.01
for f in net.parameters():
f.data.sub_(f.grad.data * learning_rate)
同時に、ニューラルネットワークを使用する場合は、SGD、Nesterov-SGD、Adam、RMSPropなどのさまざまな更新ルールを使用することもできます。これには、torch.optim
これらすべてのメソッドを実装するを使用できます。使い方も非常に簡単です。
import torch.optim as optim
# 创建优化器(optimizer)
optimizer = optim.SGD(net.parameters(), lr=0.01)
# 在训练的迭代中:
optimizer.zero_grad() # 清零梯度缓存
output = net(input)
loss = criterion(output, target)
loss.backward()
optimizer.step() # 更新参数
REF
https://pytorch.apachecn.org/docs/1.4/blitz/neural_networks_tutorial.html
https://pytorch.org/tutorials/beginner/blitz/neural_networks_tutorial.html