文章目录
- 一、神经网络相关组件
- 0.前奏
- 1.全连接层(Fully Connected Layer, FC)/密集层(Dense Layer):
- 2.卷积层(Convolutional Layer, Conv):
- a.一维卷积
- b.二维卷积
- c.分组卷积
- 3.池化层(Pooling Layer):
- a.最大池化
- b.平均池化
- c.池化层较卷积层没有引入参数的原因
- 4.循环层(Recurrent Layer, RNN):
- a.基础RNN(Vanilla RNN):
- b.长短期记忆网络(LSTM):
- c.门控循环单元(GRU):
- 5.归一化层(Normalization Layer):
- a. 批量归一化(Batch Normalization)
- b. 层归一化(Layer Normalization)
- c. 实例归一化(Instance Normalization)
- d. 组归一化(Group Normalization)
- e.参数微调与归一化层
- 6.激活层(Activation Layer):
- 7.Dropout层:
- 8.嵌入层(Embedding Layer):
- 9.注意力层(Attention Layer):
- 二、神经网络经典架构
- 1.前馈神经网络(Feedforward Neural Networks, FNN):
- 2.卷积神经网络(Convolutional Neural Networks, CNN):
- 3.循环神经网络(Recurrent Neural Networks, RNN):
- 4.自编码器(Autoencoders):
- 变分自编码器(Variational Autoencoders, VAE):
- 5.生成对抗网络(Generative Adversarial Networks, GAN):
- 6.Transformer:
- 7.图神经网络(Graph Neural Networks, GNN):
- 8.深度强化学习(Deep Reinforcement Learning, DRL):
- 三、神经网络效率指标
- 1. 延迟(Latency)
- 2. 吞吐量(Throughput)
- 3. 能效
一、神经网络相关组件
0.前奏
在神经网络中,"宽度"和"深度"是描述模型结构的两个关键维度。
-
模型的宽度(Width)–隐藏层大小:
- 模型的宽度通常指的是单个层中神经元或节点的数量。
- 一个更宽的层意味着它有更多的神经元,能够捕捉更复杂的特征,但同时也可能增加计算成本和过拟合的风险。
- 例如,在全连接层中,宽度就是该层神经元的数量。
-
模型的深度(Depth)–隐藏层数量➕2:
- 模型的深度指的是网络中层的总数,包括输入层和输出层之间的所有隐藏层。
- 一个更深的网络意味着它有更多的层,能够学习更复杂的函数和抽象特征,但同时也可能增加梯度消失或梯度爆炸的问题。
- 例如,一个具有输入层、两个隐藏层和一个输出层的网络,其深度为4。
在设计神经网络时,宽度和深度都是需要仔细考虑的因素。增加宽度可以提高模型的表达能力,但可能会导致计算成本增加和过拟合;增加深度可以学习更复杂的特征,但也可能带来训练困难和性能下降的问题。通常,通过实验和经验来平衡宽度和深度,以达到最佳的模型性能。
1.全连接层(Fully Connected Layer, FC)/密集层(Dense Layer):
每个神经元与前一层的所有神经元相连,主要用于特征的线性组合。
import torch
import torch.nn as nn
# 定义一个简单的全连接层
class SimpleDenseLayer(nn.Module):
def __init__(self, input_size, output_size):
super(SimpleDenseLayer, self).__init__()
self.fc = nn.Linear(input_size, output_size)
def forward(self, x):
x = torch.relu(self.fc(x))
return x
# 创建一个实例
input_size = 20 # 输入特征的数量
output_size = 10 # 神经元的数量
dense_layer = SimpleDenseLayer(input_size, output_size)
# 创建一个虚拟输入数据来测试层
dummy_input = torch.randn(1, input_size) # 批量大小为1
output = dense_layer(dummy_input)
print(output)
2.卷积层(Convolutional Layer, Conv):
主要用于处理图像数据,通过卷积操作提取空间特征。
a.一维卷积
import torch
import torch.nn as nn
# 定义一维卷积层
conv1d = nn.Conv1d(in_channels=1, out_channels=16, kernel_size=3, stride=1, padding=1)
# 创建一个虚拟输入数据
input_data = torch.randn(1, 1, 20) # 批量大小为1,通道数为1,长度为20
# 前向传播
output = conv1d(input_data)
print(output.shape) # 输出形状torch.Size([1, 16, 20])
-
padding参数决定了在输入特征图的边缘周围添加多少层零值像素。这样做有两个主要目的:
保持特征图尺寸: 通过适当的padding,可以使得卷积操作后的输出特征图尺寸与输入特征图尺寸保持一致。这对于构建深层网络时保持特征图的尺寸非常有用。
边缘信息: 如果不使用padding,边缘的像素点在卷积操作中被使用的次数会比中心像素点少,这可能导致边缘信息的丢失。通过padding,可以确保边缘像素点也被充分使用。 -
stride参数决定了卷积核在输入特征图上移动的步长。默认情况下,stride=1意味着卷积核每次移动一个像素。增加stride值会减少输出特征图的尺寸,因为卷积核移动的步长增加了。
例如,如果stride=2,卷积核每次移动2个像素,这样输出特征图的尺寸会减半。 -
kernel_size=n:卷积核的尺寸为nxn。
b.二维卷积
import torch
import torch.nn as nn
# 定义二维卷积层
conv2d = nn.Conv2d(in_channels=3, out_channels=16, kernel_size=3, stride=1, padding=1)
# 创建一个虚拟输入数据
input_data = torch.randn(1, 3, 32, 32) # 批量大小为1,通道数为3,图像大小为32x32
# 前向传播
output = conv2d(input_data)
print(output.shape) # 输出形状torch.Size([1, 16, 32, 32])
- 输出尺寸的计算
输出特征图的尺寸可以通过以下公式计算:
对于二维卷积:
其中,input_size是输入特征图的尺寸,padding是边缘填充的层数,kernel_size是卷积核的尺寸,stride是卷积核移动的步长。
c.分组卷积
分组卷积(Grouped Convolution)将输入通道和输出通道分成多个组,每个组独立进行卷积操作。
import torch
import torch.nn as nn
# 定义一个分组卷积层
conv2d_grouped = nn.Conv2d(in_channels=16, out_channels=32, kernel_size=3, stride=1, padding=1, groups=4)
# 创建一个虚拟输入数据
input_data = torch.randn(1, 16, 32, 32) # 批量大小为1,通道数为16,图像大小为32x32
# 前向传播
output = conv2d_grouped(input_data)
print(output.shape) # 输出形状torch.Size([1, 32, 32, 32])
3.池化层(Pooling Layer):
通常跟在卷积层后面,用于降低特征维度和参数数量,提高计算效率,包括最大池化(Max Pooling)和平均池化(Average Pooling)等。
a.最大池化
import torch
import torch.nn as nn
# 定义一个最大池化层
maxpool = nn.MaxPool2d(kernel_size=2, stride=2)
# 创建一个虚拟输入数据
input_data = torch.randn(1, 16, 32, 32) # 批量大小为1,通道数为16,图像大小为32x32
# 前向传播
output = maxpool(input_data)
print(output.shape) # 输出形状torch.Size([1, 16, 16, 16])
b.平均池化
import torch
import torch.nn as nn
# 定义一个平均池化层
avgpool = nn.AvgPool2d(kernel_size=2, stride=2)
# 创建一个虚拟输入数据
input_data = torch.randn(1, 16, 32, 32) # 批量大小为1,通道数为16,图像大小为32x32
# 前向传播
output = avgpool(input_data)
print(output.shape) # 输出形状torch.Size([1, 16, 16, 16])
c.池化层较卷积层没有引入参数的原因
池化层之所以没有参数引入,是因为池化操作本身是一个固定的操作,不涉及可学习的参数。池化层的主要作用是减少特征图的尺寸,提取特征图中的主要信息(如最大值或平均值),而不需要学习权重。
卷积层有参数引入的原因
卷积层引入参数的原因是卷积操作涉及可学习的权重(即卷积核)。每个卷积核都是一个可学习的参数矩阵,用于从输入特征图中提取特征。卷积层的参数包括:
卷积核权重: 每个卷积核的权重矩阵。
偏置项: 每个输出通道可以有一个偏置项,用于调整输出特征图的值。
当你初始化一个卷积层的模型时,权重矩阵会被赋予初始值,而不是空值或零。这些参数在训练过程中通过反向传播算法进行优化,以提取输入数据中的有用特征。
4.循环层(Recurrent Layer, RNN):
适用于处理序列数据,如语音、文本等,单元间具有循环连接,可以捕获时间序列信息。
a.基础RNN(Vanilla RNN):
最简单的循环网络结构,但容易出现梯度消失和梯度爆炸的问题。
序列长度 表示每个样本的时间步数。在处理序列数据(如文本、时间序列等)时,每个样本通常由多个时间步组成。RNN通过在每个时间步接收输入并更新内部状态,能够捕捉序列中的时间依赖关系。因此,序列长度是RNN处理序列数据时的一个重要参数。
循环 体现在nn.RNN模块内部的计算过程中。具体来说,nn.RNN在每个时间步都会接收一个输入向量,并产生一个输出向量,同时更新其内部隐藏状态。这个隐藏状态在下一个时间步会被用作输入的一部分,从而形成了一个循环的结构。
import torch
import torch.nn as nn
# 定义输入数据
batch_size = 5 # 批次大小
sequence_length = 10 # 序列长度
input_size = 10 # 输入特征的大小
hidden_size = 20 # 隐藏层的大小
num_layers = 2 # RNN层的层数
# 随机生成输入数据
x = torch.randn(batch_size, sequence_length, input_size)
# 基础RNN
class VanillaRNN(nn.Module):
def __init__(self, input_size, hidden_size, num_layers):
super(VanillaRNN, self).__init__()
self.rnn = nn.RNN(input_size, hidden_size, num_layers, batch_first=True)
def forward(self, x):
output, h_n = self.rnn(x)
return output, h_n
model_rnn = VanillaRNN(input_size, hidden_size, num_layers)
output_rnn, h_n_rnn = model_rnn(x)
print("Output Shape:", output_rnn.shape) # 输出形状: [batch_size, sequence_length, hidden_size][5, 10, 20]
print("Hidden State Shape:", h_n_rnn.shape) # 隐藏状态形状: [num_layers, batch_size, hidden_size][2, 5, 20]
b.长短期记忆网络(LSTM):
引入了三个门(输入门、输出门、遗忘门)来控制信息的流动,有效解决了梯度消失问题,适合处理长序列数据。
import torch
import torch.nn as nn
# 定义输入数据
batch_size = 5 # 批次大小
sequence_length = 10 # 序列长度
input_size = 10 # 输入特征的大小
hidden_size = 20 # 隐藏层的大小
num_layers = 2 # RNN层的层数
# 随机生成输入数据
x = torch.randn(batch_size, sequence_length, input_size)
class LSTM(nn.Module):
def __init__(self, input_size, hidden_size, num_layers):
super(LSTM, self).__init__()
self.lstm = nn.LSTM(input_size, hidden_size, num_layers, batch_first=True)
def forward(self, x):
output, (h_n, c_n) = self.lstm(x)
return output, (h_n, c_n)
model_lstm = LSTM(input_size, hidden_size, num_layers)
output_lstm, (h_n_lstm, c_n_lstm) = model_lstm(x)
print("Output Shape:", output_lstm.shape) # 输出形状: [batch_size, sequence_length, hidden_size][5, 10, 20]
print("Hidden State Shape:", h_n_lstm.shape) # 隐藏状态形状: [num_layers, batch_size, hidden_size][2, 5, 20]
print("Cell State Shape:", c_n_lstm.shape) # 单元状态形状: [num_layers, batch_size, hidden_size][2, 5, 20]
c.门控循环单元(GRU):
简化版的LSTM,只有两个门(更新门和重置门),计算复杂度低,但效果与LSTM相似。
import torch
import torch.nn as nn
# 定义输入数据
batch_size = 5 # 批次大小
sequence_length = 10 # 序列长度
input_size = 10 # 输入特征的大小
hidden_size = 20 # 隐藏层的大小
num_layers = 2 # RNN层的层数
# 随机生成输入数据
x = torch.randn(batch_size, sequence_length, input_size)# GRU层
class GRU(nn.Module):
def __init__(self, input_size, hidden_size, num_layers):
super(GRU, self).__init__()
self.gru = nn.GRU(input_size, hidden_size, num_layers, batch_first=True)
def forward(self, x):
output, h_n = self.gru(x)
return output, h_n
model_gru = GRU(input_size, hidden_size, num_layers)
output_gru, h_n_gru = model_gru(x)
print("Output Shape:", output_gru.shape) # 输出形状: [batch_size, sequence_length, hidden_size][5, 10, 20]
print("Hidden State Shape:", h_n_gru.shape) # 隐藏状态形状: [num_layers, batch_size, hidden_size][2, 5, 20]
5.归一化层(Normalization Layer):
归一化层(Normalization Layer)在深度学习中用于提高模型的训练稳定性和加速收敛。
a. 批量归一化(Batch Normalization)
批量归一化是在每个小批量数据上进行归一化处理,使得网络的输入在训练过程中保持稳定的分布。
import torch
import torch.nn as nn
# 定义一个简单的卷积神经网络
class SimpleCNN(nn.Module):
def __init__(self):
super(SimpleCNN, self).__init__()
self.conv1 = nn.Conv2d(1, 16, kernel_size=3, stride=1, padding=1)
self.bn1 = nn.BatchNorm2d(16)
self.relu = nn.ReLU()
self.pool = nn.MaxPool2d(kernel_size=2, stride=2, padding=0)
self.conv2 = nn.Conv2d(16, 32, kernel_size=3, stride=1, padding=1)
self.bn2 = nn.BatchNorm2d(32)
self.fc = nn.Linear(32 * 7 * 7, 10)
def forward(self, x):
x = self.conv1(x)
x = self.bn1(x)
x = self.relu(x)
x = self.pool(x)
x = self.conv2(x)
x = self.bn2(x)
x = self.relu(x)
x = self.pool(x)
x = x.view(x.size(0), -1)
x = self.fc(x)
return x
# 创建模型实例
model = SimpleCNN()
print(model)
当你在定义模型时只写了一句 self.bn2 = nn.BatchNorm2d(32),实际上你只是创建了一个批量归一化层(Batch Normalization Layer),并指定了输入通道数为32。然而,当你打印模型时,PyTorch会显示这个层的详细配置信息,包括默认参数和一些额外的信息。
(bn2): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
- (bn2):这是你在模型中给这个层的命名。 BatchNorm2d:表示这是一个二维的批量归一化层。 32:表示输入通道数。
- eps=1e-05:这是批量归一化层的一个默认参数,用于防止除以零的情况。
- momentum=0.1:这是批量归一化层的一个默认参数,用于控制运行时均值和方差的更新速度。
- affine=True:表示这个层会学习两个参数(gamma和beta),用于在归一化之后对数据进行缩放和偏移。
- track_running_stats=True:表示这个层会跟踪运行时的均值和方差,并在推理阶段使用这些统计量。
b. 层归一化(Layer Normalization)
层归一化是对每个样本的所有特征进行归一化处理,不依赖于小批量数据的大小。
class SimpleLSTM(nn.Module):
def __init__(self, input_size, hidden_size, num_layers):
super(SimpleLSTM, self).__init__()
self.lstm = nn.LSTM(input_size, hidden_size, num_layers, batch_first=True)
self.ln = nn.LayerNorm(hidden_size)
self.fc = nn.Linear(hidden_size, 1)
def forward(self, x):
x, _ = self.lstm(x)
x = self.ln(x)
x = self.fc(x)
return x
# 创建模型实例
model = SimpleLSTM(input_size=10, hidden_size=20, num_layers=2)
print(model)
c. 实例归一化(Instance Normalization)
实例归一化是对每个样本的每个通道进行归一化处理,常用于风格迁移等任务。
class SimpleConvNet(nn.Module):
def __init__(self):
super(SimpleConvNet, self).__init__()
self.conv1 = nn.Conv2d(3, 16, kernel_size=3, stride=1, padding=1)
self.in1 = nn.InstanceNorm2d(16)
self.relu = nn.ReLU()
self.conv2 = nn.Conv2d(16, 32, kernel_size=3, stride=1, padding=1)
self.in2 = nn.InstanceNorm2d(32)
self.fc = nn.Linear(32 * 32 * 32, 10)
def forward(self, x):
x = self.conv1(x)
x = self.in1(x)
x = self.relu(x)
x = self.conv2(x)
x = self.in2(x)
x = self.relu(x)
x = x.view(x.size(0), -1)
x = self.fc(x)
return x
# 创建模型实例
model = SimpleConvNet()
print(model)
d. 组归一化(Group Normalization)
组归一化是将通道分成若干组,对每组内的通道进行归一化处理。
class SimpleConvNet(nn.Module):
def __init__(self):
super(SimpleConvNet, self).__init__()
self.conv1 = nn.Conv2d(3, 16, kernel_size=3, stride=1, padding=1)
self.gn1 = nn.GroupNorm(4, 16)
self.relu = nn.ReLU()
self.conv2 = nn.Conv2d(16, 32, kernel_size=3, stride=1, padding=1)
self.gn2 = nn.GroupNorm(8, 32)
self.fc = nn.Linear(32 * 32 * 32, 10)
def forward(self, x):
x = self.conv1(x)
x = self.gn1(x)
x = self.relu(x)
x = self.conv2(x)
x = self.gn2(x)
x = self.relu(x)
x = x.view(x.size(0), -1)
x = self.fc(x)
return x
# 创建模型实例
model = SimpleConvNet()
print(model)
e.参数微调与归一化层
在某些情况下,只调整归一化层的参数(如批量归一化的gamma
和beta
)可以有效地改善模型的性能。这是因为归一化层的参数直接影响了数据的分布,从而影响了模型的训练过程。通过微调这些参数,可以更好地适应数据的分布,提高模型的泛化能力。
例如,在迁移学习中,通常会冻结预训练模型的卷积层参数,只微调归一化层的参数,以适应新任务的数据分布。这是因为卷积层的参数已经在大规模数据集上训练过,而归一化层的参数需要根据新数据进行调整。
# 假设我们有一个预训练的模型
model = torchvision.models.resnet18(pretrained=True)
# 冻结所有卷积层参数
for param in model.parameters():
param.requires_grad = False
# 只微调归一化层的参数
for module in model.modules():
if isinstance(module, nn.BatchNorm2d):
for param in module.parameters():
param.requires_grad = True
# 继续训练模型
6.激活层(Activation Layer):
引入非线性因素,使神经网络可以学习复杂模式,常见激活函数有ReLU、Sigmoid、Tanh等。
(对硬件不友好的激活函数慎用)
import torch
import torch.nn as nn
class SimpleNN(nn.Module):
def __init__(self):
super(SimpleNN, self).__init__()
self.fc1 = nn.Linear(784, 128)
self.relu = nn.ReLU()
self.sigmoid = nn.Sigmoid()
self.tanh = nn.Tanh()
self.leaky_relu = nn.LeakyReLU()
self.elu = nn.ELU()
self.fc2 = nn.Linear(128, 10)
def forward(self, x):
x = self.fc1(x)
x = self.relu(x) # ReLU activation
# x = self.sigmoid(x) # Sigmoid activation
# x = self.tanh(x) # Tanh activation
# x = self.leaky_relu(x) # Leaky ReLU activation
# x = self.elu(x) # ELU activation
x = self.fc2(x)
return x
model = SimpleNN()
print(model)
7.Dropout层:
一种正则化技术,随机丢弃网络中的一些神经元,防止模型过拟合。Dropout 层在训练过程中随机地将其输入单元的一部分设置为0,这有助于使模型变得不依赖于任何一个特征,因而能够提高模型的泛化能力。
import torch
import torch.nn as nn
import torch.nn.functional as F
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.fc1 = nn.Linear(16, 32) # 输入层到隐藏层
self.dropout = nn.Dropout(0.5) # Dropout层,丢弃率设置为0.5
self.fc2 = nn.Linear(32, 2) # 隐藏层到输出层
def forward(self, x):
x = F.relu(self.fc1(x)) # 应用ReLU激活函数
x = self.dropout(x) # 应用Dropout
x = self.fc2(x) # 最后一层不使用激活函数
return x
# 实例化模型
model = Net()
print(model)
# 随机生成一些数据进行测试
x = torch.randn(1, 16) # 假设输入有16个特征
output = model(x)
print(output)
8.嵌入层(Embedding Layer):
嵌入层(Embedding Layer)在自然语言处理(NLP)任务中非常常见,它用于将单词的索引(通常是整数)转换为密集的向量表示。这种向量通常是通过学习得到的,可以捕捉单词之间的语义关系。
import torch
import torch.nn as nn
import torch.nn.functional as F
class SimpleTextClassifier(nn.Module):
def __init__(self, vocab_size, embedding_dim, num_classes):
super(SimpleTextClassifier, self).__init__()
self.embedding = nn.Embedding(vocab_size, embedding_dim) # 嵌入层
self.fc = nn.Linear(embedding_dim, num_classes) # 全连接层
def forward(self, x):
x = self.embedding(x) # 将输入的索引序列转换为嵌入向量
x = torch.mean(x, dim=1) # 对序列中的嵌入向量取平均
x = self.fc(x) # 通过全连接层输出分类结果
return x
# 参数设置
vocab_size = 1000 # 词汇表大小
embedding_dim = 30 # 嵌入向量的维度
num_classes = 4 # 分类的类别数
# 实例化模型
model = SimpleTextClassifier(vocab_size, embedding_dim, num_classes)
print(model)
# 随机生成一些数据进行测试
x = torch.randint(0, vocab_size, (64, 10)) # 64个样本,每个样本有10个单词索引
output = model(x)
print(output.shape) # 输出形状应为 (64, num_classes)
9.注意力层(Attention Layer):
通过学习输入序列的权重分布来提高模型的焦点,在序列到序列的模型、Transformer结构中特别有用。这个例子展示的是一个基本的加性注意力(Additive Attention),也被称为Bahdanau 注意力。
import torch
import torch.nn as nn
import torch.nn.functional as F
class AdditiveAttention(nn.Module):
def __init__(self, key_dim, query_dim, hidden_dim):
super(AdditiveAttention, self).__init__()
self.key_layer = nn.Linear(key_dim, hidden_dim)
self.query_layer = nn.Linear(query_dim, hidden_dim)
self.v = nn.Parameter(torch.rand(hidden_dim))
def forward(self, keys, query, mask=None):
# keys: [batch_size, seq_len, key_dim]
# query: [batch_size, query_dim]
# mask: [batch_size, seq_len]
# 对keys和query进行变换
keys_transformed = self.key_layer(keys) # [batch_size, seq_len, hidden_dim]
query_transformed = self.query_layer(query) # [batch_size, hidden_dim]
# 扩展query的维度以便可以添加到keys上
query_expanded = query_transformed.unsqueeze(1) # [batch_size, 1, hidden_dim]
# 计算加性注意力的分数
scores = torch.tanh(keys_transformed + query_expanded) # [batch_size, seq_len, hidden_dim]
scores = torch.matmul(scores, self.v) # [batch_size, seq_len]
if mask is not None:
scores = scores.masked_fill(mask == 0, -1e9) # 应用mask
# 应用softmax得到注意力权重
attention_weights = F.softmax(scores, dim=1)
# 应用注意力权重到keys上
weighted_sum = torch.bmm(attention_weights.unsqueeze(1), keys).squeeze(1)
return weighted_sum, attention_weights
# 假设的维度
key_dim = 64
query_dim = 64
hidden_dim = 32
# 示例
batch_size = 5
seq_len = 10
# 随机生成keys和query
keys = torch.randn(batch_size, seq_len, key_dim)
query = torch.randn(batch_size, query_dim)
mask = torch.ones(batch_size, seq_len) # 假设没有需要mask的
attention_layer = AdditiveAttention(key_dim, query_dim, hidden_dim)
weighted_sum, attention_weights = attention_layer(keys, query, mask)
print("Weighted sum shape:", weighted_sum.shape) # 应为 [batch_size, key_dim]
print("Attention weights shape:", attention_weights.shape) # 应为 [batch_size, seq_len]
二、神经网络经典架构
1.前馈神经网络(Feedforward Neural Networks, FNN):
最简单的神经网络形式,数据从输入层流向输出层,没有循环或反馈,包括多层感知器(MLP)等。
import numpy as np
# 定义激活函数
def sigmoid(x):
return 1 / (1 + np.exp(-x))
# 定义前馈神经网络类
class FeedForwardNN:
def __init__(self, input_size, hidden_size, output_size):
# 初始化权重和偏置
self.weights1 = np.random.randn(input_size, hidden_size)
self.bias1 = np.random.randn(hidden_size)
self.weights2 = np.random.randn(hidden_size, output_size)
self.bias2 = np.random.randn(output_size)
def forward(self, x):
# 第一层
self.hidden = sigmoid(np.dot(x, self.weights1) + self.bias1)
# 第二层
self.output = sigmoid(np.dot(self.hidden, self.weights2) + self.bias2)
return self.output
# 超参数
input_size = 3
hidden_size = 4
output_size = 2
# 实例化模型
model = FeedForwardNN(input_size, hidden_size, output_size)
# 打印模型参数
print("Weights1:", model.weights1)
print("Bias1:", model.bias1)
print("Weights2:", model.weights2)
print("Bias2:", model.bias2)
2.卷积神经网络(Convolutional Neural Networks, CNN):
主要用于图像和视频处理。
通过卷积层、池化层和全连接层提取和学习图像特征。
(AlexNet:层维度的计算;
VGG-16: 3*3卷积;
ResNet-50:三重分支结构;
MobileNetV2:分组数等于通道数)
import torch
import torch.nn as nn
# 定义 AlexNet 模型
class AlexNet(nn.Module):
def __init__(self, num_classes=1000):
super(AlexNet, self).__init__()
self.features = nn.Sequential(
nn.Conv2d(3, 64, kernel_size=11, stride=4, padding=2),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=3, stride=2),
nn.Conv2d(64, 192, kernel_size=5, padding=2),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=3, stride=2),
nn.Conv2d(192, 384, kernel_size=3, padding=1),
nn.ReLU(inplace=True),
nn.Conv2d(384, 256, kernel_size=3, padding=1),
nn.ReLU(inplace=True),
nn.Conv2d(256, 256, kernel_size=3, padding=1),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=3, stride=2),
)
self.avgpool = nn.AdaptiveAvgPool2d((6, 6))
self.classifier = nn.Sequential(
nn.Dropout(),
nn.Linear(256 * 6 * 6, 4096),
nn.ReLU(inplace=True),
nn.Dropout(),
nn.Linear(4096, 4096),
nn.ReLU(inplace=True),
nn.Linear(4096, num_classes),
)
def forward(self, x):
x = self.features(x)
x = self.avgpool(x)
x = torch.flatten(x, 1)
x = self.classifier(x)
return x
# 实例化模型
model = AlexNet()
# 打印模型结构
print(model)
3.循环神经网络(Recurrent Neural Networks, RNN):
适用于序列数据处理,如自然语言和时间序列,具有内部状态,可以处理变长序列。
import torch
import torch.nn as nn
# 定义一个简单的 RNN 模型
class SimpleRNN(nn.Module):
def __init__(self, input_size, hidden_size, output_size):
super(SimpleRNN, self).__init__()
self.hidden_size = hidden_size
self.rnn = nn.RNN(input_size, hidden_size, batch_first=True)
self.fc = nn.Linear(hidden_size, output_size)
def forward(self, x):
# 初始化隐藏状态
h0 = torch.zeros(1, x.size(0), self.hidden_size)
# 前向传播 RNN
out, _ = self.rnn(x, h0)
# 取最后一个时间步的输出
out = self.fc(out[:, -1, :])
return out
# 超参数
input_size = 10 # 输入特征的大小
hidden_size = 20 # 隐藏层的大小
output_size = 1 # 输出的大小
# 实例化模型
model = SimpleRNN(input_size, hidden_size, output_size)
# 打印模型结构
print(model)
4.自编码器(Autoencoders):
无监督学习模型,用于数据降维和特征学习,包括编码器和解码器两部分。
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader
# 定义自编码器模型
class Autoencoder(nn.Module):
def __init__(self):
super(Autoencoder, self).__init__()
# 编码器部分
self.encoder = nn.Sequential(
nn.Linear(28 * 28, 128),
nn.ReLU(True),
nn.Linear(128, 64),
nn.ReLU(True),
nn.Linear(64, 12),
nn.ReLU(True),
nn.Linear(12, 3) # 压缩到3维
)
# 解码器部分
self.decoder = nn.Sequential(
nn.Linear(3, 12),
nn.ReLU(True),
nn.Linear(12, 64),
nn.ReLU(True),
nn.Linear(64, 128),
nn.ReLU(True),
nn.Linear(128, 28 * 28),
nn.Tanh()
)
def forward(self, x):
x = self.encoder(x)
x = self.decoder(x)
return x
# 超参数
batch_size = 64
learning_rate = 0.001
num_epochs = 10
# 实例化模型、损失函数和优化器
model = Autoencoder()
criterion = nn.MSELoss()
optimizer = optim.Adam(model.parameters(), lr=learning_rate)
# 打印模型结构
print(model)
变分自编码器(Variational Autoencoders, VAE):
自编码器的扩展,用于生成模型和概率建模,可以生成新的数据样本。
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torchvision import datasets, transforms
from torch.utils.data import DataLoader
# 定义 VAE 模型
class VAE(nn.Module):
def __init__(self):
super(VAE, self).__init__()
# 编码器
self.fc1 = nn.Linear(784, 400)
self.fc21 = nn.Linear(400, 20) # 均值输出层
self.fc22 = nn.Linear(400, 20) # 对数方差输出层
# 解码器
self.fc3 = nn.Linear(20, 400)
self.fc4 = nn.Linear(400, 784)
def encode(self, x):
h1 = F.relu(self.fc1(x))
return self.fc21(h1), self.fc22(h1)
def reparameterize(self, mu, logvar):
std = torch.exp(0.5*logvar)
eps = torch.randn_like(std)
return mu + eps*std
def decode(self, z):
h3 = F.relu(self.fc3(z))
return torch.sigmoid(self.fc4(h3))
def forward(self, x):
mu, logvar = self.encode(x.view(-1, 784))
z = self.reparameterize(mu, logvar)
return self.decode(z), mu, logvar
# 实例化 VAE 模型、损失函数和优化器
model = VAE()
optimizer = optim.Adam(model.parameters(), lr=1e-3)
# 定义损失函数
def loss_function(recon_x, x, mu, logvar):
BCE = F.binary_cross_entropy(recon_x, x.view(-1, 784), reduction='sum')
KLD = -0.5 * torch.sum(1 + logvar - mu.pow(2) - logvar.exp())
return BCE + KLD
# 训练模型
def train(model, epoch, train_loader):
model.train()
train_loss = 0
for batch_idx, (data, _) in enumerate(train_loader):
optimizer.zero_grad()
recon_batch, mu, logvar = model(data)
loss = loss_function(recon_batch, data, mu, logvar)
loss.backward()
train_loss += loss.item()
optimizer.step()
if batch_idx % log_interval == 0:
print(f'Train Epoch: {epoch} [{batch_idx * len(data)}/{len(train_loader.dataset)}'
f' ({100. * batch_idx / len(train_loader):.0f}%)]\tLoss: {loss.item() / len(data):.6f}')
print(f'====> Epoch: {epoch} Average loss: {train_loss / len(train_loader.dataset):.4f}')
# 数据加载和变换
dataset = datasets.MNIST('./data', train=True, download=True, transform=transforms.ToTensor())
train_loader = DataLoader(dataset, batch_size=128, shuffle=True)
# 设置训练参数
epochs = 10
log_interval = 10 # 每隔多少批次打印一次信息
for epoch in range(1, epochs + 1):
train(model, epoch, train_loader)
# 打印模型结构
print(model)
5.生成对抗网络(Generative Adversarial Networks, GAN):
由生成器和判别器组成,通过对抗训练生成新数据,广泛用于图像生成、风格迁移等。
import torch
import torch.nn as nn
# 定义生成器模型
class Generator(nn.Module):
def __init__(self, input_dim, output_dim):
super(Generator, self).__init__()
self.model = nn.Sequential(
nn.Linear(input_dim, 128),
nn.ReLU(True),
nn.Linear(128, 256),
nn.ReLU(True),
nn.Linear(256, 512),
nn.ReLU(True),
nn.Linear(512, output_dim),
nn.Tanh()
)
def forward(self, x):
return self.model(x)
# 定义判别器模型
class Discriminator(nn.Module):
def __init__(self, input_dim):
super(Discriminator, self).__init__()
self.model = nn.Sequential(
nn.Linear(input_dim, 512),
nn.LeakyReLU(0.2, inplace=True),
nn.Linear(512, 256),
nn.LeakyReLU(0.2, inplace=True),
nn.Linear(256, 128),
nn.LeakyReLU(0.2, inplace=True),
nn.Linear(128, 1),
nn.Sigmoid()
)
def forward(self, x):
return self.model(x)
# 超参数
z_dim = 100 # 噪声向量的维度
image_dim = 28 * 28 # MNIST 图像的维度
# 实例化生成器和判别器
generator = Generator(input_dim=z_dim, output_dim=image_dim)
discriminator = Discriminator(input_dim=image_dim)
# 打印模型结构
print("Generator Model: \n", generator)
print("Discriminator Model: \n", discriminator)
6.Transformer:
基于自注意力机制的模型,适用于序列到序列的任务,在自然语言处理领域取得了巨大成功,如BERT、GPT等。(接触部分和生成部分;每个transformer包含一个多头注意力机制和两个全连接层;多查询注意力;组注意力)
import torch
import torch.nn as nn
# 定义 Transformer 模型
class TransformerModel(nn.Module):
def __init__(self, input_dim, model_dim, num_heads, num_layers, output_dim, dropout=0.1):
super(TransformerModel, self).__init__()
self.model_dim = model_dim
# 词嵌入层
self.embedding = nn.Embedding(input_dim, model_dim)
# 位置编码
self.pos_encoder = PositionalEncoding(model_dim, dropout)
# Transformer 编码器
encoder_layer = nn.TransformerEncoderLayer(d_model=model_dim, nhead=num_heads, dropout=dropout)
self.transformer_encoder = nn.TransformerEncoder(encoder_layer, num_layers=num_layers)
# 输出层
self.fc = nn.Linear(model_dim, output_dim)
def forward(self, src, src_mask=None):
# 词嵌入和位置编码
src = self.embedding(src) * torch.sqrt(torch.tensor(self.model_dim, dtype=torch.float32))
src = self.pos_encoder(src)
# 通过 Transformer 编码器
output = self.transformer_encoder(src, src_mask)
# 输出层
output = self.fc(output)
return output
# 位置编码
class PositionalEncoding(nn.Module):
def __init__(self, model_dim, dropout=0.1, max_len=5000):
super(PositionalEncoding, self).__init__()
self.dropout = nn.Dropout(p=dropout)
pe = torch.zeros(max_len, model_dim)
position = torch.arange(0, max_len, dtype=torch.float).unsqueeze(1)
div_term = torch.exp(torch.arange(0, model_dim, 2).float() * (-torch.log(torch.tensor(10000.0)) / model_dim))
pe[:, 0::2] = torch.sin(position * div_term)
pe[:, 1::2] = torch.cos(position * div_term)
pe = pe.unsqueeze(0).transpose(0, 1)
self.register_buffer('pe', pe)
def forward(self, x):
x = x + self.pe[:x.size(0), :]
return self.dropout(x)
# 超参数
input_dim = 10000 # 词汇表大小
model_dim = 512 # 模型维度
num_heads = 8 # 注意力头数
num_layers = 6 # 编码器层数
output_dim = 10000 # 输出维度
dropout = 0.1 # 丢弃率
# 实例化 Transformer 模型
transformer_model = TransformerModel(input_dim, model_dim, num_heads, num_layers, output_dim, dropout)
# 打印模型结构
print(transformer_model)
7.图神经网络(Graph Neural Networks, GNN):
用于处理图结构数据,如社交网络、分子结构等,可以学习节点、边和图级别的特征。
import torch
import torch.nn.functional as F
from torch_geometric.nn import GCNConv
from torch_geometric.data import Data
# 定义GCN模型
class GCN(torch.nn.Module):
def __init__(self, num_node_features, num_classes):
super(GCN, self).__init__()
self.conv1 = GCNConv(num_node_features, 16)
self.conv2 = GCNConv(16, num_classes)
def forward(self, data):
x, edge_index = data.x, data.edge_index
# 应用第一个图卷积层
x = self.conv1(x, edge_index)
x = F.relu(x)
x = F.dropout(x, training=self.training)
# 应用第二个图卷积层
x = self.conv2(x, edge_index)
return F.log_softmax(x, dim=1)
# 假设有一个图数据实例
num_node_features = 3 # 节点特征的维度
num_classes = 4 # 类别数
# 实例化模型
model = GCN(num_node_features=num_node_features, num_classes=num_classes)
# 打印模型结构
print(model)
8.深度强化学习(Deep Reinforcement Learning, DRL):
结合深度学习和强化学习,用于决策和控制问题,如AlphaGo等。
import gym
import torch
import torch.nn as nn
import torch.optim as optim
import torch.nn.functional as F
import random
from collections import deque
# 超参数
BATCH_SIZE = 64
GAMMA = 0.99
EPS_START = 0.9
EPS_END = 0.05
EPS_DECAY = 200
TARGET_UPDATE = 10
# 创建环境
env = gym.make('CartPole-v1')
n_actions = env.action_space.n
n_states = env.observation_space.shape[0]
# 定义神经网络
class DQN(nn.Module):
def __init__(self, n_states, n_actions):
super(DQN, self).__init__()
self.fc1 = nn.Linear(n_states, 128)
self.fc2 = nn.Linear(128, 128)
self.fc3 = nn.Linear(128, n_actions)
def forward(self, x):
x = F.relu(self.fc1(x))
x = F.relu(self.fc2(x))
return self.fc3(x)
# 初始化网络和目标网络
policy_net = DQN(n_states, n_actions)
target_net = DQN(n_states, n_actions)
target_net.load_state_dict(policy_net.state_dict())
target_net.eval()
# 优化器
optimizer = optim.Adam(policy_net.parameters())
# 经验回放缓冲区
memory = deque(maxlen=10000)
# 选择动作
def select_action(state, steps_done):
sample = random.random()
eps_threshold = EPS_END + (EPS_START - EPS_END) * \
math.exp(-1. * steps_done / EPS_DECAY)
if sample > eps_threshold:
with torch.no_grad():
return policy_net(state).max(1)[1].view(1, 1)
else:
return torch.tensor([[random.randrange(n_actions)]], dtype=torch.long)
# 优化模型
def optimize_model():
if len(memory) < BATCH_SIZE:
return
transitions = random.sample(memory, BATCH_SIZE)
batch = zip(*transitions)
state_batch = torch.cat(next(batch))
action_batch = torch.cat(next(batch))
reward_batch = torch.cat(next(batch))
next_state_batch = torch.cat([s for s in next(batch) if s is not None])
non_final_mask = torch.tensor(tuple(map(lambda s: s is not None, next(batch))), dtype=torch.bool)
state_action_values = policy_net(state_batch).gather(1, action_batch)
next_state_values = torch.zeros(BATCH_SIZE)
next_state_values[non_final_mask] = target_net(next_state_batch).max(1)[0].detach()
expected_state_action_values = (next_state_values * GAMMA) + reward_batch
loss = F.smooth_l1_loss(state_action_values, expected_state_action_values.unsqueeze(1))
optimizer.zero_grad()
loss.backward()
for param in policy_net.parameters():
param.grad.data.clamp_(-1, 1)
optimizer.step()
# 主循环
num_episodes = 50
for i_episode in range(num_episodes):
state = env.reset()
state = torch.tensor([state], dtype=torch.float32)
for t in range(1000):
action = select_action(state, i_episode)
next_state, reward, done, _ = env.step(action.item())
reward = torch.tensor([reward], dtype=torch.float32)
if done:
next_state = None
else:
next_state = torch.tensor([next_state], dtype=torch.float32)
memory.append((state, action, next_state, reward))
state = next_state
optimize_model()
if done:
print(f"Episode {i_episode} finished after {t+1} timesteps")
break
if i_episode % TARGET_UPDATE == 0:
target_net.load_state_dict(policy_net.state_dict())
env.close()
三、神经网络效率指标
1. 延迟(Latency)
延迟是指从输入数据到得到模型输出结果所需的时间。在神经网络中,这通常指的是单个输入(或一小批输入)通过整个网络所需的时间。延迟是评估模型实时性能的重要指标,尤其在对实时性要求高的应用中,如自动驾驶、在线视频处理等。
延迟的衡量指标包括:
- 单次推理时间:一个数据点通过神经网络所需的时间。
- 首次推理时间:模型从初始化到完成第一次推理的总时间,这通常包括模型加载、权重初始化等准备工作的时间。
- 平均推理时间:多次推理操作的平均时间,可以更准确地反映模型的实际运行效率。
2. 吞吐量(Throughput)
吞吐量是指单位时间内网络能够处理的数据量。对于批处理任务或数据中心等场景,吞吐量是一个至关重要的性能指标。
吞吐量的衡量指标通常有:
- 每秒处理的帧数(FPS,Frames Per Second):特别是在视频处理或游戏渲染中,FPS是一个常用的吞吐量衡量指标。
- 每秒处理的事务数(TPS,Transactions Per Second):在数据库和服务器应用中更常见。
- 批量处理速度:给定批量大小下,模型每秒可以处理多少批数据。
3. 能效
能效的提升通常涉及到减少内存访问、优化模型大小和计算复杂度等方面。以下是一些具体的能效优化策略和相关指标:
-
减少内存引用:在神经网络中,内存访问通常是能耗的主要来源之一。通过减少内存访问次数,可以显著提高能效。例如,使用更高效的内存访问模式或通过量化减少数据存储所需的位数。
-
模型大小:模型大小通常由模型参数的数量和每个参数的比特位数决定。较小的模型不仅占用更少的存储空间,而且通常在推理时消耗更少的能量。
-
平衡总体激活和峰值激活:在神经网络中,每一层的输入和输出(激活)都需要存储在内存中。优化这些激活的存储和访问模式可以减少能耗。例如,通过使用稀疏表示或激活函数来减少非零元素的数量。
-
MAC乘加运算:MAC(Multiply-Accumulate)操作是神经网络中最基本的计算操作。分析每一层的MAC操作数量可以帮助我们理解模型的计算复杂度,并据此优化能效。
-
Flops(浮点运算次数):Flops是衡量模型计算量的一个指标,通常等于MAC操作次数的一半(因为每个MAC操作包含一次乘法和一次加法)。Flops可以帮助我们评估模型在硬件上的执行效率。
-
Ops(运算次数):Ops是一个更通用的术语,用来描述模型执行的所有类型的运算次数,包括但不限于浮点运算。Ops可以用来衡量模型的整体计算复杂度。
在实际应用中,能效的优化需要综合考虑上述各个因素,通过模型压缩、量化、剪枝、知识蒸馏等技术手段来减少模型的大小和计算复杂度,同时保持或提升模型的性能。此外,选择合适的硬件平台和优化算法实现也是提高能效的关键。