第 T10 周:数据增强

第 T10 周:数据增强 声明本文为「365 天深度学习训练营」内部学习记录。本文参考 K 同学啊课程内容完成仅用于个人学习与交流。猫狗识别数据集仅用于学习交流请勿对外分享数据集。本篇为个人在 T10 关卡上的实践记录。第 T10 周数据增强在本教程中你将学会如何进行数据增强并通过数据增强用少量数据达到非常棒的识别准确率。本文将展示两种数据增强方式以及如何自定义数据增强方式并将其放到代码当中。难度夯实基础语言Python3、TensorFlow2本周要求学会在代码中使用数据增强手段来提高 acc请探索更多的数据增强手段并记录我的环境语言环境Python 3.6.5实践环境可用更新版本编译器Jupyter Notebook深度学习框架TensorFlow 2.4.1实践环境TensorFlow 2.11实验数据34-data.zip25.2 MB数据目录34-data/2 类cat/dog各300张共600张两种增强接入方式方式做法特点方法一增强模块嵌入model可走 GPU 加速仅Model.fit时生效方法二在Dataset中map在数据流水线里做增强灵活可组合一、前期准备工作1. 设置 GPU如果使用的是 CPU 可以注释掉这部分代码。importtensorflowastffromtensorflow.kerasimportlayersimportmatplotlib.pyplotaspltimportnumpyasnpimportrandomimportwarnings warnings.filterwarnings(ignore)gpustf.config.list_physical_devices(GPU)ifgpus:tf.config.experimental.set_memory_growth(gpus[0],True)# 设置 GPU 显存用量按需使用tf.config.set_visible_devices([gpus[0]],GPU)print(gpus)2. 加载数据关于tf.keras.preprocessing.image_dataset_from_directory的介绍可参考CSDN 讲解。由于原始数据集不包含测试集因此需要创建一个。使用tf.data.experimental.cardinality确定验证集中有多少批次然后将其中的20%移至测试集。一共有猫、狗两类。data_dir./34-dataimg_height224img_width224batch_size32train_dstf.keras.preprocessing.image_dataset_from_directory(data_dir,validation_split0.3,subsettraining,seed12,image_size(img_height,img_width),batch_sizebatch_size)val_dstf.keras.preprocessing.image_dataset_from_directory(data_dir,validation_split0.3,subsetvalidation,seed12,image_size(img_height,img_width),batch_sizebatch_size)预期输出Found 600 files belonging to 2 classes. Using 420 files for training. Found 600 files belonging to 2 classes. Using 180 files for validation.class_namestrain_ds.class_namesprint(class_names)预期输出[cat, dog]从验证集再拆出测试集val_batchestf.data.experimental.cardinality(val_ds)test_dsval_ds.take(val_batches//5)val_dsval_ds.skip(val_batches//5)print(Number of validation batches: %d%tf.data.experimental.cardinality(val_ds))print(Number of test batches: %d%tf.data.experimental.cardinality(test_ds))归一化 性能配置AUTOTUNEtf.data.AUTOTUNEdefpreprocess_image(image,label):returnimage/255.0,label train_dstrain_ds.map(preprocess_image,num_parallel_callsAUTOTUNE)val_dsval_ds.map(preprocess_image,num_parallel_callsAUTOTUNE)test_dstest_ds.map(preprocess_image,num_parallel_callsAUTOTUNE)train_dstrain_ds.cache().shuffle(1000).prefetch(buffer_sizeAUTOTUNE)val_dsval_ds.cache().prefetch(buffer_sizeAUTOTUNE)test_dstest_ds.cache().prefetch(buffer_sizeAUTOTUNE)二、数据增强我们可以使用tf.keras.layers.experimental.preprocessing.RandomFlip与tf.keras.layers.experimental.preprocessing.RandomRotation进行数据增强新版本也可直接写tf.keras.layers.RandomFlip/RandomRotation。RandomFlip水平和垂直随机翻转每个图像RandomRotation随机旋转每个图像data_augmentationtf.keras.Sequential([layers.experimental.preprocessing.RandomFlip(horizontal_and_vertical),layers.experimental.preprocessing.RandomRotation(0.2),])第一个层表示进行随机的水平和垂直翻转第二个层表示按0.2的因子进行随机旋转。可视化增强效果plt.figure(figsize(8,8))forimages,labelsintrain_ds.take(1):imagetf.expand_dims(images[0],0)foriinrange(9):augmented_imagedata_augmentation(image,trainingTrue)axplt.subplot(3,3,i1)plt.imshow(augmented_image[0])plt.axis(off)更多数据增强方式可参考RandomRotation 文档。探索记录更多增强手段方式APITF 2.4作用水平/垂直翻转RandomFlip镜像扩充视角随机旋转RandomRotation角度扰动随机缩放RandomZoom模拟远近随机对比度RandomContrast/tf.image.stateless_random_contrast光照变化随机亮度RandomBrightness/tf.image.random_brightness明暗变化随机平移RandomTranslation位置偏移随机裁剪RandomCrop局部裁切后再用饱和度tf.image.random_saturation色彩浓淡三、增强方式方法一将其嵌入 model 中这样做的好处是数据增强这块的工作可以得到GPU 加速如果你使用了 GPU 训练的话。注意只有在模型训练时Model.fit才会进行增强在模型评估Model.evaluate以及预测Model.predict时并不会进行增强操作。modeltf.keras.Sequential([layers.Input(shape(img_height,img_width,3)),data_augmentation,# ← 嵌进 modellayers.Conv2D(16,3,paddingsame,activationrelu),layers.MaxPooling2D(),layers.Conv2D(32,3,paddingsame,activationrelu),layers.MaxPooling2D(),layers.Conv2D(64,3,paddingsame,activationrelu),layers.MaxPooling2D(),layers.Dropout(0.2),# 小数据易过拟合略加 Dropoutlayers.Flatten(),layers.Dense(128,activationrelu),layers.Dense(len(class_names))])本周 notebook 主跑方案即为方法一。方法二在 Dataset 数据集中进行数据增强defprepare(ds,shuffleFalse,augmentFalse):ifshuffle:dsds.shuffle(1000)ifaugment:dsds.map(lambdax,y:(data_augmentation(x,trainingTrue),y),num_parallel_callsAUTOTUNE)returnds.prefetch(buffer_sizeAUTOTUNE)# 示例仅对训练集增强此时 model 内不要再重复嵌增强层# train_ds_aug prepare(train_ds, shuffleTrue, augmentTrue)方法二适合把增强放在 CPU 数据流水线里与 GPU 训练并行自定义增强函数也更容易挂到map上。四、训练模型在准备对模型进行训练之前还需要再对其进行一些设置。以下内容是在模型的编译步骤中添加的损失函数loss用于衡量模型在训练期间的误差优化器optimizer决定模型如何根据数据与损失函数更新参数评价函数metrics用于监控训练和测试步骤本例用准确率model.compile(optimizeradam,losstf.keras.losses.SparseCategoricalCrossentropy(from_logitsTrue),metrics[accuracy])epochs30historymodel.fit(train_ds,validation_dataval_ds,epochsepochs)开始训练后用测试集评估loss,accmodel.evaluate(test_ds)print(Accuracy,acc)参考输出方法一实测ml_env / TF 2.11CPUEpoch 1/30 14/14 - loss: 1.0330 - accuracy: 0.5571 - val_loss: 0.6756 - val_accuracy: 0.6824 Epoch 8/30 14/14 - loss: 0.2823 - accuracy: 0.8690 - val_loss: 0.3675 - val_accuracy: 0.8649 Epoch 16/30 14/14 - loss: 0.1371 - accuracy: 0.9571 - val_loss: 0.2234 - val_accuracy: 0.9392 Epoch 27/30 14/14 - loss: 0.0724 - accuracy: 0.9738 - val_loss: 0.1779 - val_accuracy: 0.9459 ...... Epoch 30/30 14/14 - loss: 0.0627 - accuracy: 0.9738 - val_loss: 0.3629 - val_accuracy: 0.9122 1/1 [] - loss: 0.8222 - accuracy: 0.8125 Accuracy 0.8125本机结果摘要最佳验证准确率约94.59%测试集准确率81.25%测试集约 1 个 batch / 32 张波动较大期末模型 val 略回落时 test 也会受影响。课程示例可冲到更高可继续加RandomZoom、换学习率、或按 val 最优做 checkpoint。训练曲线fromdatetimeimportdatetime current_timedatetime.now()acchistory.history[accuracy]val_acchistory.history[val_accuracy]losshistory.history[loss]val_losshistory.history[val_loss]epochs_rangerange(len(loss))plt.figure(figsize(12,4))plt.subplot(1,2,1)plt.plot(epochs_range,acc,labelTraining Accuracy)plt.plot(epochs_range,val_acc,labelValidation Accuracy)plt.legend(loclower right)plt.title(Training and Validation Accuracy)plt.xlabel(str(current_time))# 打卡请带上时间戳plt.subplot(1,2,2)plt.plot(epochs_range,loss,labelTraining Loss)plt.plot(epochs_range,val_loss,labelValidation Loss)plt.legend(locupper right)plt.title(Training and Validation Loss)plt.show()五、自定义增强函数这是可以自由发挥的地方。课程示例用随机对比度importrandomdefaug_img(image):seed(random.randint(0,9),0)# 随机改变图像对比度returntf.image.stateless_random_contrast(image,lower0.1,upper1.0,seedseed)可视化# 取一张已归一化图片还原到约 0~255 再增强展示forimages,labelsintrain_ds.take(1):imagetf.expand_dims(images[3]*255.0,0)print(Min and max pixel values:,image.numpy().min(),image.numpy().max())plt.figure(figsize(8,8))foriinrange(9):augmented_imageaug_img(image)axplt.subplot(3,3,i1)plt.imshow(tf.clip_by_value(augmented_image[0],0,255).numpy().astype(uint8))plt.axis(off)那么如何将自定义增强函数应用到数据上呢参考上文的preprocess_image把aug_img嵌进去即可defpreprocess_image(image,label):imageimage/255.0imageaug_img(image)# 仅建议挂在训练集returnimage,label# train_ds train_ds.map(preprocess_image, num_parallel_callsAUTOTUNE)也可组合更多变换探索defaug_img_extra(image):imagetf.image.random_brightness(image,max_delta0.2)imagetf.image.random_saturation(image,lower0.5,upper1.5)iftf.random.uniform([])0.5:imagetf.image.flip_left_right(image)returnimage总结本周在小样本猫狗数据600 张上完成经验分享小数据先保语义再谈花样。猫狗图默认头朝上垂直翻转有时会把样本拧得不像真图horizontal_and_vertical能扩充多样性但若 val 抖、训得很快过拟合可以先改成只做水平翻转再逐步加旋转 / 缩放。增强幅度不是越大越好。两种接入方式别叠着用。方法一把增强嵌进 model方法二在Dataset.map里做同一套RandomFlip/RandomRotation同时开两遍等于扰动加倍难排查。主跑选一种即可自定义aug_img更适合挂在方法二的预处理里。看 val别只看 train。本周无增强时很容易训到接近 100% 的 train_acc但 val 会掉加上增强 一点Dropout后最佳 val 能到九成以上。期末权重不一定是最好的那一轮——test 只有约一个 batch32 张波动大更稳妥是按val_accuracy存ModelCheckpoint再用最优权重去evaluate。测试集要从验证集切且切之前别cache错顺序。先take/skip再归一化与cache否则流水线状态容易乱。val_batches // 5在 batch 很少时可能切出 0 或 1 个 batch解读 test_acc 时心里要有数数字漂亮不一定代表泛化已经稳了。增强只在fit时生效方法一。evaluate/predict不会再随机翻转旋转这是预期行为对比「有无增强」时应保证网络结构、epoch、随机种子尽量一致只改增强相关代码结论才有可比性。