# 分类器 本示例通过ResNet50模型说明如何使用MIGraphX Python API进行分类模型的推理,包括预处理、推理并获取推理结果。 ## 模型简介 本示例使用了经典的ResNet50模型,onnx文件在Resource/Models/文件夹下,模型结构可以通过netron (https://netron.app/) 查看,该模型的输入shape为[1,3,224,224] ,数据排布为NCHW。 ​ ## 预处理 在将数据输入到模型之前,需要对图像做如下预处理操作: - 图像格式转换,将BGR转换为RGB - 调整图像大小,使短边为 256,长边等比例缩放 - 裁剪图像,在中心窗口位置裁剪出224x224大小的图像 - normalize操作,对图像减均值再除方差 - 调整输入数据的尺寸为(1, 3, 224, 224) 本示例代码采用了OpenCV实现了预处理操作: ```python def Preprocessing(pathOfImage): image = cv2.imread(pathOfImage, cv2.IMREAD_COLOR) # 转换为RGB格式 image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) # 调整大小,保持长宽比 ratio = float(256) / min(image.shape[0], image.shape[1]) if image.shape[0] > image.shape[1]: new_size = [int(round(ratio * image.shape[0])), 256] else: new_size = [256, int(round(ratio * image.shape[1]))] image = np.array(cv2.resize(image, (new_size[1],new_size[0]))) # w h 格式 # 裁剪中心窗口 h, w, c = image.shape start_x = w//2 - 224//2 start_y = h//2 - 224//2 image = image[start_y:start_y+224, start_x:start_x+224, :] # transpose image = image.transpose(2, 0, 1) # 将输入数据转换为float32 img_data = image.astype('float32') # normalize mean_vec = np.array([123.675, 116.28, 103.53]) stddev_vec = np.array([58.395, 57.12, 57.375]) norm_img_data = np.zeros(img_data.shape).astype('float32') for i in range(img_data.shape[0]): norm_img_data[i,:,:] = (img_data[i,:,:] - mean_vec[i]) / stddev_vec[i] # 调整输入数据的尺寸 norm_img_data = norm_img_data.reshape(1, 3, 224, 224).astype('float32') return norm_img_data ``` ## 量化 该示例工程提供了FP16和INT8两种量化方法,可以根据选项设置是否需要量化: ```python use_int8 = False // 设置为True时,开启INT8量化 use_fp16 = False // 设置为True时,开启FP16量化 ``` ### FP16量化 使用FP16模式只需要在编译前调用migraphx.quantize_fp16() 即可。 ```python if __name__ == '__main__': ... if use_fp16: migraphx.quantize_fp16(model) ... ``` ### INT8量化 使用INT8模式需要提供量化校准数据,MIGraphX采用线性量化算法,通过校准数据计算量化参数并生成量化模型。为了保证量化精度,一般使用测试集或验证集中的数据作为校准数据。 ```python if __name__ == '__main__': ... if use_int8: dic = dict() # 创建字典 testofImage = "../Resource/Images/ImageNet_test.jpg" # 提供的量化校准数据 testimage = Preprocessing(testofImage) dic[inputName] = migraphx.argument(testimage) # 创建量化数据 calibration = [dic] # INT8量化 migraphx.quantize_int8(model, migraphx.get_target("gpu"), calibration) ... ``` ## 推理 完成预处理后,就可以执行推理了: ```python if __name__ == '__main__': ... # 预处理 pathOfImage ="../Resource/Images/ImageNet_01.jpg" image = Preprocessing(pathOfImage) # 推理 results = model.run({inputName: image}) # 推理结果,list类型 # 获取输出节点属性 result=results[0] # 获取第一个输出节点的数据,migraphx.argument类型 outputShape=result.get_shape() # 输出节点的shape,migraphx.shape类型 outputSize=outputShape.lens() # 每一维大小,维度顺序为(N,C,H,W),list类型 numberOfOutput=outputShape.elements() # 输出节点元素的个数 # 获取分类结果 print(np.array(result)) ``` - Preprocessing()函数返回输入数据(numpy类型),然后通过{inputName: migraphx.argument(image)}构造一个字典输入模型执行推理,如果模型有多个输入,则在字典中需要添加多个输入数据。 - model.run()返回模型的推理结果,返回结果是一个list类型,results[0]表示第一个输出节点的输出,是一个migraphx.argument类型,由于示例模型只有一个输出节点,所以results[0]对应resnetv24_dense0_fwd节点。最后,通过np.array(result)获取分类结果。