提取Lenet-5中的特徵

來自專欄帶土的Python應用

最近仔細看了Lenet-5這個模型,因為該模型的原始輸入圖像使用的尺寸為32*32,也是自己在研究中經常使用的圖像尺寸,所以就想使用該模型訓練自己的數據集,然後提取新的特徵,主要是第一層全連接層的輸出,備作它用。在這裡簡單記錄以一下特徵提取過程。

首先是相關準備工作:

%matplotlib inline%config InlineBackend.figure_format = retina## 載入包import numpy as npimport pandas as pdimport matplotlib.pyplot as pltfrom scipy.io import loadmat,savematimport keras as Kfrom keras.models import Sequentialfrom keras.layers import Conv2D,Activation,MaxPooling2D,Flatten,Densefrom keras.optimizers import SGDfrom sklearn.preprocessing import OneHotEncoder,StandardScalerfrom sklearn.model_selection import train_test_split

然後是數據準備:

## 該數據集含有32*32的人臉數據data = loadmat("data/YaleB_Extended_38classes_2414points_32x32.mat")A = data["A"]A2 = A.Tprint(A2.shape)(2414, 1024)for ii in range(A2.shape[0]): a = A[:,ii].reshape(32,32,order = "F") A2[ii,:] = a.reshape(1,-1)

該數據集有2414張,每張有1024個特徵,即32*32。因為matlab中和python中在轉換數據集形狀是採取的默認方式不一樣,所以要對數據集進行調整。調整時要注意reshape的參數應該為order = "F"。接著對數據集進行標準化,切分數據集等操作。

## 數據標準化scale = StandardScaler(with_mean=True,with_std=True)A2 = scale.fit_transform(A2)A2 = A2.reshape((-1,32,32,1))## 整理labellabels = data["labels"]One = OneHotEncoder()labelone = One.fit_transform(labels.reshape(-1,1)).toarray()## 切分訓練集和測試集train_x,test_x,train_y,test_y = train_test_split(A2,labelone,test_size = 0.3,random_state = 1)print(train_x.shape)print(train_y.shape)print(test_x.shape)print(test_y.shape)(1689, 32, 32, 1)(1689, 38)(725, 32, 32, 1)(725, 38)

訓練集1689張,測試集725張。

接下來開始搭建Lenet5網路模。

classnum = labelone.shape[1]model = Sequential()model.add(Conv2D(6,(5,5),strides=(1,1),padding="valid",input_shape = (32,32,1),activation = "tanh",name="conv1"))model.add(MaxPooling2D((2,2),strides=(2,2)))model.add(Conv2D(16,(5,5),strides=(1,1),padding="valid",activation = "tanh",name="conv2"))model.add(MaxPooling2D((2,2),strides=(2,2)))model.add(Flatten())model.add(Dense(120,activation="tanh",name="fc1"))model.add(Dense(84,activation="tanh",name="fc2"))model.add(Dense(classnum,activation="softmax"))model.summary()Layer (type) Output Shape Param # =================================================================conv1 (Conv2D) (None, 28, 28, 6) 156 _________________________________________________________________max_pooling2d_1 (MaxPooling2 (None, 14, 14, 6) 0 _________________________________________________________________conv2 (Conv2D) (None, 10, 10, 16) 2416 _________________________________________________________________max_pooling2d_2 (MaxPooling2 (None, 5, 5, 16) 0 _________________________________________________________________flatten_1 (Flatten) (None, 400) 0 _________________________________________________________________fc1 (Dense) (None, 120) 48120 _________________________________________________________________fc2 (Dense) (None, 84) 10164 _________________________________________________________________dense_1 (Dense) (None, 38) 3230 =================================================================Total params: 64,086Trainable params: 64,086Non-trainable params: 0

接下來開始訓練模型

## 定義優化演算法sgd = SGD(lr=0.01, decay=1e-6, momentum=0.9, nesterov=True)## 對模型進行編譯model.compile(loss="categorical_crossentropy", # 多類對數損失函數 optimizer=sgd, metrics=["accuracy"] # 精度 )#train modelmodel_fit = model.fit(train_x,train_y,batch_size=64,epochs=30)model.evaluate(test_x,test_y)[0.39910289657527004, 0.89931034490979955]

可以發現模型在測試集的精度為98.93%。查看模型的訓練過程。

## 繪製圖像plt.figure(figsize=(12,5))plt.subplot(1,2,1)plt.plot(model_fit.epoch,model_fit.history["acc"],"ro-",lw = 2)plt.grid()plt.xlabel("Model epoch")plt.ylabel("accuracy")plt.title("CNN accuracy")plt.subplot(1,2,2)plt.plot(model_fit.epoch,model_fit.history["loss"],"ro-",lw = 2)plt.grid()plt.xlabel("Model epoch")plt.ylabel("categorical crossentropy")plt.title("CNN categorical crossentropy")plt.show()

模型在訓練過程中收斂情況很好。

最後提取數據在第一個全連接層的120維度的特徵

from keras.models import Modellayer_name = "fc1"intermediate_layer_model = Model(inputs=model.input, outputs=model.get_layer(layer_name).output)intermediate_output = intermediate_layer_model.predict(A2)intermediate_output.shape(2414, 120)# 保存數據datacp = {"A":intermediate_output.T, "labels":data["labels"][0]}savemat("data/Yable_lenet5_120Feature_38class.mat",datacp)

最後可以發現所有的數據樣本得到了新的120維的特徵。

推薦閱讀:

相關文章