HybridSN 高光谱分类

  • 1 论文解读
    • 1.1 论文摘要
    • 1.2 研究现状比较
    • 1.3 HybridSN模型简介
      • 1.3.1 三维卷积核
      • 1.3.2 二维卷积核
      • 1.3.3 全连接输出
      • 1.3.4 论文中的训练方法
  • 2 代码实践
    • 2.1 取得数据引入基本函数库
    • 2.2 定义 HybridSN 类
    • 2.3 创建数据集
    • 2.4 训练模型
    • 2.5 测试模型
    • 2.6 最终测试结果
  • 3 原理及结果个人分析
    • 3.1 二维卷积和三维卷积的区别
    • 3.2 多次测试的分类结果不一样
  • 4 使用注意力机制提升分类性能

1 论文解读

首先我将对论文《Exploring 3-D–2-D CNN Feature Hierarchy for Hyperspectral Image Classification》进行简介。

1.1 论文摘要

首先引用一下 Exploring 3-D–2-D CNN Feature Hierarchy for Hyperspectral Image Classification 的摘要:

这篇论文提出了一种用于HSI分类的混合光谱CNN方法HybridSN。
由于HSI分类的性能高度依赖于空间和光谱信息,而三维CNN有助于从一些光谱波段中表示空间-光谱特征,但会存在复杂度会大大增加的问题。

因此这篇论文:

  1. 用三维CNN提取空间-光谱的特征;
  2. 在三维CNN基础上使用二维CNN学习更抽象的空间特征;
  3. 论文中表示:与单独使用三维CNN相比,混合CNN的使用降低了模型的复杂性,并经过实验表明,使用HybridSN进行HSI分类,得到了令人满意的效果。

1.2 研究现状比较

这篇论文中通过比较现有的多种HSI分类方法,阐述了仅使用二维CNN或三维CNN进行分类的缺点。

论文指出:

  1. 单纯二维CNN无法从光谱维中提取出具有良好鉴别能力的特征图;
  2. 单纯三维CNN的计算复杂,对于在光谱带上具有相似纹理的图像分类不佳。

这篇论文依此提出一个混合CNN模型的动机,克服了以往模型的这些缺点。

1.3 HybridSN模型简介

1.3.1 三维卷积核

在HybridSN模型中,三维卷积核对应图中的尺寸分别为

  1. 8×(3×3×7)×1
  2. 16×(3×3×5)×8
  3. 32×(3×3×3)×16

例如16×(3×3×5)×8表示该层具有16个三维卷积核,输入特征图的数量为8。
其中三维卷积核大小为3x3x5,分别表示了两个空间维度和一个光谱维度。

对应图片中为Feature1~3

1.3.2 二维卷积核

在HybridSN模型中,二维卷积核对应图中的尺寸为64×3×3×576

其中有64个二维卷积核,输入特征图的数量为256。

对应图片中为Feature4

1.3.3 全连接输出

  1. 首先对特征进行降维,形成1×18496 维的向量;
  2. 通过两次 Dropout 为256与128节点的全连接层;
  3. 输出16个分类

对应图片中为Feature5-6

1.3.4 论文中的训练方法

  1. 对于IP数据集,HybridSN中可训练的权重参数总数为5122176,其中所有的权值为随机初始化。
  2. 训练使用反向传播算法和Adam优化器使用Softmax函数。
  3. 使用大小为256的batch,不使用BN,每轮对网络进行100次训练。

2 代码实践

本次实践基于 summitgao 老师提供的代码进行实施,本次实验环境为Colab。

2.1 取得数据引入基本函数库

! wget http://www.ehu.eus/ccwintco/uploads/6/67/Indian_pines_corrected.mat
! wget http://www.ehu.eus/ccwintco/uploads/c/c4/Indian_pines_gt.mat
! pip install spectral

import numpy as np
import matplotlib.pyplot as plt
import scipy.io as sio
from sklearn.decomposition import PCA
from sklearn.model_selection import train_test_split
from sklearn.metrics import confusion_matrix, accuracy_score, classification_report, cohen_kappa_score
import spectral
import torch
import torchvision
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim

2.2 定义 HybridSN 类

不使用BN的情况下,网络使用ReLU()函数激活

class_num = 16class HybridSN(nn.Module):
'''you code here'''
def __init__(self, in_channels=1, out_channels=class_num):super(HybridSN, self).__init__()#三维卷积层self.conv3d = nn.Sequential(#网络在论文前面有过介绍nn.Conv3d(1,8,kernel_size=(7,3,3)),nn.ReLU(),nn.Conv3d(8,16,kernel_size=(5,3,3)),nn.ReLU(),nn.Conv3d(16,32,kernel_size=(3,3,3)),nn.ReLU())#二维卷积层self.conv2d = nn.Sequential(nn.Conv2d(576, 64, kernel_size=(3,3)),nn.ReLU())#全连接层self.fc = nn.Sequential(nn.Linear(64 * 17 * 17, 256),nn.ReLU(),nn.Dropout(0.4),nn.Linear(256, 128),nn.ReLU(),nn.Dropout(0.4),nn.Linear(128, 16))def forward(self, t):t = self.conv3d(t)#进行卷积降维3d->2dt = t.view(t.shape[0], t.shape[1]*t.shape[2], t.shape[3], t.shape[4])t = self.conv2d(t)#进行卷积降维进行flattent = t.view(t.shape[0],-1)t = self.fc(t)return t

2.3 创建数据集

  1. 首先对高光谱数据实施PCA降维(有关降维PCA的详细描述在论文II部分给出);
  2. 创建 keras 方便处理的数据格式;
  3. 随机抽取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)

2.4 训练模型

# 网络放到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')

训练结果:

2.5 测试模型

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)

  • 可以看到最终平均准确率达到97.33%

2.6 最终测试结果


这是多次测试后的结果

3 原理及结果个人分析

3.1 二维卷积和三维卷积的区别

  • 二维卷积主要用于提取空间特征,在卷积的过程中,图片与卷积核进行卷积,输出是一张二维的特征图,因此二维卷积只能提取二维的平面特征
  • 三维卷积的卷积核可以看作一个数据立方体,因此三维卷积处理的对象是一个立方体图像,三维卷积的思想与二维卷积相同,只不过多了一个维度,所以三维卷积不仅提取处理空间特征,也可以提取另一维度的特征
  • 由于高光谱图像同时具有空间信息光谱信息,因此需要使用三维卷积来提取图像的特征。根据前文叙述的三维卷积的缺点,因此这篇论文采用折衷的方法,使得三维和二维卷积的混合网络。

3.2 多次测试的分类结果不一样

  • 由于在网络中使用了Dropout()函数的使得在网络训练的过程中随机删除神经元,由于删除的神经元位置不定,从而每一次都让不同的模型进行学习。
  • 因此多次测试的分类结果不一样原因可能是由于没有使用eval()将模型切换至测试模式。
  • 因此在使用训练好的模型下应当使用model.eval()关闭Dropout模式

model.train() :启用 BatchNormalization 和 Dropout
model.eval() :不启用 BatchNormalization 和 Dropout。

4 使用注意力机制提升分类性能

  • 由于高光谱图像同时具有空间信息和光谱信息,因此我认为高光谱图像可以从空间方面、图像的通道方面和光谱信息三个方面使用注意力机制来处理特征,由于本次项目启动的时间较晚,没有来得及实践,会在之后学习中补上。
  • 在此做猜想采用通道和光谱信息的注意力机制可能会使得分类效果更好,或者几者混合使用。但缺点会使网络更加复杂,训练过程可能随之更长。
  • 由于假色彩图像通过改变了图像原有的通道突出了相关专题信息,提高图像视觉效果,从图像中提取更有用的定量化信息,而遥感之类的图像往往细节很多且很分散,单独使用空间注意力机制可能效果不会太好;
  • 可以采用空间注意力,首先找到与局部特征相关的特征空间,然后再使用通道注意力机制进行细分·····

HybridSN 高光谱分类相关推荐

  1. 基于卷积神经网络的高光谱分类 CNN+高光谱+印度松数据集

    基于卷积神经网络的高光谱分类 一.研究现状 只考虑到高光谱图像的光谱特征,即: 1.提取特征(小波变换.Gabor纹理分析.形态学剖面) 2.利用分类方法分类(支持向量机.决策树.随机森林.神经网络) ...

  2. 基于Adaboost的高光谱分类算法设计

    这次我们分享数据挖掘领域中较为经典的一个算法 AdaBoost,首先请看本次分享的目录梗概: 数据集简介 AdaBoost算法简介 AdaBoost算法实例解析 代码展示 参考文献 一.数据集简介 数 ...

  3. 基于卷积神经网络的高光谱分类(1D、2D、3D-CNN)

    算法原理 卷积神经网络(Convolutional Neural Networks,CNN)是深度学习中最常见的一种 算法,它具有强大的特征学习能力.CNN 通过结合局部感知区域.共享权重.空间或者 ...

  4. OUC暑期培训(深度学习)——第四周学习记录:MobileNetV1,V2,V3

    第四周学习:MobileNetV1,V2,V3 Part 1 视频学习及论文阅读 1.MobileNetV1 MobileNetV1论文网址:[1704.04861] MobileNets: Effi ...

  5. 第4周学习:MobileNetV1, V2, V3

    这里写目录标题 MobileNet V1 & V2 MobileNet V3 SENet 的基本原理和代码 HybridSN 高光谱分类-代码练习 MobileNet V1 & V2 ...

  6. 【AI】高光谱图像分类 — HybridSN模型

    文章目录 前言 实验目的 论文地址 一.论文解读 1.这篇论文说了啥? 2.实现步骤 (1)PCA主成分分析 (2)将数据划分为三维小块 (3)三维卷积提取光谱维度特征 (4)二维卷积卷图像特征 (5 ...

  7. 高光谱遥感影像分类研究进展 --- (15年论文,方法主要是常规处理,但是写的比较细)

    论文地址 高光谱遥感影像分类研究进展 南大.矿大.河海 15年的文章比较老,科普文,但是理论总结和语言用词都比较扎实 在总结分类策略的基础上,重点从以核方法(SVM)为代表的新型分类器设计.特征挖掘. ...

  8. [HSI论文阅读] | HybridSN: Exploring 3-D–2-D CNN Feature Hierarchy for Hyperspectral Image Classification

    仅整理个人和组里对下文引用的论文(HybridSN)的学习所获,如有错误,感谢指正~ 更新记录 ⭐️ 2021.3.6 -- 关于本文2.2.2节卷积层参数的计算 ⭐️ 2021.3.8 -- Hyb ...

  9. 高光谱遥感数据光谱特征的提取与应用---高光谱基础知识科普论文

    论文地址 高光谱遥感数据光谱特征的提取与应用 杜培军 遥感基础知识积累: 绝对温度大于0的物体在整个光谱轴上具有连续的光谱曲线 高光谱可以有效的描述一些窄而重要的局部光谱特征,可以明显看到高光谱对于光 ...

最新文章

  1. 比较ArrayList、LinkedList、Vector
  2. Struts2中action获取request、response、session的方式
  3. 删除或卸载以前添加的库:cocoapods
  4. MySQL的GROUP_CONCAT函数
  5. HDU 2647 拓扑排序
  6. java中项目启动时加载_如何在项目启动时,加载或解析某配置文件
  7. 获取jpg图片的x,y的分辨率dpi
  8. OO_2019_第一单元总结——表达式求导
  9. Atlas指南: 建立一个AJAX 涂鸦程序(三)
  10. extjs中什么时候用{},什么时候用[]
  11. 内外网同时使用-路由配置
  12. 高速PCB设计EMI之九大规则
  13. Spark大数据开发技术简介
  14. 身份认证之双因素认证 2FA
  15. python里打印空格_python打印空格
  16. 蓝桥杯 ALGO-45算法训练 调和数列问题
  17. iPad商标之争或和解
  18. 电容降压 20170619 周一
  19. 恒大通关世界500强:一家房企的进阶路与中国民营企业的边界探索
  20. PTA甲 1069~1072题解

热门文章

  1. python中可以终结一个循环的保留字是_以下可以终结一个循环的保留字是
  2. 手机 平板 屏幕分辨率 尺寸 长宽比
  3. 1.豆豆项目搭建之springboot集成mybatis-plus(包含mybatis-plus自动生成基础代码)
  4. 账号共享风险大 恐泄漏用户信息
  5. 悟透JavaScript(李站老师)-编程的快乐
  6. 路由器至游戏服务器稳定性,如何改善路由器到游戏服务器的
  7. 年薪30w还是白菜价?大数据工程师凭什么?
  8. thinkpad 开机按f12
  9. 科大讯飞版ChatGPT提前内测!附申请方法
  10. 命名冲突conflicting declaration