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

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中会设定很多隐藏层。

  • 14
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
PyTorch是一个基于Python的开源机器学习库,它提供了丰富的工具和函数来构建和训练神经网络。下面是一个简单的PyTorch神经网络教程的介绍: 1. 安装PyTorch:首先,你需要安装PyTorch库。你可以在PyTorch官方网站上找到安装指南。 2. 导入PyTorch库:在Python脚本,你需要导入PyTorch库以使用其的函数和类。 3. 构建神经网络模型:使用PyTorchtorch.nn模块来构建神经网络模型。你可以定义自己的网络结构,包括输入层、隐藏层和输出层,并选择适当的激活函数。 4. 定义损失函数:选择适当的损失函数来度量模型预测结果与真实标签之间的差异。常见的损失函数包括均方误差(MSE)和交叉熵损失(CrossEntropyLoss)。 5. 定义优化器:选择适当的优化器来更新模型的参数,以最小化损失函数。常见的优化器包括随机梯度下降(SGD)和Adam。 6. 训练模型:使用训练数据集来训练神经网络模型。通过将输入数据传递给模型并计算损失,然后使用优化器来更新模型的参数。 7. 测试模型:使用测试数据集来评估训练好的模型的性能。通过将输入数据传递给模型并计算预测结果,然后与真实标签进行比较来评估模型的准确性。 8. 调整超参数:根据模型的性能和需求,调整超参数(如学习率、隐藏层大小等)来改进模型的性能。 9. 保存和加载模型:在训练完成后,你可以保存训练好的模型以备将来使用。使用torch.save函数保存模型,并使用torch.load函数加载已保存的模型。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值