全过程带你从入门到精通《动手学PyTorch深度学习建模与应用》第二章:2.1-2.3节详解,篇幅超了,缺的后面再补吧

写在前面:点点关注不迷路,免费的赞和收藏走起来!后续更新第一时间提示哦,每周会更新不同内容,下周更新如何用各种模态的大模型去为你服务,编写代码。


在深度学习的世界里,理解基础概念是构建复杂模型的关键。第二章“深度学习基础与PyTorch实现”将帮助我们深入理解深度学习的核心概念,并通过PyTorch实现这些概念。这一章的内容非常重要,因为它不仅涵盖了神经网络的基本原理,还介绍了激活函数、损失函数和优化算法等关键组件。接下来,我们将详细探讨2.1到2.3节的内容。

2.1 深度学习基础概念

深度学习是机器学习的一个分支,它通过构建多层神经网络来学习数据中的复杂模式。与传统的机器学习方法相比,深度学习模型能够自动提取数据的特征,而无需手动设计特征提取器。这使得深度学习在图像识别、自然语言处理等领域取得了巨大的成功。

2.1.1 神经网络的基本结构

神经网络由多个层组成,每一层由多个神经元组成。神经元是神经网络的基本单元,它接收输入信号,经过加权求和和非线性激活函数处理后,输出信号到下一层。最常见的神经网络结构包括:

  • 输入层:接收输入数据。

  • 隐藏层:提取数据的特征。

  • 输出层:生成最终的预测结果。

在PyTorch中,我们可以使用torch.nn模块来构建神经网络。例如,一个简单的两层神经网络可以定义如下:

import torch
import torch.nn as nn

class SimpleNet(nn.Module):
    def __init__(self):
        super(SimpleNet, self).__init__()
        self.fc1 = nn.Linear(10, 5)  # 输入层到隐藏层
        self.fc2 = nn.Linear(5, 2)   # 隐藏层到输出层

    def forward(self, x):
        x = torch.relu(self.fc1(x))  # 使用ReLU激活函数
        x = self.fc2(x)
        return x

# 创建网络实例
net = SimpleNet()
print(net)

2.1.2 深度学习的应用领域

深度学习在多个领域都有广泛的应用,包括但不限于:

  • 计算机视觉:图像分类、目标检测、图像分割等。

  • 自然语言处理:文本分类、机器翻译、情感分析等。

  • 语音识别:语音转文字、语音识别系统等。

  • 强化学习:机器人控制、游戏AI等。

这些应用领域展示了深度学习的强大能力和灵活性。


2.2.1 前向传播:从输入到输出的旅程

前向传播(Forward Propagation)是神经网络中输入数据从输入层经过隐藏层,最终到达输出层的过程。在这个过程中,每一层的神经元会对输入数据进行加权求和,然后通过激活函数引入非线性,最终生成输出。前向传播是神经网络预测的基础,也是训练过程中不可或缺的一部分。

前向传播的数学描述

假设我们有一个简单的两层神经网络,其结构如下:

  • 输入层大小:D(输入特征数)

  • 隐藏层大小:H

  • 输出层大小:C(类别数)

对于输入数据x,前向传播的过程可以描述为:

  1. 隐藏层的输出

    h=ReLU(W1​x+b1​)

    其中,W_1是输入层到隐藏层的权重矩阵,b_1是偏置项,ReLU是激活函数。

  2. 输出层的输出

    y=W2​h+b2​

    其中,W_2是隐藏层到输出层的权重矩阵,b_2是偏置项。

最终,y就是模型的预测输出。

使用PyTorch实现前向传播

在PyTorch中,我们可以使用torch.nn模块来定义神经网络的结构,并通过forward方法实现前向传播。以下是一个完整的代码示例:

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

# 定义一个简单的两层神经网络
class SimpleNet(nn.Module):
    def __init__(self, input_size, hidden_size, output_size):
        super(SimpleNet, self).__init__()
        # 定义网络层
        self.fc1 = nn.Linear(input_size, hidden_size)  # 输入层到隐藏层
        self.fc2 = nn.Linear(hidden_size, output_size)  # 隐藏层到输出层

    def forward(self, x):
        # 前向传播过程
        x = F.relu(self.fc1(x))  # 隐藏层输出,使用ReLU激活函数
        x = self.fc2(x)          # 输出层输出
        return x

# 初始化网络
input_size = 10  # 输入特征数
hidden_size = 5  # 隐藏层大小
output_size = 2  # 输出类别数

net = SimpleNet(input_size, hidden_size, output_size)
print("神经网络结构:")
print(net)

# 创建一个随机输入张量
inputs = torch.randn(1, input_size)  # 1个样本,10个特征
print("\n输入数据:")
print(inputs)

# 前向传播
outputs = net(inputs)
print("\n网络输出:")
print(outputs)

输出结果

运行上述代码后,你将看到类似以下的输出:

神经网络结构:
SimpleNet(
  (fc1): Linear(in_features=10, out_features=5, bias=True)
  (fc2): Linear(in_features=5, out_features=2, bias=True)
)

输入数据:
tensor([[ 0.1234, -0.5678,  0.9012, -0.3456,  0.7890, -0.1112,
          0.2223, -0.3334,  0.4445, -0.5556]])

网络输出:
tensor([[ 0.1234, -0.6789]], grad_fn=)

代码解析

  1. 网络定义

    • SimpleNet类继承自torch.nn.Module,并在__init__方法中定义了两层全连接层(fc1fc2)。

    • forward方法定义了输入数据如何通过这两层进行前向传播。F.relu是ReLU激活函数,用于引入非线性。

  2. 输入数据

    • 使用torch.randn生成一个随机输入张量,模拟一个包含10个特征的样本。

  3. 前向传播

    • 调用net(inputs)时,PyTorch会自动调用forward方法,完成从输入到输出的计算过程。

前向传播的可视化

为了更好地理解前向传播的过程,我们可以将其分解为以下步骤:

  1. 输入层到隐藏层

    • 计算加权求和:z1 = W1 * x + b1

    • 应用激活函数:h = ReLU(z1)

  2. 隐藏层到输出层

    • 计算加权求和:z2 = W2 * h + b2

    • 输出结果:y = z2

在PyTorch中,这些步骤被封装在forward方法中,使得代码更加简洁和易于维护。


2.2.2 反向传播:神经网络如何“学习”?

在深度学习中,反向传播(Backpropagation)是神经网络训练的核心机制。它通过计算损失函数关于模型参数的梯度,指导模型的优化方向。简单来说,反向传播就是神经网络的“学习”过程。

2.2.2.1、反向传播的直观理解

想象一个刚学算术的小学生,老师每天布置练习题,学生根据例题尝试解题,老师批改后指出错误。神经网络的学习过程与此相似:

  • 输入层:相当于练习题(如数字图片)。

  • 输出层:学生的答案(如识别数字是“3”)。

  • 损失函数:老师的批改(计算错误程度)。

  • 反向传播:学生根据错误调整计算步骤的过程。

2.2.2.2、反向传播的数学原理

反向传播的核心是利用链式法则计算梯度。假设我们有一个简单的两层神经网络,其前向传播过程如下:

  1. 隐藏层计算

    h=ReLU(W1​x+b1​)
  2. 输出层计算

    y=W2​h+b2​

在反向传播中,我们需要计算损失函数 L 关于每个参数的梯度。具体步骤如下:

  1. 计算输出层的梯度

    ∂W2​∂L​=∂y∂L​⋅∂W2​∂y​∂b2​∂L​=∂y∂L​⋅∂b2​∂y​
  2. 计算隐藏层的梯度

    ∂W1​∂L​=∂h∂L​⋅∂W1​∂h​∂b1​∂L​=∂h∂L​⋅∂b1​∂h​

通过这些梯度,我们可以使用优化算法(如SGD或Adam)更新模型参数。

2.2.2.3、PyTorch中的反向传播实现

在PyTorch中,反向传播的实现非常简洁。我们只需要调用backward()方法,PyTorch会自动计算梯度并存储在grad属性中。以下是一个完整的代码示例:

示例代码:反向传播

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

# 定义一个简单的两层神经网络
class SimpleNet(nn.Module):
    def __init__(self, input_size, hidden_size, output_size):
        super(SimpleNet, self).__init__()
        self.fc1 = nn.Linear(input_size, hidden_size)  # 输入层到隐藏层
        self.fc2 = nn.Linear(hidden_size, output_size)  # 隐藏层到输出层

    def forward(self, x):
        x = torch.relu(self.fc1(x))  # 隐藏层输出,使用ReLU激活函数
        x = self.fc2(x)             # 输出层输出
        return x

# 初始化网络
input_size = 10  # 输入特征数
hidden_size = 5  # 隐藏层大小
output_size = 2  # 输出类别数

net = SimpleNet(input_size, hidden_size, output_size)

# 定义损失函数和优化器
criterion = nn.MSELoss()  # 使用均方误差损失
optimizer = optim.SGD(net.parameters(), lr=0.01)  # 使用SGD优化器

# 创建模拟数据
inputs = torch.randn(1, input_size)  # 输入数据
targets = torch.randn(1, output_size)  # 真实标签

# 前向传播
outputs = net(inputs)
loss = criterion(outputs, targets)

# 反向传播
loss.backward()

# 更新参数
optimizer.step()

print("损失值:", loss.item())
print("更新后的权重:", net.fc1.weight.grad)

输出结果

运行上述代码后,你将看到类似以下的输出:

损失值: 0.1234
更新后的权重: tensor([[...]])


代码解析

  1. 网络定义

    • SimpleNet类继承自torch.nn.Module,并在__init__方法中定义了两层全连接层(fc1fc2)。

    • forward方法定义了输入数据如何通过这两层进行前向传播。

  2. 损失函数和优化器

    • 使用nn.MSELoss作为损失函数,optim.SGD作为优化器。

  3. 反向传播

    • 调用loss.backward()计算梯度。

    • 调用optimizer.step()更新模型参数。

2.2.2.4、优化学习效率的技巧

为了提高神经网络的训练效率,我们可以使用以下技巧:

  1. 学习率:学习率决定了参数更新的步长。如果学习率过大,可能会导致模型无法收敛;如果学习率过小,训练速度会很慢。常用的初始学习率是0.01。

  2. 动量:动量可以帮助模型更快地收敛,避免陷入局部最优。在PyTorch中,可以通过momentum参数在优化器中启用动量。

  3. 批量训练:批量训练可以提高训练的稳定性和效率。通过DataLoader,我们可以将数据分批加载到模型中。

2.2.2.5、核心公式总结

以下是反向传播的核心公式:

步骤 关键公式 类比
前向传播 a=σ(W⋅x+b) 做练习题
损失计算 L=21​∑(ytrue​−ypred​)2 计算错题数
反向传播 ∂W∂L​=∂a∂L​⋅∂z∂a​⋅∂W∂z​ 分析错误原因
参数更新 Wnew​=Wold​−η⋅∂W∂L​ 调整学习方法

2.2.2.6、总结

通过本节的讲解,我们详细介绍了反向传播的原理及其在PyTorch中的实现。反向传播是神经网络训练的核心机制,通过计算梯度并更新参数,模型能够不断优化自己的性能。


2.3 激活函数与损失函数

激活函数和损失函数是神经网络中的两个关键组件。激活函数用于引入非线性,使得神经网络能够学习复杂的模式;损失函数用于衡量模型的预测值与真实值之间的差异,指导模型的训练。

2.3.1 激活函数

激活函数是神经网络中每个神经元的输出函数。常见的激活函数包括:

  • ReLU(Rectified Linear Unit)f(x) = max(0, x),是最常用的激活函数之一,因为它简单且计算效率高。

  • Sigmoidf(x) = 1 / (1 + exp(-x)),输出范围在(0, 1)之间,常用于二分类任务。

  • Tanh(双曲正切函数)f(x) = tanh(x),输出范围在(-1, 1)之间,比Sigmoid函数更稳定。

  • Softmax:用于多分类任务,将输出转换为概率分布。

在PyTorch中,激活函数可以通过torch.nn.functional模块来使用。例如:

import torch.nn.functional as F

x = torch.tensor([-1.0, 2.0, -3.0])
y_relu = F.relu(x)
y_sigmoid = torch.sigmoid(x)
y_tanh = torch.tanh(x)
y_softmax = F.softmax(x, dim=0)

print("ReLU:", y_relu.numpy())
print("Sigmoid:", y_sigmoid.numpy())
print("Tanh:", y_tanh.numpy())
print("Softmax:", y_softmax.numpy())

2.3.2 损失函数

损失函数用于衡量模型的预测值与真实值之间的差异。常见的损失函数包括:

  • 均方误差损失(MSE):适用于回归任务,计算预测值与真实值之间的平方差的均值。

  • loss_fn = nn.MSELoss()

  • 交叉熵损失(CrossEntropyLoss):适用于分类任务,计算预测概率分布与真实标签之间的交叉熵。

  • loss_fn = nn.CrossEntropyLoss()
  • 负对数似然损失(NLLLoss):适用于分类任务,常与log_softmax结合使用。负对数似然损失(NLLLoss):适用于分类任务,常与log_softmax结合使用。

  • loss_fn = nn.NLLLoss()

你可能感兴趣的:(深度学习,pytorch,人工智能,python,机器学习)