先尝试写一个简单的线性计算,用神经网络拟合学习。
数据生成
1 2 3 4 5 6 7 8 9 10
| import torch
W = torch.tensor([[0.3, 0.4],[0.5,0.6],[0.6,0.2]])
num_samples = 100 input_dim = 3 x = torch.rand((num_samples, input_dim))
y = torch.matmul(W.t(), x.t()).t()
|
一会儿我们用这些数据取拟合权重矩阵 $W$
定义网络
pytorch中的自定义神经网络类需要继承 nn.Module
,并且调用父类的构造函数 __init__()
来完成一些参数和方法的初始化。
最简单的网络我们只需定义网络中的层结构,如这里我加了一层线性层。以及前向传播的 forward
函数即可。
如果需要自定义损失函数等,会在之后的文章中介绍。
1 2 3 4 5 6 7 8 9 10
| import torch.nn as nn class Simple_nn(nn.Module): def __init__(self): super(Simple_nn, self).__init__() self.W = nn.Linear(input_dim, output_dim, bias=False) def forward(self, X): output = self.W(X) return output
|
进行训练
训练需要数据,我们把数据以batch的形式送进网络进行训练。目前我们不涉及dataset,dataloader的使用。
先写一个随机取batch的函数
1 2 3 4 5 6 7 8 9 10 11 12 13
| batch_size = 4
def random_batch(): random_x = torch.zeros((batch_size, input_dim)) random_y = torch.zeros((batch_size, output_dim)) random_index = np.random.choice(range(len(x)), batch_size, replace=False)
for i, index in enumerate(random_index): random_x[i] = x[index] random_y[i] = y[index] return random_x, random_y
|
然后写一个训练函数
pytorch封装了很多操作,比如说反向传播 backward
是不需要自己写的,只需要调用 loss.backward()
即可
随后,调用 torch.optim
中被称为优化器的工具就可以更新参数
像这里的 optim.SGD
就是随机梯度下降的参数更新方法。
注意,模型直到 optimizer.step()
这步才正式更新模型参数。这两步的分离是为了提供更大的灵活性,比如可以多次调用 loss.backward()
累积梯度,然后在特定时刻执行一次 optimizer.step()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| import torch.optim as optim
model = Simple_nn()
criterion = nn.MSELoss()
optimizer = optim.SGD(model.parameters(), lr=0.01)
for epoch in range(5000): input_batch, output_batch = random_batch()
optimizer.zero_grad() output_pred = model(input_batch) loss = criterion(output_pred, output_batch)
if (epoch + 1) % 1000 == 0: print('Epoch:', '%04d' % (epoch + 1), 'cost =', '{:.6f}'.format(loss))
loss.backward() optimizer.step()
print(model.W.weight.t())
|
最后得到输出,和我们一开始定义的 $W$ 是很接近的:
1 2 3
| tensor([[0.2985, 0.4066], [0.5058, 0.5921], [0.5955, 0.2015]], grad_fn=<TBackward0>)
|