CLA协议签署
当前Pull Request的提交暂无外部代码贡献者合并受阻
变更摘要
本次 PR 同步了 HiSpark.AI 仓库的多个功能增强和缺陷修复,主要涉及:新增 THRESHOLDRELU 激活类型在全链路(Schema、FP32/Int8 内核、Micro Coder、ONNX/TFLite 解析器、量化器)的支持;为 Cast 算子添加 saturate 饱和转换属性以对齐 TFLite 的 float32→uint8 行为;修复 LstmInt8CPUKernel 的影子缓冲区双重释放问题并完善张量指针恢复逻辑;扩展 Int8 PadConstant 对 2D/3D 输入的支持;以及修复 FlattenInferShape 负轴计算、UnsqueezeInferShape 负维度归一化等多个推断器的边界处理问题。
主要改动
-
新增
THRESHOLDRELU激活支持: 在ops.fbs增加ActivationType_THRESHOLDRELU枚举、新增ThresholdedReluFP32 实现及ThresholdedReluInt8Int8 量化内核,对应的 ONNX 解析器OnnxThresholdedReluParser、Int8 CoderThresholdedReluInt8Coder以及量化器白名单同步更新,形成完整的算子链路。 -
Cast算子增加saturate饱和转换: Schema 新增saturate: bool字段,PopulateCastParameter改用CastParameter结构体并读取该属性;当saturate=true时 float32→uint8 转换调用Float32ToUint8Saturate(钳位到 [0,255]),否则使用原有取模逻辑;TFLite 解析器对 uint8 目标类型自动设置该属性。 -
修复
LstmInt8CPUKernel双重释放与张量引用问题: 移除对shadow_buffers_的单独free调用(避免与Tensor析构重复释放),在Prepare和Run结束后恢复in_tensors_/out_tensors_为原始张量指针,防止下游节点访问已释放的影子缓冲区;同时修正影子缓冲区大小计算为ElementsNum() * sizeof(float)。 -
Int8
PadConstant支持 2D/3D 输入: 新增PadConstant2D和PadConstant3D函数,调整维度索引逻辑(2D 使用in_dims[3]、3D 使用in_dims[2]),PadInt8CPUKernel::RunImpl根据输入维度分派到对应实现,Coder 端同步适配。 -
构建系统与推断器修复:
package_micro.cmake将 RISCV/ARM 交叉编译库的安装逻辑拆分为独立的if块(分别检查RISCV_TOOLCHAIN_AVAILABLE和ARM_TOOLCHAIN_AVAILABLE);FlattenInferShape中负轴计算从-axis修正为+axis;UnsqueezeInferShape对负维度进行归一化并排序后再处理。


代码审查
所有 55 个文件均已审查。以下为总结:
审查总结
按严重度统计
| 严重度 | 数量 | 说明 |
|---|---|---|
| P1 | 1 | mul_int8_coder.cc 中 auto 局部变量遮蔽成员变量,导致 DoCode() 广播分支永不执行 |
| P2 | 2 | cast_base.c 中 float→int32_t 溢出风险;lstm_int8.cc 中 Prepare() 错误路径缺少 tensor 恢复 |
| P3 | 2 | gather_d_int8_coder.cc License 头部拼写错误;lstm_fp32_low_memory.c 注释与代码不一致 |
各文件审查结果
| 文件 | 结果 |
|---|---|
| cmake/package_micro.cmake | 无问题 |
| mindspore-lite/CMakeLists.txt | 无问题 |
| mindspore-lite/schema/ops.fbs | 无问题 |
| mindspore-lite/src/common/ops/operator_populate/activation_populate.cc | 无问题 |
| mindspore-lite/src/common/ops/ops_def.cc | 无问题 |
| mindspore-lite/src/common/ops/populate/activation_populate.cc | 无问题 |
| mindspore-lite/src/common/ops/populate/cast_populate.cc | 无问题 |
| mindspore-lite/src/litert/kernel/cpu/fp32/cast_fp32.cc | 无问题 |
| mindspore-lite/src/litert/kernel/cpu/fp32/cast_fp32.h | 无问题 |
| mindspore-lite/src/litert/kernel/cpu/int8/activation_int8.cc | 无问题 |
| mindspore-lite/src/litert/kernel/cpu/int8/div_int8.cc | 无问题 |
| mindspore-lite/src/litert/kernel/cpu/int8/lstm_int8.cc | P2: Prepare() 错误路径未恢复 tensor |
| mindspore-lite/src/litert/kernel/cpu/int8/mul_int8.cc | 无问题 |
| mindspore-lite/src/litert/kernel/cpu/int8/pad_int8.cc | 无问题 |
| mindspore-lite/src/litert/kernel/cpu/int8/sub_int8.cc | 无问题 |
| mindspore-lite/src/litert/kernel/cpu/int8/thresholded_relu_int8.cc | 无问题 |
| mindspore-lite/src/litert/kernel/cpu/int8/thresholded_relu_int8.h | 无问题 |
| mindspore-lite/src/litert/kernel/cpu/nnacl_c/base/cast_base.c | P2: Float32ToUint8 int32_t 溢出风险 |
| mindspore-lite/src/litert/kernel/cpu/nnacl_c/base/cast_base.h | 无问题 |
| mindspore-lite/src/litert/kernel/cpu/nnacl_c/fp32/activation_fp32.c | 无问题 |
| mindspore-lite/src/litert/kernel/cpu/nnacl_c/fp32/activation_fp32.h | 无问题 |
| mindspore-lite/src/litert/kernel/cpu/nnacl_c/fp32/lstm_fp32_low_memory.c | P3: transB 注释过时 |
| mindspore-lite/src/litert/kernel/cpu/nnacl_c/infer/flatten_infer.c | 无问题(修复了 axis 归一化公式) |
| mindspore-lite/src/litert/kernel/cpu/nnacl_c/infer/unsqueeze_infer.c | 无问题 |
| mindspore-lite/src/litert/kernel/cpu/nnacl_c/int8/pad_int8.c | 无问题 |
| mindspore-lite/src/litert/kernel/cpu/nnacl_c/int8/pad_int8.h | 无问题 |
| mindspore-lite/src/litert/kernel/cpu/nnacl_c/int8/thresholded_relu_int8.c | 无问题 |
| mindspore-lite/src/litert/kernel/cpu/nnacl_c/int8/thresholded_relu_int8.h | 无问题 |
| mindspore-lite/src/litert/kernel/cpu/nnacl_c/kernel/activation.c | 无问题 |
| mindspore-lite/src/litert/kernel/cpu/nnacl_c/kernel/cast.c | 无问题 |
| mindspore-lite/src/litert/kernel/cpu/nnacl_c/kernel/cast.h | 无问题 |
| mindspore-lite/src/litert/kernel/cpu/nnacl_c/kernel/gather.c | 无问题 |
| mindspore-lite/tools/converter/micro/coder/opcoders/base/dtype_cast_coder.cc | 无问题 |
| mindspore-lite/tools/converter/micro/coder/opcoders/nnacl/fp32/activation_fp32_coder.cc | 无问题 |
| mindspore-lite/tools/converter/micro/coder/opcoders/nnacl/fp32/gather_d_fp32_coder.cc | 无问题 |
| mindspore-lite/tools/converter/micro/coder/opcoders/nnacl/fp32/gather_fp32_coder.cc | 无问题 |
| mindspore-lite/tools/converter/micro/coder/opcoders/nnacl/fp32/instance_norm_fp32_coder.cc | 无问题 |
| mindspore-lite/tools/converter/micro/coder/opcoders/nnacl/fp32/pad_fp32_coder.cc | 无问题 |
| mindspore-lite/tools/converter/micro/coder/opcoders/nnacl/int8/activation_int8_coder.cc | 无问题 |
| mindspore-lite/tools/converter/micro/coder/opcoders/nnacl/int8/div_int8_coder.cc | 无问题 |
| mindspore-lite/tools/converter/micro/coder/opcoders/nnacl/int8/gather_d_int8_coder.cc | P3: License 头部拼写错误 |
| mindspore-lite/tools/converter/micro/coder/opcoders/nnacl/int8/gather_int8_coder.cc | 无问题 |
| mindspore-lite/tools/converter/micro/coder/opcoders/nnacl/int8/mul_int8_coder.cc | P1: auto 遮蔽成员变量 |
| mindspore-lite/tools/converter/micro/coder/opcoders/nnacl/int8/pad_int8_coder.cc | 无问题 |
| mindspore-lite/tools/converter/micro/coder/opcoders/nnacl/int8/reduce_int8_coder.cc | 无问题 |
| mindspore-lite/tools/converter/micro/coder/opcoders/nnacl/int8/resize_int8_coder.cc | 无问题 |
| mindspore-lite/tools/converter/micro/coder/opcoders/nnacl/int8/sub_int8_coder.cc | 无问题 |
| mindspore-lite/tools/converter/micro/coder/opcoders/nnacl/int8/thresholded_relu_int8_coder.cc | 无问题 |
| mindspore-lite/tools/converter/micro/coder/opcoders/nnacl/int8/thresholded_relu_int8_coder.h | 无问题 |
| mindspore-lite/tools/converter/parser/onnx/onnx_activation_parser.cc | 无问题 |
| mindspore-lite/tools/converter/parser/onnx/onnx_activation_parser.h | 无问题 |
| mindspore-lite/tools/converter/parser/onnx/onnx_gather_element_parser.cc | 无问题 |
| mindspore-lite/tools/converter/parser/onnx/onnx_reverse_sequence_parser.cc | 无问题 |
| mindspore-lite/tools/converter/parser/tflite/tflite_cast_parser.cc | 无问题 |
| mindspore-lite/tools/converter/quantizer/full_quant_quantizer.cc | 无问题 |
整体风险评估
本 PR 总体质量良好,主要贡献是 ThresholdedRelu int8 算子实现、Cast saturate 支持、以及大量 broadcast 判定从 ElementNum 比较改为 shape 比较的修复。发现的最严重问题(P1)是 mul_int8_coder.cc 中 auto 局部变量遮蔽成员变量,会导致 int8 Mul 算子微码编译在广播场景下产生错误结果——建议合入前必须修复。其他 P2/P3 问题影响较小,可在后续迭代中解决。
| 类型 | 数量 |
|---|---|
| 🔴 阻塞 | 3 |
| 🟡 建议 | 4 |
⛔ 需要修改


🔵 Low Priority
第 31–32 行的注释写道 "transB=false",但第 34 行和第 40 行的实际代码已将 transB 参数从 false 改为 true。注释与代码矛盾,会误导后续维护者。应更新注释以反映当前的转置策略。
建议:将注释中的 transB=false 更新为 transB=true,并说明原因(例如 "weight_i is stored as [4hidden, input_size] (ONNX row-major), so transB=true to treat it as [input_size, 4hidden]")。


🟠 High Priority
在 Prepare() 第 40 行,使用 auto need_broadcast_ = ... 声明了一个局部变量,它与头文件 mul_int8_coder.h:50 中定义的成员变量 bool need_broadcast_{false} 同名,从而**遮蔽(shadow)**了成员变量。
后果:第 42 行的 if (!need_broadcast_) 使用的是局部变量(正确反映广播需求),但第 96 行 DoCode() 中的 if (need_broadcast_) 使用的是成员变量,该成员变量始终为 false。这导致 DoCode() 中的广播分支永远不会被执行——即使输入 shape 不同需要广播,也会走入非广播路径,造成运行时计算错误。
修复:去掉第 40 行的 auto,直接对成员变量赋值:need_broadcast_ = (input1_shape != input2_shape);
建议:将第 40 行的 auto need_broadcast_ = 改为 need_broadcast_ =,去掉 auto 关键字,使赋值直接作用于成员变量。
| 40
| - |
|
40 | + need_broadcast_ = (input1_shape != input2_shape); |


🟠 High Priority
变更将 PadConstant2D 的维度索引从旧版的 in_dims[0]/in_dims[1] 迁移到 4D 布局下的最后两个维度 in_dims[2]/in_dims[3],但 paddings 数组的索引未同步偏移。
PadConstant4D 使用 Offset() 时的映射为:dim 0 → paddings[0],dim 1 → paddings[2],dim 2 → paddings[4],dim 3 → paddings[6]。
PadConstant2D 操作 dim 2(高度)和 dim 3(宽度),应使用 paddings[4](高度前 pad)和 paddings[6](宽度前 pad),但当前代码使用 paddings[0] 和 paddings[2](对应 dim 0、dim 1 的前 pad,在 2D 输入场景下始终为 0)。
触发条件:当 pad 参数中高度或宽度的 padding 非零时,输出数据会写入错误的内存位置(缺少 pad_before_H 的行偏移和 pad_before_W 的列偏移)。
修复方向:将第 30 行的 paddings[0] 改为 paddings[4],paddings[2] 改为 paddings[6]。
建议:将输出偏移计算中的 paddings 索引修正为与当前维度对应的正确值:(h + paddings[4]) * out_dims[3] + paddings[6]。
| 30
| - int8_t *out = out_data + (h + paddings[ |
|
30 | + int8_t *out = out_data + (h + paddings[4]) * out_dims[3] + paddings[6]; |


🟡 Medium Priority
changed lines: thresholded_relu_int8.cc:61-62
thread_count_ = MSMIN(element_size_, op_parameter_->thread_num_);
thread_stride_ = UP_DIV(element_size_, thread_count_);
affected behavior: 当 op_parameter_->thread_num_ 为 0 且 element_size_ > 0 时,MSMIN(element_size_, 0) 返回 0(MSMIN 定义为 ((x) < (y) ? (x) : (y))),然后 UP_DIV(element_size_, 0) 展开为 (((element_size_) + (0) - (1)) / (0)),触发除零错误导致程序崩溃。
failure mode: 只要运行时的 thread_num_ 被意外设为 0(例如配置错误、未正确初始化),内核执行到 ReSize() 时就会崩溃。同类 kernel pad_int8.cc 中有显式检查:MS_CHECK_FALSE_MSG(op_parameter_->thread_num_ == 0, RET_ERROR, "div zero");,但此新文件缺失该检查。
suggested fix: 在 line 61 之前添加 thread_num_ == 0 的检查,或在 MSMIN 之前确保 thread_num_ >= 1。
建议:在 line 61 之前添加对 thread_num_ 为 0 的防御检查,参考 pad_int8.cc 的做法。


🟠 High Priority
与 PadConstant2D 类似的 bug:维度索引从旧版 in_dims[0]/in_dims[1]/in_dims[2] 迁移到 4D 布局的 in_dims[1]/in_dims[2]/in_dims[3],但 paddings 索引未同步偏移。
PadConstant4D 的映射为:dim 0 → paddings[0],dim 1 → paddings[2],dim 2 → paddings[4],dim 3 → paddings[6]。
PadConstant3D 操作 dim 1(通道)、dim 2(高度)、dim 3(宽度),应分别使用 paddings[2]、paddings[4]、paddings[6]。当前代码(第 47 行)使用 paddings[0]、paddings[2]、paddings[4],与正确值相比整体偏移了 2 个位置(一个维度)。
触发条件:当输入为 3D(如 C×H×W)且通道/高度/宽度任一维度的 padding 非零时,输出数据写入错误位置。
修复方向:第 47 行的三个 paddings 索引分别改为 [2]、[4]、[6]。
建议:将输出偏移计算中的三个 paddings 索引修正为:((d + paddings[2]) * out_dims[2] + (h + paddings[4])) * out_dims[3] + paddings[6]。
| 47
| - int8_t *out = out_data + ((d + paddings[ |
|
47 | + int8_t *out = out_data + ((d + paddings[2]) * out_dims[2] + (h + paddings[4])) * out_dims[3] + paddings[6]; |


🔵 Low Priority
变更后文件第 2-3 行出现两行相同的版权声明:Copyright 2019-2026 Huawei Technologies Co., Ltd。这很可能是编辑时误粘贴导致,虽不影响功能但属于噪声。
建议:删除重复的版权行,只保留一行。


🔵 Low Priority
第 13 行 Apache License 头部出现拼写错误:"language language"(重复了 "language"),应为 "language"。这虽然是注释/头部信息,但作为开源协议声明存在明显错误,影响代码专业性。
建议:将第 13 行的 "language language" 改为 "language"。
| 13
| - * See the License for the specific language |
|
13 | + * See the License for the specific language governing permissions and |


门禁执行失败,请到openxinhuo查看:https://xinhuo.developers.hisilicon.com/openxinhuoWeb/#/CodeAccess/codeAccessDetail/17846
| # | check type | result | detail |
|---|---|---|---|
| 1 | staticcheck_codecheck | >>> | |
| 2 | staticcheck_sca_scan | >>> | |
| 3 | staticcheck_virus_scan | >>> | |
| 4 | build | NA | |
| 5 | smoke | NA | NA |


门禁执行成功,请到openxinhuo查看:https://xinhuo.developers.hisilicon.com/openxinhuoWeb/#/CodeAccess/codeAccessDetail/17862
| # | check type | result | detail |
|---|---|---|---|
| 1 | staticcheck_codecheck | >>> | |
| 2 | staticcheck_sca_scan | >>> | |
| 3 | staticcheck_virus_scan | >>> | |
| 4 | build | NA | |
| 5 | smoke | NA | NA |


【自动化合入流水线失败】PR合并状态检查失败。
PR合并检查(can_merge_check)未通过:https://gitcode.com/HiSpark/mindspore-lite/merge_requests/11。
PR的CI状态(如流水线状态信息,代码评审,评审意见状态,保护分支未设置合并权限等)检查未通过:https://gitcode.com/HiSpark/mindspore-lite/merge_requests/11。


门禁执行成功,请到openxinhuo查看:https://xinhuo.developers.hisilicon.com/openxinhuoWeb/#/CodeAccess/codeAccessDetail/18030
| # | check type | result | detail |
|---|---|---|---|
| 1 | staticcheck_codecheck | >>> | |
| 2 | staticcheck_sca_scan | >>> | |
| 3 | staticcheck_virus_scan | >>> | |
| 4 | build | NA | |
| 5 | smoke | NA | NA |


HiSpark.AI Repo Sync 2026-08-07