Arganzheng's Blog

stay hungry, stay foolish

PyTorch 深度实践(06):C++ 扩展与自定义算子

C++ Extensions and Custom Operators in PyTorch

上一篇把算子系统拆成两个维度:开发者在构建时定义 → 注册 → 实现,用户在运行时入口 → 分发 → 执行,两者通过 Operator Table 交汇。那一篇站在使用者的角度观察原生算子 add。 这一篇换到开发者的位置:自己写一个算子,把它接入 PyTorch 的算子系统1 。 这是从“阅读框架”走向“扩展框架”的关键一步。AI-Infra 工作中大量的实际需求都落在这里:一个融合 Kernel、一个新硬件的后端适配、一个推理引擎的定制算子,最终都要经过同样的路径。 本文用一个刻意简单的算子贯穿全文:scale_shift(x, alpha, beta) = alpha * x + beta。它简单到不会分散注意力,又足够涉及 Tensor 元数据、dty...

PyTorch 深度实践(05):Dispatcher 与算子系统

The Dispatcher and Operator System in PyTorch

上一篇讨论了 nn.Module 与训练系统:Module 如何组织子模块、Parameter 和 Buffer,Optimizer 如何更新参数,DataLoader 如何把数据送入训练循环。 但当我们写下: z = x + y 到底是谁决定了这个操作对应哪个算子、x 和 y 位于哪个设备、当前是否需要 Autograd、最终应该调用哪个 Kernel?1 这些问题属于 PyTorch 的算子系统(Operator System)。本文不会一开始分析复杂的 Attention,而是选择最简单的 add 算子,从两个视角把算子系统拆开:算子开发者在构建时做了什么,以及算子使用者在调用时发生了什么。 Dispatcher 解决的不是“调用哪个 Pyt...

PyTorch 深度实践(04):nn.Module 与训练系统

nn.Module and Training Systems in PyTorch

上一篇讨论了 Autograd:Tensor 运算如何形成动态计算图,backward() 如何沿图传播梯度,以及梯度状态和计算图生命周期之间有什么关系。 但一个真实的模型不会只是几个散落的 Tensor 运算。它通常包含: 多层嵌套的网络结构; 需要训练的参数; 不参与梯度更新但属于模型状态的 Buffer; 优化器和优化器状态; 训练、验证和推理三种不同阶段; 数据集、采样器和 DataLoader; CPU 到 GPU 的数据搬运; checkpoint、恢复训练和混合精度。 PyTorch 用 nn.Module 把这些对象组织起来,再通过 Optimizer、Dataset 和 DataLoader 将它们连接成训...

PyTorch 深度实践(03):自动求导与动态计算图

Autograd and Dynamic Computation Graphs in PyTorch

上一篇介绍了 Tensor 的核心模型:它不是一组孤立的数字,而是由 Storage、Shape、Stride、Storage Offset、dtype、device 和 layout 共同描述的一种数据抽象。 但 Tensor 只有数据和布局,还不能完成模型训练。训练还需要回答一个问题: 模型输出发生变化时,参数应该沿着什么方向、以多大的幅度变化?1 这需要计算梯度。PyTorch 通过 Autograd 把数学上的求导过程变成了一个可以执行的运行时系统: Tensor 运算 动态记录运算关系 形成计算图 从结果反向遍历 计算并累积梯度 Optimizer 更新参数 初学者通常只需要记住: loss.backward...

PyTorch 深度实践(02):Tensor 与内存布局

Tensor Abstraction and Memory Layout in PyTorch

上一篇从整体上介绍了 PyTorch:它不是只有 Python API 的库,而是连接模型代码、Tensor 编程模型、算子运行时、设备后端、Kernel 和硬件的一套计算平台。 这一次进入这张地图的核心数据抽象: Tensor 到底是什么?1 初学 PyTorch 时,Tensor 很容易被理解成“支持 GPU 的 NumPy 数组”。这个理解可以帮助开始使用,但不足以解释真实工程中的许多现象: 为什么 transpose() 通常不会复制数据?2 为什么 view() 有时成功,有时会报错?3 为什么 reshape() 有时是零拷贝,有时会产生一份新数据?4 为什么一个 Tensor 的 shape 相同,性能却可能完全不同?...

PyTorch 深度实践(01):PyTorch 整体介绍

PyTorch Overall Introduction

PyTorch 经常被介绍成一个“深度学习框架”,也经常被使用成一个 Python 库:导入 torch,创建 Tensor,定义 nn.Module,然后训练模型。 这种理解对于开始使用 PyTorch 已经足够,但对于训练平台、推理引擎、算子开发和 AI-Infra 来说还不够。真正需要理解的是: PyTorch 如何把 Python 中表达的张量计算,转化为可以自动求导、跨设备执行、编译优化和分布式协作的运行时系统?1 一行看起来很普通的代码: z = torch.add(x, y) 背后可能涉及: Python API Python Binding Operator Schema Dispatcher ATen O...

PyTorch 深度实践:从 Tensor 到深度学习运行时(总纲)

Deep Dive into PyTorch, from Tensor to Deep Learning Runtime

内容简介 《PyTorch 深度实践:从 Tensor 到深度学习运行时》是一组共十篇的系列文章,面向有后端工程经验、尤其是 Java 背景、准备进入 AI-Infra 方向的工程师,系统梳理 PyTorch 从 Python API 到 C++、CUDA、编译器、性能分析和分布式运行时的主要机制。 它同时是《AI 算法工程师学习地图》 L1 工具箱的深入篇:算法侧的《算法工程师的工具箱》讲 PyTorch 的”用”——五个对象、二十行训练循环、显存的账——本系列讲”改”:Dispatcher、Autograd 引擎、编译、分布式。两张地图共享本系列,算法方向的读者按需读。 这个系列不是 PyTorch API 速查表,也不是机器学习算法教程,而是试图回答一个...

C++ 在 AI-Infra(09):系列总结与通关自测

C++ for AI-Infra: Series Recap and Final Self-Test

八篇正文回答了一个问题:PyTorch 和 vLLM 的 C++ 源码里,这段代码为什么这样写。第一篇讲一个 .cpp 怎么变成 .so、import torch 拉起哪几个库;第二篇讲 at::Tensor 为什么是一个 8 字节的句柄、数据什么时候释放;第三篇讲 AT_DISPATCH 里的 scalar_t 从哪里来;第四篇讲 Dispatcher 用什么机制调到 kernel;第五篇讲算子怎么在没有任何显式调用的情况下登记进 torch.ops;第六篇讲 no_grad 为什么对其他线程不生效;第七篇讲一个 Tensor 跨过 Python/C++ 边界经过了什么;第八篇讲一个改动从写完到能提 PR 要跑哪些东西。八篇合起来,是总纲开篇那段 scale_sh...

C++ 在 AI-Infra(08):构建、调试与测试工具链

Build, Debug and Test Toolchain

PyTorch 的 CI 测试脚本 .ci/pytorch/test.sh 里有一段很奇怪的代码。在 ASan 构建下,它先设置一堆环境变量,然后故意让 Python 进程崩溃四次: if [[ "$BUILD_ENVIRONMENT" == *asan* ]]; then export ASAN_OPTIONS=detect_leaks=0:symbolize=1:detect_stack_use_after_return=true:strict_init_order=true:detect_odr_violation=1:detect_container_overflow=0:check_initialization_order=true:debug=...

C++ 在 AI-Infra(07):与 Python 之间——pybind11、Python C API 与 ABI

pybind11, the Python C API and ABI

torch.Tensor 在 Python 里是一个再普通不过的对象:能 isinstance、能子类化、能 t.foo = 1 挂属性、能被 gc 收集。但它在 C++ 里的定义,在 torch/csrc/autograd/python_variable.h 开头: // Python object that backs torch.autograd.Variable struct THPVariable { PyObject_HEAD // Payload at::Tensor cdata; // Hooks to be run on backwards pass (corresponds to Python attr // '_backw...

×