概述
从2012年深度卷积神经网络(AlexNet)成功应用于图像识别以来,发展出多个改进的卷积神经网络构架,包括2014年牛津大学的VGG,Google公司的GoogleNet,2015年微软研究院Kaiming
He推出的残差网络,网络层数越来越多,所得到的精度越来越高。深度学习能够通过提取遥感图像的高层次特征,表征出遥感场景间的细微差别。遥感图像分类就是利用计算机通过对遥感图像中各类地物的光谱信息和空间信息进行分析,选择特征,将图像中各个像元按照某种规则或算法划分不同的类别,然后获得遥感图像中与实际地物的对应信息,从而实现图像的分类。遥感图像计算机分类的依据是遥感图像像素的相似度,常使用距离和相关系数来衡量相似度。
本文通过采用SVM算法、RESNET18算法以及LSTM算法对OPTIMAL-31数据集以及WHU-RS19数据集进行训练学习,并写出实验结果分析。
方法原理
1.SVM
支持向量机(Support Vecor Machine,
SVM)本身是一个二元分类算法,是对感知器算法模型的一种扩展,它寻求的是一个最优超平面(函数g(x)
)将两类样本点分的最开,最大间隔准则(H1和H2之间间隔最大)是支持向量机最佳准则,如图。
2.RESNET18
ResNet(Residual Neural Network)由微软研究院的Kaiming He等四名华人提出,通过使用ResNet
Unit成功训练出了152层的神经网络,并在ILSVRC2015比赛中取得冠军,在top5上的错误率为3.57%,同时参数量比VGGNet低,效果非常突出。ResNet的结构可以极快的加速神经网络的训练,模型的准确率也有比较大的提升。同时ResNet的推广性非常好,甚至可以直接用到InceptionNet网络中。
3.LSTM算法
RNN( Recurrent Neural Network 循环(递归)神经网络) 跟人的大脑记忆差不多。我们的任何决定,想法都是根据我们之前已经学到的东西产生的。RNN通过反向传播和记忆机制,能够处理任意长度的序列,在架构上比前馈神经网络更符合生物神经网络的结构,它的产生也正是为了解决这类问题而应用而生的。
RNN及改进的LSTM等深度学习模型都是基于神经网络而发展的起来的认知计算模型。从原理来看,它们都是源于认知语言学中的“顺序像似性”原理:文字符号与其上下文构成一个“像”,这个“像”可以被认为是符号与符号的组合——词汇,也可以被认为是词汇与词汇的句法关系——依存关系。算法的训练过程,是通过正向和反馈两个过程从训练语料中学习出识别这些“像”的能力,并记录下“像”的模型数据,当输入的新的句子时,算法可以利用存储的模型数据识别出新输入中类似的“像”。
LSTM,即Long Short Term Memory Networks 长短时间记忆网络,是RNN的一个变种,专门用于解决Simple-RNN上述的俩问题。
LSTM通过对循环层的刻意设计来避免长期依赖和梯度消失,爆炸等问题。长期信息的记忆在LSTM中是默认行为,而无需付出代价就能获得此能力。
从网络主题上来看,RNN和LSTM是相似的,都具有一种循环神经网络的链式形式。在标准的RNN中,这个循环节点只有一个非常简单的结构,如一个tanh层。LSTM的内部要复杂得多,在循环的阶段内部拥有更多的复杂的结构,即4个不同的层来控制信息的交互。
代码实现
1.SVM
class LinearSVM(LinearClassifier):
""" A subclass that uses the Multiclass SVM loss function """
def loss(self, X, y, reg):
W = self.W
loss = 0.0
dW = np.zeros(W.shape) # initialize the gradient as zero
scores = X.dot(W)
num_classes = W.shape[1]
num_train = X.shape[0]
scores_correct = scores[np.arange(num_train), y] # 1 by N
scores_correct = np.reshape(scores_correct, (num_train, -1)) # N by 1
margins = scores - scores_correct + 1 # N by C
margins = np.maximum(0,margins)
margins[np.arange(num_train), y] = 0
loss += np.sum(margins) / num_train
loss += 0.5 * reg * np.sum(W * W)
# compute the gradient
margins[margins > 0] = 1
row_sum = np.sum(margins, axis=1) # 1 by N
margins[np.arange(num_train), y] = -row_sum
dW += np.dot(X.T, margins)/num_train + reg * W # D by C
return loss, dW
# 实例化SVM分类器并进行训练
svm = LinearSVM()
loss_hist = svm.train(train_imgs, train_label, learning_rate=1e-7, reg=2.5e4,num_iters=2500, verbose=True)
test_pred = svm.predict(test_imgs)
test_accuracy = np.mean(test_pred == test_label)
print('linear SVM on raw pixels final test set accuracy: %f' % test_accuracy)
plt.plot(loss_hist)
plt.xlabel('Iteration number')
plt.ylabel('Loss value')
# 尝试不同的学习率和正则化参数对训练结果的影响
learning_rate = [1e-8, 1e-7, 1e-6]
regularization = [1e4, 2.5e4, 5e4]
accuracy = { }
for i,lr in enumerate(learning_rate):
for j, reg in enumerate(regularization):
svm = LinearSVM()
loss_hist = svm.train(train_imgs, train_label, learning_rate=1e-7, reg=2.5e4,num_iters=2500, verbose=True)
test_pred = svm.predict(test_imgs)
test_accuracy = np.mean(test_pred == test_label)
accuracy[(lr, reg)] = test_accuracy
for lr, reg in sorted(accuracy):
test_accuracy = accuracy[(lr, reg)]
print('lr %e reg %e test accuracy: %f' % (lr, reg, test_accuracy))
# 可视化SVM的权值矩阵
svm = LinearSVM()
loss_hist = svm.train(train_imgs, train_label, learning_rate=1e-7, reg=2.5e4,num_iters=2500, verbose=True)
w = svm.W[:-1,:] # strip out the bias
w = w.reshape(40, 40, 3, 19)
w_min, w_max = np.min(w), np.max(w)
classes = ['Airport','Beach','Bridge','Commercial','Desert','Farmland','footballField','Forest','Industrial','Meadow',
'Mountain','Park','Parking','Pond','Port','railwayStation','Residential','River','Viaduct']
for i in range(19):
plt.subplot(4, 5, i + 1)
# Rescale the weights to be between 0 and 255
wimg = 255.0 * (w[:, :, :, i].squeeze() - w_min) / (w_max - w_min)
plt.imshow(wimg.astype('uint8'))
plt.axis('off')
plt.title(classes[i])
plt.subplots_adjust(wspace =0.5, hspace =0.5) #调整子图间距
2.Resnet
start_time = time.time()
max_accuracy = 0.0
for epoch in range(args.start_epoch, args.epochs):
if args.distributed:
data_loader_train.sampler.set_epoch(epoch) ##################################################################################
train_stats = train_one_epoch(
model, criterion, data_loader_train,
optimizer, device, epoch, loss_scaler,
args.clip_grad, model_ema, mixup_fn
)
lr_scheduler.step(epoch)
if args.output_dir:
checkpoint_paths = [output_dir / 'checkpoint.pth']
for checkpoint_path in checkpoint_paths:
utils.save_on_master({
'model': model_without_ddp.state_dict(),
'optimizer': optimizer.state_dict(),
'lr_scheduler': lr_scheduler.state_dict(),
'epoch': epoch,
'model_ema': get_state_dict(model_ema),
'args': args,
}, checkpoint_path)
if epoch % args.print_epoch == 0:
test_stats = evaluate(data_loader_val, model, device)
print(f"Accuracy of the network on the {len(dataset_val)} test images: {test_stats['acc1']:.1f}%")
max_accuracy = max(max_accuracy, test_stats["acc1"])
print(f'Max accuracy: {max_accuracy:.2f}%')
log_stats = {**{f'train_{k}': v for k, v in train_stats.items()},
**{f'test_{k}': v for k, v in test_stats.items()},
'epoch': epoch,
'n_parameters': n_parameters}
if args.output_dir and utils.is_main_process():
with (output_dir / "log.txt").open("a") as f:
f.write(json.dumps(log_stats) + "\n")
total_time = time.time() - start_time
total_time_str = str(datetime.timedelta(seconds=int(total_time)))
print('Training time {}'.format(total_time_str))
3.LSTM代码
def train(model, train_loader, num_epochs, sequence_length, input_size, device, learning_rate):
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)
Loss_list = []
j = 0;
total_step = len(train_loader)
for epoch in range(num_epochs):
for i, (images, labels) in enumerate(train_loader):
images = images.reshape(-1, sequence_length, input_size).to(device)
#labels = class_label.index(labels)
labels = labels.to(device)
# Forward pass
outputs = model(images)
loss = criterion(outputs, labels)
# Backward and optimize
optimizer.zero_grad()
loss.backward()
optimizer.step()
if (i+1) % 10 == 0:
print ('Epoch [{}/{}], Step [{}/{}], Loss: {:.4f}'
.format(epoch+1, num_epochs, i+1, total_step, loss.item()))
Loss_list.append(loss.item())
j = j+1
x = range(j)
plt.plot(x, Loss_list, '.-')
# 对LSTM进行训练和测试
model = RNN(input_size, hidden_size, num_layers, num_classes, dropout=0.5).to(device)
train(model, train_loader, num_epochs, sequence_length, input_size, device, learning_rate)# learning_rate
test(model, test_loader, sequence_length, input_size, device)
# 观察learning rate和dropout的取值对LSTM模型的训练效果的影响
dropout = [0.3, 0.5, 0.7]
learning_rate = [0.000005,0.00005,0.0005]
accuracy = { }
for i,lr in enumerate(learning_rate):
for j, dp in enumerate(dropout):
model = RNN(input_size, hidden_size, num_layers, num_classes, dropout=dp).to(device)
train(model, train_loader, num_epochs, sequence_length, input_size, device, lr)
test_accuracy = test(model, test_loader, sequence_length, input_size, device)
accuracy[(lr, dp)] = test_accuracy
for lr, dp in sorted(accuracy):
test_accuracy = accuracy[(lr, dp)]
print('lr %e dp %e test accuracy: %f' % (lr, dp, test_accuracy))
结果分析
SVM
由于不同的学习率和正则化参数的取值会对SVM的训练结果造成明显的影响,本实验采用了[1e-08, 1e-07,
1e-06]三种学习率以及[1e04, 2.5e04,
5.0e04]三种正则化参数共9种参数组合进行测试,经过训练之后的测试精度分别如下图所示:
测试结果显示,1e-08的学习率和2.5e04正则化参数组合下的效果最好,SVM在训练后的测试精度达到了20%。但是在后续的测试中,我也发现1e-08的学习率似乎有些过于小了,因为在训练过程中其损失值的下降往往非常缓慢,有几次也陷入了局部最小值中。因此我认为在本数据集中,1e-07的学习率是更为可取的。
Resnet
由于本次实验代码是学姐带领做的,代码复杂度较高,数据集很大,调参和读懂很难,我们只是通过实验结果分析其识别准确度大概在60%左右。
LSTM
本实验先选用0.00005的学习率和0.5的dropout值进行训练,最后获得了36.4%的测试精度。训练过程中的损失值的变化如下图所示: