# 学习笔记|Pytorch使用教程08(transforms数据预处理方法(二))

Pytorch 同时被 2 个专栏收录
39 篇文章 12 订阅
78 篇文章 4 订阅

## 学习笔记|Pytorch使用教程08

• transforms——图像变换
• transforms——transforms方法操作
• 自定义transforms方法

## 一.transforms——图像变换

当为a时，上下左右均填充a个像素。
当为（a，b）时，上下填充b个像素，左右填充a个像素。
当为（a，b，c，d）时，上下左右分别填充a，b，c，d
• fill：constant时，设置填充的像数值，（R，G，B）or（Gray）

import os
import numpy as np
import torch
import random
from matplotlib import pyplot as plt
import torchvision.transforms as transforms
from tools.my_dataset import RMBDataset
from tools.common_tools import transform_invert

def set_seed(seed=1):
random.seed(seed)
np.random.seed(seed)
torch.manual_seed(seed)
torch.cuda.manual_seed(seed)

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.join("..", "..", "data", "rmb_split")
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)),

# 2 ColorJitter
# transforms.ColorJitter(brightness=0.5),
# transforms.ColorJitter(contrast=0.5),
# transforms.ColorJitter(saturation=0.5),
# transforms.ColorJitter(hue=0.3),

# 3 Grayscale
# transforms.Grayscale(num_output_channels=3),

# 4 Affine
# transforms.RandomAffine(degrees=30),
# transforms.RandomAffine(degrees=0, translate=(0.2, 0.2), fillcolor=(255, 0, 0)),
# transforms.RandomAffine(degrees=0, scale=(0.7, 0.7)),
# transforms.RandomAffine(degrees=0, shear=(0, 0, 0, 45)),
# transforms.RandomAffine(degrees=0, shear=90, fillcolor=(255, 0, 0)),

# 5 Erasing
# transforms.ToTensor(),
# transforms.RandomErasing(p=1, scale=(0.02, 0.33), ratio=(0.3, 3.3), value=(254/255, 0, 0)),
# transforms.RandomErasing(p=1, scale=(0.02, 0.33), ratio=(0.3, 3.3), value='1234'),

# 1 RandomChoice
# transforms.RandomChoice([transforms.RandomVerticalFlip(p=1), transforms.RandomHorizontalFlip(p=1)]),

# 2 RandomApply
# transforms.RandomApply([transforms.RandomAffine(degrees=0, shear=45, fillcolor=(255, 0, 0)),
#                         transforms.Grayscale(num_output_channels=3)], p=0.5),
# 3 RandomOrder
# transforms.RandomOrder([transforms.RandomRotation(15),
#                         transforms.RandomAffine(degrees=0, translate=(0.01, 0.1), scale=(0.9, 1.1))]),

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

# ============================ step 5/5 训练 ============================
for epoch in range(MAX_EPOCH):

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()


2.ColorJitter

• brightness：亮度调整因子
当为a时，从[max(0, 1 - a), 1 + a]中随机选择。
当为（a，b）时，从[a, b]中选择。
• constant：对比度参数，同brightness。
• saturation：饱和度参数，同brightness。
• hue：色相参数，当为ａ时，从[-a, a]中选择参数，注：0 <= a <= 0.5

３.Grayscale
４.RandomGrayscale

• num_output_channels：输出通道数，只能设置成１或３
• p：概率值，图像被转换为灰度图的概率

５.RandomAffine

• degrees：旋转角度设置
• translate：平移区间设置，如（ａ，ｂ），ａ设置宽(width)，ｂ设置高(height)。
图像在宽维度平移的区间为　-img_width * a < dx < img_width * a　。
• scale：缩放比例（以面积为单位）
• fill_colore：一种填充颜色设置。
• shear：错切角度设置，有水平错切和锤子错切。
若为ａ，则仅在ｘ轴错切，错切角度在（－ａ，ａ）之间
若为（ａ，ｂ），则ａ设置ｘ轴角度，ｂ设置ｙ的角度。
若为（ａ，ｂ，ｃ，ｄ），则ａ，ｂ设置ｘ轴角度，ｃ，ｄ设置ｙ轴角度。
• resample：采样方式，有NEAREST、BILINEAR 、BICUBIC。
• fill_color：填充的颜色

６.RandomErasing

• p：概率值，执行该操作的概率
• scale：遮挡区域的面积
• ratio：遮挡区域的长宽比
• value： 设置遮挡区域的像数值（R，G，B）ｏｒ（Gray）

    transforms.ToTensor(),
transforms.RandomErasing(p=1, scale=(0.02, 0.33), ratio=(0.3, 3.3), value=(254/255, 0, 0)),
#transforms.ToTensor(),
#transforms.Normalize(norm_mean, norm_std),


value设置成字符串的进行，就会随机填充。

７.transforms.Lambda

• lambda：lambda匿名函数
lambda[arg1 [,arg2,…, argn]]: expression
eg:

## 二．transforms——transforms方法操作

	transforms.RandomChoice([transforms.RandomVerticalFlip(p=1), transforms.RandomHorizontalFlip(p=1)])
transforms.ToTensor(),
transforms.Normalize(norm_mean, norm_std),


    transforms.RandomApply([transforms.RandomAffine(degrees=0, shear=45, fillcolor=(255, 0, 0)),
transforms.Grayscale(num_output_channels=3)], p=0.5),


    transforms.RandomOrder([transforms.RandomRotation(15),
transforms.RandomAffine(degrees=0, translate=(0.01, 0.1), scale=(0.9, 1.1))]),


## 三．自定义transforms方法

import os
import numpy as np
import torch
import random
import torchvision.transforms as transforms
from PIL import Image
from matplotlib import pyplot as plt
from tools.my_dataset import RMBDataset
from tools.common_tools import transform_invert

def set_seed(seed=1):
random.seed(seed)
np.random.seed(seed)
torch.manual_seed(seed)
torch.cuda.manual_seed(seed)

set_seed(1)  # 设置随机种子

# 参数设置
MAX_EPOCH = 10
BATCH_SIZE = 1
LR = 0.01
log_interval = 10
val_interval = 1
rmb_label = {"1": 0, "100": 1}

"""增加椒盐噪声
Args:
snr （float）: Signal Noise Rate
p (float): 概率值，依概率执行该操作
"""

def __init__(self, snr, p=0.9):
assert isinstance(snr, float) or (isinstance(p, float))
self.snr = snr
self.p = p

def __call__(self, img):
"""
Args:
img (PIL Image): PIL Image
Returns:
PIL Image: PIL image.
"""
if random.uniform(0, 1) < self.p:
img_ = np.array(img).copy()
h, w, c = img_.shape
signal_pct = self.snr
noise_pct = (1 - self.snr)
mask = np.random.choice((0, 1, 2), size=(h, w, 1), p=[signal_pct, noise_pct/2., noise_pct/2.])
img_[mask == 1] = 255   # 盐噪声
img_[mask == 2] = 0     # 椒噪声
return Image.fromarray(img_.astype('uint8')).convert('RGB')
else:
return img

# ============================ step 1/5 数据 ============================
split_dir = os.path.join("..", "..", "data", "rmb_split")
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)),
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

# ============================ step 5/5 训练 ============================
for epoch in range(MAX_EPOCH):

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()



## 四．总结

• 原则：让训练集与测试集更接近。
• 空间位置：平移
• 色彩：灰度图，色彩抖动
• 形状：仿射变换
• 上下文场景：遮挡、填充
• ．．．

import os
import random
import numpy as np
import torch
import torch.nn as nn
import torchvision.transforms as transforms
import torch.optim as optim
from matplotlib import pyplot as plt
from model.lenet import LeNet
from tools.my_dataset import RMBDataset
from tools.common_tools import transform_invert

def set_seed(seed=1):
random.seed(seed)
np.random.seed(seed)
torch.manual_seed(seed)
torch.cuda.manual_seed(seed)

set_seed()  # 设置随机种子
rmb_label = {"1": 0, "100": 1}

# 参数设置
MAX_EPOCH = 10
BATCH_SIZE = 16
LR = 0.01
log_interval = 10
val_interval = 1

# ============================ step 1/5 数据 ============================

split_dir = os.path.join("..", "..", "data", "rmb_split")
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((32, 32)),
#transforms.RandomGrayscale(p=0.9),
transforms.ToTensor(),
transforms.Normalize(norm_mean, norm_std),
])

valid_transform = transforms.Compose([
transforms.Resize((32, 32)),
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

# ============================ step 2/5 模型 ============================

net = LeNet(classes=2)
net.initialize_weights()

# ============================ step 3/5 损失函数 ============================
criterion = nn.CrossEntropyLoss()                                                   # 选择损失函数

# ============================ step 4/5 优化器 ============================
optimizer = optim.SGD(net.parameters(), lr=LR, momentum=0.9)                        # 选择优化器
scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=10, gamma=0.1)     # 设置学习率下降策略

# ============================ step 5/5 训练 ============================
train_curve = list()
valid_curve = list()

for epoch in range(MAX_EPOCH):

loss_mean = 0.
correct = 0.
total = 0.

net.train()

# forward
inputs, labels = data
outputs = net(inputs)

# backward
loss = criterion(outputs, labels)
loss.backward()

# update weights
optimizer.step()

# 统计分类情况
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == labels).squeeze().sum().numpy()

# 打印训练信息
loss_mean += loss.item()
train_curve.append(loss.item())
if (i+1) % log_interval == 0:
loss_mean = loss_mean / log_interval
print("Training:Epoch[{:0>3}/{:0>3}] Iteration[{:0>3}/{:0>3}] Loss: {:.4f} Acc:{:.2%}".format(
epoch, MAX_EPOCH, i+1, len(train_loader), loss_mean, correct / total))
loss_mean = 0.

scheduler.step()  # 更新学习率

# validate the model
if (epoch+1) % val_interval == 0:

correct_val = 0.
total_val = 0.
loss_val = 0.
net.eval()
inputs, labels = data
outputs = net(inputs)
loss = criterion(outputs, labels)

_, predicted = torch.max(outputs.data, 1)
total_val += labels.size(0)
correct_val += (predicted == labels).squeeze().sum().numpy()

loss_val += loss.item()

valid_curve.append(loss_val)
print("Valid:\t Epoch[{:0>3}/{:0>3}] Iteration[{:0>3}/{:0>3}] Loss: {:.4f} Acc:{:.2%}".format(
epoch, MAX_EPOCH, j+1, len(valid_loader), loss_val, correct / total))

train_x = range(len(train_curve))
train_y = train_curve

valid_x = np.arange(1, len(valid_curve)+1) * train_iters*val_interval # 由于valid中记录的是epochloss，需要对记录点进行转换到iterations
valid_y = valid_curve

plt.plot(train_x, train_y, label='Train')
plt.plot(valid_x, valid_y, label='Valid')

plt.legend(loc='upper right')
plt.ylabel('loss value')
plt.xlabel('Iteration')
plt.show()

# ============================ inference ============================

BASE_DIR = os.path.dirname(os.path.abspath(__file__))
test_dir = os.path.join(BASE_DIR, "test_data")

test_data = RMBDataset(data_dir=test_dir, transform=valid_transform)

# forward
inputs, labels = data
outputs = net(inputs)
_, predicted = torch.max(outputs.data, 1)

rmb = 1 if predicted.numpy()[0] == 0 else 100

img_tensor = inputs[0, ...]  # C H W
img = transform_invert(img_tensor, train_transform)
plt.imshow(img)
plt.title("LeNet got {} Yuan".format(rmb))
plt.show()
plt.pause(0.5)
plt.close()


Training:Epoch[000/010] Iteration[010/010] Loss: 0.6578 Acc:56.88%
Valid:   Epoch[000/010] Iteration[002/002] Loss: 1.0045 Acc:56.88%
Training:Epoch[001/010] Iteration[010/010] Loss: 0.3343 Acc:89.38%
Valid:   Epoch[001/010] Iteration[002/002] Loss: 0.1628 Acc:89.38%
Training:Epoch[002/010] Iteration[010/010] Loss: 0.0836 Acc:98.75%
Valid:   Epoch[002/010] Iteration[002/002] Loss: 0.0362 Acc:98.75%
Training:Epoch[003/010] Iteration[010/010] Loss: 0.2507 Acc:95.00%
Valid:   Epoch[003/010] Iteration[002/002] Loss: 0.0157 Acc:95.00%
Training:Epoch[004/010] Iteration[010/010] Loss: 0.0389 Acc:98.75%
Valid:   Epoch[004/010] Iteration[002/002] Loss: 0.0119 Acc:98.75%
Training:Epoch[005/010] Iteration[010/010] Loss: 0.0402 Acc:98.75%
Valid:   Epoch[005/010] Iteration[002/002] Loss: 0.0001 Acc:98.75%
Training:Epoch[006/010] Iteration[010/010] Loss: 0.0043 Acc:100.00%
Valid:   Epoch[006/010] Iteration[002/002] Loss: 0.0008 Acc:100.00%
Training:Epoch[007/010] Iteration[010/010] Loss: 0.0178 Acc:99.38%
Valid:   Epoch[007/010] Iteration[002/002] Loss: 0.0000 Acc:99.38%
Training:Epoch[008/010] Iteration[010/010] Loss: 0.0381 Acc:99.38%
Valid:   Epoch[008/010] Iteration[002/002] Loss: 0.0000 Acc:99.38%
Training:Epoch[009/010] Iteration[010/010] Loss: 0.0065 Acc:100.00%
Valid:   Epoch[009/010] Iteration[002/002] Loss: 0.0001 Acc:100.00%


Training:Epoch[000/010] Iteration[010/010] Loss: 0.6856 Acc:52.50%
Valid:   Epoch[000/010] Iteration[002/002] Loss: 0.9902 Acc:52.50%
Training:Epoch[001/010] Iteration[010/010] Loss: 0.4071 Acc:85.00%
Valid:   Epoch[001/010] Iteration[002/002] Loss: 0.0719 Acc:85.00%
Training:Epoch[002/010] Iteration[010/010] Loss: 0.1547 Acc:93.75%
Valid:   Epoch[002/010] Iteration[002/002] Loss: 0.0026 Acc:93.75%
Training:Epoch[003/010] Iteration[010/010] Loss: 0.3176 Acc:90.62%
Valid:   Epoch[003/010] Iteration[002/002] Loss: 0.0187 Acc:90.62%
Training:Epoch[004/010] Iteration[010/010] Loss: 0.0939 Acc:96.25%
Valid:   Epoch[004/010] Iteration[002/002] Loss: 0.0008 Acc:96.25%
Training:Epoch[005/010] Iteration[010/010] Loss: 0.0115 Acc:100.00%
Valid:   Epoch[005/010] Iteration[002/002] Loss: 0.0000 Acc:100.00%
Training:Epoch[006/010] Iteration[010/010] Loss: 0.0621 Acc:98.75%
Valid:   Epoch[006/010] Iteration[002/002] Loss: 0.0000 Acc:98.75%
Training:Epoch[007/010] Iteration[010/010] Loss: 0.0696 Acc:95.62%
Valid:   Epoch[007/010] Iteration[002/002] Loss: 0.0001 Acc:95.62%
Training:Epoch[008/010] Iteration[010/010] Loss: 0.0609 Acc:96.88%
Valid:   Epoch[008/010] Iteration[002/002] Loss: 0.0001 Acc:96.88%
Training:Epoch[009/010] Iteration[010/010] Loss: 0.0143 Acc:99.38%
Valid:   Epoch[009/010] Iteration[002/002] Loss: 0.0000 Acc:99.38%


• 7
点赞
• 2
评论
• 28
收藏
• 打赏
• 扫一扫，分享海报

05-04 1777

07-23 1996
11-02 4561

NotFound1911

¥2 ¥4 ¥6 ¥10 ¥20

1.余额是钱包充值的虚拟货币，按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载，可以购买VIP、C币套餐、付费专栏及课程。