Skip to content

7. SigmaStar后处理模块

7.1.模块介绍

SigmaStar后处理模块位置在SGS_IPU_SDK/Scripts/postprocess 。 该模块主要以TFLitePostProcess类实现了一套生成TFLite Flatbuffer的API和一个检测网络后处理BBOX的通用生成方法。 使用该模块时,先根据后处理方法编写python后处理文件,生成独立的后处理模型文件,再使用网络连接程序将Backbone网络模型和后处理模型连接成一个网络模型文件。 编写的python文件可参考SGS_IPU_SDK/Scripts/postprocess/postprocess_method文件夹下的示例。 编写完成后,生成方法:

  1. 编写文件保存在SGS_IPU_SDK/Scripts/postprocess/postprocess_method,在SGS_IPU_SDK/Scripts/postprocess/postprocess_method/__ini__.py中添加刚刚保存的文件名称,以caffe_yolo_v2_postprocess.py文件为例,然后在目录SGS_IPU_SDK/Scripts/postprocess/处输入命令:

    python3 postprocess.py -n caffe_yolo_v2_postprocess
    

  2. 编写后处理网络python文件,运行postprocess.py时,-n/--model_name参数给定编写的后处理python文件路径。 连接网络程序在SGS_IPU_SDK/bin/concat_net,后处理网络的输入名称在设置时需与Backbone网络输出的名称相符,否则在连接网络模型时会发生错误。

concat_net的参数说明如下:

--mode:网络连接模式:concat或append。连接Backbone网络与后处理网络请使用append模式。

--input_config:input_config.ini文件,需使用完整网络的配置文件。完整网络的配置文件与Backbone网络的配置文件仅在outputs的名称不同,其余设置应完全一致。

--model1:Backbone网络模型sim路径。

--model2:后处理网络模型sim路径。

--output:合成网络模型的输出路径。

以下章节详细介绍封装好的后处理流程和自定义后处理流程的python文件编写,用以生成后处理网络模型文件。


7.2. bbox坐标解码模块使用

为方便使用,Sigmastar分析了SSD、YOLOv1、YOLOv2、YOLOv3等网络的后处理,针对bbox坐标的提取已经抽象出一套解码流程,不同网络在结构上一样,不同点在部分的算子使用和anchor参数的传入。因此可以通过配置config字典变量,即可生成bbox坐标的后处理网络模型。bbox坐标解码网络如下图所示:

box_process

生成bbox坐标解码网络模型,可修改config字典变量,该变量参数意义如下表所示:

参数名 参数类型 描述信息
sh ape [ int] bbox tensor的形状,比如 [1,837]
tx_func (tflite.BuiltinOperator, str) 1. tflite.BuiltinOperator为tflite内置算子类型; 2. str为字符串x_scale或者None:当1中指定的算子为单口算子时str填None,如果为双口算子,这里填x_scale并在成员变量x_scale中指定其值。
ty_func (tflite.BuiltinOperator, str) 1. tflite.BuiltinOperator为tflite内置算子类型; 2. str为字符串y_scale或者None:当1中指定的算子为单口算子时str填None,如果为双口算子,这里填y_scale并在成员变量y_scale中指定其值。
tw_func (tflite.BuiltinOperator, str) 1. tflite.BuiltinOperator为tflite内置算子类型; 2. str为字符串w_scale或者None:当1中指定的算子为单口算子时str填None,如果为双口算子,这里填w_scale并在成员变量w_scale中指定其值。
th_func (tflite.BuiltinOperator, str) 1. tflite.BuiltinOperator为tflite内置算子类型; 2. str为字符串h_scale或者None:当1中指定的算子为单口算子时str填None,如果为双口算子,这里填h_scale并在成员变量h_scale中指定其值。
x_scale float tx_func[1]为x_scale时指定的值
y_scale float tx_func[1]为y_scale时指定的值
w_scale float tx_func[1]为w_scale时指定的值
h_scale float tx_func[1]为h_scale时指定的值
anchor_selector str constant或者为None 指定pw和ph是constant还是有pw_func和ph_func生成
pw [ float ] 如果anchor_selector为constant时pw指定为一个float列表
ph [ float ] 如果anchor_selector为constant时ph指定为一个float列表
ppw [ float ] 如果anchor_selector为constant时ppw指定为一个float列表
pph [ float ] 如果anchor_selector为constant时pph指定为一个float列表
px [ float ] px指定为一个float列表
py [ float ] py指定为一个float列表
sx [ float ] sx指定为一个float列表
sy [ float ] sy指定为一个float列表
sw [ float ] sw指定为一个float列表
sh [ float ] sh指定为一个float列表

7.3. 创建节点TFlite Flatbuffer 节点API

7.3.1. buildBuffer

buildBuffer(buffer_name, buffer_data=None)
创建一个buffer。

:param buffer_name:一个字符串用来在coding时标识buffer,不会存入模型内部。

:param buffer_data:默认如果创建的buffer是用于variable tensor使用,则使用默认None值即可。如果是常量tensor的buffer则传入data的字节流。

:return:返回编码后的偏移量


7.3.2. buildTensor

buildTensor(shape, name, buffer=0,type=tflite.TensorType.TensorType().FLOAT32)
创建一个tensor。

:param shape:[int] int列表标识tensor的形状

:param name:字符串标识创建tensor的名字

:param buffer:int类型的索引值,标识在buffer array中的index :param type:tensor类型tflite.TensorType,默认为FLOAT32

:return:返回创建的tensor在subgraph的tensor array中的index,如果是已经存在的tensor则直接返回index


7.3.3. buildOperatorCode

buildOperatorCode(opcode_name, builtin_code, custom_code=None)
创建或返回一个已经创建的OperatorCode。

:param opcode_name:一个字符串,是用户用来标识记录区分算子的名字,实作会保障同一类型的OperatorCode只有一个存在于OperatorCode array中。

:param builtin_code:tflite.BuiltinOperator类型,即内置算子类型

:param custom_code:用户指定的字符串客户标记符

:return:返回OperatorCode的index


7.3.4. buildOperator

buildOperator(op_code_name, input_names, output_names,builtin_options_type=None, builtin_options=None, custom_options=None, is_custom=False)
创建operator,创建的operator在subgraph中使用。

:param op_code_name:buildOperatorCode中指定的OperatorCode标识符,使用名字来获取返回OperatorCode的index

:param input_names:[str]输入tensor的名字列表

:param output_names:[str]输出tensor的名字列表

:param builtin_options_type:tflite.BuiltinOptions类型,如果需要指定必须的option参数,这里指定是哪一类算子的参数。

:param builtin_options:int类型,对应builtin_options_type的算子参数内容的flatbuffer的offset,使用如createReshapeOptions等API创建的flatbuffer。目前TFLitePostProcess.py只实现了少数几个option的flatbuffer encoding。如果有其他没有实现的可以参照createReshapeOptions实作新的方法。

:param custom_options:[byte] 用flexbuffer encoding后的bytearray。如果是custom算子,在这里指定参数,对应的算子解析自己的参数。

:param is_custom:是否为客制化算子,默认为False

:return:返回subgraph中operators的index。


7.3.5. buildSubGraph

buildSubGraph(input_tensor_names, output_tensor_names, subgraph_name)
创建一个subgraph,将创建的buffer一起编进一个subgraph。

:param input_tensor_names:[str]类型,subgraph的输入tensor名字列表,必须依据使用buildTensor创建过的tensor的名字

:param output_tensor_names:[str]类型,subgraph的输出tensor名字列表,必须依据使用buildTensor创建过的tensor的名字

:param subgraph_name:str类型,指定一个名字标识subgraph

:return:返回subgraph的flatbuffer offset


7.3.6. createModel

createModel(version, operator_codes, subgraphs, description, buffers, metadata_buffer=None)
将所有encoded data 编码成完整的tflite flatbuffer。

:param version:uint; tflite版本。传入3即可。

:param operator_codes:[OperatorCode]; OperatorCode列表,使用buildOperatorCode创建,保存在TFLitePostProcess.operator_codes中。

:param subgraphs:[SubGraph];SubGraph列表,保存在TFLitePostProcess.subgraphs中。

:param description:string;用户指定一个描述字符串。

:param buffers:[Buffer];buffer列表,使用buildBuffer创建,保存在TFLitePostProcess.buffers列表中。

:param metadata_buffer:[int];目前没使用到,传None。

:return:返回创建的完整tflite flatbuffer句柄


7.3.7. createFlexBuffer

createFlexBuffer(values)
OperatorCode类型为tflite.BuiltinOperator.BuiltinOperator().CUSTOM算子参数传递。

:param values:tuple类型的列表,tuple的类型为(str, int/float, str):

第一项为value名称,算子实作者使用这个名字来解析value

第二项为value,

第三项为value类型的字符串,标识第二项的类型,如果第二项为int 这里填'int';如果是float类型,这里填'float'。目前仅支持float和int类型。

:return:返回编码后的bytearray。

使用sample:

cus_options = [(b"input_coordinate_x1",0,"int"),
                (b"input_coordinate_y1",1,"int"),
                (b"input_coordinate_x2",2,"int"),
                (b"input_coordinate_y2",3,"int"),
                (b"nms_score_threshold",0.4,"float"),
                (b"nms_iou_threshold",0.45,"float")]
options = sgs_builder.createFlexBuffer(cus_options)

7.3.8. buildBoxDecoding

buildBoxDecoding(unpacked_box)
输入bbox坐标解码网络前,分离Backbone网络的输出bbox坐标。

:param unpacked_box:bbox的输入tensor名字列表,为四个tensor

:return:返回x1,y1,x2,y2 四个decoded tensor的名字列表。


7.4. SigmaStar定制后处理算子

SigmaStar定制的后处理算子OperatorCode类型为tflite.BuiltinOperator.BuiltinOperator().CUSTOM,因此需要使用createFlexBuffer的API来传递参数,参数传递必须使用三项的tuple类型且为(str, int/float, str)。


7.4.1. PostProcess_Unpack

PostProcess_Unpack算子目的是将Backbone网络的输出分离,支持最大分离出7个分支。 使用方法如下:

cus_options = [(b"x_offset",0,"int"), 
                (b"x_lengh",1,"int"), 
                (b"y_offset",1,"int"), 
                (b"y_lengh",1,"int"), 
                (b"w_offset",2,"int"), 
                (b"w_lengh",1,"int"), 
                (b"h_offset",3,"int"), 
                (b"h_lengh",1,"int"), 
                (b"confidence_offset",0,"int"), 
                (b"confidence_lengh",0,"int"), 
                (b"scores_offset",0,"int"), 
                (b"scores_lengh",0,"int"), 
                (b"max_score",0,"int")]
根据网络的不同,修改每行的第二个参数。如果该分支不需要,则对应的offset和lengh填0。

x_offset:分出坐标x偏移量

x_lengh:坐标x长度,一般为1

y_offset:分出坐标y偏移量

y_lengh:坐标y长度,一般为1

w_offset:分出坐标w偏移量

w_lengh:坐标w长度,一般为1

h_offset:分出坐标h偏移量

h_lengh:坐标h长度,一般为1

confidence_offset:分出confidence偏移量

confidence_lengh:confidence长度,一般为1

scores_offset:分出scores偏移量

scores_lengh:scores长度,为网络的分类数量。

max_score:一般为1

通过参数设置不同,结合bbox坐标解码模块,PostProcess_Unpack有如下后处理网络示例:


1.分离bbox坐标

Separating bbox coordinates


2.分离bbox坐标、confidence、scores、max_score

Separating bbox coordinates, confidence, scores, and max_score


7.4.2. TFLite_Detection_NMS

TFLite_Detection_NMS算子将NMS操作组合成为一个算子,与PostProcess_Unpack算子配合,最大支持7个输入,输出为4个或5个。 使用方法如下:

cus_options = [(b"input_coordinate_x1",1,"int"), 
                (b"input_coordinate_y1",0,"int"), 
                (b"input_coordinate_x2",3,"int"), 
                (b"input_coordinate_y2",2,"int"), 
                (b"input_class_idx",5,"int"), 
                (b"input_score_idx",4,"int"), 
                (b"input_confidence_idx",-1,"int"), 
                (b"input_facecoordinate_idx",-1,"int"), 
                (b"output_detection_boxes_idx",0,"int"), 
                (b"output_detection_classes_idx",1,"int"), 
                (b"output_detection_scores_idx",2,"int"), 
                (b"output_num_detection_idx",3,"int"), 
                (b"output_detection_boxes_index_idx",-1,"int"), 
                (b"nms",0,"float"), 
                (b"clip",0,"float"), 
                (b"max_detections",10,"int"), 
                (b"max_classes_per_detection",1,"int"), 
                (b"detections_per_class",1,"int"), 
                (b"num_classes",90,"int"), 
                (b"bmax_score",0,"int"), 
                (b"num_classes_with_background",1,"int"), 
                (b"nms_score_threshold",9.99999994e-09,"float"), 
                (b"nms_iou_threshold",0.600000024,"float")]
根据网络的不同,修改每行的第二个参数。如果该参数不需要,则对应参数填-1。

input_coordinate_x1:对应PostProcess_Unpack算子x_offset的序号。

input_coordinate_y1:对应PostProcess_Unpack算子y_offset的序号。

input_coordinate_x2:对应PostProcess_Unpack算子w_offset的序号。

input_coordinate_y2:对应PostProcess_Unpack算子h_offset的序号。

input_class_idx:对应类别的输入序号。

input_score_idx:对应PostProcess_Unpack算子score的序号。

input_confidence_idx:对应PostProcess_Unpack算子confidence的序号。

input_facecoordinate_idx:默认为-1。

output_detection_boxes_idx:输出检测bbox的坐标序号。

output_detection_classes_idx:输出对应检测的类别序号。

output_detection_scores_idx:输出对应检测的分值序号。

output_num_detection_idx:输出共检测到的目标个数序号。

output_detection_boxes_index_idx:输出检测到目标排序下标的序号。

nms:0为Fast NMS,1为Normal NMS。

clip:是否截断越界的bbox坐标值,1为截断,0为保留。

max_detections:最大输出目标个数。

max_classes_per_detection:默认为1。

detections_per_class:默认为1。

num_classes:网络模型类别数量(不包含背景,此选项仅为SSD后处理设置)。

bmax_score:对应PostProcess_Unpack算子max_score时,为1,否则为0。

num_classes_with_background:默认为1。

nms_score_threshold:NMS分数阈值。

nms_iou_threshold:NMS的IoU阈值。

Please Note:

  • TFLite_Detection_NMS算子最大支持24576个bbox输入。

7.4.2.1. 选择是否需要NMS输出index信息

NMS可以选择4个或5个输出,其中必选4个输出为:检测bbox坐标、检测类别、检测分值、检测个数,可选1个输出为:检测bbox对应的下标。 如果需要增加检测bbox对应的下标输出,按照如下方法修改后处理python文件。 以下示例以ssd_mobilenet_v1模型的后处理为例,完整代码详见

SGS_IPU_SDK/Scripts/postprocess/postprocess_method/ssd_mobilenet_v1_index_postprocess.py
创建“detectionIndex”Tensor,插在“numDetections”Tensor后面,红框内为添加内容:

sgs_builder.buildTensor(model_config["out_shapes"][3],"numDetections") 
nms_out_tensors.append("numDetections") 

sgs_builder.buildTensor(model_config["out_shapes"][4],"detectionIndex") 
nms_out_tensors.append("detectionIndex") 

cus_code = 'TFLite_Detection_NMS' 
sgs_builder.buildOperatorCode("SGS_nms",tflite.BuiltinOperator.BuiltinOperator().CUSTOM,cus_code)
修改TFLite_Detection_NMS算子参数,output_detection_boxes_index_idx填4:

cus_options = [(b"input_coordinate_x1",1,"int"), 
                (b"input_coordinate_y1",0,"int"), 
                (b"input_coordinate_x2",3,"int"), 
                (b"input_coordinate_y2",2,"int"), 
                (b"input_class_idx",5,"int"),
                (b"input_score_idx",4,"int"), 
                (b"input_confidence_idx",-1,"int"), 
                (b"input_facecoordinate_idx",-1,"int"), 
                (b"output_detection_boxes_idx",0,"int"), 
                (b"output_detection_classes_idx",1,"int"), 
                (b"output_detection_scores_idx",2,"int"), 
                (b"output_num_detection_idx",3,"int"),
                (b"output_detection_boxes_index_idx",4,"int"), 
                (b"nms",0,"float"), 
                (b"clip",0,"float"), 
                (b"max_detections",10,"int"), 
                (b"max_classes_per_detection",1,"int"), 
                (b"detections_per_class",1,"int"), 
                (b"num_classes",90,"int"), 
                (b"bmax_score",0,"int"), 
                (b"num_classes_with_background",1,"int"), 
                (b"nms_score_threshold",9.99999994e-09,"float"), 
                (b"nms_iou_threshold",0.600000024,"float")]
创建网络模型输出Tensor名称:

network_out_tensors = [] 
network_out_tensors.append("detectionBoxes") 
network_out_tensors.append("detectionClasses") 
network_out_tensors.append("detectionScores") 
network_out_tensors.append("numDetections") 
network_out_tensors.append("detectionIndex") 
sgs_builder.subgraphs.append(sgs_builder.buildSubGraph(model_config["input"],network_out_tensors,model_config["name"]))
修改模型配置参数,out_shapes增加detectionIndex的输出shape:

model_config = {"name":"ssdlite_mobilenet_v2",
                 "input" : ["Squeeze","convert_scores"],
                 "input_shape" : [[1,1917,4],[1,1917,91]],
                 "shape" : [1,1917],
                 "out_shapes" : [[1,10,4],[1,10],[1,10],[1],[1,10]]}
修改完成后,生成的后处理模型NMS输出就有5个输出。

Please Note:

  • 连接backbone网络时请先修改input_config.ini文件中outputs,因为多了一个输出Tensor,避免连接网络时发生错误。

7.5. 获取离线anchor数据

Caffe网络中如果PriorBox节点中数据是离线生成的,可以通过以下方法获取。 具体网络请参考SGS_Models/caffe/caffe_ssd_mobilenet_v1。 转换带PriorBox节点的backbone网络,使用Netron打开网络prototxt文件,如下图所示。

Offline Anchor

修改对应的input_config.ini文件和ConvertTool转换命令,有3个输出,生成backbone网络部分。 转换完成后,所有PriorBox节点生成为一个节点。使用Netron打开生成的backbone网络,先点击mbox_priorbox节点,再点击红框中的保存按钮,即可将anchor的数据保存为.npy文件。 在配置bbox坐标解码模块时,使用numpy.load读取.npy文件,配置好对应的变量。如果已有anchor数据,可以不用此方法,直接使用anchor数据。

npy anchor data

后处理python文件在编写时,增加模型配置的输入为3个输入,增加mbox_priorbox的shape,具体代码详见

SGS_IPU_SDK/Scripts/postprocess/postprocess_method/caffe_ssd_mobilenet_v1_postprocess.py

model_config = {"name":"caffe_ssd_mobilenet_v1", 
                "input" : ["mbox_loc","mbox_conf_softmax","mbox_priorbox"], 
                "input_shape" : [[1,1917,4],[1,1917,21],[1917,4]], 
                "shape" : [1,1917], 
                "out_shapes" : [[1,10,4],[1,10],[1,10],[1]]}

生成后处理模型后,使用concat_net工具连接会自动清除mbox_priorbox节点。


7.6. 举例使用

以下示例以caffe_yolo_v2模型的后处理为例,具体代码详见

SGS_IPU_SDK/Scripts/postprocess/postprocess_method/caffe_yolo_v2_postprocess.py

7.6.1. 创建一个TFLitePostProcess实例

首先配置config字典变量,根据bbox坐标解码的实际计算方法配置config的各个参数。

配置参数:

box_num = 5 
side_x = 13 
side_y = 13 
ppw = anchor.ones(845) 
px = anchor.index_div_linear(1,1,0,box_num ,side_x,side_y) 
pph = anchor.ones(845) 
py = anchor.index_div_linear(1,1,0,side_x*box_num,side_y,1) 
pw = anchor.ones(845) 
ph = anchor.ones(845) 
sx = anchor.ns(845,1.0/13) 
sy = anchor.ns(845,1.0/13) 
biases= [[1.3221,1.73145],[3.19275,4.00944],[5.05587,8.09892],[9.47112,4.84053],[11.2364,10.0071]] 
sw = [x[0]/(2*13) for x in biases ]*(13*13) 
sh = [x[1]/(2*13) for x in biases ]*(13*13)

配置config字典变量:

config = {"shape" : [1,845],
         "tx_func" : (tflite.BuiltinOperator.BuiltinOperator().LOGISTIC,None),                       
         "ty_func" : (tflite.BuiltinOperator.BuiltinOperator().LOGISTIC,None), 
         "tw_func" : (tflite.BuiltinOperator.BuiltinOperator().RESHAPE,None), 
         "th_func" : (tflite.BuiltinOperator.BuiltinOperator().RESHAPE,None),
         "x_scale" : 0.1, 
         "y_scale" : 0.1, 
         "w_scale" : 1, 
         "h_scale" : 1, 
         "anchor_selector" : "constant", 
         "pw" : pw, 
         "ph" : ph, 
         "pw_func" : (None,None), 
         "ph_func" : (None,None), 
         "ppw" : ppw, 
         "px" : px, 
         "pph" : pph, 
         "py" : py, 
         "sx" : sx, 
         "sy" : sy, 
         "sw" : sw, 
         "sh" : sh
         }

创建TFLitePostProcess实例:

yolov2 = TFLitePostProcess(config)


7.6.2. 创建常量Tensor

将float列表pack成bytearray

py_vector=[] 
for value in self.py: 
    py_vector += bytearray(struct.pack("f", value))
使用bytearray创建常量buffer

self.buildBuffer("py_buffer",py_vector)
使用常量buffer创建tensor
self.buildTensor([len(self.py)],"py_tensor",self.getBufferByName("py_buffer"))


7.6.3. 创建一个算子

创建一个双口Mul算子:

score1_out_tensors = [] 
score1_in_tensors = [] 
score1_in_tensors.append("confidence_tensor") 
score1_in_tensors.append("score0_tensor") 
sgs_builder.buildTensor([1,845], "SGS_score1")
score1_out_tensors.append("SGS_score1") 
sgs_builder.buildOperatorCode("SGS_score_mul",tflite.BuiltinOperator.BuiltinOperator().MUL) 
sgs_builder.buildOperator("SGS_score_mul",score1_in_tensors,score1_out_tensors)

创建一个Reshape算子,需要创建常量Tensor:

reshape_out_shape1 = [1,4695,4] 
reshape_out_tensors1 = [] 
reshape_in_tensors1 = [] 
sgs_builder.buildBuffer('NULL') 
sgs_builder.buildTensor([1,4695,1,4], '283_in') 
reshape_in_tensors1.append('283_in') 
reshape_vector1 = [] 
for value in reshape_out_shape1: 
    reshape_vector1 += bytearray(struct.pack("i", value)) 
sgs_builder.buildBuffer("reshape_vector1",reshape_vector1) 
sgs_builder.buildTensor([len(reshape_out_shape1)],"reshape_shape1",sgs_builder.getBufferByName("reshape_vector1"),tflite.TensorType.TensorType().INT32) 
reshape_in_tensors1.append("reshape_shape1") 
sgs_builder.buildTensor(reshape_out_shape1,"reshape_tensor1") 
reshape_out_tensors1.append("reshape_tensor1") 
sgs_builder.buildOperatorCode("SGS_reshape1",tflite.BuiltinOperator.BuiltinOperator().RESHAPE) 
reshape_newshape1 = sgs_builder.createReshapeOptions(reshape_out_shape1) 
sgs_builder.buildOperator("SGS_reshape1",reshape_in_tensors1, reshape_out_tensors1,tflite.BuiltinOptions.BuiltinOptions().ReshapeOptions,reshape_newshape1)

7.6.4. 创建客制化算子

创建OperatorCode

sgs_builder.buildOperatorCode("SGS_nms",tflite.BuiltinOperator.BuiltinOperator().CUSTOM,cus_code) 
cus_options = [(b"input_coordinate_x1",0,"int"), 
                (b"input_coordinate_y1",1,"int"), 
                (b"input_coordinate_x2",2,"int"), 
                (b"input_coordinate_y2",3,"int"), 
                (b"input_class_idx",6,"int"), 
                (b"input_score_idx",5,"int"), 
                (b"input_confidence_idx",4,"int"), 
                (b"input_facecoordinate_idx",-1,"int"), 
                (b"output_detection_boxes_idx",0,"int"), 
                (b"output_detection_classes_idx",1,"int"), 
                (b"output_detection_scores_idx",2,"int"),
                (b"output_num_detection_idx",3,"int"), 
                (b"output_detection_boxes_index_idx ",-1,"int"), 
                (b"nms",0,"int"), 
                (b"clip",0,"int"), 
                (b"max_detections",100,"int"), 
                (b"max_classes_per_detection",1,"int"), 
                (b"detections_per_class",1,"int"),
                 (b"num_classes",20,"int"), 
                (b"bmax_score",1,"int"), 
                (b"num_classes_with_background",1,"int"), 
                (b"nms_score_threshold",0.4,"float"), 
                (b"nms_iou_threshold",0.45,"float")]

创建flexbuffer

options = sgs_builder.createFlexBuffer(cus_options)

使用flexbuffer创建Operator

sgs_builder.buildOperator("SGS_nms", nms_in_tensors, nms_out_tensors, None, None, options)


7.6.5. 创建model并保存为模型文件

创建subgraph

sgs_builder.subgraphs.append(sgs_builder.buildSubGraph(['conv23'],nms_out_tensors,'caffe_yolo_v2'))

创建model

sgs_builder.model = sgs_builder.createModel(3, sgs_builder.operator_codes, 
sgs_builder.subgraphs, 'caffe_yolo_v2', sgs_builder.buffers) 
file_identifier = b'TFL3' 
sgs_builder.builder.Finish(sgs_builder.model, file_identifier)

输出模型

buf = sgs_builder.builder.Output()

保存模型到文件

outfilename = 'caffe_yolo_v2_postprocess.sim' 
with open(outfilename, 'wb') as f:
    f.write(buf)