移动测试开发 少数据量情况下的深度学习模型训练效果提升技巧
背景
在进行目标识别的过程中,获取大量的数据是一件比较困难的事,但好的模型往往是基于大的数据集训练而来的。数据量较少时,模型性能难以达到理想的状态。尤其是在做项目的过程中,用户上传的测试数据与我们用于训练的数据之间的差异难以把控,可能会因为一些不相干的因素(角度不同,模糊度不同,目标大小不同等)的干扰而导致识别的效果不够理想。因此,需要进一步的丰富训练数据的表现,从而提高模型的鲁棒性,达到更好的识别目标的目的。
核心技术与架构图
针对不同的数据,应根据数据和待识别目标的特点对数据集进行扩充,目前大多数目标识别框架都做了相关的数据扩充,但这些数据扩充的方式不一定适合自己的训练数据,因此要结合自己数据,避免重复和无意义的操作。
技术优势
相较于原始数据,扩充后的数据在形态和细节上更加丰富,重要特征更加明显,可避免不相干特征对重要特征的干扰。尤其是当待识别的目标较小,模糊不清时,通过相关的扩充技术,可让训练出的模型参数更优。即使待识别的图像存在一些缺陷,也能够准确的识别出目标。
技术实现
以识别手机中的固定标志为例:
下图为一张手机图片,上边有四个固定的标志,我们的目的是识别出这四个标志。由于根据原始数据训练出的模型的识别效果较差,因此对原始数据进行多种变换,将数据集进行扩充。
(1) 旋转
当我们识别的目标在图像中所处位置存在角度变化时,就需要排除这种角度干扰,可通过随机旋转的方式进行数据的扩充,让最终的模型能够识别不同角度的该目标。
random_angle = np.random.randint(1, 360)
img_rote = image.rotate(random_angle, mode)
(2) 翻转(水平/垂直)
当目标在图像中的朝向不是固定的时候(即朝向不能作为一个特征的时候),就需要对数据进行水平或垂直方向上的翻转,从而避开朝向(与角度类似)的干扰,使得模型能够识别各个朝向的该目标。
image = image.transpose(Image.FLIP_LEFT_RIGHT)
(3) 随机裁剪
随机裁剪相当于建立每个因子特征与相应类别的权重关系,减弱背景 (或噪音) 因子的权重,且使模型面对缺失值不敏感,也就可以产生更好的学习效果,增加模型稳定性。
crop_win_size = np.random.randint(250, 360)
random_region = ((image_width - crop_win_size) >>1, (image_height - crop_win_size) >>1, (image_width + crop_win_size) >>1, (image_height + crop_win_size) >>1)
(4) 缩放
图像按照一定的比例进行放大和缩小并不改变图像中的内容,对样本进行随机尺度变换,实现多尺度训练,进而跨尺度特征融合,使得模型对于不同尺度的图像有更强的适应性,可以增加模型的泛化性能。
image = image.resize((nw, nh), Image.BICUBIC)
new_image = Image.new('RGB', target_size, (128, 128, 128))
new_image.paste(image, ((w - nw) // 2, (h - nh) // 2))
(5) 随机色彩抖动
颜色抖动是指对图像的曝光度(exposure)、饱和度(saturation)和色调(hue)进行随机变化形成不同光照及颜色下的图片,达到数据增强的目的,尽可能使得模型能够使用不同光照条件小的情形,提高模型泛化能力。
random_factor = np.random.randint(0, 31) / 10.
img_color = ImageEnhance.Color(image).enhance(random_factor) # 调整图像的饱和度
img_brightness = ImageEnhance.Brightness(color_image).enhance(random_factor)# 调整图像的亮度
img_contrast = ImageEnhance.Contrast(brightness_image).enhance(random_factor)# 调整图像的对比度
img_sharpness = ImageEnhance.Sharpness(contrast_image).enhance(random_factor)# 调整图像锐化度
(6) 模糊化
当所需识别的目标比较模糊时,此时通过清晰数据训练而来的模型很难识别模糊的数据,因此为了缓解图像模糊而造成的误识别,对图像加入高斯噪声来模拟模糊情况,从而提升模型的性能。
img_blur = cv2.GaussianBlur(image, kernel_size, sigma)
(7) 透明化
当图像透明度不同时也会对目标的识别造成干扰,因此需要在透明度上来丰富数据集。
b_channel, g_channel, r_channel = cv2.split(image)
alpha_channel = np.ones(b_channel.shape, dtype=b_channel.dtype) * 255
alpha_channel[:, :int(b_channel.shape[0])] = 180
img_BGRA = cv2.merge((b_channel, g_channel, r_channel, alpha_channel))
(8) 分块
小目标的识别一直是目标检测中的难点,如果目标在图像中的位置范围较为固定,可采取分块的方式,将图像中的各个目标切分出来以排除其他目标的干扰,用于训练和预测。从而提升小目标识别的准确度。
img_block = image[int(h*1 / 9):int(h*1 / 2), :int(w *9/ 24), :]
效果展示
下图分别展示了未经数据扩充和数据扩充后训练出模型对两张新的图像的测试效果,可看出,后者对目标的识别精准度明显得到了提升,尤其是在模糊的小目标的识别上表现更好。
总结
数据扩充已被证明是一种有效的提高模型鲁棒性的方法,扩充的方法也有很多,但需要结合自己的数据和目标的特征进行具体分析,选择合适的方法,才能有效的提升模型的性能。