# ----------------------------------第五章 PyTorch常用工具模块--------------------------------------
# 主要三大部分:数据,可视化和GPU加速
# -------------------5.1 数据处理----------------------------------
# ------------------5.1.1 数据加载---------------------------------
# 在PyTorch中,数据加载可通过自定义的数据集对象,数据集对象被抽象为Dataset类,
# 实现自定义的数据集需要继承Dataset,并实现两个Python魔法方法
# (1)__getitem__:返回一条数据,或一个样本,obj[index]等价于obj.__getitem__(index)
# (2)__len__:返回样本的数量,len(obj)等价于obj._len_()
# “Dogs vs Cats”是一个分类问题,判断一张图片是狗还是猫,其所有图片都存放在一个文件夹,根据文件名的前缀判断是狗还是猫
# %env LS_COLORS=None
# !tree --charset ascii data/dogcat/
import torch as t
from torch.utils import data
import os
from PIL import Image
import numpy as np
# os模块提供了多数操作系统的功能接口函数,与文件、目录打交道
# 常用os模块的命令,
# 1、os.name---判断目前正在使用的平台,并给出操作系统的名字,无()
# 2、os.getcwd()---get current work directory获取当前工作目录
# 3、os.listdir(path)---列出path目录下所有的文件和目录名
# 4、os.remove(path)---删除path指定的文件
# 5、os.rmdir(path)---删除path指定的目录
# 6、os.mkdir(path)---创建path指定的目录
class DogCat(data.Dataset): # 继承基类data.Dataset
def __init__(self, root): # 初始化构造函数
# listdir()返回指定路径下的文件和文件夹列表
imgs = os.listdir(root)
# 输出所有文件和文件夹
for file in imgs:
print(file)
# cat.12484.jpg
# cat.12485.jpg
# cat.12486.jpg
# cat.12487.jpg
# dog.12496.jpg
# dog.12497.jpg
# dog.12498.jpg
# dog.12499.jpg
# 所有图片的绝对路径
# 这里不实际加载图片,只是指定路径,当调用__getitem__时才会真正读图片
# os.path.join()函数功能:连接两个或更多的路径名组件
self.imgs = [os.path.join(root, img) for img in imgs]
print(root)
# ./data/dogcat/
print(imgs)
# ['cat.12484.jpg', 'cat.12485.jpg', 'cat.12486.jpg', 'cat.12487.jpg', 'dog.12496.jpg', 'dog.12497.jpg', 'dog.12498.jpg', 'dog.12499.jpg']
def __getitem__(self, index):
img_path = self.imgs[index] # 获取图片地址
# dog->1,cat->0
# python中split()和os.path.split()两个函数
# split():拆分字符串,通过指定分隔符对字符串进行切片,并返回分割后的字符串列表(list)
# os.path.split():按照路径将文件名和路径分割开
label = 1 if 'dog' in img_path.split('/')[-1] else 0
pil_img = Image.open(img_path) # PIL中的Image读入
array = np.asarray(pil_img) # 转换为数组形式
data = t.from_numpy(array) # array转换为tensor
return data, label
def __len__(self):
return len(self.imgs)
dataset = DogCat('./data/dogcat/')
imgs, label = dataset[0] # 相当于调用dataset.__getitem__(0)
for img, label in dataset:
print(img.size(), img.float().mean(), label)
# torch.Size([500, 497, 3]) tensor(106.4917) 0
# torch.Size([499, 379, 3]) tensor(171.8088) 0
# torch.Size([236, 289, 3]) tensor(130.3022) 0
# torch.Size([374, 499, 3]) tensor(115.5157) 0
# torch.Size([375, 499, 3]) tensor(116.8187) 1
# torch.Size([375, 499, 3]) tensor(150.5086) 1
# torch.Size([377, 499, 3]) tensor(151.7141) 1
# torch.Size([400, 300, 3]) tensor(128.1548) 1
# 上述代码是如何自定义自己的数据集,并依次获取,
# 但这里返回的数据不适合实际使用,引起具有如下两方面问题:
# (1)返回样本的形状不一,因每张图片的大小都不一样,这对于需要取batch训练的神经网络来说,很不友好
# (2)返回样本的数值较大,未归一化至[-1,1]
# 针对上述问题,PyTorch提供了torchvision,它是一个视觉工具包,提供了很多视觉图像处理的工具,
# 其中,transforms模块提供了对PIL Image对象和Tensor对象的常用操作
# 1、对于PIL Image的操作包括
# Scale:调整图片尺寸,长宽比保持不变
# CenterCrop\RandomCrop\RandomResizedCrop:裁剪图片
# Pad:填充
# ToTensor:将PIL Image的对象转成Tensor,会自动将[0,255]归一化至[0,1]
# 2、对Tensor操作包括:
# Normalize:标准化,即减均值,除以标准差
# ToPILImage:将Tensor对象转为PIL Image对象
# ----------------------transform优化升级上述代码(+图片数据归一处理)---------------------------------------------
import os
from PIL import Image
import numpy as np
from torchvision import transforms as T
# 如果要对图片进行多个操作,可通过Compose函数将这些操作拼接起来,类似于nn.Sequential
# 注意,这些操作定义后是以函数的形式存在,真正使用时调用它的__call__方法,类似于nn.Module
# 例如,将图片调整为224*224,首先构建操作trans=Resize((224,224)),然后调用trans(img)
# 下面我们就用transforms这些操作优化上面实现的dataset
# Compose组合处理
transform = T.Compose([
T.Resize(224), # 缩放图片(Image),保持长宽比不变,最短边为224像素
T.CenterCrop(224), # 从图片中间切出224*224的图片,进行中心切割
T.ToTensor(), # 将图片(Image)转成Tensor,归一化至【0,1】
T.Normalize(mean=[.5, .5, .5], std=[.5, .5, .5]) # 标准化至[-1,1],规定均值和标准差
])
class DogCat(data.Dataset): # 继承基类(data.Dataset)
def __init__(self, root, transforms=None): # 初始化构造函数,transforms默认为None
imgs = os.listdir(root) # listdir()返回指定路径下的文件和文件夹列表
self.imgs = [os.path.join(root, img) for img in imgs] # join结合路径
self.transforms = transforms
def __getitem__(self, index):
img_path = self.imgs[index] # 提取路径
label = 0 if 'dog' in img_path.split('/')[-1] else 1 # 加标签
data = Image.open(img_path) # 这一步才真正读取图片文件Image.open(path)
if self.transforms: # 默认为None,不做图片处理,否则调用transform进行操作
data = self.transforms(data)
return data, label
def __len__(self):
return len(self.imgs)
dataset = DogCat('./data/dogcat/', transforms=transform)
img.label = dataset[0]
for img, label in dataset:
print(img.size(), label)
# torch.Size([3, 224, 224]) 1
# torch.Size([3, 224, 224]) 1
# torch.Size([3, 224, 224]) 1
# torch.Size([3, 224, 224]) 1
# torch.Size([3, 224, 224]) 0
# torch.Size([3, 224, 224]) 0
# torch.Size([3, 224, 224]) 0
# torch.Size([3, 224, 224]) 0
# --------------------------------------Dataset--ImageFolder-------------------------------------
# 除了上述操作之外,transform还可通过Lamba封装自定义的转化策略
# 例如,想对PIL IMage进行随机旋转,
# 则可写成这样trans=T.Lamba(lamda img:img.rotate(random()*360)
# torchvision已经预先实现了常用的Dataset,包括前面使用过的CIFAR-10,ImageNet\MNIST等数据集
# 可通过torchvision.datasets.CIFAR10调用,
# 介绍一个经常使用到的Dataset--ImageFolder,它的实现和上述DogCat相似
# ImageFolder假设所有文件按文件夹保存,每个文件夹存储同一个类别的图片,文件夹名为类名
# 其构造函数如下:
# ImageFolder(root,transform=None,target_transform=None,loader=default_loader)
# 主要四个参数如下:
# 1、root:在root指定路径下寻找图片
# 2、transform:对PIL Image进行转换操作,trandform输入是使用loader读取图片的返回对象
# 3、target_transform:对label的转换
# 4、loader:给定路径后如何读取图片,默认读取为RGB格式的PIL Image对象
# label是按照文件夹名顺序排序后存成字典,即(类名:类序号(从0开始))
# 一般来说最好直接将文件夹命名为从0开始的数字,
# 这样会和ImageFolder实际的label一致,如果不是这种命名规范,
# 建议看看self.class_to_idx属性了解label和文件夹名的映射关系
from torchvision.datasets import ImageFolder
dataset = ImageFolder('data/dogcat_2/')
# cat文件夹的图片对应label 0,dog对应1
print(dataset.class_to_idx)
# {'cat': 0, 'dog': 1}
print(dataset.imgs) # 所有图片的路径和对应的label
# [('data/dogcat_2/cat\\cat.12484.jpg', 0), ('data/dogcat_2/cat\\cat.12485.jpg', 0), ('data/dogcat_2/cat\\cat.12486.jpg', 0), ('data/dogcat_2/cat\\cat.12487.jpg', 0), ('data/dogcat_2/dog\\dog.12496.jpg', 1), ('data/dogcat_2/dog\\dog.12497.jpg', 1), ('data/dogcat_2/dog\\dog.12498.jpg', 1), ('data/dogcat_2/dog\\dog.12499.jpg', 1)]
# 没有任何的transform,所以返回的还是PIL Image对象
print(dataset[0][1]) # 第一维是第几张图,第二维为1返回label
# 0
print(dataset[0][0]) # 为0返回图片数据
# <PIL.Image.Image image mode=RGB size=497x500 at 0x19B2EFA4188>
# //dataset[0][0].show() # 可以显示出图片弹窗
# 加上transform
normalize = T.Normalize(mean=[0.4, 0.4, 0.4], std=[0.2, 0.2, 0.2]) # 标准化至[-1,1],规定均值和标准差
transform = T.Compose([
T.RandomResizedCrop(224), # 随机选定位置切224*224
T.RandomHorizontalFlip(), # 随机水平翻转,概率为0.5
T.ToTensor(), # 图片转换为Tensor
normalize, # 标准化至[-1,1],规定均值和标准差
])
dataset = ImageFolder('data/dogcat_2/', transform=transform)
# 深度学习中图片数据一般保存CxHxW,即通道数*图片高度*图片宽度
print(dataset[0][0].size())
# torch.Size([3, 224, 224])
to_img = T.ToPILImage() # 换为图片的函数重命名
# 0.2和0.4是标准差和均值的近似
# dataset[0][0].show()#此时的是Tensor不可以.show()
# to_img(dataset[0][0]).show()# 变形
# print(dataset[0][0])
# print(dataset[0][0]*0.2+0.4)
# to_img(dataset[0][0]).show()
# //to_img(dataset[0][0] * 0.2 + 0.4).show() # 因为前面进行normalize,因而还进行还原后转为img
# ----------------------DataLoader------------------------------------------------
# Dataset只负责数据的抽象,一次调用__getitem__只会返回一个样本,在训练神经网络,最好是对一个batch数据进行操作
# 同时还需要对数据进行shuffle(洗牌,打乱顺序)和并行加速,
# PyTorch提供了DataLoader帮助我们实现这些功能
# DataLoader的函数定义如下:
# DataLoader(dataset,bach_size=1,shuffle=False,sampler=None,num_workers=0,
# collate_fn=default_collate,pin_memory=False,drop_last=False)
# (1)dataset:加载的数据集(Dataset对象)
# (2)batch_size:batch size
# (3)shuffle:是否将数据打乱
# (4)sampler:样本抽样
# (5)num_workers:使用多进程加载的进程数,0代表不使用多进程
# (6)collate_fn:如何将多个样本数据拼接成一个batch,一般使用默认拼接方式即可
# (7)pin_memory:是否将数据保存在pin memory区,pin memory中的数据转到GPU会快一些
# (8)drop_last:dataset中的数据个数可能不是batch_size的整数倍,
# drop_last为True会将多出来不足一个batch的数据丢弃
from torch.utils.data import DataLoader
dataloader = DataLoader(dataset, batch_size=3, shuffle=True, num_workers=0, drop_last=False)
# dataloader本质上是一个可迭代对象,可以使用iter()进行访问,
# 采用iter(dataloader)返回的是一个迭代器,然后可以使用next()访问。
dataiter = iter(dataset)
imgs, labels = next(dataiter)
print(imgs.size())
# torch.Size([3, 224, 224])
# dataloader是一个可迭代的对象,意味着我们可以使用迭代器一样使用它,例如:
# for batch_datas,batch_labels in dataloader:
# train()
# 或
# dataiter=iter(dataloader)
# batch_datas,batch_labels1=next(dataiter)
# 在数据处理中,有时会出现某个样本无法读取的问题,比如某张图片损坏,
# 这时在__getitem__函数中将出现异常,此时需要将出错的样本剔除
# 如果遇到这种情况无法处理,返回None对象,然后Dataloader实现自定义collate_fn,将空对象过滤掉
# 注意,这种情况dataloader返回的batch数目少于batch_size
class NewDogCat(DogCat): # 继承前面实现的DogCat
def __getitem__(self, index):
try:
# 调用父类函数的获取函数,DogCat.__getitem__(self,index)
return super(NewDogCat, self).__getitem__(index)
except:
return None, None
from torch.utils.data.dataloader import default_collate # 导入默认的拼接方式
def my_collate_fn(batch):
"""batch中每个元素形如(data,label)"""
# 过滤为None的数据,list(seq)将元组转换为列表
# filter函数是一个python内置函数,用于过滤序列,过滤掉不符合条件的元素,返回一个迭代器对象
# filter(function,iterable)--function:可迭代函数--iterable:可迭代对象
# 如果判断为True,则加入可迭代对象
# 匿名函数lamdba,没有具体名称的函数,允许快速定义单行函数,类似于C语言中的宏,可以用在任何函数的地方
batch = list(filter(lambda x: x[0] is not None, batch))
if len(batch) == 0: return t.Tensor() # tensor([])返回空张量
return default_collate(batch) # 用默认方式拼接过滤后的batch数据
print("-----------------")
dataset = NewDogCat('data/dogcat_wrong/', transforms=transform)
print(dataset[0])
# (tensor([[[-0.4314, -0.4314, -0.3922, ..., -0.0392, -0.0392, -0.0392],
# [-0.4314, -0.4314, -0.3922, ..., -0.0196, -0.0196, -0.0196],
# [-0.4314, -0.4314, -0.4118, ..., 0.0000, 0.0000, 0.0000],
# ...,
# [-1.0000, -1.0000, -1.0196, ..., 2.8824, 2.8824, 2.8824],
# [-1.0784, -1.0784, -1.0588, ..., 2.9020, 2.9020, 2.9020],
# [-1.0980, -1.0980, -1.0784, ..., 2.9020, 2.9020, 2.9020]]]), 1)
# 还未使用定义的my_collate_fn(batch)
# for img,label in dataset:
# print(img.size(),label)
# torch.Size([3, 224, 224]) 1
# torch.Size([3, 224, 224]) 1
# torch.Size([3, 224, 224]) 1
# torch.Size([3, 224, 224]) 1
# torch.Size([3, 224, 224]) 0
# torch.Size([3, 224, 224]) 0
# torch.Size([3, 224, 224]) 0
# torch.Size([3, 224, 224]) 0
# Traceback (most recent call last):
# File "D:/PyCharm/1120/5.1 utilities.py", line 274, in <module>
# print(img.size(),label)
# AttributeError: 'NoneType' object has no attribute 'size'
#
dataloader = DataLoader(dataset, 2, collate_fn=my_collate_fn, num_workers=0, shuffle=True)
# batchsize=2,collate_fn样本数据拼接方式,num_workers使用多线程加载的进程数,0代表不使用多线程,shuffle是否打算顺序
# for batch_datas, batch_labels in dataloader:
# print(batch_datas.size(), batch_labels.size())
# torch.Size([2, 3, 224, 224]) torch.Size([2])
# torch.Size([1, 3, 224, 224]) torch.Size([1])
# torch.Size([2, 3, 224, 224]) torch.Size([2])
# torch.Size([2, 3, 224, 224]) torch.Size([2])
# torch.Size([1, 3, 224, 224]) torch.Size([1])
# 一共有9张图片,包括一张损坏图片,batch_size=2
# 这个是batch_size,其中第2个batch_size为1,因为有一张损坏,导致其无法正常返回
# 而最后一个batch_size=1,这是因为共有9张,无法整除2(batch_size),
# 因此最后一个batch的数据会少于bath_size,可通过指定drop_last来丢弃最后一个不足batch_size的batch
# 对于诸如样本损坏或数据集加载异常等情况,还可以通过其他方式解决
# 例如,但凡遇到异常情况,就随机一张图片代替:
###class NewDogCat(DogCat): # 继承基类DogCat
### def __getitem__(self, item): # 定义重写(__getitem__)
# try,except,finally----在有可能出错的代码前面加上try,捕获到错误后,except处理,finally部分无论与否都会执行
### try:
### return super(NewDogCat, self).__getitem__(index)
### except:
### new_index = random.randint(0, len(self) - 1)
### return self[new_index]
# 1、python中无处不对象,所有创建的变量,类都是在创建类的实体对象或是类的继承、或是类的继承类的实体对象
# print(type(int))---# <class 'type'>
# b=3
# print(type(b))---# <class 'int'>
# 2、子类继承时,给基类的函数加上vitual之后变成虚函数,子类对应函数不管加不加vitual,对应函数都会成为虚函数
# 当子类没有定义该函数时,自动调用父类对应该函数
# 3、多态性---是指不同类的对象对同一消息的不同响应
# 实现多态的方法,以父类指针形式调用虚函数,
# 4、多重继承,一个字类有多个父类
# super用于多重继承时指定继承的那个父类的函数,使用mro函数查看继承顺序
# ------------------------------sampler模块(对数据进行采样)-------------------------------------------------
# 常用的有随机采样器:RandomSampler,当dataloader的shuffle参数为True,系统会自动调用这个采样器,实现打乱数据
# 默认采用SequentialSampler,它会按顺序一个一个进行采样,
# 另一个采样方法,WeightRandomSampler,会根据每个样本的权重选取数据,在样本比例不均衡问题中,可以用来进行采样
# WeightedRandomSampler两个参数:每个样本的权重weights,样本综述num_samples,以及一个可选参数replacement
# 权重越大样本被选中概率越大,待选取的样本数一般小于全部样本数目
# replacement用于指定是都可以重复选取某一个样本,默认为True,即允许在一个epoch中重复采样某一个数据
# 如果设为False,则当某一类样本被全部取完,但是其样本数目仍未达到num_samples,samples将不会再从该类选择数据
# 此时可能导致weights参数失效,
dataset = DogCat('data/dogcat/', transforms=transform)
# 狗的图片被取出的概率是猫的概率的两倍
# 两类图片被取出的概率与weights的绝对大小无关,只与比值有关
weights = [2 if label == 1 else 1 for data, label in dataset]
print(weights)
# [2, 2, 2, 2, 1, 1, 1, 1]
from torch.utils.data.sampler import WeightedRandomSampler
sampler = WeightedRandomSampler(weights, num_samples=9, replacement=True)
dataloader = DataLoader(dataset, batch_size=3, sampler=sampler)
for datas, labels in dataloader:
print(labels.tolist())
# [0, 1, 1]
# [0, 0, 1]
# [1, 1, 1]
# 猫狗比例约为1:2,一共有8个样本,返回9个,说明肯定有重复返回的,这就是replacement参数的作用
# 如果replacement=False:
sampler = WeightedRandomSampler(weights, 8, replacement=False)
dataloader = DataLoader(dataset, batch_size=4, sampler=sampler)
for datas, labels in dataloader:
print(labels.tolist())
# [1, 1, 1, 0]
# [1, 0, 0, 0]
# 在这种情况下,num_samples等于dataset样本总数,为了不重复选取,sampler会将每个样本都返回,这样就失去weight参数的意义
# 由上可知,如果指定sampler,shuffle不再生效,并且sampler.num_samples会覆盖dataset实际大小,
# 即一个epoch返回的图片总数取决于sampler.num_samplers
# -------------------------5.2 计算机视觉工具包:torchvision--------------------------------------------------------------
# 视觉工具包torchvion独立于PyTorch,需通过pip install torchvision安装,主要有下面三个部分
# 1、models:提供深度学习中各种经典网络结构及预训练好的模型,包括AlexNet,VGG系列,ResNet系列,Inception系列
# 2、dataset:提供常用的数据集加载,设计上都是继承torch.utils.data.Dataset,主要是MNIST\CIFAR10\ImageNet,COCO等
# 3、transforms:提供常用的数据预处理操作,主要包括Tensor以及PIL Image对象的操作
from torchvision import models
from torch import nn
# 加载预训练好的模型,如果不存在会自动下载
# 预训练好的模型保存在torch.models下面,squeezent是其中一个模型
resnet34 = models.squeezenet1_1(pretrained=True, num_classes=1000)
# 修改最后的全连接层为10分类问题(默认是ImageNet上的1000分类)
resnet34.fc = nn.Linear(512, 100)
from torchvision import datasets
# 指定数据集路径为data,如果数据集不存在就进行下载,通过train=False获取测试集
transform = T.Compose([
T.ToTensor(),
T.Lambda(lambda x: x.repeat(3, 1, 1)),
T.Normalize(mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5))
]) # 修改的位置
dataset = datasets.MNIST('data/', download=True, train=False, transform=transform)
# transform中涵盖了大部分对Tensor和PIL Image的常用处理,
# 转换分两布:1、构建转换操作,例如trandf=tranform.Normalize(mean=x,std=y
# 2、执行转换操作,例如output=transf(input),
# 另外可以将多个处理操作用Compose拼接,形成一个处理转换流程
from torchvision import transforms
to_pil = transforms.ToPILImage()
# to_pil(t.rand(3, 64, 64)).show()
# torchvision还提供两个常用函数,make_grid,能将多张图片拼接成一个网格中
print(len(dataset))
# 10000
dataloader = DataLoader(dataset, shuffle=True, batch_size=16)
from torchvision.utils import make_grid, save_image
dataiter = iter(dataloader)
img = make_grid(next(dataiter)[0], 4) # 拼成14*4网格图片,且会转成3通道
to_img(img).show()
# 报错,图片格式是灰度图只有一个channel,需要白城RGB图才可以
# 376行,重新写transform,中添加lamdba变成三通道即可解决
save_image(img, 'a.png') # 另一个是save_img,能将Tensor保存为图片
Image.open('a.png')
# ----------------------------------5.3 可视化工具----------------------------------------
# ------------------5.3.1 Tensorboard---------------------------
# Tensorboard最初是作为TensorFlow的可视化工具,Tensorboard相对独立,只要用户保存的数据遵循格式,就可以可视化
# TensorboardX是将Tensorboard的功能抽取出来,使得非TensorFlow用户也能使用它进行可视化,几乎支持原生TensorBoard所有功能
from tensorboardX import SummaryWriter
# 构建对象logger,logdir用来指定log文件的保存路径
# flush_secs用来指定刷新同步间隔
logger = SummaryWriter(log_dir='experimient_cnn', flush_secs=2)
for ii in range(100):
logger.add_scalar('data/loss', 10 - ii ** 0.5)
logger.add_scalar('data/accuracy', ii ** 0.5 / 10)
# ---------------5.3.2 visdom------------------------------------------------
# Visdom是Facebook专门为PyTorch开发的一款可视化工具,Visdom十分轻量级,但却支持丰富功能,能胜任大多数的科学运算可视化任务
# Visdom可以创造、组织和共享多种数据的可视化,包括数值、图像、文本甚至是视频,其支持PyTorch、Torch及Numpy
# 用户可通过编程组织可视化空间,或通过用户接口为生动数据打造仪表板,检查实验结果或调试代码
# Visdom中有两个重要概念:
# 1、env:环境,不同环境的可视化结果相互隔离,,互补影响,使用时如果不指定env,默认使用main,不同用户,不同程序一般使用不同的env
# 2、pane:窗格,窗格可用于可视化图像,数值或打印文本等,其可以拖动、缩放、保存和关闭,一个程序中可使用同一个env的不同Pane,每个pane可视化或记录某一信息
import torch as t
import visdom
# 新建一个连接客户端,指定env=u'test1',默认端口为8097,host是‘loslhost’
vis = visdom.Visdom(env=u'test1', use_incoming_socket=False)
x = t.arange(1, 100, 0.01)
y = t.sin(x) # win窗口名字,opts用于设置Pane格式
vis.line(X=x, Y=y, win='sinx', opts={'title': 'y=sin(x)'})
# 逐一分析代码,
# vis=visdom.Visdom(env=u'test1'),用于构建一个客户端,客户端除了指定env之外,还可以指定host,port等参数
# vis作为一个客户端对象,可以使用常见的画图函数,包括:
# 1、line:类似于Matlab中的plot操作,用于记录某些标量的变化,如损失、准确率等
# 2、image:可视化图片,可以是输入的图片,可以是GAN生成的图片,可以是卷积核的信息
# 3、text:用于记录日志等文字信息,支持Html格式
# 4、hisgram:可视化分布,主要是查看数据,参数的分布
# 5、scatter:散点图
# 6、bar:饼状图
# 7、pie:饼状图
# 下面主要介绍深度学习中常见的line,image和text操作
# Visdom同时支持PyTorch的tensor和Numpy的ndarray两种数据结构,但不支持Python的int\foloat等类型
# 因此每次传入需先将数据转成ndarray和tensor,上述操作参数一般不同,但有两个参数绝大多数操作具备:
# 1、win:用于指定pane名字,如果不指定,visdom将自动分配一个新的Pane,如果两次操作指定win名字一样,将会覆盖
# 2、opts:选项,接收一个字典,常见的option有title,xlabel,ylabel,width等,主要用于设置pane的显示格式
# 每次操作都会覆盖之前的值,指定参数update='append'会避免覆盖之前的数值,
# 除了使用update参数,还可以使用vis.updataTrace方法更新图,
# updateTrace不仅能在指定pane新增一个和已有数据相互独立的Trace,还能像update='append那样在同一个trace上追加数据
# append追加数据
# (1)line
for ii in range(0, 10):
# y=x
x = t.Tensor([ii])
y = x
vis.line(X=x, Y=y, win='polynomial', update='append' if ii > 0 else None)
# updateTrace新增一条线
x = t.arange(1, 9, 0.1)
y = (x ** 2) / 9
vis.line(X=x, Y=y, win='polynomial', name='this is a new Trace', update='new')
# (2)image
# image画图功能分一下两类:
# 1、image接收一个二维或三维向量,H*W或3*H*W,前者是黑白图像,后者是彩色图像
# 2、images接受一个四维向量N*C*H*W,C可以是1或3,分别代表黑白和彩色图像,
# 可实现类似torchvison中make_grid功能,将多张图片拼接在一起
# images也可以接收一个二维或三维向量,它所实现功能与image一致
# 可视化一个随机的黑白图片
vis.image(t.randn(64, 64).numpy(), win='random1')
# 随机可视化一张彩色图片
vis.image(t.randn(3, 64, 64).numpy(), win='random2') # 要重新指定一个win会被覆盖,默认不覆盖
# 可视化36张随机的彩色图片,每一行6张
vis.images(t.randn(36, 3, 64, 64), nrow=6, win='random3', opts={'title': 'random_imgs'})
# 不用.numpy()也可
# (3)text
# vis.text用于可视化文本,支持所有的html标签,同时也遵循着html的语法标准,
# 例如,换行需使用,<br>标签,\r\n无法实现换行,下列举例说明
vis.text(u'''<h1>Hello Visdom</h1><br>Visdom是Facebook专门为<b>PyTorch</b>开发的一个可视化工具,
在内部使用了很久,在2017年3月份开源了它。
Visdom十分轻量级,但是却有十分强大的功能,支持几乎所有的科学运算可视化任务''',
win='visdom',
opts={'title': u'visdom简洁'}
)
# -----------------------------5.4 使用GPU加速:cuda---------------------------------
# CPU:中央处理器,GPU:图形处理器
# 在PyTorch中以下数据结构分为CPU和GPU两个版本:
# 1、Tensor;2、nn.Moudle(包括常用的layer,loss function,以及容器Sequential等)
# 均带有.cuda方法,调用此方法即可将其转为对应GPU对象,
# 注意,tensor.cuda会返回一个新的对象,这个新的对象的数据已转移至GPU,而之前的tensor还在原来的设备上(CPU)
# module.cuda会将所有的数据都歉意至GPU,并返回自己,所以module=module.cuda()和module.cuda()效果一样
# nn.module在GPU和CPU之间的转换,本质上利用Tensor在GPU和CPU之间的转换,