pytorch入门:utils.data , torchvision , tensorboardX

pytorch数据处理工作箱

数据下载和预处理是机器学习,深度学习项目种耗时有重要的任务,数据预处理关系到数据质量和模型性能,pytorch提供了专门的数据下载,数据处理包。

概述

数据处理(数据装载,数据预处理,数据增强)主要工具包和相互关系:
在这里插入图片描述
左边是 torch.utils.data 工具包,包括四个类:

  • Dataset,一个抽象类,其他数据要继承这个类,并且覆写_getitem__ ,len 的构造方法。
  • DataLoader: 定义一个新的迭代器,实现批量(batch)读取,大量数据(shuffle)并提供并行加速等功能。
  • random_split: 把数据集随机拆分为给定长度的非重叠的新数据集
  • *sampler: 多种采样函数。

中间的 torchvision 是可视化处理工具,是一个视觉处理包,需要额外安装。主要功能:

  • datasets 提供常用的数据加载,继承自 utils.data.Dataset,比如 COCO, MMIST等。
  • models: 提供深度学习种各种经典的网络结构和已经训练好的模型(芜湖,pretrained=True),包括 AlexNet,VGG ,ResNet等。
  • transforms,常用的数据处理操作,包括对 tensor,PIL Image的操作。
  • utils 包括两个函数,make_grid,将多张图片拼接在一个网络种,一个 save_img, 将 tensor 保存成图片。

utils.data 简介

utils.data 包括 Dataset and DataLoader ,torch.utils.data.Dataset 为抽象类。自定义的数据集要继承这个类,并构造 len, getitem ,两个函数,前者提供数据的大小(size), 后者通过给定索引获得数据和标签。getitem 一次获得一个数据,需要通过 DataLoader 定义迭代器,实现batch 读取。

import torch
from torch.utils import data
import numpy as np

# 定义获取数据的类
class TestDataset(data.Dataset):#继承Dataset
    def __init__(self):
        self.Data=np.asarray([[1,2],[3,4],[2,1],[3,4],[4,5]])#一些由2维向量表示的数据集
        self.Label=np.asarray([0,1,0,1,2])#这是数据集对应的标签

    def __getitem__(self, index):
        #把numpy转换为Tensor
        txt=torch.from_numpy(self.Data[index])
        label=torch.tensor(self.Label[index])
        return txt,label 

    def __len__(self):
        return len(self.Data)

Test=TestDataset()
print(Test[2])  #相当于调用__getitem__(2)
print(Test.__len__())


#輸出:
#(tensor([2, 1]), tensor(0))  # 只返回一个样本,批量处理要同时进行打乱和并行加速的操作
#5							  # 可以使用DataLoader

data.DataLoader(
	dataset,						# 加载的数据集
	batch_size=1,					# 批大小
	shuffle=False,					# 是否打乱数据
	sampler=None, 					# 样本抽样
	batch_sample=None,				
	num_workers=0,					# 多进程加载的进程数,0表示不使用
	collate_fn=<function default_collate at 0x7f108ee01620>, 
	pin_memory=False,				# 是否将内存保存在pin memory区,这样转到GPU 更快一些
	drop_last=False,				# 将不足一个batch的数据丢弃,为True时。
	timeout=0,
	worker_init_fn=None
)

test_loader = data.DataLoader(Test,batch_size=2,shuffle=False)
for i,traindata in enumerate(test_loader):
    print('i:',i)
    Data,Label=traindata
    print('data:',Data)
    print('Label:',Label)
>>>
i: 0
data: tensor([[1, 2],
        [3, 4]])
Label: tensor([0, 1])
i: 1
data: tensor([[2, 1],
        [3, 4]])
Label: tensor([0, 1])
i: 2
data: tensor([[4, 5]])     # 只有5个数据
Label: tensor([2])


dataiter=iter(test_loader)    # 也可以转换成迭代器在读取
imgs,labels=next(dataiter)
#imgs.size()

一般用dataset 处理同一个目录下的数据,如果数据在不同的目录下,就不是很方便,这就可以使用 torchvision ,可以自动获取标签,还提供了很多数据处理,增强的转换函数。

torchvision 简介

transforms

提供了对 PIL Image对象和Tensor对象的常用操作

  1. 对PIL Image:
  • Scale/Resize,调整尺寸,长宽比保持不变
  • CenterCrop, RandomCrop ,RandomSizedCrop, 剪裁图片,前两个是固定size, 后一个则是random size 。
  • Pad 填充
  • ToTensor ,将一个取值为 [0,255] 的PIL.Image转成Tensor ,形状为(H,W,C) 的nudarray 转换成 【C,H,W】 取值为【0,1】 的torch.FloatTensor
  • RandomHorizontalFlip 图像随机水平翻转,翻转概率为 0.5。
  • RandomVerticalFlip ,图像随机垂直翻转。
  • ColorJitter,修改两队,对比度,和饱和度
  1. 对Tensor :
  • Normalize,标准化,减去平均值,除以标准差。
  • ToPILImage 将Tensor 转为PIL Image

对数据集进行对各操作,就通过Compose将这些操作拼接。

import torch
import torchvision
import torchvision.transforms as transforms

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))# 三维就要有三个
    transforms.Lambda(lambda x:x.add(10))      # 自定个 lambda 表达式,每个像素加10 
])

ImageFolder

当文件依据标签处于不同文件下时,如:
─── data
    ├── zhangliu
    │   ├── 001.jpg
    │   └── 002.jpg
    ├── wuhua
    │   ├── 001.jpg
    │   └── 002.jpg
    .................
可以利用 torchvision.datasets.ImageFolder 来直接构造 dataset
loader = datasets.ImageFolder(path)    # 将目录中的文件名自动转换为序列,
loader = data.DataLoader(dataset)    # 载入后,标签自动就是整数序列了

from torchvision import transforms, utils
from torchvision import datasets
import torch
import matplotlib.pyplot as plt 
# %matplotlib inline

my_trans=transforms.Compose([
    transforms.RandomResizedCrop(224),
    transforms.RandomHorizontalFlip(),
    transforms.ToTensor()
])
train_data = datasets.ImageFolder('./data/torchvision_data', transform=my_trans)   # 读取数据然后进行处理
train_loader = data.DataLoader(train_data,batch_size=8,shuffle=True,)
                                            
for i_batch, img in enumerate(train_loader):
    if i_batch == 0:
        print(img[1])         # 标签
        fig = plt.figure()
        grid = utils.make_grid(img[0])       
        plt.imshow(grid.numpy().transpose((1, 2, 0)))
        plt.show()
        utils.save_image(grid,'test01.png')
    break

可视化工具

Tensorboard 是 tensorflow 的可视化工具,可以记录训练数据,评估数据,网格结构,图像等。可以在 web 上展示,对于观察神经网络训练的过程非常有帮助,虽然也可以采用 tensorboard_logger , visdom 等工具,但这些方法比较复杂,所以推出了更厉害的 tensorboardX.

tensorboardX 简介

支持 scalar,image,figure,histogram,audio,text,graph ,onnx_graph,,,等可视化方式。
使用步骤:

from tensorboardX import SummaryWriter
write = SumaryWriter(log_dir='log')  # 指定日志存放路径
# SummaryWriter(log_dir=, comment='', **kwargs) comment 文件名后的后缀,也可以不指定路径自动创建一个runs 目录
writer.add_xxx()    # 调用实例
# add_xxx(tag=name,object,iteration=number) 标签,记录的对象,迭代次数
writer.close()    # 关闭


# 启动tensorboard服务
到日志的目录,输入:
tensorboard --logdir=logs 
然后再浏览器中打开返回的目录就行 http://localhost:port  

在这里插入图片描述

用tensorboardX可视化神经网络

import torch
import torch.nn as nn
import torch.nn.functional as F
import torchvision
from tensorboardX import SummaryWriter

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

#定义输入
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, ))

。。我画出来就三个块。。。说是要降低一下版本。。。以后在搞吧。。看来这玩意都不能下最新版的啊。。。
在这里插入图片描述

用tensorboardX可视化损失值

一层全连接神经网络,训练一个一元二次函数的参数。

import torch
import torch.nn as nn
from tensorboardX import SummaryWriter
import numpy as np

input_size = 1
output_size = 1
num_epoches = 60
learning_rate = 0.01

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)   # 加噪声


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)

浏览器中,如果没有立刻出图的话可以等一下刷新试试。。。玄学
在这里插入图片描述

用 tensorboardX 可视化特征图

不同卷积层的特征图的抽取程度是不一样的

import torch
import torchvision
import torchvision.transforms as transforms
from tensorboardX import SummaryWriter

transform = transforms.Compose(
    [transforms.ToTensor(),
     transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])

# 可以百度下一个cifar10数据集,更快。。
trainset = torchvision.datasets.CIFAR10(root='./data', train=True,
                                        download=False, transform=transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=4,
                                          shuffle=True, num_workers=2)

testset = torchvision.datasets.CIFAR10(root='./data', train=False,
                                       download=False, transform=transform)
testloader = torch.utils.data.DataLoader(testset, batch_size=4,
                                         shuffle=False, num_workers=2)

classes = ('plane', 'car', 'bird', 'cat',
           'deer', 'dog', 'frog', 'horse', 'ship', 'truck')

import torch.nn as nn
import torch.nn.functional as F
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

class CNNNet(nn.Module):   # 这就来CNN 了吗
    def __init__(self):
        super(CNNNet,self).__init__()
        self.conv1 = nn.Conv2d(in_channels=3,out_channels=16,kernel_size=5,stride=1)
        self.pool1 = nn.MaxPool2d(kernel_size=2,stride=2)
        self.conv2 = nn.Conv2d(in_channels=16,out_channels=36,kernel_size=3,stride=1)
        self.pool2 = nn.MaxPool2d(kernel_size=2, stride=2)
        self.fc1 = nn.Linear(1296,128)
        self.fc2 = nn.Linear(128,10)      

    def forward(self,x):
        x=self.pool1(F.relu(self.conv1(x)))
        x=self.pool2(F.relu(self.conv2(x)))
        #print(x.shape)
        x=x.view(-1,36*6*6)
        x=F.relu(self.fc2(F.relu(self.fc1(x))))
        return x

net = CNNNet()
net=net.to(device)

import torch.optim as optim
LR=0.001

criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=LR, momentum=0.9)
#初始化数据
for m in net.modules():
    if isinstance(m,nn.Conv2d):    # 是否是卷积层
        nn.init.normal_(m.weight)
        nn.init.xavier_normal_(m.weight)
        nn.init.kaiming_normal_(m.weight)    #卷积层参数初始化
        nn.init.constant_(m.bias, 0)
    elif isinstance(m,nn.Linear):
        nn.init.normal_(m.weight)   #全连接层参数初始化,,以后会看明白的对吧。。。

#训练模型
for epoch in range(2):  

    running_loss = 0.0
    for i, data in enumerate(trainloader, 0):
        # 获取训练数据
        inputs, labels = data
        inputs, labels = inputs.to(device), labels.to(device)

        # 权重参数梯度清零
        optimizer.zero_grad()

        # 正向及反向传播
        outputs = net(inputs)     # 都是自动正向传播的
        loss = criterion(outputs, labels) 
        loss.backward()       # 损失反向
        optimizer.step() 

        # 显示损失值
        running_loss += loss.item()
        if i % 2000 == 1999:    # 2000个批量打印一次损失
            print('[%d, %5d] loss: %.3f' %(epoch + 1, i + 1, running_loss / 2000))
            running_loss = 0.0

print('Finished Training')


import torchvision.utils as vutils
writer = SummaryWriter(log_dir='logs',comment='feature map')
for i, data in enumerate(trainloader, 0):
    # 获取训练数据
    inputs, labels = data
    inputs, labels = inputs.to(device), labels.to(device)
    x=inputs[0].unsqueeze(0)     # torch.Size([1, 3, 32, 32])
    break

img_grid = vutils.make_grid(x, normalize=True, scale_each=True, nrow=2)

net.eval()
for name, layer in net._modules.items():

    # 为fc层预处理x
    x = x.view(x.size(0), -1) if "fc" in name else x
    print(x.size())

    x = layer(x)
    print(f'{name}')

    # 查看卷积层的特征图
    if  'layer' in name or 'conv' in name:
        x1 = x.transpose(0, 1)  # C,B, H, W  ---> B,C, H, W
        img_grid = vutils.make_grid(x1, normalize=True, scale_each=True, nrow=4)  # normalize进行归一化处理
        writer.add_image(f'{name}_feature_maps', img_grid, global_step=0)

在这里插入图片描述

出现的问题

我的是 1.7.0 的报错 Output 0 of UnbindBackward is a view and is being modified inplace。。。

解决方法就是 脑补链接 ,将报错的 utils.py 里的 74行改成:
在这里插入图片描述
绝了。。。

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值