目录
一、数据增强
二、transforms——裁剪
1. transforms.CenterCrop
2. transforms.RandomCrop
3. RandomResizedCrop
4. FiveCrop
5.TenCrop
三、transforms——翻转、旋转
1. RandomHorizontalFlip
2. RandomVerticalFlip
3. RandomRotation
任务简介:
pytorch提供了大量的transforms预处理方法,在这里归纳总结为四大类共二十二种方法进行一 一学习;学会自定义transforms方法以兼容实际项目;
详细说明:
本节介绍数据的预处理模块transforms的运行机制,数据在读取到pytorch之后通常都需要对数据进行预处理,包括尺寸缩放、转换张量、数据中心化或标准化等等,这些操作都是通过transforms进行的,所以本节重点学习transforms的运行机制并介绍数据标准化(Normalize)的使用原理。
测试代码:
# -*- coding: utf-8 -*-
import os
os.environ["KMP_DUPLICATE_LIB_OK"]="TRUE"
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
import numpy as np
import torch
import random
from torch.utils.data import DataLoader
import torchvision.transforms as transforms
from PIL import Image
from matplotlib import pyplot as plt
path_lenet = os.path.abspath(os.path.join(BASE_DIR, "..", "..", "model", "lenet.py"))
path_tools = os.path.abspath(os.path.join(BASE_DIR, "..", "..", "tools", "common_tools.py"))
assert os.path.exists(path_lenet), "{}不存在,请将lenet.py文件放到 {}".format(path_lenet, os.path.dirname(path_lenet))
assert os.path.exists(path_tools), "{}不存在,请将common_tools.py文件放到 {}".format(path_tools, os.path.dirname(path_tools))
import sys
hello_pytorch_DIR = os.path.abspath(os.path.dirname(__file__)+os.path.sep+".."+os.path.sep+"..")
sys.path.append(hello_pytorch_DIR)
from tools.my_dataset import RMBDataset
from tools.common_tools import set_seed, transform_invert
set_seed(1) # 设置随机种子
# 参数设置
MAX_EPOCH = 10
BATCH_SIZE = 1
LR = 0.01
log_interval = 10
val_interval = 1
rmb_label = {"1": 0, "100": 1}
# ============================ step 1/5 数据 ============================
split_dir = os.path.abspath(os.path.join("..", "..", "data", "rmb_split"))
if not os.path.exists(split_dir):
raise Exception(r"数据 {} 不存在, 回到lesson-06\1_split_dataset.py生成数据".format(split_dir))
train_dir = os.path.join(split_dir, "train")
valid_dir = os.path.join(split_dir, "valid")
norm_mean = [0.485, 0.456, 0.406]
norm_std = [0.229, 0.224, 0.225]
train_transform = transforms.Compose([
transforms.Resize((224, 224)),
# 1 CenterCrop
transforms.CenterCrop(196), # 512
# 2 RandomCrop
# transforms.RandomCrop(224, padding=16),
# transforms.RandomCrop(224, padding=(16, 64)),
# transforms.RandomCrop(224, padding=16, fill=(255, 0, 0)),
# transforms.RandomCrop(512, pad_if_needed=True), # pad_if_needed=True
# transforms.RandomCrop(224, padding=64, padding_mode='edge'),
# transforms.RandomCrop(224, padding=64, padding_mode='reflect'),
# transforms.RandomCrop(1024, padding=1024, padding_mode='symmetric'),
# 3 RandomResizedCrop
# transforms.RandomResizedCrop(size=224, scale=(0.5, 0.5)),
# 4 FiveCrop
# transforms.FiveCrop(112),
# transforms.Lambda(lambda crops: torch.stack([(transforms.ToTensor()(crop)) for crop in crops])),
# 5 TenCrop
# transforms.TenCrop(112, vertical_flip=False),
# transforms.Lambda(lambda crops: torch.stack([(transforms.ToTensor()(crop)) for crop in crops])),
# 1 Horizontal Flip
# transforms.RandomHorizontalFlip(p=1),
# 2 Vertical Flip
# transforms.RandomVerticalFlip(p=0.5),
# 3 RandomRotation
# transforms.RandomRotation(90),
# transforms.RandomRotation((90), expand=True),
# transforms.RandomRotation(30, center=(0, 0)),
# transforms.RandomRotation(30, center=(0, 0), expand=True), # expand only for center rotation
transforms.ToTensor(),
transforms.Normalize(norm_mean, norm_std),
])
valid_transform = transforms.Compose([
transforms.Resize((224, 224)),
transforms.ToTensor(),
transforms.Normalize(norm_mean, norm_std)
])
# 构建MyDataset实例
train_data = RMBDataset(data_dir=train_dir, transform=train_transform)
valid_data = RMBDataset(data_dir=valid_dir, transform=valid_transform)
# 构建DataLoder
train_loader = DataLoader(dataset=train_data, batch_size=BATCH_SIZE, shuffle=True)
valid_loader = DataLoader(dataset=valid_data, batch_size=BATCH_SIZE)
# ============================ step 5/5 训练 ============================
for epoch in range(MAX_EPOCH):
for i, data in enumerate(train_loader):
inputs, labels = data # B C H W
img_tensor = inputs[0, ...] # C H W
img = transform_invert(img_tensor, train_transform)
plt.imshow(img)
plt.show()
plt.pause(0.5)
plt.close()
# bs, ncrops, c, h, w = inputs.shape
# for n in range(ncrops):
# img_tensor = inputs[0, n, ...] # C H W
# img = transform_invert(img_tensor, train_transform)
# plt.imshow(img)
# plt.show()
# plt.pause(1)
裁剪结果:
196*196,中心裁剪
设置transforms.CenterCrop(512) 时,输出:
超过224*224部分的区域用0像素点填充。
在上述代码基础下做测试:
当设置 transforms.RandomCrop(224, padding=16) 时:
为什么左上角是黑色的?
因为pandding=16操作,使得图像尺寸扩大32(16 + 16)个像素点,大于原来的像素点(224),然后RandomCrop随机选择一个224*224大小的图像,如图所示,是选择图像的左上角。
当设置 transforms.RandomCrop(224, padding=(16, 64)) 时:
左右填充区域小,上下填充区域大。
当设置 transforms.RandomCrop(224, padding=16, fill=(255, 0, 0)) 时:
填充区域的RGB值为(255, 0, 0),显示为红色。
当设置 transforms.RandomCrop(512, pad_if_needed=True) 时:
当size(512) 大于图像的尺寸(224)时,要设置 pad_if_needed=True,否则会报错。
当设置 transforms.RandomCrop(224, padding=64, padding_mode=‘edge’) 时:
扩充的像素点,是边缘像素点的值。
当设置transforms.RandomCrop(224, padding=64, padding_mode=‘reflect’)时:
进行镜像填充。
当设置 transforms.RandomCrop(1024, padding=1024, padding_mode=‘symmetric’) 时:
设置 transforms.RandomResizedCrop(size=224, scale=(0.5, 0.5)) 时:
裁剪图片大小50%的面积,然后resize到224*224。
功能:在图像的上下左右及中心裁剪出尺寸为size的图片。
设置 transforms.FiveCrop(112)
会报错:TypeError: pic should be PIL Image or ndarray. Got
添加设置:
transforms.FiveCrop(112)
transforms.Lambda(lambda crops: torch.stack([(transforms.ToTensor()(crop)) for crop in crops]))
#transforms.ToTensor(),
#transforms.Normalize(norm_mean, norm_std),
输出:
FiveCrop对图像进行左上角、右上角、左下角、右下角以及中心进行裁剪。
设置:
transforms.TenCrop(112, vertical_flip=False),
transforms.Lambda(lambda crops: torch.stack([(transforms.ToTensor()(crop)) for crop in crops])),
TenCrop是在FiveCrop的基础上进行水平翻转(vertical_flip=False),vertical_flip=True为垂直翻转
设置 transforms.RandomHorizontalFlip(p=1) 时:
水平翻转
设置 transforms.RandomVerticalFlip(p=0.5) 时:
垂直翻转,概率p=50%
当设置 transforms.RandomRotation(90) 时:
在-90°到90°之间随机旋转。
当设置transforms.RandomRotation((90), expand=True) 时:
图像区域扩大,不丢失图像信息。
设置 transforms.RandomRotation(30, center=(0, 0)) :
在左上角进行旋转,会丢失信息。
当设置 transforms.RandomRotation(30, center=(0, 0), expand=True), # expand only for center rotation:
expand 只对中心旋转有效。中心旋转和左上角旋转需要扩大的长度是不一样的,计算方法也不一样,expand方法是不能找回旋转中心不在中心位置的图片左上角丢失的信息。