操作符
在核心操作符之上,适配器还有二十个张量操作符。每个都以 {"name": [arguments]} 的形式调用。下面的表格中,T 是张量,形状是非负整数列表,轴从 0 开始计数。预算一页列出了每个操作符的开销。
其中七个名称是普通单词:
shape、full、cast、pad、crop、concat和stack。唯一的键是其中之一的对象会调用它。与之同名的数据键前面加上$:{"$shape": [6, 7]}就是数据{"shape": [6, 7]},在节点上和在tinybrains中都是如此。
构建张量
| 操作符 | 参数 | 结果 |
|---|---|---|
zeros | shape, dtype | 全零张量 |
full | shape, dtype, value | 用 value 填满的张量 |
tensor | value, dtype? | 把嵌套的 JSON 数组变成张量,形状与数组相同 |
scatter | points, shape, dtype, value? | 全零,再写入每个点:[r, c] 写入 value(默认 1),[r, c, v] 写入 v |
rle_expand | runs, shape, dtype | [v0, n0, v1, n1, …] 按行优先顺序展开。游程超出末尾则失败;不足末尾的,操作符用零补齐 |
one_hot | indices, depth, dtype | 形状 [len(indices), depth],在每个索引处放一个 1。索引超出 0 … depth − 1 的得到一行零。它不接受轴参数 |
scatter 会丢弃形状之外的点,不会把它环绕到地图另一边;同一格上后面的点会覆盖前面的点。每次写入都把值饱和到数据类型的范围:把 300 写入 i8 得到 127,而回绕式转换会得到 44。
点的第三个元素是值,所以在用敌人和蚁丘构建存在平面之前,先把它们裁成 [r, c]:
{"scatter": [
{"map": [{"var": "foes"}, [{"var": "0"}, {"var": "1"}]]},
{"var": "size"},
"i8"
]}
其中的 map,在一份观测上运行的结果:
在 DataLogic Studio 中打开——数据:一份示例观测:三只蚂蚁、一只敌蚁、一个食物、双方蚁丘、三格水域
重塑与组合
| 操作符 | 参数 | 结果 |
|---|---|---|
stack | tensors, axis | 在 axis 处新增一个轴。所有输入的形状和数据类型必须相同 |
concat | tensors, axis | 沿已有的轴拼接。其他各维必须一致 |
unstack | T, axis | 一个张量的 JSON 列表,axis 上每个索引对应一个 |
reshape | T, shape | 同样的元素,换成新形状。元素数必须相等,且不接受 -1 |
transpose | T, perm? | 重排各轴:perm[i] 是将成为第 i 轴的输入轴。不给 perm 时,轴顺序反转 |
pad | T, before, after, value | 在每个轴 d 上添加 before[d] 和 after[d] 个格子,以 value 填充(默认 0) |
crop | T, offset, shape | 从 offset 开始、大小为 shape 的区域。超出输入边缘的部分为零 |
把七个 [H, W] 平面在第 0 轴上堆叠得到 [7, H, W],再重塑为 [1, 7, H, W] 就加上了计算图期望的批次轴。一份真实的清单根据观测的大小构建第二个形状,所以一个适配器适用于每张地图。
stack不接受数据类型参数。每个平面必须已经是输入所声明的数据类型,所以要给每个平面各自的构造操作符传入这个数据类型。数据类型混杂是错误,stack从不做类型提升。
转换与归一化
| 操作符 | 参数 | 结果 |
|---|---|---|
cast | T, dtype | 转换后的张量。整数类型会饱和,并向零截断 |
normalize | T, mean, scale? | (x − mean) × scale,结果为 f32。scale 默认为 1 |
这两个就是这门语言全部的算术。它有意不提供加法、乘法和卷积(为什么)。
没有
dilate。把非零格周围距离平方范围内的每一格都标记出来(含环绕),只服务于一个平面,即视野掩码,而观测为此携带了vis。那个平面只需一次rle_expand。
读取张量
| 操作符 | 参数 | 结果 |
|---|---|---|
argmax | T, axis | 一个扁平的 JSON 列表:其他各轴每个位置上沿 axis 的最大值索引,按行优先顺序。并列时取第一个 |
gather | T, indices, axis? | 沿 axis(默认 0)取 indices 处各切片组成的张量。索引超出末尾则调用失败 |
to_list | T | 张量,以嵌套 JSON 列表表示 |
shape | T | 它的形状,以列表表示 |
dtype | T | 它的数据类型,以字符串表示 |
适配器必须以张量结尾,所以这些只能在中途使用,绝不能作为最后一步。shape 和 dtype 让程序能根据手上的东西分支。节点对 to_list 和其他操作符一样按元素计价,所以转换整张地图就要付整张地图的开销。
裁判用
argmax和gather读取你的策略头,你不需要用它们来写策略头。适配器可以使用它们(为双输入计算图供数的适配器,可能会从自己构建的张量推导出第二个输入),但典型的参赛模型两者都不会调用。
这里没有的
at、get、len 和 range 不是这门语言的操作符。改用下面这些: