首页人工智能Pytorch【深度学习(PyTorch...

【深度学习(PyTorch篇)】22.使用神经网络替换线性模型

本系列文章配套代码获取有以下两种途径:

  • 通过百度网盘获取:
链接:https://pan.baidu.com/s/1XuxKa9_G00NznvSK0cr5qw?pwd=mnsj 提取码:mnsj
  • 前往GitHub获取
https://github.com/returu/PyTorch





本次将使用神经网络模型替代之前的线性模型作为逼近函数。
神经网络是由许多神经元连接而成的网络。每个神经元接收来自其他神经元的输入信号,然后将这些信号加权求和,再通过一个激活函数,最后输出一个信号。
激活函数的主要作用是在神经网络中引入非线性因素,激活函数通过其非线性的特性,能够将输入信号映射到一个非线性的输出空间。没有激活函数,神经网络就只是一堆线性操作的组合,这样的网络无论有多少层,其整体仍然是线性的,表达能力非常有限。而现实世界中的数据关系往往是非线性的,因此我们需要激活函数来让神经网络能够拟合这些非线性关系。
本次将在两个线性模块nn.Linear之间添加一个激活函数,由此构建一个简单的神经网络模型:一个线性模块nn.Linear一个激活函数nn.Tanh,另一个线性模块nn.Linear

01

神经网络搭建:


PyTorch框架中,搭建神经网络的方式多种多样,nn提供了一种通过nn.Sequential容器来连接模型的方式。该操作可以将各个层封装到Sequential构建的容器当中,是一种简单且直观的方法,适用于那些具有简单线性层叠结构的网络。
Sequential类允许我们将多个网络层按照顺序堆叠起来。每个添加到Sequential对象中的模块都将按照它们在构造函数中被传入的顺序被添加到计算图中执行顺序的顶部。
本次构建的神经网络模型结构为:线性模块nn.Linear+激活函数nn.Tanh+线性模块nn.Linear
# 神经网络模型
>>> model_1 = nn.Sequential(
...     nn.Linear(1,13),
...     nn.Tanh(),
...     nn.Linear(13,1)
... )

>>> model_1
Sequential(
  (0): Linear(in_features=1, out_features=13, bias=True)
  (1): Tanh()
  (2): Linear(in_features=13, out_features=1, bias=True)
)
调用model.parameters()方法可以查看由子模块组成的模型的参数:
>>> for param in model_1.parameters():
...     print(param.shape)
...
torch.Size([13, 1])
torch.Size([13])
torch.Size([1, 13])
torch.Size([1])
调用model.named_parameters()方法可以实现通过名称识别参数的功能。
>>> for name,param in model_1.named_parameters():
...     print(name , '-->',param.shape)
...
0.weight --> torch.Size([13, 1])
0.bias --> torch.Size([13])
2.weight --> torch.Size([1, 13])
2.bias --> torch.Size([1])
通过上面的输出可以看到,Sequential中每个子模块的名称就是模块在参数中出现的序号。
Sequential也接受使用OrderedDict来命名模块名称并传递给Sequential中的每个模块。
>>> from collections import OrderedDict

# 神经网络模型
>>> model_2 = nn.Sequential(OrderedDict([
...     ('hidden_layer' , nn.Linear(1,13)) ,
...     ('hidden_activation' ,  nn.Tanh()) ,
...     ('output_layer' , nn.Linear(13,1))])
... )

>>> model_2
Sequential(
  (hidden_layer): Linear(in_features=1, out_features=13, bias=True)
  (hidden_activation): Tanh()
  (output_layer): Linear(in_features=13, out_features=1, bias=True)
)
通过方式创建的神经网络模型,除了可以使用named_parameters()方法通过名称识别参数,还可以通过将子模块作为属性来访问某一个特定的参数,这对检查参数或者监控梯度非常有用。
>>> for name,param in model_2.named_parameters():
...     print(name , '-->',param.shape)
...
hidden_layer.weight --> torch.Size([131])
hidden_layer.bias --> torch.Size([13])
output_layer.weight --> torch.Size([113])
output_layer.bias --> torch.Size([1])

# 通过子模块作为属性来访问一个特定的参数
>>> model_2.hidden_layer.bias
Parameter containing:
tensor([-0.9065-0.8778,  0.9589-0.8350,  0.4945-0.0443-0.9624,  0.8843,
        -0.4794,  0.0036-0.7114-0.6724-0.7271], requires_grad=True)

# 未进行反向传播,因此梯度为None
>>> model_2.hidden_layer.bias.grad
>>> print(model_2.hidden_layer.bias.grad)
None

02

使用神经网络替换线性模型:


接下来,我们就可以使用神经网络模型替代之前的线性模型完成数据拟合。
  • 生成数据:
与之前代码一致,要记得增加batch维度。
# 设置随机数种子,保证运行结果一致
torch.manual_seed(2024)

def get_fake_data(num):
    """
    生成随机数据,y = 0.5 * x +30并加上一些随机噪声
    """

    x = torch.randint(low = -5, high=30, size=(num,)).to(dtype=torch.float32)
    y = 0.5 * x +30 + torch.randn(num,)
    return x,y

x , y = get_fake_data(num=11)
x = x * 0.1

# 增加batch维度
x = x.unsqueeze(1)
y = y.unsqueeze(1)

  • 定义函数:
只需在此处将线性模型替换为神经网络模型即可。
# 神经网络模型
seq_model = nn.Sequential(OrderedDict([
    ('hidden_layer' , nn.Linear(1,13)) ,
    ('hidden_activation' ,  nn.Tanh()) ,
    ('output_layer' , nn.Linear(13,1))])   
)

# 定义损失函数
loss_fn = nn.MSELoss()

# 实例化一个优化器
learning_rate=1e-2

optimizer = torch.optim.SGD(seq_model.parameters() , lr=learning_rate)
  • 循环训练,求解参数值:
代码整体结构与之前一致,本次加入了模型循环训练过程中的损失值的记录。
在获取损失值时使用了tensor.item()方法,该方法用于从只包含一个元素的张量中提取该元素值,并将其作为Python标量返回。这需要获取单个数值时非常有用,例如,计算损失或准确度等标量值时。
需要注意的是,item()只能用于只有一个元素的张量。如果在一个包含多个元素的张量上调用item(),将抛出错误。
from IPython import display

# 设置全局字体
plt.rcParams["font.sans-serif"] = "Microsoft YaHei"

def training_loop(n_epochs , optimizer , model , loss_fn , x , y):

    # 记录损失的列表
    losses = []

    for epoch in range(1 , n_epochs+1):
        #前向传播
        y_p = model(x)
        loss = loss_fn(y_p ,y)

        # 梯度归零
        optimizer.zero_grad()
        # 反向传播
        loss.backward()
        # 参数更新
        optimizer.step()

        # 记录损失
        losses.append(loss.item())


        if epoch % 10 ==0:

            display.clear_output(wait=True)
            # 原始数据
            plt.plot(x , y , 'o' , label="原始数据")
            # 线性模型
            plt.plot(x , (4.827*x+29.977) , label="线性模型")

            # 获取xy轴的范围
            xmin,xmax,ymin,ymax = plt.axis()
            # 输入,模型预测值
            plt.plot(torch.arange(xmin , xmax , 0.1).numpy() , model(torch.arange(xmin , xmax , 0.1).unsqueeze(1)).detach().numpy() , '-' , label="神经网络模型")
            plt.plot(x.detach().numpy() , y_p.detach().numpy() , 'k+' ,markersize=10 , label="神经网络模型预测值")

            plt.legend()
            plt.show()
            plt.pause(0.5)

    return losses
设置相关参数值并运行,得到参数值。
losses = training_loop(n_epochs=200 , optimizer=optimizer , model=seq_model , loss_fn=loss_fn , x=x , y=y)

  • 可视化损失:
对循环训练过程中记录的损失值进行可视化。
从结果中可以看到,模型损失在前20轮下降很快,因为输入数据较为简单,神经网络模型可以很快速的进行拟合。
plt.plot(range(200), losses)  
plt.xlabel('Epoch')  
plt.ylabel('Loss')  
plt.title('Loss vs. Epoch')  
plt.show()


更多内容可以前往官网查看

https://pytorch.org/


本篇文章来源于微信公众号: 码农设计师

RELATED ARTICLES

欢迎留下您的宝贵建议

Please enter your comment!
Please enter your name here

- Advertisment -

Most Popular

Recent Comments