2.数据读取与数据扩增
2.1 学习目标
- 学习python和pytorch中图像读取
- 学会扩增方法和pytorch读取赛题数据
2.2 图像读取
python常用的对图像读取的库
- Pillow(Pillow是Python里的图像处理库,PIL:Python Image Library)
- openCV
2.2.1 pillow
# 导入pillow库
from PIL import Image
# 类中的函数
im = Image.open(''xxx.jpg) # 读取照片
Image.new(mode, size, color) # 创建一副(size,size),颜色为color的图片
Image.blend(image1, image2, alpha) #合并两张图片,image1 * ( 1.0 - alpha ) + image2 * alpha
# 类中的方法
im.copy() # 复制图像,但仍然会保留原图像。
im.filter( filter ) # 对图片使用滤波器后的副本
im.crop( box ) # 返回图像某个给定区域。box 是一个 4 元素元组,定义了 left, upper, right, lower 像素坐标。
im.save() # 保存图片
Pillow的官方文档:https://pillow.readthedocs.io/en/stable/
2.2.2 OpenCV
# 导入OpenCV库
import cv2
# 加载图片
img.imread('cat.jpg')
#opencv默认颜色通道为BRG,转换成RGB
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
# 转换为灰度图
img = cv2.cvtColor(img, cv2.COLOR_BGR2GREY)
# 边缘检测
edges = cv2.Canny(img, 30, 70) # 参数2、3表示最低、高阈值
cv2.imwrire('cat.jpg', edges)
OpenCV包含了众多的图像处理的功能,OpenCV包含了你能想得到的只要与图像相关的操作。此外OpenCV还内置了很多的图像特征处理算法,如关键点检测、边缘检测和直线检测等。
2.3 数据扩增方法(Data Augmentation)
- 数据扩增的作用
在深度学习模型的训练过程中,数据扩增是必不可少的环节。现有深度学习的参数非常多,一般的模型可训练的参数量基本上都是万到百万级别,而训练集样本的数量很难有这么多,数据扩增可以增加样本的数量。
其次数据扩增可以扩展样本空间,假设现在的分类模型需要对汽车进行分类,左边的是汽车A,右边为汽车B。如果不使用任何数据扩增方法,深度学习模型会从汽车车头的角度来进行判别,而不是汽车具体的区别。
- 数据扩增的方法
在常见的数据扩增方法中,一般会从图像颜色、尺寸、形态、空间和像素等角度进行变换。当然不同的数据扩增方法可以自由进行组合,得到更加丰富的数据扩增方法。
以torchvision为例,常见的数据扩增方法包括:
- transforms.CenterCrop 对图片中心进行裁剪
- transforms.ColorJitter 对图像颜色的对比度、饱和度和零度进行变换
- transforms.FiveCrop 对图像四个角和中心进行裁剪得到五分图像
- transforms.Grayscale 对图像进行灰度变换
- transforms.Pad 使用固定值进行像素填充
- transforms.RandomAffine 随机仿射变换
- transforms.RandomCrop 随机区域裁剪
- transforms.RandomHorizontalFlip 随机水平翻转
- transforms.RandomRotation 随机旋转
- transforms.RandomVerticalFlip 随机垂直翻转
2.4 Pytorch读取数据
在Pytorch中数据是通过Dataset进行封装,并通过DataLoder进行并行读取。
- Dataset: 对数据集的封装,提供索引方式的对数据样本进行读取
- DataLoder: 对Dataset进行封装,提供批量读取的迭代读取
import os, sys, glob, shutil, json
import cv2
from PIL import Image
import numpy as np
import torch
from torch.utils.data.dataset import Dataset
import torchvision.transforms as transforms
class SVHNDataset(Dataset):
def __init__(self, img_path, img_label, transform=None):
self.img_path = img_path
self.img_label = img_label
if transform is not None:
self.transform = transform
else:
self.transform = None
def __getitem__(self, index):
img = Image.open(self.img_path[index]).convert('RGB')
if self.transform is not None:
img = self.transform(img)
# 对每一列的标签转化成numpy格式进行处理
lbl = np.array(self.img_label[index], dtype=np.int
# 如果不足5个,扩充为5个字符。
# 列表相加为组合,列表乘一个数为重复几次。结果示例[1,2,10,10,10]
lbl = list(lbl) + (5 - len(lbl)) * [10]
return img, torch.from_numpy(np.array(lbl[:5]))
def __len__(self):
return len(self.img_path)
train_path = glob.glob('../input/train/*.png')
train_path.sort()
train_json = json.load(open('../input/train.json'))
train_label = [train_json[x]['label'] for x in train_json]
data = SVHNDataset(train_path, train_label,
transforms.Compose([
# 缩放到固定尺寸
transforms.Resize((64, 128)),
# 随机颜色变换
transforms.ColorJitter(0.2, 0.2, 0.2)
# 加入随机旋转(+-5度)
transforms.RandomRotation(5),
# 将图片转换为pytorch 的tesntor
# transforms.ToTensor(),
# 对图像像素进行归一化
# transforms.Normalize([0.485,0.456,0.406],[0.229,0.224,0.225])
]))
2.5 torch的Dataset和DataLoader
- pytorch提供了一个数据读取的方法,其由两个类构成:torch.utils.data.Dataset 和 DataLoader
- 我们要自定义自己数据读取的方法,就需要继承torch.utils.data.Dataset,并将其封装到DataLoader中
- torch.utils.data.Dataset表示该数据集,继承该类可以重载其中的方法,实现多种数据读取及数据预处理方式
- torch.utils.data.DataLoader 封装了Data对象,实现单(多)进程迭代器输出数据集
2.5.1 torch.utils.data.Dataset
- 要自定义自己的Dataset类,至少要重载两个方法,__ len __, __ getitem __
- __len__返回的是数据集的大小
- __getitem__实现索引数据集中的某一个数据
- 除了这两个基本功能,还可以在__getitem__时对数据进行预处理,或者是直接在硬盘中读取数据,对于超大的数据集还可以使用lmdb来读取
getitem 就是使得input 和output一一对应的关键
2.5.2 torch.utils.data.Dataloader
- Dataloader将Dataset或其子类封装成一个迭代器
- 这个迭代器可以迭代输出Dataset的内容
- 同时可以实现多进程、shuffle、不同采样策略,数据校对等等处理过程