第七章 数据扩充与数据预处理
7.2 特殊的数据扩充方式
7.2.3 Mixup法
以Facebook人工智能研究院(FAIR)开发的深度学习训练框架PyTorch代码为例,mixup法可按如下实现进行。
1# mixup (PyTorch)
2import torch
3import numpy as np
4
5for (x, y) in dataloader:
6 # Ln.7-Ln.11: Shuffle the images in the batch randomly and mixup the images by the hyperparameter `lam`.
7 lam = np.random.beta(1.0, 1.0)
8 perm = torch.randperm(x.shape[0])
9 x1, x2 = x, x[perm]
10 y1, y2 = y, y[perm]
11 x = lam * x1 + (1 - lam) * x2
12
13 # Ln.14-Ln.18: Predict the mixed images and calculate the corresponding loss.
14 pred = net(x)
15 loss = lam * criterion(pred, y1) + (1 - lam) * criterion(pred, y2)
16 optimizer.zero_grad()
17 loss.backward()
18 optimizer.step()
此外,mixup法在MindSpore中可按如下实现。
1# mixup (MindSpore)
2import mindspore
3import numpy as np
4from mindspore import ops
5
6def train_loop(model, dataset, loss_fn, optimizer):
7 # Ln.8-Ln.20: Define forward function
8 def forward_fn(data, label, alpha=1.0):
9 # Ln.10-Ln.15: Shuffle the images in the batch randomly and mixup the images by the hyperparameter `lam`.
10 lam = np.random.beta(alpha, alpha)
11 perm = np.random.permutation(data.shape[0])
12
13 x1, x2 = data, data[perm]
14 y1, y2 = label, label[perm]
15 x = lam * x1 + (1 - lam) * x2
16
17 # Ln.18-Ln.20: Predict the mixed images and calculate the corresponding loss.
18 pred = model(x)
19 loss = lam * loss_fn(pred, y1) + (1 - lam) * loss_fn(pred, y2)
20 return loss, pred
21
22 # Ln.23: Get gradient function
23 grad_fn = mindspore.value_and_grad(forward_fn, None, optimizer.parameters, has_aux=True)
24
25 # Ln.26-Ln.29: Define function of one-step training
26 def train_step(data, label):
27 (loss, _), grads = grad_fn(data, label)
28 loss = ops.depend(loss, optimizer(grads))
29 return loss
30
31 model.set_train()
32 for batch, (data, label) in enumerate(dataset.create_tuple_iterator()):
33 loss = train_step(data, label)
可以看到,mixup法的插值操作对象为原始图像像素空间。而Manifold mixup法对深度学习模型的隐层表示(hidden representation)进行插值,并取得了优于mixup的效果。具体而言,Manifold mixup法可由PyTorch实现如下:
1# manifold mixup (PyTorch)
2import torch
3import numpy as np
4
5for (x, y) in dataloader:
6 lam = np.random.beta(1.0, 1.0)
7 perm = np.random.permutation(x.shape[0])
8
9 # Ln.10-Ln.16: Mixup the hidden representations, predict the mixed representations and calculate the corresponding loss.
10 x = net.forward_to_certain_layer(x)
11 x = lam * x + (1 - lam) * x[perm]
12 pred = net.forward_from_certain_layer(x)
13 loss = lam * criterion(pred, y1) + (1 - lam) * criterion(pred, y2)
14 optimizer.zero_grad()
15 loss.backward()
16 optimizer.step()
此外,Manifold mixup法在MindSpore中实现如下:
1# manifold mixup (MindSpore)
2import mindspore
3import numpy as np
4from mindspore import ops
5
6def train_loop(model, dataset, loss_fn, optimizer):
7 # Ln.8-Ln.17: Define forward function
8 def forward_fn(data, label):
9 lam = np.random.beta(alpha, alpha)
10 perm = np.random.permutation(data.shape[0])
11
12 # Ln.13-Ln.17: Mixup the hidden representations, predict the mixed representations and calculate the corresponding loss.
13 x = model.forward_to_certain_layer(data)
14 x = lam * x + (1 - lam) * x[perm]
15 pred = model.forward_from_certain_layer(x)
16
17 loss = lam * loss_fn(pred, y) + (1 - lam) * loss_fn(pred, y[perm])
18 return loss, pred
19
20 # Ln.20: Get gradient function
21 grad_fn = mindspore.value_and_grad(forward_fn, None, optimizer.parameters, has_aux=True)
22
23 # Ln.23-Ln.26: Define function of one-step training
24 def train_step(data, label):
25 (loss, _), grads = grad_fn(data, label)
26 loss = ops.depend(loss, optimizer(grads))
27 return loss
28
29 model.set_train()
30 for batch, (data, label) in enumerate(dataset.create_tuple_iterator()):
31 loss = train_step(data, label)
7.3 深度学习数据预处理
以PyTorch代码为例,图像减均值操作可以按以下步骤进行。
1# Subtract the mean values (PyTorch)
2import torch
3
4mean = torch.tensor([0.485, 0.456, 0.406]).reshape(3, 1, 1)
5var = torch.tensor([0.229, 0.224, 0.225]).reshape(3, 1, 1)
6
7def train(data, label, net, loss_fun):
8 # Ln.9: Input the image into the network by subtracting the mean and dividing by the variance.
9 out = net((data - mean) / var)
10 loss = loss_fun(out, label)
11 loss.backward()
在MindSpore中的实现如下:
1# Subtract the mean values (MindSpore)
2import mindspore
3import numpy as np
4
5mean = mindspore.Tensor(np.array([0.485 * 255, 0.456 * 255, 0.406 * 255])).reshape(3, 1, 1)
6var = mindspore.Tensor(np.array([0.229 * 255, 0.224 * 255, 0.225 * 255])).reshape(3, 1, 1)
7
8def forward_fn(data, label, model, loss_fn):
9 # Ln.10: Input the image into the network by subtracting the mean and dividing by the variance.
10 logits = model((data - mean) / var)
11 loss = loss_fn(logits, label)
12 return loss, logits
或者该操作可直接在数据预处理模块中完成,PyTorch中的实现如下:
1# Build the training dataset (PyTorch)
2import torchvision.datasets
3import torchvision.transforms as transforms
4from torch.utils.data import DataLoader
5
6print('preparing dataset...')
7transform = transforms.Compose([
8 transforms.Resize(size=config.resize_size),
9 transforms.RandomHorizontalFlip(),
10 transforms.RandomCrop(size=config.image_size),
11 transforms.ToTensor(),
12 # Ln.12: Normalize data, e.g., the subtract the mean values operation.
13 transforms.Normalize(mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225))
14])
15train_dataset = torchvision.datasets.ImageFolder(root='./data',transform=transform)
16train_loader = DataLoader(dataset=train_dataset, batch_size=config.batch_size, shuffle=True)
此外,MindSpore中的实现如下:
1# Build the training dataset (MindSpore)
2import mindspore
3from mindspore.dataset import ImageFolderDataset
4import mindspore.dataset.vision as transforms
5
6mean = [0.485 * 255, 0.456 * 255, 0.406 * 255]
7std = [0.229 * 255, 0.224 * 255, 0.225 * 255]
8
9dataset_train = ImageFolderDataset(data_path, shuffle=True)
10
11trans_train = [
12 transforms.RandomCropDecodeResize(size=224, scale=(0.08, 1.0), ratio=(0.75, 1.333)),
13 transforms.RandomHorizontalFlip(prob=0.5),
14 # Ln.15: Normalize data, e.g., the subtract the mean values operation.
15 transforms.Normalize(mean=mean, std=std),
16 transforms.HWC2CHW()
17]
18dataset_train = dataset_train.map(operations=trans_train, input_columns=["image"])
19dataset_train = dataset_train.batch(batch_size=16, drop_remainder=True)