torchvision中有4个功能模块:model、datasets、transforms和utils。利用datasets可以下载一些经典数据集。这里将重点介绍如何使用datasets的ImageFolder处理自定义数据集,以及如何使用transforms对源数据进行预处理、增强等。
transforms提供了对PIL Image对象和Tensor对象的常用操作。
Scale/Resize:调整尺寸,长宽比保持不变。
CenterCrop、RandomCrop、RandomSizedCrop:裁剪图片,CenterCrop和RandomCrop在crop时是固定size,RandomResizedCrop则是random size的crop。
Pad:填充。
ToTensor:把一个取值范围是 [ 0 , 255 ] [0, 255] [0,255]的PIL.Image转换成Tensor。形状为 ( H , W , C ) (H, W, C) (H,W,C)的Numpy.ndarray转换成形状为 [ C , H , W ] [C, H, W] [C,H,W],取值范围是 [ 0 , 1.0 ] [0, 1.0] [0,1.0]的torch.FloatTensor。
RandomHorizontalFlip:图像随机水平翻转,翻转概率为0.5。
RandomVerticalFlip:图像随机垂直翻转。
ColorJitter:修改亮度、对比度和饱和度。
Normalize:标准化,即,减均值,除以标准差。
ToPILImage:将Tensor转为PIL Image。
如果要对数据集进行多个操作,可通过Compose将这些操作像管道一样拼接起来,类似于nn.Sequential。以下为示例代码:
transforms.Compose([
# 将给定的PIL.Image进行中心切割,得到给定的size,
# size可以是tuple, (target_height, target_width)
# size也可以是一个Integer,在这种情况下,切出来的图片形状是正方形。
transforms.CenterCrop(10),
# 切割中心点的位置随机选取
transforms.RandomCrop(20, padding=0),
# 把一个取值范围是[0, 255]的PIL.Image或者shape为(H, W, C)的numpy.ndarray,
# 转换为形状为(C, H, W),取值范围是[0, 1]的torch.FloatTensor
transforms.ToTensor(),
#规范化到[-1, 1]
transforms.Normalize(mean = (0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5))
还可以自定义一个Python Lambda表达式,如将每个像素值加10,可表示为:transforms.Lambda(lambda x: x.add(10))。
更多内容请参考link
当文件依据标签处于不同文件下时,如:
─── data
├── zhangliu
│ ├── 001.jpg
│ └── 002.jpg
├── wuhua
│ ├── 001.jpg
│ └── 002.jpg
…
可以利用torchvision.datasets.ImageFolder来直接构造出dataset,代码如下:
loader = datasets.ImageFolder(path)
loader = data.DataLoader(dataset)
ImageFolder会将目录中的文件夹名自动转化成序列,当DataLoader载入时,标签自动就是整数序列了。
Tensorboard是Google TensorFlow的可视化工具,它可以记录训练数据、评估数据、网络结构、图像等,并且可以在web上展示,对于观察神经网络训练的过程非常有帮助。pytorch可以采用tensorboard_logger、visdom等可视化工具,但这些方法比较复杂或不够友好。为了解决这一问题,人们推出了可用于pytorch可视化的新的更强大的工具——tensorboardX。
tensorboardX功能很强大,支持scalar、image、figure、histogram、audio、text、graph、onnx_graph、embedding、pr_curve and videosummaries等可视化方式。
使用tensorboardX的一般步骤如下所示。
1)导入tensorboardX,实例化SummaryWriter类,指明记录日志路径等信息。
from tensorboardX import SummaryWriter
# 实例化SummaryWriter,并指明日志存放路径。在当前目录没有logs目录将自动创建。
writer = SummaryWriter(log_dir='logs')
# 调用实例,这里只是泛指
writer.add_xxx()
# 关闭writer
writer.close()
说明:
①如果是Windows环境,log_dir注意路径解析,如:
# 无需考虑下述用法:
# writer = SummaryWriter(log_dir=r'D:\myboard\test\logs')
②SummaryWriter格式为:
SummaryWriter(log_dir=None, comment=' ', **kwargs)
# 其中comment在文件命名加上comment后缀
③如果不写log_dir,系统将在目录创建一个runs的目录。
2)调用相应的API接口,接口一般格式为:
add_xxx(tag-name, object, iteration-number)
# 即add_xxx(标签,记录的对象,迭代次数)
3)启动tensorboard服务:
cd到logs目录所在的同级目录,在命令行输入如下命令,logdir等式右边可以是相对路径或绝对路径。
# 这是进入到logs的根目录时,命令行执行的操作
tensorboard --logdir=logs --port 6006
# 这是未进入到logs的根目录时,命令行执行的操作
# tensorboard --logdir=D:\myboard\test\logs --port 6006
4)web展示
在浏览器输入
http://服务器IP或名称:6006 # 如果是本机,服务器名称可以使用localhost
就可以看到logs目录保存的各种图形。
有关tensorboardX的更多内容,可以参考官网:link
1)导入需要的模块
import torch
import torch.nn as nn
import torch.nn.functional as F
import torchvision
from tensorboardX import SummaryWriter
2)构建神经网络
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.conv1 = nn.Conv2d(1, 10, kernel_size=5)
self.conv2 = nn.Conv2d(10, 20, kernel_size=5)
self.conv2_drop = nn.Dropout2d()
self.fc1 = nn.Linear(320, 50)
self.fc2 = nn.Linear(50, 10)
self.bn = nn.BatchNorm2d(20)
def forward(self, x):
x = F.max_pool2d(self.conv1(x), 2)
x = F.relu(x) + F.relu(-x)
x = F.relu(F.max_pool2d(self.conv2_drop(self.conv2(x)), 2))
x = self.bn(x)
x = x.view(-1, 320)
x = F.relu(self.fc1(x))
x = F.dropout(x, training=self.training)
x = self.fc2(x)
x = F.softmax(x, dim=1)
return x
3)把模型保存为graph
input = torch.rand(32, 1, 28, 28)
# 实例化神经网络
model = Net()
# 将model保存为graph
with SummaryWriter(log_dir='logs', comment='Net') as w:
w.add_graph(model, (input,))
之后就可以打开浏览器查看网络详细内容,对上面的打开解释不够清楚的,也可以参考这篇文章学习如何打开link
可视化损失值,需要使用add_scalar函数,这里利用一层全连接神经网络,训练一元二次函数的参数。
import torch
import numpy as np
import torch.nn as nn
import torch.optim as optim
from tensorboardX import SummaryWriter
dtype = torch.FloatTensor
writer = SummaryWriter(log_dir='logs', comment='Linear')
np.random.seed(100)
x_train = np.linspace(-1, 1, 100).reshape(100, 1)
y_train = 3 * np.power(x_train, 2) + 2 + 0.2 * np.random.rand(x_train.size).reshape(100, 1)
input_size = 1
output_size = 1
learning_rate = 0.01
num_epoches = 60
model = nn.Linear(input_size, output_size)
criterion = nn.MSELoss()
optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate)
for epoch in range(num_epoches):
inputs = torch.from_numpy(x_train).type(dtype)
targets = torch.from_numpy(y_train).type(dtype)
output = model(inputs)
loss = criterion(output, targets)
optimizer.zero_grad()
loss.backward()
optimizer.step()
# 保存loss的数据与epoch数据
writer.add_scalar('训练损失值', loss, epoch)
吴茂贵,郁明敏,杨本法,李涛,张粤磊. Python深度学习(基于Pytorch). 北京:机械工业出版社,2019.