
























最近这段时间 Cerebras 相关的编程接口发生了比较大的变动,在 1.4 版本发布之后,我认为是一个比较恰当的时间点去重新整理一下现有的编程接口。在这个版本中,最重要的功能更新是更新了软件 color 补全硬件 color。
传统 GPU 集群在训练大规模 AI 模型时面临严重的通信瓶颈。当模型参数达到万亿级别,需要数百甚至数千块 GPU 协同工作,芯片间的数据传输延迟往往超过实际计算时间。
Cerebras 的技术方案是将所有计算单元集成在单一晶圆上,从根本上消除芯片间通信开销[1]。
Cerebras Wafer-Scale Engine (WSE) 是一块完整的硅晶圆,面积达到 46,225 平方毫米[2]。WSE-3 的关键技术指标:
WSE 上分布着数十万个处理单元(Processing Elements, PE)。每个 PE 都是一个完整的计算单元[3]:
1 | |
关键特性:
PE 之间的通信是 Cerebras 架构的核心特性[4]。
Wavelet 是一个 32 位的数据包,可以在单个时钟周期内从一个 PE 发送到相邻的 PE。这是 PE 间通信的基本单位:
1 | |
为了避免网络拥塞并实现高效的数据流控制,Cerebras 引入了 Colors 概念——虚拟的通信通道[5]:
1 | |
Colors 的技术优势:
假设我们要实现一个简单的数据处理流水线:
1 | |
代码实现:
1 | |
WSE 这么大,数据是如何进出的?Cerebras 使用了特殊的 I/O 设计:
1 | |
这就是为什么使用 memcpy 时必须设置 --fabric-offsets=4,1——前 4 列被 I/O 系统占用[6]。
Cerebras 已经发布了三代 WSE,每一代都有显著提升[7]:
| 特性对比 | WSE-1 (2019) | WSE-2 (2021) | WSE-3 (2024) |
|---|---|---|---|
| 制程 | 16nm | 7nm | 5nm |
| 核心数 | 40万 | 85万 | 90万 |
| 性能提升 | 基准 | 2.1× | 2.25× |
| 内存 | 18GB | 40GB | 44GB |
| 新特性 | - | Wafer-Scale Cluster | MemoryX 外部内存 |
1 | |
CSL 编程模型由三个核心文件组成,每个文件负责不同的功能层面:
1 | |
三个文件的职责分工:
让我们详细解析 commands_wse3.sh 中的每个参数:
1 | |
--fabric-dims=12,7:定义可用的 fabric 区域大小
width + 4, height + 1(因为 memcpy 占用)--fabric-offsets=4,1:PE 网格的起始位置
--memcpy:启用数据传输功能
--channels=1:I/O 通道数量
1 | |
这是一个最简单的 CSL 程序示例,演示了:
1 | |
1 | |
1 | |
1 | |
基于 gemv-05-multiple-pes 模式[8],这个示例演示了:
1 | |
1 | |
1 | |
1 | |
1 | |
本章详细介绍第 4 章和第 5 章示例中使用的所有 API。
@import_module
1 | |
导入 CSL 模块。
参数:
filename:模块文件名(comptime string)param_binding:参数绑定(comptime 匿名结构体)示例:
1 | |
@set_rectangle
1 | |
设置 PE 网格的矩形尺寸。必须在 layout 块中调用。
参数:
width:网格宽度(comptime 整数)height:网格高度(comptime 整数)@set_tile_code
1 | |
为指定坐标的 PE 设置执行代码。
参数:
x_coord, y_coord:PE 坐标(comptime 整数)filename:代码文件名(comptime string)param_binding:参数绑定(comptime 匿名结构体)@export_name
1 | |
在 layout 中声明要导出的符号。
参数:
name:符号名称(string)type:符号类型is_distributed:是否为分布式符号(布尔值,默认 false)示例:
1 | |
@export_symbol
1 | |
在 PE 代码中导出符号供 host 访问。
参数:
symbol:要导出的变量或函数name:导出名称(可选)示例:
1 | |
@zeros
1 | |
创建零初始化的数组。
参数:
array_type:数组类型表达式示例:
1 | |
@constants
1 | |
创建常量初始化的数组。
参数:
array_type:数组类型value:初始化值示例:
1 | |
@as
1 | |
显式类型转换。
参数:
type:目标类型value:要转换的值示例:
1 | |
@bitcast
1 | |
位级别类型转换(不改变位模式)。
@range
1 | |
创建循环范围。
参数:
type:索引类型count:元素数量(从 0 开始)start:起始值end:结束值(不包含)step:步长示例:
1 | |
@get_color
1 | |
获取通信颜色。
参数:
color_id:颜色 ID(0-23)@set_color_config
1 | |
配置 PE 的颜色路由。
参数:
x, y:PE 坐标color:颜色对象config:路由配置示例:
1 | |
param
1 | |
声明编译时参数,可从 layout 或命令行传入。
示例:
1 | |
comptime
1 | |
标记在编译时执行的代码块。
SdkRuntime
1 | |
创建 SDK 运行时实例。
参数:
compile_dir:编译输出目录cmaddr:CS 系统地址(可选,格式 “IP:port”)基本控制方法:
1 | |
get_id
1 | |
获取导出符号的 ID。
参数:
symbol_name:符号名称(字符串)返回:
memcpy_h2d - Host 到 Device
1 | |
参数:
symbol:目标符号 IDdata:源数据(numpy 数组)px, py:起始 PE 坐标width, height:PE 网格尺寸elem_per_pe:每个 PE 的元素数量streaming:是否使用流式传输order:数据布局顺序data_type:数据类型(16 位或 32 位)nonblock:是否非阻塞memcpy_d2h - Device 到 Host
1 | |
参数:
result:目标数组(numpy 数组)memcpy_h2dlaunch
1 | |
在设备上执行函数。
参数:
function_name:函数名称(字符串)nonblock:是否非阻塞执行MemcpyDataType
1 | |
MemcpyOrder
1 | |
1 | |
1 | |
获取特定 PE 的 memcpy 参数。
参数:
pe_id:PE 索引(对于 2D 网格,使用 y * width + x)1 | |
1 | |
1 | |
1 | |
三个文件,三个角色
Fabric 偏移是硬性要求
--fabric-offsets=4,1数组导出必须用指针
@export_symbol(data)@export_symbol(&data)别忘了 unblock_cmd_stream()
多 PE 符号要分布式导出
@export_name("data", [*]f32, false)@export_name("data", [*]f32, true)完整的示例代码即将发布到 GitHub:
[TODO: 添加 GitHub 仓库链接]
仓库将包含:
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。