自学内容网 自学内容网

Pytorch学习笔记day3——用神经网络学习一组函数

好的,我们开始吧。首先第一个问题,神经网络的本质是什么?是古典主义的人类的神经元吗?绝对不是,他只是一个优化函数
y = f θ ( x ) y = f_{\theta}(x) y=fθ(x)
这和小学学到的线性函数拟合并无本质区别。只是其中参数 θ \theta θ是大量的参数,并且函数 f θ f_{\theta} fθ本身的形式也会非常复杂。相应的参数 θ \theta θ也无法像线性拟合一样,直接列方程求解,而是依赖于优化算法。

所以今天,我们就尝试用神经网络,去学习几个函数表达式。

训练代码解读

不多说了直接贴代码

import numpy as np
import math
import matplotlib.pyplot as plt

import torch
import torch.nn as nn
import torch.optim as optim

class Net(nn.Module):
    def __init__(self, num_layers, input_size, hidden_size, output_size):
        super(Net, self).__init__()
        self.layers = nn.ModuleList([nn.Linear(input_size, hidden_size, bias=True)] + 
                                    [nn.Linear(hidden_size, hidden_size, bias=True) for _ in range(num_layers - 2)] + 
                                    [nn.Linear(hidden_size, output_size, bias=True)])
        
    def forward(self, x):
        for layer in self.layers:
            x = nn.functional.gelu(layer(x))
        return x

if __name__=="__main__":
    # 被训练函数---------------------------
    x = np.linspace(0.1, 2.1, 100)
    y = [[math.exp(ele)*ele, math.exp(ele), ele*ele] for ele in x]
    
    plt.plot(x, y)
    plt.show()

    # 训练部分------------------------
    # 生成被训练数据------------------------
    x = torch.Tensor(x.reshape(-1,1))
    y = torch.Tensor(y)
    
    # 初始化网络
    net = Net(6, 1, 32, 3)
 
    # 定义损失函数和优化器
    loss_fn = nn.MSELoss(reduction='sum')
    optimizer = optim.Adam(net.parameters(), lr=0.01)
 
    # 训练模型
    epochs = 1000
    for epoch in range(epochs):
        y_pred = net(x)
        loss = loss_fn(y_pred, y)
        
        optimizer.zero_grad() #梯度清零,否则梯度会累积
        loss.backward()       #计算参数关于loss函数的梯度,需要做梯度会穿
        optimizer.step()      #利用梯度对model参数进行一次训练
        
        if epoch % 10 == 0:
            print('epoch: ', epoch, "    loss: ", loss.item())
        if epoch % 100 == 0:
            plt.clf()
            plt.plot(x, y,'b-',x, y_pred.detach().numpy(),'r-')
            plt.show()

这里多说一句撒,关于训练的写法,我觉得mindspore设计得是比pytorch要好的。optimizer.zero_grad()这种事情,mindspore就不需要做,不如说正常人前一次梯度都不会保留吧,默认不保留才是合理的吧。第二个是,获取梯度的grad,loss.backward应该显式的写出来,然后传进优化器的一次训练步才更加符合直觉,比如像下面这样

grad = loss.backward()       #梯度回传获取grad
optimizer.step(grad)      #利用梯度对net的参数进行一次训练
# 上述两行纯属个人yy,不能运行的哈

训练结果如下
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

可以看到300左右就已经收敛得比较好了。

神经网络的局限性与正则化的重要性

简单粗暴的将被学习的函数第一个分量减去10

    x = np.linspace(0.1, 2.1, 100)
    y = [[math.exp(ele)*ele - 10, math.exp(ele), ele*ele] for ele in x]

突然就不能学了
在这里插入图片描述
这其实是因为,我们使用的激活函数,为gelu函数。嗯差不多长下面这样,这种激活函数是没法表示负值的。导致整个神经网络没法表示负数。
在这里插入图片描述
所以说神经网络也不完全是魔法,而是一个优化问题。我们需要先找到能以较少参数就表示被优化函数的网络,然后再对这个网络里面的参数进行优化,才能得到合理的结果。对当前情况,我们选一个,能表示较大负数的激活函数,例如:呃?!我震惊的发现好像没有类似这样的激活函数,AI训练的问题大多数都是非负的。

好吧,所以神经网络要学习的问题,我们一定要做合适的正则化或者归一化,让我们的网络能够表示当前的问题才行。


原文地址:https://blog.csdn.net/qq_40583925/article/details/140534515

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!