玩命加载中...
# 构造卷积网络进行形状识别 3个小节,预计用时**45分钟**。 卷积神经网络是解决图像相关的机器学习问题的常用模型。本教程基于SofaSofa数据练习赛<a href="http://sofasofa.io/competition.php?id=9" target="_blank">形状识别2:方圆之外</a>的数据集,讲解和展示了建立卷积神经网恋的步骤。 本教程基于**Python 3.7**与**TensorFlow**。 原创者:**[Zealing](http://sofasofa.io/user_profile.php?id=1001997)** | 修改校对:SofaSofa TeamM | <hr> ### 1. 加载数据 ```python # --- 参数设置 --- # 手动查看测试集中的图像,并且增加了五个异形,放入训练集 num_anno=5 epochs=100 SEED=0 # 考虑到异性并不多,所以设置如下权重,来解决非平衡下的分类 class_weight={0:1.,1:1.,2:10.} ``` ```python # 加载训练集 import numpy as np import matplotlib.pyplot as plt np.random.seed(0) train_data_raw = np.genfromtxt('train.csv', delimiter=',') train_data=train_data_raw[1:,1:] [n_train,d]=train_data.shape y_train=train_data[:,d-1] x_train=train_data[:,:-1] [n_train,d]=x_train.shape sz=40 x_train=x_train.reshape([n_train,sz,sz]) # 加载测试集 test_data_raw = np.genfromtxt('test.csv', delimiter=',') test_data=test_data_raw[1:,:] x_test=test_data[:,1:] n_test=x_test.shape[0] x_test=x_test.reshape([n_test,sz,sz]) ``` ## 2. 数据处理 数据处理中我们先对图像进行预处理,步骤包括 - 利用中值滤波(median filter)进行降噪 - 利用阈值分割法(threshold segmentation)生成掩膜(binary mask) - 利用形态闭合(morphology closing)来填充图中的小洞 ```python from skimage.restoration import (denoise_tv_chambolle, denoise_bilateral, denoise_wavelet, estimate_sigma) from scipy import ndimage, misc import statistics import scipy def my_preprocessing(I,show_fig=False): I_median=ndimage.median_filter(I, size=5) mask=(I_median<statistics.mode(I_median.flatten())); I_out=scipy.ndimage.morphology.binary_closing(mask,iterations=2) if(np.mean(I_out[15:25,15:25].flatten())<0.5): I_out=1-I_out if show_fig: fig= plt.figure(figsize=(8, 4)) plt.gray() plt.subplot(2,4,1) plt.imshow(I) plt.axis('off') plt.title('Image') plt.subplot(2,4,2) plt.imshow(I_median) plt.axis('off') plt.title('Median filter') plt.subplot(2,4,3) plt.imshow(mask) plt.axis('off') plt.title('Mask') plt.subplot(2,4,4) plt.imshow(I_out) plt.axis('off') plt.title('Closed mask') fig.tight_layout() plt.show() return I_out I_out=my_preprocessing(x_test[5],True); x_train_prc=np.zeros_like(x_train) x_test_prc=np.zeros_like(x_test) for i in range(n_train): x_train_prc[i]=my_preprocessing(x_train[i]) for i in range(n_test): x_test_prc[i]=my_preprocessing(x_test[i]) ``` ![png](output_5_0.png) 此外,我们还人工从测试集中挑选了训练集中并未出现过的标签的五个样本,加入训练集中。 ```python from sklearn.preprocessing import MultiLabelBinarizer from sklearn.utils import shuffle # 五个异形在原数据中对应的下标 anno_idx=np.array([4949, 4956, 4973, 4974, 4988]) anno_idx=anno_idx[::-1] anno_idx_add=anno_idx[:num_anno] x_train_prc_anno=x_train_prc y_train_anno=y_train.reshape([-1,1]) x_add=x_test_prc[anno_idx_add] y_add=np.ones([num_anno,1])*2 # 对异形进行过采样 for i in range(4000/num_anno): x_train_prc_anno=np.append(x_train_prc_anno,x_add,axis=0) y_train_anno=np.append(y_train_anno,y_add,axis=0) x_train_prc_anno,y_train_anno = shuffle(x_train_prc_anno, y_train_anno, random_state=0) mlb1=MultiLabelBinarizer() y_train_mlb=mlb1.fit_transform(y_train_anno) ``` ### 3. 训练卷积神经网络 卷积神经网络(CNN)一般包括卷积层、池化层、全连接层。有时为了防止过拟合,我们也会加入dropout层。 在数据样本量较小时,我们也会进行数据增广。 ```python from keras.callbacks import TensorBoard from keras.layers import Dense, Dropout, MaxPooling2D, Flatten, Convolution2D from keras.models import Sequential from keras.optimizers import Adam from keras import backend as K from keras.preprocessing.image import ImageDataGenerator import tensorflow as tf tf.random.set_random_seed(SEED) session_conf = tf.ConfigProto(intra_op_parallelism_threads=1, inter_op_parallelism_threads=1) sess = tf.Session(graph=tf.get_default_graph(), config=session_conf) K.set_session(sess) def built_model(): n_filter=32; model = Sequential() model.add(Convolution2D(filters=n_filter, kernel_size=(5, 5), input_shape=(40, 40, 1), activation='relu')) model.add(Convolution2D(filters=n_filter, kernel_size=(5,5), activation='relu')) model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Convolution2D(filters=n_filter, kernel_size=(5,5), activation='relu')) model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Convolution2D(filters=n_filter, kernel_size=(3, 3), activation='relu')) model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Dropout(0.5)) model.add(Flatten()) model.add(Dense(units=128, activation='relu')) model.add(Dense(3, activation='softmax')) # Final Layer using Softmax model.compile(loss='categorical_crossentropy', optimizer=Adam(lr=0.0003), metrics=['accuracy']) model.summary() return model def train_model(x_train,y_train, x_test, batch_size=64, epochs=20, model=None, class_weight={0:1.,1:1.,2:10.}): if np.ndim(x_train)<4: x_train=np.expand_dims(x_train,3) x_test=np.expand_dims(x_test,3) if model is None: model = built_model() datagen = ImageDataGenerator( rotation_range=180, width_shift_range=0.1, height_shift_range=0.1, horizontal_flip=True ) # 训练模型的同时进行数据增广 history=model.fit_generator(datagen.flow(x_train, y_train, batch_size=batch_size), steps_per_epoch=len(x_train) / batch_size, epochs=epochs, class_weight=class_weight, validation_data=datagen.flow(x_train, y_train, batch_size=batch_size), validation_steps=1) print("Loss on training and testing.") plt.plot(history.history['loss'], label='train') plt.plot(history.history['val_loss'], label='valid') plt.legend() plt.show() pred_prob_train = model.predict(x_train, batch_size=batch_size, verbose=1) pred_train = np.array(pred_prob_train > 0.5).astype(int) pred_prob_test = model.predict(x_test, batch_size=batch_size, verbose=1) pred_test = np.array(pred_prob_test > 0.5).astype(int) y_test_hat=pred_test[:,1]+pred_test[:,2]*2; y_train_hat=pred_train[:,1]+pred_train[:,2]*2; return y_train_hat,y_test_hat,history ``` Using TensorFlow backend. ```python y_train_hat,y_test_hat,history=train_model(x_train_prc_anno, y_train_mlb,x_test_prc, epochs=epochs,batch_size=64,class_weight=class_weight) ``` _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= conv2d_1 (Conv2D) (None, 36, 36, 32) 832 _________________________________________________________________ conv2d_2 (Conv2D) (None, 32, 32, 32) 25632 _________________________________________________________________ max_pooling2d_1 (MaxPooling2 (None, 16, 16, 32) 0 _________________________________________________________________ conv2d_3 (Conv2D) (None, 12, 12, 32) 25632 _________________________________________________________________ max_pooling2d_2 (MaxPooling2 (None, 6, 6, 32) 0 _________________________________________________________________ conv2d_4 (Conv2D) (None, 4, 4, 32) 9248 _________________________________________________________________ max_pooling2d_3 (MaxPooling2 (None, 2, 2, 32) 0 _________________________________________________________________ dropout_1 (Dropout) (None, 2, 2, 32) 0 _________________________________________________________________ flatten_1 (Flatten) (None, 128) 0 _________________________________________________________________ dense_1 (Dense) (None, 128) 16512 _________________________________________________________________ dense_2 (Dense) (None, 3) 387 ================================================================= Total params: 78,243 Trainable params: 78,243 Non-trainable params: 0 _________________________________________________________________ Epoch 1/100 156/156 [==============================] - 4s 26ms/step - loss: 2.2816 - acc: 0.3979 - val_loss: 1.1561 - val_acc: 0.4688 Epoch 2/100 156/156 [==============================] - 2s 15ms/step - loss: 1.4215 - acc: 0.5093 - val_loss: 0.7161 - val_acc: 0.6562 Epoch 3/100 156/156 [==============================] - 2s 14ms/step - loss: 0.7764 - acc: 0.7068 - val_loss: 0.3253 - val_acc: 0.8594 Epoch 4/100 156/156 [==============================] - 2s 13ms/step - loss: 0.5159 - acc: 0.8224 - val_loss: 0.4067 - val_acc: 0.8281 Epoch 5/100 156/156 [==============================] - 2s 13ms/step - loss: 0.3667 - acc: 0.8801 - val_loss: 0.0952 - val_acc: 0.9688 ... ... Epoch 96/100 156/156 [==============================] - 2s 13ms/step - loss: 0.0201 - acc: 0.9949 - val_loss: 9.9051e-05 - val_acc: 1.0000 Epoch 97/100 156/156 [==============================] - 2s 13ms/step - loss: 0.0207 - acc: 0.9941 - val_loss: 0.0071 - val_acc: 1.0000 Epoch 98/100 156/156 [==============================] - 2s 13ms/step - loss: 0.0263 - acc: 0.9945 - val_loss: 6.1150e-04 - val_acc: 1.0000 Epoch 99/100 156/156 [==============================] - 2s 15ms/step - loss: 0.0200 - acc: 0.9945 - val_loss: 0.0016 - val_acc: 1.0000 Epoch 100/100 156/156 [==============================] - 3s 17ms/step - loss: 0.0300 - acc: 0.9934 - val_loss: 0.0015 - val_acc: 1.0000 Loss on training and testing. ![png](output_10_1.png) 10000/10000 [==============================] - 0s 46us/step 5191/5191 [==============================] - 0s 47us/step ### 5. 提交结果 最后的结果可以提交到<a href="http://sofasofa.io/competition.php?id=9#c4" target="_blank">这里</a>,来看看精度如何哦! ```python import pandas as pd submit = pd.read_csv('sample_submit.csv') submit['y'] = y_test_hat submit.to_csv('my_CNN_prediction.csv', index=False) ``` <ul class="pager"> <li class="next"><a href="../../tutorials.php"><b><i class="fa fa-graduation-cap" aria-hidden="true"></i>&nbsp; 学完咯!</b></a></li> </ul>