Apache SINGA 常用工具与 API 详解
Apache SINGA 5.1.0 常用工具与 API 详解,按 device 设备、tensor 张量、autograd 自动微分、layer 算子层、model 训练模型、opt 优化器六大类梳理核心接口、参数表与实测代码,覆盖张量运算、卷积层、图模式训练、模型保存恢复与优化器选择,全部示例在 Ubuntu 22.04 实测通过。
Apache SINGA 常用工具与 API 详解
目标:按模块分类梳理 Apache SINGA 5.1.0 的核心 Python API——
device(设备)、tensor(张量)、autograd(自动微分)、layer(算子层)、model(训练模型)、opt(优化器),每个分类给出参数表与可直接运行的实测代码及真实回显。SINGA 无命令行工具,Python SDK 即其主要使用形态。
一、环境信息
- 操作系统:Ubuntu 22.04.5 LTS(x86_64,12 核)
- Python:3.10.12(虚拟环境
/root/singa-venv) - SINGA 版本:5.1.0(
singa.__version__返回 5100,CPU + oneDNN 1.1 构建) - Python 依赖:numpy 1.23.5、protobuf 3.20.3
- 安装与兼容性补丁:《Apache SINGA 安装指南》
二、API 分类概览
| 分类 | 导入方式 | 职责 | 常用入口 |
|---|---|---|---|
| 设备 | from singa import device | 计算设备创建与选择 | get_default_device() |
| 张量 | from singa import tensor | 多维数组与运算 | Tensor()、copy_from_numpy()、to_numpy() |
| 自动微分 | from singa import autograd | 前向算子与反向梯度 | matmul、softmax_cross_entropy、backward |
| 算子层 | from singa import layer | 神经网络层封装 | Linear、ReLU、Conv2d、MaxPool2d |
| 训练模型 | from singa import model | 模型基类与生命周期 | model.Model、compile、save_states |
| 优化器 | from singa import opt | 梯度更新与分布式选项 | SGD、AdaGrad、Adam、RMSProp |
模块内可见类名(实测 dir() 过滤结果):
opt:AdaGrad, Adam, Constant, DecayScheduler, DistOpt, ExponentialDecay, Optimizer, RMSProp, SGDlayer:Linear, ReLU, Sigmoid, SoftMax, Flatten, Conv2d, MaxPool1d/2d, AvgPool1d/2d, BatchNorm2d, Dropout, Embedding, RNN/LSTM, Gemm, Add, Cat, Reshape, SoftMaxCrossEntropy, CrossEntropy, BinaryCrossEntropy, MeanSquareError等
三、前置条件
确认安装与补丁就绪(详见《Apache SINGA 安装指南》):
source /root/singa-venv/bin/activate
python3 -c 'import singa; print(singa.__version__)'
实测回显:
5100
四、device:设备 API
4.1 分类说明
| API | 说明 |
|---|---|
device.get_default_device() | 返回默认计算设备;CPU 构建下为 CppCPU 实例,训练/推理统一入口 |
device.create_cuda_gpu() | 创建 GPU 设备(0 号卡),需 CUDA 构建 |
device.create_cuda_gpu_on(id) | 创建指定编号的 GPU 设备,需 CUDA 构建 |
⚠️ 前置说明:GPU 接口(
create_cuda_gpu*)需以USE_CUDA=ON编译并具备 CUDA/cuDNN 环境,本环境为 CPU 构建,以下仅给出 CPU 路径实测。
4.2 实测代码
from singa import device, tensor
dev = device.get_default_device()
x = tensor.Tensor((2, 3), dev, tensor.float32)
x.copy_from_numpy([[1, 2, 3], [4, 5, 6]])
print(dev)
print(dev.id())
实测回显:
<singa.singa_wrap.Device; proxy of <Swig Object of type 'std::shared_ptr< singa::Device > *' at 0x7272df3c2340> >
-1
打印对象为 SWIG 包装的 singa_wrap.Device 代理;dev.id() 返回 -1 表示默认设备由内部选择(非用户显式创建的编号设备)。所有张量创建都显式传入该设备对象,多设备场景即为不同 dev 的切换。
五、tensor:张量 API
5.1 分类说明
| 类别 | API | 说明 |
|---|---|---|
| 创建 | Tensor(shape, dev, dtype) | 形状、设备、数据类型(tensor.float32 / tensor.int32 等) |
| 转换 | copy_from_numpy(arr) | numpy 数组写入张量(需先创建同形状张量) |
| 转换 | to_numpy(t) | 张量转 numpy 数组 |
| 转换 | from_numpy(arr) | 由 numpy 数组创建张量(要求 numpy 1.23.x) |
| 初始化 | set_value(v) | 全部元素置为标量 v(未初始化即读取会 abort) |
| 初始化 | gaussian(mean, std) | 正态分布随机初始化 |
| 初始化 | uniform(low, high) | 均匀分布随机初始化 |
| 运算 | +、-、*、/ | 逐元素运算,重载操作符 |
| 运算 | tensor.transpose(t, axes) | 轴变换 |
| 运算 | tensor.reshape(t, shape) | 形状变换 |
| 属性 | shape、dtype、data | 形状元组、类型枚举、底层 CTensor |
5.2 实测代码
import numpy as np
from singa import tensor, device, autograd
dev = device.get_default_device()
x = tensor.Tensor((2, 3), dev, tensor.float32)
x.copy_from_numpy(np.array([[1., 2., 3.], [4., 5., 6.]], dtype=np.float32))
print('x =', tensor.to_numpy(x).tolist())
print('x shape:', x.shape, 'dtype:', x.dtype)
print('x + 1 =', tensor.to_numpy(x + 1).tolist())
print('x * 2 =', tensor.to_numpy(x * 2).tolist())
实测回显:
x = [[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]
x shape: (2, 3) dtype: 0
x + 1 = [[2.0, 3.0, 4.0], [5.0, 6.0, 7.0]]
x * 2 = [[2.0, 4.0, 6.0], [8.0, 10.0, 12.0]]
形状变换与初始化:
a = tensor.Tensor((2, 3), dev, tensor.float32)
a.copy_from_numpy(np.array([[1., 0., 2.], [0., 1., 1.]], dtype=np.float32))
at = tensor.transpose(a, (1, 0))
print('transpose(a,(1,0)) =', tensor.to_numpy(at).tolist())
print('reshape(a,(3,2)) =', tensor.to_numpy(tensor.reshape(a, (3, 2))).tolist())
g = tensor.Tensor((2, 2), dev, tensor.float32)
g.gaussian(0.0, 1.0)
u = tensor.Tensor((2, 2), dev, tensor.float32)
u.uniform(0.0, 1.0)
sv = tensor.Tensor((2, 2), dev, tensor.float32)
sv.set_value(3.0)
print('set_value(3.0) =', tensor.to_numpy(sv).tolist())
实测回显(gaussian/uniform 为随机值,逐次不同):
transpose(a,(1,0)) = [[1.0, 0.0], [0.0, 1.0], [2.0, 1.0]]
reshape(a,(3,2)) = [[1.0, 0.0], [2.0, 0.0], [1.0, 1.0]]
set_value(3.0) = [[3.0, 3.0], [3.0, 3.0]]
六、autograd:自动微分 API
6.1 分类说明
| API | 说明 |
|---|---|
autograd.matmul(x, w) | 矩阵乘法前向算子 |
autograd.softmax_cross_entropy(out, target) | 多分类交叉熵损失,target 为 tensor.int32 类标签张量 |
autograd.mse_loss(out, target) | 均方误差损失 |
autograd.backward(loss) | 非图模式反向传播,返回 [(param, grad), ...] |
autograd.training | 模块级开关:True 时算子缓存反向所需中间量 |
autograd.linear / relu / sigmoid 等函数 | 与 layer 同名层对应的功能算子 |
6.2 实测代码
import numpy as np
from singa import tensor, device, autograd, opt
dev = device.get_default_device()
autograd.training = True
a = tensor.Tensor((2, 3), dev, tensor.float32)
a.copy_from_numpy(np.array([[1., 0., 2.], [0., 1., 1.]], dtype=np.float32))
b = tensor.Tensor((3, 2), dev, tensor.float32)
b.copy_from_numpy(np.array([[1., 2.], [3., 4.], [5., 6.]], dtype=np.float32))
c = autograd.matmul(a, b)
print('matmul(a,b) =', tensor.to_numpy(c).tolist())
实测回显:
matmul(a,b) = [[11.0, 14.0], [8.0, 10.0]]
⚠️ 注意:非图模式下手写
autograd.backward(loss)+ 优化器逐参更新,在 CPU 构建上存在崩溃风险(多参数 + momentum 时实测出现free(): invalid size);训练请统一走第八章model.Model图模式路径。
七、layer:算子层 API
7.1 分类说明
| 层类 | 关键参数 | 说明 |
|---|---|---|
Linear(size) | 输出单元数;输入维度在前向时按输入张量推断 | 全连接层,内部参数 W/b |
ReLU() / Sigmoid() | 无 | 逐元素激活层 |
Conv2d(nb_kernels, kernel_size, padding=0, activation=None) | 滤波器数、卷积核边长、填充、激活 | 2D 卷积;输入通道自动推断(旧式三参调用兼容转换) |
MaxPool2d(kernel_size, stride, padding=0) | 池化核、步长 | 2D 最大池化 |
Flatten() | 无 | 展平(卷积输出接全连接) |
SoftMaxCrossEntropy() | 无 | softmax + 交叉熵损失层(图模式训练用) |
层的前向调用统一为 layer.forward(x);图模式下由 model.Model 生命周期自动管理参数与梯度。
7.2 实测代码
import numpy as np
from singa import tensor, device, layer
dev = device.get_default_device()
lin = layer.Linear(4)
xin = tensor.Tensor((2, 6), dev, tensor.float32)
xin.gaussian(0.0, 0.1)
out = lin.forward(xin)
print('Linear(6->4) out shape:', out.shape)
pool = layer.MaxPool2d(2, 2, padding=0)
xx = tensor.Tensor((1, 1, 4, 4), dev, tensor.float32)
xx.copy_from_numpy(np.arange(16, dtype=np.float32).reshape(1, 1, 4, 4))
po = pool.forward(xx)
print('MaxPool2d(2,2) out:', tensor.to_numpy(po).reshape(2, 2).tolist())
实测回显:
Linear(6->4) out shape: (2, 4)
MaxPool2d(2,2) out: [[5.0, 7.0], [13.0, 15.0]]
卷积层(需 oneDNN 构建):
from singa import autograd
autograd.training = True
conv = layer.Conv2d(20, 5, padding=0)
x = tensor.Tensor((2, 1, 28, 28), dev, tensor.float32)
x.gaussian(0, 1)
y = conv.forward(x)
print(tuple(y.shape))
实测回显:
(2, 20, 24, 24)
28×28 输入经 5×5 无填充卷积输出 24×24,通道数由 1 变为滤波器数 20。
八、model:训练模型 API
8.1 分类说明
model.Model 实测可见方法:compile, train, eval, forward, train_one_batch, save_states, load_states, get_states, set_states, get_params, set_params, initialize, graph 等。生命周期四步:
| 步骤 | API | 说明 |
|---|---|---|
| 1. 定义 | 子类继承 model.Model,在 __init__ 注册层,实现 forward 与 train_one_batch | 属性即层,参数自动注册 |
| 2. 编译 | compile([sample_x], is_train=True, use_graph=True, sequential=True) | 用样例输入构图;use_graph=True 为官方推荐稳定路径 |
| 3. 训练/评估 | train() / eval() 切换模式;调用 model(x, y, dist_option, spars) 返回 (out, loss) | 非训练模式直接 model(x) 得前向输出 |
| 4. 存取 | save_states(fpath, aux_states=...) / load_states(fpath) | 单文件检查点,含参数与辅助状态 |
8.2 实测代码
import numpy as np, os
from singa import tensor, device, layer, opt, model, autograd
class MLP(model.Model):
def __init__(self):
super().__init__()
self.linear1 = layer.Linear(8)
self.linear2 = layer.Linear(4)
def forward(self, x):
return self.linear2(self.linear1(x))
def train_one_batch(self, x, y, dist_option='plain', spars=None):
out = self.forward(x)
loss = autograd.softmax_cross_entropy(out, y)
self.optimizer(loss)
return out, loss
dev = device.get_default_device()
m = MLP()
tx = tensor.Tensor((2, 10), dev, tensor.float32)
ty = tensor.Tensor((2,), dev, tensor.int32)
m.optimizer = opt.SGD(lr=0.01)
m.compile([tx], is_train=True, use_graph=True, sequential=True)
m.train()
tx.copy_from_numpy(np.random.rand(2, 10).astype(np.float32))
ty.copy_from_numpy(np.array([1, 2], dtype=np.int32))
out, loss = m(tx, ty, 'plain', spars=None)
print('train step loss:', float(tensor.to_numpy(loss)[0]))
os.makedirs('/tmp/singa-ckpt', exist_ok=True)
epoch = tensor.Tensor((1,), dev, tensor.int32)
epoch.set_value(1)
m.save_states('/tmp/singa-ckpt/mlp-states', aux_states={'epoch': epoch})
print('ckpt files:', sorted(os.listdir('/tmp/singa-ckpt')))
m2 = MLP()
m2.optimizer = opt.SGD(lr=0.01)
m2.compile([tx], is_train=True, use_graph=True, sequential=True)
m2.load_states('/tmp/singa-ckpt/mlp-states')
print('load_states OK')
实测回显:
train step loss: 1.0017001628875732
ckpt files: ['mlp-states']
load_states OK
⚠️ 注意:
save_states的aux_states中每个 Tensor 必须先set_value(...)初始化,否则进程 abort(Check failed: initialized_ Must initialize data before reading it)。
九、opt:优化器 API
9.1 分类说明
| API | 关键参数 | 说明 |
|---|---|---|
opt.SGD(lr, momentum=0.0, weight_decay=0.0) | 学习率、动量、L2 正则 | 随机梯度下降(示例默认选择) |
opt.AdaGrad / opt.Adam / opt.RMSProp | 各自学习率与状态参数 | 自适应学习率族 |
opt.lr.ExponentialDecay(initial_lr, decay_rate, decay_steps) | 衰减参数 | 学习率调度(DecayScheduler 配套) |
optimizer(loss) | 损失张量 | train_one_batch 内调用:反向传播并更新全部参数 |
opt.DistOpt | 分布式封装 | 需 ENABLE_DIST=ON 构建与 MPI/ZMQ 环境,本构建未启用未实测 |
9.2 实测代码
from singa import opt
sgd = opt.SGD(lr=0.01, momentum=0.9, weight_decay=1e-5)
print('SGD created:', type(sgd).__name__)
实测回显:
SGD created: SGD
在 train_one_batch 中通过 self.optimizer(loss) 触发整批参数的梯度更新;评估前用 model.eval() 关闭训练模式即可避免误更新。
十、注意事项
⚠️ 注意:
- 张量初始化(
set_value/gaussian/uniform/copy_from_numpy)必须先于任何读取,否则底层断言 abort。tensor.from_numpy与 numpy 1.24+ 不兼容(np.float移除),固定 numpy 1.23.x。- Python 3.10 需先修补
singa/model.py的collections.abc导入,否则 import model 即报错。Conv2d前向要求 oneDNN 构建(USE_DNNL=ON);DistOpt要求ENABLE_DIST=ON构建,两者在本指南环境的状态分别为「已启用」「未启用」。- GPU 设备 API 需 CUDA 构建,本环境未实测;CPU 路径统一用
device.get_default_device()。
十一、常见问题
Q1:to_numpy 输出的 dtype 打印为 0?
tensor.dtype 返回类型枚举(0 对应 float32);数据类型以 numpy 数组实际 dtype 为准。
Q2:训练循环该用 autograd.backward 还是 model.Model?
统一用 model.Model 图模式(compile(use_graph=True) + train_one_batch),官方示例即此路径,实测稳定;手写 backward 循环在 CPU 上有崩溃风险(见第六章注意)。
Q3:save_states 报 Must initialize data before reading it?
aux_states 里的张量未初始化。先 t = tensor.Tensor((1,), dev, tensor.int32); t.set_value(epoch) 再传入。
Q4:优化器怎么在 Model 里挂载?
m.optimizer = sgd(属性赋值);train_one_batch 内的 self.optimizer(loss) 自动使用它。
十二、参考链接
- SINGA Python API 文档:
https://singa.apache.org/docs/(Python API 章节) - 官方示例仓库:
https://github.com/apache/singa/tree/master/examples - 张量与自动微分教程:
https://singa.apache.org/docs/tensor/