为了进一步探索不同网络结构在WISDM数据集上的表现,本文将继续深入研究,将训练模型推广到其他网络结构中,包括ResNet、LSTM和ShuffleNet,并通过仿真实验对比这些网络在WISDM数据集上的训练效果。
残差网络(ResNet)通过引入“残差学习”的概念,解决了深度神经网络训练困难的问题。其核心思想是通过残差块(Residual Block)将输入直接与输出相加,从而缓解梯度消失问题,使得网络可以训练得更深。
ResNet沿用了VGG完整的3 × 3卷积层设计。残差块里首先有2个有相同输出通道数的3 × 3卷积层。 每个卷积层后接一个批量规范化层和ReLU激活函数。 然后我们通过跨层数据通路,跳过这2个卷积运算,将输入直接加在最后的ReLU激活函数前。
核心思想:
· 残差块(Residual Block) :输入通过一个或多个卷积层后,与输入相加,形成残差。这样做可以使得网络学习到的是输入和输出之间的残差,而不是直接学习输出,从而缓解了梯度消失问题,使得网络可以成功训练更深的模型。
优点:
· 通过残差学习,可以有效地训练更深的网络,提高了模型的性能。
· 网络结构易于拓展,可以构建更复杂的模型。
缺点:
· 虽然缓解了梯度消失问题,但在某些情况下仍然可能遇到梯度爆炸的问题。
· 模型参数较多,需要较大的数据集进行训练。
网络结构:
ResNet(
(layer1): Sequential(
(0): Block(
(block): Sequential(
(0): Conv2d(1, 64, kernel_size=(3, 1), stride=(2, 1), padding=(1, 0))
(1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(2): ReLU()
(3): Conv2d(64, 64, kernel_size=(1, 1), stride=(1, 1))
(4): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
)
(short): Sequential(
(0): Conv2d(1, 64, kernel_size=(3, 1), stride=(2, 1), padding=(1, 0))
(1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
)
LSTM是一种特殊的循环神经网络(RNN),通过引入门控机制(输入门、遗忘门和输出门)和记忆单元,能够学习长期依赖信息,特别适合处理时间序列数据。
核心思想:
· 门控机制(Gating Mechanism) :LSTM通过引入输入门、遗忘门和输出门来控制信息的流动,解决了传统RNN的短期记忆问题。
· 记忆单元(Memory Cell) :LSTM的核心是记忆单元,它可以添加或移除信息,从而实现长期记忆。
优点:
· 能够处理长期依赖问题,适用于时间序列数据。
· 通过门控机制,可以有效地避免梯度消失和梯度爆炸问题。
缺点:
· 参数数量较多,训练时间较长。
· 门控机制增加了模型的复杂度。
网络结构:
LSTM(
(lstm): LSTM(3, 512, num_layers=2, batch_first=True)
(fc): Linear(in_features=512, out_features=6, bias=True)
)
ShuffleNet是一种高效的卷积神经网络,通过分组卷积和通道洗牌操作减少计算量,同时保持较高的准确率。
核心思想:
· 分组卷积:将输入通道分成多个组,每组独立进行卷积操作,然后合并结果。这样可以减少计算量和参数数量。
· 通道洗牌:在分组卷积后,通过通道洗牌操作重新混合不同组的特征图,以保持特征的多样性。
优点:
· 计算效率高,适用于资源受限的环境。
· 通过通道洗牌操作,可以在减少计算量的同时保持特征的多样性。
缺点:
· 虽然减少了计算量,但在某些复杂任务上可能不如其他网络结构表现出色。
· 分组卷积可能会牺牲一定的模型性能。
网络结构:
ShuffleNet(
(layer): Sequential(
(0): Conv2d(1, 1, kernel_size=(3, 1), stride=(2, 1), padding=(1, 0))
(1): Conv2d(1, 64, kernel_size=(1, 1), stride=(1, 1))
(2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(3): ReLU()
(19): ChannelShuffleModule()
)
(ada_pool): AdaptiveAvgPool2d(output_size=(1, 3))
(fc): Linear(in_features=1536, out_features=6, bias=True)
)
CNN是一种深度学习模型,主要用于处理具有网格结构的数据,如图像和时间序列数据。其核心思想是利用卷积层(Convolutional Layer)提取局部特征,然后通过池化层(Pooling Layer)进行下采样以减少特征维度,最后通过全连接层(Fully Connected Layer)进行分类或回归。
CNN的典型结构包括多个卷积层、池化层和全连接层。以下是一个简单的CNN结构示例:
import torch.nn as nn
class CNN(nn.Module):
def __init__(self, input_channels, num_classes):
super(CNN, self).__init__()
self.conv1 = nn.Conv2d(in_channels=input_channels, out_channels=32, kernel_size=3, stride=1, padding=1)
self.relu = nn.ReLU()
self.pool = nn.MaxPool2d(kernel_size=2, stride=2)
self.conv2 = nn.Conv2d(in_channels=32, out_channels=64, kernel_size=3, stride=1, padding=1)
self.fc1 = nn.Linear(64 * 7 * 7, 128) # 假设输入图像大小为28x28
self.fc2 = nn.Linear(128, num_classes)
def forward(self, x):
x = self.conv1(x)
x = self.relu(x)
x = self.pool(x)
x = self.conv2(x)
x = self.relu(x)
x = self.pool(x)
x = x.view(x.size(0), -1) # 展平特征
x = self.fc1(x)
x = self.relu(x)
x = self.fc2(x)
return x
Block
类是一个残差网络的基本构建块,它包含两个卷积层,分别后接批量归一化(BatchNorm)和ReLU激活函数。(stride, 1)
,填充为 (1, 0)
。class Block(nn.Module):
def __init__(self, inchannel, outchannel, stride):
super().__init__()
self.block = nn.Sequential(
nn.Conv2d(inchannel, outchannel, (3, 1), (stride, 1), (1, 0)),
nn.BatchNorm2d(outchannel),
nn.ReLU(),
nn.Conv2d(outchannel, outchannel, 1, 1, 0),
nn.BatchNorm2d(outchannel)
)
self.short = nn.Sequential()
if (inchannel != outchannel or stride != 1):
self.short = nn.Sequential(
nn.Conv2d(inchannel, outchannel, (3, 1), (stride, 1), (1, 0)),
nn.BatchNorm2d(outchannel)
)
ResNet
类定义了整个网络结构,它由四个残差层(layer1
到 layer4
)组成,每一层由多个残差块组成。[b, c, series, modal]
,其中 b
是批次大小,c
是通道数,series
是序列长度,modal
是模态数(例如,图像的高度)。AdaptiveAvgPool2d
)将特征图的大小调整为 (1, train_shape[-1])
,然后通过一个全连接层(fc
)输出类别预测。class ResNet(nn.Module):
def __init__(self, train_shape, category):
super().__init__()
self.layer1 = self.make_layers(1, 64, 2, 1)
self.layer2 = self.make_layers(64, 128, 2, 1)
self.layer3 = self.make_layers(128, 256, 2, 1)
self.layer4 = self.make_layers(256, 512, 2, 1)
self.ada_pool = nn.AdaptiveAvgPool2d((1, train_shape[-1]))
self.fc = nn.Linear(512*train_shape[-1], category)
make_layers
方法用于创建每个残差层中的多个残差块。它接受输入通道数、输出通道数、步长和块的数量作为参数,并返回一个由这些块组成的序列。def make_layers(self, inchannel, outchannel, stride, blocks):
layer = [Block(inchannel, outchannel, stride)]
for i in range(1, blocks):
layer.append(Block(outchannel, outchannel, 1))
return nn.Sequential(*layer)
forward
方法中,输入数据 x
会逐层通过残差层,然后通过自适应平均池化层和全连接层,最终输出类别预测。def forward(self, x):
out = self.block(x) + self.short(x)
return nn.ReLU()(out)
从训练得到的结果我们可以发现在准确率(Accuracy)、精确率(Precision)、召回率(Recall)、F1分数(F1-score)、参数量(Parameters)、推理时间(Inference Time) 六个维度上分别为:
LSTM网络特别适合于处理和预测时间序列数据,因为它们可以捕捉长期依赖关系,在本次实验中可以发挥出其特点,我们首先使用用LSTM层来处理序列数据,然后使用全连接层来进行分类预测。通过选取序列最后一个时间步的隐藏状态来进行分类,这是处理序列数据的一个常见做法,尤其是当序列长度固定时。
我们使用LSTM
类继承自 nn.Module
,构造函数 __init__
接受两个参数:train_shape
和 category
。
train_shape
是训练数据的形状,这里假设它是一个包含序列长度和模态数的列表或元组。category
是类别的数量,即网络输出的维度,用于分类任务。class LSTM(nn.Module):
def __init__(self, train_shape, category):
super().__init__()
self.lstm = nn.LSTM(train_shape[-1], 512, 2, batch_first=True)
self.fc = nn.Linear(512, category)
其中self.lstm
是LSTM层,其参数如下:
train_shape[-1]
是输入特征的维度,即模态数。512
是LSTM隐藏层的维度。2
表示堆叠两个LSTM层。batch_first=True
表示输入和输出的张量的第一个维度是批次大小(batch size)。self.fc
是一个全连接层,它将LSTM层的输出映射到类别空间。它的输入维度是512(LSTM隐藏层的维度),输出维度是 category
。
forward
方法定义了数据通过网络的正向传播过程。输入 x
的形状假设为 [b, c, series, modal]
,其中 b
是批次大小,c
是通道数(在这里为1,因为 squeeze(1)
被调用)。
x.squeeze(1)
将通道数维度移除,使得 x
的形状变为 [b, series, modal]
。self.lstm(x)
将数据 x
通过LSTM层,输出一个包含隐藏状态和细胞状态的元组。
def forward(self, x):
x, _ = self.lstm(x.squeeze(1))
x = x[:, -1, :]
x = self.fc(x)
return x
从训练得到的结果我们可以发现在准确率(Accuracy)、精确率(Precision)、召回率(Recall)、F1分数(F1-score)、参数量(Parameters)、推理时间(Inference Time) 六个维度上分别为:
ShuffleNet通过深度可分离卷积和通道混合技术减少了模型的参数量和计算量,同时保持了较好的性能。这种卷积首先使用 groups
参数将输入通道分组,然后对每个组应用一个轻量级的 (kernel_size, 1)
卷积,接着是一个 1x1
的卷积来组合这些输出。在每个深度可分离卷积后面,紧跟着一个批量归一化层、一个ReLU激活函数和一个通道混合模块。
ChannelShuffleModule
是一个通道混合模块,它接收一个张量作为输入,并将其通道按照指定的组数进行重组和混合。在构造函数中,channels
是输入张量的通道数,groups
是要将通道分成的组数。
forward
方法首先将输入张量重塑为 (batch, groups, channel_per_group, series, modal)
的形状,然后通过 permute
重新排列这些组,最后再将其重塑回 (batch, channels, series, modal)
的形状。
class ChannelShuffleModule(nn.Module):
def __init__(self, channels, groups):
super().__init__()
'''
channels: 张量通道数
groups: 通道组数【将channels分为groups组去shuffle】
'''
assert channels % groups == 0
self.channels = channels
self.groups = groups
self.channel_per_group = self.channels // self.groups
ShuffleNet
类继承自 nn.Module
,定义了ShuffleNet的主体结构。
构造函数 __init__
接受 train_shape
(训练样本的形状)、category
(类别数)和 kernel_size
(卷积核大小)作为参数。
self.layer
是一个由多个卷积层、批量归一化层、ReLU激活函数和通道混合模块组成的序列。这些层按照顺序执行,逐步增加网络的深度并减少特征图的尺寸。
class ShuffleNet(nn.Module):
def __init__(self, train_shape, category, kernel_size=3):
super(ShuffleNet, self).__init__()
self.layer = nn.Sequential(
nn.Conv2d(1, 1, (kernel_size, 1), (2, 1), (kernel_size // 2, 0), groups=1),
nn.Conv2d(1, 64, 1, 1, 0),
nn.BatchNorm2d(64),
nn.ReLU(),
ChannelShuffleModule(channels=64, groups=8),
nn.Conv2d(64, 64, (kernel_size, 1), (2, 1), (kernel_size // 2, 0), groups=64),
nn.Conv2d(64, 128, 1, 1, 0),
nn.BatchNorm2d(128),
nn.ReLU(),
ChannelShuffleModule(channels=128, groups=8),
nn.Conv2d(128, 128, (kernel_size, 1), (2, 1), (kernel_size // 2, 0), groups=128),
nn.Conv2d(128, 256, 1, 1, 0),
nn.BatchNorm2d(256),
nn.ReLU(),
ChannelShuffleModule(channels=256, groups=16),
nn.Conv2d(256, 256, (kernel_size, 1), (2, 1), (kernel_size // 2, 0), groups=256),
nn.Conv2d(256, 512, 1, 1, 0),
nn.BatchNorm2d(512),
nn.ReLU(),
ChannelShuffleModule(channels=512, groups=16)
)
self.ada_pool = nn.AdaptiveAvgPool2d((1, train_shape[-1]))
self.fc = nn.Linear(512*train_shape[-1], category)
forward
方法定义了数据通过网络的正向传播过程。x
的形状假设为 [b, c, series, modal]
,其中 b
是批次大小,c
是通道数,series
是序列长度,modal
是模态数。
首先,x
通过 self.layer
中定义的多个卷积层和通道混合模块。
然后,使用 self.ada_pool
进行自适应平均池化,将特征图的 series
维度缩减到 1
。
接着,通过 view
方法将池化后的特征图展平,并通过一个全连接层 self.fc
进行分类。def forward(self, x):
x = self.layer(x)
x = self.ada_pool(x)
x = x.view(x.size(0), -1)
x = self.fc(x)
return x
从训练得到的结果我们可以发现在准确率(Accuracy)、精确率(Precision)、召回率(Recall)、F1分数(F1-score)、参数量(Parameters)、推理时间(Inference Time) 六个维度上分别为:
将得到的四组实验数据写入表格中,进行横向深入对比:
从模型参数量来看,LSTM>Resnet>CNN>Shufflenet。ResNet在性能和效率之间取得了很好的平衡;CNN在保持较高准确率的同时,具有较小的模型尺寸和较快的推理速度;LSTM适合处理时间序列数据,但计算成本较高;ShuffleNet则在资源受限的环境中表现出色,尽管其准确率略低。
以下是我们对各个模型的关键指标更详细的对比:
如果对预测性能有极高的要求,ResNet可能是最佳选择。如果对速度和模型大小有更高的要求,CNN或Shufflenet可能更合适。LSTM由于其参数量最大,可能适用于需要捕获长期依赖关系的任务,但需要更多的计算资源。
通过对ResNet、LSTM、ShuffleNet和CNN在WISDM数据集上的对比实验,我们发现不同网络结构在不同场景下各有优劣。ResNet在性能和效率之间取得了很好的平衡;CNN在保持较高准确率的同时,具有较小的模型尺寸和较快的推理速度;LSTM适合处理时间序列数据,但计算成本较高;ShuffleNet则在资源受限的环境中表现出色,尽管其准确率略低。在实际应用中,应根据具体任务需求选择合适的模型结构。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。