【TVM 教程】向 Relay 中添加 Compiler Pass

【从零开始学深度学习编译器】五,TVM Relay以及Pass简介 0x0. 介绍 在前面几节的介绍中我们了解到了TVM是如何将ONNX前端模型转换为IR Module的,并且还剖析了TVM中的Relay算子和TOPI算子的扭转过程,注意Relay算子的最终计算也是基于TOPI算子集合完成的。然后我们在基于ONNX模型结构了解TVM的前端那篇文章的示例程序中还有一个很重要的细节没有介绍,即下面这几行代码: ###################################################################### # Relay Build 阅读详情

Apache TVM 是一个深度的深度学习编译框架,适用于 CPU、GPU 和各种机器学习加速芯片。更多 TVM 中文文档可访问 →https://tvm.hyper.ai/

Compiler Pass 是扩展 Relay 功能集及优化 Relay 程序的主要接口。通过编写 compiler pass,用户可以基于最终目标,修改 AST 或收集 AST 相关信息。事实上,Relay 内置的一些重要特性(如自动微分和类型推断)都“标准”的 compiler pass。

整体来看,编写 pass 包括两个关键组成部分:

  • 创建一个或多个遍历程序的 C++ 类
  • 将遍历实现及其在 pass manager API 中的元数据包装,从而方便与 Pass Infrastructure 轻松交互

首先,我们将概述编写 compiler pass 的关键机制。然后通过 Relay 中常量折叠 pass 的具体示例进行演示。

AST 遍历器(Traversers)

用于遍历 Relay 程序的基类是 ExprFunctor。它提供的公共接口是一个 VisitExpr 方法,该方法接收一个表达式以及零个或多个参数,并返回某种类型的实例。扩展此类时,可以通过覆盖每种表达式类型的 VisitExpr_ 实现,来定义 AST 遍历模式。

VisitExpr 和 VisitExpr_ 之间的关系与调度有关。每个 VisitExpr_ 定义都针对特定类型的表达式,但用户无法每次都得知要访问的节点类型。为了解决这个问题,ExprFunctor 提供了一个 VisitExpr 函数,将给定表达式路由转换为 VisitExpr_ 实例进而解决问题。尽管 C++ 已经提供了动态调度,但 ExprFunctor 定义了自己的虚表供 VisitExp 使用。通过定义虚表可以更好地控制调度。例如,定义一个在每次访问之前都打印 “Here” 的 PrintVisitor 遍历器,可以覆盖 VisitExpr:

void PrintVisitor::VisitExpr(const Expr& expr) {
  std::cout << "Here" << std::endl;
  ExprFunctor::VisitExpr(expr);
}

ExprFunctor 本身是一个非常通用的类,这就是为什么更多时候你会扩展 ExprVisitor 或 ExprMutator。这些类扩展了 ExprFunctor,并提供了 VisitExpr_ 的默认实现,这些实现捕获了每种表达式类型的常见遍历模式。有了这些默认的实现,开发者只需针对想要不同行为的表达式类型,提供覆盖的实现。后续章节将针对每个子类进行详细描述。

表达式访问器(Expression Visitors)

ExprVisitor 不用于修改程序的pass,而是用于实施程序分析和收集信息的 pass。使用这个类,VisitExpr 和私有 counterparts 不会返回任何内容。此类提供的 VisitExpr_ 实现只是访问表达式的所有表达式字段。 IfNode 的默认实现如下所示:

void ExprVisitor::VisitExpr_(const IfNode* op) {
  this->VisitExpr(op->cond);
  this->VisitExpr(op->true_branch);
  this->VisitExpr(op->false_branch);
}

注意,这里调用的是 VisitExpr 而非 VisitExpr_,因此用户可以使用 ExprFunctor 中的虚表进行路由。

如果要编写一个 CallChecker 类来检查程序中是否出现函数调用,只需扩展 ExprVisitor 并定义以下 VisitExpr_ 方法:

void VisitExpr_(const CallNode* n) final {
  result_ = true;
}

其中 result_ 是一个字段。在该示例中,无需在 CallNode 字段上进一步递归,因为 result_ 已经为 true,原始表达式中包含一个调用。为了使该访问器可用,可以采用以下方法:

bool Check(const Expr& expr) final {
  result_ = false;
  VisitExpr(expr);
  return result_;
}

以上就是全部操作。在调用 top-level 的递归之前,定义一个执行一些记录的公有接口是很常见的操作。用户也可以通过创建一个生成 CallChecker 实例,并在其上调用 Check 的独立程序来进一步包装 API,重要的是用尽可能少的资源用实现目标。

表达式修改器(Expression Mutators)

ExprMutator 用于以某种方式转换程序的 pass。通过这个类,VisitExpr 及其对应的私有部分返回 Expr。此类提供的默认 VisitExpr_ 实现访问表达式的所有表达式字段,并将字段设置为访问它们的结果。TupleGetItemNode 的默认实现如下所示:

Expr ExprMutator::VisitExpr_(const TupleGetItemNode* g) {
  auto t = this->Mutate(g->tuple);
  if (g->tuple == t) {
    return GetRef<Expr>(g);
  } else {
    return TupleGetItem(t, g->index);
  }
}

这里有几点需要注意。首先,Mutate 是 ExprMutator 中 VisitExpr 的别名。其次,如果对 Mutate 的调用修改了 tuple 字段,则只返回一个新节点。这种更新的方法称为功能更新,这样做可以避免不必要的分配。

ExprMutator 有、而 ExprVisitor 没有的一个功能,是用于缓存结果的内置 memo_ 字段。ExprMutator 有一个记忆器(memoizer)这是合理的,因为用户知道正在缓存哪些类型的结果(即 Expr),而 ExprVisitor 的访问方法不返回任何内容。通常,当用户要在 ExprVisitor 的子类中缓存结果时,需要自行定义缓存。

如果希望编写一个 IfCollapser 类,用它的真实分支替换每个 if 语句,用户将为 IfNode 覆盖 VisitExpr_:

Expr ExprMutator::VisitExpr_(const IfNode* op) {
  return this->Mutate(op->true_branch);
}

注意:返回的表达式不一定是 IfNode,这是正常的,因为返回类型是 Expr。接下来创建一个公有接口:

Expr CollapseIfs(const Expr& expr) final {
  return this->Mutate(expr);
}

虽然使用这个修改器无需做任何记录,但仍然鼓励用户将描述性方法作为接口。

示例:常量折叠

为了更好地理解编写 pass 的过程,本部分将以常量折叠 pass(可在 src/relay/transforms/fold_constant.cc 中找到)作为示例进行讲解。常量折叠 pass 相对简单,且包含两种类型的遍历。

常量折叠涉及只包含常量的程序评估表达式(evaluating expression),然后用评估它们的结果替换这些表达式。此过程的目的是预加载可以进行的所有计算。为了实现这一点,常量折叠 pass 使用了一个访问器(ConstantChecker)和一个修改器(ConstantFolder)。

ConstantChecker 访问器

此访问器用于检查表达式是否为常量。在 Relay 中,用户将 ConstantNode 或者只有常量字段的 TupleNode 的表达式定义为常量。

使用 memo_ 字段从节点映射到它们是否为常量,并缓存这些结果。下面是 ConstantChecker 中的 VisitExpr_ 定义。

void VisitExpr_(const ConstantNode* n) final {
  memo_[GetRef<Constant>(n)] = true;
}

void VisitExpr_(const TupleNode* n) final {
  bool result = true;
  for (const auto& field : n->fields) {
    if (!Check(field)) {
      result = false;
      break;
    }
  }
  memo_[GetRef<Tuple>(n)] = result;
}

用于协调这些定义的记录是一个 Check 方法,它返回给定的表达式是否被认定为常量。

bool Check(const Expr& expr) {
  const auto it = memo_.find(expr);
  if (it != memo_.end())
    return it->second;
  VisitExpr(expr);
  return memo_[expr];
}

并不是所有遇到的节点都要修改 memo_;相反,用户只有在遇到的节点有可能是常数时,才修改 memo_。当 memo_ 不包含 expr 时,需要依赖默认的 false 值。

ConstantFolder 修改器

这个修改器执行了大部分的常量折叠过程,并在内部使用 ConstantChecker。在 Relay 中,常量折叠涉及三种节点类型:LetNode、TupleItemGetNode 和 CallNode。后续段落中将进行详细讲解。

Expr VisitExpr_(const LetNode* op) final {
  Expr value = this->Mutate(op->value);
  if (value.as<ConstantNode>()) {
    memo_[op->var] = value;
    return this->Mutate(op->body);
  } else {
    Var var = Downcast<Var>(this->Mutate(op->var));
    Expr body = this->Mutate(op->body);
    if (var.same_as(op->var) &&
        value.same_as(op->value) &&
        body.same_as(op->body)) {
      return GetRef<Expr>(op);
    } else {
      return Let(var, value, body);
    }
  }
}

在 LetNode 示例里,首先尝试常量折叠绑定在表达式的值。如果可以,填充 memo_ 并返回访问主体的结果——本质上是将绑定的值传到主体中的使用点。如果无法常量折叠绑定的值,可以参照默认的实现方法:

Expr VisitExpr_(const TupleGetItemNode* op) final {
  Expr res = ExprMutator::VisitExpr_(op);
  op = res.as<TupleGetItemNode>();
  if (const auto* tuple = op->tuple.as<TupleNode>()) {
    return tuple->fields[op->index];
  } else {
    return res;
  }
}

在 TupleItemGetNode 的例子里,需要检查 op->tuple 字段是否为 TupleNode。如果是,我们将 get 元组替换为 op->index 指向的元组的字段。这样做的原因是因为 op->tuple 可能被错误评估为一个元组。

Expr VisitExpr_(const CallNode* call) final {
  static auto op_stateful = Op::GetAttrMap<TOpIsStateful>("TOpIsStateful");
  Expr res = ExprMutator::VisitExpr_(call);
  call = res.as<CallNode>();
  // 我们不使用零参数的常量折叠函数。
  // 这是一个很有用的启发式方法。
  // 例如折叠那些 shape=(4, 5) 是有害的。
  if (call->args.size() == 0) return res;
  const OpNode* op = call->op.as<OpNode>();
  if (op == nullptr) return res;
  // 跳过有状态的算子。
  if (op_stateful.get(GetRef<Op>(op), false)) return res;
  bool all_const_args = true;
  for (Expr arg : call->args) {
    if (!checker_.Check(arg)) {
      all_const_args = false;
    }
  }
  if (all_const_args) {
    return ConstEvaluate(res);
  } else {
    return res;
  }
}

在 CallNode 示例中,首先使用 ExprMutator 的 VisitExpr_ 来访问调用,它将调用的所有字段都常量折叠了。之所以使用 ExprMutator::VisitExpr_ 而不是 VisitExpr,是因为我们想要绕过虚表(以避免死循环)并使用 ExprMutator 提供的默认实现。只有当所有参数都是常量时,才评估调用(使用 ConstantChecker)。评估调用会产生一个值,因此这里使用辅助方法 ValueToExpr ,将评估的表达式放回 AST 中。

现在,我们为常量文件夹构造了一个更方便的接口 FoldConstant。FoldConstant 是 ConstantFolder 类之外的一个独立函数,它负责接收表达式并在内部创建和使用 ConstantFolder 实例(其完整的定义在 src/relay/transforms/fold_constant.cc 中)。

用 Pass Manager 注册 Pass

*注意:更多详情请参阅 Pass Infrastructure 中的文档。

编写 AST 遍历器后,用以下代码可将 pass 注册为 TVM API 端点:

namespace transform {

Pass FoldConstant() {
  runtime::TypedPackedFunc<Function(Function, Module, PassContext)> pass_func =
    [=](Function f, Module m, PassContext pc) {
      return Downcast<Function>(FoldConstant(f));
  };
  return CreateFunctionPass(pass_func, 2, "FoldConstant", {});
}

}  // 命名空间转换

将上述代码生成的 Pass 对象提供给 pass 基础架构,可以使得 AST 遍历应用于给定 Relay 模块中的所有函数,这是常量折叠过程预期的行为(它应该尽可能折叠所有常量)。

函数 CreateFunctionPass 允许注册 pass 的优化级别(在本例中为 2),可用于根据 pass 的一般实用性、 pass 名称和 pass 中的任何依赖项将 pass 组合在一起。pass 的依赖项以列表形式给出,罗列了当前 pass 运行所必需的所有 pass 的结果。FoldConstant 没有任何依赖,但是很多 Relay pass 确实依赖有类型信息,所以 InferType 是一个常见的依赖;其他的可能依赖于程序为 A-范式,通过 ToANormalForm pass。

注意,PassContext 对象包含 pass 用于错误报告和配置选项的信息; FoldConstant 不需要此信息,但其他 pass 可能会引用它们的 PassContext 对象。

现在可以通过 pass 基础结构调用 pass 了,推荐为 pass 添加 Python 绑定,如以下代码片段所示:

TVM_REGISTER_GLOBAL("relay._transform.FoldConstant")
.set_body_typed(FoldConstant);

通过以上方法定义了 Pass 对象后,就可以用 pass 基础架构的 Sequential 结构来调用了。 Sequential 接收一个 pass 列表,并将其按顺序应用于 Relay 模块,从而获得转换后的模块。例如,下面的代码将 FoldConstant 和 ToANormalForm pass 逐一应用于 mod 中的每个函数,并获得一个新模块。

seq = transform.Sequential([
    relay.transform.FoldConstant(),
    relay.transform.ToANormalForm()
])
new_mod = seq(mod)

更多注册相关的内容,请查看 TVM Runtime 系统;pass 管理器接口相关的更多信息,请查看 Pass 基础架构; Relay 的标准 pass 列表及实现方式,请分别查看 include/tvm/relay/transform.h 及 src/relay/transforms/。

在RISC-V开发板上跑通ResNet-18:用TVM搞定模型交叉编译与NPU部署的完整流程 本文详细介绍了如何在RISC-V开发板上使用TVM工具链实现ResNet-18模型的交叉编译与NPU部署。从环境准备、模型量化到异构加速配置,提供了完整的实战流程和常见问题解决方案,帮助开发者在资源受限的嵌入式设备上高效运行AI模型。 阅读详情

相关推荐

面向具身智能的通用AI编译器:从模型到异构硬件的实战部署指南

AI编译器是连接深度学习模型与底层硬件执行的关键技术,其核心原理在于将高级计算图转换为针对特定硬件优化的低级代码。通过计算图优化、算子融合和硬件感知调度,AI编译器能显著提升模型推理效率并降低资源消耗,这对于嵌入式系统和边缘计算场景具有重要技术价值。在机器人、自动驾驶等具身智能领域,面对异构硬件和实时性要求,通用AI编译器的作用尤为突出。本文以TVM为例,结合多模态大模型和算法流水线等热词,深入解析如何利用编译器技术解决从算法到硬件的部署难题,为复杂AI系统的工程化落地提供实践思路。

weixin_34323858的博客 427

TVM 实践指南:向 Relay 框架添加自定义 Compiler Pass 的完整流程

摘要:本文详细介绍了TVM深度学习编译器中Relay中间表示层自定义CompilerPass的开发方法。文章从RelayCompilerPass的架构解析入手,阐明其函数级和模块级Pass的分层设计及注册机制。通过代码示例展示了自定义Pass的核心开发流程,包括IR遍历、模式匹配、节点转换等关键技术,并以Conv2D-BatchNorm融合为例演示具体实现。最后探讨了Pass的调试、性能评估及集成优化最佳实践,为开发者提供了TVM中间表示优化的完整技术指南。

jingpide9527的博客 835

深度学习编译器测试:OATest框架解析与实践

深度学习编译器作为AI模型部署的核心组件,其优化质量直接影响推理性能与可靠性。编译器测试面临上下文依赖性强、模式化特征明显等挑战,传统随机测试方法难以有效覆盖优化路径。OATest创新性地采用模式提取与上下文合成技术,通过动态插桩捕获TVM/ONNXRuntime等框架的优化触发条件,结合计算图合成生成高覆盖率测试用例。该框架在优化错误检测率上显著优于NNSmith等工具,特别擅长发现逻辑错误和类型系统问题等隐蔽缺陷。工程实践中,OATest可集成到CI/CD流程,通过模式迁移和强化学习持续提升测试效果,为

weixin_30700977的博客 384

TVM Compiler中文教程:TVM.Relay使用外部库

文章目录TVM.Relay中使用外部库创建一个简单的网络使用cuda后端构建和运行卷积层使用cuDNN实现验证结果结论 TVM.Relay中使用外部库 这篇教程介绍怎么在Relay中使用cuDNN、cuBlas这样的外部库。 Relay在内部使用TVM生成特定目标的代码。例如,使用cuda作为后端,TVM为用户提供的网络生成所有层的cuda kernel代码。但是有时,将设备厂商提供的外部库合并到...

Mars_WH的专栏 3913

基于Buddy-MLIR的DeepSeekR1模型编译与优化实战

在AI模型部署领域,编译器技术是实现算法到硬件高效执行的关键桥梁。MLIR(多级中间表示)作为下一代编译器基础设施,通过分层抽象和渐进式Lowering机制,将高级框架算子逐步转换为底层硬件指令,解决了传统编译器在AI领域面临的碎片化问题。其核心价值在于提供了统一的中间表示和优化管道,使得跨硬件平台的性能调优成为可能。在工程实践中,开发者可以利用MLIR进行循环融合、平铺、向量化等高级优化,显著提升计算密集型和内存密集型任务在CPU、GPU等硬件上的执行效率。本文以DeepSeekR1大语言模型为例,详细展

weixin_33725515的博客 446

【信息科学与工程学】计算机科学与自动化——第二十四篇 编译器10——编译原理与词法分析02

链接时优化:全局DCE(579)、LTO(580)安全编译:CFI(581、586)、ASan(582)、UBSan(583)、MSan(584)、TSan(585)、CET(587)、PAC(588)、MTE(589)、SFI(590)、Wasm沙箱(591)侧信道与秘密:侧信道缓解(592)、常量时间(593)、秘密清理(594)内存安全:ASLR(595)、栈保护(596)、整数溢出检测(597)、除零检测(598)、空指针检测(599)、数组边界检查(600)至此编号达到600。

weixin_49199313的博客 195

TVM Relax深度解析:从程序抽象到动态形状与多后端混编

在深度学习编译器领域,计算图的中间表示(IR)决定了优化能力的上限。传统图IR如Relay擅长表达静态的算子依赖关系,但在内存分配、控制流和动态形状等“执行语义”层面存在明显短板。TVM Relax的提出,正是将抽象层级从“数据流图”升级为带执行语义的“程序表示”,让编译器能显式处理内存生命周期、设备切换和运行时函数调用。它通过DataflowBlock保证无副作用优化,结合ShapeExpr实现动态维度推理,并借助call_packed实现多后端无缝混编。这项技术不仅适用于静态网络部署,更支撑起动态bat

weixin_34199405的博客 405

SpringBoot+Vue+Mysql社区医院信息平台(源码+文档)

SpringBoot+Vue+Mysql学生宿舍信息管理系统 WEB端软件项目(源码+文档) 项目包含:①完整源码(后端+管理后台+用户前台);②数据库脚本文件;③万字论文文档;④开题报告;⑤答辩PPT;⑥项目运行视频教程。 项目架构: B/S 架构、MVC 分层设计 技术栈: Java、MySQL、SpringBoot、MyBatis-Plus、Token 权限校验、管理后台 Vue+ElementUI+ECharts、用户前台 Layui+jQuery、Maven 构建。 一、角色设计 学生用户: 注册登录、浏览宿舍信息、查询宿舍安排、在线报修、缴费查询、失物招领、桶装水预订、评论交流、收藏等。 商家用户: 注册登录、桶装水品牌与商品信息维护、预订订单查看与处理。 维修人员: 注册登录、查看待处理报修、接单维修、填写报修处理结果与进度反馈。 管理员: 学生管理、班级管理、宿舍信息管理、宿舍安排管理、报修处理管理、缴费信息管理、卫生检查与文明宿舍管理、失物招领管理、桶装水与商家管理、维修人员管理、公告资讯与轮播图管理等。 二、前台功能模块(学生端) 1. 首页展示:轮播图、宿舍公告、最新动态推荐、常用服务快速入口 2. 宿舍信息模块:宿舍列表、楼栋与房间条件筛选、宿舍详情查看、我的宿舍安排查询 3. 在线报修模块:在线提交宿舍设施报修申请、上传故障描述、查看报修进度与维修处理结果 4. 缴费模块:水电等缴费记录查询、缴费状态查看 5. 卫生检查与文明宿舍:宿舍卫生检查结果公示、文明宿舍展示 6. 失物招领模块:失物信息发布、招领信息发布、详情查看、评论互动 7. 桶装水预订:桶装水品牌与商品浏览、在线预订、我的预订记录查询 8. 假期留宿:假期留校申请提交、申请记录查询 9. 评论与收藏:信息评论、查看他人评论、评论回复互动、收藏感兴趣的内容 10. 个人中心...

MXNet架构解析:从符号图到Graph Runtime的确定性设计

深度学习框架的核心价值不仅在于模型训练能力,更在于推理部署阶段的确定性、资源可控性与跨平台可预测性。MXNet通过符号式与命令式混合执行模型、带类型推导的静态计算图、以及深度定制的Graph Runtime,在内存规划、算子融合、异构调度等底层机制上实现毫秒级延迟与零抖动性能。其架构天然支持梯度压缩、弹性容错与ONNX无损导出,成为高SLA要求场景下分布式训练与边缘AI部署的关键技术选型。本文深入解析MXNet的Architecture设计原理及其在Distributed Training和Producti

weixin_30718391的博客 337

YOLOv8作物病害检测实战源码

这是一套基于YOLOv8n的农田病虫害目标检测系统,对叶片照片做目标检测,识别健康叶片、褐斑病、白粉病、锈病四类,并给出对应防治建议。全流程纯CPU可跑,配套交付完整Python源码、9章实战教程(md/html/pdf三种格式)、100张自造样本及YOLO标签、训练曲线与混淆矩阵截图、Tkinter界面和答辩PPT。 系统围绕五项功能展开:同一套推理逻辑覆盖图像、视频、摄像头三种来源;图形界面选文件即检测,画面叠彩色框标注病名与置信度,右侧面板同步给出症状与防治措施;检测记录自动写入CSV,统计页一键生成四类病害占比饼图;训练结束自动产出损失与精度曲线;内置防治建议文案库,检测命中即回填面板。 选型用YOLOv8n nano档,参数量约320万、权重约6.2MB,CPU单帧几十毫秒,小样本训练5到8分钟完成。数据由data_gen.py程序化绘制100张叶片图,固定随机种子,重跑分布一致,不依赖公开数据集。依赖全部锁版本,教程第7章整理了19条真实报错及排查方法,第8章给出换模型档、换PlantVillage数据集的迁移路径。 适合做计算机视觉方向课程设计或毕业设计的学生,也适合智慧农业方向想了解检测模型如何落进业务面板的学习者。不需要GPU,不需要系统学过目标检测,教程第3章会按需补齐原理。 使用时先pip install -r requirements.txt装好依赖,download_data.py下载预训练权重,data_gen.py生成样本后train.py训练,完成后用main.py infer批量检测或main.py gui启动界面。

数据挖掘实战:决策树 + 聚类 + 关联规则,零 Key 离线可跑(Python 源码)

数据挖掘实战包。用 Python 标准库实现 CART 风格决策树、K-Means 聚类与 Apriori 关联规则,在虚构「星河便利店」会员表和购物篮上跑通分类、分群与购物篮分析,并给出准确率、轮廓系数、支持度/置信度/提升度。零第三方依赖、零 API Key 即可离线跑通。含 4 个样例、离线冒烟、中文 README(含「使用方法」)。均为作者原创可运行源码。MIT。作者 blog.youkuaiyun.com/mtl1994

AI工程加速:五类加速器协同优化实战指南

AI加速并非单纯升级GPU或更换框架,而是一个覆盖硬件、平台、框架、编译器与云服务的系统性工程问题。其核心原理在于各层之间的嵌套依赖与生命周期协同——例如CUDA驱动版本必须匹配XLA编译器Pass,而后者又依赖云服务实例的AMI镜像支持。这种跨栈耦合决定了单点优化存在明显天花板,唯有纵向深度适配(如TensorRT针对Orin芯片的手动shape调优)与横向流程闭环(如将模型契约前置到训练阶段)才能释放真实性能价值。典型应用场景包括低延迟推理服务优化、大模型训练Pipeline提速及边缘AI功耗控制等。本

weixin_30872337的博客 400

科技中介服务机构在技术供需对接中如何实现服务流程的自动化与标准化?.docx

科技中介服务机构在技术供需对接中如何实现服务流程的自动化与标准化?

MLIR生产化、C++26 ABI绑定与ThinLTO强制化:LLVMCon 2025三大工程拐点

MLIR已从研究型中间表示演进为芯片级AI编译基础设施,其分层Dialect设计、可组合Pass机制和细粒度副作用建模(如SideEffectResource)显著提升编译效率与错误定位能力;与此同时,Clang对C++26的支持转向ABI原子性绑定,放弃渐进式feature flag,强制耦合libc++26以保障二进制兼容性;而LTO架构完成分布式重构,ThinLTO成为链接时IR拓扑分析的强制前置阶段,并引入跨云缓存一致性协议。这三大动向共同指向一个事实:现代编译器基础设施正从‘功能可用’全面迈入‘工

civtsbiqr522632413的博客 409

产业园区如何高效对接企业技术需求与高校科研成果?.docx

科易网基于AI模型+行业大数据,在技术转移、成果转化、技术经纪、知识产权、产业创新、科技招商等垂直领域的多样化应用场景,推出科技创新领域的AI+工具与数智化解决方案,推动科技创新与产业创新智能化发展。

国央企创新负责人如何快速掌握本地科技资源分布与匹配情况?.docx

科易网基于AI模型+行业大数据,在技术转移、成果转化、技术经纪、知识产权、产业创新、科技招商等垂直领域的多样化应用场景,推出科技创新领域的AI+工具与数智化解决方案,推动科技创新与产业创新智能化发展。

高校技术转移办公室人员如何系统化管理科技成果信息?.docx

科易网基于AI模型+行业大数据,在技术转移、成果转化、技术经纪、知识产权、产业创新、科技招商等垂直领域的多样化应用场景,推出科技创新领域的AI+工具与数智化解决方案,推动科技创新与产业创新智能化发展。

国央企创新负责人如何实现科技成果的精准识别与高效筛选?.docx

科易网基于AI模型+行业大数据,在技术转移、成果转化、技术经纪、知识产权、产业创新、科技招商等垂直领域的多样化应用场景,推出科技创新领域的AI+工具与数智化解决方案,推动科技创新与产业创新智能化发展。

上一篇: 覆盖近 1.5 万个物种,谷歌 DeepMind 发布 Perch 2.0,刷新生物声学分类检测 SOTA
下一篇: 【Triton 教程】triton_language.expand_dims
HyperAI超神经
博客等级 码龄7年 8872粉丝 1753原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值