2.3 常用层 (Common Layers)


文档摘要

2.3 常用层 (Common Layers) PyTorch 模型构建基石:常用层 (Common Layers) 详解与实践 在深度学习的广阔天地中,PyTorch 以其灵活性和强大的功能,成为了研究人员和工程师构建复杂模型的首选框架之一。模型构建的核心在于选择和组合各种神经网络层,而 常用层 (Common Layers) 正是构成这些模型的基石。掌握这些常用层的原理、应用以及在 PyTorch 中的实现,对于深入理解和有效构建神经网络模型至关重要。 2.3.1 线性层 (Linear Layer) 线性层,也称为全连接层 (Fully Connected Layer) 或 Dense 层,是神经网络中最基础且应用最广泛的层之一。

2.3 常用层 (Common Layers)

PyTorch 模型构建基石:常用层 (Common Layers) 详解与实践

在深度学习的广阔天地中,PyTorch 以其灵活性和强大的功能,成为了研究人员和工程师构建复杂模型的首选框架之一。模型构建的核心在于选择和组合各种神经网络层,而 常用层 (Common Layers) 正是构成这些模型的基石。掌握这些常用层的原理、应用以及在 PyTorch 中的实现,对于深入理解和有效构建神经网络模型至关重要。

2.3.1 线性层 (Linear Layer)

线性层,也称为全连接层 (Fully Connected Layer) 或 Dense 层,是神经网络中最基础且应用最广泛的层之一。其核心作用是对输入数据进行线性变换,实现特征的线性组合空间变换。在数学上,线性层可以表示为矩阵乘法和偏置项的加法:

\mathbf{y} = \mathbf{xW}^T + \mathbf{b}

其中:

  • \mathbf{x} 是输入向量。

  • \mathbf{W} 是权重矩阵,其维度决定了输入和输出特征空间的维度变换。

  • \mathbf{b} 是偏置向量,为每个输出特征提供一个可学习的偏移量。

  • \mathbf{y} 是输出向量。

线性层通过学习权重矩阵 \mathbf{W} 和偏置向量 \mathbf{b},能够将输入数据从一个特征空间映射到另一个特征空间。它在神经网络中扮演着至关重要的角色,常用于:

  • 特征提取的最后阶段: 将前面层提取的高级特征进行线性组合,最终用于分类或回归任务。

  • 不同维度空间之间的转换: 调整特征向量的维度,以适应后续层的输入要求。

  • 构建简单的线性模型: 单独使用线性层即可构建简单的线性回归或线性分类模型。

2.3.1.1 PyTorch 中的 nn.Linear

在 PyTorch 中,线性层通过 torch.nn.Linear 类实现。其构造函数接受三个主要参数:

  • in_features: 输入特征的维度。

  • out_features: 输出特征的维度。

  • bias: 布尔值,指示是否使用偏置项,默认为 True

代码实践:

import torch import torch.nn as nn # 定义一个输入维度为 10,输出维度为 5 的线性层 linear_layer = nn.Linear(in_features=10, out_features=5) # 创建一个随机输入张量 (batch_size, in_features) input_tensor = torch.randn(64, 10) # 通过线性层进行前向传播 output_tensor = linear_layer(input_tensor) # 打印输出张量的形状 print("Input Tensor Shape:", input_tensor.shape) print("Output Tensor Shape:", output_tensor.shape) # 查看线性层的权重和偏置参数 print("Linear Layer Weights:", linear_layer.weight.shape) # (out_features, in_features) print("Linear Layer Bias:", linear_layer.bias.shape) # (out_features)

代码详解:

  1. nn.Linear(in_features=10, out_features=5): 我们创建了一个线性层实例 linear_layer,指定输入特征维度为 10,输出特征维度为 5。PyTorch 会自动初始化权重矩阵 linear_layer.weight 的形状为 (5, 10),偏置向量 linear_layer.bias 的形状为 (5)

  2. torch.randn(64, 10): 我们创建了一个形状为 (64, 10) 的随机输入张量 input_tensor,其中 64 代表 batch size,10 代表输入特征维度。

  3. output_tensor = linear_layer(input_tensor): 将输入张量 input_tensor 传递给线性层 linear_layer 进行前向传播,得到输出张量 output_tensor

  4. 形状输出: 可以看到,输入张量的形状为 (64, 10),输出张量的形状为 (64, 5)。线性层将每个样本的特征维度从 10 变换到了 5。权重矩阵的形状为 (5, 10),偏置向量的形状为 (5),这与线性层的数学公式和 PyTorch 的实现一致。

Mermaid 图示:

2.3.2 卷积层 (Convolutional Layer)

卷积层 是深度学习中,特别是计算机视觉领域中至关重要的层。它通过卷积运算提取输入数据中的局部特征,并具有平移不变性的特性,使其能够有效地处理图像、语音等具有空间或时间结构的数据。

卷积运算的核心是卷积核 (Kernel)滤波器 (Filter)。卷积核是一个小的权重矩阵,它在输入数据上滑动 (convolve),并在每个位置执行元素乘积求和的操作。这个过程可以形象地理解为使用卷积核扫描输入数据,提取局部模式。

对于二维卷积 (2D Convolution),常用于图像处理,其运算过程可以描述如下:

  1. 定义卷积核: 选择一个大小为 k \times k 的卷积核,其中 k 通常为奇数,例如 3 或 5。

  2. 滑动窗口: 将卷积核在输入图像上滑动,从左上角开始,每次滑动一定的步长 (stride)。

  3. 卷积运算: 在每个滑动位置,将卷积核与输入图像对应区域进行元素乘积,并将所有乘积结果求和,得到输出特征图 (Feature Map) 的一个像素值。

  4. 重复操作: 重复步骤 2 和 3,直到卷积核滑遍整个输入图像,生成完整的输出特征图。

卷积层通常包含多个卷积核,每个卷积核可以学习到不同的局部特征。通过堆叠多个卷积层,网络可以逐步提取图像中越来越高级、抽象的特征,例如边缘、纹理、形状、物体部件等。

2.3.2.1 PyTorch 中的 nn.Conv2d

在 PyTorch 中,二维卷积层通过 torch.nn.Conv2d 类实现。其构造函数接受以下主要参数:

  • in_channels: 输入特征图的通道数。对于 RGB 图像,in_channels 为 3。

  • out_channels: 输出特征图的通道数,即卷积核的数量。

  • kernel_size: 卷积核的大小,可以是一个整数 (正方形卷积核) 或一个元组 (height, width)

  • stride: 卷积核滑动的步长,可以是一个整数或一个元组 (stride_height, stride_width),默认为 1。

  • padding: 输入图像边缘填充的层数,可以是整数或字符串 'valid' (不填充) 或 'same' (保持输出尺寸与输入尺寸相同,需要根据 kernel_sizestride 自动计算填充)。

  • bias: 布尔值,指示是否使用偏置项,默认为 True

代码实践:

import torch import torch.nn as nn # 定义一个卷积层:输入通道为 3,输出通道为 16,卷积核大小为 3x3,步长为 1,padding 为 1 conv_layer = nn.Conv2d(in_channels=3, out_channels=16, kernel_size=3, stride=1, padding=1) # 创建一个随机输入图像张量 (batch_size, channels, height, width) input_image = torch.randn(64, 3, 32, 32) # 假设输入图像大小为 32x32 # 通过卷积层进行前向传播 output_feature_map = conv_layer(input_image) # 打印输出特征图的形状 print("Input Image Shape:", input_image.shape) print("Output Feature Map Shape:", output_feature_map.shape) # 查看卷积层的权重和偏置参数 print("Conv Layer Weights:", conv_layer.weight.shape) # (out_channels, in_channels, kernel_height, kernel_width) print("Conv Layer Bias:", conv_layer.bias.shape) # (out_channels)

代码详解:

  1. nn.Conv2d(...): 我们创建了一个卷积层实例 conv_layer,配置了输入通道数、输出通道数、卷积核大小、步长和 padding 等参数。PyTorch 会自动初始化卷积核权重 conv_layer.weight 的形状为 (16, 3, 3, 3),偏置向量 conv_layer.bias 的形状为 (16)

  2. torch.randn(64, 3, 32, 32): 我们创建了一个形状为 (64, 3, 32, 32) 的随机输入图像张量 input_image,其中 64 是 batch size,3 是通道数 (RGB),32x32 是图像的高度和宽度。

  3. output_feature_map = conv_layer(input_image): 将输入图像张量 input_image 传递给卷积层 conv_layer 进行前向传播,得到输出特征图 output_feature_map

  4. 形状输出: 可以看到,输入图像的形状为 (64, 3, 32, 32),输出特征图的形状为 (64, 16, 32, 32)。由于我们设置了 padding=1stride=1,并且卷积核大小为 3x3,因此输出特征图的尺寸与输入图像尺寸保持一致 (32x32)。输出通道数变为 16,这是因为我们设置了 out_channels=16,卷积层使用了 16 个不同的卷积核来提取特征。权重矩阵的形状为 (16, 3, 3, 3),偏置向量的形状为 (16),符合卷积层的参数定义。

Mermaid 图示:

2.3.3 池化层 (Pooling Layer)

池化层,也称为汇聚层,通常紧跟在卷积层之后,用于降低特征图的空间分辨率 (减小尺寸) 和增强特征的平移不变性。池化操作在每个特征图上独立进行,它将输入特征图划分为一系列不重叠或重叠的区域 (通常是正方形),并对每个区域内的像素值进行聚合统计,例如取最大值 (Max Pooling) 或平均值 (Average Pooling)。

常见的池化操作包括:

  • 最大池化 (Max Pooling): 取每个池化窗口内的最大值作为输出。最大池化能够有效地保留区域内的最显著特征,并对小的平移和形变具有更强的鲁棒性。

  • 平均池化 (Average Pooling): 计算每个池化窗口内像素值的平均值作为输出。平均池化能够平滑特征图,降低噪声的影响,并提供区域内的平均特征

池化层的主要作用包括:

  • 降维 (Dimensionality Reduction): 减小特征图的尺寸,降低后续计算的复杂度,并减少模型参数数量,防止过拟合。

  • 平移不变性 (Translation Invariance): 通过聚合局部区域的特征,使得模型对于输入数据中目标位置的微小变化更加鲁棒。

  • 特征抽象 (Feature Abstraction): 池化操作可以提取更高层次的特征,例如从边缘特征到纹理特征,再到物体部件特征。

2.3.3.1 PyTorch 中的 nn.MaxPool2d

在 PyTorch 中,二维最大池化层通过 torch.nn.MaxPool2d 类实现。其构造函数接受以下主要参数:

  • kernel_size: 池化窗口的大小,可以是一个整数 (正方形窗口) 或一个元组 (height, width)

  • stride: 池化窗口滑动的步长,可以是一个整数或一个元组 (stride_height, stride_width),默认为 kernel_size

  • padding: 输入特征图边缘填充的层数,默认为 0。

代码实践:

import torch import torch.nn as nn # 定义一个最大池化层:池化窗口大小为 2x2,步长为 2 max_pool_layer = nn.MaxPool2d(kernel_size=2, stride=2) # 假设输入特征图是卷积层的输出 (batch_size, channels, height, width) input_feature_map = torch.randn(64, 16, 32, 32) # 通过最大池化层进行前向传播 output_feature_map_pooled = max_pool_layer(input_feature_map) # 打印输出特征图的形状 print("Input Feature Map Shape:", input_feature_map.shape) print("Output Pooled Feature Map Shape:", output_feature_map_pooled.shape)

代码详解:

  1. nn.MaxPool2d(kernel_size=2, stride=2): 我们创建了一个最大池化层实例 max_pool_layer,设置池化窗口大小为 2x2,步长为 2。这意味着池化窗口在特征图上以步长 2 滑动,且每个 2x2 区域内只保留最大值。

  2. torch.randn(64, 16, 32, 32): 我们假设输入特征图 input_feature_map 是卷积层的输出,形状为 (64, 16, 32, 32)

  3. output_feature_map_pooled = max_pool_layer(input_feature_map): 将输入特征图传递给最大池化层 max_pool_layer 进行前向传播,得到池化后的输出特征图 output_feature_map_pooled

  4. 形状输出: 可以看到,输入特征图的形状为 (64, 16, 32, 32),输出池化特征图的形状为 (64, 16, 16, 16)。由于池化窗口大小为 2x2,步长为 2,因此特征图的高度和宽度都缩小了一半 (从 32 变为 16),通道数保持不变。

Mermaid 图示:

2.3.4 循环层 (Recurrent Layer)

循环层,也称为循环神经网络 (Recurrent Neural Network, RNN),专门用于处理序列数据,例如文本、语音、时间序列等。与前馈神经网络不同,循环层具有记忆能力,它可以将之前的输入信息传递到当前时刻,从而捕捉序列数据中的时序依赖关系。

RNN 的核心思想是在网络中引入循环连接,使得网络在处理序列的每个元素时,不仅考虑当前的输入,还考虑之前的状态信息。最基础的 RNN 结构可以表示为:

\begin{aligned} \mathbf{h}_t &= f(\mathbf{W}_{ih}\mathbf{x}_t + \mathbf{W}_{hh}\mathbf{h}_{t-1} + \mathbf{b}_h) \\ \mathbf{y}_t &= g(\mathbf{W}_{ho}\mathbf{h}_t + \mathbf{b}_o) \end{aligned}

其中:

  • \mathbf{x}_t 是时刻 t 的输入向量。

  • \mathbf{h}_t 是时刻 t 的隐藏状态向量,它存储了网络在时刻 t 的记忆信息。

  • \mathbf{h}_{t-1} 是上一时刻 t-1 的隐藏状态向量,RNN 通过循环连接将上一时刻的状态传递到当前时刻。

  • \mathbf{y}_t 是时刻 t 的输出向量。

  • \mathbf{W}_{ih}\mathbf{W}_{hh}\mathbf{W}_{ho} 是权重矩阵。

  • \mathbf{b}_h\mathbf{b}_o 是偏置向量。

  • fg 是激活函数,通常使用 tanh 或 ReLU 等。

然而,基础 RNN 在处理长序列时容易出现梯度消失梯度爆炸问题,导致难以学习长距离依赖关系。为了解决这个问题,出现了更高级的循环层结构,例如 长短期记忆网络 (Long Short-Term Memory, LSTM)门控循环单元 (Gated Recurrent Unit, GRU)

LSTM 通过引入门控机制 (输入门、遗忘门、输出门和细胞状态) 来更有效地控制信息的流动和长期记忆的存储,从而克服了梯度消失问题,在处理长序列数据上表现出色。

2.3.4.1 PyTorch 中的 nn.LSTM

在 PyTorch 中,LSTM 层通过 torch.nn.LSTM 类实现。其构造函数接受以下主要参数:

  • input_size: 输入特征的维度。

  • hidden_size: 隐藏状态的维度,也决定了 LSTM 单元的记忆容量。

  • num_layers: LSTM 层的层数,可以堆叠多层 LSTM。

  • batch_first: 布尔值,如果为 True,则输入张量的第一个维度为 batch size,否则第二个维度为 batch size,默认为 False (即时间步维度在第一个维度)。

  • bidirectional: 布尔值,如果为 True,则使用双向 LSTM,可以同时考虑序列的前向和后向信息。

代码实践:

import torch import torch.nn as nn # 定义一个 LSTM 层:输入特征维度为 20,隐藏状态维度为 50,单层 LSTM lstm_layer = nn.LSTM(input_size=20, hidden_size=50, num_layers=1) # 创建一个随机输入序列张量 (seq_len, batch_size, input_size) input_sequence = torch.randn(30, 64, 20) # 假设序列长度为 30,batch size 为 64 # 初始化 LSTM 的隐藏状态和细胞状态 (h_0, c_0) # 形状为 (num_layers * num_directions, batch_size, hidden_size) h0 = torch.randn(1, 64, 50) # 单层单向 LSTM, num_directions=1 c0 = torch.randn(1, 64, 50) # 通过 LSTM 层进行前向传播 output_sequence, (hn, cn) = lstm_layer(input_sequence, (h0, c0)) # 打印输出序列和最终隐藏状态的形状 print("Input Sequence Shape:", input_sequence.shape) print("Output Sequence Shape:", output_sequence.shape) # (seq_len, batch_size, num_directions * hidden_size) print("Final Hidden State Shape (hn):", hn.shape) # (num_layers * num_directions, batch_size, hidden_size) print("Final Cell State Shape (cn):", cn.shape) # (num_layers * num_directions, batch_size, hidden_size)

代码详解:

  1. nn.LSTM(input_size=20, hidden_size=50, num_layers=1): 我们创建了一个单层 LSTM 层实例 lstm_layer,输入特征维度为 20,隐藏状态维度为 50。

  2. torch.randn(30, 64, 20): 我们创建了一个形状为 (30, 64, 20) 的随机输入序列张量 input_sequence,其中 30 是序列长度 (seq_len),64 是 batch size,20 是输入特征维度 (input_size)。

  3. h0 = torch.randn(1, 64, 50), c0 = torch.randn(1, 64, 50): 我们初始化了 LSTM 的初始隐藏状态 h0 和初始细胞状态 c0。对于单层单向 LSTM,它们的形状都为 (1, 64, 50),分别代表 (num_layers * num_directions, batch_size, hidden_size)。如果未显式提供初始状态,LSTM 会默认使用零初始化。

  4. output_sequence, (hn, cn) = lstm_layer(input_sequence, (h0, c0)): 将输入序列 input_sequence 和初始状态 (h0, c0) 传递给 LSTM 层 lstm_layer 进行前向传播,得到输出序列 output_sequence 和最终的隐藏状态 hn 及细胞状态 cn

  5. 形状输出: 可以看到,输入序列的形状为 (30, 64, 20),输出序列的形状为 (30, 64, 50)。输出序列包含了每个时间步的 LSTM 输出,其维度为 (seq_len, batch_size, num_directions * hidden_size)。最终的隐藏状态 hn 和细胞状态 cn 的形状都为 (1, 64, 50),它们代表了整个序列处理完毕后 LSTM 的最终状态。

Mermaid 图示 (简化版,仅展示单时间步 LSTM):

2.3.5 嵌入层 (Embedding Layer)

嵌入层 (Embedding Layer) 用于将离散的符号 (例如单词、ID、类别标签等) 转换为连续的低维向量,也称为词向量或嵌入向量。嵌入层在自然语言处理 (NLP) 和推荐系统等领域中广泛应用。

在处理文本数据时,通常需要将文本中的单词转换为数值表示,以便输入到神经网络中。One-hot 编码是一种常见的表示方法,但它会产生高维稀疏的向量,难以捕捉单词之间的语义关系。嵌入层则能够学习到单词的分布式表示,将每个单词映射到一个低维稠密的向量空间中,使得语义相似的单词在向量空间中也彼此靠近。

嵌入层本质上是一个查找表 (Lookup Table)。它维护一个嵌入矩阵,矩阵的每一行对应一个符号的嵌入向量。当输入一个符号的索引时,嵌入层会根据索引在嵌入矩阵中查找对应的行向量,并将其作为输出。

2.3.5.1 PyTorch 中的 nn.Embedding

在 PyTorch 中,嵌入层通过 torch.nn.Embedding 类实现。其构造函数接受以下主要参数:

  • num_embeddings: 嵌入词汇表的大小,即不同符号的总数。

  • embedding_dim: 每个嵌入向量的维度,即低维空间的维度。

  • padding_idx: 可选参数,指定一个 padding 索引,该索引的嵌入向量在训练过程中保持固定为零向量。

代码实践:

import torch import torch.nn as nn # 定义一个嵌入层:词汇表大小为 10000,嵌入维度为 100 embedding_layer = nn.Embedding(num_embeddings=10000, embedding_dim=100) # 创建一个符号索引的张量 (batch_size, seq_len) input_indices = torch.randint(0, 10000, (64, 50)) # 假设 batch_size 为 64,序列长度为 50 # 通过嵌入层进行前向传播 output_embeddings = embedding_layer(input_indices) # 打印输出嵌入向量的形状 print("Input Indices Shape:", input_indices.shape) print("Output Embeddings Shape:", output_embeddings.shape) # (batch_size, seq_len, embedding_dim) # 查看嵌入层的嵌入矩阵 print("Embedding Matrix Shape:", embedding_layer.weight.shape) # (num_embeddings, embedding_dim)

代码详解:

  1. nn.Embedding(num_embeddings=10000, embedding_dim=100): 我们创建了一个嵌入层实例 embedding_layer,词汇表大小为 10000,嵌入维度为 100。PyTorch 会自动初始化嵌入矩阵 embedding_layer.weight 的形状为 (10000, 100)

  2. torch.randint(0, 10000, (64, 50)): 我们创建了一个形状为 (64, 50) 的随机整数张量 input_indices,作为输入符号的索引。索引的取值范围在 [0, 10000) 之间,模拟词汇表中的单词索引。

  3. output_embeddings = embedding_layer(input_indices): 将输入索引 input_indices 传递给嵌入层 embedding_layer 进行前向传播,得到输出嵌入向量 output_embeddings

  4. 形状输出: 可以看到,输入索引的形状为 (64, 50),输出嵌入向量的形状为 (64, 50, 100)。嵌入层将每个索引转换为一个 100 维的嵌入向量,因此输出张量的维度增加了一维,变为 embedding_dim。嵌入矩阵的形状为 (10000, 100),与我们定义的词汇表大小和嵌入维度一致。

Mermaid 图示:

2.3.6 激活函数 (Activation Function)

激活函数 (Activation Function) 在神经网络中扮演着至关重要的角色。它们被应用于神经网络的输出,引入非线性,使得神经网络能够学习和逼近复杂的非线性函数。如果没有激活函数,无论神经网络有多少层,都只能进行线性变换,表达能力将受到限制。

常用的激活函数包括:

  • ReLU (Rectified Linear Unit): f(x) = \max(0, x)。ReLU 是目前最常用的激活函数之一,其优点是计算简单、收敛速度快,并且在正区间内梯度为常数,有助于缓解梯度消失问题。但 ReLU 在负区间内梯度为 0,可能导致神经元 "死亡"。

  • Sigmoid: f(x) = \frac{1}{1 + e^{-x}}。Sigmoid 函数将输入值压缩到 (0, 1) 之间,常用于二分类问题的输出层,表示概率值。但 Sigmoid 函数在输入值较大或较小时容易出现梯度饱和,导致梯度消失。

  • Tanh (Hyperbolic Tangent): f(x) = \tanh(x) = \frac{e^x - e^{-x}}{e^x + e^{-x}}。Tanh 函数将输入值压缩到 (-1, 1) 之间,与 Sigmoid 函数类似,也容易出现梯度饱和问题。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U