AI备忘录 - Pytorch
type: channel
link: http://www.aiuai.cn/tag/Pytorch
items: Pytorch - DatasetClass
items: Pytorch - 图像分类库timm快速使用
items: Pytorch - 1D2D3D卷积操作
items: Pytorch - 低版本加载高版本模型报错
items: Pytorch - inference_mode API
items: Pytorch - einsum爱因斯坦求和约定标记法
items: Pytorch - 矩阵相乘@与逐元素相乘*
items: Pytorch - 基于torch.distributed.all_gather的梯度反向传播[译]
items: Pytorch - DataParallel和DistributedDataParallel
items: Pytorch - 提升性能的几个技巧[转]

Pytorch - DatasetClass
type: item
date: 2024-01-29T05:30:38+00:00
description: From: https://twitter.com/akshay_pachaar/status/1751583417463124020典型的 Dataset 类，如：tabular data表格数据(tabular data)，以 lris 数据集为例：text dataNLP 中，往往将 text 划分为多个小的 pieces，即 tokens，一般是 words 或 subwords.将 raw text 转换为 embedding(vectors) 生成器可以使用的格式，是一个必要的初始化步骤.image data看下图片数据集的格式，其对应的 Dataset Class 如，

Pytorch - 图像分类库timm快速使用
type: item
date: 2022-02-05T10:30:00+00:00
description: 原文：Getting Started with PyTorch Image Models (timm): A Practitioner’s Guide - 2022.02.02Github： rwightman/pytorch-image-modelsPyTorch Image Models（timm） 是一个优秀的图像分类 Python 库，其包含了大量的图像模型（Image Models）、Optimizers、Schedulers、Augmentations 等等.timm 提供了参考的 training 和 validation 脚本，用于复现在 ImageNet 上的训练结果；以及更多的 官方文档 和 timmdocs project.https://rwightman.github.io/pytorch-image-models/https://fastai.github.io/timmdocs/但，由于 timm 的功能之多，所以在定制使用时很难知道如何入手. 这里主要进行概述.pip install timm==0.5.41. Modelstimm 提供了大量的模型结构集合，而且很多模型都包含了预训练权重，或 PyTorch 训练、或从Jax和TensorFlow中移植，很方便下载使用.模型列表：https://paperswithcode.com/lib/timm查看模型列表：#打印 timm 提供的模型列表 print(timm.list_models()) print(len(timm.list_models())) #739 #带有预训练权重的模型列表 print(timm.list_models(pretrained=True)) print(len(timm.list_models(pretrained=True))) #592其中，timm.list_models() 函数：list_models(filter='', module='', pretrained=False, exclude_filters='', name_matches_cfg=False)查看特定族模型，如：print(timm.list_models('gluon_resnet*')) print(timm.list_models('*resnext*', 'resnet') ) print(timm.list_models('resnet*', pretrained=True))1.1. create_model 一般用法timm 创建模型最简单的方式是采用 create_model.以 Resnet-D 模型为例（Bag of Tricks for Image Classification For Convolutional Neural Networks paper），其是Resnet 的一种变形，其采用 average pool 进行下采样.model = timm.create_model('resnet50d', pretrained=True) print(model) #查看模型配置参数 print(model.default_cfg) ''' {'url': 'https://github.com/rwightman/pytorch-image-models/releases/download/v0.1-weights/resnet50d_ra2-464e36ba.pth', 'num_classes': 1000, 'input_size': (3, 224, 224), 'pool_size': (7, 7), 'crop_pct': 0.875, 'interpolation': 'bicubic', 'mean': (0.485, 0.456, 0.406), 'std': (0.229, 0.224, 0.225), 'first_conv': 'conv1.0', 'classifier': 'fc', 'architecture': 'resnet50d'} '''1.2. create_model 修改输入通道timm models 有个非常有用的特点，其可以处理任意通道数量的输入图像. 这是很多其他库所不具备的. 其实现原理可参考：https://fastai.github.io/timmdocs/models#So-how-is-timm-able-to-load-these-weights?model = timm.create_model('resnet50d', pretrained=True, in_chans=1) print(model) #test, single cha…

Pytorch - 1D2D3D卷积操作
type: item
date: 2022-02-04T10:33:00+00:00
description: 1D CNN，kernel 在 1 个方向移动，输入和输出是 2 维的，通常用于时序（Time-Series）数据2D CNN，kernel 在 2 个方向移动，输入和输出是 3 维的，通常用于图像数据3D CNN，kernel 在 3 个方向移动，输入和输出是4 维的，通用用于 3D 图像数据1D 卷积 - Conv1DConv1D，kernel 沿着一个维度进行滑动.比如，时间序列数据，如图：图：从传感器（accelerometer）获得的时间序列数据以人体穿戴在胳膊上的传感器所采集到的时序数据为例. 数据从 3 个轴表示，1D CNN 可以从传感器数据进行行为识别任务分析，如，人站立、行走、跳等. 该数据有 2 维，第一维是time-steps，另一个是在 3 个轴方向上的传感器值.kernel 在传感器数据上滑动的方式如下图，每一行表示某一轴的时间序列传感器数据. kernel仅能在时间轴方向上移动.''' https://pytorch.org/docs/stable/generated/torch.nn.Conv1d.html ''' import torch from torch import nn model = nn.Conv1d(in_channels=1, out_channels=10, kernel_size=5, stride=1) input = torch.randn(20, 1, 50) output = model(input)1D CNNs 被普遍应用于传感器数据，还可以用于音频和文本数据，因为其可以被表示为时序数据. 如图：2D 卷积 - Conv2DLenet-5 结构中首先提出标准CNN网络. Conv2D 普遍应用于图像数据. 其 2D 是因为，kernel 沿着数据的两个维度进行滑动，如图：CNN 的优势在于，采用 kernel 可以提取数据的空间特征. 例如，CNN 可以检测边缘、颜色分布等，其有助于网络对于图像分类的鲁棒性.''' https://pytorch.org/docs/stable/generated/torch.nn.Conv2d.html ''' import torch from torch import nn # With square kernels and equal stride model = nn.Conv2d(16, 33, 3, stride=2) # non-square kernels and unequal stride and with padding model = nn.Conv2d(16, 33, (3, 5), stride=(2, 1), padding=(4, 2)) # non-square kernels and unequal stride and with padding and dilation model = nn.Conv2d(16, 33, (3, 5), stride=(2, 1), padding=(4, 2), dilation=(3, 1)) input = torch.randn(20, 16, 50, 100) output = model(input)3D 卷积 - Conv3D3D CNN 中，kernel 沿 3 个维度滑动，如图：Conv3D 通常应用于 3D图像数据，如，MRI （Magnetic Resonance Imageing） 数据、CT（Computerized Tomography）扫描数据等.''' https://pytorch.org/docs/stable/generated/torch.nn.Conv3d.html ''' import torch from torch import nn # With square kernels and equal stride model = nn.Conv3d(16, 33, 3, stride=2) # non-square kernels and unequal stride and with padding model = nn.Conv3d(16, 33, (3, 5, 2), stride=(2, 1, 1), padding=(4, 2, 0)) input = torch.randn(20, 16, 10, 50, 100) output = model(input)

Pytorch - 低版本加载高版本模型报错
type: item
date: 2021-10-10T09:10:00+00:00
description: Pytorch 低版本环境(如，1.0) 加载高版本(如，1.10) 训练的模型，报错如下：xxx is a zip archive (did you mean to use torch.jit.load()?)原因：Pytorch1.6 版本后模型保存torch.save()参数变更，重新加上参数 _use_new_zipfile_serialization=False 保存，即可：https://pytorch.org/docs/stable/generated/torch.save.htmlimport torch #device = torch.device("cuda" if torch.cuda.is_available() else "cpu") #model.load_state_dict(torch.load(save_path),map_location=device) state_dict = torch.load('pytorch_model.pth') state_dict = torch.load('pytorch_model.pth', map_location="cpu") #state_dict = torch.load('pytorch_model.bin', map_location="cpu") torch.save(state_dict, 'pytorch_model.pth', _use_new_zipfile_serialization=False) #torch.save(state_dict, 'pytorch_model.bin', _use_new_zipfile_serialization=False)

Pytorch - inference_mode API
type: item
date: 2021-06-15T14:59:00+00:00
description: Pytorch1.9 released 里发布了一个 Inference Mode API(Beta).推理模式API ( Inference Mode API ) 可以显著加速推理工作负载的速度，同时保持安全，并确保永远不会计算不正确的梯度. 在不需要 autograd 时，其提供了最好的性能.inference_mode — PyTorch 1.9.0 documentation定义如：class torch.inference_mode(mode=True) #参数 mode: 是否开启推断模式InferenceMode 是类似与 no_grad 的上下文管理器(context manager)，主要用于确定不需要与 autograd 交互时使用. 这种模式下运行的代码，通过禁用试图跟踪(view tracking) 和版本计数器缓冲(version counter bumps) 来获得更好的性能.InferenceMode 上下文管理器是局部线程的(thread local)，其不会影响其他线程中的计算.InferenceMode 也起到装饰器的作用.使用示例:import torch x = torch.ones(1, 2, 3, requires_grad=True) with torch.inference_mode(): y = x * x # y.requires_grad # False y._version #Traceback (most recent call last): #File "<stdin>", line 1, in <module> #RuntimeError: Inference tensors do not track version counter. @torch.inference_mode() def func(x): return x * x out = func(x) out.requires_grad #False

Pytorch - einsum爱因斯坦求和约定标记法
type: item
date: 2021-06-08T13:05:00+00:00
description: 原文：EINSUM IS ALL YOU NEED - EINSTEIN SUMMATION IN DEEP LEARNING - 2018.05.02译文：einsum满足你一切需要：深度学习中的爱因斯坦求和约定作者：TIM ROCKTASCHEL节选，学习.1. einsum 标记法1.1. 矩阵相乘比如，两个矩阵相乘，$A \in R^{I \times K}$ 和 $B \in R^{K \times J}$ ；再计算每列的和，最终得到矩阵 $c \in R^J$，其可以表达为：其中，表达式说明了每个元素 $c_i$ 的计算过程. 列向量 $A_{i:}$ 乘以行向量 $B_{:j}$，再求和.einsum 标记法中，隐式地省略了求和符号，而是累加重复的下标(如，$k$) 和输出中未标出的下标(如 $i$).1.2. 向量点积比如，两个向量 $a, b \in R^{J}$ 的点积，可以表达为：1.3. 高阶张量变换比如，深度学习常见的一种高阶张量(higher-order tensor)，其包含一个 batch 中有 N 个训练样本，每个样本是一个长度为 T 的 K 维词向量序列，期望将词向量投影到一个不同的维度 Q.记，张量为 $T \in R^{N \times T \times K}$，投影矩阵记为 $W \in R^{K \times Q}$，则，einsum 表达式为：1.4. 四阶张量变换比如，对于四阶张量 $T \in R^{N \times T \times K \times M}$，期望使用上述的投影矩阵 W 将第三维投影到 Q 维，并累加到第二维，再对结果中的第一维和最后一维进行转置，最终得到张量 $C \in R^{M \times Q \times N}$. einsum 表达式为：注，这里是通过交换下标 n 和 m ($C_{mqn}$ 而不是 $C_{nqm}$)，转置了张量结果.2. Numpy/PyTorch/TensorFlow 中 einsum 标记法NumPy - einsum 符号标记函数 - AIUAINumpy - np.einsumPyTorch - torch.einsumTensorFlow - tf.einsum表示形式均为：einsum(equation, operands) #equation - einsum 约定字符串 #operands - 张量序列如，1.1.矩阵相乘，$c_j = \sum _i \sum_k A_{ik} B_{kj}$，其表示形式如：equation = 'ik,kj -> j'Numpy/PyTorch/TensorFlow 支持 einsum 的好处在于，可以应用于神经网络架构中的任意计算图，且可以反向传播.典型 einsum 调用形式如：其中，方框是占位符，表示张量维度. 根据该式，可以推断，arg1 和 arg3 是矩阵，arg2 是三阶张量，einsum 计算结果 result 是矩阵.注意，einsum 处理的是可变数量的输入. 以下依PyTorch为例示例介绍.2.1. 矩阵转置import torch a = torch.arange(6).reshape(2, 3) #tensor([[0, 1, 2], # [3, 4, 5]]) b = torch.einsum('ij->ji', [a]) #tensor([[0, 3], # [1, 4], # [2, 5]])2.2. 求和import torch a = torch.arange(6).reshape(2, 3) b = torch.einsum('ij->', [a]) #tensor(15)2.3. 列求和import torch a = torch.arange(6).reshape(2, 3) b = torch.einsum('ij->j', [a]) #tensor([3, 5, 7])2.4. 行求和import torch a = torch.arange(6).reshape(2, 3) b = torch.einsum('ij->i', [a]) #tensor([ 3, 12])2.5. 矩阵-向量相乘import torch a = torch.arange(6).reshape(2, 3) b = torch.arange(3) #tensor([0, 1, 2]) c = torch.einsum('ik,k->i', [a, b]) #tensor([ 5, 14])2.6. 矩阵-矩阵相乘import torch a = torch.arange(6).reshape(2, 3) b = torch.arange(15).…

Pytorch - 矩阵相乘@与逐元素相乘*
type: item
date: 2021-06-06T13:18:00+00:00
description: Pytorch 代码里看到 @ 和 * 两个操作符，其功能如下.1. 矩阵相乘@示例如，import torch # X = torch.tensor([[1,2],[3,4],[5,6]]) #torch.Size([3, 2]) #tensor([[1, 2], # [3, 4], # [5, 6]]) Y = torch.tensor([[7,8],[9, 10]]) #torch.Size([2, 2]) #tensor([[5, 6], # [7, 8]]) Z = X@Y #torch.Size([3, 2]) #tensor([[ 25, 28], # [ 57, 64], # [ 89, 100]]) #等价于： Z = torch.matmul(X, Y)2. 矩阵逐元素相乘*示例如，import torch # X = torch.tensor([[1,2],[3,4],[5,6]]) #torch.Size([3, 2]) #tensor([[1, 2], # [3, 4], # [5, 6]]) Y = torch.tensor([[7,8],[9, 10],[11,12]]) #torch.Size([3, 2]) #tensor([[ 7, 8], # [ 9, 10], # [11, 12]]) Z = X*Y #tensor([[ 7, 16], # [27, 40], # [55, 72]]) #等价于： Z = torch.mul(X, Y)

Pytorch - 基于torch.distributed.all_gather的梯度反向传播[译]
type: item
date: 2021-05-16T05:16:38+00:00
description: 原文：Gradient backpropagation with torch.distributed.all_gather - 2021.02.07作者：Jianfeng Wang本文主要是关于 torch.distributed.all_gather 的使用与如何确保梯度被正确计算.torch.distributed.all_gather 定义如：https://pytorch.org/docs/stable/_modules/torch/distributed/distributed_c10d.html#all_gatherdef all_gather(tensor_list, tensor, group=None, async_op=False): """ Gathers tensors from the whole group in a list. Complex tensors are supported. Args: tensor_list (list[Tensor]): Output list. It should contain correctly-sized tensors to be used for output of the collective. tensor (Tensor): Tensor to be broadcast from current process. group (ProcessGroup, optional): The process group to work on. If None, the default process group will be used. async_op (bool, optional): Whether this op should be an async op Returns: Async work handle, if async_op is set to True. None, if not async_op or if not part of the group Examples: >>> # All tensors below are of torch.int64 dtype. >>> # We have 2 process groups, 2 ranks. >>> tensor_list = [torch.zero(2, dtype=torch.int64) for _ in range(2)] >>> tensor_list [tensor([0, 0]), tensor([0, 0])] # Rank 0 and 1 >>> tensor = torch.arange(2, dtype=torch.int64) + 1 + 2 * rank >>> tensor tensor([1, 2]) # Rank 0 tensor([3, 4]) # Rank 1 >>> dist.all_gather(tensor_list, tensor) >>> tensor_list [tensor([1, 2]), tensor([3, 4])] # Rank 0 [tensor([1, 2]), tensor([3, 4])] # Rank 1 >>> # All tensors below are of torch.cfloat dtype. >>> # We have 2 process groups, 2 ranks. >>> tensor_list = [torch.zero(2, dtype=torch.cfloat) for _ in range(2)] >>> tensor_list [tensor([0.+0.j, 0.+0.j]), tensor([0.+0.j, 0.+0.j])] # Rank 0 and 1 >>> tensor = torch.tensor([1+1j, 2+2j], dtype=torch.cfloat) + 2 * rank * (1+1j) >>> tensor tensor([1.+1.j, 2.+2.j]) # Rank 0 tensor([3.+3.j, 4.+4.j]) # Rank 1 >>> dist.all_gather(tensor_list, tensor) >>> tensor_list [tensor([1.+1.j, 2.+2.j]), tensor([3.+3.j, 4.+4.j])] # Rank 0 [tensor([1.+1.j, 2.+2.j]), tensor([3.+3.j, 4.+4.j])] # Rank 1 """ _check_tensor_list(t…

Pytorch - DataParallel和DistributedDataParallel
type: item
date: 2021-05-16T02:46:00+00:00
description: 基于多个 GPUs 的数据并行化处理，其基本思想是，每个 GPU 复制一个模型副本，分别对 batch 数据进行前向和后向计算. 后向计算的梯度发送到服务器，由服务器运行 reduce 操作，计算平均梯度. 然后，将平均梯度传输回 GPU，GPU 使用 SGD 更新模型参数. 采用数据并行和有效的网络通信库(如NCCL)，可以实现训练时间的几乎线性减少.Pytorch 关于数据并行有两种实现：nn.parallel.data_parallel 和 DistributedDataParallel.1. 数据加载并行化深度学习框架，如Pytorch 和 Tensorflow，网络训练从磁盘读取输入数据开始，一般包括四个步骤：[1] - 从磁盘加载数据到 host；[2] - 将数据从可分页的(pageable)数据传输到 host 的固定内存(pinned memory)；[3] - 将数据从固定内存传输到 GPU；[4] - 在 GPU 上进行前向和后向计算.这些步骤中的每一个都必须尽可能并行化，并且每当不存在数据依赖性时，下一个 batch 都应与当前 batch 进行管道化(pipelined).PyTorch 中的 Dataloader 提供了多进程(multi-process)从磁盘加载数据(设置num_works>0)以及多线程(multi-threaded) 将数据从可分页的(pageable)数据传输到 host 的固定内存(设置 pin_memory = True)的能力.对于大批量的数据，若仅有一个线程用于加载数据，则数据加载时间占主导地位，这意味着无论如何加快数据处理速度，性能都会受到数据加载时间的限制. 如图：如，Pytorch 中设置num_workers = 4以及pin_memory = True. 即可使用多进程(multiple processes)从磁盘读取不重叠的数据，并启动生产者-消费者线程(producer-consumer thread) 以将这些进程读取的数据从可分页的内存转移到固定内存.多进程可以更快的加载数据，且，当数据处理的时间足够长时，管道化数据加载几乎能够忽略数据加载延迟. 其原因是，处理当前 batch 数据的同时，下一 batch 的数据已经从磁盘读取并传输到固定内存里. 如果当前 batch 的处理时间足够长，下一 batch 的数据是立即可用的. 基于这种思想，有助于 num_workers 参数的选择，其应是，从磁盘读取 batch 数据的速度比 GPUs 处理当前 batch 数据的速度更快(但，也不能太高，因为多个进程也会浪费系统资源).如图，2. DataParallelnn.parallel.data_parallel2.1. 工作过程如图：DataParallel 的工作过程如：[1] - 将整个 mini-batch 数据加载到主线程(main thread);[2] - 在各 GPU 上分发(scatter) sub mini-batchs 的数据;[3] - 在各 GPU 上复制模型；[4] - 每个 GPU 分别在各自的线程对其 sub mini-batch 的数据进行前向计算;[5] - 在主 GPU 上收集(gather) 网络输出，并通过将网络输出与 batch 内每个元素的真实标签比较，计算损失函数；[6] - 分发损失函数到各 GPU，每个 GPU 进行后向传播，以计算梯度；[7] - 在主 GPU 上 reduce 梯度；[8] - 更新主 GPU 上的模型参数.以上即完成了一次迭代. 由于只在主 GPU 上更新了模型参数，因此，其他GPU上的模型现在并未同步，且必须在下一次迭代开始时，将模型参数广播到其他 GPU.nn.parallel.data_parallel.py 中 forward 函数的实现，对应如：不过，backwords 的实现是 C 的，2.2. 存在问题[1] - 冗余数据副本数据从主机(host) 复制到主GPU，然后将sub mini-batches 分发到其他GPU上[2] - 在前向计算前跨GPUs 进行模型复制由于模型参数是在主GPU上更新的，因此模型必须在每次前向计算开始时重新同步[3] - 每个 batch 的线程创建/销毁开销并行转发是在多个线程中实现的（这可能只是PyTorch问题）[4] - 梯度减少管道机会未利用(Gradient reduction pipelining opportunity left unexploited)Pytorch数据并行实现中，梯度下降发生在后向传播的末尾处.[5] - 在主GPU上不必要地收集模型输出output[6] - GPU利用率不均在主GPU上进行损失函…

Pytorch - 提升性能的几个技巧[转]
type: item
date: 2021-05-08T12:58:29+00:00
description: 原文：7 tips for squeezing maximum performance from pytorch原文：7个提升PyTorch性能的技巧出处：AI公园 - 微信公众号作者：William Falcon编译：ronghuaiyang为了帮助训练得更快，这里有几个技巧，应该知道它们可能会减慢训练代码.1. 在DataLoader中使用workersdata_loader = DataLoader( dataset, collate_fn=collate_fn, batch_sampler=sampler, num_workers=NUM_WORKERS, #多进程 pin_memory=True, )PyTorch允许同时在多个进程上加载数据. PyTorch 可以通过处理 NUM_WORKERS 个批次绕过GIL锁，每个批次在一个单独的进程上。应该使用多少workers？一个好的经验法则是:num_worker = 4 * num_GPU可以参考：Guidelines for assigning num_workers to DataLoader缺点是，内存使用也会增加.2. 设置 Pin memory有时候GPU显存显示是满的，但模型并没有使用那么多，这种开销称为 pinned memory. 这个内存被保留为一种 “working allocation” 类型.当在一个DataLoader中启用pinned_memory时，它自动将获取的数据张量放在 pinned memory 中，并使数据更快地传输到CUDA-enabled的gpu.图：How to Optimize Data Transfers in CUDA C/C++这意味着不需要不必要的去调用：torch.cuda.empty_cache()3. 避免CPU与GPU间的传输# bad.cpu() .item() .numpy()大量使用 .item() 或 .cpu() 或 .numpy() 调用，对于性能来说是非常糟糕的，因为每个调用都将数据从GPU 传输到 CPU，从而极大地降低了性能.如果试图清除附加的计算图，请使用 .detach() .# good.detach()其不会将内存转移到GPU，会删除任何附加到该变量的计算图.4. 直接在GPUs上构建张量大多数人都是这样在GPUs上创建张量的:t = tensor.rand(2,2).cuda()然而，这首先创建CPU张量，然后将其转移到GPU……这真的很慢. 相反，直接在想要的设备上创建张量：t = tensor.rand(2,2, device=torch.device('cuda:0'))5. 使用DistributedDataParallel使用DistributedDataParallel不要使用DataParallel.PyTorch有两个主要的模式用于在多 GPUs训练：第一种是DataParallel，它将一批数据分割到多个GPUs上. 但这也意味着模型必须复制到每个GPU上，一旦在GPU 0 上计算出梯度，它们必须同步到其他GPU. 这需要大量昂贵的GPU传输. 第二种是，DistributedDataParallel在每个GPU(在它自己的进程中)上创建模型副本，并且只让数据的一部分对该GPU可用. 这就像是让N个独立的模型进行训练，除了一旦每个模型都计算出梯度，它们就会在模型之间同步梯度. 这意味着在每批处理中只在GPUs之间传输一次数据.6. 使用16-bit精度这是另一种加快训练速度的方法，实际上现在还没有很多人使用这种方法.模型训练采用 16bit，数据从32位变到到16位，其有几个优点:[1] - 使用了一半的内存(这意味着可以将batch大小翻倍，并将训练时间减半)[2] - 某些GPU(V100, 2080Ti)可以自动加速(3 -8倍)，因为它们针对16位计算进行了优化.注：在PyTorch 1.6之前，还必须安装Nvidia Apex，现在16位是PyTorch的原生版本.7. 对代码进行Profile如果没有PyTorch-Lightning，最后一条建议可能很难实现，但可以使用cprofiler这样的工具来实现.然而，在 PyTorch-Lightning 中，可以通过两种方式获得所有在训练期间所做的调用的总结：第一种是，内置的basic profiler:Trainer(profile=True)可以给出这样的输出：第二种是，高级的profiler：profiler = AdvancedProfiler() trainer = Trainer(profiler=profiler)得到更细粒度的结果：