请解析这段代码: void ConvOnnx::run(NodeDef *dst_node, const onnx::NodeProto *src_node, onnx::GraphProto *src_graph, std::map<std::string, onnx::TensorProto> &weights) { VLOG(0) << "run Converter, op type is Conv" << "[" << src_node->op_type() << "]"; std::map<std::string, const onnx::NodeProto *> all_node_map; for (int i = 0; i < src_graph->node_size(); i++) { const onnx::NodeProto &node = src_graph->node(i); all_node_map[node.name()] = &node; } onnx::AttributeProto value; if (jz_onnx::find_attr_value(*src_node, "rate", value)) { std::vector<int64> tmp; tmp.resize(value.ints_size()); for (int j = 0; j < value.ints_size(); j++) { tmp[j] = value.ints(j); } add_node_attr("rate", tmp, dst_node); } if (jz_onnx::find_attr_value(*src_node, "strides", value)) { const int num_stride = value.ints_size() + 2; std::vector<int64> tmp(num_stride, 1); for (int j = 0; j < value.ints_size(); j++) { tmp[j + 1] = value.ints(j); } add_node_attr("strides", tmp, dst_node); } if (jz_onnx::find_attr_value(*src_node, "dilations", value)) { const int num_dilation = value.ints_size() + 2; std::vector<int64> tmp(num_dilation, 1); for (int j = 0; j < value.ints_size(); j++) { tmp[j + 1] = value.ints(j); } add_node_attr("dilations", tmp, dst_node); } if (jz_onnx::find_attr_value(*src_node, "auto_pad", value)) { const auto &paddingType = value.s(); if (paddingType == "NOTSET" || paddingType == "VALID") { add_node_attr("padding", "VALID", dst_node); } else if (paddingType == "SAME_UPPER" || paddingType == "SAME_LOWER") { if (paddingType == "SAME_LOWER") { VLOGW << "The padding mode in ONNX SAME_LOWER and Magik SAME is not exactly the same!"; } add_node_attr("padding", "SAME", dst_node); } else { VLOGEC(MAGIK_CONVERT, MAGIK_CODE_NOT_SUPPORT_ATTRIBUTE) << "Auto type '" << paddingType << "' is not supported!"; } } if (jz_onnx::find_attr_value(*src_node, "pads", value)) { add_node_attr("padding", "VALID", dst_node); auto pad_values = value.ints(); if (pad_values.size() == 4) { // HWHW => HHWW std::vector<int64> pads{value.ints(0), value.ints(2), value.ints(1), value.ints(3)}; add_node_attr("pads", pads, dst_node); } else if (pad_values.size() == 2) { std::vector<int64> pads{value.ints(0), value.ints(1)}; add_node_attr("pads", pads, dst_node); } else { VLOGEC(MAGIK_CONVERT, MAGIK_CODE_NOT_MATCHED_SIZE) << "Conv pad size error! (node: " << src_node->name() << ", " << "pads size" << pad_values.size() << ")"; } }
时间: 2025-06-27 09:12:16 浏览: 17
这段代码的主要功能是对 ONNX 模型中的卷积层(Convolution Layer)进行属性转换,将原始 ONNX 节点的属性映射到目标节点上。以下是逐步解析的内容:
---
### **函数基本信息**
- **函数名**: `ConvOnnx::run`
- **参数列表**:
- `NodeDef *dst_node`: 目标节点,用于存储转换后的结果。
- `const onnx::NodeProto *src_node`: 来源节点,表示从 ONNX 中读取的原始卷积层信息。
- `onnx::GraphProto *src_graph`: 整个 ONNX 图形的原型数据。
- `std::map<std::string, onnx::TensorProto> &weights`: 存储权重等张量的信息。
---
### **核心逻辑分解**
#### 1. 初始化日志输出
```cpp
VLOG(0) << "run Converter, op type is Conv"
<< "[" << src_node->op_type() << "]";
```
- 这一行通过调试日志确认当前正在处理的操作符类型是否为 `Conv` 卷积运算符。
- 日志记录了操作符的实际名称 `src_node->op_type()`。
---
#### 2. 构建所有节点的地图索引
```cpp
std::map<std::string, const onnx::NodeProto *> all_node_map;
for (int i = 0; i < src_graph->node_size(); i++) {
const onnx::NodeProto &node = src_graph->node(i);
all_node_map[node.name()] = &node;
}
```
- 遍历整个图形的所有节点,将其按名字存入 `all_node_map` 映射表中。
- 后续可能会用这张地图来查找其他相关的节点。
---
#### 3. 处理特定属性
##### a. 提取并设置 `rate` 属性
```cpp
if (jz_onnx::find_attr_value(*src_node, "rate", value)) {
std::vector<int64> tmp;
tmp.resize(value.ints_size());
for (int j = 0; j < value.ints_size(); j++) {
tmp[j] = value.ints(j);
}
add_node_attr("rate", tmp, dst_node);
}
```
- 如果原节点存在名为 `"rate"` 的属性,则提取其整数值数组,并添加到目标节点的 `"rate"` 属性中。
---
##### b. 提取并设置 `strides` 属性
```cpp
if (jz_onnx::find_attr_value(*src_node, "strides", value)) {
const int num_stride = value.ints_size() + 2;
std::vector<int64> tmp(num_stride, 1);
for (int j = 0; j < value.ints_size(); j++) {
tmp[j + 1] = value.ints(j);
}
add_node_attr("strides", tmp, dst_node);
}
```
- 对于步幅(`strides`),先构造一个长度为 `(num_stride)`、初始值全为 `1` 的向量。
- 将原始的步幅值填充到 `[1..n+1]` 区间内,最后保存为目标节点的 `"strides"` 属性。
---
##### c. 提取并设置 `dilations` 属性
```cpp
if (jz_onnx::find_attr_value(*src_node, "dilations", value)) {
const int num_dilation = value.ints_size() + 2;
std::vector<int64> tmp(num_dilation, 1);
for (int j = 0; j < value.ints_size(); j++) {
tmp[j + 1] = value.ints(j);
}
add_node_attr("dilations", tmp, dst_node);
}
```
- 填充过程类似于步幅的处理方式,只是这里是针对膨胀系数(`dilations`)。
---
##### d. 设置自动填充模式(`auto_pad`)
```cpp
if (jz_onnx::find_attr_value(*src_node, "auto_pad", value)) {
const auto &paddingType = value.s();
if (paddingType == "NOTSET" || paddingType == "VALID") {
add_node_attr("padding", "VALID", dst_node);
} else if (paddingType == "SAME_UPPER" || paddingType == "SAME_LOWER") {
if (paddingType == "SAME_LOWER") {
VLOGW << "The padding mode in ONNX SAME_LOWER and Magik SAME is not exactly the same!";
}
add_node_attr("padding", "SAME", dst_node);
} else {
VLOGEC(MAGIK_CONVERT, MAGIK_CODE_NOT_SUPPORT_ATTRIBUTE)
<< "Auto type '" << paddingType << "' is not supported!";
}
}
```
- 根据 `"auto_pad"` 的值决定目标节点的填充模式:
- 若为 `"VALID"` 或未设置,默认采用无填充的方式;
- 若为 `"SAME_UPPER"` 或 `"SAME_LOWER"`,统一转化为 `"SAME"` 并发出警告提示;
- 其他未知类型的填充方式会被标记为错误。
---
##### e. 设置显式的填充大小(`pads`)
```cpp
if (jz_onnx::find_attr_value(*src_node, "pads", value)) {
add_node_attr("padding", "VALID", dst_node);
auto pad_values = value.ints();
if (pad_values.size() == 4) {
// HWHW => HHWW
std::vector<int64> pads{value.ints(0), value.ints(2), value.ints(1), value.ints(3)};
add_node_attr("pads", pads, dst_node);
} else if (pad_values.size() == 2) {
std::vector<int64> pads{value.ints(0), value.ints(1)};
add_node_attr("pads", pads, dst_node);
} else {
VLOGEC(MAGIK_CONVERT, MAGIK_CODE_NOT_MATCHED_SIZE)
<< "Conv pad size error! (node: " << src_node->name() << ", "
<< "pads size" << pad_values.size() << ")";
}
}
```
- 当检测到有明确指定的填充大小时:
- 如果尺寸为 4,则按照 `(H_start, W_start, H_end, W_end)` 的顺序调整为 `(H_start, H_end, W_start, W_end)` 形式;
- 如果尺寸为 2,则保持不变;
- 其他情况视为非法输入并报错。
---
### **总结**
该代码实现了对 ONNX 模型中卷积层属性的一次全面转换,包括但不限于步幅、填充模式、膨胀因子等内容。它通过一系列条件分支完成了对各种特殊情况的兼容性和错误处理。
---
###
阅读全文
相关推荐
















