Arganzheng's Blog

stay hungry, stay foolish

Python 在 AI-Infra(02 下):类型系统——数据契约设计

Type System III: Data Contract Design

前两篇沿着”类型信息如何流动”展开:上篇讲怎么写(typing 工具箱),中篇讲怎么分发、谁消费(存根、mypy、运行时读注解)。本篇的组织轴切换——不再讨论类型信息本身,而是讨论用这些能力去构建什么:数据契约。 所谓数据契约,就是对”一组数据长什么样”的正式约定。在 AI Infra 里它无处不在:推理服务的请求体与响应体、训练任务的配置文件、模型仓库里的元数据、Worker 之间传递的消息。Java 工程师熟悉的 Bean Validation、Jackson、@ConfigurationProperties 在这里对应的是 @dataclass、Pydantic BaseModel、BaseSettings——但它们不是一一对应的翻译,而是同一份类型注解的三...

Python 在 AI-Infra(02 中):类型系统——类型信息的分发与消费

Type System II: Distributing and Consuming Type Information

上篇讲了怎么写类型:typing 工具箱里每个工具表达哪一种类型意图。但写下来的注解在 Python 里默认什么都不发生——解释器只是把它存进 __annotations__,不检查、不转换。类型信息要产生作用,得有人读它。本篇讲的就是这条链路的中间两段: 分发:我写的注解怎么随包发给别人?没有源码注解的库(torch._C 这类 C 扩展)怎么提供类型信息?——.pyi 存根、typeshed、types-*、py.typed / PEP 561; 消费:谁在读注解、什么时候读、读到之后做什么?——静态一侧是 mypy / pyright 在开发时推理与检查;动态一侧是 get_type_hints()、@dataclass 的代码生成、Pydanti...

Python 在 AI-Infra(02 上):类型系统——类型表达与 typing 工具箱

Type System I: Type Expression and the typing Toolbox

Python 是动态类型语言,但这不意味着”无类型”。自 Python 3.5 引入 typing 模块以来,类型注解已经从”可选装饰”演变为大型项目的工程标配。PyTorch、vLLM、FastAPI 等 AI Infra 项目大量依赖类型系统的高级特性。 与 Java 把类型声明、编译检查、.class 文件携带类型信息、运行时反射合为一体不同,Python 的类型系统由两个协作层构成——类型信息提供层和类型信息消费层。而在这两层之上,还有一层工程落地:用它们构建数据契约。 本系列这一讲围绕的核心问题是: Python 的类型信息从哪里来、被谁消费,又如何在系统边界上落成可执行的数据契约?1 这条链路太长,一篇放不下,所以拆成三篇:上篇讲类型表达...

Python 在 AI-Infra(01 下):对象如何工作——对象模型、协议、装饰器与生成器

How Objects Work — Object Model, Protocols, Decorators and Generators

上篇讲的是代码怎么跑:源码编译成 code object,调用创建帧,名称在帧里按 LEGB 解析,import 找到并执行模块,异常沿帧链传播。本篇讲对象怎么工作——上篇开头那七行里剩下的五行: model(x):走的是 call,中间可能插入 hooks for batch in loader:迭代协议 + 生成器的暂停与恢复 with torch.inference_mode():上下文管理协议:进入时改状态、退出时恢复 @register(“cuda”):装饰器在模块导入时执行,注册表能否填上取决于谁导入了它 self.linear = nn.Linear(4, 4):setattr 拦截赋值,把子模块登记到 _modules 这...

Python 在 AI-Infra(01 上):代码如何被执行——执行模型、作用域、导入与异常

How Code Runs — Execution Model, Scopes, Imports and Exceptions

Python 常被认为是一门”简单易学”的语言。但在深度学习框架、推理服务和分布式训练系统里,真正需要掌握的不是语法,而是语法背后的运行时模型。下面这些在 AI-Infra 代码里随处可见的写法,每一行都依赖一个可以被替换、被拦截、被扩展的机制: import torch:触发 .so 扩展加载、算子注册、后端初始化 model(x):走的是 call,中间可能插入 hooks for batch in loader:迭代协议 + 生成器的暂停与恢复 with torch.inference_mode():上下文管理协议:进入时改状态、退出时恢复 @register(“cuda”):装饰器在模块导入时执行,注册表能否填上取决于谁导入了它 ...

Python 在 AI-Infra:从语言机制到生产交付(总纲)

Python for AI-Infra, from Language Mechanisms to Production Delivery (Overview)

内容简介 《Python 在 AI-Infra:从语言机制到生产交付》是一组共七讲、九篇的系列文章(第一讲拆成上下两篇、第二讲拆成上中下三篇,其余各一篇),面向有后端工程经验(尤其是 Java 背景)、准备转向 AI-Infra 方向的工程师,系统梳理这个方向真正需要的 Python 能力:语言核心机制、类型系统与数据契约、并发与异步、反射与元编程、内存管理、测试与调试、以及工程化交付。 它同时是《AI 算法工程师学习地图》 L1 工具箱的深入篇:算法侧的《算法工程师的工具箱》只讲训练代码里用到的 Python 子集,把语言机制与运行时交给这里——两张地图共享本系列,算法方向的读者按需读。 这个系列不是 Python 语法教程,也不是技巧集合,而是试图回答一个...

算法工程师的工具箱(07):系列总结与通关自测

Tooling for AI Algorithm Engineers: Series Recap and Final Self-Test

六篇正文回答了一个问题:把一个想法变成一次能跑、能复现、能与 baseline 对比的实验,要经过哪些工具、每个工具用到什么程度。第一篇讲训练代码里那一小撮 Python 语法与流式过语料,第二篇在 NumPy 上建立形状直觉并用 Pandas、Matplotlib 看结果,第三篇写出二十行训练循环,第四篇算这个循环要多少显存,第五篇用 Hugging Face 的六个库组装一次真实的 LoRA SFT,第六篇解释为什么快为什么慢、怎么让实验三个月后还能复现。六篇合起来,是《算法工程师的工具箱》总纲里 L1 那一层的全部:会到能做实验为止,越过那条线就进 Infra 地图。 本文不讲新内容,做三件事:把六篇压成一张表与六段回顾,把贯穿六篇的几条线拎出来,然后给一套...

算法工程师的工具箱(06):GPU 直觉与实验管理——两个上限、四块显存、能复现

GPU Intuition and Experiment Management: Two Ceilings, Four Memory Buckets, and Reproducibility

不写 kernel 的算法工程师也需要一份 GPU 直觉——不是为了优化它,而是为了解释:一次训练为什么慢、一次推理为什么快不起来、一个 OOM 从哪里来、我改的这个结构把瓶颈推向了哪边。这份直觉只有两个数字(算力、带宽)和一张表(显存的四块)。本篇讲它们,然后讲读 torch.profiler 的表,最后讲一件与 GPU 无关但同样决定实验能不能算数的事:怎么让三个月前的结果能复现。 全篇的核心问题是: 不写 kernel,能不能解释一次训练为什么慢、一次推理为什么快不起来、一个 OOM 从哪里来?1 三个月后能不能复现今天这次实验?2 一、总览 1. 本文的组织方式 前半(二到四章)回答”为什么快为什么慢”:先给 GPU 的两个上限与它们的比值...

算法工程师的工具箱(05):Hugging Face 生态——六个库与一次 LoRA SFT 的组装

The Hugging Face Ecosystem: Six Libraries, a Six-Line LoRA SFT, and Why Reading the Source Is the Fastest Way to Learn

前两篇的训练循环训的是自己写的小模型。真实工作里模型不是自己写的——是从 Hugging Face Hub 下载的 Llama、Qwen、DeepSeek;数据也不是随机切窗口——是 Hub 上的数据集经过 chat template、loss mask、packing;训练器也不是二十行——是 trl 的 SFTTrainer / DPOTrainer / GRPOTrainer。Hugging Face 的六个库把这条路铺好了,六行代码能组装一次 LoRA SFT。这一篇讲六个库各管什么、六行背后发生了什么、以及一个比任何教程都重要的习惯:卡住的时候直接读源码。 全篇的核心问题是: 能不能用 peft + trl 在一小时内跑起一个 LoRA SFT?...

算法工程师的工具箱(04):PyTorch 使用层(下)——混合精度、显存的账与多卡启用

PyTorch in Use, Part 2: Mixed Precision, the Memory Ledger and Turning On Multi-GPU

上一篇的二十行训练循环写出来之后,第一个撞上的问题几乎总是 CUDA out of memory。这一篇把”跑得动跑不动”从试出来变成算出来:训练时每个参数在显存里有几份东西、各多少字节;激活为什么与参数量无关却可能是大头;混合精度省的是哪一块;LoRA 为什么能把 128 GB 变成 17 GB;一张卡放不下时 DDP 与 FSDP 各做了什么。这是 L5 里”全量还是 LoRA、几张卡”这个决策的第一道约束,先于任何效果上的考虑。 全篇的核心问题是: 能不能算出一个 8B 模型全量微调要多少显存、为什么 LoRA 能放进一张卡?1 OOM 的时候知道看哪一块?2 一、总览 1. 一张账 混合精度训练的显存账:每参数字节、全量、LoRA、QLoR...

×