[{"data":1,"prerenderedAt":229},["ShallowReactive",2],{"content-query-Q6UaTstuBg":3},{"_path":4,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":8,"description":9,"date":10,"cover":11,"type":12,"category":13,"body":14,"_type":223,"_id":224,"_source":225,"_file":226,"_stem":227,"_extension":228},"/technology-blogs/zh/3386","zh",false,"","基于MindSpore案例的香橙派开发板离线推理实践--使用FCN实现图像语义分割","样例介绍","2024-08-20","https://obs-mindspore-file.obs.cn-north-4.myhuaweicloud.com/file/2024/11/28/c7014cf9470540bc863e7b06f48180fc.png","technology-blogs","实践",{"type":15,"children":16,"toc":213},"root",[17,25,29,35,40,45,50,60,68,73,80,88,94,102,108,113,121,127,135,141,149,155,160,165,173,178,183],{"type":18,"tag":19,"props":20,"children":22},"element","h1",{"id":21},"基于mindspore案例的香橙派开发板离线推理实践-使用fcn实现图像语义分割",[23],{"type":24,"value":8},"text",{"type":18,"tag":19,"props":26,"children":27},{"id":9},[28],{"type":24,"value":9},{"type":18,"tag":30,"props":31,"children":32},"p",{},[33],{"type":24,"value":34},"功能：使用FCN模型对输入图片进行语义分割。 样例输入：原始图片。 样例输出：与输入大小相同的图像，输出图像的每个像素对应了输入图像每个像素的类别。",{"type":18,"tag":19,"props":36,"children":38},{"id":37},"前期准备",[39],{"type":24,"value":37},{"type":18,"tag":30,"props":41,"children":42},{},[43],{"type":24,"value":44},"基础镜像的样例目录中已包含转换后的om模型以及测试图片，如果直接运行，可跳过此步骤。如果需要重新转换模型，可参考如下步骤：",{"type":18,"tag":30,"props":46,"children":47},{},[48],{"type":24,"value":49},"利用atc工具将原始模型转换为om模型，转换命令如下：",{"type":18,"tag":51,"props":52,"children":54},"pre",{"code":53},"atc --model=FCN8s.onnx --framework=5 --output=FCN8s --input_format=NCHW   --log=error --soc_version=Ascend310B4\n",[55],{"type":18,"tag":56,"props":57,"children":58},"code",{"__ignoreMap":7},[59],{"type":24,"value":53},{"type":18,"tag":51,"props":61,"children":63},{"code":62},"其中各个参数具体含义如下：\n* --output_type：指定网络输出数据类型。\n* --input_shape：模型的输入节点名称和形状。\n* --input_format：输入Tensor的内存排列方式。\n* --output：输出的模型文件路径。\n* --soc_version：昇腾AI处理器型号。\n* --insert_op_conf：插入算子的配置文件路径与文件名，例如aipp预处理算子。\n* --framework：原始框架类型,  0: Caffe, 1: MindSpore, 3: TensorFlow, 5: ONNX。\n* --save_original_model：转换后是否保留原始模型文件。\n* --model：原始模型文件路径。\n* --precision_mode：选择算子精度模式。   \n",[64],{"type":18,"tag":56,"props":65,"children":66},{"__ignoreMap":7},[67],{"type":24,"value":62},{"type":18,"tag":19,"props":69,"children":71},{"id":70},"模型推理实现",[72],{"type":24,"value":70},{"type":18,"tag":74,"props":75,"children":77},"h3",{"id":76},"_1-导入三方库",[78],{"type":24,"value":79},"1. 导入三方库",{"type":18,"tag":51,"props":81,"children":83},{"code":82},"import os\nimport cv2\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport mindspore.dataset as ds\n\nimport acl\nimport acllite_utils as utils\nfrom acllite_model import AclLiteModel\nfrom acllite_resource import resource_list\n",[84],{"type":18,"tag":56,"props":85,"children":86},{"__ignoreMap":7},[87],{"type":24,"value":82},{"type":18,"tag":74,"props":89,"children":91},{"id":90},"_2-定义acllite资源初始化与去初始化类",[92],{"type":24,"value":93},"2. 定义acllite资源初始化与去初始化类",{"type":18,"tag":51,"props":95,"children":97},{"code":96},"class AclLiteResource:\n    \"\"\"\n    AclLiteResource\n    \"\"\"\n    def __init__(self, device_id=0):\n        self.device_id = device_id\n        self.context = None\n        self.stream = None\n        self.run_mode = None\n        \n    def init(self):\n        \"\"\"\n        init resource\n        \"\"\"\n        print(\"init resource stage:\")\n        ret = acl.init()\n\n        ret = acl.rt.set_device(self.device_id)\n        utils.check_ret(\"acl.rt.set_device\", ret)\n\n        self.context, ret = acl.rt.create_context(self.device_id)\n        utils.check_ret(\"acl.rt.create_context\", ret)\n\n        self.stream, ret = acl.rt.create_stream()\n        utils.check_ret(\"acl.rt.create_stream\", ret)\n\n        self.run_mode, ret = acl.rt.get_run_mode()\n        utils.check_ret(\"acl.rt.get_run_mode\", ret)\n\n        print(\"Init resource success\")\n\n    def __del__(self):\n        print(\"acl resource release all resource\")\n        resource_list.destroy()\n        if self.stream:\n            print(\"acl resource release stream\")\n            acl.rt.destroy_stream(self.stream)\n\n        if self.context:\n            print(\"acl resource release context\")\n            acl.rt.destroy_context(self.context)\n\n        print(\"Reset acl device \", self.device_id)\n        acl.rt.reset_device(self.device_id)\n        print(\"Release acl resource success\")\n",[98],{"type":18,"tag":56,"props":99,"children":100},{"__ignoreMap":7},[101],{"type":24,"value":96},{"type":18,"tag":74,"props":103,"children":105},{"id":104},"_3-数据预处理",[106],{"type":24,"value":107},"3. 数据预处理",{"type":18,"tag":30,"props":109,"children":110},{},[111],{"type":24,"value":112},"由于PASCAL VOC 2012数据集中图像的分辨率大多不一致，无法放在一个tensor中，故输入前需做标准化处理",{"type":18,"tag":51,"props":114,"children":116},{"code":115},"class SegDataset:\n    def __init__(self,\n                 image_mean,\n                 image_std,\n                 data_file='',\n                 batch_size=32,\n                 crop_size=512,\n                 max_scale=2.0,\n                 min_scale=0.5,\n                 ignore_label=255,\n                 num_classes=21,\n                 num_readers=2,\n                 num_parallel_calls=4):\n\n        self.data_file = data_file\n        self.batch_size = batch_size\n        self.crop_size = crop_size\n        self.image_mean = np.array(image_mean, dtype=np.float32)\n        self.image_std = np.array(image_std, dtype=np.float32)\n        self.max_scale = max_scale\n        self.min_scale = min_scale\n        self.ignore_label = ignore_label\n        self.num_classes = num_classes\n        self.num_readers = num_readers\n        self.num_parallel_calls = num_parallel_calls\n        max_scale > min_scale\n\n    def preprocess_dataset(self, image, label):\n        image_out = cv2.imdecode(np.frombuffer(image, dtype=np.uint8), cv2.IMREAD_COLOR)\n        label_out = cv2.imdecode(np.frombuffer(label, dtype=np.uint8), cv2.IMREAD_GRAYSCALE)\n        sc = np.random.uniform(self.min_scale, self.max_scale)\n        new_h, new_w = int(sc * image_out.shape[0]), int(sc * image_out.shape[1])\n        image_out = cv2.resize(image_out, (new_w, new_h), interpolation=cv2.INTER_CUBIC)\n        label_out = cv2.resize(label_out, (new_w, new_h), interpolation=cv2.INTER_NEAREST)\n\n        image_out = (image_out - self.image_mean) / self.image_std\n        out_h, out_w = max(new_h, self.crop_size), max(new_w, self.crop_size)\n        pad_h, pad_w = out_h - new_h, out_w - new_w\n        if pad_h > 0 or pad_w > 0:\n            image_out = cv2.copyMakeBorder(image_out, 0, pad_h, 0, pad_w, cv2.BORDER_CONSTANT, value=0)\n            label_out = cv2.copyMakeBorder(label_out, 0, pad_h, 0, pad_w, cv2.BORDER_CONSTANT, value=self.ignore_label)\n        offset_h = np.random.randint(0, out_h - self.crop_size + 1)\n        offset_w = np.random.randint(0, out_w - self.crop_size + 1)\n        image_out = image_out[offset_h: offset_h + self.crop_size, offset_w: offset_w + self.crop_size, :]\n        label_out = label_out[offset_h: offset_h + self.crop_size, offset_w: offset_w+self.crop_size]\n        if np.random.uniform(0.0, 1.0) > 0.5:\n            image_out = image_out[:, ::-1, :]\n            label_out = label_out[:, ::-1]\n        image_out = image_out.transpose((2, 0, 1))\n        image_out = image_out.copy()\n        label_out = label_out.copy()\n        label_out = label_out.astype(\"int32\")\n        return image_out, label_out\n\n    def get_dataset(self):\n        ds.config.set_numa_enable(True)\n        dataset = ds.MindDataset(self.data_file, columns_list=[\"data\", \"label\"],\n                                 shuffle=True, num_parallel_workers=self.num_readers)\n        transforms_list = self.preprocess_dataset\n        dataset = dataset.map(operations=transforms_list, input_columns=[\"data\", \"label\"],\n                              output_columns=[\"data\", \"label\"],\n                              num_parallel_workers=self.num_parallel_calls)\n        dataset = dataset.shuffle(buffer_size=self.batch_size * 10)\n        dataset = dataset.batch(self.batch_size, drop_remainder=True)\n        return dataset\n",[117],{"type":18,"tag":56,"props":118,"children":119},{"__ignoreMap":7},[120],{"type":24,"value":115},{"type":18,"tag":74,"props":122,"children":124},{"id":123},"_4-前处理推理后处理所需要的函数",[125],{"type":24,"value":126},"4. 前处理、推理、后处理所需要的函数",{"type":18,"tag":51,"props":128,"children":130},{"code":129},"# 定义处理数据集的参数\nIMAGE_MEAN = [103.53, 116.28, 123.675]\nIMAGE_STD = [57.375, 57.120, 58.395]\nDATA_FILE = \"data/VOC_mindrecord\"\n\n# 定义模型推理参数\neval_batch_size = 1\ncrop_size = 512\nmin_scale = 0.5\nmax_scale = 2.0\nignore_label = 255\nnum_classes = 21\n\n@utils.display_time\ndef pre_process():\n    \"\"\"\n    image preprocess\n    \"\"\"\n    # 实例化Dataset\n    dataset = SegDataset(image_mean=IMAGE_MEAN,\n                         image_std=IMAGE_STD,\n                         data_file=DATA_FILE,\n                         batch_size=eval_batch_size,\n                         crop_size=crop_size,\n                         max_scale=max_scale,\n                         min_scale=min_scale,\n                         ignore_label=ignore_label,\n                         num_classes=num_classes,\n                         num_readers=2,\n                         num_parallel_calls=4)\n\n    dataset = dataset.get_dataset()\n    return dataset\n\n# 图片推理\n@utils.display_time\ndef inference(dataset, model):\n    \"\"\"\n    model inference\n    \"\"\"\n    show_data = next(dataset.create_dict_iterator())\n    show_images = show_data[\"data\"].asnumpy()\n    mask_images = show_data[\"label\"].reshape([1, 512, 512])\n    show_images = np.clip(show_images, 0, 1)\n    result = model.execute([show_data[\"data\"].asnumpy(), ])\n    res = result[0].argmax(axis=1)\n    return res ,show_images\n\n@utils.display_time\ndef post_process(res, show_images):\n    \"\"\"\n    post process\n    \"\"\"\n    plt.figure(figsize=(8, 5))\n    plt.subplot(2, 1, 1)\n    plt.imshow(show_images[0].transpose(1, 2, 0))\n    plt.axis(\"off\")\n    plt.subplots_adjust(wspace=0.05, hspace=0.02)\n    plt.subplot(2, 1, 2)\n    plt.imshow(res.transpose(1, 2, 0))\n    plt.axis(\"off\")\n    plt.subplots_adjust(wspace=0.05, hspace=0.02)\n    plt.show()\n",[131],{"type":18,"tag":56,"props":132,"children":133},{"__ignoreMap":7},[134],{"type":24,"value":129},{"type":18,"tag":74,"props":136,"children":138},{"id":137},"_5-构造主函数串联整个代码逻辑",[139],{"type":24,"value":140},"5. 构造主函数，串联整个代码逻辑",{"type":18,"tag":51,"props":142,"children":144},{"code":143},"path = os.getcwd()\ndef main():\n    # acl初始化\n    acl_resource = AclLiteResource()\n    acl_resource.init()\n    # 加载模型\n    model_path = os.path.join(path, \"FCN8s.om\")\n    model = AclLiteModel(model_path)\n    # preprocess\n    dataset = pre_process()   # 前处理\n    # inference\n    res, show_images = inference(dataset, model)   # 推理\n    # postprocess\n    post_process(res, show_images)  # 后处理    \n",[145],{"type":18,"tag":56,"props":146,"children":147},{"__ignoreMap":7},[148],{"type":24,"value":143},{"type":18,"tag":74,"props":150,"children":152},{"id":151},"_6-运行",[153],{"type":24,"value":154},"6. 运行",{"type":18,"tag":30,"props":156,"children":157},{},[158],{"type":24,"value":159},"运行完成后，会显示推理前和推理后的图片。",{"type":18,"tag":30,"props":161,"children":162},{},[163],{"type":24,"value":164},"**注意：**本案例在离线推理的过程中可能会出现内存不足的问题，可以根据情况查看FAQ文档中的解决方案。",{"type":18,"tag":51,"props":166,"children":168},{"code":167},"main()\n",[169],{"type":18,"tag":56,"props":170,"children":171},{"__ignoreMap":7},[172],{"type":24,"value":167},{"type":18,"tag":19,"props":174,"children":176},{"id":175},"样例总结",[177],{"type":24,"value":175},{"type":18,"tag":30,"props":179,"children":180},{},[181],{"type":24,"value":182},"我们来回顾一下以上代码，可以包括以下几个步骤：",{"type":18,"tag":184,"props":185,"children":186},"ol",{},[187,193,198,203,208],{"type":18,"tag":188,"props":189,"children":190},"li",{},[191],{"type":24,"value":192},"初始化acl资源：在调用acl相关资源时，必须先初始化AscendCL，否则可能会导致后续系统内部资源初始化出错。",{"type":18,"tag":188,"props":194,"children":195},{},[196],{"type":24,"value":197},"对图片进行前处理：使得模型正常推理。",{"type":18,"tag":188,"props":199,"children":200},{},[201],{"type":24,"value":202},"推理：利用AclLiteModel.execute接口对图片进行推理。",{"type":18,"tag":188,"props":204,"children":205},{},[206],{"type":24,"value":207},"对推理结果进行后处理：使得图片正常画出。",{"type":18,"tag":188,"props":209,"children":210},{},[211],{"type":24,"value":212},"可视化图片：利用plt将结果画出。",{"title":7,"searchDepth":214,"depth":214,"links":215},4,[216,218,219,220,221,222],{"id":76,"depth":217,"text":79},3,{"id":90,"depth":217,"text":93},{"id":104,"depth":217,"text":107},{"id":123,"depth":217,"text":126},{"id":137,"depth":217,"text":140},{"id":151,"depth":217,"text":154},"markdown","content:technology-blogs:zh:3386.md","content","technology-blogs/zh/3386.md","technology-blogs/zh/3386","md",1776506129123]