Kaggle竞赛排名Top 10% —— 手写数字识别Digit Recognizer
2018-02-26 16:17
756 查看
介绍
这个比赛是Kaggle上的一个手写数字识别比赛,主要供新手进行入门学习,所需相关数据可到该网站下载。下面的Demo主要是以深度学习框架Keras搭建的卷积神经网络CNN为模型,比赛成绩为Top10%,该Demo提供了比赛的基本思路,如有错漏或相关问题,欢迎提出。
源码地址为:https://github.com/Zheng-Wenkai/Kaggle_DigitRecognizer
一、数据总览
1.1 查看数据基本情况
originPath='E:\\Data\\kaggle\\DigitRecognizer\\' train_data=pd.read_csv(originPath+'train.csv') test_data=pd.read_csv(originPath+'test.csv') train_data.info() print('_____________________________________________________') test_data.info()
运行结果:
RangeIndex: 42000 entries, 0 to 41999 Columns: 785 entries, label to pixel783 _____________________________________________________ RangeIndex: 28000 entries, 0 to 27999 Columns: 784 entries, pixel0 to pixel783
由运行结果可知,train_data有42000行,行名称由0到41999,有785列,列名称由label到pixel783。test_data同理
1.2 查看是否存在缺失值
isnull()判断是否有缺失值;any()返回是否有任何元素在请求轴上为真(会将DataFrame转为Series),若axis=0则以columns为单位,若axis=1则以index为单位,axis默认为0;
describe()对数据进行描述性统计(对象属性会返回count计数和,unique不重复的值的数量,top最常见的值的value,freq最常见的值的频率)
print(train_data.isnull().any().describe()) print('_____________________________________________________') print(test_data.isnull().any().describe())
运行结果:
count 785 unique 1 top False freq 785 dtype: object _____________________________________________________ count 784 unique 1 top False freq 784 dtype: object
由运行结果可知,该数据集不存在缺失值;若存在缺失值,还需要另外加以处理
1.3 查看训练集标签Y的情况
X_train=train_data.drop(columns=['label']) Y_train=train_data.label del train_data # 绘制计数直方图 sns.countplot(Y_train) plt.show() # 使用pd.Series.value_counts() print(Y_train.value_counts())
运行结果
由运行结果可知,训练集数据均匀;若数据不均匀(即某一类的数据集数量多,而某一类的数据集数量少),则需要对数据进行处理(如数据扩增或增加新的训练样本)
二、建立base_model
2.1 数据预处理
X_train=train_data.drop(columns=['label']) Y_train=train_data.label del train_data # 改变维度:第一个参数是图片数量,后三个参数是每个图片的维度 X_train = X_train.values.reshape(-1,28,28,1) test_data = test_data.values.reshape(-1,28,28,1) print(X_train.shape) print(test_data.shape) print("Train Sample:",X_train.shape[0]) print("Test Sample:",test_data.shape[0]) # 归一化:将数据进行归一化到0-1 因为图像数据最大是255 X_train=X_train/255.0 test_data=test_data/255.0 # 将类别向量(从0到nb_classes的整数向量)映射为二值类别矩阵 Y_train = to_categorical(Y_train, num_classes = nb_classes) X_train,X_val,Y_train,Y_val=train_test_split(X_train,Y_train,test_size=0.1) plt.imshow(X_train[0][:,:,0], cmap="Greys") plt.show()
运行结果:
由运行结果可知,数据处理成功将csv数据转化成图片
2.2 建立CNN模型
model = Sequential() # filters:卷积核的数目(即输出的维度) # kernel_size:卷积核的宽度和长度。如为单个整数,则表示在各个空间维度的相同长度。 model.add(Conv2D(filters = 32, kernel_size = (5,5),activation ='relu', input_shape = (28,28,1))) model.add(Conv2D(filters = 32, kernel_size = (5,5),activation ='relu')) model.add(MaxPool2D(pool_size=(2,2))) model.add(Dropout(0.25)) model.add(Conv2D(filters = 64, kernel_size = (3,3),activation ='relu')) model.add(Conv2D(filters = 64, kernel_size = (3,3),activation ='relu')) model.add(MaxPool2D(pool_size=(2,2), strides=(2,2))) model.add(Dropout(0.25)) model.add(Flatten()) model.add(Dense(256, activation = "relu")) model.add(Dropout(0.5)) model.add(Dense(10, activation = "softmax"))
2.3 编译和训练模型
optimizer=RMSprop(lr=0.001, rho=0.9, epsilon=1e-08, decay=0.0) # 使用多类的对数损失categorical_crossentropy model.compile(loss='categorical_crossentropy', optimizer=optimizer, metrics=['accuracy']) history=model.fit(X_train,Y_train, batch_size=batch_size, epochs=nb_epoch, verbose=2, validation_data=(X_val,Y_val))
三、评估base_model
3.1 查看验证集的loss和accuracy
score = model.evaluate(X_val, Y_val, verbose=0) print('Val loss:', score[0]) print('Val accuracy:', score[1])
由运行结果可知,验证集的accuracy为98.9%
3.2 绘制学习曲线
fig, ax = plt.subplots(2,1) ax[0].plot(history.history['loss'], color='b', label="Training loss") ax[0].plot(history.history['val_loss'], color='r', label="validation loss",axes =ax[0]) ax[0].legend(loc='best', shadow=True) ax[1].plot(history.history['acc'], color='b', label="Training accuracy") ax[1].plot(history.history['val_acc'], color='r',label="Validation accuracy") ax[1].legend(loc='best', shadow=True) plt.show()
运行结果:
由运行结果可知,validation 的 loss 和 accuracy 的波动较大,且traning的学习曲线情况优于validation,故base_model出现了轻微的过拟合现象。
3.3 查看混淆矩阵
混淆矩阵的每一列代表了预测类别 ,每一列的总数表示预测为该类别的数据的数目;每一行代表了数据的真实归属类别,每一行的数据总数表示该类别的数据实例的数目。def plot_confusion_matrix(cm, classes, normalize=False, title='Confusion matrix', cmap="Blues"): """ This function prints and plots the confusion matrix. Normalization can be applied by setting `normalize=True`. """ plt.imshow(cm, interpolation='nearest', cmap=cmap) plt.title(title) plt.colorbar() tick_marks = np.arange(len(classes)) plt.xticks(tick_marks, classes, rotation=45) plt.yticks(tick_marks, classes) # 是否进行标准化 if normalize: cm = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis] thresh = cm.max() / 2. for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])): plt.text(j, i, cm[i, j], horizontalalignment="center", color="white" if cm[i, j] > thresh else "black") plt.tight_layout() plt.ylabel('True label') plt.xlabel('Predicted label') plt.show() # 根据验证集标签的真实值和预测值计算混淆矩阵(confusion_matrix) Y_pred = model.predict(X_val) Y_pred_classes = np.argmax(Y_pred,axis = 1) Y_true = np.argmax(Y_val,axis = 1) confusion_mtx = confusion_matrix(Y_true, Y_pred_classes) # 绘制混淆矩阵 plot_confusion_matrix(confusion_mtx, classes = range(10))
运行结果:
由运行结果可知:错误分类主要集中在对7的分类(其中有8个样本被从9误分类为7),混淆矩阵可以为我们进一步优化模型提供指导。
3.4 查看最显著的错误
def display_errors(errors_index,img_errors,pred_errors, obs_errors): n = 0 nrows = 2 ncols = 3 fig, ax = plt.subplots(nrows,ncols,sharex=True,sharey=True) for row in range(nrows): for col in range(ncols): error = errors_index ax[row,col].imshow((img_errors[error]).reshape((28,28)),cmap="Greys") ax[row,col].set_title("Predicted label :{}\nTrue label :{}".format(pred_errors[error],obs_errors[error])) n += 1 plt.show() errors = (Y_pred_classes - Y_true != 0) # 矩阵相减得到误差集(?*1) # 使用布尔索引 Y_pred_classes_errors = Y_pred_classes[errors] # 误差集的预测标签Y(?*1) Y_pred_errors = Y_pred[errors] # 误差集的预测序列(?*10) Y_true_errors = Y_true[errors] # 误差集的真实标签Y(?*1) X_val_errors = X_val[errors] # 误差集的特征X,即数字图片(?*28*28*1) # 误差集中对错误标签的预测概率 Y_pred_errors_prob = np.max(Y_pred_errors,axis = 1) # 误差集中对真实标签的预测概率,np.diagonal是返回对角线的元素 true_prob_errors = np.diagonal(np.take(Y_pred_errors, Y_true_errors, axis=1)) delta_pred_true_errors = Y_pred_errors_prob - true_prob_errors # 排序并返回的是数组值从小到大的索引值 sorted_dela_errors = np.argsort(delta_pred_true_errors) most_important_errors = sorted_dela_errors[-6:] display_errors(most_important_errors, X_val_errors, Y_pred_classes_errors, Y_true_errors)
运行结果:
可视化错误分类的样本(可以通过对代码的修改来调整可视化样本的数量),从而可以得知错误分类的具体情况,为我们进一步优化模型提供指导。
四、模型的进一步优化
4.1 数据扩增
# 用以生成一个batch的图像数据,支持实时数据提升 datagen = ImageDataGenerator( featurewise_center=False, # set input mean to 0 over the dataset samplewise_center=False, # set each sample mean to 0 featurewise_std_normalization=False, # divide inputs by std of the dataset samplewise_std_normalization=False, # divide each input by its std zca_whitening=False, # apply ZCA whitening rotation_range=10, # randomly rotate images in the range (degrees, 0 to 180) zoom_range = 0.1, # Randomly zoom image width_shift_range=0.1, # randomly shift images horizontally (fraction of total width) height_shift_range=0.1, # randomly shift images vertically (fraction of total height) horizontal_flip=False, # randomly flip images vertical_flip=False) # randomly flip images
4.2 学习率自适应
当评价指标val_acc不在提升时,减少学习率learning_rate_reduction = ReduceLROnPlateau(monitor='val_acc', patience=3, verbose=1, factor=0.5, min_lr=0.00001)
4.3 训练和编译模型
optimizer=RMSprop(lr=0.001, rho=0.9, epsilon=1e-08, decay=0.0) # 使用多类的对数损失categorical_crossentropy model.compile(loss='categorical_crossentropy', optimizer=optimizer, metrics=['accuracy']) history = model.fit_generator(datagen.flow(X_train,Y_train, batch_size=batch_size), epochs =nb_epoch, validation_data = (X_val,Y_val), verbose = 2, steps_per_epoch=X_train.shape[0] // batch_size+1, callbacks=[learning_rate_reduction])
4.4 评估优化模型
评估步骤与上述相同,这里不再重复1、学习曲线
Validation的学习曲线较为稳定,且过拟合现象明显下降,模型准确率由0.989上升为0.995。
2、混淆矩阵
3、最显著的错误
4.5 关于模型优化的进一步建议
可以使用集成模型,具体可参考机器学习 —— 集成学习已尝试了bagging集成中的投票模型(通过对测试集进行数据扩增,使用同一模型对同一图片的不同变化进行多次评估),但模型准确度下降,故不贴出代码
对模型进行改造:可以使用最新的CapsulesNet胶囊网络或尝试其他模型,而不是使用当前的CNN模型
进一步挖掘新的特征
五、对测试集进行预测
print('Begin to predict for testing data ...') results = model.predict(test_data) results = np.argmax(results,axis = 1) results = pd.Series(results,name="Label") submission = pd.concat([pd.Series(range(1,28001),name = "ImageId"),results],axis = 1) submission.to_csv(originPath+"submit.csv",index=False)
六、在kaggle上提交预测结果
该模型对测试集预测的准确率达到0.99614,在kaggle上的排名为Top10%
相关文章推荐
- 基于机器学习多种方法的kaggle竞赛入门之手写数字的图像识别预测
- kaggle-Digit Recognition(手写数字识别)
- 【Kaggle笔记】手写数字识别分类(线性支持向量机)
- Kaggle Digit Recognizer 基于sklearn实现的手写数字识别 for MNIST data
- 利用scikit-learn下的knn实现kaggle的手写数字识别问题
- Lamda新论文gcForest测试-手写数字测试识别详解(Kaggle数据集)
- Sklearn-手写数字识别 & kaggle
- kaggle入门篇一【手写数字识别】
- 在Kaggle手写数字数据集上使用Spark MLlib的朴素贝叶斯模型进行手写数字识别
- 在Kaggle手写数字数据集上使用Spark MLlib的RandomForest进行手写数字识别
- kaggle竞赛流程简介——以手写识别为例
- knn算法实现的数字手写识别
- caffe的python接口学习(4):mnist实例---手写数字识别
- 手写数字识别hebb和SVM
- 深度学习引论(四):手写数字识别(Step by step)
- SVM 手写数字识别
- 手把手入门神经网络系列(2)_74行代码实现手写数字识别
- Caffe学习-手写数字识别
- CNN:人工智能之神经网络算法进阶优化,六种不同优化算法实现手写数字识别逐步提高,应用案例自动驾驶之捕捉并识别周围车牌号—Jason niu
- 使用OPENCV训练手写数字识别分类器