Pytorch对两张图片进行相同的数据增广操作

参考资料

  1. 个人博客 - Pytorch同时对输入输出使用transform
  2. 知乎 - 4个例子让你的pytorch数据增强过程不随机
  3. CSDN - Tensorflow如何对两幅图像做同样的数据增广操作
  4. Pytorch官方文档 - torchvision.transforms.functional

问题描述

原始的人脸表情识别训练过程中,对于每张输入的图片,都有一个表情标签与之对应(这里只考虑单标签)。可以直接使用torchvision.transform中的transforms.RandomCroptransforms.RandomHorizontalFliptransforms.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如图所求 然后对图片同时进行随机旋转和翻转,代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
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

def my_transform3(image, mask):
# 随机裁剪
i, j, h, w = transforms.RandomResizedCrop.get_params(
image, scale=(0.7, 1.0), ratio=(1, 1))
image = tf.resized_crop(image, i, j, h, w, 48)
mask = tf.resized_crop(mask, i, j, h, w, 48)
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')

image_tensor, mask_tensor = my_transform3(image, mask)

#此时image, mask为tensor,需转成PIL Image
image_crop = transforms.ToPILImage()(image_tensor).convert('L').save('0_crop.jpg')
mask_crop = transforms.ToPILImage()(mask_tensor).convert('L').save('0_seg_face_crop.jpg')

旋转后图片为(每次旋转结果可能都不一样,角度随机) 50%可能性翻转后图片为 随机裁剪,裁剪后大小为原来的[0.8,1],长宽比例为1:1,最后并将resize为(48, 48),图片为: