Pytorch常用工具总结
数据处理
数据加载
- 自定义数据集- 继承Dataset,实现python方法:- __getitem__: 返回一条数据/一个样本
- __len__: 返回样本数量
 
 
- 继承
以猫狗识别为例:
- 文件结构 - 所有文件放在一个文件夹,根据前缀判断 - 1 
 2
 3
 4
 5
 6
 7
 8
 9- data/dogcat/ 
 |-- cat.12484.jpg
 |-- cat.12485.jpg
 |-- cat.12486.jpg
 |-- cat.12487.jpg
 |-- dog.12496.jpg
 |-- dog.12497.jpg
 |-- dog.12498.jpg
 `-- dog.12499.jpg
- 在构造函数中获取图片路径 - 1 
 2
 3
 4
 5- def __init__(self, root): 
 # 图片文件夹路径
 imgs = os.listdir(root)
 # 遍历文件夹下所有文件 + 文件姐路径=> 构成绝对路径
 self.imgs = [os.path.join(root, img) for img in imgs]
- 定义 - __getitem__,这一步中真正读取图片,并根据文件名生成label- 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11- def __getitem__(self, index): 
 img_path = self.imgs[index]
 # 根据文件名生成Label
 label = 1 if 'dog' in img_path.split('/')[-1] else 0
 # 加载图片
 pil_img = Image.open(img_path)
 # 图片转为numpy
 array = np.asarray(pil_img)
 # numpy转为tensor
 data = t.from_numpy(array)
 return data, bale
- 还需要定义 - __len__,返回imgs数组的长度
- 调用数据加载类 - ```python 
 dataset = DogCat(FILEPATH)- 访问某个元素- dataset[INDEX] - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 ### transforms
 - 常见操作
 - | 操作 | 说明 |
 | ------------------------------------------------ | ------------------------------------------------ |
 | `Scale` | 调整图片尺寸,长宽比 |
 | `CenterCrop`, ``RandomCrop`, `RandomResizedCrop` | 裁剪 |
 | `pad` | 填充 |
 | `ToTensor` | 将PIL Image对象转成Tensor,将[0, 255]归一化[0,1] |
 - 对Tensor的操作
 - Normalize: 标准化
 - `ToPILImage`: Tensor转PIL Image
 - `Compose`: 拼接
 - 实现
 - ```python
 transform = T.Compose([
 T.Resize(224), # 缩放,保持长宽比,短边224
 T.CenterCrop(224), # 中间切224*224
 T.ToTensor(), # 归一化到[0, 1]
 T.Normalize(mean = [.5, .5, .5], std = [.5, .5, .5]) # 表转化到[-1, 1]
 ])
- 在数据集的类中定义transform,并在 - __getitem__方法中返回transforms处理过的data(图像数据).
 
- 自定义转换 - e.g. trans=T.Lambda(lambda img: img.rotate(random()*360))
 
- e.g. 
ImageFolder
- 假设文件按文件夹保存,每个文件夹存储同类别,文件夹名为类名。 - 1 - ImageFolder(root, transform=None, target_transform=None, loader=default_loader) - root: 路径
- transform: 对图片的转换操作
- target_transform: 对label转换
- loader: 读取格式
 
- 属性 - class_to_idx- 类名和类下标的对应关系
 
图片保存:Channel x Height x Width
DataLoader
- ```python 
 DataLoader(dataset, batch_size=1, shuffle=False, sampler=None, num_workers=0, collate_fn=default_collate, pin_memory=False, drop_last=False)- 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 - `dataset` - Dataset对象
 - `shuffle` - 打乱
 - `sampler`
 - `num_workers` - 多进程加载的进程数
 - `collate_fn` - 多个样本数据拼成一个batch的方法,一般使用默认
 - `pin_memory` - 是否将数据保存在`pin_memory`区,转到GPU快
 - `drop_last` -师傅 将最后不足`batch_size`个数据丢弃
 #### 可迭代
 - 可以使用for循环
 - ```python
 for batch_datas, batch_labels in dataloader:
- 可以使用迭代器 - ```python
 dataiter = iter(dataloader)
 batch_datas, batch_labels = next(dataiter)1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 ### 剔除出错样本
 #### 返回None,并在拼合为batch的时候筛选掉
 - 使用`try`, `except`
 - 异常情况:`return None, None`
 > 这里需要配合实现`Dataloader`的`collate_fn`,将None过滤
 ```python
 from torch.utils.data.dataloader import default_collate # 导入默认的拼接方式
 def my_collate_fn(batch):
 # 过滤为None的数据
 batch = list(filter(lambda x:x[0] is not None, batch))
 if len(batch) == 0: return t.Tensor()
 return default_collate(batch) # 用默认方式拼接过滤后的batch数据
 
- ```python
随机选取图片代替
- 优点:保证每个batch的数目仍是batch_size
注意事项
- 高负载的操作放在__getitem__,如加载图片 => 为实现并行加速
- dataset包含只读,避免修改 => 使用多进程加载,修改可能产生冲突
sampler
- 对数据采样,loader里面shuffle为True,调用随机采样器RandomSampler,打乱数据;默认使用SequentialSampler,顺序采样
WeightedRandomSampler
- 根据每个样本的权重选取数据,比例不均衡问题中进行重采样
- 构建时提供每个样本的权重weights和选取样本总数num_samples,可选replacement- 权重越大被选中概率越大
- replacement决定是否可以重复选取某一样本
 
在指定了sampler的情况下,shuffle不再生效;一个epoch返回的图片总数取决于sampler.num_samples
计算机视觉工具包 torchvision
- models:提供网络结构以及预训练好的模型
- datasets:提供常用的数据集加载
- transforms:提供常用的数据预处理
Visdom
- env: 不同环境的可视化结果相互隔离,默认- main
- pane: 窗格
安装和使用
- ```shell 
 $ pip install visdom
 $ python -m visdom.server # 启动visdom服务
 $ nohup python -m visdom.server & # 将服务放至后台运行- 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 > **注意:**
 >
 > 手动指定保存`env`,在web上或者程序里save,否则visdom服务重启后,信息会丢失。
 #### 常用操作
 - 新建连接客户端
 - ```python
 vis = visdom.Visdom(env=u'test1',use_incoming_socket=False)- 可以指定host, port..
 
- 画图函数: line, image, text, histogram, scatter, bar, pie… 
支持tensor和narray的数据结构
常见参数
- win: 指定Pane的名字,两次操作指定的win相同,则覆盖- 需要更新数值且不覆盖,指定参数 - update='append'- 也可以使用 - vis.updateTrace更新图:- 增加新trace - 1 
 2
 3- x = t.arange(0, 9, 0.1) 
 y = (x ** 2) / 9
 vis.line(X=x, Y=y, win='polynomial', name='this is a new Trace',update='new')- 在原trace上追加 - 1 
 2
 3
 4
 5- 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)
 
- opts: 选项,接收字典,用于pane的显示格式
text
- 支持html
使用GPU加速 cuda
注意事项
- 损失函数定义后也应该调用 - criterion.cuda转移到GPU
- 推荐方法设置环境变量 - CUDA_VISIBLE_DEVICES,- 在运行py的命令行实现 
- 在程序中: - ```python
 import os
 os.environ[“CUDA_VISIBLE_DEVICES”] = “2”1 
 2
 3
 4
 5
 - 在Jupyter notebook中:
 - ```shell
 %env CUDA_VISIBLE_DEVICES=1,2
 
- ```python
 
持久化
- 可持久化的对象:- Tensor
- Variable
- nn.Module
- Optimizer
 
- 都保存成Tensor,使用t.save(OBJ, FILENAME)和t.load(FILENAME)可完成- load的时候可以指定加载的存储位置,设置- map_location参数
 
- 建议module和optimizer保存为state_dict
module
- ```python保存t.save(model.state_dict(), FILENAME)加载model.load_state_dict(t.load(FILENAME))1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 - optimizer同样
 #### 一起保存加载
 - ```python
 all_data = dict(
 optimizer = optimizer.state_dict(),
 model = model.state_dict(),
 info = u'模型和优化器的所有参数'
 )
 t.save(all_data, 'all.pth')
 
 all_data = t.load('all.pth')