实验4:MobileNet ShuffleNet - OUC

news/2025/11/3 20:36:17/文章来源:https://www.cnblogs.com/ouc-qhb/p/19188265

实验4:MobileNet & ShuffleNet

姓名: 学号:
姓名和学号?
本实验属于哪门课程? 中国海洋大学25秋《软件工程原理与实践》
实验名称? 实验4:MobileNet & ShuffleNet
博客链接:

学习要求

  • CNN的基本结构:卷积、池化、全连接
  • 典型的⽹络结构:AlexNet、VGG、GoogleNet、ResNet

实验内容

代码作业

1.定义 HybridSN 类

根据图中所示,数据处理流程可以这样描述:

  • 首先连续进行三次3D卷积运算,,旨在从原始输入数据中逐步抽取出具有判别力的空谱联合特征。
    • 网络首层使用8个尺寸为7×3×3的三维卷积核对输入数据进行操作
    • 第二层采用16个尺寸为5×3×3的卷积核,对初级特征进行更深层次的加工与抽象
    • 第三层配置32个尺寸为3×3×3的卷积核,进一步细化所提取的特征
  • 重塑为标准的二维格式,以便后续的二维卷积处理。
    • 模型使用64个3×3的二维卷积核对重塑后的特征图进行空间卷积
  • 之后将经过所有卷积操作后得到的二维特征图展平为一个一维长向量,为全连接层的分类做准备。
    • 最终输出结果为16个节点的最终分类类别数。

下面是代码实现:

import torch
import torch.nn as nnclass_num = 16class HybridSN(nn.Module):''' your code here '''def __init__(self):super(HybridSN, self).__init__()self.conv3d_1 = nn.Conv3d(1, 8, (7, 3, 3))self.conv3d_2 = nn.Conv3d(8, 16, (5, 3, 3))self.conv3d_3 = nn.Conv3d(16, 32, (3, 3, 3))self.conv2d = nn.Conv2d(576, 64, (3, 3))self.linear_1 = nn.Linear(18496, 256)self.linear_2 = nn.Linear(256, 128)self.linear_3 = nn.Linear(128, class_num)# Activation and dropoutself.activation_fn = nn.ReLU()self.dropout_layer = nn.Dropout(0.4)def forward(self, x):# 3D convolutional operationsx = self.activation_fn(self.conv3d_1(x))x = self.activation_fn(self.conv3d_2(x))x = self.activation_fn(self.conv3d_3(x))batch_size = x.shape[0]x = x.view(batch_size, -1, x.shape[3], x.shape[4])x = self.activation_fn(self.conv2d(x))x = x.view(batch_size, -1)x = self.activation_fn(self.linear_1(x))x = self.dropout_layer(x)x = self.activation_fn(self.linear_2(x))x = self.dropout_layer(x)x = self.linear_3(x)return x''' your code here '''# 随机输入, 测试网络结构是否通
x = torch.randn(1, 1, 30, 25, 25)
net = HybridSN()
y = net(x)
print(y.shape)

2.创建数据集

首先对高光谱数据实施PCA降维;然后创建 keras 方便处理的数据格式;然后随机抽取 10% 数据做为训练集,剩余的做为测试集。

  • 首先定义基本函数
# 对高光谱数据 X 应用 PCA 变换
def applyPCA(X, numComponents):newX = np.reshape(X, (-1, X.shape[2]))pca = PCA(n_components=numComponents, whiten=True)newX = pca.fit_transform(newX)newX = np.reshape(newX, (X.shape[0], X.shape[1], numComponents))return newX# 对单个像素周围提取 patch 时,边缘像素就无法取了,因此,给这部分像素进行 padding 操作
def padWithZeros(X, margin=2):newX = np.zeros((X.shape[0] + 2 * margin, X.shape[1] + 2* margin, X.shape[2]))x_offset = marginy_offset = marginnewX[x_offset:X.shape[0] + x_offset, y_offset:X.shape[1] + y_offset, :] = Xreturn newX# 在每个像素周围提取 patch ,然后创建成符合 keras 处理的格式
def createImageCubes(X, y, windowSize=5, removeZeroLabels = True):# 给 X 做 paddingmargin = int((windowSize - 1) / 2)zeroPaddedX = padWithZeros(X, margin=margin)# split patchespatchesData = np.zeros((X.shape[0] * X.shape[1], windowSize, windowSize, X.shape[2]))patchesLabels = np.zeros((X.shape[0] * X.shape[1]))patchIndex = 0for r in range(margin, zeroPaddedX.shape[0] - margin):for c in range(margin, zeroPaddedX.shape[1] - margin):patch = zeroPaddedX[r - margin:r + margin + 1, c - margin:c + margin + 1]   patchesData[patchIndex, :, :, :] = patchpatchesLabels[patchIndex] = y[r-margin, c-margin]patchIndex = patchIndex + 1if removeZeroLabels:patchesData = patchesData[patchesLabels>0,:,:,:]patchesLabels = patchesLabels[patchesLabels>0]patchesLabels -= 1return patchesData, patchesLabelsdef splitTrainTestSet(X, y, testRatio, randomState=345):X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=testRatio, random_state=randomState, stratify=y)return X_train, X_test, y_train, y_test

然后读取并创建数据集:

# 地物类别
class_num = 16
X = sio.loadmat('Indian_pines_corrected.mat')['indian_pines_corrected']
y = sio.loadmat('Indian_pines_gt.mat')['indian_pines_gt']# 用于测试样本的比例
test_ratio = 0.90
# 每个像素周围提取 patch 的尺寸
patch_size = 25
# 使用 PCA 降维,得到主成分的数量
pca_components = 30print('Hyperspectral data shape: ', X.shape)
print('Label shape: ', y.shape)print('\n... ... PCA tranformation ... ...')
X_pca = applyPCA(X, numComponents=pca_components)
print('Data shape after PCA: ', X_pca.shape)print('\n... ... create data cubes ... ...')
X_pca, y = createImageCubes(X_pca, y, windowSize=patch_size)
print('Data cube X shape: ', X_pca.shape)
print('Data cube y shape: ', y.shape)print('\n... ... create train & test data ... ...')
Xtrain, Xtest, ytrain, ytest = splitTrainTestSet(X_pca, y, test_ratio)
print('Xtrain shape: ', Xtrain.shape)
print('Xtest  shape: ', Xtest.shape)# 改变 Xtrain, Ytrain 的形状,以符合 keras 的要求
Xtrain = Xtrain.reshape(-1, patch_size, patch_size, pca_components, 1)
Xtest  = Xtest.reshape(-1, patch_size, patch_size, pca_components, 1)
print('before transpose: Xtrain shape: ', Xtrain.shape) 
print('before transpose: Xtest  shape: ', Xtest.shape) # 为了适应 pytorch 结构,数据要做 transpose
Xtrain = Xtrain.transpose(0, 4, 3, 1, 2)
Xtest  = Xtest.transpose(0, 4, 3, 1, 2)
print('after transpose: Xtrain shape: ', Xtrain.shape) 
print('after transpose: Xtest  shape: ', Xtest.shape) """ Training dataset"""
class TrainDS(torch.utils.data.Dataset): def __init__(self):self.len = Xtrain.shape[0]self.x_data = torch.FloatTensor(Xtrain)self.y_data = torch.LongTensor(ytrain)        def __getitem__(self, index):# 根据索引返回数据和对应的标签return self.x_data[index], self.y_data[index]def __len__(self): # 返回文件数据的数目return self.len""" Testing dataset"""
class TestDS(torch.utils.data.Dataset): def __init__(self):self.len = Xtest.shape[0]self.x_data = torch.FloatTensor(Xtest)self.y_data = torch.LongTensor(ytest)def __getitem__(self, index):# 根据索引返回数据和对应的标签return self.x_data[index], self.y_data[index]def __len__(self): # 返回文件数据的数目return self.len# 创建 trainloader 和 testloader
trainset = TrainDS()
testset  = TestDS()
train_loader = torch.utils.data.DataLoader(dataset=trainset, batch_size=128, shuffle=True, num_workers=2)
test_loader  = torch.utils.data.DataLoader(dataset=testset,  batch_size=128, shuffle=False, num_workers=2)

创建结果:

创建结果

3.开始训练

我们使用的是GPU训练。代码如下:

# 使用GPU训练,可以在菜单 "代码执行工具" -> "更改运行时类型" 里进行设置
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")# 网络放到GPU上
net = HybridSN().to(device)
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(net.parameters(), lr=0.001)# 开始训练
total_loss = 0
for epoch in range(100):for i, (inputs, labels) in enumerate(train_loader):inputs = inputs.to(device)labels = labels.to(device)# 优化器梯度归零optimizer.zero_grad()# 正向传播 + 反向传播 + 优化 outputs = net(inputs)loss = criterion(outputs, labels)loss.backward()optimizer.step()total_loss += loss.item()print('[Epoch: %d]   [loss avg: %.4f]   [current loss: %.4f]' %(epoch + 1, total_loss/(epoch+1), loss.item()))print('Finished Training')

4.模型测试

首先,设置一个标志变量 count 并初始化为 0,用于追踪当前处理的是第几个批次。随后,在模型测试的迭代过程中,每个批次的数据都会被送入 GPU 并通过模型计算得到输出。对于模型产生的预测结果,处理规则如下:若是首个批次(count 等于 0),则将其直接作为总体预测结果的初始值;若不是首个批次,则将该批次的预测结果与之前累积的总体预测结果进行拼接。以此类推,循环结束后即可得到涵盖所有测试样本的最终预测数组 y_pred_test

count = 0
# 模型测试
for inputs, _ in test_loader:inputs = inputs.to(device)outputs = net(inputs)outputs = np.argmax(outputs.detach().cpu().numpy(), axis=1)if count == 0:y_pred_test =  outputscount = 1else:y_pred_test = np.concatenate( (y_pred_test, outputs) )# 生成分类报告
classification = classification_report(ytest, y_pred_test, digits=4)
print(classification)

模型测试结果:

模型测试结果

观察测试结果不难看出,该模型的整体分类准确率达到95.14%,F1-score加权平均值也达到95.12%,两项指标均超过95%的水平,表明模型在绝大多数情况下具有良好的分类性能。然而,不同类别之间的表现存在一定差异,例如类别8的准确率为81.82%,但其召回率仅为50%,这意味着该类别中有一半的样本未被正确识别。总体而言,模型在样本数量充足的类别上表现出色,能够达到很高的识别精度,但在样本量相对不足的类别上,其性能表现则有所下降。

下面代码用于展示分类结果

# load the original image
X = sio.loadmat('Indian_pines_corrected.mat')['indian_pines_corrected']
y = sio.loadmat('Indian_pines_gt.mat')['indian_pines_gt']height = y.shape[0]
width = y.shape[1]X = applyPCA(X, numComponents= pca_components)
X = padWithZeros(X, patch_size//2)# 逐像素预测类别
outputs = np.zeros((height,width))
for i in range(height):for j in range(width):if int(y[i,j]) == 0:continueelse :image_patch = X[i:i+patch_size, j:j+patch_size, :]image_patch = image_patch.reshape(1,image_patch.shape[0],image_patch.shape[1], image_patch.shape[2], 1)X_test_image = torch.FloatTensor(image_patch.transpose(0, 4, 3, 1, 2)).to(device)                                   prediction = net(X_test_image)prediction = np.argmax(prediction.detach().cpu().numpy(), axis=1)outputs[i][j] = prediction+1if i % 20 == 0:print('... ... row ', i, ' handling ... ...')

第一次

思考题

训练HybridSN,然后多测试⼏次,会发现每次分类的结果都不⼀样,请思考为什么?

第一次的结果:

和上图一致。

第二次的结果:

第二次

why?

  • 每次训练时,卷积层、全连接层的初始权重都是随机生成的,不同的初始点会导致梯度下降走向不同的局部最优解,这是结果差异的主要来源。
  • Dropout层在训练时随机"关闭"部分神经元,每次前向传播时,被关闭的神经元组合不同,相当于每次都在训练不同的"子模型"。
  • 每个epoch样本的呈现顺序不同,影响梯度下降的路径和收敛速度。

如果想要进⼀步提升⾼光谱图像的分类性能,可以如何改进?

  • 注意力机制增强:引⼊通道注意力、空间注意力、光谱注意力机制设计三维注意力模块,同时处理空间-光谱维度使⽤⾃注意力机制捕获长距离依赖
  • 多尺度特征融合:加入空洞卷积扩⼤感受野构建特征金字塔网络多分⽀结构提取不同尺度的特征
  • 数据增强优化:针对⾼光谱特点设计增强策略:光谱抖动、波段丢弃使⽤MixUp、CutMix等先进增强技术⽣成对抗网络进⾏数据扩充
  • 网络架构改进: 增加3D卷积层数,网络架构更深;引入残差连接

depth-wise conv 和 分组卷积有什么区别与联系?

区别:

Depth-wise卷积: 输⼊通道数 = 分组数 = 输出通道数

分组卷积: 分组数 < 输⼊通道数

Depth-wise卷积 (极端情况) input_channels = groups = output_channels

分组卷积 (⼀般情况) input_channels > groups, output_channels > groups

联系:

都是标准卷积的泛化形式;都通过减少通道间连接来降低计算量;Depth-wise是分组卷积在groups=C_in时的特例。

SENet 的注意⼒是不是可以加在空间位置上?

答: 不可以

在 ShuffleNet 中,通道的 shuffle 如何⽤代码实现?

shuffle的核心思想是将分组卷积后的特征图在通道维度上重新洗牌,促进组间信息交流。

标准实现如下:

import torch
import torch.nn as nndef channel_shuffle(x, groups):batch_size, num_channels, height, width = x.size()# 检查通道数是否能被分组数整除assert num_channels % groups == 0# 计算每组的通道数channels_per_group = num_channels // groups# 重塑: [batch, groups, channels_per_group, height, width]x = x.view(batch_size, groups, channels_per_group, height, width)# 转置: [batch, channels_per_group, groups, height, width]  x = x.transpose(1, 2).contiguous()# 重塑回原始维度: [batch, channels, height, width]x = x.view(batch_size, -1, height, width)return x

问题总结

体会

心得体会

本次试验让我接触到多种新型网络模型,包括 MobileNet 系列的 V1、V2 及 V3 版本,还有 ShuffleNet、SENet 与 CBAM 模型,并对它们的核心结构、优势特性及适用场景建立了系统认知。同时,通过深入学习 HybridSN 网络模型,我了解了其 “3D 卷积 - 2D 卷积 - 全连接层” 的组合网络架构。

我完成了该网络类代码的编写与运行,直观观察到它在高光谱图像分类任务中的实际表现,也进一步深化了对 2D 卷积和 3D 卷积的理解,可以梳理出两者在原理及应用上的差异。

在完成思考题的过程中,我对 HybridSN 模型的认知得到进一步提升。我主动搜索并学习了优化高光谱图像分类性能的多种思路,理清了深度可分离卷积与分组卷积的异同点,整体收获十分丰富。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/954874.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

模拟赛 31

T1简单题,排序后直接枚举两个有画面格子之间的间隔数,即为可能节省的行数或列数,移动次数也易求。点击查看代码 #include<bits/stdc++.h> #define MAXN 500005 #define int long long const int inf=1e18; us…

CSP-S 2025 T3 小结

这个主要是写给自己看的。 就是观察到 b 性质是个扫描线。 考虑加强,会发现把 trie 树套上去就没了。 前面的思路不难想,主要是最后一步。 代码: #include<bits/stdc++.h> #include<bits/extc++.h> usi…

第三十二篇

今天是11月3号,进行期中考试了,难

2025年苏州AIGEO 优化服务商深度测评:TOP5 企业核心优势与实战案例对比

这份 GEO 优化服务商榜单与实践指南,既提供了可直接对标选择的优质服务商,也拆解了不同行业的定制化策略与落地路径。对企业而言,GEO 优化不再是单一的技术操作,而是 AI 时代品牌抢占流量入口、传递核心价值的关键…

使用 Docker Compose 轻松实现 INFINI Console 离线部署与持久化管理

本文是 INFINI Console 环境搭建系列的第四篇,专为需要在离线或内网环境中容器化部署 INFINI Console 与 Easysearch 的用户设计。系列回顾与引言 在我们的 INFINI 本地环境搭建系列博客中:第一篇《搭建持久化的 INF…

第6章 语句

6.5 if语句悬垂else (dangling-else) 问题:当一个if子句多于else子句时,对于每一个else,究竟属于哪个if。 C++中会将else匹配给最后出现的尚未匹配的if子句。

十一月杂题

十一月杂题1. CF1067D Computer Game 考虑有了一次升级机会之后一定只会对着期望收益最高的做。于是只需要决策升级之前的决策。设 \(f_t\) 为还剩 \(t\) 秒的最大收益,\(x\) 为期望收益最大的任务的期望收益,则有 \…

Modbus RTU 通信格式详解学习笔记

看似与人为善、心肠柔软之人,必然有一块坚硬如铁的心境土壤,在苦难人生中,死死支撑着那份看似愚蠢的善意1️⃣ 核心思想:Modbus RTU 报文 = 一封结构化的“电报” 想象一下,你要给朋友发一封电报:你得先告诉邮局…

Selenium3+Python3 自动化项目项目实战day1

HTML CSS JavaScript HTMl总体脉络 CSS皮肤组织 JavaScript二者神经组织 HTML 超文本标记语言 HTMl元素 HTML表单 CSS JaveScript

P1.python环境的配置和安装

P1.python环境的配置和安装1.1CUDA安装: 1.查看CUDA Version 在终端输入nvidia-smi2.下载安装配置CUDA1.2python3.8安装 C:\Users\ASUS\AppData\Local\Programs\Python\Python381.3Anaconda安装 1.软件下载安装测试一…

Python 中可变对象的“引用赋值”特性——可变对象的“引用传递”

一、踩坑代码 某程序老鸟讲了一个故事: “2019年夏天,我在做一个推荐系统的用户画像模块。当时写了这样的代码: # 当时的蠢代码,现在想起来都脸红 default_preferences = [] # 想着所有用户共享一个默认偏好 user…

CSP-S 2025 游寄喵

使用了新的文风喵……希望能缓解气氛喵……poi 酱写下这篇游记的时候大概心态很炸喵……不过还是尽量收住了我的垃圾情绪喵,如果不慎伤到您的话欢迎指出喵……poi 酱谢罪喵……(跪着) 如果您有帮到 poi 酱没有 ack …

Modbus协议分类及测试学习笔记

只是两个人相处,那么喜欢一个人,可能会觉得她所有都好,但是以后在一起了,就要学会喜欢她的不好。记住,Modbus不是一种协议,而是一套“通信规则”,它可以在不同的“交通工具”上运行 1️⃣ 核心思想:Modbus是“…

MarkDown初入

MarkDown学习 标题 几个“#”后+一个空格,就是几级标题,最多6级 文字修饰 Hello,Word! 前后+”**“是+粗 一个”*“斜体 三个就是全都要 双波浪就是划掉 Hello,Word! Hello,Word! Hello,Word! 引用学习狂神教…

英语_作文_8AU3_Curiosity

Curiosity is one of the most important qualities the human have.It let us have ability to explore the unknown. We always asked "why", even we found our question‘s answers surpringly and amaz…

习题-极大原理

习题1. 若\(a\)和\(b\)是两个实数,当\(b-a\)为正有理数时定义\(a\prec b\),证明这是\(\mathbb{R}\)上的一个严格偏序。它的极大全序子集是什么?2. (a) 设\(\prec\)是集合\(A\)中的一个严格偏序,\(A\)中的一个关系\…

极大原理

我们已经说过,由选择公理可以得到任意集合都能良序化这一深刻的定理。在数学中,选择公理还有更加重要的推论。这里所提及的“极大原理”有多种版本。在1914年至1935年间,多位数学家曾对极大原理独立地予以论述,他们…

P7. TensorBoard的使用(一)

P7. TensorBoard的使用(一)7.1SummaryWriter类使用 1.官方文档对SummaryWriter的介绍 按住Ctrl,点中SummaryWriter点击查看代码 Writes entries directly to event files in the log_dir to be consumed by TensorB…

二分搜索优化DP(子序列问题)

P1020 [NOIP 1999 提高组] 导弹拦截 题解 题目描述 某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一…

如何从手机内部恢复数据?2025年9大最佳手机数据恢复软件

如何从手机内部存储中恢复数据?手机存储着许多重要数据,例如照片、视频、短信和其他文件。如果您的手机损坏且无法访问,该怎么办?手机中存储的所有重要文件都丢失了,或者您不小心删除了重要文件。接下来,我们将向…