PyTorch 线性回归模型构建与神经网络基础要点解析

笔记

1 PyTorch构建线性回归模型

1.1 创建数据集

python 复制代码
import torch
from torch.utils.data import TensorDataset  # 创建x和y张量数据集对象
from torch.utils.data import DataLoader  # 创建数据集加载器
import torch.nn as nn  # 损失函数和回归函数
from torch.optim import SGD  # 随机梯度下降函数, 取一个训练样本算梯度值
from sklearn.datasets import make_regression  # 创建随机样本, 工作中不使用
import matplotlib.pyplot as plt
​
plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号
​
​
# todo: 1-创建线性回归样本 x y coef(w) b
def create_datasets():
    x, y, coef = make_regression(n_samples=100,  # 样本数
                                 n_features=1,  # 特征数
                                 noise=10,  # 标准差, 噪声, 样本离散程度
                                 coef=True,  # 返回系数, w
                                 bias=14.5,  # 截距 b
                                 random_state=0)
​
    # 将数组转换成张量
    x = torch.tensor(data=x)
    y = torch.tensor(data=y)
    # print('x->', x)
    # print('y->', y)
    # print('coef->', coef)
    return x, y, coef
​
if __name__ == '__main__':
    x, y, coef = create_datasets()

1.2 训练模型

python 复制代码
# todo: 2-模型训练
def train(x, y, coef):
    # 创建张量数据集对象
    datasets = TensorDataset(x, y)
    print('datasets->', datasets)
    # 创建数据加载器对象
    # dataset: 张量数据集对象
    # batch_size: 每个batch的样本数
    # shuffle: 是否打乱样本
    dataloader = DataLoader(dataset=datasets, batch_size=16, shuffle=True)
    print('dataloader->', dataloader)
    # for batch in dataloader:  # 每次遍历取每个batch样本
    #   print('batch->', batch)  # [x张量对象, y张量对象]
    #   break
    # 创建初始回归模型对象, 随机生成w和b, 元素类型为float32
    # in_features: 输入特征数 1个
    # out_features: 输出特征数 1个
    model = nn.Linear(in_features=1, out_features=1)
    print('model->', model)
    # 获取模型对象的w和b参数
    print('model.weight->', model.weight)
    print('model.bias->', model.bias)
    print('model.parameters()->', list(model.parameters()))
    # 创建损失函数对象, 计算损失值
    criterion = nn.MSELoss()
    # 创建SGD优化器对象, 更新w和b
    optimizer = SGD(params=model.parameters(), lr=0.01)
    # 定义变量, 接收训练次数, 损失值, 训练样本数
    epochs = 100
    loss_list = []  # 存储每次训练的平均损失值
    total_loss = 0.0
    train_samples = 0
    for epoch in range(epochs):  # 训练100次
        # 借助循环实现 mini-batch SGD 模型训练
        for train_x, train_y in dataloader:
            # 模型预测
            # train_x->float64
            # w->float32
            y_pred = model(train_x.type(dtype=torch.float32))  # y=w*x+b
            print('y_pred->', y_pred)
            # 计算损失值, 调用损失函数对象
            # print('train_y->', train_y)
            # y_pred: 二维张量
            # train_y: 一维张量, 修改成二维张量, n行1列
            # 可能发生报错, 修改形状
            # 修改train_y元素类型, 和y_pred类型一致, 否则发生报错
            loss = criterion(y_pred, train_y.reshape(shape=(-1, 1)).type(dtype=torch.float32))
            print('loss->', loss)
            # 获取loss标量张量的数值 item()
            # 统计n次batch的总MSE值
            total_loss += loss.item()
            # 统计batch次数
            train_samples += 1
            # 梯度清零
            optimizer.zero_grad()
            # 计算梯度值
            loss.backward()
            # 梯度更新 w和b更新
            # step()等同 w=w-lr*grad
            optimizer.step()
        # 每次训练的平均损失值保存到loss列表中
        loss_list.append(total_loss / train_samples)
        print('每次训练的平均损失值->', total_loss / train_samples)
    print('loss_list->', loss_list)
    print('w->', model.weight)
    print('b->', model.bias)
    
    # 绘制每次训练损失值曲线变化图
    plt.plot(range(epochs), loss_list)
    plt.title('损失值曲线变化图')
    plt.grid()
    plt.show()
​
    # 绘制预测值和真实值对比图
    # 绘制样本点分布
    plt.scatter(x, y)
    # 获取1000个样本点
    # x = torch.linspace(start=x.min(), end=x.max(), steps=1000)
    # 计算训练模型的预测值
    y1 = torch.tensor(data=[v * model.weight + model.bias for v in x])
    # 计算真实值
    y2 = torch.tensor(data=[v * coef + 14.5 for v in x])
    plt.plot(x, y1, label='训练')
    plt.plot(x, y2, label='真实')
    plt.legend()
    plt.grid()
    plt.show()
​
​
if __name__ == '__main__':
    x, y, coef = create_datasets()
    train(x, y, coef)

2 人工神经网络介绍

2.1 什么是人工神经网络

  • 仿生生物学神经网络的计算模型

  • ANN(人工神经网络)->NN(神经网络)

2.2 如何构建人工神经网络

神经网络是由三个层, 每层由多个神经元构成

  • 输入层: 输入样本的特征值, 一层

  • 隐藏层: 提取复杂特征, 可以有多层

  • 输出层: 输出y值, y预测值

2.3 人工神经网络内部状态值和激活值

神经元如何工作

  • 内部状态值(加权求和值)

    • z=w1*x1+w2*x2+...+b
  • 激活值

    • a=f(z)

3 激活函数介绍

3.1 激活函数作用

  • 给神经网络模型中引入非线性因素

  • 生产环境中,问题存在线性不可分情况

3.2 常见激活函数

  • sigmoid激活函数

    • sigmoid激活值范围是[0, 1], 只有正信号, 没有负信号, 模型只能学习到正信号

    • 加权求和值在[-6,6]范围, 计算激活值时分布到[0, 1], 否则激活值只能是0或1

    • sigmoid激活函数导数值范围是[0,0.25], 加权求和值在[-6,6]范围, 激活值梯度才分布到[0, 0.25], 否则梯度为0

    • 神经网络中梯度连乘, sigmoid激活函数梯度值很小, 接近0, 梯度消失 0.25*0.25*0.25*...

    • sigmoid一般在二分类输出层使用, 如果神经网络隐藏层在5层之内也可以考虑使用sigmoid

    python 复制代码
    # sigmoid激活值: torch.sigmoid(x)
    ​
    import torch
    import matplotlib.pyplot as plt
    ​
    plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
    plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号
    ​
    ​
    def dm01():
        # 创建x值, 线性模型输出值作为激活函数的输入值
        x = torch.linspace(-20, 20, 1000)
        # 计算激活值
        y = torch.sigmoid(input=x)
        # 创建画布对象和坐标轴对象
        _, axes = plt.subplots(1, 2)  # 一行两列, 绘制两个子图
        axes[0].plot(x, y)
        axes[0].grid()
        axes[0].set_title('sigmoid激活函数')
    ​
        # 创建x值,可以自动微分, 线性模型输出值作为激活函数的输入值
        x = torch.linspace(-20, 20, 1000, requires_grad=True)
        torch.sigmoid(input=x).sum().backward()
        axes[1].plot(x.detach().numpy(), x.grad)
        axes[1].grid()
        axes[1].set_title('sigmoid激活函数')
        plt.show()
    ​
    ​
    if __name__ == '__main__':
        dm01()
  • tanh激活函数

    • tanh激活值范围是[-1, 1], 既有正信号, 又有负信号, 激活值是以0对称, 模型可以学习到正负信号

    • 加权求和值在[-3,3]范围, 计算激活值时分布到[-1, 1], 否则激活值只能是-1或1

    • tanh激活函数导数值范围是[0,1], 加权求和值在[-3,3]范围, 相比sigmoid激活导数更大, 模型收敛程度更快, 但是如果加权求和值大于3或小于-3, 也是会导致梯度消失, 最好分布在0附近(梯度值最大)

    • tanh激活函数可以在隐藏层使用, 不是优先选择, 浅层神经网络可以使用

    python 复制代码
    # tanh激活值: torch.tanh(x)
    ​
    import torch
    import matplotlib.pyplot as plt
    from torch.nn import functional as F
    # F.sigmoid()
    # F.tanh()
    ​
    plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
    plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号
    ​
    ​
    def dm01():
        # 创建x值, 线性模型输出值作为激活函数的输入值
        x = torch.linspace(-20, 20, 1000)
        # 计算激活值
        y = torch.tanh(input=x)
        # 创建画布对象和坐标轴对象
        _, axes = plt.subplots(1, 2)  # 一行两列, 绘制两个子图
        axes[0].plot(x, y)
        axes[0].grid()
        axes[0].set_title('tanh激活函数')
    ​
        # 创建x值,可以自动微分, 线性模型输出值作为激活函数的输入值
        x = torch.linspace(-20, 20, 1000, requires_grad=True)
        torch.tanh(input=x).sum().backward()
        axes[1].plot(x.detach().numpy(), x.grad)
        axes[1].grid()
        axes[1].set_title('tanh激活函数')
        plt.show()
    ​
    ​
    if __name__ == '__main__':
        dm01()
  • relu激活函数

    • relu激活值范围是[0, x], x是线性输出的正值, 只有正信号

    • 加权求和值大于0, 也可以一部分小于0(神经元死亡, 防止过拟合)

    • relu激活函数导数值0或1, 如果线性输出大于0, 导数为1, 不会出现梯度消失情况, 模型收敛程度更快; 如果线性输出小于0, 神经元死亡, 防止过拟合(选择leaky relu或prelu)

    • relu激活函数优先选择, 计算复杂度最小, 大于0不存在梯度消失情况

    python 复制代码
    # relu激活值: torch.relu(x)
    ​
    import torch
    import matplotlib.pyplot as plt
    from torch.nn import functional as F
    # F.sigmoid()
    # F.tanh()
    ​
    plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
    plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号
    ​
    ​
    def dm01():
        # 创建x值, 线性模型输出值作为激活函数的输入值
        x = torch.linspace(-20, 20, 1000)
        # 计算激活值
        y = torch.relu(input=x)
        # torch.leaky_relu()
        # torch.prelu()
        # 创建画布对象和坐标轴对象
        _, axes = plt.subplots(1, 2)  # 一行两列, 绘制两个子图
        axes[0].plot(x, y)
        axes[0].grid()
        axes[0].set_title('relu激活函数')
    ​
        # 创建x值,可以自动微分, 线性模型输出值作为激活函数的输入值
        x = torch.linspace(-20, 20, 1000, requires_grad=True)
        torch.relu(input=x).sum().backward()
        axes[1].plot(x.detach().numpy(), x.grad)
        axes[1].grid()
        axes[1].set_title('relu激活函数')
        plt.show()
    ​
    ​
    if __name__ == '__main__':
        dm01()
  • softmax激活函数

    • 多分类任务的输出层使用, 将输出层加权求和值转换成概率
    python 复制代码
    import torch
    import pandas as pd
    ​
    ​
    def dm01():
        # 创建输出层加权求和值
        y = torch.tensor(data=[[0.2, 0.02, 0.15, 0.15, 1.3, 0.5, 0.06, 1.1, 0.05, 3.75],
                               [0.2, 0.02, 0.15, 3.75, 1.3, 0.5, 0.06, 1.1, 0.05, 0.15]])
        # softmax激活函数转换成概率值
        # 1轴按列计算
        # y_softmax = torch.softmax(input=y, dim=-1)
        y_softmax = torch.softmax(input=y, dim=1)
        print('y_softmax->', y_softmax)
    ​
    ​
    if __name__ == '__main__':
        dm01()

3.6 如何选择激活函数

  • 隐藏层

    • 优选relu激活函数, 其次选leaky relu/prelu

    • 尽量少使用sigmoid激活函数, 可以使用tanh激活函数代替sigmoid激活函数 浅层神经网络

  • 输出层

    • 二分类问题 sigmoid激活函数

    • 多分类问题 softmax激活函数

    • 回归问题 identity激活函数

4 参数初始化

4.1 参数初始化作用

  • 参数->w和b, 创建初版模型时指定w和b的值

  • 选择合适的参数, 计算得到的加权求和的值会落到激活函数合理的区间, 加快模型收敛速度以及增加不同学习特征值

4.2 常见参数初始化方法

  • 随机初始化

  • 全0、1初始化

  • 固定值初始化

  • kaiming初始化

  • xavier初始化

    python 复制代码
    import torch
    import torch.nn as nn
    ​
    ​
    # 随机参数初始化
    def dm01():
        # 创建线性层对象, 对线性层的权重进行初始化
        # in_features: 输入神经元个数
        # out_features: 输出神经元个数
        linear1 = nn.Linear(in_features=5, out_features=8)
        linear2 = nn.Linear(in_features=8, out_features=10)
        # 均匀分布初始化,默认在(0,1)区间均匀分布, 可以通过a和b参数调整区间
        nn.init.uniform_(linear1.weight)
        nn.init.uniform_(linear1.weight, a=-1/torch.sqrt(torch.tensor(5.0)), b=1/torch.sqrt(torch.tensor(5.0)))
        nn.init.uniform_(linear1.bias)
        print(linear1.weight)
        print(linear1.bias)
    ​
    ​
    # 正态分布参数初始化
    def dm02():
        # 创建线性层对象, 对线性层的权重进行初始化
        # in_features: 输入神经元个数
        # out_features: 输出神经元个数
        linear1 = nn.Linear(in_features=5, out_features=8)
        linear2 = nn.Linear(in_features=8, out_features=10)
        # 均匀分布初始化
        nn.init.normal_(linear1.weight)
        nn.init.normal_(linear1.bias)
        print(linear1.weight)
        print(linear1.bias)
    ​
    ​
    # nn.init.zeros_()  # 全0初始化
    # nn.init.ones_()  # 全1初始化
    # nn.init.constant_(val=0.1)  # 全固定值初始化
    # nn.init.kaiming_uniform_()  # 凯明均匀分布初始化
    # nn.init.kaiming_normal_()  # 凯明正态分布初始化
    # nn.init.xavier_uniform_()  # xavier均匀分布初始化
    # nn.init.xavier_normal_()  # xavier正态分布初始化
    ​
    ​
    if __name__ == '__main__':
        dm01()
        dm02()

4.3 如何选择参数初始化方法

  • 浅层神经网络可以选择随机初始化

  • 深层神经网络结合激活函数选择

    • tanh激活函数 -> xavier初始化

    • relu激活函数 -> kaiming初始化

相关推荐
伊织code1 小时前
PyTorch API 10 - benchmark、data、批处理、命名张量
pytorch·python·ai·api·-·10
Francek Chen4 小时前
【现代深度学习技术】注意力机制04:Bahdanau注意力
人工智能·pytorch·深度学习·神经网络·注意力机制
我是小伍同学10 小时前
基于卷积神经网络和Pyqt5的猫狗识别小程序
人工智能·python·神经网络·qt·小程序·cnn
12960045212 小时前
pytorch基础的学习
人工智能·pytorch·学习
沉默媛13 小时前
RuntimeError: expected scalar type ComplexDouble but found Float
人工智能·pytorch·深度学习
埃菲尔铁塔_CV算法14 小时前
POSE识别 神经网络
人工智能·深度学习·神经网络
大G哥14 小时前
加速LLM大模型推理,KV缓存技术详解与PyTorch实现
人工智能·pytorch·python·深度学习·缓存
qq_263_tohua14 小时前
第99期 dropout防止过拟合
pytorch·python·深度学习
奋斗者1号16 小时前
神经网络中之多类别分类:从基础到高级应用
大数据·神经网络·分类