数据读取主要使用dataset和dataloader类。
dataset
dataset函数在乱序的输入数据中,实现对数据的整理和排序,输入数据列表,支持下表检测。
dataloader函数将dataset输出的数据列表打包分块,将数据设置为batchsize大小。
有两种数据组织形式:一种是将同一label类型的数据放入同一文件夹下,文件夹名称就是label;第二种是一个文件夹中放数据,另一个文件夹放label。
所有的数据集都需要继承dataset这个类;每个子类都需要重写getitem这个函数,用于获取数据集和label;可以选择性重写len方法,返回数据集长度。
#torch.utils.data包用于加载数据
#os包用于文件操作
from torch.utils.data import Dataset
import os
from PIL import Image
class Mydata(Dataset):
def __init__(self,root_dir,label_dir):
self.root_dir=root_dir
self.label_dir=label_dir
self.path=os.path.join(self.root_dir,self.label_dir)#将两个路径进行拼接
self.img_list=os.listdir(self.path)#列出路径下的文件列表
def __getitem__(self, idx):
img_path=self.img_list[idx]
img_item_path=os.path.join(self.path,img_path)
img=Image.open(img_item_path)
label=self.label_dir
return img,label
def __len__(self):
return len(self.img_list)
root_dir="D:\\project\\pytorch-tutorial-master\\hymenoptera_data\\train"
label_dir="ants"
ants_data=Mydata(root_dir,label_dir)#创建类的对象
img,label=ants_data[1]#该处使用魔法函数,使类对象具有检索id的功能
img.show()
使用self定义的类中全局变量,使用时通过self.变量,即使该变量的定义和使用在同一函数中
不使用self定义的变量的作用域只有定义变量所在的函数,使用时不需要加self,在其他函数中不能使用
写地址时,使用符号"/""\",不能使用""
魔法函数
上述代码中的三个函数都属于魔法函数。
__init__函数用于初始化类属性,在类创建对象时自动调用,无需用户在外界调用,类似于C++中类的构造函数,在创建对象时自动调用。
__getitem__函数赋予对象id检索功能,用户使用ants_data[id]时相当于自动调用ants_data.getitem(id)。
__len__函数返回长度:len(ants_data)相当于调用ants_data.len()。
tensorboard
显示函数图形和图片
SummaryWriter该类是一个直接向log_dir写东西的事件文件,可以被tensorboard进行解析。
大概就是可以将函数,图片和网络模型写入一个事件文件,该文件在tensorboard上进行显示,SummaryWriter就是操作将函数,图片和网络模型写入事件文件的类。
- 新建SummaryWriter类对象
- 准备数据
- writer.add_image()或writer.add_scalar()
- 关闭writer.close()
from torch.utils.tensorboard import SummaryWriter
import numpy as np
from PIL import Image
writer = SummaryWriter("logs")#新建类
image_path = "data/train/ants_image/6240329_72c01e663e.jpg"
img_PIL = Image.open(image_path)
img_array = np.array(img_PIL)
print(type(img_array))
print(img_array.shape)
writer.add_image("train", img_array, 1, dataformats='HWC')#将图片写入事件文件
# y = 2x
for i in range(100):
writer.add_scalar("y=2x", 3*i, i)#将函数写入事件文件
#关闭
writer.close()
具体执行过程:
- 运行后会生成logs文件夹,且在文件夹下生成执行文件,每运行一次生成一次。
- 执行文件:在terminal中将路径定位到logs文件夹的上一级文件夹输入tensorboard --logdir=logs;默认打开的端口号是6006,为了避免多进程时产生冲突,手动更改端口号,tensorboard --logdir=logs --port=端口号
- 点击链接,进入tensorboard.
注意
当修改writer.add_scalar(“y=2x”,2i,i),再重新运行生成执行文件,再将执行文件打开。生成两个图形。
当只修改函数表达式,不修改title。修改writer.add_scalar(“y=2x”,3i,i),再重新运行生成执行文件,再将执行文件打开。出错。解决方式:把之前logs文件夹下的执行文件删除再重新开始运行;创建新的文件夹放执行文件。
add_scale()
def add_scalar(self, tag, scalar_value, global_step=None, walltime=None):
tag相当于title,scalar_value相当于y轴,global_step相当于x轴
add_image()
def add_image(self, tag, img_tensor, global_step=None, walltime=None, dataformats='CHW'):
tag (string): title
img_tensor (torch.Tensor, numpy.array, or string/blobname): Image data#要求输入图片的格式为tensor,numy,或者字符串
- • Image.open()函数读出图片数组类型为’PIL.JpegImagePlugin.JpegImageFile’
• opencv读取图片数组格式为numpy格式,将数组转换为numpy格式:np.array()
经过Image读取并转成numpy的图像数组格式为(H,W,C),add_image()函数默认使用输入图片的格式为(C,H,W),所以需要指定dataformats参数。
如果后续添加图像,改变图像路径,没有改变title,图像将以step的形式展示(需要修改step);要想让图像单独显示,只需要在生成执行文件时修改title.
transform
transform是一个python文件,里面有很多用于图片处理的类。
如何将图片数据变为tensor数据类型
- 新建一个ToTensor类的对象
- 将图像传入
from torchvision import transforms
from PIL import Image
img_path="D:\\project\\pytorch-learn-code\\pytorch-tutorial-master\\hymenoptera_data\\train\\ants\\0013035.jpg"
img_PIL=Image.open(img_path)
#1.新建一个ToTensor类的对象
tensor_trans=transforms.ToTensor()
#2.将图像传入
#在括号中Ctrl+p可以显示需要输入的参数
img_tensor=tensor_trans(img_PIL)
print(img_tensor)
几种常见的transforms的使用
from PIL import Image
from torchvision import transforms
from torch.utils.tensorboard import SummaryWriter
writer=SummaryWriter("Test")
img=Image.open("D:\\project\\pytorch-learn-code\\pytorch-tutorial-master\imgs\\000.jpg")
#Totensor
tensor_trans=transforms.ToTensor()
img_tensor=tensor_trans(img)
writer.add_image("Totensor",img_tensor)
#Normalize
#input[channel] = (input[channel] - mean[channel]) / std[channel]
trans_norm=transforms.Normalize([0.5,0.5,0.5],[0.5,0.5,0.5])
img_norm=trans_norm(img_tensor)
writer.add_image("Norm",img_norm)
writer.close()
compose的使用
Compose()中的参数需要是一个列表。python中,列表的表示形式为【数据1,数据2,…】,在Compose中,数据需要是transforms类型,所以得到compose([transforms参数1,transforms参数2,…])
from PIL import Image
from torchvision import transforms
from torch.utils.tensorboard import SummaryWriter
writer=SummaryWriter("Test")
img=Image.open("D:\\project\\pytorch-learn-code\\pytorch-tutorial-master\imgs\\000.jpg")
#compose
trans_resize=transforms.Resize(512)
trans_totensor=transforms.ToTensor()
trans_compose=transforms.Compose([trans_resize,trans_totensor])
img_compose=trans_compose(img)
writer.add_image("Compose",img_compose)
writer.close()
• 上述程序是将图片img,先经过resize,再经过totensor。
注意:前面transforms函数的输出,必须和后面transforms函数的输出匹配。
torchvision数据集
• root:数据存储位置
• train:True为训练集,False为测试集
• download:TRUE下载数据集,如果数据集已经下载完成,不会重新下载
transfrom:执行transforms中的操作,对文件中的每张图片都进行
import torchvision
from torch.utils.tensorboard import SummaryWriter
#定义tensorforms操作,将数据集中的每张图片都Totensor
dataset_transform = torchvision.transforms.Compose([
torchvision.transforms.ToTensor()
])
train_set = torchvision.datasets.CIFAR10(root="./dataset", train=True, transform=dataset_transform, download=True)
test_set = torchvision.datasets.CIFAR10(root="./dataset", train=False, transform=dataset_transform, download=True)
# print(test_set[0])#获取第一个图片,类似于之前的Dataset
# print(test_set.classes)#获取类别序列
# img, target = test_set[0]#target是类别id,对应在classes列表中的索引
# print(img)
# print(target)
# print(test_set.classes[target])
#将数据集中的前10个在tensorboard中进行显示
writer = SummaryWriter("p10")
for i in range(10):
img, target = test_set[i]
writer.add_image("test_set", img, i)
writer.close()
dataloader
dataset是数据集,dataloader是从dataset中取部分数据送入神经网络。
○ dataset:没有默认值,数据集的位置,数据集的索引,第一张,第二张数据到底是什么;总共有多少数据
○ batch_size:每次读取数据的数量
○ shuffle:读取数据之前是否将数据打乱,TRUE打乱
○ batch_sampler
○ num_workers:是否采用多进程加载数据
drop_last:当数据不够一个batch时,剩下的数据是舍弃还是不舍弃,TRUE舍弃
import torchvision
# 准备的测试数据集
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter
#测试数据集
test_data = torchvision.datasets.CIFAR10("./dataset", train=False, transform=torchvision.transforms.ToTensor())
#加载测试集
test_loader = DataLoader(dataset=test_data, batch_size=64, shuffle=True, num_workers=0, drop_last=True)
# 测试数据集中第一张图片及target
img, target = test_data[0]
print(img.shape)
print(target)
writer = SummaryWriter("dataloader")
for epoch in range(2):
step = 0
for data in test_loader:
imgs, targets = data
# print(imgs.shape)
# print(targets)
writer.add_images("Epoch: {}".format(epoch), imgs, step)
step = step + 1
writer.close()