深度学习初探:高光谱数据处理的入门代码指南
·
深度学习高光谱入门代码手把手指导
高光谱图像那密密麻麻的波段看着就让人头大是不是?别慌,今天咱们直接用代码撕开这层神秘面纱。先把手弄脏——加载数据才是正经事。高光谱数据通常藏在.mat文件里,咱们用scipy来拆这个快递:
from scipy.io import loadmat
import numpy as np
data = loadmat('Indian_pines_corrected.mat')['indian_pines_corrected']
gt = loadmat('Indian_pines_gt.mat')['indian_pines_gt']
print(f"数据尺寸:{data.shape},标签尺寸:{gt.shape}")
看到输出是(145,145,200)和(145,145)没?这表示200个波段的空间数据,每个像素对应一个标签。但直接处理200维要命啊,咱们先做个降维手术:
from sklearn.decomposition import PCA
h, w, c = data.shape
flatten_data = data.reshape(-1, c)
pca = PCA(n_components=30) # 保留30个主成分
reduced_data = pca.fit_transform(flatten_data).reshape(h, w, -1)
print(f"降维后尺寸:{reduced_data.shape}")
这时候数据变成(145,145,30),舒服多了吧?但直接扔进神经网络会被维度打脸。咱们得造点小方块——把每个像素及其周围区域抠出来:
def create_patches(data, gt, window_size=15):
half_size = window_size // 2
padded_data = np.pad(data, [(half_size, half_size), (half_size, half_size), (0, 0)], mode='reflect')
patches = []
labels = []
for i in range(half_size, padded_data.shape[0]-half_size):
for j in range(half_size, padded_data.shape[1]-half_size):
patch = padded_data[i-half_size:i+half_size+1, j-half_size:j+half_size+1]
label = gt[i-half_size, j-half_size]
if label != 0: # 跳过背景类
patches.append(patch)
labels.append(label-1) # 标签从0开始
return np.array(patches), np.array(labels)
X, y = create_patches(reduced_data, gt)
print(f"样本形状:{X.shape},标签数量:{len(y)}")
看到生成的(10249, 15, 15, 30)样本没?这才是神经网络能消化的格式。上模型环节,整个轻量级的HybridSN结构:
import torch
import torch.nn as nn
class HyperSpectraNet(nn.Module):
def __init__(self, num_classes):
super().__init__()
# 光谱特征提取
self.conv3d_1 = nn.Conv3d(1, 8, (7, 3, 3))
self.conv3d_2 = nn.Conv3d(8, 16, (5, 3, 3))
# 空间特征提取
self.conv2d = nn.Conv2d(16*7, 64, 3)
self.fc = nn.Linear(64*7*7, num_classes)
def forward(self, x):
x = x.unsqueeze(1) # 增加通道维度
# 光谱卷积 [B,1,15,15,30] -> [B,8,9,13,28]
x = self.conv3d_1(x)
x = nn.ReLU()(x)
# 继续压缩光谱维度 [B,8,9,13,28] -> [B,16,5,11,26]
x = self.conv3d_2(x)
x = nn.ReLU()(x)
# 合并光谱维度 [B,16,5,11,26] -> [B,16*5,11,26]
b, c, d, h, w = x.shape
x = x.view(b, c*d, h, w)
# 空间卷积 [B,80,11,26] -> [B,64,9,24]
x = self.conv2d(x)
x = nn.ReLU()(x)
x = x.view(b, -1)
return self.fc(x)
model = HyperSpectraNet(num_classes=16)
print(f"参数量:{sum(p.numel() for p in model.parameters())}") # 约50万参数
这结构妙在先用3D卷积榨取光谱特征,然后转2D卷积抓空间信息。注意维度变化:[1,15,15,30]输入,经过两次3D卷积后光谱维度从30被压缩到26,再展平进入2D卷积。
深度学习高光谱入门代码手把手指导
训练环节得注意类别不平衡问题,咱们上加权采样:
from torch.utils.data import DataLoader, WeightedRandomSampler
class_counts = np.bincount(y)
class_weights = 1. / class_counts
weights = class_weights[y]
sampler = WeightedRandomSampler(weights, len(weights))
train_loader = DataLoader(torch.utils.data.TensorDataset(
torch.FloatTensor(X).permute(0,3,1,2), # 调整维度为[通道, 高, 宽]
torch.LongTensor(y)),
batch_size=64, sampler=sampler)
最后整个训练循环,记得用交叉熵损失:
optimizer = torch.optim.Adam(model.parameters(), lr=0.001, weight_decay=1e-4)
criterion = nn.CrossEntropyLoss()
for epoch in range(50):
model.train()
for inputs, labels in train_loader:
outputs = model(inputs)
loss = criterion(outputs, labels)
optimizer.zero_grad()
loss.backward()
optimizer.step()
# 验证环节
with torch.no_grad():
val_outputs = model(val_inputs)
acc = (val_outputs.argmax(1) == val_labels).float().mean()
print(f"Epoch {epoch} | Loss: {loss.item():.4f} | Acc: {acc:.2%}")
跑完50个epoch,准确率大概能到85%左右。要是想再提升,试试这些骚操作:
- 在数据增强里加随机旋转和镜像
- 把PCA换成MNF变换
- 在模型里加SE注意力模块
- 用标签平滑代替普通交叉熵
最后提醒新手:高光谱分类最大的坑是数据泄露!千万别在降维前就划分数据集,否则PCA会偷看到测试集信息。正确姿势是先分train/test,再分别做PCA拟合。

更多推荐
所有评论(0)