AI编译器之——为什么大模型需要Relax?

放在最前:

Relax 的关键创新

深度学习模型(比如 ChatGPT这种大模型)在运行时经常遇到“输入尺寸不固定”的情况。比如你问它一个问题,这次输入是10个字,下次可能是100个字。传统编译器处理这种“变来变去”的尺寸很笨——要么只能按固定尺寸优化(导致变尺寸时性能暴跌),要么每次都要重新编译(慢到没法用)。

Relax 的创新:

  1. 符号形状:让编译器学会“代数” Relax 允许编译器用“符号变量”(比如 n)表示未知的尺寸,就像代数里的未知数。比如告诉编译器:“这个张量的形状是 (n, 4),另一个是 (n+1, 4)”。这样编译器就能理解它们的尺寸关系,像做数学题一样优化内存和计算流程,而不是两眼一抹黑。

  2. 跨层级优化:把大任务拆小,再拼起来 传统编译器优化像“一刀切”——要么全用高级抽象(但性能差),要么全用底层代码(但改不动)。Relax
    允许同时用高级和低级代码,比如把一部分计算合并成高效内核(底层),另一部分保持灵活(高层)。就像修车时既能用现成零件,也能自己造零件,组合出最优方案。

接下来讲我们的故事。

一、为什么深度学习需要专门的编译器?

1.1 传统编译器的局限

在接触深度学习编译器之前,很多小伙伴会问:“为什么我们不能直接用 GCC、LLVM 这类成熟的通用编译器?”

  • 通用编译器聚焦 CPU 指令流水,针对的是 C/C++/Rust 等通用语言,优化目标是比较均匀的 CPU 核心与指令集。
  • 深度学习往往要在 GPU、TPU、NPU、FPGA 或移动 GPU 等多种硬件上加速,其核心是高度并行、涉及多维张量运算,需要针对张量算子的并行调度、向量化、缓存利用等进行专门的优化。
  • 传统编译器并不会天然去做“卷积融合”或“矩阵乘法切分与并行策略搜索”等,这些对深度学习性能至关重要。

因此,深度学习编译器(ML Compiler) 兴起:如 TVM、XLA、MLIR、IREE 等。它们往往具备以下能力:

  1. 接收“深度学习计算图”(如 PyTorch、TensorFlow 等)或 IR 形式的描述;
  2. 根据目标硬件生成高效的 GPU/CPU/专用加速器内核;
  3. 可能会对算子做自动搜索和调优,寻求最大化硬件性能;
  4. 在图级、张量级做内存规划、算子融合、类型推断等高级优化,从而超越单纯的“手工库调用”模式。

1.2 大模型与“动态形状”带来的新挑战

现阶段,大模型(如 GPT-4、Llama2、CodeLlama 等)在对话、文本生成、AI 助手等方面迅猛发展。这类模型动辄数十亿到上千亿参数,且在推理时需要处理可变长度的上下文,采用Key-Value Cache等机制。这就带来了“动态形状(Dynamic Shape)”需求:

  • 输入序列长度可变:不同对话轮次可能输入长短不一的文本;
  • 缓存形状随推理步数变化:KV 缓存在生成更多 token 时会不断扩展;
  • 模型中一些算子只有在运行时才知道输出大小(如 unique, non_zero 之类);
  • 大模型中还有多分支逻辑,可能需要在运行时决定下一步算子的执行路径。

这些特性使得编译器如果不能很好地处理动态形状,就会大幅退化

  • 要么只在编译期把维度视作未知,一旦到了实际执行就不得不反复调度“通用 kernel”,错失高性能;
  • 要么在图级被迫拆分成多个静态图副本(所谓 “bucketing” 或 “多分段编译”),既浪费编译存储成本,也难维护。

基于此,业界与学术界逐渐认识到:机器学习编译器需要更精细的动态形状感知能力,不再简单地把形状标记为 any-1,而应该能够在 IR 中把形状的符号维度与算术关系“显式”地表示出来,并支持相应的运算、优化、内存复用调度等。


二、Relax:面向动态形状与跨层级优化的下一代 IR

Relax 就是为了解决上述问题而提出的一种编译 IR(中间表示),它来自 TVM 项目,是继 Relay IR 之后专门为“动态形状–aware”而设计的下一代 IR。

2.1 Relax 的主要特点

  1. 一等公民的符号形状(First-class symbolic shape)

    • 在 IR 中,形状(Shape)可以显式地出现,带有符号维度和符号表达式(例如 (n, 4), (n+1, m), (n//2, 256) 等);
    • 让编译器在可能的范围内进行静态分析推断;对无法在编译期确定的部分,则留待运行时做动态检查或推断。
  2. 在同一个 IR 中同时表示高层图级与底层算子级

    • 传统编译器往往将“图级 IR”与“张量/循环级 IR”严格区分:先在高层做一些融合,然后一次性 Lower 到低层,丢失很多高层信息;
    • Relax 允许在一个 IR 内既能描述网络的整体数据流(图级),也能内嵌或调用自定义的 TensorIR 函数(循环级或外部库),以支持跨层次的优化与信息反馈。
  3. 可组合的动态形状优化

    • 算子融合(Fusion)、内存规划(Memory Planning)、Tensor 程序调度、调用外部高性能库等,都可以在 Relax 中以组合式、分阶段的方式完成;
    • 对大语言模型中最常见的注意力模块、KV Cache 更新等也能做“动态形状–aware”融合和调度。

这些特点使得 Relax 能够比前代 IR(如 Relay)在大模型和复杂动态场景中拥有更灵活、更强劲的性能表现。


三、整体编译流程:从模型到可执行

  1. 模型导入(Parse/Import)
    • 可能来自 ONNX、PyTorch、TensorFlow、或手写 IR 脚本;
    • 得到初始的 Relax 表达,可含若干动态维度(标记为 -1 或 symbolic name)。
  2. 形状推断与校正(Shape Inference & Refinement)
    • 编译器在 IR 中为每个张量插入更明确的形状注释;能在编译期确定的就确定;不能的则以符号表达式表示;
    • 如果涉及“只能在 runtime 知道结果大小”的算子(如 unique),则插入 match_cast 断言或动态检查。
  3. 算子融合与分层降级
    • 对可并行的 element-wise 等算子做融合,减少内核调用;
    • 对部分算子调用外部高性能库(如 cuBLAS/cutlass)或自定义 TensorIR 来实现;
    • 这一步是跨层可重复的,可先融合一部分,保留另一部分,后面还可继续融合,直到达成最优策略。
  4. TensorIR 优化/自动调度
    • 已经降级(lower)到 TensorIR 的子图/算子可以进一步进行循环级别的分块、向量化、并行化等调度优化;
    • Auto-scheduler 工具可在此阶段搜索更优的 kernel 实现。
  5. 内存规划(Memory Planning)
    • 在动态形状环境下,编译器需要尽量根据符号大小做全局分析,判断哪些张量可以复用显存/内存;
    • 将生存期互斥且大小能相等(符号表达式可推断相同)的张量复用同一块内存。
  6. 生成可执行
    • 最终输出一段在目标硬件上执行的函数或可执行模块;
    • 在运行时,给定具体的输入形状,编译器生成的代码会做必要的动态检查,然后运行高性能内核。

对编译器而言,这些阶段可以是一系列Pass,有些 Pass 可能会重复数次,或者先做融合再做部分形状推断等,现实中可能比上图更复杂。不过,对初学者只需把握此“自上而下、分阶段优化”的大图即可。


四、Relax 核心概念:符号形状与跨层 IR

本节我们用更多示例与短代码片段,帮助读者理解 Relax两大核心抽象:第一类符号形状(symbolic shape)与跨层 IR(cross-level IR)。学习编译器 IR 可能会略显抽象,但理解这部分对掌握后续的优化机制很关键。

4.1 第一类符号形状(Symbolic Shape)

4.1.1 基本用法

在传统编译器或 ONNX、Relay 等前代系统中,遇到维度不确定时,常以 -1any 表示。但这样会使编译期几乎无法进一步推断,导致大量潜在优化失败。Relax 的做法是:

  • 在类型注释(annotation)里允许声明诸如 Tensor((n, 4), "float32")
  • 其中 n 是一个符号变量,代表“此维度在编译期不知道具体值,但它是所有后续算子里相同的那个 n”;
  • 当多个张量都依赖 n,编译器就能判断它们形状上的关联,从而做正确的融合、内存复用等。

例如,一个函数签名可以是:

def subfunc(x: Tensor((n, 4), "f32")) -> Tensor((n*4,), "f32"):# x 的形状是 (n,4),编译器知道 n 是符号维度...# 返回一个形状 (n*4,) 的张量return y

这里 (n*4,) 也是一个符号表达式,表示 1D 张量,长度为 n*4。

  • 在编译阶段,如果后面还有算子接收 subfunc 的输出,就能匹配到其输入形状需要是 (n*4,)
  • 在运行时,真正传进来的 x 可能是 (16,4),则 n=16,返回张量就会实际变成 (64, )。
4.1.2 动态检查:match_cast 与类型断言

并不是所有维度都能在编译时精确得知表达式。某些算子(比如 unique)的输出大小只有在运行时才知道。这时为了继续后续的形状推断,可以写类似:

# 伪代码示例
def unique_and_exp(x: Tensor((n,), "f32")) -> Tensor((m,), "f32"):lv0 = unique(x)                         # output shape 不确定lv1 = match_cast(lv0, Tensor((m,), "f32"))  # match_cast 表示把 lv0 的形状“匹配”为 (m,)# 如果运行时发现 lv0 并非 1D,或与 m 不一致,就会报错return exp(lv1)

match_cast 告诉编译器:“我期望 lv0 最终是一维张量,并把其长度符号标记为 m。” 在编译后,执行时如果实际大小不对,就会触发动态断言错误。一旦通过,则编译器就能用 m 去表示后续算子的形状。

4.2 跨层 IR:在同一个环境中描述图级和算子级

4.2.1 call_tir / call_dps_library

在深度学习中,“算子级”常常是“CPU/GPU Kernel 代码、卷积/矩阵乘法内核、元素级 for-loop 程序”等;而“图级”则是算子之间的数据流。

  • 传统做法:先在图级 IR(如 Relay)里写网络结构,然后“一次性” Lower 到低层(如 TensorIR)生成 kernel 代码;此时高层信息就丢了。
  • Relax 做法:在同一个 IR 里保留了调用低层内核的语句:
    1. call_tir:调用自定义或自动生成的 TensorIR 函数;
    2. call_dps_library:调用外部已经写好的库函数,采用 Destination-Passing Style(DPS)给定输出 buffer。

也就是说,Relax 在图级的函数中,可以直接把若干节点替换成一次 “call_tir(…)”,对应一个底层循环级实现。后续若还想做跨算子融合或调度变更,可以再做局部更新,而不必重新从头编译。

4.2.2 部分降级(Partial Lowering)与可组合优化

由于可以在图级 IR 与算子级 IR“共存”,所以 Relax 可以分多阶段地把一部分图节点转换为 call_tir,保留另一部分依旧是图节点:

  • 先融合一批简单的 element-wise,生成一个合并的 TensorIR;
  • 再观察剩余算子是否还可与之融合,或者替换为外部库;
  • 多轮迭代后,得到最终形态的“call_tir / call_library + 符号形状注释 + 融合调度”,极大地增大了优化的灵活度。

五、动态形状带来的关键优化:融合与内存复用

本节我们在介绍完 Relax 的核心抽象后,来看两项在大模型或变形模型里尤其重要的编译优化:算子融合内存规划。这两者如果结合“动态形状意识(symbolic shape)”来做,往往能省下大量计算与显存资源。

5.1 动态形状–感知算子融合

5.1.1 为什么要融合

深度学习中,很多小算子如果单独执行,需要反复把中间结果写回到显存再读出来,导致大量数据搬运开销。而把多层 element-wise(如 ReLU、Add、LayerNorm 的局部操作)或者某些常见操作(如 MatMul + BiasAdd + ReLU)合并为一个 kernel,可以大幅减少中间数据的 IO,提升 GPU 利用率。

5.1.2 动态场景下的形状匹配

要做融合,需要确认被融合的算子在形状上可匹配。如果二者在编译期就是完全静态如 (128,256) -> (128,256),这很简单。但在动态形状中,要判断 (n,256)(n,256) 是不是同一个 n 还是两个无关符号,就需要依赖 Relax 对符号的统一管理。如果编译器识别它们共享同一个 n,就可安全融合。否则只能分开。

比如:

# 假设前面已有 lv0: Tensor((n,256), "f32")
lv1 = relu(lv0)          # shape (n,256)
lv2 = add(lv1, 1.0)      # shape (n,256)

如果这两个算子是都在 IR 中定义为 call_tir(“relu_fn”)、call_tir(“add_fn”),并且编译器看到二者形状都是 (n,256),则可以把二者合并为一个新的 fused kernel:call_tir(“relu_add_fused”)。

5.1.3 生成融合后的 TensorIR

融合后,Relax 会生成一个新的 TensorIR 函数,如 fused_relu_add. 其循环伪代码可能长这样:

@tensorir_function
def fused_relu_add(X: Buffer((n,256), "f32"), Out: Buffer((n,256), "f32")):for i, j in grid(n, 256):# ReLUtmp = max(X[i, j], 0.0)# Add(1.0)Out[i, j] = tmp + 1.0

随后,高层 IR 会把对 relu(…) 和 add(…) 的两个调用替换成对 fused_relu_add 的一次性调用,大大减少内核启动和中间存储的消耗。对大模型而言,类似的融合技巧能显著提高吞吐率。

5.2 动态形状–感知内存复用

5.2.1 生存期与复用分析

在大模型推理或训练中,往往有很多中间张量的大小都取决于符号维度(如 n*256(n+1)*256 等)。如果编译器能够在图级知道某些张量“不会同时被用到”,并且它们的形状大小在运行时可确认相同,就能将它们复用同一块显存 buffer。

5.2.2 如何判断大小相等

对静态形状,如 (128,256)(128,256),很简单。对动态形状,如 (n,256)(n,256)

  • 如果确知它们的 n 是同一个符号,就表示大小相等;
  • 如果一个是 (n+1, 4),另一个是 (4n+4,),编译器可以做算术简化,判断其是否总相等;
  • 如果仍无法在编译期确定,则需要在运行时比较符号值,若相等则复用,否则分配新的空间。
5.2.3 应用于大模型 KVCache

在大语言模型里,KVCache 占用大量显存,并且在对话生成时会不断扩充 shape。如果编译器能对其“持续存在”的部分做一次性分配,然后对其他一些临时张量做复用,就可以显著降低峰值显存。对于在手机端部署大模型这种极端场景,这种编译级内存规划尤为重要。


六、实践案例:如何用 Relax 编译一个简化的 LLM 推理

本节我们通过一个“简化的 LLM 推理”案例,示例哪些算子需要动态形状,以及 Relax 如何自动完成优化。案例中并不会展示完整的大语言模型(那包含非常多层),而是强调动态部分的核心思路。

6.1 场景与算子

  • 我们有一个“变体的 LLM Block”,包含:
    1. 嵌入层(Embedding)
    2. KVCache 存取更新
    3. Self-Attention(可调用外部库)
    4. 一些元素级操作(ReLU、LayerNorm、Add)
  • 对于多轮生成past_len 会从 0 开始,一步步增长,每次生成一个新 token 就将 KVCache 扩充到 (past_len+1, hidden_dim)

在 Relax 中,形式可能是这样:

def forward_block(x: Tensor((batch, seq_len), "int32"),past_kv: Tensor((batch, heads, past_len, dim_per_head), "f16")):# 1. Embedding => (batch, seq_len, hidden_dim)emb_out = call_dps_library("my_lookup_table", [x], shape=(batch, seq_len, hidden_dim))# 2. Self-Attention => 需要 (batch, seq_len, hidden_dim) + past_kv# 输出新 token 的隐状态,以及更新后的 kvattn_out, new_kv = call_dps_library("cutlass_attention", [emb_out, past_kv],# 形状注释仅示例out_shape_attn=(batch, seq_len, hidden_dim),out_shape_kv=(batch, heads, past_len+seq_len, dim_per_head))# 3. 对 attn_out 做一些 element-wise 操作,如 ReLUrelu_out = call_tir(my_relu, [attn_out], Tensor((batch, seq_len, hidden_dim),"f16"))# 4. ... 省略更多算子return relu_out, new_kv

核心看点在于:

  • “past_len+seq_len” 这样的符号表达式可以直接写到 out_shape_kv 上;
  • 后续所有需要 KVCache 的地方,Relax 都能将其形状与上一轮调用中传回的“new_kv”对应起来;
  • 在编译阶段,就能识别 (batch, seq_len, hidden_dim) 这类形状为一组动态符号 (b, s, d),并与 KVCache 维度 (b, h, p, d') 建立关联。

6.2 编译过程中的优化要点

  1. 算子融合:将 element-wise 算子(如 ReLU、BiasAdd、LayerNorm)合并,减少 GPU kernel 启动;
  2. 部分外部库:像 Attention 核心可直接调用 cutlass 或 cublas gemm,拿到更优实现;
  3. 动态形状–感知内存复用:把临时结果的形状 (b, s, d) 与其他同形张量复用(不与 KVCache 复用,因为 KVCache 需要长期保留)。
  4. 最终可执行:在 runtime,每一轮生成 token 时 seq_len=1past_len 会随轮数不断增加,但 kernel 并不退化为最通用模式,因为 “d, b 等大部分维度是已知或可做静态特化”,只在 p 维度上做循环。

6.3 实际性能与对比

Relax 论文和社区提供的结果:

  • 对 Llama2-7B、13B、甚至更大规模模型,在 GPU 上或 Apple M 系列上,用 Relax 做端到端编译后,可获得与手工写 kernel 或 llama.cpp 类似、甚至更优的推理速度;
  • 在一些 GPU(如 AMD)或移动 GPU(如苹果 Metal、Adreno、Mali)上,Relax 的移植性也表现不错,往往能超越那些只针对英伟达 CUDA 优化的手工实现。

七、在移动与嵌入式设备部署

除服务器 GPU 场景外,Relax 也非常关注在手机、平板、IoT 设备等硬件上的部署。因为这些设备内存更有限,且可能需要动态形状(如可变输入分辨率、可变语音片段长度、多轮对话上下文等):

  • 符号形状让编译器能精确或半精确地推断各种张量大小,并且在运行时做动态适配;
  • 内存规划在小内存环境里尤为重要,比如将中间结果在不同算子间复用,避免反复分配;
  • Relax 还能生成基于 OpenCL、Vulkan、Metal、或 WebGPU 的内核,满足移动 GPU / 浏览器端加速。

这样一来,端侧大模型(如在 iOS、Android 上跑 Llama2 7B)的解决方案更加可行:

  • 对手机而言,只要在编译期对 hidden_dim 这类较大的维度做特化,然后对 batch=1、seq_len=1 场景进行融合与调度优化,再配合 4bit/8bit 量化,就能在手机上以有限速度完成对话式推理。
  • 这对注重隐私离线场景的应用开发来说意义重大。

八、对照与总结:Relax 与其他编译器

编译器动态形状支持跨层抽象典型特点
XLA部分支持,但限制较多以静态图为主专注于 TPU 上大规模训练/推理;动态形状处理不够灵活
Relay(TVM)any-1 标记单向降级传统上更偏静态形状,对动态形状支持有限
MLIR取决于具体 Dialect无统一跨层 IR通用编译基础设施,需自行扩展和封装
PyTorch compileSymbolic shape + Inductor没有跨层共享 IR主要在 Python 端合并算子,算子级仍依赖库或生成 IR
Relax完整“符号形状”概念图级 + 算子级同层动态形状一等公民,支持可组合的降级与优化

从上表可见,Relax 的突出特征在于把“图级 IR”和“算子级 IR”统一在一个 IR 系统中,并且对动态形状的表达力很强,这使得它在应对 LLM 推理、多变输入形状、端上部署等问题时更加从容。


九、更多代码与示例

下面给出一个更细的示例,涵盖定义 TensorIR 函数图级调用、以及如何融合的大致流程,帮助大家直观理解。

9.1 定义一个自定义 ReLU 的 TensorIR 函数

@tensorir_function
def my_relu(X: Buffer((n, m), "f32"),Y: Buffer((n, m), "f32")
):# 这里 (n, m) 是符号形状for i, j in grid(n, m):with block():# 计算块Y[i, j] = max(X[i, j], 0.0)

此处 my_relu 函数描述了如何在低层循环级别执行 ReLU,用 for 循环遍历 (n, m),对每个元素做 max(0, x[i,j])。在实际生成 GPU 代码时,编译器会根据调度将这个 for-loop 分配到 GPU block/thread。

9.2 在 Relax 中图级调用

def main_fn(x: Tensor((n, 4), "f32"),w: Tensor((4, 8), "f32")) -> Tensor((n, 8), "f32"):# x shape = (n,4), w shape = (4,8)with dataflow():# 假设有一个 MatMul 的 TensorIR 函数 matmul_fnlv0: Tensor((n, 8), "f32") = call_tir(matmul_fn, [x, w], Tensor((n,8), "f32")   # 输出形状注释)# 再调用自定义 ReLUlv1: Tensor((n, 8), "f32") = call_tir(my_relu,[lv0],Tensor((n, 8), "f32"))return lv1
  • call_tir(matmul_fn, [x, w], ...) 表示调用我们编写/调度好的矩阵乘法内核;
  • 产出 (n,8) 张量后,再通过 call_tir(my_relu, [lv0], ...) 调用上面定义的 ReLU 内核;
  • Relax 保留了对 (n,4), (4,8), (n,8) 这几个形状的符号注释,可用于后续融合或内存复用分析。

9.3 融合(Fusion)演示

如果编译器发现 matmul_fnmy_relu 都是 element-wise 在输出张量 (n,8) 上执行,那么就可决定合并二者:

  1. 对于极度通用的 matmul 来说,它可能并不等同于 element-wise;但若是“matmul + scale + bias + relu”之类场景,就经常可融合。这里仅举例说明融合思路
  2. 编译器会自动生成一个 fused_matmul_relu 的 TensorIR 函数,把 matmul 的结果值在同一个 kernel 中顺便做 ReLU;
  3. 高层 IR 的 call_tir 则更新为 call_tir(fused_matmul_relu, ...),减少一次内存读写。

在实际大模型里,会出现类似“MatMul + LayerNorm + Dropout + Add”之类序列,只要编译器判定形状与数据流吻合,就能通过动态形状符号把它们合并到一个 kernel。


十、实用价值与未来展望

10.1 应对大模型时代的需求

  1. 高效的动态形状支持:对 GPT、Llama2、CodeLlama 等,需要处理可变序列长度与 KV 缓存;Relax 能做到在保持高效特化的同时,不必“人工静态化”。
  2. 端到端性能:结合自动调度、内存复用、算子融合,系统可在 GPU、移动设备等多种硬件平台上逼近甚至超越手工编写的 kernel 水平。
  3. 可移植性:同一套编译 IR + Pass,能分别生成 CUDA/OpenCL/Metal/Vulkan 等后端代码,而对模型开发者而言,则无需重复编写底层内核。

10.2 在移动端的部署场景

  • 推理加速:无须将所有中间张量写回 CPU,再转换到 GPU,而是直接在 GPU 上做融合 kernel;
  • 节省内存:动态形状感知的内存规划让“臃肿的大模型”在手机上也能艰难但可行地跑通;
  • 多分支逻辑或多模态输入:比如 NLP + CV 混合的场景,在实时 App 中可以动态切换输入大小与算子路径。

10.3 展望

Relax 还在不断演进:

  • 有研究者在探索分布式训练的拓展,让 IR 同时处理分块(sharding)后的大模型在多机集群上训练;
  • 更多稀疏化量化剪枝策略也可与 Relax IR 结合,在图级就记录稀疏模式并在 TensorIR 里利用;
  • 伴随硬件创新(如低精度算力引擎、AI ISP 管线等),Relax 也可通过自定义算子或库来快速适配。

总之,以符号形状为核心、跨层级抽象为骨架的编译体系,将会在未来支撑更灵活、更大规模的深度学习场景。


结语

通过本教程,相信读者可以初步理解:深度学习编译器为何需要在 IR 中“显式地表达”动态形状;又为何“跨层次”统一抽象如此关键Relax 在这两点上都做了深入设计,并结合了可组合优化(算子融合、内存规划、自动调度、外部库调用)的理念,形成了面向大规模、动态模型部署的强力编译体系。

在实际使用中,TVM 社区也为 Relax 提供了大量实例与工具,包括:

  • 从 PyTorch/ONNX 等前端一键导入;
  • 内部库如 cutlass、cublas、blascpu、metalLib 等的集成;
  • 针对 LLM(GPT、Llama2 等)或图像模型(ResNet、Yolo 等)的端到端示例。

读者如果对这条技术路线感兴趣,可前往 TVM 官方文档 或 Relax 社区 了解最新进展。在大模型浪潮下,让我们期待 Relax 及相关编译技术,能为更多开发者带来动态、高效、可移植的深度学习部署体验


参考与延伸阅读

  1. T. Chen et al. “TVM: An Automated End-to-End Optimizing Compiler for Deep Learning.” OSDI 2018.
  2. C. Lattner et al. “MLIR: Scaling Compiler Infrastructure for Domain Specific Computation.” CGO 2021.
  3. S. Feng et al. “TensorIR: An Abstraction for Automatic Tensorized Program Optimization.” ASPLOS 2023.
  4. L. Zheng et al. “Ansor: Generating High-Performance Tensor Programs for Deep Learning.” OSDI 2020.
  5. J. Shao et al. “Tensor Program Optimization with Probabilistic Programs.” NeurIPS 2022.
  6. G. Gerganov, “llama.cpp.” https://github.com/ggerganov/llama.cpp
  7. T. Wolf et al. “Transformers: State-of-the-Art Natural Language Processing.” EMNLP 2020.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/9643.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

计算机网络 (60)蜂窝移动通信网

一、定义与原理 蜂窝移动通信网是指将一个服务区分为若干蜂窝状相邻小区并采用频率空间复用技术的移动通信网。其原理在于,将移动通信服务区划分成许多以正六边形为基本几何图形的覆盖区域,称为蜂窝小区。每个小区设置一个基站,负责本小区内移…

17.Word:李楠-学术期刊❗【29】

目录 题目​ NO1.2.3.4.5 NO6.7.8 NO9.10.11 NO12.13.14.15 NO16 题目 NO1.2.3.4.5 另存为手动/F12Fn光标来到开头位置处→插入→封面→选择花丝→根据样例图片,对应位置填入对应文字 (手动调整即可)复制样式:开始→样式对话框→管理…

Java面试题2025-并发编程基础(多线程、锁、阻塞队列)

并发编程 一、线程的基础概念 一、基础概念 1.1 进程与线程A 什么是进程? 进程是指运行中的程序。 比如我们使用钉钉,浏览器,需要启动这个程序,操作系统会给这个程序分配一定的资源(占用内存资源)。 …

Java创建项目准备工作

新建项目 新建空项目 每一个空项目创建好后都要检查jdk版本 检查SDK和语言级别——Apply——OK 检查当前项目的Maven路径,如果已经配置好全局,就是正确路径不用管 修改项目字符集编码,将所有编码都调整为UTF-8 创建Spingboot工程 创建Spring…

2007-2020年各省国内专利申请授权量数据

2007-2020年各省国内专利申请授权量数据 1、时间:2007-2020年 2、来源:国家统计局、统计年鉴 3、指标:行政区划代码、地区名称、年份、国内专利申请授权量(项) 4、范围:31省 5、指标解释:专利是专利权的简称&…

(一)QT的简介与环境配置WIN11

目录 一、QT的概述 二、QT的下载 三、简单编程 常用快捷键 一、QT的概述 简介 Qt(发音:[kjuːt],类似“cute”)是一个跨平台的开发库,主要用于开发图形用户界面(GUI)应用程序,…

【C语言】main函数解析

一、前言 在学习编程的过程中,我们很早就接触到了main函数。在Linux系统中,当你运行一个可执行文件(例如 ./a.out)时,如果需要传入参数,就需要了解main函数的用法。本文将详细解析main函数的参数&#xff…

自创《艺术人生》浅析

艺术是生活的馈赠,艺术是苦痛的呻吟。 笔记模板由python脚本于2025-01-29 00:01:11创建,本篇笔记适合喜欢写诗读诗诵诗的coder翻阅。 【学习的细节是欢悦的历程】 博客的核心价值:在于输出思考与经验,而不仅仅是知识的简单复述。 …

二进制安卓清单 binary AndroidManifest - XCTF apk 逆向-2

XCTF 的 apk 逆向-2 题目 wp,这是一道反编译对抗题。 题目背景 AndroidManifest.xml 在开发时是文本 xml,在编译时会被 aapt 编译打包成为 binary xml。具体的格式可以参考稀土掘金 MindMac 做的类图(2014),下面的博…

AboutDialog组件的功能和用法

文章目录 1 概念介绍2 使用方法3 示例代码 我们在上一章回中介绍了AlertDialog Widget相关的内容,本章回中将介绍AboutDialog Widget.闲话休提,让我们一起Talk Flutter吧。 1 概念介绍 我们在这里说的AboutDialog是一种弹出式窗口,和上一章回中介绍的Al…

计算机网络 IP 网络层 2 (重置版)

IP的简介: IP 地址是互联网协议地址(Internet Protocol Address)的简称,是分配给连接到互联网的设备的唯一标识符,用于在网络中定位和通信。 IP编制的历史阶段: 1,分类的IP地址: …

关于产品和技术架构的思索

技术架构或者设计应该和产品设计分离,但是又不应该和产品架构独立。 听起来非常的绕并且难以理解。 下面我们用一个例子来解读这两者的关系 产品(族谱图) 如果把人类当作产品,那设计师应该是按照上面设计的(当然是正常的伦理道德)…

第十四讲 JDBC数据库

1. 什么是JDBC JDBC(Java Database Connectivity,Java数据库连接),它是一套用于执行SQL语句的Java API。应用程序可通过这套API连接到关系型数据库,并使用SQL语句来完成对数据库中数据的查询、新增、更新和删除等操作…

蓝牙技术在物联网中的应用有哪些

蓝牙技术凭借低功耗、低成本和易于部署的特性,在物联网领域广泛应用,推动了智能家居、工业、医疗、农业等多领域发展。 智能家居:在智能家居系统里,蓝牙技术连接各类设备,像智能门锁、智能灯泡、智能插座、智能窗帘等。…

Visual Studio Code修改terminal字体

个人博客地址:Visual Studio Code修改terminal字体 | 一张假钞的真实世界 默认打开中断后字体显示如下: 打开设置,搜索配置项terminal.integrated.fontFamily,修改配置为monospace。修改后效果如下:

开发环境搭建-4:WSL 配置 docker 运行环境

在 WSL 环境中构建:WSL2 (2.3.26.0) Oracle Linux 8.7 官方镜像 基本概念说明 容器技术 利用 Linux 系统的 文件系统(UnionFS)、命名空间(namespace)、权限管理(cgroup),虚拟出一…

71-《颠茄》

颠茄 颠茄,别名:野山茄、美女草、别拉多娜草,拉丁文名:Atropa belladonna L.是双子叶植物纲、茄科、颠茄属多年生草本,或因栽培为一年生,根粗壮,圆柱形。茎下部单一,带紫色&#xff…

2025 = 1^3 + 2^3 + 3^3 + 4^3 + 5^3 + 6^3 + 7^3 + 8^3 + 9^3

【算法代码】 #include <bits/stdc.h> using namespace std;int year2025; int main() {cout<<year<<" ";int i1;while(year) {cout<<i<<"^3";if(i<9) cout<<" ";year-pow(i,3);i;}return 0; }/* 202…

三天急速通关JavaWeb基础知识:Day 1 后端基础知识

三天急速通关JavaWeb基础知识&#xff1a;Day 1 后端基础知识 0 文章说明1 Http1.1 介绍1.2 通信过程1.3 报文 Message1.3.1 请求报文 Request Message1.3.2 响应报文 Response Message 2 XML2.1 介绍2.2 利用Java解析XML 3 Tomcat3.1 介绍3.2 Tomcat的安装与配置3.3 Tomcat的项…

Baklib揭示内容中台与人工智能技术的创新协同效应

内容概要 在当今信息爆炸的时代&#xff0c;内容的高效生产与分发已成为各行业竞争的关键。内容中台与人工智能技术的结合&#xff0c;为企业提供了一种新颖的解决方案&#xff0c;使得内容创造的流程更加智能化和高效化。 内容中台作为信息流动的核心&#xff0c;能够集中管…