图片数据是深度学习中最常用的数据类型,好的图片数据集对模型训练起着至关重要的作用,要想获得好的数据集,就要对数据集进行预处理操作,比如旋转、切割、归一化等操作,预处理之后再进行数据分批化,就可以传入模型进行训练。总体步骤总结如下:
不论数据从哪里获取,一般都要进行预处理变换操作,torchvision.transforms
是 PyTorch 的图像变换操作库,该库下有很多预处理类,它们的功能各不相同。
import torchvision.transforms as transforms
类 | 描述 |
---|---|
transforms.Compose([transforms.ToTensor(),...]) |
预处理整合,放入其他预处理操作。 |
transforms.ToTensor() |
图像 Tensor 化,将图片像素值转为 [0,1]范围; shape转为 (C,H,W) 格式。 |
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)) | 图像归一化,参数为每个通道的均值与标准差; 若value为像素值,则转换后的value=(value-0.5)/0.5; 注意通道数要和输入图片的通道数相同。 |
transforms.CenterCrop(size) |
从中心裁剪图像,裁剪图像到 (size,size) 大小(输入为整型或元组); 超过图像原本大小的部分填充黑色。 |
transforms.RandomCrop(size) |
随机选取一个位置切割图像,裁剪图像到 (size,size) 大小(输入为整型或元组), 超过原图大小会报错。 |
transforms.RandomHorizontalFlip(p=0.5) |
图像水平翻转,p 为被翻转的概率。 |
transforms.Resize(size) |
调整图像大小。 参数: size:期待输出图片的大小,元组或整型。 当输入为元组 (h,w) 时,输出的大小就是 (h,w)。 当输入为整型 size 时,如果原图 height > weight,输出的大小为 (size*height/width, size)。 interpolation:图像插值方式,默认为线性插值。一般默认即可。(可选) max_size = None:最大尺寸,整型。(可选) antialias = None:抗锯齿标志。(可选) |
transforms.Scale(Resize) |
也可以调整图像尺寸,但是被废弃,改用 transforms.Resize() |
PyTorch 自带以下数据。
from torchvision.datasets import FashionMNIST
数据集对应的类 | 描述 |
---|---|
datasets.MNIST() |
手写字体数据集 |
datasets.FashionMNIST() |
衣服、鞋子、包等10类数据 |
datasets.KMNIST() |
一些文字的灰度数据 |
datasets.CocoCaptions() |
用于图像标注的MS COCO数据 |
datasets.CocoDetection() |
用于检测的MS COCO数据 |
datasets.LSUN() |
10个场景20个目标的分类数据集 |
datasets.CIFAR10() |
CIFAR10类的数据集 |
datasets.CIFAR100() |
CIFAR100类的数据集 |
datasets.STL10() |
10类的分类数据和大量的未分类数据 |
datasets.ImageFolder() |
从本地文件夹中加载并预处理数据,并将图片按照文件夹自动分类 |
参数:
train_data = FashionMNIST/MNIST/KMNIST/CIFAR10/CIFAR100(
root, # 数据保存路径
train=True, # 下载训练数据集还是测试集
transform=transforms.Compose([]), # 数据预处理
target_transform = None, # 标签预处理
download=False, # 是否将数据下载到root中,一般为 True
)
属性:
d = FashionMNIST()
d.classes # 标签名列表,['T-shirt/top', 'Trouser', ......, 'Ankle boot']
d.class_to_idx # 标签名_序号的字典,{'T-shirt/top': 0, ...... ,'Ankle boot': 9}
d.data # 未经 transform 处理的原图片数据
d.targets # 未经 transform 处理的原标签纸
假设有 3 类图片数据,每一类图片单独放在一个文件夹中,那么数据目录应按照如下格式建立:
---- imgdata--------------数据库根目录
|
|---- classes1----------------类别1根目录
| |---- 1.png
| |---- …
|---- classes2----------------类别2根目录
| |---- 1.png
| |---- …
|---- classes3----------------类别3根目录
|---- 1.png
|---- …
此时的图片数据路径可以设为:train_data_root='imgdata/'
支持的图片类型:.jpg, .jpeg, .png, .ppm, .bmp, .pgm, .tif, .tiff, .webp
dataset =torchvision.datasets.ImageFolder()
:从本地文件夹中加载并预处理数据,并将图片按照文件夹自动分类
参数:
dataset =torchvision.datasets.ImageFolder(
root # 数据根目录(必选,str 类型)
transform = None # 对图片进行预处理的操作,返回转换后的图片。两种写法(可选,常用)
'''
# 1. transform=torchvision.transforms.ToTensor()
# 2. transform=torchvision.transforms.Compose([
transforms.Resize(opt.img_size),
transforms.CenterCrop(opt.img_size),
transforms.ToTensor(), # 转化成张量
......])
不管哪种写法,都要有 transforms.ToTensor(),否则容易报错
'''
target_transform = None # 对标签进行预处理的操作,返回转换后的标签(可选,不常用)
loader = default_loader # 数据集的加载方式,一般默认即可(可选)
is_valid_file = None # 获取图像文件的路径并检查该文件是否有效,用于检查损坏的文件,一般不用(可选)
)
属性:
classes # 列表形式的分类名称,如 ['classes1','classes2','classes3']
class_to_idx # 字典形式的类名与标签,如 {'classes1':0,'classes2':1,'classes3':2}
imgs # 包含(image path, class_index)元组形式的列表
获取数据集后,可以将数据集进行合并、拆分以及分批化处理,在图像训练中最常用的就是分批化处理。
from torch.utils.data import *
数据集对应的类 | 描述 |
---|---|
TensorDataset(a,b,c,...) |
将多个tensor数据集沿水平方向合并,它们的第一个维度(batch_size)要相同 |
ConcatDataset([a,b,...]) |
将多个tensor数据集沿垂直方向合并 |
Subset(a,[index1,index2,...]) |
根据索引获取数据集的子集,[index,…] 为具体的索引值 |
random_split(a,[num1,num2,...,]) |
随机将数据集拆分为给定长度的非重叠新数据集 num1+num2+…=len(a) |
DataLoader() |
数据集分批化 |
DataLoader
常用参数:
dataloader = torch.utils.data.DataLoader(
dataset # 从本地或框架加载的数据集
batch_size = 1 # batch_size 大小(可选,int 类型)
shuffle = False # 是否在每个 epoch 打乱数据(可选)
drop_last = False # 是否丢弃最后一个不完整的 batch(可选)
# drop_last=True 时 len(dataset)/batch_size 向下取整
# drop_last=False 时 len(dataset)/batch_size 向上取整
num_workers = 0 # 使用的线程数(可选,int 类型)
)
from torchvision.datasets import FashionMNIST
import torchvision.transforms as transforms
from torch.utils.data import random_split
dataset = FashionMNIST(
root='./data/FashionMNIST', # 数据保存路径
train=False, # 下载训练数据集还是测试集
transform=transforms.ToTensor(),
download=True, # 将数据下载到root中,已存在时不下载
)
print(len(dataset)) # 10000
d1,d2 = random_split(dataset,[2000,8000])
print(len(d1)) # 2000
print(len(d2)) # 8000
from torchvision.datasets import ImageFolder
from torch.utils.data import DataLoader
import torchvision.transforms as transforms
# 1.根目录
root = 'datasets/train'
# 2.预处理加载数据集
dataset = ImageFolder(root,transform=transforms.ToTensor())
print('图片总数量:',len(dataset)) # 3842
print('classes:', dataset.classes) # ['leopard', 'lion', 'tiger']
print('class_to_idx:', dataset.class_to_idx) # {'leopard': 0, 'lion': 1, 'tiger': 2}
print('imgs:\n', dataset.imgs)
# [('datasets/train\\leopard\\1 (100).jpg', 0), ('datasets/train\\leopard\\1 (1000).jpg', 0), ...... ]
# 3.数据集分批
dataloader = DataLoader(dataset=dataset, batch_size=128, shuffle=True, drop_last=True)
print('loader总数量:',len(dataloader)) # 30
for step,(imgs,labels) in enumerate(dataloader):
print('imgs.shape:',imgs.shape) # torch.Size([128, 3, 512, 512])
print('labels.shape:',labels.shape) # labels.shape: torch.Size([128])
print(labels) # tensor([0, 0, 1, ......, 0, 2]