参考资料
- 个人博客 - Pytorch同时对输入输出使用transform
- 知乎 - 4个例子让你的pytorch数据增强过程不随机
- CSDN - Tensorflow如何对两幅图像做同样的数据增广操作
- Pytorch官方文档 - torchvision.transforms.functional
问题描述
原始的人脸表情识别训练过程中,对于每张输入的图片,都有一个表情标签与之对应(这里只考虑单标签)。可以直接使用torchvision.transform
中的transforms.RandomCrop
、transforms.RandomHorizontalFlip
、transforms.RandomRotation
等对图片进行随机操作,从而实现对数据的增广操作,提高模型的泛化能力。
但在人脸表情识别中引入Attention机制后,对于每张输入图片,则对应一个脸部分割的概率图。在对原始图片进行transform
的变换时,与之对应的脸部分割图mask应与之进行相同的变化。但是上面提到的所有操作都是随机操作,涉及一个随机值。所以,无法做到输入与mask进行相同的transform
。所以,决定放弃使用数据增广的操作,而是直接使用的是原图,训练过程中出现train的准确率不断上升,最后达到100%,而test的准确率则开始是上升,中间出现波动。最后开始下降。很显然,模型过拟化。为了解决这个问题,相当于解决如何用Pytorch对两张图片进行相同的数据增广操作的问题?
解决方法
在pytorch文档上可以看到,除了torchvision.transform 还有torchvision.transforms.functional。
相比transform ,transforms.functional 更加灵活,该方法只提供了图像的增强变换功能,而并没有随机部分
引用自资料1
实际上是用torchvision.transforms.functional中提供的函数(都没有引入随机性),来自定义transform
函数。
示例
原图及脸部分割mask如图所求
然后对图片同时进行随机旋转和翻转,代码如下
import random
import cv2
from torchvision import transforms
import torchvision.transforms.functional as tf
from PIL import Image
def my_transform1(image, mask):
# 拿到角度的随机数。angle是一个-180到180之间的一个数
angle = transforms.RandomRotation.get_params([-180, 180])
# 对image和mask做相同的旋转操作,保证他们都旋转angle角度
image = image.rotate(angle)
mask = mask.rotate(angle)
image = tf.to_tensor(image)
mask = tf.to_tensor(mask)
return image, mask
def my_transform2(image, mask):
# 50%的概率应用垂直,水平翻转。
if random.random() > 0.5:
image = tf.hflip(image)
mask = tf.hflip(mask)
if random.random() > 0.5:
image = tf.vflip(image)
mask = tf.vflip(mask)
image = tf.to_tensor(image)
mask = tf.to_tensor(mask)
return image, mask
# transform处理对象一般都是 PIL Image
image = Image.open('./0.jpg') # 原图
mask = Image.open('./0_seg_face.jpg') # mask
image_tensor, mask_tensor = my_transform1(image, mask)
#此时image, mask为tensor,需转成PIL Image
image_rotate = transforms.ToPILImage()(image_tensor).convert('L').save('0_rotate.jpg')
mask_rotate = transforms.ToPILImage()(mask_tensor).convert('L').save('0_seg_face_rotate.jpg')
image_tensor, mask_tensor = my_transform2(image, mask)
#此时image, mask为tensor,需转成PIL Image
image_flip = transforms.ToPILImage()(image_tensor).convert('L').save('0_flip.jpg')
mask_flip = transforms.ToPILImage()(mask_tensor).convert('L').save('0_seg_face_flip.jpg')
旋转后图片为(每次旋转结果可能都不一样,角度随机)
翻转后图片为