前端工程师也能玩转深度学习--数据集处理篇

avatar
阿里巴巴 前端委员会智能化小组 @阿里巴巴

文/ 阿里淘系 F(x) Team - 禹喆

前言

当下,人工智能多次被提到国家战略,其发展势头可称得上是互联网行业之最,在各个大厂都疯狂招揽AI相关人才的同时,人工智能行业的入门门槛也越来越高。但是,人工智能真正要落地,离不开各行各业的工程师。传统意义上讲,将人工智能引入到工程中大概是这样的过程:收集数据集->处理数据集->定义模型->训练模型->模型调参->开发模型服务->模型部署->加入工程链路。
首先声明,本篇文章仅适用于图片分类数据集的处理,大家如果已经拥有了自己的图片数据集,例如传统的mnist,猫狗数据集这种,以文件夹名称为图片的标签,就直接进入数据增强和数据集划分,数据增强是本篇文章的重点所在,下面会重点介绍。
作为阿里巴巴-淘系技术部-频道与D2C智能团队的一员,我们的使命就是:前端智能让业务创新更⾼效。整个的过程有一定的上手难度,不过不用担心,小编会从实际项目入手,一步步为你揭开AI的神秘面纱。

数据增强

数据增强可以说是极其关键的一步,一套更加丰富的数据集对模型能力的提升是非常大的,小编将传统的各种图片数据增强的方法都集成到一起并且随机化,包括图片的裁剪,翻转,局部遮挡,像素模糊等等。
无论是使用TensorFlow还是PyTorch,都有自带的一些数据增强方法,在这里小编为亲准备了一套更专业,随机化程度更高的数据增强方法,主要使用imgaug,有兴趣的小伙伴可以去官网浏览哦 imgaug官网 可见一张图片就能有许多种变换方式,通过数据增强可以使得数据集更加丰富。
image.png
在方法中小编定义了很多种数据增强的方法,对于每个数据文件夹,随机选取2-5种方法对数据进行增强,很大程度上保证了数据的不重复性。话不多说,直接上代码

import cv2
from imgaug import augmenters as iaa
import os

sometimes = lambda aug: iaa.Sometimes(0.5, aug)
# 定义一组变换方法.
seq = iaa.Sequential([
    # 选择2到5种方法做变换
    iaa.SomeOf((2, 5),
        [
                iaa.Fliplr(0.5), # 对50%的图片进行水平镜像翻转
                iaa.Flipud(0.5), # 对50%的图片进行垂直镜像翻转  

                sometimes(
                    iaa.Superpixels(
                        p_replace=(0, 1.0),
                        n_segments=(20, 200)
                    )
                ),
                iaa.OneOf([
                    iaa.GaussianBlur((0, 3.0)),
                    iaa.AverageBlur(k=(2, 7)),
                    iaa.MedianBlur(k=(3, 11)),
                ]),
                iaa.Sharpen(alpha=(0, 1.0), lightness=(0.75, 1.5)),
                iaa.Emboss(alpha=(0, 1.0), strength=(0, 2.0)),
                iaa.AdditiveGaussianNoise(
                    loc=0, scale=(0.0, 0.05*255)
                ),
                iaa.Invert(0.05, per_channel=True), 
                iaa.Add((-10, 10), per_channel=0.5),
                iaa.AddElementwise((-40, 40)),
                iaa.Multiply((0.5, 1.5)),
                iaa.MultiplyElementwise((0.5, 1.5)),
                iaa.ContrastNormalization((0.5, 2.0)),
        ],
        random_order=True
    )
 
],random_order=True) #apply augmenters in random order
 
# 图片文件相关路径
path = 'cat'
savedpath = 'cat-aug'
 
imglist=[]
filelist = os.listdir(path)
 
# 遍历要增强的文件夹,把所有的图片保存在imglist中
for item in filelist:
    if(item == '.DS_Store'):
        continue
    img = cv2.imread(path +'/'+ item)
    imglist.append(img)
print('all the picture have been appent to imglist')
print(len(imglist))
 
#对文件夹中的图片进行增强操作,循环n次,n为数据集扩充的倍数,可以自己设置哦
for count in range(4):
    images_aug = seq.augment_images(imglist)
    for index in range(len(images_aug)-1):
        filename = str(count) + str(index) +'.jpg'
        #保存图片
        cv2.imwrite(savedpath +'/'+ filename,images_aug[index])
        print('image of count%s index%s has been writen'%(count,index))

亲们可以定义自己的数据增强方法,建议尽量增大样本扩充的随机性,以上方法即使在普通的电脑上速度也非常快,但是考虑到深度学习的图片数据集比较大,所以脚本的输入是一个图片文件夹,亲们可以先准备少量的数据实验一下~

数据集划分

在进行模型训练之前,最好能够将数据集切分为训练集,测试集和验证集,训练集用于模型拟合的数据样本;验证集是模型训练过程中单独留出的样本集,它可以用于调整模型的超参数和用于对模型的能力进行初步评估;测试集用来评估模最终模型的泛化能力,但不能作为调参、选择特征等算法相关的选择的依据。

# 将一个文件夹下图片按比例分在三个文件夹下
import os
import random
import shutil
from shutil import copy2
datadir_normal = "./cat-aug"

all_data = os.listdir(datadir_normal)#(图片文件夹)
num_all_data = len(all_data)
print( "num_all_data: " + str(num_all_data) )
index_list = list(range(num_all_data))
random.shuffle(index_list)
num = 0

trainDir = "./train/cat"#(将训练集放在这个文件夹下)
if not os.path.exists(trainDir):
    os.mkdir(trainDir)
        
validDir = './validation/cat'#(将验证集放在这个文件夹下)
if not os.path.exists(validDir):
    os.mkdir(validDir)
        
testDir = './test/cat'#(将测试集放在这个文件夹下)        
if not os.path.exists(testDir):
    os.mkdir(testDir)
        
for i in index_list:
    fileName = os.path.join(datadir_normal, all_data[i])
    if num < num_all_data*0.8:
        copy2(fileName, trainDir)
    elif num>num_all_data*0.8 and num < num_all_data*0.9:
        copy2(fileName, validDir)
    else:
        copy2(fileName, testDir)
    num += 1
num_train = len(os.listdir(trainDir))
print('num_train:' + str(num_train))

num_test = len(os.listdir(testDir))
print('num_test:' + str(num_test))

num_val = len(os.listdir(validDir))
print('num_val:' + str(num_val))

以上代码是按照3:1:1来划分数据集的,比较经典,大家也可以自己去调整划分的比例

写在最后

处理数据集的方法千变万化,作为算法模型的“养料”,数据集的质量直接决定了模型的能力,以上只是算法工程中模型训练之前的一部分,小编会继续出一系列的文章,和大家一起愉快地走进AI的大门。