CNN进行土地覆盖分类
让我们通过对数据应用主成分分析(PCA)来创建Sundarbans卫星图像的三维补丁。以下代码用于创建实现PCA的功能,创建3D补丁以及将数据按70:30的比例拆分为训练数据和测试数据。分割数据后,使用tensorflow.keras包中的to_categorical()方法对训练标签和测试标签进行编码。
defapplyPCA(X, numComponents=75): 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)) returnnewX, pcadefpadWithZeros(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, :] =XreturnnewXdefcreateImageCubes(X, y, windowSize=5, removeZeroLabels=False): margin=int((windowSize-1) /2) zeroPaddedX=padWithZeros(X, margin=margin) #splitpatchespatchesData=np.zeros((X.shape[0] *X.shape[1], windowSize, windowSize, X.shape[2])) patchesLabels=np.zeros((X.shape[0] *X.shape[1])) patchIndex=0forrinrange(margin, zeroPaddedX.shape[0] -margin): forcinrange(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+1ifremoveZeroLabels: patchesData=patchesData[patchesLabels>0,:,:,:] patchesLabels=patchesLabels[patchesLabels>0] patchesLabels-=1returnpatchesData, patchesLabelsdefsplitTrainTestSet(X, y, testRatio, randomState=42): X_train, X_test, y_train, y_test=train_test_split(X, y, test_size=testRatio, random_state=randomState, stratify=y) returnX_train, X_test, y_train, y_test##GLOBALVARIABLESdataset='SB'test_size=0.30windowSize=15MODEL_NAME='Sundarbans'path='/content/drive/MyDrive/Sundarbans/'X_data=np.moveaxis(arr_st, 0, -1) y_data=loadmat('Sundarbands_gt.mat')['gt'] #ApplyPCAK=5X,pca=applyPCA(X_data,numComponents=K) print(f'Data After PCA: {X.shape}') #Create3DPatchesX, y=createImageCubes(X, y_data, windowSize=windowSize) print(f'Patch size: {X.shape}') #SplittrainandtestX_train, X_test, y_train, y_test=splitTrainTestSet(X, y, testRatio=test_size) X_train=X_train.reshape(-1, windowSize, windowSize, K, 1) X_test=X_test.reshape(-1, windowSize, windowSize, K, 1) #OneHotEncodingy_train=to_categorical(y_train) y_test=to_categorical(y_test) print(f'Train: {X_train.shape}\nTest: {X_test.shape}\nTrain Labels: {y_train.shape}\nTest Labels: {y_test.shape}')
CNN模型
让我们构建一个具有不同图层(例如卷积,dropout和密集图层)的三维CNN。以下代码用于使用TensorFlow创建用于土地覆盖分类的3D-CNN。
S=windowSizeL=Koutput_units=y_train.shape[1] ##inputlayerinput_layer=Input((S, S, L, 1)) ##convolutionallayersconv_layer1=Conv3D(filters=16, kernel_size=(2, 2, 3), activation='relu')(input_layer) conv_layer2=Conv3D(filters=32, kernel_size=(2, 2, 3), activation='relu')(conv_layer1) conv2d_shape=conv_layer2.shapeconv_layer3=Reshape((conv2d_shape[1], conv2d_shape[2], conv2d_shape[3]*conv2d_shape[4]))(conv_layer2) conv_layer4=Conv2D(filters=64, kernel_size=(2,2), activation='relu')(conv_layer3) flatten_layer=Flatten()(conv_layer4) ##fullyconnectedlayersdense_layer1=Dense(128, activation='relu')(flatten_layer) dense_layer1=Dropout(0.4)(dense_layer1) dense_layer2=Dense(64, activation='relu')(dense_layer1) dense_layer2=Dropout(0.4)(dense_layer2) dense_layer3=Dense(20, activation='relu')(dense_layer2) dense_layer3=Dropout(0.4)(dense_layer3) output_layer=Dense(units=output_units, activation='softmax')(dense_layer3) #definethemodelwithinputlayerandoutputlayermodel=Model(name=dataset+'_Model' , inputs=input_layer, outputs=output_layer) model.summary()
3D-CNN模型总共具有1,204,098个可训练参数。下图显示了已开发的3D-CNN模型的摘要。
训练
为了训练定义的DNN,我使用了Adam优化器,分类交叉熵,准确性作为度量以及回调。对用于训练3D-CNN的优化器,丢失和回调的简要说明。
Adam优化器
Adam是一种优化算法,可以代替经典的随机梯度下降过程来基于训练数据来更新网络权重。使用adam优化器的优点是:
- 计算效率高。
- 很少的内存需求。
- 梯度的对角线重标不变。
- 非常适合于数据和/或参数较大的问题。
- 适用于非固定目标。
- 适用于非常嘈杂/或稀疏梯度的问题。
- 超参数具有直观的解释,通常需要很少的调整。
分类交叉熵
交叉熵是用于多类分类问题的默认损失函数。在这种情况下,它适用于目标值位于{0,1,3,…,n}集中的多类分类,其中为每个类分配一个唯一的整数值。从数学上讲,它是最大似然推理框架下的首选损失函数。损失函数是第一个评估的函数,只有在有充分理由的情况下才可以更改。
交叉熵将计算得分,该得分总结问题中所有类别的实际概率分布与预测概率分布之间的平均差。分数被最小化,理想的交叉熵值为0。可以在编译模型时通过指定“ categoical_crossentropy”将交叉熵指定为Keras中的损失函数。
回调
EarlyStopping:减少神经网络过度拟合的一种技术是使用早期停止。尽早停止会在模型没有真正学习到任何东西的情况下终止训练过程,从而防止模型过度训练。这是非常灵活的-您可以控制要监视的指标,需要更改多少才能被视为“仍在学习”,以及在模型停止训练之前它可能连续震荡多少个时期。
ModelCheckpoint:此回调将在每个成功的时期之后将模型作为检查点文件(hdf5或h5格式)保存到磁盘。您实际上可以将输出文件设置为根据轮次动态命名。您也可以将损失值或准确性值写入日志文件名的一部分。
TensorBoard:此回调在每批训练后记录,以监控您的指标,图形,直方图,图像等
以下代码用于编译和训练模型。
#Compilemodel.compile(optimizer='adam', loss='categorical_crossentropy', metrics= ['accuracy']) #Callbackslogdir=path+"logs/"+model.name+'_'+datetime.now().strftime("%d:%m:%Y-%H:%M:%S") tensorboard_callback=TensorBoard(log_dir=logdir) es=EarlyStopping(monitor='val_loss', min_delta=0, patience=1, verbose=1, restore_best_weights=True) checkpoint=ModelCheckpoint(filepath='Pavia_University_Model.h5', monitor='val_loss', mode='min', save_best_only=True, verbose=1) #Fithistory=model.fit(x=X_train, y=y_train, batch_size=1024*6, epochs=6, validation_data=(X_test, y_test), callbacks= [tensorboard_callback, es, checkpoint])
训练期间的准确性和损失图的代码以及输出如下所示,X轴表示时期,Y轴表示百分比。
importpandasaspdhistory=pd.DataFrame(history.history) plt.figure(figsize= (12, 6)) plt.plot(range(len(history['accuracy'].values.tolist())), history['accuracy'].values.tolist(), label='Train_Accuracy') plt.plot(range(len(history['loss'].values.tolist())), history['loss'].values.tolist(), label='Train_Loss') plt.plot(range(len(history['val_accuracy'].values.tolist())), history['val_accuracy'].values.tolist(), label='Test_Accuracy') plt.plot(range(len(history['val_loss'].values.tolist())), history['val_loss'].values.tolist(), label='Test_Loss') plt.xlabel('Epochs') plt.ylabel('Value') plt.legend() plt.show()
结果
训练后的CNN模型具有96.00%的准确度,让我们看一看混淆矩阵-通常用表格表示来描述分类模型(或“分类器”)对一组已知真实值的测试数据的性能。
pred=model.predict(X_test, batch_size=1204*6, verbose=1) plt.figure(figsize= (10,7)) classes= [f'Class-{i}'foriinrange(1, 7)] mat=confusion_matrix(np.argmax(y_test, 1), np.argmax(pred, 1)) df_cm=pd.DataFrame(mat, index=classes, columns=classes) sns.heatmap(df_cm, annot=True, fmt='d') plt.show()
分类报告显示准确性以及分类精度,召回率,f1得分和支持。输出如下所示:
#ClassificationReportprint(classification_report(np.argmax(y_test, 1), np.argmax(pred, 1), target_names= [f'Class-{i}'foriinrange(1, 7)])) precisionrecallf1-scoresupportClass-10.950.930.9416222Class-20.990.990.9923570Class-31.001.001.006095Class-40.950.970.9616790Class-50.950.980.9613545Class-60.860.850.869066accuracy0.9685288macroavg0.950.950.9585288weightedavg0.960.960.9685288
最后,让我们可视化Sundarbans卫星的分类图。以下代码用于创建分类图。
pred_t=model.predict(X.reshape(-1, windowSize, windowSize, K, 1), batch_size=1204*6, verbose=1) #VisualizeGroundtruthep.plot_bands(np.argmax(pred_t, axis=1).reshape(954, 298), cmap=ListedColormap(['darkgreen', 'green', 'black', '#CA6F1E', 'navy', 'forestgreen'])) plt.show()
下图显示了Sundarbans卫星数据的RGB复合图像,真实情况和分类图。
结论
本文介绍了用于卫星图像的土地覆盖分类的各种深度学习方法,并且还展示了3D-CNN在Sundarbans卫星图像的土地覆盖分类中的实现和训练。
可以从下面的GitHub存储库访问本文中使用的代码。