在第一篇实战里说过测试集分数还有比较大的提升空间,深度学习里有一句话:garbage in,garbage out。如果我们喂进去的图片质量差,那么训练后的模型肯定不理想。所以在第一篇的基础上,通过从以下方面考虑提升模型质量。1、进行图片预处理,提高喂进去图片的质量。2、进行数据增强,增加样本数量。3、使用多种模型进行预测,最后做个ensemble。
plus代码:https://github.com/872699467/Plant-Pathology-Plus
图片预处理
对初始图片先进行高斯模糊,取出噪点,再使用Canny算子对训练集和测试集的图片进行边缘检测,并进行裁切将多余的背景去除。将得到的边界框坐标(x1,y1,x2,y2)保存到csv文件中。关于Canny算子的工作原理,可参考https://blog.csdn.net/fengye2two/article/details/79190759
# Canny边缘检测并进行bounding box切割
def edge_and_cut(img):
emb_img = img.copy()
img = cv2.GaussianBlur(img, ksize=(5, 5), sigmaX=0)
edges = cv2.Canny(img, 100, 200)
nonzero = edges.nonzero()
# 未检测到边缘
if len(nonzero[0]) == 0 or len(nonzero[1]) == 0:
col_min = 0
row_min = 0
col_max = img.shape[1]
row_max = img.shape[0]
else:
col_min = min(nonzero[1])
row_min = min(nonzero[0])
col_max = max(nonzero[1])
row_max = max(nonzero[0])
emb_img[row_min - 10:row_min + 10, col_min:col_max] = [255, 0, 0]
emb_img[row_max - 10:row_max + 10, col_min:col_max] = [255, 0, 0]
emb_img[row_min:row_max, col_min - 10:col_min + 10] = [255, 0, 0]
emb_img[row_min:row_max, col_max - 10:col_max + 10] = [255, 0, 0]
fig, ax = plt.subplots(nrows=1, ncols=3, figsize=(30, 20))
ax[0].imshow(img, cmap='gray')
ax[0].set_title('Original Image', fontsize=24)
ax[1].imshow(edges, cmap='gray')
ax[1].set_title('Canny Edges', fontsize=24)
ax[2].imshow(emb_img, cmap='gray')
ax[2].set_title('Bounding Box', fontsize=24)
plt.show()
return (col_min, row_min, col_max, row_max)
当我们再进行模型训练时,就只是将下图红色边界框的图片喂到模型中,剔除了无用的背景像素,提高了数据的质量。
边缘检测效果
数据增强
由于训练集的图片数量不多,所以我们可以用cv2的一系列操作进行图片的变化,增加训练集的数量。
一、水平/垂直翻转
# 垂直/水平翻转
def invert(img):
fig, ax = plt.subplots(nrows=1, ncols=3, figsize=(30, 20))
ax[0].imshow(img)
ax[0].set_title('Original Image', fontsize=24)
ax[1].imshow(cv2.flip(img, 0))
ax[1].set_title('Vertical Flip', fontsize=24)
ax[2].imshow(cv2.flip(img, 1))
ax[2].set_title('Horizontal Flip', fontsize=24)
plt.show()
水平/垂直翻转
二、卷积
他使得图像是在强光照射下拍摄,这是由于np.ones(7,7)之和为49,而除数是36,所以增加了图片的亮度。如果除数是49,就是平滑操作了。而除数大于49,则整体亮度减少,像是阴天拍摄的。
# 卷积操作
def conv(img):
fig, ax = plt.subplots(nrows=1, ncols=2, figsize=(20, 20))
kernel = np.ones((7, 7), np.float32) / 36
conv = cv2.filter2D(img, -1, kernel)
ax[0].imshow(img)
ax[0].set_title('Original Image', fontsize=24)
ax[1].imshow(conv)
ax[1].set_title('Convolved Image', fontsize=24)
plt.show()
除数为36,整体亮度变亮
除数为64,整体亮度变暗
三、模糊
# 模糊操作
def blur(img):
fig, ax = plt.subplots(nrows=1, ncols=2, figsize=(20, 20))
ax[0].imshow(img)
ax[0].set_title('Original Image', fontsize=24)
ax[1].imshow(cv2.blur(img, (30, 30)))
ax[1].set_title('Blurred Image', fontsize=24)
plt.show()
模糊操作
Ensemble
Ensemble有点三个臭皮匠顶过一个诸葛亮的意思,如果你只用一个模型预测,预测结果的好坏只由你一个模型决定,但是如果我用多个模型预测,再将得到的结果按照一定的权重进行结合,往往只比一个模型的预测结果要好。Ensemble的特点为:1、将多个分类方法聚集在一起,以提高分类的准确率。2、由训练数据构建一组基分类器,然后通过对每个基分类器的预测进行投票来进行分类。3、如果把单个分类器比作一个决策者的话,Ensemble的方法就相当于多个决策者共同进行一项决策。
我分别用resnet18和densenet121进行了交叉验证,每一折训练15个epoch。
一、resnet18的损失变化和训练集得分
最终训练集的得分为:0.998847
resnet18训练集得分
二、densenet121的损失变化和训练集得分
densenet121的训练集和验证集损失变化
最终训练集的得分为:0.996672
densenet121训练集得分
最后将两个模型预测的得到进行ensemble。
squeezenet_res = pd.read_csv('results/resnet_results.csv').iloc[:, [1, 2, 3, 4]].values
densenet_res = pd.read_csv('results/densenet_result.csv').iloc[:, [1, 2, 3, 4]].values
sub = pd.read_csv('data/sample_submission.csv')
ensemble_1, ensemble_2, ensemble_3 = [sub] * 3
ensemble_1.iloc[:, [1, 2, 3, 4]] = 0.25 * squeezenet_res + 0.75 * densenet_res
ensemble_2.iloc[:, [1, 2, 3, 4]] = 0.5 * squeezenet_res + 0.5 * densenet_res
ensemble_3.iloc[:, [1, 2, 3, 4]] = 0.75 * squeezenet_res + 0.25 * densenet_res
ensemble_1.to_csv('results/submission_ensemble_1.csv', index=False)
ensemble_2.to_csv('results/submission_ensemble_2.csv', index=False)
ensemble_3.to_csv('results/submission_ensemble_3.csv', index=False)
将第一个emseble_1提交,最终得分为0.965,比第一篇的0.919高出不少。
得分情况
网友评论