自学内容网 自学内容网

2. 深度学习的项目流程(批量化打包数据、构建模型、训练模型、波士顿房价预测、激活函数、多层感知机)

原文链接:https://blog.csdn.net/Deadwalk/article/details/139649117?spm=1001.2014.3001.5502

1. 深度学习基本流程

1.1 流程图

  • 由于训练的本质就是求loss函数的最小值;所以,我们类比求 y = 2 x 2 y = 2x^2 y=2x2 最小值的过程,来看一下线性回归训练(也就是求loss最小值)的过程,其流程如下:
    在这里插入图片描述

1.2 代码实现

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

# 生成模拟数据
torch.manual_seed(42)
x_train = torch.randn(100, 13)  # 100个样本,每个样本有13个特征
y_train = torch.randn(100, 1)   # 每个样本对应一个输出值

# 定义模型
model = nn.Linear(13, 1)  # 输入特征数为13,输出特征数为1

# 初始化优化器
criterion = nn.MSELoss()  # 均方误差损失
optimizer = optim.SGD(model.parameters(), lr=0.01)  # 随机梯度下降优化器

# 迭代次数和学习率
epochs = 1000
learning_rate = 1e-2

# 使用 PyTorch 进行梯度下降
for _ in range(epochs):
    optimizer.zero_grad()  # 梯度清零

    outputs = model(x_train)  # 正向传播
    loss = criterion(outputs, y_train)  # 计算损失
    loss.backward()  # 反向传播
    optimizer.step()  # 更新参数

# 输出最终模型参数
print("线性回归模型的权重:", model.weight)
print("线性回归模型的偏置:", model.bias)

1.3 基本概念

  • 模型 model
    • 前向传播:把特征 X 带入模型 model ,得到预测结果 y_pred
      • 训练时:自动在底层构建计算图(把正向传播的流程记录下来,方便进行后续的分布求导/链式求导
      • 例如:在导数中,对于一个复合函数 h ( g ( f ( x ) ) ) h( g( f(x))) h(g(f(x))) ,我们需要进行链式求导,即 h ( g ( f ( x ) ) ) = f ′ ∗ g ′ ∗ h ′ h( g( f(x))) = f' * g' * h' h(g(f(x)))=fgh
    • 反向传播:本质是计算每个参数的梯度,是通过损失函数发起的
    • 模型的作用:只负责前向传播 forward,不负责后向传播 backward
  • 训练流程
    1. 从训练集中,取一批 batch 样本 (x, y)
    2. 把样本特征 X 送入模型 model,得到预测结果 y_pred
    3. 计算损失函数 loss = f(y_pred, y),计算当前的误差 loss
    4. 通过 loss , 反向传播,计算每个参数 (w, b) 的梯度
    5. 利用优化器 optimizer ,通过梯度下降法,更新参数
    6. 利用优化器 optimizer 清空参数的梯度
    7. 重复1-6 直至迭代结束(各项指标满足要求或是误差很小)
  • 预测流程
    1. 拿到待测样本 X(推理时,没有标签,只有特征)
    2. 把样本特征 X 送入模型 model ,得到预测结果 y_pred
    3. 根据 y_pred 解析并返回预测结果即可

2. 深度学习项目流程

  • 通过上述内容梳理,我们已经了解深度学习的一个基本流程,包括:定义模型、训练、预测。
  • 但是在实际工程使用中,由于训练数据比较庞大,所以我们还需要一些额外的步骤,例如:增加批量化打包流程。
  • 为了更好地理解深度学习的整体流程,我们仍然使用机器学习中使用的《波士顿房价预测》案例,来看一下深度学习下应该如何实现。

2.1 批量化打包数据

  • 原因:在实际的工程中,深度学习要进行大数据量的训练,批量化打包数据有以下优点:
    • 提高训练效率:通过批量化处理数据,可以充分利用GPU的并行计算能力,加快模型训练速度;
    • 稳定模型训练:批量化处理可以降低训练过程中的方差,使模型更加稳定;
    • 减少内存消耗:批量化处理可以减少在每个迭代中需要存储的数据量,节省内存消耗。
  • 原理:使用生成器来打包数据
    • 生成器记录了一个规则,每次调用生成器就会返回一个批次数据。
  • 实现
    1. 先自定义dataset
    2. 再定义dataloader
    from torch.utils.data import DataLoader, TensorDataset
    # 批量化打包数据示例代码
    # 创建数据集和数据加载器
    dataset = TensorDataset(x_tensor, y_tensor)
    data_loader = DataLoader(dataset, batch_size=16, shuffle=True)
    

2.2 构建模型

  • 定义
    • 在深度学习中构建模型是指设计神经网络结构,确定网络的层数、每层的神经元数量、激活函数等参数,以实现特定的学习任务。
  • 常见方式
    • Sequential模型:Sequential模型是一种简单的线性堆叠模型,层按顺序依次堆叠在一起,适用于顺序处理的神经网络结构。
    • Class子类化模型:通过继承框架提供的模型基类,用户可以自定义模型的结构和计算逻辑,实现更加灵活和定制化的模型构建。
    • 除上述方式之外,还有迁移学习、模型组合、模型集成、自动机器学习(AutoML)、超网络(Hypernetwork) 等方式,由于不是本章内容重点,暂不展开。

2.3 训练模型

(1)筹备训练

  • a. 定义损失函数
    • 目的:损失函数用于衡量模型预测结果与真实标签之间的差异,是优化算法的目标函数,帮助模型学习正确的参数。
    • 常见损失函数:
      • 均方误差损失(Mean Squared Error, MSE)
      • 交叉熵损失(Cross Entropy Loss)
  • b. 定义优化器
    • 目的:优化器用于更新模型参数,通过最小化损失函数来提高模型性能,调整模型参数使得损失函数达到最小值。
    • 常见优化器:
      • 随机梯度下降(SGD)
      • Adam
      • Adagrad等
  • c. 设置训练次数
    • 定义:训练次数指的是将整个训练数据集在模型上反复训练的次数,每次完整地遍历整个数据集称为一个训练周期(Epoch)。
    • 作用:通过增加训练次数,模型可以更好地学习数据集中的模式和特征,提高模型的泛化能力,减少过拟合的风险。
  • d. 设置学习率
    • 定义:学习率是优化算法中的一个重要超参数,控制模型参数在每次迭代中更新的步长大小,即参数沿着梯度方向更新的幅度。
    • 目的:学习率的选择影响模型训练的速度和性能,合适的学习率能够使模型更快地收敛到最优解,而过大或过小的学习率可能导致训练不稳定或陷入局部最优解。

(2)开始训练

  • 训练过程中需要监控模型指标,如:准确率、损失值等
  • 训练过程中需要保存模型参数,方便后续推理
  • 避免过拟合

2.4 模型推理

  • 训练好模型之后,直接使用模型进行推理即可。

3. 深度学习实现波士顿房价预测

3.1 数据读取、切分、预处理

# 数据读取
file_name = './housing.data'
X = []
y = []
with open(file=file_name, mode='r', encoding='utf8') as f:
#     f.readline()
    for  line in f:
        line = line.strip()
        if line:
            sample = [float(ele) for ele in line.split(" ") if ele]
            X.append(sample[:-1])
            y.append(sample[-1])

# 数据切分
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, 
                                                    test_size=0.2,
                                                    random_state=0)

# 数据预处理(规范化)
import numpy as np

# 转numpy数组
X_train = np.array(X_train)
X_test = np.array(X_test)

# 提取参数
_mean = X_train.mean(axis=0)
_std = X_train.std(axis=0) + 1e-9  # 为了避免除零,此处加上一个非常小的数

# 执行规范化处理
X_train = (X_train - _mean) / _std
X_test = (X_test - _mean) / _std

3.2 批量化打包数据

  • 通过定义一个继承Dataset的数据集类,方便数据的常见操作,如:len()、index()等。
import torch
from torch.utils.data import Dataset
from torch.utils.data import DataLoader


# 1. 继承Dataset 自定义一个数据集类
class HouseDataset(Dataset):
    """
        自定义一个房价数据集
    
    """
    def __init__(self, X, y):
        """
            接受参数,定义静态属性
        """
        self.X = X
        self.y = y
        
    
    def __len__(self):
        """
            返回数据集样本的个数
        """
        return len(self.X)
    
    
    def __getitem__(self, idx):
        """
            通过索引,读取第idx个样本
        """
        x = self.X[idx]
        y = self.y[idx]
        
        # 转张量
        x = torch.tensor(data=x, dtype=torch.float32)
        y = torch.tensor(data=[y], dtype=torch.float32)
        return x, y

此处__len__和__getitem__方法是Python的魔法方法,他们是回调(callback)函数,不需要用户自己调用而由系统调用。即:

告诉系统我定义的数据集在取长度和按index取元素调用哪个方法;
当系统触发这两种情况(取长度和按index取元素)时,会自动调用类里的__len__和__getitem__方法。

# 训练集加载器
house_train_dataset = HouseDataset(X=X_train, y=y_train)
house_train_dataloader = DataLoader(dataset=house_train_dataset, 
                                    batch_size=12,
                                    shuffle=True)

# 测试集加载器
house_test_dataset = HouseDataset(X=X_test, y=y_test)
house_test_dataloader = DataLoader(dataset=house_test_dataset, 
                                    batch_size=32,
                                    shuffle=True)

# 测试代码:查看上述训练集和测试集的数据形状
for X, y in house_train_dataset:
    print(X)
    print(X.shape)
    print(y)
    print(y.shape)
    break

tensor([-0.3726, -0.4996, -0.7049, 3.6645, -0.4249, 0.9357, 0.6937, -0.4372,
-0.1622, -0.5617, -0.4846, 0.3717, -0.4110])
torch.Size([13])
tensor([26.7000])
torch.Size([1])

3.3 搭建模型

# 模型搭建
from torch import nn

# # 搭建方法1:
# model = nn.Linear(in_features=13, out_features=1)

# # 搭建方法2:
# model = nn.Sequential(
#     nn.Linear(in_features=13, out_features=1)
# )

# 搭建方法3:
class Model(nn.Module):
    """
        自定义一个类
            - 必须继承 nn.Module
    """
    def __init__(self, n_features=13):
        """
            接收超参
            定义处理的层
        """
        # 先初始化父类
        super(Model, self).__init__()
        
        # 定义一个线性层(做一次矩阵变换)
        self.linear = nn.Linear(in_features=n_features, out_features=1)
        
    def forward(self, x):
        """
            模型前向传播逻辑
        """
        x = self.linear(x)
        return x


# 实例化模型
model = Model(n_features=13)
# 测试代码:可以看到模型的运行结果
for X, y in house_train_dataloader:
    y_pred = model(X)
    print(y_pred)
    print(y)
    break

tensor([[-0.3277],
[-0.3072],
[ 0.0355],
[-0.0539],
[-0.1478],
[-0.2848],
[ 0.5001],
[ 0.8047],
[ 0.2635],
[-0.2561],
[-0.1742],
[-0.4823]], grad_fn=)
tensor([[33.1000],
[14.5000],
[35.4000],
[39.8000],
[22.5000],
[23.8000],
[36.5000],
[14.6000],
[35.1000],
[25.0000],
[20.3000],
[18.8000]])

3.4 训练模型

(1)筹备训练

  • 定义模型(实例化上述自定义模型)、定义损失函数、定义优化器、定义训练次数和定义学习率
# 定义模型
model = Model(n_features=13)

# 定义训练的轮次
epochs = 100

# 定义学习率
learing_rate = 1e-3

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

# 定义优化器
optimizer = torch.optim.SGD(params=model.parameters(), 
                            lr=learing_rate)

(2)定义监控指标和方法

  • 在训练的过程中,我们需要对训练过程的重要指标加以监控,以避免训练有问题。
# 定义查看损失函数的方法,用于监控训练过程
def get_loss(dataloader):
    # 模型设置为评估模式
    # (BatchNorm LayNorm Dropout层,在train模式和eval模式下,行为是不一样)
    model.eval()
    
    
    # 收集每个批量的损失
    losses = []
    
    # 构建一个无梯度的环境(底层不会默认自动创建计算图,节约资源)
    with torch.no_grad():
        for X, y in dataloader:
            y_pred = model(X)
            loss = loss_fn(y_pred, y)
            losses.append(loss.item())
    
    # 计算每个批量损失的平均值
    final_loss = sum(losses) / len(losses)
    
    # 保留小数点后5位
    final_loss = round(final_loss, ndigits=5)
    
    return final_loss

(3)实现训练过程

def train():
    # 记录训练过程
    train_losses = []
    test_losses = []
    
    
    # 每一轮次
    for epoch in range(epochs):
        #模型设为训练模式
        model.train()
        
        # 每一批量
        for X, y in house_train_dataloader:
            # 1. 正向传播
            y_pred = model(X)
            
            # 2. 损失计算
            loss = loss_fn(y_pred, y)
            
            # 3. 反向传播
            loss.backward()
            
            # 4. 优化一步
            optimizer.step()
            
            # 5. 清空梯度
            optimizer.zero_grad()
            
        # 计算模型当前的损失情况
        train_loss = get_loss(dataloader=house_train_dataloader)
        test_loss = get_loss(dataloader=house_test_dataloader)
        
        train_losses.append(train_loss)
        test_losses.append(test_loss)
        
        print(f"当前是第{epoch+1}轮,训练集损失为:{train_loss}, 测试集损失为:{test_loss}")
        
    return train_losses, test_losses

(4)开始训练

train_losses, test_losses = train()

当前是第1轮,训练集损失为:512.23866, 测试集损失为:470.53479
当前是第2轮,训练集损失为:441.68754, 测试集损失为:414.82328
当前是第3轮,训练集损失为:387.13285, 测试集损失为:417.94884
当前是第4轮,训练集损失为:339.7604, 测试集损失为:321.25851
当前是第5轮,训练集损失为:295.34212, 测试集损失为:283.35604
当前是第6轮,训练集损失为:259.63065, 测试集损失为:304.31802
当前是第7轮,训练集损失为:229.71633, 测试集损失为:274.742
当前是第8轮,训练集损失为:201.60888, 测试集损失为:213.39904
当前是第9轮,训练集损失为:179.15055, 测试集损失为:193.0374
当前是第10轮,训练集损失为:158.91308, 测试集损失为:154.98766
当前是第11轮,训练集损失为:140.94878, 测试集损失为:143.02044
当前是第12轮,训练集损失为:125.19098, 测试集损失为:144.65741
当前是第13轮,训练集损失为:112.88125, 测试集损失为:129.76349
当前是第14轮,训练集损失为:100.19187, 测试集损失为:131.55499
当前是第15轮,训练集损失为:90.06036, 测试集损失为:96.69405
当前是第16轮,训练集损失为:81.32993, 测试集损失为:88.38998
当前是第17轮,训练集损失为:73.30434, 测试集损失为:83.43338
当前是第18轮,训练集损失为:66.68453, 测试集损失为:94.52958
当前是第19轮,训练集损失为:60.70854, 测试集损失为:111.13627
当前是第20轮,训练集损失为:55.5599, 测试集损失为:75.72988
当前是第21轮,训练集损失为:51.33824, 测试集损失为:102.07828
当前是第22轮,训练集损失为:47.48327, 测试集损失为:59.70907
当前是第23轮,训练集损失为:44.18092, 测试集损失为:53.83336
当前是第24轮,训练集损失为:41.14358, 测试集损失为:94.82549
当前是第25轮,训练集损失为:38.32627, 测试集损失为:89.27538
当前是第26轮,训练集损失为:36.4985, 测试集损失为:47.11266
当前是第27轮,训练集损失为:33.95471, 测试集损失为:44.56353
当前是第28轮,训练集损失为:32.83847, 测试集损失为:49.46564
当前是第29轮,训练集损失为:30.80773, 测试集损失为:77.49344
当前是第30轮,训练集损失为:29.49684, 测试集损失为:74.35186
当前是第31轮,训练集损失为:29.75533, 测试集损失为:45.33565
当前是第32轮,训练集损失为:27.50819, 测试集损失为:40.49028
当前是第33轮,训练集损失为:26.46446, 测试集损失为:37.61283
当前是第34轮,训练集损失为:25.75421, 测试集损失为:38.15598
当前是第35轮,训练集损失为:25.35517, 测试集损失为:42.44055
当前是第36轮,训练集损失为:24.32058, 测试集损失为:35.23858
当前是第37轮,训练集损失为:23.8545, 测试集损失为:45.60548
当前是第38轮,训练集损失为:23.91668, 测试集损失为:34.84441
当前是第39轮,训练集损失为:23.40606, 测试集损失为:44.46604
当前是第40轮,训练集损失为:22.6011, 测试集损失为:36.04847
当前是第41轮,训练集损失为:22.31131, 测试集损失为:34.43374
当前是第42轮,训练集损失为:22.0708, 测试集损失为:33.82917
当前是第43轮,训练集损失为:22.30289, 测试集损失为:37.85688
当前是第44轮,训练集损失为:21.53935, 测试集损失为:38.87277
当前是第45轮,训练集损失为:21.3713, 测试集损失为:33.417
当前是第46轮,训练集损失为:21.23279, 测试集损失为:31.88459
当前是第47轮,训练集损失为:21.06997, 测试集损失为:40.63353
当前是第48轮,训练集损失为:21.41602, 测试集损失为:36.13148
当前是第49轮,训练集损失为:21.15649, 测试集损失为:36.81873
当前是第50轮,训练集损失为:20.78297, 测试集损失为:70.94823
当前是第51轮,训练集损失为:20.58092, 测试集损失为:33.10058
当前是第52轮,训练集损失为:20.60467, 测试集损失为:35.11913
当前是第53轮,训练集损失为:20.43625, 测试集损失为:33.78005
当前是第54轮,训练集损失为:20.52897, 测试集损失为:34.07798
当前是第55轮,训练集损失为:20.64655, 测试集损失为:39.28524
当前是第56轮,训练集损失为:20.30059, 测试集损失为:33.22317
当前是第57轮,训练集损失为:20.25821, 测试集损失为:36.61137
当前是第58轮,训练集损失为:20.17982, 测试集损失为:31.30995
当前是第59轮,训练集损失为:20.7384, 测试集损失为:61.73834
当前是第60轮,训练集损失为:20.29678, 测试集损失为:31.74056
当前是第61轮,训练集损失为:20.14952, 测试集损失为:36.40789
当前是第62轮,训练集损失为:20.14775, 测试集损失为:34.92755
当前是第63轮,训练集损失为:20.2442, 测试集损失为:35.53998
当前是第64轮,训练集损失为:20.06632, 测试集损失为:64.03114
当前是第65轮,训练集损失为:19.99748, 测试集损失为:33.22721
当前是第66轮,训练集损失为:19.96938, 测试集损失为:30.25136
当前是第67轮,训练集损失为:19.99487, 测试集损失为:31.36242
当前是第68轮,训练集损失为:20.17933, 测试集损失为:58.25826
当前是第69轮,训练集损失为:19.93474, 测试集损失为:38.55068
当前是第70轮,训练集损失为:20.28924, 测试集损失为:40.849
当前是第71轮,训练集损失为:20.0135, 测试集损失为:31.5855
当前是第72轮,训练集损失为:19.83351, 测试集损失为:34.03661
当前是第73轮,训练集损失为:20.40153, 测试集损失为:30.72532
当前是第74轮,训练集损失为:19.93389, 测试集损失为:29.66065
当前是第75轮,训练集损失为:19.84209, 测试集损失为:31.01681
当前是第76轮,训练集损失为:19.76584, 测试集损失为:29.77414
当前是第77轮,训练集损失为:19.99292, 测试集损失为:35.58202
当前是第78轮,训练集损失为:20.03342, 测试集损失为:29.54016
当前是第79轮,训练集损失为:19.84374, 测试集损失为:34.61122
当前是第80轮,训练集损失为:19.78551, 测试集损失为:57.45225
当前是第81轮,训练集损失为:19.99286, 测试集损失为:38.98204
当前是第82轮,训练集损失为:20.83931, 测试集损失为:37.50468
当前是第83轮,训练集损失为:19.8902, 测试集损失为:32.13173
当前是第84轮,训练集损失为:20.81494, 测试集损失为:36.72431
当前是第85轮,训练集损失为:19.76138, 测试集损失为:32.56446
当前是第86轮,训练集损失为:19.93493, 测试集损失为:32.25109
当前是第87轮,训练集损失为:19.87319, 测试集损失为:29.45971
当前是第88轮,训练集损失为:19.76319, 测试集损失为:30.47269
当前是第89轮,训练集损失为:19.66747, 测试集损失为:31.15023
当前是第90轮,训练集损失为:19.99098, 测试集损失为:58.56397
当前是第91轮,训练集损失为:19.69602, 测试集损失为:28.64936
当前是第92轮,训练集损失为:19.76346, 测试集损失为:29.46989
当前是第93轮,训练集损失为:19.72865, 测试集损失为:39.08675
当前是第94轮,训练集损失为:19.64981, 测试集损失为:30.54216
当前是第95轮,训练集损失为:19.74504, 测试集损失为:29.54564
当前是第96轮,训练集损失为:19.93373, 测试集损失为:29.28439
当前是第97轮,训练集损失为:19.62625, 测试集损失为:43.54383
当前是第98轮,训练集损失为:19.64032, 测试集损失为:40.3629
当前是第99轮,训练集损失为:19.62572, 测试集损失为:32.7787
当前是第100轮,训练集损失为:19.59034, 测试集损失为:34.74736

3.5 图形化监控数据

  • 为了方便查看训练过程变化情况,可以使用matplotlib绘制损失函数的变化曲线。
from matplotlib import pyplot as plt

plt.plot(train_losses, c="blue", label="train_loss")
plt.plot(test_losses, c="red", label="test_loss")
plt.title("The Losses")
plt.xlabel(xlabel="epoches")
plt.ylabel(ylabel="loss")
plt.legend()

在这里插入图片描述

  • 由上图可以看到:在一开始的训练中,损失值快速下降;当训练次数到40次左右后,损失值已经下降不明显。
  • 我们可以通过加入激活函数,引入非线性因素来优化模型。

3.6 激活函数

  • 定义:
    • 激活函数是神经网络中的一种非线性函数,通常应用在神经元的输出上,将输入信号转换为输出信号。激活函数引入了非线性因素,使神经网络可以学习和表达复杂的非线性关系。
  • 举个例子:
    • 想象一下,神经网络就像是一个复杂的拼图游戏,每个神经元就像是拼图中的一个小块。当我们只使用线性函数(比如直线)作为激活函数时,就好比每个小块都是直线,无法拼出复杂的图案,只能表达简单的线性关系。
      但是,当我们引入非线性的激活函数时,就好比在每个小块上加入了各种形状和曲线,使得每个小块可以表达更加复杂的形状和关系。这样,当我们把许多这样的小块(神经元)组合在一起时,就可以拼出更加复杂和多样的图案(非线性关系),从而让神经网络能够学习和表达更加复杂的模式和特征。
      因此,激活函数的作用就是为神经网络引入了这种非线性因素,使得神经网络可以更好地学习和表达复杂的非线性关系,就像在拼图游戏中加入了各种形状和曲线,让我们能够拼出更加丰富多彩的图案一样。
  • 常见激活函数有:Sigmoid函数、Tanh函数、ReLU函数、Softmax函数,相关内容在补充知识段落展开。
  • 使用方法:
class Model(nn.Module):
    """
        自定义一个类
            - 必须继承 nn.Module
    """
    def __init__(self, n_features=13):
        """
            接收超参
            定义处理的层
        """
        # 先初始化父类
        super(Model, self).__init__()
        
        # 定义一个线性层(做一次矩阵变换)
        self.linear = nn.Linear(in_features=n_features, out_features=1)
        
    def forward(self, x):
        """
            模型前向传播逻辑
        """
        x = self.linear(x)
        x = nn.ReLU()(x)  # 添加ReLU激活函数
        return x

当前是第495轮,训练集损失为:19.04356, 测试集损失为:38.45236
当前是第496轮,训练集损失为:19.29613, 测试集损失为:31.20161
当前是第497轮,训练集损失为:19.03669, 测试集损失为:30.85609
当前是第498轮,训练集损失为:19.01585, 测试集损失为:29.17376
当前是第499轮,训练集损失为:19.03183, 测试集损失为:28.62275
当前是第500轮,训练集损失为:19.10681, 测试集损失为:32.04256

在这里插入图片描述

3.7 多层感知机

  • 由于无法模拟诸如异或以及其他复杂函数的功能,使得单层感知机的应用较为单一。一个简单的想法是,如果能在感知机模型中增加若干隐藏层,增强神经网络的非线性表达能力,就会让神经网络具有更强拟合能力。
    请添加图片描述

  • 大脑是一个多层感知机,每一层都在学习不同级别的特征。

    • 输入层:输入层就像你的眼睛,它接收到动物的各种特征信息,比如颜色、大小等。
    • 隐藏层:隐藏层就像你的大脑皮层,它处理输入的特征信息,并尝试从中提取出更加抽象和复杂的特征,比如动物的轮廓、纹理等。
    • 输出层:输出层就像你的嘴巴,它根据隐藏层提取的特征信息做出判断,比如判断输入的动物是狗还是猫。
    • 通过多次学习和训练,你的大脑(多层感知机)会逐渐调整隐藏层中的神经元(神经元就像大脑中的神经元)的连接权重,从而更好地识别不同类型的动物。
  • 实现方法:修改自定义模型的初始化方法,加入一个新的线性层

class Model(nn.Module):
    """
        自定义一个类
            - 必须继承 nn.Module
    """
    def __init__(self, n_features=13):
        """
            接收超参
            定义处理的层
        """
        # 先初始化父类
        super(Model, self).__init__()
        
        # 定义两个线性层     
        self.linear1 = nn.Linear(in_features=n_features, out_features=8)
        self.linear2 = nn.Linear(in_features=8, out_features=1)

    def forward(self, x):
        """
            模型前向传播逻辑
        """
        x = self.linear1(x)
        x = torch.relu(x)  # 添加ReLU激活函数
        x = self.linear2(x)

        return x

当前是第95轮,训练集损失为:7.32678, 测试集损失为:18.07006
当前是第96轮,训练集损失为:7.16269, 测试集损失为:33.28857
当前是第97轮,训练集损失为:7.33148, 测试集损失为:23.29867
当前是第98轮,训练集损失为:7.24137, 测试集损失为:17.90972
当前是第99轮,训练集损失为:7.30563, 测试集损失为:17.59436
当前是第100轮,训练集损失为:7.21022, 测试集损失为:18.19897

在这里插入图片描述

  • 由上图可以看到,多层感知机+引入激活函数,损失值已经降到8左右;对比之前未优化的模型,模型的损失值变小,预测准确性得到提升。

原文地址:https://blog.csdn.net/weixin_38566632/article/details/140319602

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