说明:
1.这是我在学习过程中的笔记,可能会有错误,欢迎各位读者指出错误(不要因为我是娇花而怜惜我(╹▽╹))
2.提醒自己要填的坑:
torch.set_default_tensor_type()
torch.strided
CUDA pinned memory
CUDA in multiprocessing
torch.nn.Parameter
torch.nn.BatchNorm1d
torch.nn.Conv1d
torchvision.transforms
torch.set_grad_enabled()
3.该篇不定期更新
1.permute()
意义:更改张量维度的排列
import torch
import numpy as np
a = np.array([[[0, 1, 2],[3, 4, 5]]])
input = torch.tensor(a)
input.size() # torch.Size([1, 2, 3])
output = input.permute([2, 0, 1])
output.size() # torch.Size([3, 1, 2])
output
# tensor([[[0, 3]],
# [[1, 4]],
# [[2, 5]]], dtype=torch.int32)
2.randint()
意义:返回范围在low(包括)和high(不包括)之间的均匀生成的随机整数
torch.randint(low=0, high, size, *, generator=None, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False) → Tensor
参数
low(int,optional)-随机分布的下界,默认为0
high(int)- 随机分布的上界
size(tuple)-返回的张量的形状
generator(torch.Generator, optional)-采样的伪随机数生成器
out(Tensor, optional)-输出张量
dtype(torch.dtype, optional)-希望的返回张量的数据类型 (默认为None,使用全局默认)(torch.set_default_tensor_type())
layout(torch.layout,optional)- 希望的返回张量的布局 (默认为torch.strided)
device(torch.device, optional )- 希望的返回张量的使用设备(CPU或CUDA)
requires_grad(bool,optional)-如果需要记录梯度在返回张量上(默认为False)
参考:
PyTorch官方文档
3.torch.utils.data.DataLoader
意义:PyTorch提供的数据加载器
支持 (1)映射样式和可迭代样式的数据集
(2)定义数据加载顺序
(3)自动装载
(4)单进程和多进程数据加载
(5)自动内存固定
DataLoader(dataset, batch_size=1, shuffle=True, sampler=None, batch_sampler=None, num_workers=0, collate_fn=None, pin_memory=False, drop_last=False, timeout=0, worker_init_fn=None, *, prefetch_factor=2, persistent_workers=False)
dataset: 数据集,支持两种数据集
(1)映射型数据集
实现了__getitem__()和__len__()方法,表示索引(或键)到数据样本的映射。
(2)迭代型数据集
可迭代数据集是IterableDataset实现__iter()协议的子类的实例,并且表示数据样本上的可迭代形式。这种类型的数据集特别适用于随机读取价格昂贵甚至不可能的情况,并且批处理大小取决于所获取的数据。
batch_size(int, optional): 每个batch装载多少样本,默认为1
shuffle(bool, optional): 当为True时,每个周期都打乱数据顺序,默认为False
sampler(torch.utils.data.Sampler or Iterable, optional):定义从数据集中获取数据的策略,可以为任何实现了__len__的Iterable。如果该项指定了,shuffle必须为False
batch_sampler(torch.utils.data.Sampler or Iterable, optional):与sample相似,但是每次返回一系列索引。与batch_size, shuffle, sampler和drop_last相兼容。
num_works(int, optional): 多少个子线程用于数据装载。0意味着数据会装载入主线程(默认为0)
collate_fn(callable, optional): 合并样本形成小批量的张量。当对映射型数据集进行批量装载时使用。
pin_memory(bool, optional): 当为True时,数据装载器在返回张量之前将其复制到CUDA的固定内存。--------
droup_last(bool, optional): 当设为True时,如果数据集大小不能被批大小(batch_size)整除时,则丢弃剩余不完整的batch。反之,若为False,最后一个batch会更小(默认为False)
timeout(numeric, optional): 如果为正数,表示从worker进程收集一个batch等待的时间,如果时间超过了还没收集到,就不收集了。该数必须大于等于0。(默认为0)
worker_init_fn(callable, optional): 如果不是None,在seed之后和数据装载之前,它会在根据worker id在每个worker子线程上调用,并作为输入(默认为None)
prefetch_factor(int, optional, keyword-only arg):每个worker提前装载的样本数。2意味着有2 * num_workers 个样本提前装载(默认为2)
persistent_workers(bool, optional): 如果为True,数据装载会直到整个数据集被装载完毕后才关闭所有worker线程。这使得Dataset实例存活。(默认为False)
Data Loading and Sampler
对于迭代型数据集,数据装载顺序完全用户定义的迭代(iterable)方式确定。
对于映射型数据集,torch.utils.data.Sampler用来指定数据集中索引(或键)的迭代顺序。可以用shuffle参数自动实现随机装载数据,但是用Sampler可以让用户根据自己的需求实现每轮装载数据的方式。
Loading Batched and Non-Batched Data
DataLoader通过参数batch_size,drop_last和batch_sampler自动采集数据入batch中。
(1)自动装载(默认)
对于映射型数据集,用户可以指定batch_sampler,这样可以每次生成一个键的列表。
batch_sampler对映射型数据集使用方式如下:
for indices in batch_sampler:
yield collate_fn([dataset[i] for i in indices])
batch_sampler对迭代型数据集使用方式如下:
dataset_iter = iter(dataset)
for indices in batch_sampler:
yield collate_fn([next(dataset_iter) for _ in indices])
(2)非自动装载
在某些特殊场景下,用户想要手动处理batch方式(根据个人需求),就要用到非自动装载。
当batch_size和batch_sampler均为None时,自动装载关闭。每个样本获取方式由参数collate_fn传递的函数处理。
collate_fn的默认实现为将NumPy数组转化为PyTorch张量。
Working with collate_fn
(1)当自动装载关闭
collate_fn会对每一个数据样本调用,输出由data loader的迭代器产生。默认为将NumPy数组转换为PyTorch的张量。
(2)当自动装载开启
collate_fn每次会对一组数据样本调用。期望将输入样本装进batch,使得可以从data loader迭代器产生。
Single- and Multi-process Data Loading
(1)Single-process data loading(default)
默认使用单线程装载数据,因此装载数据过程中可能出现计算阻塞。但是,这种模式在线程共享资源较小,或者整个数据集较小而且可以整个装进内存中时,表现较好。除此之外,单线程更容易寻找错误和debug。
(2)Multi-process data loading
通过参数num_workers设置工作线程数量。这种模式下,每次会创建一个DataLoader的迭代器和num_workers个工作线程,参数dataset,collate_fn和worker_init_fn会传递给每个worker。
torch.utils.data.get_worker_info()
在worker线程中返回有用信息(包括worker ID,数据集副本等),在主线程中返回None。用户可以在数据集代码用这个函数或者worker_init_fn分别配置每一个数据集副本,以此来决定是否在每个worker线程中运行该代码。例如,在对数据集进行分片时特别有用。
对于映射型数据集,主线程使用sampler
生成索引,并将它们发送给worker。因此,任何打乱随机化等操作都在主线程中完成,通过分配索引直到数据装载。
对于迭代型数据集,因为每个worker线程获得一个dataset的副本,原生的多线程装载会重复的数据上操作。使用torch.utils.data.get_worker_info()
或者worker_init_fn
(或者两者合用)可以独立配置每个副本。
worker线程会在迭代过程线束或者迭代器被当做垃圾收集时关闭。
Platform-Specific behaviors
因为worker依赖于Python的multiprocessing,worker在Windows和Unix上的行为是不同的。
在Unix上,fork()是默认的multiprocessing启动方法。利用fork(),子worker可以通过复制的地址空间获取dataset和Python参数函数。
在Windows上,spawn()是默认的multiprocessing启动方法。利用spawn(),将启动一个解释器,该解释器运行主脚本,随后是内部工作程序函数,该函数通过pickle序列化接收dataset, collate_fn以及其他参数。
这种单独的序列化意味着您应该采取两个步骤来确保在使用多进程数据加载时与Windows兼容:
1.将大部分主要脚本代码包含在if __name__ == '__main__'
块中,以此确保在启动每个worker进程是,该脚本不会再次运行(很可能生成错误)。你可以在此放置数据集和DataLoader实例生成逻辑,因为这可以不必再worker进程中在此运行。
2.确保任何自定义的collate_fn,worker_fn或dataset代码被声明为顶层定义,在__main__外部检查。
Randomness in multi-process data loading
默认下,每个worker有自己的PyTorch seed(随机数生成的seed),被设置为base_seed + worker_id,其中base_seed是由主进程用RNG生成的长整数,但是,对别的库来说,seed可能被在初始化worker时重复使用(例如NumPy),这使得每个worker返回相等的随机数。
在worker_init_fn中,你可以用torch.utils.data.get_worker_info()或torch.initial_seed()获得每个worker的PyTorch seed,然后可以在数据装载钱当做别的库的seed。
Memory Pinning
注意事项:
(1)当对IterableDataset使用多线程装载(multi-process data loading)时,同一个数据集会在每个worker线程重复,所以必须进行配置来避免数据重复。
(2)参数sampler和batch_sampler都和迭代性数据集不兼容,因为这种数据集没有索引或键的概念。
(3)参数batch_size和drop_last对于从sampler构造batch_sampler是必须的。对于映射型数据集,sampler既不是用户提供的,也不是基于参数shuffle构造的。
(4)当用多线程从迭代型数据集获取数据时,drop_last会丢弃每个worker线程的最后一个(不满batch_size)的batch。
(5)一般不推荐在多线程装载中返回CUDA张量,因为在多线程中使用CUDA和共享CUDA张量有许多细微之处。我们推荐使用automatic memory pinning(如设置 pin_memory=True),这样能快速将数据转入支持CUDA的GPU。
参考:
PyTorch官方文档