最简单的深度学习代码demo

1.初始化

在处理机器学习或深度学习的数据准备过程,将训练集和验证集转换为PyTorch张量类型以便于后续的模型训练。下面逐句解析代码的意义:

数据转换为 PyTorch Tensors

x_train, y_train, x_valid, y_valid = map(torch.tensor, (x_train, y_train, x_valid, y_valid))

这条语句的作用是将x_trainy_trainx_validy_valid(即训练特征、训练标签、验证特征、验证标签)都转化为torch.Tensor对象,这是PyTorch中用于数值计算的基本数据结构。这一转化使得数据能够在GPU上加速运算,并且能够配合PyTorch神经网络模块和其他数学运算函数。

获取形状和范围

n, c = x_train.shape

这里x_train.shape返回的是训练集特征的维度大小,赋值给了变量nc

  • n: 训练样本的数量。它表示x_train中有多少个样本或实例。
  • c: 特征数量或每个样本的维度。在图像识别任务中,如果是灰度图,则c代表图片的宽度或高度;如果是彩色图像(例如RGB),则c=3,分别对应红绿蓝三个通道。

在使用梯度下降算法进行模型训练时的常见操作。下面逐行解析这段代码:

定义批量大小

bs = 64

bs代表批量大小(batch size),是每次迭代中模型将同时处理的数据量。在训练深度学习模型时,数据集通常被划分为多个小批量(batches),模型在每个小批量上进行前向和反向传播,然后更新权重。选择合适的批量大小对于训练效率和模型性能都很重要。

获取一个批次的数据

xb = x_train[0:bs] # a mini-batch from x
yb = y_train[0:bs]

这里xbyb分别从训练集特征x_train和标签y_train中提取了前bs个数据点,形成了一个批次的特征和标签数据。这些将被用于模型的单次前向传播和梯度计算。

初始化权重和偏置

weights = torch.randn([784, 10], dtype = torch.float, requires_grad = True)

weights是模型的权重矩阵,其维度为[784, 10]。这假设输入的特征向量长度为784(例如28x28的图像数据),模型有10个输出类别(比如数字0到9的分类)。torch.randn函数用于从标准正态分布中随机初始化权重,requires_grad = True指定了这个张量需要梯度计算,以便在反向传播中更新权重。

bias = torch.zeros(10, requires_grad=True)

bias是模型的偏置向量,长度为10,初始化为全零向量。偏置项的作用是使模型能够拟合数据的偏移,它同样被标记为需要梯度计算。

整个过程描述了从数据准备到模型初始化的初步步骤,为后续的模型训练(前向传播、损失计算、反向传播和权重更新)奠定了基础。

2.定义了一个简单的多层感知机(MLP)模型

该模型被设计用来处理像MNIST这样的手写数字分类问题。下面是代码分析及完善后的版本:

import torch
import torch.nn as nn
import torch.nn.functional as F

class MnistModel(nn.Module): # 使用更具描述性的类名
def __init__(self):
super(MnistModel, self).__init__() # 调用父类构造方法
self.fc1 = nn.Linear(784, 128) # 输入层到隐藏层1
self.fc2 = nn.Linear(128, 256) # 隐藏层1到隐藏层2
self.fc3 = nn.Linear(256, 10) # 隐藏层2到输出层

def forward(self, x):
x = x.view(-1, 784) # 将输入重塑成 [batch_size, 784] 的一维向量
x = F.relu(self.fc1(x)) # 应用ReLU激活函数
x = F.relu(self.fc2(x)) # 应用ReLU激活函数
x = self.fc3(x) # 输出层没有激活函数
return x # 返回模型的输出结果
  1. 模型构造

    • 类定义 MnistModel 继承自 nn.Module
    • 构造函数调用了基类 nn.Module 的构造函数并通过 super() 实现。
    • 定义了三层线性变换(全连接层):两层隐含层和一层输出层。
  2. 前向传播

    • 在 forward 函数中定义了数据通过网络的流动过程。
    • 输入首先被展平成一维向量,这是因为卷积层会生成二维或多维的特征图,而全连接层接收的是扁平化的向量。
    • ReLU 激活函数应用于每一层全连接层后除最后一层外的所有层。
    • 最终输出直接来自最后一个全连接层,不需要经过激活函数是因为交叉熵损失函数包含了Softmax操作。
  3. 可学习参数访问

    • 可以通过 model.named_parameters() 或者 model.parameters() 来获取模型中的所有可学习参数的迭代器,这对于设置optimizer(优化器)非常重要,因为后者需要知道哪些参数应该被更新。

这样构建的模型可以直接用于训练,只需要适配正确的输入数据格式(一般为 [batch_size, 1, 28, 28])并配置好损失函数(如 nn.CrossEntropyLoss)和优化器(如 torch.optim.SGDtorch.optim.Adam)。

3.主要处理函数流程

get_data函数

 使用TensorDatasetDataLoader可以极大地简化数据处理和加载的过程,特别是在深度学习中。下面是对这段代码的详细解析:

使用TensorDataset封装数据
from torch.utils.data import TensorDataset
from torch.utils.data import DataLoader

train_ds = TensorDataset(x_train, y_train)
valid_ds = TensorDataset(x_valid, y_valid)
  • TensorDataset接收多个Tensor参数,通常是一个特征Tensorx_trainx_valid)和一个目标Tensory_trainy_valid)。这些数据通常存储在内存中,适用于不需从磁盘实时读取数据的场景。
  • 通过使用TensorDataset,可以将特征数据和标签数据打包成一个数据集,便于后续使用DataLoader进行处理。
使用DataLoader加载数据
train_dl = DataLoader(train_ds, batch_size=bs, shuffle=True)
valid_dl = DataLoader(valid_ds, batch_size=bs * 2)
  • DataLoader是PyTorch中用于数据加载的工具,它可以从数据集中批量、高效地获取数据,并可进行数据的打乱(shuffle)以提高模型的泛化能力。
  • batch_size参数指定了数据加载的批量大小,shuffle参数如果设置为True,则每次迭代前数据会被打乱,这对于训练是很有益的。
  • valid_dlbatch_size设置为bs * 2,这是因为验证集通常不需要参与训练,因此可以使用更大的批量来加快验证过程的速度。
封装数据加载器
def get_data(train_ds, valid_ds, bs):
return (
DataLoader(train_ds, batch_size=bs, shuffle=True),
DataLoader(valid_ds, batch_size=bs * 2),
)
  • 这个函数接受训练数据集、验证数据集以及批量大小作为参数,返回一个元组,包含了训练数据加载器和验证数据加载器。
  • 这种封装方式使得数据加载的配置更加灵活,便于在不同的训练配置中重用。
总结

通过TensorDatasetDataLoader,可以方便地管理数据的加载和预处理,特别是在模型训练和验证过程中。这种方式不仅简化了数据处理的代码,还提高了数据加载的效率和模型训练的性能。

get_model 函数

from torch import optim
def get_model():
    model = Mnist_NN()
    return model, optim.SGD(model.parameters(), lr=0.001)

此函数的作用是初始化一个模型实例及对应的优化器。具体过程如下:

  1. 实例化模型:这里假设已经定义了一个名为 Mnist_NN 的类,该类继承自 PyTorch 的 nn.Module,代表一个可以处理MNIST数据集的神经网络结构。
  2. 创建优化器:基于模型的所有可学习参数(model.parameters()),使用随机梯度下降(SGD)作为优化算法,设定初始学习率为 0.001。

最终返回的是模型实例和优化器对象。

损失函数 

def loss_batch(model, loss_func, xb, yb, opt=None):
    loss = loss_func(model(xb), yb)

    if opt is not None:
        loss.backward()
        opt.step()
        opt.zero_grad()

    return loss.item(), len(xb)

这个函数主要用于计算单个批次(batch)的数据在模型预测时的损失值,并在训练状态下更新模型参数。具体步骤如下:

  1. 计算损失:首先利用模型对输入数据 xb 进行前向传播得到预测结果,然后使用给定的损失函数 loss_func 来比较预测结果与真实标签 yb 的差距,从而获得损失值 loss
  2. 参数更新:如果提供了优化器 opt(即此函数是在训练过程中被调用),那么会进行梯度清零(opt.zero_grad())、反向传播(loss.backward())以及应用优化器更新规则(opt.step()),完成一次迭代。
  3. 返回结果:最后,函数返回该批次的损失值(转换为 Python 原生数值类型)和批大小。

这两个函数都是构建机器学习/深度学习模型训练流程的基础组件。其中,get_model 函数负责初始化模型和优化器;loss_batch 函数则是每次迭代的核心部分,用来计算损失并在必要时更新模型参数。

训练流程

一般在训练模型时加上model.train(),这样会正常使用Batch Normalization和 Dropout
- 测试的时候一般选择model.eval(),这样就不会使用Batch Normalization和 Dropout


import numpy as np

def fit(steps, model, loss_func, opt, train_dl, valid_dl):
    for step in range(steps):
        model.train()
        for xb, yb in train_dl:
            loss_batch(model, loss_func, xb, yb, opt)

        model.eval()
        with torch.no_grad():
            losses, nums = zip(
                *[loss_batch(model, loss_func, xb, yb) for xb, yb in valid_dl]
            )
        val_loss = np.sum(np.multiply(losses, nums)) / np.sum(nums)
        print('当前step:'+str(step), '验证集损失:'+str(val_loss))

实现一个简易的模型训练循环,通常在深度学习中用于训练神经网络模型。下面是对这段代码的详细中文解析:

import numpy as np

这一行导入了NumPy库,它是一个强大的数学计算库,常用于科学计算,特别是数组和矩阵运算。

def fit(steps, model, loss_func, opt, train_dl, valid_dl):

定义了一个名为fit的函数,这个函数接受以下参数:

  • steps: 训练的总步数,即整个训练集要遍历的次数(epoch数量);
  • model: 要训练的机器学习或深度学习模型;
  • loss_func: 损失函数,用于量化模型预测值与实际值之间的差距;
  • opt: 优化器,负责根据损失函数调整模型参数;
  • train_dl: 训练数据加载器,用于提供小批量(batch)的训练数据;
  • valid_dl: 验证数据加载器,用于评估模型在未见数据上的表现。
for step in range(steps):
...

接下来是一个主循环,按照指定的steps数量进行迭代。

model.train()

将模型设为训练模式,这是很重要的一步,因为在训练和验证/测试时,一些层的行为会不同,比如Batch Normalization和Dropout。

for xb, yb in train_dl:
loss_batch(model, loss_func, xb, yb, opt)

内部嵌套循环,遍历每个批次的数据(xb表示输入特征,yb表示对应的目标标签),并将它们传递给loss_batch函数执行单个批次的前向传播、计算损失、梯度下降等步骤。

model.eval()
with torch.no_grad():
...

将模型转换为评估模式,并开启无梯度计算上下文,防止在模型评估期间积累不必要的计算图,节省内存和提高速度。

losses, nums = zip(*[loss_batch(model, loss_func, xb, yb) for xb, yb in valid_dl])

这里用列表推导式对验证集的每一批数据计算损失,然后把所有这些损失和相应批次大小存入lossesnums元组中。

val_loss = np.sum(np.multiply(losses, nums)) / np.sum(nums)

计算平均验证损失,通过乘以每个批次的样本数再求和得到加权损失总和,最后除以总的样本数获得平均损失。

print('当前step:' + str(step)...)

打印当前轮次的信息,便于监控训练进程。

整体来看,实现了基本的监督学习训练流程,包括多个epoch的训练和验证阶段,是深度学习模型训练的一个常见模板。

4.总结主流程

### 三行搞定!

train_dl, valid_dl = get_data(train_ds, valid_ds, bs)
model, opt = get_model()
fit(25, model, loss_func, opt, train_dl, valid_dl)

汇总了一个典型深度学习模型训练流程的主要步骤,下面将对每一行进行详细解析:

1. train_dl, valid_dl = get_data(train_ds, valid_ds, bs)

这一行负责创建训练数据加载器 (train_dl) 和验证数据加载器 (valid_dl)。这里的 get_data 是一个自定义的函数,它接收三个参数:

  • train_ds: 训练数据集对象。
  • valid_ds: 验证数据集对象。
  • bs: batch size,即每次训练时使用的样本数量。

数据加载器 (DataLoader) 在PyTorch中是一个非常重要的组件,它可以从数据集中批量读取数据,并在多个数据点上执行mini-batch梯度下降。这不仅提高训练效率,还通过随机采样帮助避免过拟合。

2. model, opt = get_model()

在这一步骤中,get_model 函数被调用,返回模型对象 (model) 和优化器 (opt)。

  • model: 这是由 get_model 函数初始化并返回的具体神经网络模型。这个函数可能包含模型结构的定义和初始化权重的操作。

  • opt: 优化器对象,用于更新模型的参数。常见的优化器有SGD(随机梯度下降)、Adam等等,它们决定了如何根据计算得到的梯度调整模型的权重。

3. fit(25, model, loss_func, opt, train_dl, valid_dl)

最后这行代码调用了训练循环(fit函数),这是整个模型训练的核心部分。它接受以下参数:

  • 25: 迭代轮数或epoch数量,表示模型将在完整数据集上训练的次数。

  • model: 上面提到的模型对象,用于训练和评估。

  • loss_func: 损失函数,它是衡量模型预测值与真实标签之间差距的一种方式。常见类型有交叉熵损失、均方误差等。

  • opt: 之前创建的优化器,用于更新模型参数。

  • train_dl: 训练数据加载器,提供每一批次的数据供模型训练。

  • valid_dl: 验证数据加载器,用于在每个epoch结束时评估模型的泛化能力,而不改变模型的权重。

综上所述,这段代码实现了模型的定义、数据准备、模型训练和性能评估的基本流程。在实际应用中,get_data, get_modelfit 函数的具体实现可能会有所不同,但整体逻辑遵循上述框架。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值