探索 TT-Metal:Tenstorrent 的 low-level 开发软件栈

介绍

TT-Metal 全称 TT Metalium,是一个面向异构 CPU 和 Tenstorrent 设备集合的底层软件平台,它使用户能够直接访问 RISC-V 处理器、片上网络(NoC),以及 Tensix Core 中的矩阵和向量计算引擎。对于那些希望定制模型、开发新模型,甚至执行非机器学习代码的开发人员来说,TT-Metal 提供了极大的灵活性。平台中没有任何黑盒操作、加密的 API 或隐藏的功能,确保了开发过程的透明性和可控性。

TT-Metal 整体架构

下图展示了Tenstorrent 基于 TT-Metal 构建的软件栈。通过 TT-Metal,开发者可以编写主机驱动程序和核函数,用以实现特定的数学运算(例如,矩阵乘法、图像缩放等),然后将它们打包成库。使用这些库作为构建模块,框架为用户提供了一个灵活的高级环境,用户可以在其中开发各种高性能计算(HPC)和机器学习(ML)应用程序。

TT-Metal 编程模式

异构 AI 加速器编程模式

在异构 AI 加速器的编程中,我们通常会区分两种核心接口:Host 接口和 Device 接口。这种区分对于编程流程至关重要,每种接口承担着不同的职责,并在各自的执行环境中发挥作用。

  • Host 接口:

    • 定义:Host 接口主要负责主机端(CPU)的内存管理、资源分配、任务调度和数据传输等操作。

    • 功能:处理与设备(如 GPU 或其他 AI 加速器)的通信,包括数据的发送和接收,以及确保数据在 Host 和 Device 之间安全、高效地移动。

  • Device 接口:

    • 定义:Device 接口则专注于在设备端执行实际的计算任务,即执行核函数(Kernel)。

    • 功能:它直接与硬件交互,利用设备的计算能力来加速 AI 算法和处理数据。

  • 编程模式:

    • 内存管理:通过 Host 接口管理 Host 和 Device 的内存。

    • 数据准备:在 Host 端准备输入数据,并使用 Host 接口将其传输到 Device 内存。

    • 内核配置:在 Device 端配置计算内核的参数和执行环境。

    • 执行计算:通过 Device 接口启动计算内核,执行并行计算任务。

    • 数据同步:确保计算结果从 Device 同步回 Host,可能涉及等待设备完成计算。

    • 结果处理:在 Host 端接收结果数据,并进行后续处理或分析。

TT-Metal 编程模式

TT-Metal 基本上遵循了异构 AI 加速器的编程模式,尽管在硬件细节上存在少许差异 (主要表现在核函数的调用上).

在深入探讨 TT-Metal 的编程模式之前,我们首先需要回顾一下相关的硬件基础知识。

Tenstorrent 硬件架构

如上图所示,Grayskull(Wormhole)是一个由 Tensix 核心构成的网状结构,每个 Tensix 核心配备了五个独立的 RISC-V 小型核心。其中,CPU1 和 CPU5 负责管理 NOC(网络芯片)硬件以实现数据传输,而 CPU2、CPU3 和 CPU4 则承担计算任务。

内存架构

Tenstorrent 内存架构分为两层,所有 Tensix core 共享的 DRAM,以及每个 Tensix core 独享的 SRAM。后文提及的 DRAM buffer 和 SRAM buffer 指的是从共享的 DRAM 和独享的 SRAM 分配的 buffer。

TT-Metal 核函数

在 TT-Metal 架构中,每个 RISC-V CPU 都需要通过手动编写核函数来实现控制。核函数根据其功能被划分为以下几类:

  • Data movement kernel:负责数据的传输,具体分为两种类型:

    • Reader kernel:从 Buffer(Buffer 是 DRAM buffer 或者其他 Tensix core 的 SRAM buffer) 读取数据到本地 SRAM。

    • Writer kernel:将数据从本地 SRAM 写入回 Buffer。

  • Compute kernel:负责执行实际的计算任务。

如下图所示,TT-Metal 的核函数调用构建了一个 pipeline,由 Reader kernel、Compute kernel 和 Writer kernel 组成。这个 pipeline 的工作流程是:Reader kernel 首先从 Buffer 提取数据到本地 SRAM,然后 Compute kernel 对数据进行处理,最后 Writer kernel 将结果数据写回 Buffer。

Compute 占用的三个 riscv cpu 分工如下:

  • CPU2:UNPACK 将数据从 SRAM Buffer 拷贝到寄存器 SrcA、SrcB(源寄存器,如下图绿色部分所示)

  • CPU3:调用 Matrix & Vector engines 进行计算

  • CPU4:PACK 将数据从寄存器 dst(目标寄存器) 拷贝到 SRAM Buffer

关于更多关于 Tensix core 的细节见前文 Tenstorrent数据流芯片Grayskull 和 Wormhole解析

TT-Metal 示例分析

一个典型 tt-metal 简单程序的目录结构如下所示:

example
├── CMakeLists.txt
├── kernels
│   ├── reader.cpp   # Reader kernel
│   ├── compute.cpp  # Compute kernel
│   └── writer.cpp   # Writer kernel
└── example.cpp      # host driver

Kernels 和 host 均使用 C++ 进行开发,并且支持到 C++20 标准。开发过程中,通过 TT-Metal host & device api 来实现数据传输和计算。接下来,我们将通过一个简单的示例程序——矩阵乘法(matmul)——来分析这些 API 的使用。

host driver

以下是 TT-Metal 单核矩阵乘示例 host driver 代码的简化版本。

Device *device = CreateDevice(device_id);
CommandQueue& cq = device->command_queue();
Program program{};
CoreRange core({0, 0}, {0, 0});
// create dram & sram buffer
auto src0_dram_buffer = CreateBuffer(dram_config_A);
auto src1_dram_buffer = CreateBuffer(dram_config_B);
auto dst_dram_buffer  = CreateBuffer(dram_config_C);
auto cb_src0 = CreateCircularBuffer(program, core, cb_src0_config);
auto cb_src1 = CreateCircularBuffer(program, core, cb_src1_config);
auto cb_output = CreateCircularBuffer(program, core, cb_output_config);

// create kernels
auto reader_id = CreateKernel(
    program,
    "kernels/dataflow/reader_bmm_8bank.cpp",
    core,
    tt_metal::DataMovementConfig{.processor = DataMovementProcessor::RISCV_1, .noc = NOC::RISCV_1_default, .compile_args = reader_compile_time_args});

auto writer_id = CreateKernel(
    program,
    "kernels/dataflow/writer_bmm_8bank.cpp",
    core,
    tt_metal::DataMovementConfig{.processor = DataMovementProcessor::RISCV_0, .noc = NOC::RISCV_0_default, .compile_args = writer_compile_time_args});

auto matmul_single_core_kernel_id = CreateKernel(
    program,
    "kernels/compute/bmm.cpp",
    core,
    tt_metal::ComputeConfig{.math_fidelity = math_fidelity, .compile_args = compute_args}
);

// pass arguments
tt_metal::SetRuntimeArgs(
    program, reader_id, core,
    {src0_addr, src1_addr, Mt, Kt, Nt, Mt*Kt, Kt*Nt, B, uint32_t(bcast_batch ? 1 : 0)}
);

tt_metal::SetRuntimeArgs(
    program, writer_id, core,
    {dst_addr, 0, Mt, Kt, Nt, Mt*Kt, Kt*Nt, B}
    
// enqueue data and program
EnqueueWriteBuffer(cq, src0_dram_buffer, a.data(), false);
EnqueueWriteBuffer(cq, src1_dram_buffer, b.data(), false);
EnqueueProgram(cq, program, false);
EnqueueReadBuffer(cq, dst_dram_buffer, output.data(), true);
CloseDevice(device);

代码可以分为几个部分:

  • 初始化设备和关闭:CreateDevice、CloseDevice

  • 分配内存

    • CreateBuffer – 创建 DRAM buffer

    • CreateCircularBuffer – 创建 SRAM 环形队列(circular buffer,简称 cb,后文接口中以 cb_ 开头的字符都与 circular buffer 有关)

  • 创建 kernel:CreateKernel,具体 kernel 的实现在外部文件中

    • reader_bmm_8bank.cpp – Reader kernel

    • writer_bmm_8bank.cpp – Writer kernel

    • bmm.cpp – Compute kernel

  • 参数传递:SetRuntimeArgs

  • 编译和加载:EnqueueProgram

其中,CoreRange core({0, 0}, {0, 0}) 代表了使用的核,由第一个核的坐标和最后一个核的坐标组成,在此表示使用一个核,坐标是 {0, 0}。

Data movement kernel

以下是单核矩阵乘示例 Reader kernel 代码的简化版本。

// src0
const InterleavedAddrGenFast<src0_is_dram> s0 = {
    .bank_base_address = src0_addr,
    .page_size = src0_tile_bytes,
    .data_format = src0_data_format
};
cb_reserve_back(cb_id_in0, onetile);
uint32_t l1_write_addr_in0 = get_write_ptr(cb_id_in0);
noc_async_read_tile(itileA, s0, l1_write_addr_in0);
noc_async_read_barrier();
cb_push_back(cb_id_in0, onetile);

主要使用了 circular bufferdata movement 相关的 api。circular buffer 是基于 tile 的 FIFO 队列,它通过两个指针来追踪 buffer 的当前位置。在 Tenstorrent 的设计中,数据传输和计算都是以 tile 为单位进行的,因此 kernel API 大多是针对 tile 来设计的。

src0_addr 是作为参数传入的,它代表 DRAM buffer 的地址。cb_id_in0 是 circular buffer 的索引,利用它可以获取 circular buffer 的地址。

  • cb_reserve_back – 在 circular buffer 中申请一个空闲的 tile

  • get_write_ptr – 通过 circular buffer index 获取 SRAM address

  • noc_async_read_tile – 从 DRAM buffer 传输一个 tile 到 SRAM buffer 中

  • noc_async_read_barrier – 等待 tile 传输完毕

  • cb_push_back – 将传输完毕的 tile push 到队列中(实际上会移动 circular buffer 的指针)

由此可知,Reader/Writer kernel 的主要功能是将数据在外部 buffer(如 DRAM 或其他 Tensix 的 SRAM)与本地 SRAM buffer 之间进行基于 tile 的传输。

Compute kernel

以下是单核矩阵乘示例 Compute kernel 代码的简化版本。

mm_init();

acquire_dst(tt::DstMode::Full);
cb_wait_front(tt::CB::c_in0, onetile);
cb_wait_front(tt::CB::c_in1, onetile);

matmul_tiles(tt::CB::c_in0, tt::CB::c_in1, 0, 0, 0, false);

cb_pop_front(tt::CB::c_in0, onetile);
cb_pop_front(tt::CB::c_in1, onetile);

cb_reserve_back(tt::CB::c_out0, onetile);
pack_tile(0, tt::CB::c_out0);
cb_push_back(tt::CB::c_out0, onetile);

release_dst(tt::DstMode::Full);
void matmul_tiles(uint32_t in0_cb_id, uint32_t in1_cb_id, uint32_t in0_tile_index, uint32_t in1_tile_index, uint32_t idst, const uint32_t transpose) {
    UNPACK(( llk_unpack_AB_matmul(in0_cb_id, in1_cb_id, in0_tile_index, in1_tile_index) ));
    MATH(( llk_math_matmul<MATH_FIDELITY>(idst, transpose)  ));
}
  • mm_init – matmul kernel 封装的函数,主要实现一些初始化

  • acquire_dst、release_dst – 申请和释放 dst 寄存器,dst 寄存器会用于保存 matmul 的结果

  • matmul_tiles – 将数据从 circular buffer 拷贝到 SrcA 和 SrcB 寄存器,然后调用 FPU 指令执行 matmul 计算,结果保存在 dst 寄存器

  • pack_tile – 将数据从 dst 寄存器拷贝到 circular buffer

  • cb_wait_front、cb_pop_front、cb_reserve_back、cb_push_back – cb 操作

可以看到,最终通过调用 Low level kernel 接口来执行计算任务,LLK 相关细节见前文算子的从上而下映射:从算子到自定义指令

TT-NN

TT-NN 库是专为 Tenstorrent 硬件设计的高级库,用于运行 AI 模型。它基于 TT-Metal API 进行封装,提供了一系列高效的算子,类似于 NVIDIA 硬件上的 cublas(高级线性代数库)。利用 TT-NN 库,用户可以轻松地在 Tenstorrent 硬件上开发和部署 AI 模型,无需直接与底层硬件接口打交道。

TT-NN Operation 列表

TT-NN operation 是用 C++ 实现的一种函数,它封装了 Python 接口供用户使用。这种操作的输入和输出通常是一个或多个 tensor。

Category Operations
Core as_tensor, from_torch, to_torch, to_device, from_device, to_layout, dump_tensor, load_tensor, deallocate, reallocate, to_memory_config
Tensor Creation arange, empty, zeros, zeros_like, ones, ones_like, full, full_like
Matrix Multiplication matmul, linear
Pointwise Unary abs, acos, acosh, asin, asinh, atan, atan2, atanh, bitwise_and, bitwise_or, bitwise_xor, bitwise_not, bitwise_left_shift, bitwise_right_shift, cbrt, celu, clip, clone, cos, cosh, deg2rad, digamma, elu, erf, erfc, erfinv, exp, exp2, expm1, floor, ceil, geglu, gelu, glu, hardshrink, hardsigmoid, hardswish, hardtanh, heaviside, hypot, i0, identity, isfinite, isinf, isnan, isneginf, isposinf, leaky_relu, lerp, lgamma, log, log10, log1p, log2, log_sigmoid, logical_not, logit, mish, multigammaln, neg, prelu, reglu, relu, relu_max, relu_min, relu6, remainder, rsqrt, rdiv, rsub, sigmoid, sigmoid_accurate, sign, silu, sin, sinh, softmax, softplus, softshrink, softsign, swish, tan, tanh, signbit, polygamma, rad2deg, reciprocal, sqrt, square, swiglu, tril, triu, tanhshrink, threshold
Pointwise Binary add, multiply, subtract, pow, ldexp, logical_and, logical_or, logical_xor, logaddexp, logaddexp2, xlogy, squared_difference, gtz, ltz, gez, lez, nez, eqz, gt, ge, lt, le, eq, ne, isclose, polyval, nextafter, maximum, minimum, atan2_bw, embedding_bw, addalpha_bw, subalpha_bw, xlogy_bw, hypot_bw, ldexp_bw, logaddexp_bw, logaddexp2_bw, squared_difference_bw, concat_bw, rsub_bw, min_bw, max_bw, lerp_bw
Pointwise Ternary addcdiv, addcmul, mac, where, addcmul_bw, addcdiv_bw, where_bw
Losses l1_loss, mse_loss
Reduction max, mean, min, std, sum, var, argmax, topk
Data Movement concat, pad, permute, reshape, repeat, repeat_interleave
Normalization group_norm, layer_norm, rms_norm
Transformer split_query_key_value_and_split_heads, concatenate_heads, attention_softmax, attention_softmax_, rotary_embedding
Embedding embedding
Pooling global_avg_pool2d, MaxPool2d
Vision upsample
KV Cache fill_cache_for_user_, update_cache_for_token_

TT-NN Operation 的实现

TT-NN Operation 分为 HostOperation、DeviceOperation、ExternalOperation 三种,可以将这三个视为基类(虽然在实现上并没有继承关系),当需要新增一个 Operation 时,需要实现一个类,这个类需要包含一些固定的函数,如下图所示的 compute_output_shapes、create_output_tensors、create_program 等,其中最重要的逻辑在 create_program 中实现。

观察 struct Convcreate_program 源码,其实现机制与上文中提到的 matmul 算子的 driver 类似。Conv 算子的目录结构如下图所示,其中 *conv_op.cpp 是 driver 部分,而 kernels 文件夹包含了 Reader kernel、Compute kernel 和 Writer kernel。与上文提到的 matmul 实现对比,Conv Operation 的输入和输出是 Tensor,所以输入输出数据需要在 Tensor 和 tile 之间进行转换处理。

使用 C++ 实现 Operation 后,需要调用 ttnn::register_operation 函数来注册 Operation。注册完成后,通过 pybinding 提供 Python 接口,这样用户层就可以方便地使用这些 Operation 了。

Softmax 在 TTNN 上实现

TTNN softmax operation 源码目录结构如下:

其中,softmax_op.cpp 文件是其入口文件,实现了 create_program 函数,对接 TTNN 库的架构。softmax_op_multi_core.cpp 文件是其 driver 文件,负责创建 buffer 和 kernel 并传递参数。compute & dataflow 目录则是其 compute kernel & data movement kernel 位置所在。

可以看出,TTNN operation 的实现方式和手动调用 TT-Metal 实现算子是一样的。

void scale_mask_softmax_multi_core {
    Program program = CreateProgram();
    auto [num_cores, all_cores, core_group_1, core_group_2, num_tile_rows_per_core_group_1, num_tile_rows_per_core_group_2] 
     = tt::tt_metal::split_work_to_cores(grid_size, num_tile_rows, true);
    ...
    CreateCircularBuffer(..);
    ...
    softmax_kernels_id = createKernel(...);
    reader_kernels_id = createKernel(...);
    writer_kernels_id = createKernel(...);
    ...
    for (auto i = 0; i < num_cores, ++i) {
        // set kernel core id
        // split input data
    }
    auto override_runtime_arguments_callback = [](){...}
    return program, override_runtime_arguments_callback
}

Driver 的简化逻辑如上所示:会根据物理核心的数量和数据的大小决定使用核心的数量,并且根据 num_cores 划分数据。

Softmax 的 compute kernel 实现和单核 matmul 类似,区别在于,softmax 有多个 circle buffer 存放中间数据,多个算子顺序执行,数据多次在 src0, src1, dst 和 circle buffer 之间移动。(参考文件:tt-metal/ttnn/cpp/ttnn/operations/normalization/softmax/device/kernels/compute/softmax.cpp)

对比于 TT-Buda 的 softmax,Netlist 部分如下所示:

  softmax_single_tile:
    target_device: 0
    input_count: 1
    exp:   {type: exp,        grid_loc: [0, 0], grid_size: [1, 1], inputs: [input_activation   ], t: 1, mblock: [1, 1], ublock: [1, 1], in_df: [Float16_b],            acc_df: Float16, out_df: Float16_b, intermed_df: Float16_b, ublock_order: r, buf_size_mb: 2, math_fidelity: HiFi3}
    sum:   {type: matmul,     grid_loc: [0, 1], grid_size: [1, 1], inputs: [exp, input_constant], t: 1, mblock: [1, 1], ublock: [1, 1], in_df: [Float16_b, Float16_b], acc_df: Float16, out_df: Float16_b, intermed_df: Float16_b, ublock_order: r, buf_size_mb: 2, math_fidelity: HiFi3, attributes: {m_k: 1, u_kt: 1}}
    recip: {type: reciprocal, grid_loc: [0, 2], grid_size: [1, 1], inputs: [sum                ], t: 1, mblock: [1, 1], ublock: [1, 1], in_df: [Float16_b],            acc_df: Float16, out_df: Float16_b, intermed_df: Float16_b, ublock_order: r, buf_size_mb: 2, math_fidelity: HiFi3}
    mult:  {type: multiply,   grid_loc: [0, 3], grid_size: [1, 1], inputs: [exp, recip         ], t: 1, mblock: [1, 1], ublock: [1, 1], in_df: [Float16_b, Float16_b], acc_df: Float16, out_df: Float16_b, intermed_df: Float16_b, ublock_order: r, buf_size_mb: 2, math_fidelity: HiFi3}

可以看出 softmax 由四个算子组成,使用了四个 core,数据在四个 core 之间流动。而 TTNN 的 softmax 则是将数据进行切分,在多个 core 上并行处理数据,并不是 dataflow 的形式。

每个 TTNN 的 op 都会重新分配 tensix core,单个 op 内部可以通过 data movement kernel 进行数据传输(手动管理),执行的时候,需要再执行完一个 TTNN op 之后,才可以执行下一个。

理论上,可以将模型封装成一个 TTNN op 的形式,手动分配 tensix core,并进行数据移动的管理,但是复杂度过大。如果只是使用现有的 TTNN op 去实现模型,模型并不是以 dataflow 的形式运行的,而且 op by op 的执行方式很难发挥出芯片的性能。

TT-NN 示例

以下是使用 TT-NN 库,在设备上运行 exp 操作的示例:

import torch
import ttnn
device_id = 0
device = ttnn.open_device(device_id=device_id) # 打开设备
torch_input_tensor = torch.rand(2, 4, dtype=torch.float32) # 生成数据
input_tensor = ttnn.from_torch(torch_input_tensor, dtype=ttnn.bfloat16, layout=ttnn.TILE_LAYOUT, device=device) # 转换 tensor 格式
output_tensor = ttnn.exp(input_tensor) # 计算
torch_output_tensor = ttnn.to_torch(output_tensor) # 转换 tensor 格式
ttnn.close_device(device) # 关闭设备

如上所示,用户只需调用 TT-NN 库提供的接口,便能完成算子的执行。这种方法确实比直接使用 TT-Metal API 手写 driver 和三个 kernel 要简化许多。在 Tenstorrent 的架构中,计算和数据传输都是基于 tile 的方式进行。AI 模型通常使用 tensor 作为数据结构,为了便于对 tensor 进行切割和填充以适应 tiled-base 的处理,ttnn 定义了自己的 tensor 类型。Operations 默认使用 ttnn.tensor,因此在实际使用过程中,需要在 ttnn.tensor 和 PyTorch 的 torch.tensor 之间进行转换,以确保数据能够正确地在 Tenstorrent 硬件上执行计算。

AI 模型的支持

前文提到,tt-buda 支持模型的方式是通过将现有模型进行转换来实现的。而在使用 TT-Metal 的情况下,开发者则需要手动完成一些额外的工作。

模型支持的方式

TT-NN 的设计借鉴了 PyTorch 的接口风格,这为模型支持提供了一种思路,即从 PyTorch 模型出发,逐步替换为 TT-NN operation。以下是实现这一思路的具体步骤:

  1. 重写 PyTorch 模型:首先使用 PyTorch 的 functional API 将模型重写,确保模型的表达式是函数式的,这有助于后续的替换工作。

  2. 替换为 TT-NN operations:接着,将重写后的 PyTorch 模型中的 function API 逐步替换为 TT-NN 提供的对应 operations。这一步骤需要确保 TT-NN operations 能够与 PyTorch 的功能相匹配,并且能够在 Tenstorrent 硬件上高效运行。

  3. 优化:在替换操作完成之后,要进行模型的优化。包括调整 tensor 的布局以适应 tiled-base 的计算模式,优化数据传输路径等优化,以确保模型在 Tenstorrent 硬件上达到最佳性能。

支持的模型

如上图所示,TT-Metal 支持的模型分为两类:一类是已经相对成熟且稳定支持的模型,这些模型被放置在 models/demos 目录下;另一类是仍处于实验阶段,尚未完全支持的模型,它们位于 models/experimental 目录中。正如上文所述,模型移植需要开发者手动进行重写和优化,这是一个相当耗时的过程。TT-Metal 作为一个开源项目,鼓励有兴趣的开发者参与到模型移植的工作中来,并且官方为此提供了现金奖励,以激励社区的参与和贡献。

性能数据

使用 TT-Metal 在 Wormhole 上跑大模型的性能如下图所示:

下表是在 Wormhole 单卡上使用 TT-Metal 跑 Falcon7b 模型的数据,throughput 为 456 tokens/s,和官方给出的 493 tokens/s 差距不大。

step_name measurement_name value step_warm_up_num_iterations step_start_ts step_end_ts
compile_prefill time(s) 11.206939 2024-07-18T05:57:37+0000 2024-07-18T05:57:48+0000
compile_decode time(s) 10.812242 2024-07-18T05:57:48+0000 2024-07-18T05:57:59+0000
inference_prefill tokens/s 1625.522516175113 5 2024-07-18T05:58:13+0000 2024-07-18T05:58:15+0000
inference_decode tokens/s 456.8390978108997 10 2024-07-18T05:58:15+0000 2024-07-18T05:58:17+0000
inference_decode tokens/s/user 14.276221806590616 10 2024-07-18T05:58:15+0000 2024-07-18T05:58:17+0000

下图显示了 Mistral7b 在 A100 上不同 batch 跑出来的数据。

使用 TT-Metal 在单张 Wormhole 卡上跑 Mistral-7B 模型实现了 32 batch 352 t/s 的性能,逊色于 Mistral-7B 模型在 A100 上的性能数据(大概在32 batch 1000 tokens/s左右)。Tenstorrent 芯片可以很方便的多卡互联做横向扩展,性能有进一步提升的空间,关于 Tenstorrent 横向扩展的能力,更详细的信息见前文Tenstorrent数据流芯片Grayskull 和 Wormhole解析

总结

本文介绍了 TT-Metal 软件框架,这是一种专为 Tenstorrent 处理器优化的编程环境,旨在高效开发和部署 AI 模型。文章探讨了 TT-Metal 的架构特点,以及如何使用 API 构建和优化算子。文中还介绍了 TT-NN 库,以及如何使用 TT-NN 进行模型移植。有关接口的详细信息,请参阅官方文档,更多细节和深入分析将在后续文章中阐述。

参考资料

  1. TT-Metal 官方文档 Welcome to TT-Metalium documentation! — TT-Metalium documentation

  2. TT-NN 官方文档 Welcome to TT-NN documentation! — TT-NN documentation

  3. TT-Metal API 接口 APIs — TT-Metalium documentation

  4. TT-Metal github 仓库 GitHub - tenstorrent/tt-metal: 🤘 TT-NN operator library, and TT-Metalium low level kernel programming model.

1 Like