零基础入门CV赛事-Task2数据读取与数据扩增学习笔记
这次笔记为参与天池街道字符识别赛事中组队学习的第二篇学习笔记
赛题名称
- 赛题名称:零基础入门CV之街道字符识别
- 赛题目标:通过这道赛题可以引导大家走入计算机视觉的世界,主要针对竞赛选手上手视觉赛题,提高对数据建模能力。
- 赛题任务:赛题以计算机视觉中字符识别为背景,要求选手预测街道字符编码,这是一个典型的字符识别问题。
为了简化赛题难度,赛题数据采用公开数据集SVHN,因此大家可以选择很多相应的paper作为思路参考。
Task2 数据读取于数据扩增
2.1 学习目标
- 学习Python和Pytorch中图像读取
- 学会扩增方法和Pytorch读取赛题数据
2.2 图像读取
Python中图像数据读取的方式常见的有两种:Pillow和OpenCV。
Pillow能够提供常见的图像读取和处理的操作,而且与torchvision有着较好的交互性。
OpenCV由于发展的非常早,也常常用于计算机视觉、数字图像处理和机器视觉等功能。其学习成本由于功能上高于Pillow,从而需要花较多时间了解。
2.2.1 使用Pillow进行图像读取
Pillow库的安装
pip install Pillow
# 导入Pillow库
from PIL import Image, ImageFilter
# 图片读取
img = Image.open('cat.jpg')
# 图片处理
img2 = img.filter(ImageFilter.BLUR)
img3 = img.thumbnail((w//2, h//2))
# 图片保存
img2.save('cat_filter.jpg', 'jepg')
2.2.2 使用OpenCV进行图像读取
OpenCV除了可以像PIL读取数据和对图形形状的处理还有很多的图形特征算法,包括关键点检测、边缘检测和直线检测等等。
OpenCV安装
pip install opencv-python
# 导入OpenCV库
import cv2
# 图片读取
img = cv2.imread('cat.jpg')
#OpenCV默认颜色通道顺序是BRG,需要转换成RGB
img1 = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
# 图片处理
img2 = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 转换为灰度图像
# 边缘检测
img3 = cv2.Canny(img2, 30, 70)
# 图片保存
cv2.imwrite('canny.jpg', edges)
在这次赛题学习中,Baseline中给定的图像读取代码使用Pillow库中Image类读取,在其余部分也未曾见OpenCV的声影,所以我尝试这使用OpenCV来代替Image,并且通过查阅资料发现OpenCV可以使用CUDA来进行多通道读取图像,所以代码实现为以下:
cv2.setNumThreads(4)
img = cv2.imread(self.img_path[index])
img = cv2.UMat(img)
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
img = cv2.UMat.get(img)
img = Image.fromarray(img.astype(np.uint8))
在不是用CUDA加速读取时可以不用添加UMat(),之后运行了几遍小的epoch后,发现,这样提速的效果不明显,由于我的才疏浅陋,并不能使它与torchvision有着良好的交互性,使用了Image.fromarray
将cv2输出的array数组转换为PIL类,所以最后还是使用最初的方法:
img = Image.open(self.img_path[index]).convert('RGB')
2.3 数据增强方法
使用固定规则的图像进行训练模型是远远不够的,这时就需要进行数据增强,可以有效的缓解模型过拟合的情况,也可以给模型带来更强的泛化能力。
2.3.1 常见的数据扩增方法
在常见的数据扩增方法中,一般会从图像颜色、尺寸、形态、空间和像素等角度进行变换。当然不同的数据扩增方法可以自由进行组合,得到更加丰富的数据扩增方法。
以torchvision为例,常见的数据扩增方法包括:
- transforms.CenterCrop 对图片中心进行裁剪
- transforms.ColorJitter 对图像颜色的对比度、饱和度和零度进行变换
- transforms.FiveCrop 对图像四个角和中心进行裁剪得到五分图像
- transforms.Grayscale 对图像进行灰度变换
- transforms.Pad 使用固定值进行像素填充
- transforms.RandomAffine 随机仿射变换
- transforms.RandomCrop 随机区域裁剪
- transforms.RandomHorizontalFlip 随机水平翻转
- transforms.RandomRotation 随机旋转
- transforms.RandomVerticalFlip 随机垂直翻转
2.3.2 常用的数据扩增库
- torchvision
https://github.com/pytorch/vision
pytorch官方提供的数据扩增库,提供了基本的数据数据扩增方法,可以无缝与torch进行集成;但数据扩增方法种类较少,且速度中等;
- imgaug
https://github.com/aleju/imgaug
imgaug是常用的第三方数据扩增库,提供了多样的数据扩增方法,且组合起来非常方便,速度较快;
- albumentations
https://albumentations.readthedocs.io
是常用的第三方数据扩增库,提供了多样的数据扩增方法,对图像分类、语义分割、物体检测和关键点检测都支持,速度较快。
2.4 心得体会
赛事组队学习到现在,也渐渐对赛题理解越来越清晰,在考虑训练出好的模型时,同样会考虑模型处理的效率,使用jupyter运行baseline,每个epoch运行时间耗时大约为150s,而模型构造成熟往往不是用一两个epoch就能完成的,由于jupyter是单线程操作,在使用cuda多线程读取数据时,会产生报错信息,这里我先将baseline中的代码在pycharm中实现,其中会将一些代码用函数的形式将其封装,这样,在我的win10环境下也能够在DataLoader类中可以将num_workers设置成大于0的值,同时调整batch_size的是值,使用GPU在短时间内读取相比之前有着更多的数据量,同时将pin_memory设置为True,最终每个epoch运行时间减小为90s,心满意足的开始进行下一步。