Kiba518

Kiba518

沈阳-架构-开发。

Fork me on GitHub

零基础学习人工智能—Python—Pytorch学习(四)

前言

接续上一篇的optimizer的学习。

optimizer

代码和上一篇文章的一样,如下:

import torch
import numpy as np
import torch.nn as nn

X = torch.tensor([1, 2, 3, 4], dtype=torch.float32)
Y = torch.tensor([2, 4, 6, 8], dtype=torch.float32)
w2 = torch.tensor(0.0, requires_grad=True)
 
def forward(_x):
    return w2* _x


learning_rate = 0.01
n_iter = 100  # 循环次数
loss =nn.MSELoss()
optimizer =torch.optim.SGD([w2],lr=learning_rate)

 
for epoch in range(n_iter):
    y_pred = forward(X)# 
    l = loss(Y, y_pred) #相当于计算了预测y与真实y的关系
    l.backward() #执行完反向传播后,w2里就已经有w2.grad了
    optimizer.step() #optimizer初始化时就接收了w2,现在w2有了grad,就可以执行step进行优化了,优化时会使用梯度grad属性和学习率learning_rate来优化w2
    optimizer.zero_grad() #梯度清零

   
    if epoch % 1 == 0:
        print(f'epoch {epoch+1}:w2= {w2:.3f} ,loss = {l:.8f}')
print(f'f(5)={forward(5):.3f}')

可以看到,我们这里引用增加了一个import torch.nn as nn。
这里只是简单的使用了nn.MSELoss(),我们就不用手写这个计算平均值的步骤了。
然后我们定义了一个optimizer,接收了两个参数,一个是权重w2,一个是学习率learning_rate。
这里我们的传递的是一个Tensors数组,而不是w2。
上篇文章已经介绍的w是根据梯度x.grad生成的,所以,按理应该是一个跟x同类型的矩阵,这里[w2]跟x不同型,但这里他只是一个数,这是因为计算时,会自动把这种一个数的矩阵变形为跟x同型的矩阵。
正确的写法应该是下面这样。

import torch
import numpy as np
import torch.nn as nn

X = torch.tensor([1, 2, 3, 4], dtype=torch.float32)
Y = torch.tensor([2, 4, 6, 8], dtype=torch.float32)
w2 = torch.tensor([0.0,0.0,0.0,0.0], requires_grad=True)
def forward(_x):
    return w2* _x #如果w2不是1个元素或者4个元素,这里就无法相乘
learning_rate = 0.01
n_iter = 100  # 循环次数
loss =nn.MSELoss()
optimizer =torch.optim.SGD([w2],lr=learning_rate)
for epoch in range(n_iter):
    y_pred = forward(X)# 
    l = loss(Y, y_pred) 
    l.backward()  
    optimizer.step() 
    optimizer.zero_grad() 
    if epoch % 1 == 0:
        print(f'epoch {epoch+1}:w21= {w2[0]:.3f} w22= {w2[1]:.3f}  ,loss = {l:.8f}')

思维逻辑重述

回忆一下前面将的青蛙例子,我们重新叙述一下这个计算逻辑,首先我们有个y,这个是我们的目标,然后有个x,这个是我们的输入数据。然后通过w和b这俩参数,结合公式y=wx+b,一次一次的尝试求出w和b,然后通过求出的w和b修正x,然后我们得到了一个新的矩阵——修正x;我们令y_predict=x修正矩阵,就形成了x通过变化得到了预测y,即y_predict。然后我们就可以比较y和y_predict了。

torch.nn简介

torch.nn 是 PyTorch 的一个核心模块,专门用于构建和训练神经网络。这个模块提供了各种类和函数,使你可以方便地定义神经网络模型、实现前向传播和反向传播、定义损失函数,以及进行参数优化等任务。

Linear

torch.nn.Linear的概念是PyTorch 中用于实现线性变换(全连接层)的模块。这里我们先无视他的定义。
先看几个变量的含义。
X.shape:返回的是一个 torch.Size 对象 形状信息分别是 行数(样本数)和列数(特征数),这里特别注意样本和特征这俩词,这是俩干扰我们学习非常狠的名词,注意这个特征并不是我们线性代数里通过计算得到的特征值或特征向量,他就是矩阵的列数量。
nn.Linear(input_size, output_size):这是实例化Linear,入参是俩数,分别叫做input_size, output_size,这俩参数的含义如下。

反人类的定义

input_size:是输入特征的数量,也就是每个输入样本的维度。
output_size:是输出特征的数量,也就是模型希望输出的特征维度。

正常定义

input_size:表示输入数据 X 的列数。
output_size:表示模型预测输出 y_predict 的列数。
注:这里要把反人类的定义多看几遍,因为,如果你学习人工智能,你会在各种视频和文章中看到别人用反人类定义来描述操作与问题。如果不能很好的转换这个理解,就只能等着被恶心吧。
这里,我们可以稍微思考一下,就可以根据input_size和output_size的分别传入推测出一个结论,那就是我们可以输入3 * 3的矩阵x,然后利用torch.nn这个库,输出成4 * 4的矩阵,然后再和4 * 4矩阵y比较。
不过Linear的话,要求输入和输出矩阵的维度必须匹配,所以,这里我们是不用这么做的,不过稍微联想一下即可得出结论,多层神经网络或其他层(如卷积层)肯定可以做这样复杂的映射。
Linear使用代码如下:

import torch
import numpy as np
import torch.nn as nn

X = torch.tensor([[1], [2], [3], [4]], dtype=torch.float32)
Y = torch.tensor([[2], [4], [6], [8]], dtype=torch.float32)

n_samples, n_features = X.shape  # x是4行1列矩阵,这里返回4和1
print("n_samples", n_samples, "n_features", n_features)
input_size = n_features
output_size = n_features
model = nn.Linear(input_size, output_size)

learning_rate = 0.01
n_iter = 100  # 循环次数
loss = nn.MSELoss()
[w, b]= model.parameters()
optimizer = torch.optim.SGD([w, b], lr=learning_rate)

for epoch in range(n_iter):
    y_pred = model(X)  # 这里的 model(X) 调用的是 model 的 forward 方法
    l = loss(Y, y_pred)
    l.backward()
    optimizer.step()
    optimizer.zero_grad()
    if epoch % 1 == 0:
        [w, b] = model.parameters()
        print(f'epoch {epoch+1}:w2= {w[0][0].item():.3f} ,loss = {l:.8f}')

如上代码,我们使用model = nn.Linear(input_size, output_size)定义了一个线性模型对象。
然后使用 torch.optim.SGD时,传入了model.parameters()的返回值。
model.parameters()的返回值就是w和b。model.parameters()在被调用后,会在内部创建一个w和一个b。
权重矩阵 w:形状为 [output_size, input_size]。
偏置向量 b:形状为 [output_size]。
然后我们使用model(x)调用这个实例,这里Linear类里应该是实现了__call__方法,所以类的实例可以像函数一样被调用。
这里我们传递了x,有了x它就可以前向传播了,即,model(x)里我们传递了x,同时触发了前向传播。
所以,model(x)的返回值是一个预测的y值。
然后我们使用我们通过nn.MSELoss()定义的[标量函数/损失函数]来进行计算标量。
然后这个标量就可以使用反向传播了。
然后,我们就得到了模型参数w和b的值了。

nn.Module简介

nn.Module 是 PyTorch 中所有神经网络模块的基类。所有的神经网络层(如线性层、卷积层、LSTM 等)都继承自这个类。
通过继承 nn.Module,可以定义自己的网络层或模型,并利用 PyTorch 的自动微分功能来进行训练。
nn.Linear 是 nn.Module 的子类,是一个特定的神经网络层类,继承自 nn.Module。它实现了一个最简单的线性变换层,也叫全连接层。
通过继承 nn.Module,nn.Linear 能够利用 nn.Module 提供的所有功能,比如注册参数、前向传播、保存和加载模型等。
结构如下:

# nn.Module
#    |
#    |-- nn.Linear
#    |-- nn.Conv2d
#    |-- nn.RNN
#    |-- (Other Modules)

下面自定义一个类,继承Module实现Linear的代码:

X = torch.tensor([[1], [2], [3], [4]], dtype=torch.float32)  # 4行1列矩阵
Y = torch.tensor([[2], [4], [6], [8]], dtype=torch.float32)

n_samples, n_features = X.shape
print("n_samples", n_samples, "n_features", n_features)
input_size = n_features
output_size = n_features

# model = nn.Linear(input_size, output_size) 
class LinearRegression(nn.Module):
    def __init__(self, input_dim, output_dim):
        super(LinearRegression,self).__init__()
        # define layers
        self.lin = nn.Linear(input_dim, output_dim)
    def forward(self, x):return self.lin(x)
model =LinearRegression(input_size, output_size)

learning_rate = 0.01
n_iter = 100  # 循环次数
loss = nn.MSELoss()
[w, b]= model.parameters()

optimizer = torch.optim.SGD([w, b], lr=learning_rate)

for epoch in range(n_iter):
    y_pred = model(X) #能用对象直接调用,说明了LinearRegression继承的Module里有实现call方法,而call方法,调用的正是我们的forward,因此他的返回值就是y_pred
    l = loss(Y, y_pred)
    l.backward()
    optimizer.step()
    optimizer.zero_grad()  # 梯度清零

    if epoch % 1 == 0:
        [w, b] = model.parameters()
        print(f'epoch {epoch+1}:w2= {w[0][0].item():.3f} ,loss = {l:.8f}')

传送门:
零基础学习人工智能—Python—Pytorch学习(一)
零基础学习人工智能—Python—Pytorch学习(二)
零基础学习人工智能—Python—Pytorch学习(三)
零基础学习人工智能—Python—Pytorch学习(四)
零基础学习人工智能—Python—Pytorch学习(五)
零基础学习人工智能—Python—Pytorch学习(六)
零基础学习人工智能—Python—Pytorch学习(七)


注:此文章为原创,任何形式的转载都请联系作者获得授权并注明出处!



若您觉得这篇文章还不错,请点击下方的【推荐】,非常感谢!

https://www.cnblogs.com/kiba/p/18354543

posted @ 2024-08-12 15:01  kiba518  阅读(380)  评论(0编辑  收藏  举报