如何在Caffe2中实现PyTorch风格cumsum并解决梯度报错问题
如何在Caffe2中实现PyTorch的
cumsum等效操作(兼容梯度计算)? 我目前尝试在Caffe2中实现与PyTorch的cumsum功能等效的操作,希望使用标准算子(不修改C++代码),但遇到了问题。
当前实现代码:
pred_cdist = net.Transpose( net.SparseLengthsSum( [ net.Transpose(prediction), as_blob( np.array( [ ix for length in range(pred_shape[1]) for ix in range(length) ], dtype="int32", ) ), as_blob(np.array(list(range(pred_shape[1])), dtype="int32")), ] ) )
该方法前向传播可行,但计算梯度时出现报错:Gradient of output .../Transpose is sparse (expected dense)..。请问是否有其他实现方式,或如何调整现有方案让梯度计算正常?
解决方案
方案一:修复现有SparseLengthsSum的梯度问题
报错核心原因是SparseLengthsSum输出的梯度为稀疏格式,但后续Transpose仅支持稠密梯度输入。只需在两者之间加入ToDense算子转换格式即可:
sparse_sum = net.SparseLengthsSum( [ net.Transpose(prediction), as_blob( np.array( [ix for length in range(pred_shape[1]) for ix in range(length)], dtype="int32", ) ), as_blob(np.array(list(range(pred_shape[1])), dtype="int32")), ] ) # 转换为稠密张量,解决梯度格式不兼容问题 dense_sum = net.ToDense(sparse_sum) pred_cdist = net.Transpose(dense_sum)
方案二:直接使用原生CumSum算子(推荐)
如果你的Caffe2版本较新,框架已内置CumSum原生算子,完全等效于PyTorch的cumsum,且原生支持梯度计算:
# 示例:沿着dim=1计算累积和,对应PyTorch的torch.cumsum(prediction, dim=1) pred_cdist = net.CumSum(prediction, axes=[1])
这个方案最简洁,无需手动组合算子,也不会出现稀疏/稠密格式冲突问题。
方案三:用稠密算子组合模拟(兼容旧版本)
若无法使用原生CumSum,可通过循环+Slice+Expand+Add的稠密算子组合实现cumsum,全程避免稀疏张量:
# 假设输入形状为(N, C),沿着dim=1计算累积和 current_sum = prediction pred_cdist = current_sum for i in range(1, pred_shape[1]): # 截取前i列的结果并扩展维度 prev_sum = net.Slice(current_sum, starts=[0, 0], ends=[pred_shape[0], i]) expanded_prev = net.Expand(prev_sum, dims=[pred_shape[0], pred_shape[1]-i], axes=[1]) # 累加得到当前列的累积和 current_sum = net.Add(current_sum, expanded_prev) # 拼接所有列的结果 pred_cdist = net.Concat([pred_cdist, current_sum], axis=1)
该方案所有算子均为稠密类型,梯度计算自然兼容。
内容的提问来源于stack exchange,提问作者Isaac
相关产品推荐
相关产品推荐

