介绍
当作快速过这个资料的笔记,一些关于别的库的介绍是不完全的,考虑在使用的时候从别的信息渠道就行信息的搜集。也可以作为后面待更博客列举?
具体
torchscript
Introduction to TorchScript — PyTorch Tutorials 2.2.1+cu121 documentation
Loading a TorchScript Model in C++ — PyTorch Tutorials 2.2.1+cu121 documentation
这里介绍了把pytorch模型转换成torchscript的两种方法torch.jit.trace和torch.jit.script,前者会失去控制流信息,后者会保留控制流信息(具体查阅文档)。
转化为torchscript有以下好处:
- 不需要Python解释器也可以运行,可以被pytorch自带的特殊解释器直接使用
- 转为torchscript可以进行各种优化,提高运行效率
- 方便被其他语言调用
ONNX
这里介绍了在高效且跨平台ONNX运行环境部署的基本教程,通过torch.onnx把模型转化为onnx格式并保存,然后读取本地保存onnx格式模型并运行。
剖析pytorch model
Profiling your PyTorch Module — PyTorch Tutorials 2.2.1+cu121 documentation
这里介绍了torch.autograd.profiler,在代码里添加with profiler.record_function("MASK INDICES"):可以记录代码运行的指标,比如时间,cpu和内存使用率等,名字可以自定义,支持可视化结果。
Introduction to Holistic Trace Analysis — PyTorch Tutorials 2.2.1+cu121 documentation
Trace Diff using Holistic Trace Analysis — PyTorch Tutorials 2.2.1+cu121 documentation
这里介绍了HolisticTraceAnalysis(HTA),一个用来剖析GPU运行情况的库。
把GPU运行时间分为了等待时间、计算时间和非计算时间,方便开发者评测模型运行的情况。还支持查看GPU内部的运行情况,也支持和之前的记录进行对比,也能可视化结果。
troch.fx 操作计算图
(测试版)在 FX 中构建卷积/批量范数热熔器 — PyTorch 教程 2.2.1+cu121 文档
torch.fx
是 PyTorch
提供的一个模块,它允许用户通过操作计算图来转换和优化 PyTorch
模型。这个模块提供了一种方式来表示和操作 PyTorch
模型的抽象,使得开发者可以更容易地对模型进行修改,例如重构模型结构、插入调试代码、优化性能等。
教程里介绍了一种融合相邻层的操作(只能用于eval模式)。比如融合卷积和归一化,融合之前,模型会把卷积结果写回显存,然后在调用归一化并且从显存读取之前结果;融合后变成一种操作,卷积结果不会写回显存,而是直接进行归一化后写会显存。
def _parent_name(target : str) -> Tuple[str, str]:
"""
Splits a ``qualname`` into parent path and last atom.
For example, `foo.bar.baz` -> (`foo.bar`, `baz`)
"""
*parent, name = target.rsplit('.', 1)
return parent[0] if parent else '', name
def replace_node_module(node: fx.Node, modules: Dict[str, Any], new_module: torch.nn.Module):
assert(isinstance(node.target, str))
parent_name, name = _parent_name(node.target)
setattr(modules[parent_name], name, new_module)
def fuse(model: torch.nn.Module) -> torch.nn.Module:
model = copy.deepcopy(model)
# The first step of most FX passes is to symbolically trace our model to
# obtain a `GraphModule`. This is a representation of our original model
# that is functionally identical to our original model, except that we now
# also have a graph representation of our forward pass.
#获取计算图
fx_model: fx.GraphModule = fx.symbolic_trace(model)
modules = dict(fx_model.named_modules())
# The primary representation for working with FX are the `Graph` and the
# `Node`. Each `GraphModule` has a `Graph` associated with it - this
# `Graph` is also what generates `GraphModule.code`.
# The `Graph` itself is represented as a list of `Node` objects. Thus, to
# iterate through all of the operations in our graph, we iterate over each
# `Node` in our `Graph`.
#枚举所有计算图节点
for node in fx_model.graph.nodes:
# The FX IR contains several types of nodes, which generally represent
# call sites to modules, functions, or methods. The type of node is
# determined by `Node.op`.
#计算图节点还有别的属性,具体可以查阅相关资料
if node.op != 'call_module': # If our current node isn't calling a Module then we can ignore it.
continue
# For call sites, `Node.target` represents the module/function/method
# that's being called. Here, we check `Node.target` to see if it's a
# batch norm module, and then check `Node.args[0].target` to see if the
# input `Node` is a convolution.
#modules指的是模块,node.target指的是节点名字,node.args应该指的是输入这个节点的前置节点
if type(modules[node.target]) is nn.BatchNorm2d and type(modules[node.args[0].target]) is nn.Conv2d:
if len(node.args[0].users) > 1: # Output of conv is used by other nodes
continue
conv = modules[node.args[0].target]
bn = modules[node.target]
fused_conv = fuse_conv_bn_eval(conv, bn)
replace_node_module(node.args[0], modules, fused_conv)
# As we've folded the batch nor into the conv, we need to replace all uses
# of the batch norm with the conv.
#把使用到node节点输出的地方变成node.args[0]节点输出
node.replace_all_uses_with(node.args[0])
# Now that all uses of the batch norm have been replaced, we can
# safely remove the batch norm.
fx_model.graph.erase_node(node)
#检查计算图(Graph)的完整性和一致性,确定计算图的正确性
fx_model.graph.lint()
# After we've modified our graph, we need to recompile our graph in order
# to keep the generated code in sync.
#recompile()方法的作用是将这些修改后的计算图转换回 Python 代码,这样你就可以创建一个新的 PyTorch 模型实例,它包含了你所做的所有修改
fx_model.recompile()
return fx_model
(测试版)使用 FX 构建简单的 CPU 性能分析器 — PyTorch 教程 2.2.1+cu121 文档
通过
print(traced_rn18.graph)
我们可以查看计算图的信息,这里只选择一行查看,例子:
%layer1_1_conv2 : [num_users=1] = call_module[target=layer1.1.conv2](args = (%layer1_1_relu,), kwargs = {})
%layer1_1_conv2:节点名字,
[num_users=1]:被几个后续节点使用,
call_module:表面这是一个调用模块,
target=layer1.1.conv2:调用模块的名字,
args = (%layer1_1_relu,):传递给模块的参数(输入模块的之前节点)
kwargs = {}:额外关键词参数
可以参照教程写一个继承torch.fx.Interpreter的类,重写run和run_node实现对于计算图的捕获,在运行过程中添加自定义行为。
存储组织
(beta) Channels Last Memory Format in PyTorch — PyTorch Tutorials 2.2.1+cu121 documentation
这里介绍了内存组织方式torch.channels_last,torch.contiguous_format等,同时介绍了一下torch.stride、torch.contiguous和torch.is_contiguous等函数。
有的操作符会保留内存组织格式。
可以通过model.to(memory_format=)把模型转化为适合的组织形式,同时输入也需要相应的转换(框架应该支持自动转换?)。
但由于不是所有的操作符都支持某种内存组织格式,可能需要进行检查,这里给了检查和设置的示例代码。
前向模式自动微分
正向模式自动微分 (Beta) — PyTorch 教程 2.2.1+cu121 文档
这里看的不是很明白。挖个坑(todo...
正向传播一次只能算出相对一个参数的梯度,如果有n个参数,需要计算n次,所以这里的tangent只有一个,而不是每个参数对应一个。
可以参考【自动微分原理】AD的正反向模式 - 知乎 (zhihu.com)。
(这么一看,正向自动微分被方向自动微分爆杀?目前应用少且pytorch也只是测试版本
微分矩阵计算
雅可比派、黑森派、hvp、vhp 等:编写函数转换 — PyTorch 教程 2.2.1+cu121 文档
这里提供了各种使用自动求导计算微分矩阵的方法。
模型组装
模型组装 — PyTorch 教程 2.2.1+cu121 文档
这里介绍了torch.func.stack_model_state、torch.vmap等函数用来组装一系列结构相同参数不同的模型的输出,类似于使用cat连接模型输出,但是增加了底层优化。
单样本梯度
Per-sample-gradients — PyTorch 教程 2.2.1+cu121 文档
在一些要求对每个样本单独计算梯度的特殊情况下,可以使用本篇介绍的方法优化速度。
这里介绍了torch.func.grad、torch.func.functional_call、torch.func.vmap来优化加速(注意不同库有不同的同名函数)
这里grad和vmap都是创建的可调用对象,与别的同名函数不同。
c++接口
Using the PyTorch C++ Frontend — PyTorch Tutorials 2.2.1+cu121 documentation
介绍了怎么使用c++调用
TorchScript 中的动态并行性
TorchScript 中的动态并行性 — PyTorch 教程 2.2.1+cu121 文档
这里介绍了torch.jit.fork和torch.jit.wait两个函数用来并行执行pytorch相关代码。同时也引入了相关的类torch.jit.Future。
c++接口中的自动求导
Autograd in C++ Frontend — PyTorch Tutorials 2.2.1+cu121 documentation
这里都是一些用c++扩展pytorch的内容,后面需要细致学习(挖坑todo
自定义函数求二阶导
Double Backward with Custom Functions — PyTorch Tutorials 2.2.1+cu121 documentation
这篇文章介绍了怎么使用继承自torch.autograd.Function的自定义函数(重新forward和backward),计算导数,并且用torch.autograd.gradcheck使用数值解验证求导以及使用torchviz 可视化图形。
同时,注意在运行过程中,保存求导所需要参数时候建议按照教程分保存输入、保存输出和保存中间结果考虑代码结构,避免bug。
forward函数返回结果似乎和backward参数对应,backward输入参数是每个forward函数返回结果的grad。
保存中间结果的时候需要把中间结果返回,这样可以让pytorch的自动微分系统追踪这些中间结果(个人理解为返回中间结果相当于注册了这些中间结果,在backward的时候设置grad模型就会追踪这些中间结果,理解可能有误,但是使用的时候参考教程应该问题不大)。
自定义函数实现卷积
先介绍了自定义卷积函数的构造,这里的once_differentiable指的是正向传播的结果只会反向传播一次,作用为求二阶导的时候会报错,从而起到限制的作用。
然后介绍了自定义批量归一化层的构造,然后介绍了自定义函数混合卷积和批量归一化,从而实现了节省内存的作用。
自定义 C++ 和 CUDA 扩展
Custom C++ and CUDA Extensions — PyTorch Tutorials 2.2.1+cu121 documentation
这里介绍了两个扩展c++组件的方法,“ahead of time ”和“just in time”。
ahead of time:构建setup.py文件用于构建c++扩展,然后在对应的cpp文件里面构建c++扩展代码。
just in time:通过torch.utils.cpp_extension.load直接加载cpp文件,会把编译的中间文件存在一个临时目录里。
这里还介绍了编写混合 C++/CUDA 扩展,由于还没有学过cuda,挖个坑todu...
使用自定义 C++ 运算符扩展 TorchScript
Extending TorchScript with Custom C++ Operators — PyTorch Tutorials 2.2.1+cu121 documentation
如题,后面需要细致学习todo,,,
使用自定义 C++ 类扩展 TorchScript
Extending TorchScript with Custom C++ Classes — PyTorch Tutorials 2.2.1+cu121 documentation
如题,后面需要细致学习todo,,,
在C++中注册一个分派操作符
Registering a Dispatched Operator in C++ — PyTorch Tutorials 2.2.1+cu121 documentation
由于一个操作在不同的设备上对应不同的底层代码,所以为了抽象化其操作,方便调用,需要在内核注册对应设备对应函数,然后在调用。
比如,第一个把 myadd_cpu
注册到cpu上的
myadd
函数,当在cpu上运行 myadd
函数时候,会调用
myadd_cpu
TORCH_LIBRARY_IMPL(myops, CPU, m) {
m.impl("myadd", myadd_cpu);
}
TORCH_LIBRARY_IMPL(myops, CUDA, m) {
m.impl("myadd", myadd_cuda);
}
然后在使用的时候,通过torch的调度器自动根据设备在内核寻找合适函数调用。
Tensor myadd(const Tensor& self, const Tensor& other) {
static auto op = torch::Dispatcher::singleton()
.findSchemaOrThrow("myops::myadd", "")
.typed<decltype(myadd)>();
return op.call(self, other);
}
这里还介绍了自动投影机制autocast,用于在运算之前把精度投影到合适的精度。
在 C++ 中扩展新后端的调度程序
Extending dispatcher for a new backend in C++ — PyTorch Tutorials 2.2.1+cu121 documentation
后端(backend)通常指的是支持PyTorch运行的底层系统或框架,这里介绍了如何添加自定义的框架。(大致是需要实现一些基本的运算,别的运算可以表示成这样运算的组合)。
Facilitating New Backend Integration by PrivateUse1 — PyTorch Tutorials 2.2.1+cu121 documentation
这里介绍了使用privateuse1注册新后端的流程。
结合tensorboard的profiler
PyTorch Profiler With TensorBoard — PyTorch Tutorials 2.2.1+cu121 documentation
这篇文章介绍了profiler结合tensorboard的使用。
使用Ray Tune进行超参数调优
Hyperparameter tuning with Ray Tune — PyTorch Tutorials 2.2.1+cu121 documentation
这篇文章介绍了怎么使用Ray Tune库进行超参数的搜索。
优化Vision Transformer模型
Optimizing Vision Transformer Model for Deployment — PyTorch Tutorials 2.2.1+cu121 documentation
这篇文章介绍了怎么去优化Vision Transformer模型,列举了一些常见的优化方式。
参数化教程
Parametrizations Tutorial — PyTorch Tutorials 2.2.1+cu121 documentation
这里的参数化指的是类似于对模型部分权重使用的一种限制,应该是在参数修改后调用(比如初始化,参数更新等)的一些nn.module,从而使得模型更加灵活,实现对不同参数的不同处理过程,具体使用过程也是看教程,进行类的注册,使用函数parametrize。
with parametrize.cached():可以开启参数的缓存模型。
可以对于一个参数注册多个参数化模块。
同时参数化模块内部有的函数可以只在特殊时期调用,比如初始化。
可以移除参数化模块。
剪枝教程
Pruning Tutorial — PyTorch Tutorials 2.2.1+cu121 documentation
这里介绍了剪枝和机制,以及钩子函数的引入。
介绍了组合剪枝,通过移除重参数化来永久化剪枝,不同模块针对剪枝,全局剪枝,扩展自己的剪枝函数等。
动态量化
(beta) Dynamic Quantization on BERT — PyTorch Tutorials 2.2.1+cu121 documentation
这里介绍了使用torch.quantization.quantize_dynamic动态量化一次常见模型的例子。
计算机视觉的量化迁移学习教程
这篇文章介绍了在微调时候插入量化模拟层和反量化层,从而让模型适应量化的过程(QAT)。
PyTorch 中具有 Eager 模式的静态量化
(beta) Static Quantization with Eager Mode in PyTorch — PyTorch Tutorials 2.2.1+cu121 documentation
这个教程演示如何进行训练后静态量化,并说明两种更先进的技术,通道量化和量化感知训练。
从第一性原理挖掘 PyTorch Intel CPU 性能
这里介绍了优化CPU性能的方法和原理,目前来说太高深(挖矿todo
带 Ax 的多目标 NAS
Multi-Objective NAS with Ax — PyTorch Tutorials 2.2.1+cu121 documentation
这篇文章介绍了怎么使用Ax平台进行神经网络架构的搜索。
torch.compile介绍
Introduction to torch.compile — PyTorch Tutorials 2.2.1+cu121 documentation
可以使用torch.compile当做装饰器或者函数使用。
同时也列举了几个模式以及和别的几个优化方法的对比。
Inductor CPU backend debugging and profiling
Inductor CPU backend debugging and profiling — PyTorch Tutorials 2.2.1+cu121 documentation
这篇文章介绍了怎么对C++后端进行debug和profile的过程。有点复杂,,,(挖坑todo
实现高效缩放点积注意力Transformer
这篇文章介绍了怎么优化使用常用的缩放点积注意力。
torch.nested.nested_tensor支持融合不同长度的张量。
知识蒸馏
Knowledge Distillation Tutorial — PyTorch Tutorials 2.2.1+cu121 documentation
这篇教程介绍了知识蒸馏的几个方式,主要都是在损失函数里面添加教师模型和学生模型的各种量化差异来训练学生模型。