YOLO-v7转TensorFlow时,如何正确输出标量值?
问题描述
尝试修改YOLO-v7模型输出,添加表示边界框数量的标量输出张量,但转换为TensorFlow时收到警告:
WARNING: The numpy array (ndarray) cannot be specified as an output layer. Therefore, the tool outputs a sequentially numbered .npy binary file. .npy_file_path: tf_output/0.npy
复现步骤
- 使用
onnx_graphsurgeon修改PyTorch模型输出,代码如下:
num_boxes_int = gs.Variable(name='num_boxes_int', dtype=np.int64) num_boxes_out = gs.Variable(name='num_boxes_out', dtype=np.float32) num_boxes_node = gs.Node(op="Shape", inputs=[bbox_out], outputs=[num_boxes_int], attrs={ 'start':1,'end':2}) graph.nodes.append(num_boxes_node) num_boxes_cast_node = gs.Node(op="Cast", inputs=[num_boxes_int], outputs=[num_boxes_out], attrs={'to':int(onnx.TensorProto.FLOAT)}) graph.nodes.append(num_boxes_cast_node) ... graph.outputs = [num_boxes_out, ...]
- 执行命令转换为OpenVINO格式:
!mo --input_model {onnx_model_path} --input_shape [1,3,{input_height},{input_width}] --output_dir {openvino_dir}
经netron.app验证显示正常。
- 执行命令转换为TensorFlow:
!openvino2tensorflow \ --model_path {openvino_dir}/{openvino_filename} \ --model_output_path {tf_output_dir} \ --weight_replacement_config {weight_replacement_config_path} \ --non_verbose \ --output_saved_model \ --output_no_quant_float32_tflite \ --output_float16_quant_tflite \ --output_full_integer_quant_tflite \ --output_dynamic_range_quant_tflite
- 收到上述警告信息,且在netron.app中查看生成的.tflite文件时,其余输出正常,但缺失
num_detections输出。
请问正确输出标量值的方法是什么?
解决方案
问题根源在于TensorFlow/TFLite不支持纯标量(0维张量)作为模型输出,openvino2tensorflow工具会将这类输出导出为单独的.npy文件而非包含在模型中。要解决这个问题,需要把标量输出转换为形状为[1]的1维张量,具体修改步骤如下:
1. 修改ONNX GraphSurgeon代码,添加Reshape节点
在原有的Cast节点之后,添加一个Reshape节点,把标量张量转换成形状为[1]的1维张量:
# 定义Reshape的目标形状:形状为[1]的常量张量 num_boxes_shape = gs.Constant(name="num_boxes_shape", values=np.array([1], dtype=np.int64)) # 定义Reshape后的输出变量 num_boxes_final = gs.Variable(name='num_boxes_final', dtype=np.float32, shape=(1,)) # 创建Reshape节点 num_boxes_reshape_node = gs.Node(op="Reshape", inputs=[num_boxes_out, num_boxes_shape], outputs=[num_boxes_final]) graph.nodes.append(num_boxes_reshape_node) # 更新模型输出为Reshape后的张量 graph.outputs = [num_boxes_final, ...] # 替换原来的num_boxes_out
2. 重新导出ONNX并转换格式
- 重新运行修改后的ONNX GraphSurgeon代码,导出新的ONNX模型
- 再次执行OpenVINO转换命令,之后用
openvino2tensorflow转换为TensorFlow/TFLite格式
3. 验证输出
转换完成后,在netron.app中查看.tflite文件,num_boxes_final(或你自定义的输出名)会作为1维张量存在于输出列表中,同时不会再出现导出.npy文件的警告。
补充说明
如果后续需要在推理时获取标量值,只需从形状为[1]的张量中取出唯一元素即可(比如在TensorFlow中用tf.squeeze()或直接索引[0])。
内容的提问来源于stack exchange,提问作者Hui Liu
相关产品推荐
相关产品推荐

