在利用PyTorch开始进入深度学习“大坑”的时候必须将以上的几个模块熟练掌握,这样才可以运用自如的写自己的算法或者魔改别人算法的code,下面将对以上几个模块逐一介绍其重点和一些注意事项。
Dataset & DataLoader 属于 torch中 torch.utils.data 中的模块,要使用 Dataset & DataLoader时, 必须预先导入,具体代码如下所示:
# DataLoader & Dataset 同时使用时一起导入
from torch.utils.data import Dataset Dataloader
# DataLoader & Dataset 不是同时使用时,需要哪一个就导入哪一个
# 利用 Dataset 来构建自己的数据集时,必须导入Dataset
from torch.utils.data import Dataset
# 利用DataLoader 来加载自己的数据集或者官方提供的数据集时,必须导入Dataloader
from torch.utils.data import Dataloader
Dataset 是一个抽象类,为了能够方便的读取,需要将要使用的数据包装为Dataset类。
自定义的Dataset需要继承它并且实现两个成员方法:
# 使用kaggle上的一个竞赛bluebook for bulldozers自定义一个数据集
import torch
from torch.utils.data import Dataset # 导入抽象类Dataset
import pandas as pd # 本质是使用pandas进行处理,只是相当于进行了封装。
# 定义一个数据集
class BulldozerDataset(Dataset):
""" 数据集演示 """
def __init__(self, csv_file):
# 实现初始化方法,在初始化的时候将数据读载入
# 数据保存在self.df中
self.df=pd.read_csv(csv_file)
def __len__(self): # 本质替换定义了len()函数的作用
# 返回df的长度
return len(self.df)
def __getitem__(self, idx): # 本质定义了替换iloc[]的作用
# 根据 idx 返回一行数据
return self.df.iloc[idx].SalePrice
# 实例化一个对象访问它
ds_demo= BulldozerDataset('median_benchmark.csv') #传入一个.csv文件
#实现了 __len__ 方法所以可以直接使用len获取数据总数
len(ds_demo)
# output: 11573
#用索引可以直接访问对应的数据,对应 __getitem__ 方法
ds_demo[0]
# output: 24000.0
# 对刚刚上面建立的Dataset,利用DataLoader 进行读取。
dl = torch.utils.data.DataLoader(ds_demo, batch_size=10, shuffle=True, num_workers=0)
# DataLoader返回的是一个可迭代对象,我们可以使用迭代器分次获取数据
# DataLoader本质是一个类,用来实现复杂的函数功能和其他功能
# .csv(原始数据)--->ds_demo(Dataset类对象)--->dl(DataLoader类对象)
idata=iter(dl) # iter() 迭代函数
print(next(idata))
# 更常见的用法是使用for循环对其进行遍历
for i, data in enumerate(dl):
print(i,data)
# 为了节约空间,这里只循环一遍
break
# output:0 tensor([24000., 24000., 24000., 24000., 24000., 24000., 24000., 24000., 24000., 24000.], dtype=torch.float64)
# 第一个维度是batch_size==10,每一个元素其实是一个实际的数据
import os
from PIL import Image
from torch.utils.data import Dataset
class PatchDataset(Dataset):
def __init__(self, data_dir, transform=None):
"""
:param data_dir: 数据集所在路径
:param transform: 数据预处理
"""
self.data_info = self.get_img_info(data_dir)
self.transform = transform
def __getitem__(self, item):
path_img, label = self.data_info[item]
image = Image.open(path_img).convert('RGB')
if self.transform is not None:
image = self.transform(image)
return image, label
def __len__(self):
return len(self.data_info)
@staticmethod
def get_img_info(data_dir):
path_dir = os.path.join(data_dir, 'train_dataset.txt')
data_info = []
with open(path_dir) as file:
lines = file.readlines()
for line in lines:
data_info.append(line.strip('\n').split(' '))
return data_info
from torch.utils.data import Dataset, DataLoader
from torchvision import transforms, utils
normalize = transforms.Normalize(
mean=[0.485, 0.456, 0.406],
std=[0.229, 0.224, 0.225]
)
preprocess = transforms.Compose([
#transforms.Scale(256),
#transforms.CenterCrop(224),
transforms.ToTensor(),
normalize
])
def default_loader(path):
img_pil = Image.open(path)
img_pil = img_pil.resize((224,224))
img_tensor = preprocess(img_pil)
return img_tensor
#当然出来的时候已经全都变成了tensor
class trainset(Dataset):
def __init__(self, loader=default_loader):
#定义好 image 的路径
self.images = file_train
self.target = number_train
self.loader = loader
def __getitem__(self, index):
fn = self.images[index]
img = self.loader(fn)
target = self.target[index]
return img,target
def __len__(self):
return len(self.images)
A custom Dataset class must implement three functions: init, len, and getitem.
# A example
# The FashionMNIST images are stored in a directory img_dir, and their labels are stored separately in a CSV file annotations_file.
import os
import pandas as pd
from torchvision.io import read_image # 该函数读取图像的结果直接输出是一个tensor
class CustomImageDataset(Dataset):
def __init__(self, annotations_file, img_dir, transform=None, target_transform=None):
self.img_labels = pd.read_csv(annotations_file)
self.img_dir = img_dir
self.transform = transform
self.target_transform = target_transform
def __len__(self):
return len(self.img_labels)
def __getitem__(self, idx):
img_path = os.path.join(self.img_dir, self.img_labels.iloc[idx, 0])
image = read_image(img_path)
label = self.img_labels.iloc[idx, 1]
if self.transform:
image = self.transform(image)
if self.target_transform:
label = self.target_transform(label)
return image, label
注:在构建自己的Dataset时候,如果需要用额外的包读图像,最好还是用 PIL,因为pytorch源码里就是用到了 PIL 读取图像。
# 下载并存放数据集
train_dataset = torchvision.datasets.CIFAR10(root="数据集存放位置",download=True)
# load数据
train_loader = torch.utils.data.DataLoader(dataset=train_dataset)
datasets 属于 torchvision 中的模块,需要利用datasets中的数据时必须提前将其导入,具体代码如下所示
from torchvision import datasets
# 具体例子 1如下所示:
import torch
import torchvision
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader
import torchvision.transforms as transforms
data_transform = transforms.Compose([
transforms.Resize(299),
transforms.CenterCrop(299),
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406],
std=[0.229, 0.224, 0.225])
])
train_dataset =torchvision.datasets.ImageFolder(root='ILSVRC2012/train',transform=data_transform)
train_dataset_loader =DataLoader(train_dataset,batch_size=4, shuffle=True,num_workers=4)
train_dataset = torchvision.datasets.ImageFolder(root='ILSVRC2012/val',transform=data_transform)
train_dataset_loader = DataLoader(train_dataset,batch_size=4, shuffle=True,num_workers=4)
# 具体例子 2 如下所示:
import os
import torch
import numpy as np
import matplotlib.pyplot as plt
from torch.utils.data import Dataset, DataLoader
from torchvision import transforms, datasets
data_transform = transforms.Compose([
transforms.RandomSizedCrop(224),
transforms.RandomHorizontalFlip(),
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406],
std=[0.229, 0.224, 0.225])
])
hymenoptera_dataset = datasets.ImageFolder(root='hymenoptera_data/train', # 下载到本地ImageNet的路径
transform=data_transform)
dataset_loader = torch.utils.data.DataLoader(hymenoptera_dataset,
batch_size=4, shuffle=True,
num_workers=4)
models 属于 torchvision 中的模块,需要调用时,需预先导入,具体代码如下所示:
# 直接导入models
import torchvision.models
# 导入并用别名
import torchvision.models as models
alexnet vgg resnet squeezenet densenet inception googlenet shufflenet
You can construct a model with random weights by calling its constructor:
import torchvision.models as models
resnet18 = models.resnet18()
alexnet = models.alexnet()
vgg16 = models.vgg16()
squeezenet = models.squeezenet1_0()
densenet = models.densenet161()
inception = models.inception_v3()
googlenet = models.googlenet()
shufflenet = models.shufflenet_v2_x1_0()
mobilenet_v2 = models.mobilenet_v2()
mobilenet_v3_large = models.mobilenet_v3_large()
mobilenet_v3_small = models.mobilenet_v3_small()
resnext50_32x4d = models.resnext50_32x4d()
wide_resnet50_2 = models.wide_resnet50_2()
mnasnet = models.mnasnet1_0()
ImageNet 1-crop error rates (224x224)
# ImageNet 的均值和方差
normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406],
std=[0.229, 0.224, 0.225])
The accuracies of the pre-trained models evaluated on COCO val2017 are as follows
Here are the summary of the accuracies for the models trained on the instances set of COCO train2017 and evaluated on COCO val2017.
transforms 属于 torchvision 中的模块,用于对数据进行预处理,主要是图像的处理( 有22个function),可以使用Compose将其链接在一起。
最常用的处理:CenterCrop、Grayscale、RandomCrop、RandomHorizontalFlip、RandomVerticalFlip、RandomRotation、Normalize、ToTensor
# torchvision.transforms.Compose(transforms)
# Compose的例子 1
transforms.Compose([
transforms.CenterCrop(10),
transforms.ToTensor(),
])
# Compose的例子 2
data_transform = transforms.Compose([
transforms.RandomSizedCrop(224),
transforms.RandomHorizontalFlip(),
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406],
std=[0.229, 0.224, 0.225])
])