Pytorch神经网络入门(1)参数的手动更新和自动更新

您所在的位置:网站首页 lumion85如何更新模型 Pytorch神经网络入门(1)参数的手动更新和自动更新

Pytorch神经网络入门(1)参数的手动更新和自动更新

2023-07-28 05:45| 来源: 网络整理| 查看: 265

Pytorch 作为深度学习届两大扛把子框架之一(另一个是Tensorflow),一直都受着AI炼丹师们的喜爱。这里将简单介绍一下神经网络参数的手动更新和自动更新。

首先来说手动更新,可能很多初学者随便打开一本pytorch书或者教程,发现他们的梯度更新方式都大同小异,都是那几句话,但他其中的具体步骤究竟是怎样的,还是有必要了解一下。

在这里插入图片描述 一般情况下,神经网络都是有隐藏层的,当然也可以像上图左边那样,只有输入输出。

神经网络的循环过程

如下: 1,输入进来,前向传播,先用初始化的矩阵将输入转换成和输出类似的形式。 2, 然后计算Loss,也就是计算预测的结果和实际结果差了多少。 3,根据这个Loss反向传播,获取不同矩阵的梯度 4,根据获取的梯度,更新梯度。

整个流程大致就是一个epoch,在实际场景的神经网络训练中,这样的循环可能都是成百万次,千万次级别的。当然,初学的时候用不到这么多。

手动更新

来看代码:

import torch import numpy as np x_data = np.array( [[0, 0], [1, 0], [1, 1], [0, 0], [0, 0], [0, 1]]) x_data_torch = torch.from_numpy(x_data).float() y_data = np.array([0,1,2,0,0,2]) y_data_torch = torch.from_numpy(y_data) num_features = 2 num_classes = 3 n_hidden_1 = 5

以上是数据X,y以及一些参数设定,比如特征有2个,输出的类别有3个,隐藏层的维度是5。具体的数据是没有任何意义的,其实对于神经网络而言,他也不知道究竟在学什么😂

接下来是手动参数更新, 这里的神经网络包含了一层隐藏层,所以第一层的权重矩阵W的维度应该是(num_features, n_hidden_1),对应特征数和隐藏层维度,即(2,5),然后input的维度是(6,2) 于是x*W1的维度就应该是(6,5)然后再和B1矩阵相加。

import torch.nn as nn import torch.nn.functional as F from sklearn.metrics import accuracy_score W1 = torch.randn(num_features, n_hidden_1, requires_grad=True) B1 = torch.randn(n_hidden_1, requires_grad=True) Wout = torch.randn(n_hidden_1, num_classes, requires_grad=True) Bout = torch.randn(num_classes, requires_grad=True) learning_rate=0.01 no_of_epochs = 1000 for epoch in range(no_of_epochs): #explicitly defne the forward and backward z1 = torch.add(torch.matmul(x_data_torch, W1), B1) Zout = torch.add(torch.matmul(F.relu(z1), Wout), Bout) log_softmax = F.log_softmax(Zout,dim=1) loss = F.nll_loss(log_softmax, y_data_torch) loss.backward() with torch.no_grad(): W1.data -= learning_rate*W1.grad.data B1.data -= learning_rate*B1.grad.data Wout.data -= learning_rate*Wout.grad.data Bout.data -= learning_rate*Bout.grad.data W1.grad.data.zero_() B1.grad.data.zero_() Wout.grad.data.zero_() Bout.grad.data.zero_() if epoch % 200 == 199: with torch.no_grad(): z1 = torch.add(torch.matmul(x_data_torch ,W1),B1) Zout = torch.add(torch.matmul(F.relu(z1) ,Wout),Bout) predicted = torch.argmax(Zout, 1) train_acc = accuracy_score(predicted.numpy(),y_data) print('Epoch: %d, loss: %.4f, train_acc: %.3f' %(epoch + 1, loss.item() , train_acc)) print("Finished") # Result print('Predicted :', predicted.numpy()) print('Truth :', y_data) print('Accuracy : %.2f' %train_acc)

这里的整体操作就是先用input X 和W1矩阵相乘,然后给所得矩阵的每一行加上B1矩阵,这个X*W1+B1会经过一个relu层,然后输入到第二层,第二层也是相似的方式,先乘再加。所得到的结果经过log_softmax调整后,和y计算negative log likelihood loss(nll loss),然后再反向传播获取每个矩阵对应的梯度。

然后用with torch.no_grad() 自己设定更新方式, 这里用到的就是梯度下降法。然后为了在对每个矩阵调用zero_()使其参数清零,防止梯度堆积(gradient accumulation)

最后设定一个输出方式,每200epochs输出一次当前的Loss和准确度。

大致结果如下,由于数据很小,并且矩阵是随机初始的,每次结果可能不同。

在这里插入图片描述

自动更新

在大型的深度学习网络中,不可能每次都自定义梯度该如何更新,所以这里就需要自动更新。

import torch.nn as nn import torch.nn.functional as F import torch.optim as optim from sklearn.metrics import accuracy_score class ModelWithHiddenLayer(nn.Module): def __init__(self, input_size, hidden_size, output_size): super(ModelWithHiddenLayer, self).__init__() self.linear1 = nn.Linear(input_size, hidden_size) self.linear2 = nn.Linear(hidden_size, output_size) def forward(self, x): z1 = self.linear1(x) Zout = self.linear2(F.relu(z1)) return Zout model = ModelWithHiddenLayer(num_features, n_hidden_1, num_classes) learning_rate=0.01 no_of_epochs = 1000 # If you apply Pytorch’s CrossEntropyLoss to your output layer, # you get the same result as applying Pytorch’s NLLLoss to a LogSoftmax layer added after your original output layer. criterion = nn.CrossEntropyLoss() optimiser = optim.SGD(model.parameters(), lr=learning_rate)

首先设定好模型,criterion是用来计算loss的,可以设定不同的loss,这里选的是交叉熵。optimiser是设定梯度更新方式的,这里设定的是SGD随机梯度下降。

for epoch in range(no_of_epochs): # loop over the dataset multiple times # get the inputs inputs = x_data_torch labels = y_data_torch model.train() # zero the parameter gradients optimiser.zero_grad() # forward + backward + optimize outputs = model(inputs) loss = criterion(outputs, labels) # We don't need to calcualte logsoftmax here loss.backward() optimiser.step() # print statistics if epoch % 200 == 199: # print every 200 epochs model.eval() pred_outputs = model(inputs) predicted = torch.argmax(pred_outputs, 1) train_acc = accuracy_score(predicted.numpy(),y_data) print('%d, loss: %.4f, train_acc: %.4f' %(epoch + 1, loss.item(), train_acc)) print('Finished Training') # Result pred_outputs = model(inputs) _, predicted = torch.max(pred_outputs, 1) print('Predicted :', predicted.numpy()) print('Truth :', y_data) train_acc = accuracy_score(predicted.numpy(),y_data) print('Accuracy : %.2f' %train_acc)

这种情况下,只需要简单的写出大致流程即可实现神经网络训练。

首先调用model.train() 进行训练,然后用optimiser将梯度都设为0,然后用模型输出一个预测结果,用criterion计算相应的loss,然后用loss.backward()进行反向传播,再用optimiser.step()更新梯度。

预测结果不再展示,其实更复杂的模型都是从最简单的变出来的,一般的模型,即时再复杂,也都是这几步,知识他们的模型class中会设定很多隐藏层。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3