• [MindX SDK] Overlap-CRNN重叠文本识别设计案例
    MindX SDK——Overlap-CRNN重叠文本识别设计案例1 案例概述本开发样例使用CRNN完成重叠文本的识别任务,供用户参考。 本系统基于昇腾Ascend310卡。本仓库是重叠文本任务的下游任务,即在完成对重叠文本还原后针对mask识别出文本。1.1 支持的产品本系统采用Atlas300-3010作为实验验证的硬件平台,并支持Atlas200RC以及Atlas500的硬件平台.具体产品实物图和硬件参数请参见《Atlas 300 AI加速卡 用户指南(型号 3010)》。由于采用的硬件平台为含有Atlas 300的Atlas 800 AI服务器 (型号3010),而服务器一般需要通过网络访问,因此需要通过笔记本或PC等客户端访问服务器,而且展示界面一般在客户端。1.2 支持的版本版本号查询方法,在Ascend产品环境下,运行命令:npu-smi info1.3 软件方案介绍软件方案主要为还原文本的识别系统,子系统功能具体描述请参考 表1.1 系统方案各子系统功能描述。重叠文本识别子系统可以实现识别还原后图像的mask的输入,然后通过等比例放缩等操作最后对图像进行识别,本方案选择使用crnn作为重叠文本识别模型。系统方案中各模块功能如表1.2 所示。表1.1 系统方案各子系统功能描述:序号子系统功能描述1重叠文本识别子系统重叠文本识别子系统将上一个子系统得到的结果,进行等比例放缩操作,放缩的大小与模型的输入大小有关,之后将结果送入到文字识别模型进行文字识别,并将识别结果进行输出。表1.2 系统方案中各模块功能:序号子系统功能描述1输入图像将图像(JPG格式)通过pillow库读入。2输入字典将字典(txt格式)通过本地代码输入到pipeline中。3图像解码通过PILLOW第三方库对图像解码。4图像放缩文字识别模型的输入为固定维度,所以需要放射变换的结果进行等比例放缩。5文字识别在图像放缩后,将缓存区数据送入文字识别模型。本方案选用crnn进行文本识别6结果可视化通过pillow库可视化单张图像的识别。1.4 代码目录结构与说明eg:本sample工程名称为Overlap-CRNN,工程目录如下图所示:├── crnn_single_infer.py #单张图片推理 ├── crnn_infer.py #精度测试 ├── README.md ├── ch_sim_en_digit_symble.txt #字典 ├── models #不同类型的模型文件 │ ├── air_model │ │ ├── crnn.air │ └── ckpt_model │ │ ├── crnn.ckpt │ └── om_model │ │ ├── crnn.om ├── dataset #测试数据集 │ ├── img │ ├── map_record.json │ └── annotation.json1.5 技术实现流程图实现流程图如下图所示:1.6 特性及适用场景本案例中的 CRNN模型适用于英文的灰度图像的识别,并可以返回测试图像的word-based的精度值。本模型在以下几种情况去噪效果良好:图像中文字清晰可见、排版工整、字符大小适中等。在以下几种情况去噪效果不太好:图像中文字模糊、排版随意、字符较小等。1.7 代码地址本项目的代码地址为:cid:link_32 环境依赖请列出环境依赖软件和版本。推荐系统为ubuntu 18.04或centos 7.6,环境依赖软件和版本如下表:软件名称版本mindspore1.8.1MindX SDK3.0RC2Ascend-CANN-toolkit5.1.RC2ubuntu18.04.1 LTSpython3.9.2cv24.5.5.64numpy1.23.1pillow9.1.0在编译运行项目前,需要设置环境变量:环境变量介绍. ${sdk_path}/set_env.sh . ${ascend_toolkit_path}/set_env.sh3 模型训练模型均在GPU下训练得到,如果需要使用本仓库提供的模型进行推理或模型转换,请务必参照GPU所需的参数设置,然后将模型按照提供的文件夹目录放至即可。相关模型的下载链接如下:[下载链接]cid:link_1)步骤1 从昇腾社区的modelzoo中下载官方CRNN模型代码,并按安装官方文档中的步骤完成训练:下载链接CRNN_for_MindSpore_1.2_code/default_config.yamlmodel_version: "V2" # V2可以在GPU和Ascend上训练 label_dict: "PATH/TO/ch_sim_en_digit_symble.txt" # 使用自己的字典的路径 max_text_length: 12 image_width: 112 class_num: 6703 blank: 6702 train_dataset_path: "" # 训练数据集路径 train_eval_dataset: "synth" # 名称使用synth train_eval_dataset_path: "" # 测试数据路径CRNN_for_MindSpore_1.2_code/src/dataset.py将第41行的:letters = [letter for letter in config1.label_dict]修改为:letters = [] with open(config1.label_dict, 'r') as f: for line in f: letter = line.strip('\n') letters.append(letter) f.close()将CaptchaDataset函数更换为:class CaptchaDataset: """ create train or evaluation dataset for crnn Args: img_root_dir(str): root path of images max_text_length(int): max number of digits in images. device_target(str): platform of training, support Ascend and GPU. """ def __init__(self, img_root_dir, is_training=True, config=config1): if not os.path.exists(img_root_dir): raise RuntimeError( "the input image dir {} is invalid!".format(img_root_dir)) self.img_root_dir = img_root_dir if is_training: self.imgslist = os.path.join(self.img_root_dir, 'annotation_train.txt') else: self.imgslist = os.path.join(self.img_root_dir, 'annotation_test.txt') self.img_names = {} self.img_list = [] with open(self.imgslist, 'r') as f: for line in f: img_name, img_label = line.strip('\n').split('\t') self.img_list.append(img_name) self.img_names[img_name] = str(img_label) f.close() self.max_text_length = config.max_text_length self.blank = config.blank self.class_num = config.class_num self.sample_num = len(self.img_list) self.batch_size = config.batch_size print("There are totally {} samples".format(self.sample_num)) def __len__(self): return self.sample_num def __getitem__(self, item): img_name = self.img_list[item] try: im = Image.open(os.path.join(self.img_root_dir, img_name)) except IOError: print("%s is a corrupted image" % img_name) return self[item + 1] im = im.convert("RGB") r, g, b = im.split() im = Image.merge("RGB", (b, g, r)) image = np.array(im) if not check_image_is_valid(image): print("%s is a corrupted image" % img_name) return self[item + 1] text = self.img_names[img_name] label_unexpanded = text_to_labels(text) label = np.full(self.max_text_length, self.blank) if self.max_text_length < len(label_unexpanded): label_len = self.max_text_length else: label_len = len(label_unexpanded) for j in range(label_len): label[j] = label_unexpanded[j] return image, labelCRNN_for_MindSpore_1.2_code/src/metric.py将第18行的字典label_dict = "abcdefghijklmnopqrstuvwxyz0123456789"修改为( dict_path 为自行准备的字典 ch_sim_en_digit_symble.txt ,可在本仓库下找到):label_dict = [] with open("[dict_path]", 'r') as f: for line in f: letter = line.strip('\n') label_dict.append(letter) f.close()步骤2 训练得到ckpt模型文件后,进入CRNN_for_MindSpore_1.2_code文件夹下执行命令(修改ckpt_file和air_file_name参数为自己的路径):python export.py --ckpt_file [ckpt_file] --file_name [air_file_name] --file_format AIR4 模型推理步骤1 将生成的AIR模型转移到推理服务器,放至在Overlap-CRNN/models/air_model路径下。cd ./Overlap-CRNN mkdir models cd models mkdir air_model步骤2 进入推理服务器执行命令(修改air_model_path和output_model_path参数为自己的路径):atc --model=[air_model_path] --framework=1 --output=[output_model_path] --soc_version=Ascend310 --output_type=FP32 --op_select_implmode=high_precision --input_shape="input:1,3,32,112"模型转换工具(ATC)相关介绍如下:ATC介绍相关模型的下载链接如下:模型下载步骤3 执行该命令会在当前目录下生成项目需要的模型文件[output_model].om。执行后终端输出为:ATC start working now, please wait for a moment. ATC run success, welcome to the next use.表示命令执行成功。步骤4 将任意一张jpg格式的图片存到当前目录下(./Overlap-CRNN),命名为test.jpg。步骤5 按照模型转换获取om模型,放置在Overlap-CRNN/models/om_model/路径下。若未自行转换模型,使用的是仓库提供的模型,则无需修改相关文件,否则修改crnn_single_infer.py中相关配置,将MODEL_PATH对象的路径改成实际的om模型的路径;IMAGE_PATH对象的路径改成实际的测试图片的路径;SAVE_PATH对象设置成需要保存可视化图像的路径。相关参数在Overlap-CRNN/crnn_single_infer.py下:MODEL_PATH = "./models/om_model/crnn.om" IMAGE_PATH = "./test.jpg" SAVE_PATH = "./show.jpg"步骤6 在命令行输入 如下命令运行整个工程:python crnn_single_infer.py步骤7 运行结束输出show.jpg5 测试精度步骤1 在Overlap-CRNN/dataset/路径下准备相同格式的数据集(已提供测试用的数据集,按照文件目录放至即可:下载链接)步骤2 在命令行输入 如下命令运行整个工程:python crnn_infer.py模型在测试集上的精度达标,最终模型的的acc为89.17%,满足精度要求(acc≥80%)。
  • [经验分享] 使用MindStudio开发基于MindX SDK的X射线图像缺陷检测应用(下)
    bilibili视频链接:使用MindStudio开发基于MindX SDK的X射线图像缺陷检测应用9、本地编写python文件1、main.pymain.py主要进行一些推理前的操作和调用infer.py进行推理,以及调用postprocess.py进行推理结果后处理。步骤一:导入相关包,并定义相关函数步骤二:编写各个函数parser_args函数用于读入执行改文件时所需的一些参数def parser_args(): parser = argparse.ArgumentParser(description="FasterRcnn inference") parser.add_argument("--img_path", type=str, required=False, default="../data/test/crop/", help="image directory.") parser.add_argument( "--pipeline_path", type=str, required=False, default="../pipeline/fasterrcnn_ms_dvpp.pipeline", help="image file path. The default is 'config/maskrcnn_ms.pipeline'. ") parser.add_argument( "--model_type", type=str, required=False, default="dvpp", help= "rgb: high-precision, dvpp: high performance. The default is 'dvpp'.") parser.add_argument( "--infer_mode", type=str, required=False, default="infer", help= "infer:only infer, eval: accuracy evaluation. The default is 'infer'.") parser.add_argument( "--infer_result_dir", type=str, required=False, default="../data/test/infer_result", help= "cache dir of inference result. The default is '../data/test/infer_result'.") parser.add_argument("--ann_file", type=str, required=False, help="eval ann_file.") arg = parser.parse_args() return argget_img_metas函数用于记录图像缩放比例def get_img_metas(file_name): img = Image.open(file_name) img_size = img.size org_width, org_height = img_size resize_ratio = cfg.MODEL_WIDTH / org_width if resize_ratio > cfg.MODEL_HEIGHT / org_height: resize_ratio = cfg.MODEL_HEIGHT / org_height img_metas = np.array([img_size[1], img_size[0]] + [resize_ratio, resize_ratio]) return img_metasprocess_img函数用于对图像进行预处理def process_img(img_file): img = cv2.imread(img_file) model_img = mmcv.imrescale(img, (cfg.MODEL_WIDTH, cfg.MODEL_HEIGHT)) if model_img.shape[0] > cfg.MODEL_HEIGHT: model_img = mmcv.imrescale(model_img, (cfg.MODEL_HEIGHT, cfg.MODEL_HEIGHT)) pad_img = np.zeros( (cfg.MODEL_HEIGHT, cfg.MODEL_WIDTH, 3)).astype(model_img.dtype) pad_img[0:model_img.shape[0], 0:model_img.shape[1], :] = model_img pad_img.astype(np.float16) return pad_imgcrop_on_slide函数用于对图片进行滑窗裁剪,因为输入的图片尺寸大多都为4000*1000左右,不利于缺陷的识别和推理,对其进行滑窗裁剪后,得到的多张小图片更利于缺陷识别和推理def crop_on_slide(cut_path, crop_path, stride): if not os.path.exists(crop_path): os.mkdir(crop_path) else: remove_list = os.listdir(crop_path) for filename in remove_list: os.remove(os.path.join(crop_path, filename)) output_shape = 600 imgs = os.listdir(cut_path) for img in imgs: if img.split('.')[1] != "jpg" and img.split('.')[1] != "JPG": raise ValueError("The file {} is not jpg or JPG image!".format(img)) origin_image = cv2.imread(os.path.join(cut_path, img)) height = origin_image.shape[0] width = origin_image.shape[1] x = 0 newheight = output_shape newwidth = output_shape while x < width: y = 0 if x + newwidth <= width: while y < height: if y + newheight <= height: hmin = y hmax = y + newheight wmin = x wmax = x + newwidth else: hmin = height - newheight hmax = height wmin = x wmax = x + newwidth y = height # test crop_img = os.path.join(crop_path, ( img.split('.')[0] + '_' + str(wmax) + '_' + str(hmax) + '_' + str(output_shape) + '.jpg')) cv2.imwrite(crop_img, origin_image[hmin: hmax, wmin: wmax]) y = y + stride if y + output_shape == height: y = height else: while y < height: if y + newheight <= height: hmin = y hmax = y + newheight wmin = width - newwidth wmax = width else: hmin = height - newheight hmax = height wmin = width - newwidth wmax = width y = height # test crop_img = os.path.join(crop_path, ( img.split('.')[0] + '_' + str(wmax) + '_' + str(hmax) + '_' + str( output_shape) + '.jpg')) cv2.imwrite(crop_img, origin_image[hmin: hmax, wmin: wmax]) y = y + stride x = width x = x + stride if x + output_shape == width: x = widthimage_inference函数用于流的初始化,推理所需文件夹的创建、图片预处理、推理时间记录、推理后处理、推理结果可视化def image_inference(pipeline_path, s_name, img_dir, result_dir, rp_last, model_type): sdk_api = SdkApi(pipeline_path) if not sdk_api.init(): exit(-1) if not os.path.exists(result_dir): os.makedirs(result_dir) img_data_plugin_id = 0 img_metas_plugin_id = 1 logging.info("\nBegin to inference for {}.\n\n".format(img_dir)) file_list = os.listdir(img_dir) total_len = len(file_list) if total_len == 0: logging.info("ERROR\nThe input directory is EMPTY!\nPlease place the picture in '../data/test/cut'!") for img_id, file_name in enumerate(file_list): if not file_name.lower().endswith((".jpg", "jpeg")): continue file_path = os.path.join(img_dir, file_name) save_path = os.path.join(result_dir, f"{os.path.splitext(file_name)[0]}.json") if not rp_last and os.path.exists(save_path): logging.info("The infer result json({}) has existed, will be skip.".format(save_path)) continue try: if model_type == 'dvpp': with open(file_path, "rb") as fp: data = fp.read() sdk_api.send_data_input(s_name, img_data_plugin_id, data) else: img_np = process_img(file_path) sdk_api.send_img_input(s_name, img_data_plugin_id, "appsrc0", img_np.tobytes(), img_np.shape) # set image data img_metas = get_img_metas(file_path).astype(np.float32) sdk_api.send_tensor_input(s_name, img_metas_plugin_id, "appsrc1", img_metas.tobytes(), [1, 4], cfg.TENSOR_DTYPE_FLOAT32) start_time = time.time() result = sdk_api.get_result(s_name) end_time = time.time() - start_time if os.path.exists(save_path): os.remove(save_path) flags = os.O_WRONLY | os.O_CREAT | os.O_EXCL modes = stat.S_IWUSR | stat.S_IRUSR with os.fdopen(os.open((save_path), flags, modes), 'w') as fp: fp.write(json.dumps(result)) logging.info( "End-2end inference, file_name: {}, {}/{}, elapsed_time: {}.\n".format(file_path, img_id + 1, total_len, end_time)) draw_label(save_path, file_path, result_dir) except Exception as ex: logging.exception("Unknown error, msg:{}.".format(ex)) post_process()步骤三:main方法编写if __name__ == "__main__": args = parser_args() REPLACE_LAST = True STREAM_NAME = cfg.STREAM_NAME.encode("utf-8") CUT_PATH = "../data/test/cut/" CROP_IMG_PATH = "../data/test/crop/" STRIDE = 450 crop_on_slide(CUT_PATH, CROP_IMG_PATH, STRIDE) image_inference(args.pipeline_path, STREAM_NAME, args.img_path, args.infer_result_dir, REPLACE_LAST, args.model_type) if args.infer_mode == "eval": logging.info("Infer end.\nBegin to eval...") get_eval_result(args.ann_file, args.infer_result_dir)2、infer.pyinfer.py中是主要的sdk推理步骤,包括流的初始化到流的销毁,编写完成后在main.py中调用。步骤一:导入相关包,并定义相关类和函数步骤二:编写各个函数init魔法属性用来构造sdk实例化对象def __init__(self, pipeline_cfg): self.pipeline_cfg = pipeline_cfg self._stream_api = None self._data_input = None self._device_id = Nonedel魔法属性用来销毁实例化对象def __del__(self): if not self._stream_api: return self._stream_api.DestroyAllStreams()_convert_infer_result函数用来将推理结果输出def _convert_infer_result(infer_result): data = infer_result.get('MxpiObject') if not data: logging.info("The result data is empty.") return infer_result for bbox in data: if 'imageMask' not in bbox: continue mask_info = json_format.ParseDict(bbox["imageMask"], MxpiDataType.MxpiImageMask()) mask_data = np.frombuffer(mask_info.dataStr, dtype=np.uint8) bbox['imageMask']['data'] = "".join([str(i) for i in mask_data]) bbox['imageMask'].pop("dataStr") return infer_resultinit函数用来stream manager的初始化def init(self): try: with open(self.pipeline_cfg, 'r') as fp: self._device_id = int( json.loads(fp.read())[self.STREAM_NAME]["stream_config"] ["deviceId"]) logging.info("The device id: {}.".format(self._device_id)) # create api self._stream_api = StreamManagerApi() # init stream mgr ret = self._stream_api.InitManager() if ret != 0: logging.info("Failed to init stream manager, ret={}.".format(ret)) return False # create streams with open(self.pipeline_cfg, 'rb') as fp: pipe_line = fp.read() ret = self._stream_api.CreateMultipleStreams(pipe_line) if ret != 0: logging.info("Failed to create stream, ret={}.".format(ret)) return False self._data_input = MxDataInput() except Exception as exe: logging.exception("Unknown error, msg:{}".format(exe)) return False return Truesend_data_input函数用来传输推理数据def send_data_input(self, stream_name, plugin_id, input_data): data_input = MxDataInput() data_input.data = input_data unique_id = self._stream_api.SendData(stream_name, plugin_id, data_input) if unique_id < 0: logging.error("Fail to send data to stream.") return False return Truesend_img_input函数用来传入图片def send_img_input(self, stream_name, plugin_id, element_name, input_data, img_size): vision_list = MxpiDataType.MxpiVisionList() vision_vec = vision_list.visionVec.add() vision_vec.visionInfo.format = 1 vision_vec.visionInfo.width = img_size[1] vision_vec.visionInfo.height = img_size[0] vision_vec.visionInfo.widthAligned = img_size[1] vision_vec.visionInfo.heightAligned = img_size[0] vision_vec.visionData.memType = 0 vision_vec.visionData.dataStr = input_data vision_vec.visionData.dataSize = len(input_data) buf_type = b"MxTools.MxpiVisionList" return self._send_protobuf(stream_name, plugin_id, element_name, buf_type, vision_list)send_tensor_input函数用来传入张量数据def send_tensor_input(self, stream_name, plugin_id, element_name, input_data, input_shape, data_type): tensor_list = MxpiDataType.MxpiTensorPackageList() tensor_pkg = tensor_list.tensorPackageVec.add() # init tensor vector tensor_vec = tensor_pkg.tensorVec.add() tensor_vec.deviceId = self._device_id tensor_vec.memType = 0 tensor_vec.tensorShape.extend(input_shape) tensor_vec.tensorDataType = data_type tensor_vec.dataStr = input_data tensor_vec.tensorDataSize = len(input_data) buf_type = b"MxTools.MxpiTensorPackageList" return self._send_protobuf(stream_name, plugin_id, element_name, buf_type, tensor_list)get_result函数用来获得推理结果def get_result(self, stream_name, out_plugin_id=0): infer_res = self._stream_api.GetResult(stream_name, out_plugin_id, self.INFER_TIMEOUT) if infer_res.errorCode != 0: logging.info("GetResultWithUniqueId error, errorCode={}, errMsg={}".format(infer_res.errorCode, infer_res.data.decode())) return None res_dict = json.loads(infer_res.data.decode()) return self._convert_infer_result(res_dict)_send_protobuf函数用来对目标检测结果进行序列化def _send_protobuf(self, stream_name, plugin_id, element_name, buf_type, pkg_list): protobuf = MxProtobufIn() protobuf.key = element_name.encode("utf-8") protobuf.type = buf_type protobuf.protobuf = pkg_list.SerializeToString() protobuf_vec = InProtobufVector() protobuf_vec.push_back(protobuf) err_code = self._stream_api.SendProtobuf(stream_name, plugin_id, protobuf_vec) if err_code != 0: logging.error( "Failed to send data to stream, stream_name:{}, plugin_id:{}, " "element_name:{}, buf_type:{}, err_code:{}.".format( stream_name, plugin_id, element_name, buf_type, err_code)) return False return True3、postprocess.py对经过滑窗裁剪后的小图片进行推理,最后得到的推理结果也是在小图片上,因此需要对推理结果进行后处理,将小图片上的推理结果还原到未经过滑窗裁剪的图片上。步骤一:导入相关包,并定义相关函数步骤二:编写各个函数json_to_txt函数用来将得到的json格式推理结果转为txt格式def json_to_txt(infer_result_path, savetxt_path): if os.path.exists(savetxt_path): shutil.rmtree(savetxt_path) os.mkdir(savetxt_path) files = os.listdir(infer_result_path) for file in files: if file.endswith(".json"): json_path = os.path.join(infer_result_path, file) with open(json_path, 'r') as fp: result = json.loads(fp.read()) if result: data = result.get("MxpiObject") txt_file = file.split(".")[0] + ".txt" flags = os.O_WRONLY | os.O_CREAT | os.O_EXCL modes = stat.S_IWUSR | stat.S_IRUSR with os.fdopen(os.open(os.path.join(savetxt_path, txt_file), flags, modes), 'w') as f: if file.split('_')[0] == "W0003": temp = int(file.split("_")[2]) - 600 else: temp = int(file.split("_")[1]) - 600 for bbox in data: class_vec = bbox.get("classVec")[0] class_id = int(class_vec["classId"]) confidence = class_vec.get("confidence") xmin = bbox["x0"] ymin = bbox["y0"] xmax = bbox["x1"] ymax = bbox["y1"] if xmax - xmin >= 5 and ymax - ymin >= 5: f.write( str(xmin + temp) + ',' + str(ymin) + ',' + str(xmax + temp) + ',' + str( ymax) + ',' + str( round(confidence, 2)) + ',' + str(class_id) + '\n')hebing_txt函数用来将滑窗裁剪后的小图片推理结果还原到原始图片上def hebing_txt(txt_path, save_txt_path, remove_txt_path, cut_path): if not os.path.exists(save_txt_path): os.makedirs(save_txt_path) if not os.path.exists(remove_txt_path): os.makedirs(remove_txt_path) fileroot = os.listdir(save_txt_path) remove_list = os.listdir(remove_txt_path) for filename in remove_list: os.remove(os.path.join(remove_txt_path, filename)) for filename in fileroot: os.remove(os.path.join(save_txt_path, filename)) data = [] for file in os.listdir(cut_path): data.append(file.split(".")[0]) txt_list = os.listdir(txt_path) flags = os.O_WRONLY | os.O_CREAT | os.O_EXCL modes = stat.S_IWUSR | stat.S_IRUSR for image in data: fw = os.fdopen(os.open(os.path.join(save_txt_path, image + '.txt'), flags, modes), 'w') for txtfile in txt_list: if image.split('_')[0] == "W0003": if image.split('_')[1] == txtfile.split('_')[1]: for line in open(os.path.join(txt_path, txtfile), "r"): fw.write(line) else: if image.split('_')[0] == txtfile.split('_')[0]: for line in open(os.path.join(txt_path, txtfile), "r"): fw.write(line) fw.close() fileroot = os.listdir(save_txt_path) for file in fileroot: oldname = os.path.join(save_txt_path, file) newname = os.path.join(remove_txt_path, file) shutil.copyfile(oldname, newname)py_cpu_nms、plot_bbox、nms_box函数用来对还原后的推理结果进行nms去重处理,在进行滑窗裁剪时,为了不在裁剪时将缺陷切断从而保留所有缺陷,所以设置的滑窗步长小于小图片尺寸,因此得到的推理结果会有重复,需进行nms去重处理def py_cpu_nms(dets, thresh): x1 = dets[:, 0] y1 = dets[:, 1] x2 = dets[:, 2] y2 = dets[:, 3] areas = (y2 - y1 + 1) * (x2 - x1 + 1) scores = dets[:, 4] keep = [] index = scores.argsort()[::-1] while index.size > 0: i = index[0] # every time the first is the biggst, and add it directly keep.append(i) x11 = np.maximum(x1[i], x1[index[1:]]) # calculate the points of overlap y11 = np.maximum(y1[i], y1[index[1:]]) x22 = np.minimum(x2[i], x2[index[1:]]) y22 = np.minimum(y2[i], y2[index[1:]]) w = np.maximum(0, x22 - x11 + 1) # the weights of overlap h = np.maximum(0, y22 - y11 + 1) # the height of overlap overlaps = w * h ious = overlaps / (areas[i] + areas[index[1:]] - overlaps) idx = np.where(ious <= thresh)[0] index = index[idx + 1] # because index start from 1 return keep def plot_bbox(dets, c='k'): x1 = dets[:, 0] y1 = dets[:, 1] x2 = dets[:, 2] y2 = dets[:, 3] plt.plot([x1, x2], [y1, y1], c) plt.plot([x1, x1], [y1, y2], c) plt.plot([x1, x2], [y2, y2], c) plt.plot([x2, x2], [y1, y2], c) plt.title(" nms") def nms_box(image_path, image_save_path, txt_path, thresh, obj_list): if not os.path.exists(image_save_path): os.makedirs(image_save_path) remove_list = os.listdir(image_save_path) for filename in remove_list: os.remove(os.path.join(image_save_path, filename)) txt_list = os.listdir(txt_path) for txtfile in tqdm.tqdm(txt_list): boxes = np.loadtxt(os.path.join(txt_path, txtfile), dtype=np.float32, delimiter=',') if boxes.size > 5: if os.path.exists(os.path.join(txt_path, txtfile)): os.remove(os.path.join(txt_path, txtfile)) flags = os.O_WRONLY | os.O_CREAT | os.O_EXCL modes = stat.S_IWUSR | stat.S_IRUSR fw = os.fdopen(os.open(os.path.join(txt_path, txtfile), flags, modes), 'w') keep = py_cpu_nms(boxes, thresh=thresh) img = cv.imread(os.path.join(image_path, txtfile[:-3] + 'jpg'), 0) for label in boxes[keep]: fw.write(str(int(label[0])) + ',' + str(int(label[1])) + ',' + str(int(label[2])) + ',' + str( int(label[3])) + ',' + str(round((label[4]), 2)) + ',' + str(int(label[5])) + '\n') x_min = int(label[0]) y_min = int(label[1]) x_max = int(label[2]) y_max = int(label[3]) color = (0, 0, 255) if x_max - x_min >= 5 and y_max - y_min >= 5: cv.rectangle(img, (x_min, y_min), (x_max, y_max), color, 1) font = cv.FONT_HERSHEY_SIMPLEX cv.putText(img, (obj_list[int(label[5])] + str(round((label[4]), 2))), (x_min, y_min - 7), font, 0.4, (6, 230, 230), 1) cv.imwrite(os.path.join(image_save_path, txtfile[:-3] + 'jpg'), img) fw.close()post_process函数用来调用以上编写的函数,最后在main.py中被调用def post_process(): infer_result_path = "../data/test/infer_result" txt_save_path = "../data/test/img_txt" json_to_txt(infer_result_path, txt_save_path) txt_path = "../data/test/img_txt" all_txt_path = "../data/test/img_huizong_txt" nms_txt_path = "../data/test/img_huizong_txt_nms" cut_path = "../data/test/cut" hebing_txt(txt_path, all_txt_path, nms_txt_path, cut_path) cut_path = "../data/test/cut" image_save_path = "../data/test/draw_result" nms_txt_path = "../data/test/img_huizong_txt_nms" obj_lists = ['qikong', 'liewen'] nms_box(cut_path, image_save_path, nms_txt_path, thresh=0.1, obj_list=obj_lists)10、代码运行前面的步骤完成之后,我们就可以进行代码的运行了,本项目中,图片的输入输出位置都是用的相对路径,因此不需要修改路径参数,按以下步骤进行模型推理:步骤一:放置待检测图片本项目中,将图片放置在./python/data/test/cut目录下,例如我放的图片:步骤二:在main.py中设置好初始图片所在位置和结果图片保存位置。步骤三:设置运行脚本运行应用点击下图箭头所指,设置自己的运行脚本点击绿色箭头,开始运行运行成功,查看推理结果五、常见问题在使用 MindStudio 时,遇到问题,可以登陆华为云论坛云计算论坛开发者论坛技术论坛-华为云 (huaweicloud.com)进行互动,提出问题,会有专家老师为你解答。1、CANN 连接错误连接服务器 SSH 成功,但是连接 CANN 失败:点击OK,点击Show Error Details,查看报错信息:问题:权限不够,无法连接。解决方案:在远程环境自己的工作目录下重新下载CANN后,再连接CANN即可。2、后处理插件权限问题如图,运行时显示权限不够:两种解决方案:方案一:在远程终端中找到后处理插件所在位置,修改其权限为640,如图:修改完成后,需将改文件设置为不同步,如图:方案二:在远程终端环境中找到后处理插件所在位置,将其复制到MindX SDK自带的后处理插件库文件夹下,并修改其权限为640,然后修改pipeline文件中后处理插件所在位置。注:MindX SDK自带的后处理插件库文件夹一般为${MX_SDK_HOME}/lib/modelpostprocessors/
  • [经验分享] 使用MindStudio开发基于MindX SDK的X射线图像缺陷检测应用(上)
    bilibili视频链接:使用MindStudio开发基于MindX SDK的X射线图像缺陷检测应用一、MindStudio1、MindStudio介绍MindStudio简介:MindStudio 提供您在 AI 开发所需的一站式开发环境,支持模型开发、算子开发以及应用开发三个主流程中的开发任务。依靠模型可视化、算力测试、IDE 本地仿真调试等功能,MindStudio 能够帮助您在一个工具上就能高效便捷地完 成 AI 应用开发。MindStudio 采用了插件化扩展机制,开发者可以通过开发插件来扩展已有功能。功能简介针对安装与部署,MindStudio 提供多种部署方式,支持多种主流操作系统, 为开发者提供最大便利。针对网络模型的开发,MindStudio 支持 TensorFlow、PyTorch、MindSpore 框 架的模型训练,支持多种主流框架的模型转换。集成了训练可视化、脚本转换、模型转换、精度比对等工具,提升了网络模型移植、分析和优化的效率。针对算子开发,MindStudio 提供包含 UT 测试、ST 测试、TIK 算子调试等的全套算子开发流程。支持 TensorFlow、PyTorch、MindSpore 等多种主流框架 的 TBE 和 AI CPU 自定义算子开发。针对应用开发,MindStudio 集成了 Profiling 性能调优、编译器、MindX SDK 的应用开发、可视化 pipeline 业务流编排等工具,为开发者提供了图形化 的集成开发环境,通过 MindStudio 能够进行工程管理、编译、调试、性能分析等全流程开发,能够很大程度提高开发效率。功能框架MindStudio功能框架如下图所示,目前含有的工具链包括:模型转换工具、模型训练工具、自定义算子开发工具、应用开发工具、工程管理工具、编译工具、流程编排工具、精度比对工具、日志管理工具、性能分析工具、设备管理工具等多种工具。场景介绍开发场景:在非昇腾AI设备(如windosw平台)上安装MindStudio和Ascend-cann-toolkit开发套件包。在该开发场景下,我们仅用于代码开发、编译等不依赖昇腾设备的活动,如果要运行应用程序或者模型训练等,需要通过MindStudio远程连接(SSH)已经部署好运行环境所需要软件包(CANN、MindX SDK等)的昇腾AI设备。开发运行场景:在昇腾AI设备(昇腾AI服务器)上安装MindStudio、Ascend-cann-toolkit开发套件包等安装包和AI框架(进行模型训练时需要安装)。在该开发环境下,开发人员可以进行代码编写、编译、程序运行、模型训练等操作。软件包介绍MindStudio:提供图形化开发界面,支持应用开发、调试和模型转换功能, 同时还支持网络移植、优化和分析等功能,可以安装在linux、windows平台。Ascend-cann-toolkit:开发套件包。为开发者提供基于昇腾 AI 处理器的相关算法开发工具包,旨在帮助开发者进行快速、高效的模型、算子和应用的开发。开发套件包只能安装在 Linux 服务器上,开发者可以在安装开发套件包后,使用 MindStudio 开发工具进行快速开发。注:由于Ascend-cann-toolkit只能安装在linux服务器上,所以在Windows场景下代码开发时,需先安装MindStudio软件,再远程连接同步Linux服务器的CANN和MindX SDK到本地。二、MindX SDK1、MindX SDK介绍MindX SDK 提供昇腾 AI 处理器加速的各类 AI 软件开发套件(SDK),提供极简易用的 API,加速 AI 应用的开发。应用开发旨在使用华为提供的 SDK 和应用案例快速开发并部署人工智能应用,是基于现有模型、使用pyACL 提供的 Python 语言 API 库开发深度神经网络 应用,用于实现目标识别、图像分类等功能。mxManufacture & mxVision 关键特性:配置文件快速构建 AI 推理业务。插件化开发模式,将整个推理流程“插件化”,每个插件提供一种功能,通过组装不同的插件,灵活适配推理业务流程。提供丰富的插件库,用户可根据业务需求组合 Jpeg 解码、抠图、缩放、模型推理、数据序列化等插件。基于 Ascend Computing Language(ACL),提供常用功能的高级 API,如模型推理、解码、预处理等,简化 Ascend 芯片应用开发。支持自定义插件开发,用户可快速地将自己的业务逻辑封装成插件,打造自己的应用插件。三、可视化流程编排介绍1、SDK基础概念通过 stream(业务流)配置文件,Stream manager(业务流管理模块)可识别需要构建的 element(功能元件)以及 element 之间的连接关系,并启动业务流程。Stream manager 对外提供接口,用于向 stream 发送数据和获取结果,帮助用户实现业务对接。Plugin(功能插件)表示业务流程中的基础模块,通过 element 的串接构建成一个 stream。Buffer(插件缓存)用于内部挂载解码前后的视频、图像数据, 是 element 之间传递的数据结构,同时也允许用户挂载 Metadata(插件元数据), 用于存放结构化数据(如目标检测结果)或过程数据(如缩放后的图像)2、可视化流程编排MindX SDK 实现功能的最小粒度是插件,每一个插件实现特定的功能,如图片解码、图片缩放等。流程编排是将这些插件按照合理的顺序编排,实现负责的功能。可视化流程编排是以可视化的方式,开发数据流图,生成 pipeline 文件供应用框架使用。下图为推理业务流 Stream 配置文件 pipeline 样例。配置文件以 json 格式编写,用户必须指定业务流名称、元件名称和插件名称,并根据需要,补充元件属性和下游元件名称信息。四、项目开发(Python)本项目主要介绍在Windows场景下使用MindStudio软件,连接远程服务器配置的MindX SDK、CANN环境,采用Faster R-CNN模型对GDxray焊接缺陷数据集进行焊接缺陷检测的应用开发。项目参考模型地址:Faster R-CNN项目代码地址:contrib/Faster_R-CNN · Ascend/mindxsdk-referenceappsGDXray是一个公开X射线数据集,其中包括一个关于X射线焊接图像(Welds)的数据,该数据由德国柏林的BAM联邦材料研究和测试研究所收集。Welds集中W0003 包括了68张焊接公司的X射线图像。本项目基于W0003数据集并在焊接专家的帮助下将焊缝和其内部缺陷标注。数据集下载地址:cid:link_61、MindStudio安装点击超链接下载MindStudio安装包MindStudio安装包下载点击超链接,进入MindStudio用户手册,在安装指南下安装操作中可以看见MindStudio具体的安装操作。MindStudio用户手册2、新建一个项目点击Ascend App,新建一个项目,在D:\Codes\python\Ascend\MyApp位置下创建自己的项目。点击 Change 安装CANN,进入 Remote CANN Setting 界面,如下图所示,远程连接需要配置SSH连接,点击**"+"**,进入SSH连接界面。参数解释Remote Connection远程服务器 IPRemote CANN location远程服务器中 CANN 路径下图为SSH连接界面中,ssh远程连接需配置远程终端账号,点击**"+"**后,进入SSH连接配置界面。下图为SSH配置界面,配置好后点击Test Connection,出现 ”Sucessfully connected!“即配置成功。返回到 Remote CANN Setting 界面,输入远程CANN路径完成 CANN 安装,点击 OK。接着,选择MindX SDK Project(Python),如下图所示,被圈出来的4个项目,上面两个是空模板,在这里面创建我们自己的工程项目,因为我们要创建Python版的应用,所以被单独框出来的这个;下面两个是官方给出的样例项目,如果对目录结构和应该写哪些代码不太熟悉的话,也可以创建一个样例项目先学习一下。选择完成后,点击Finish完成项目的创建进入项目,项目创建完成后,可根据自己需要新建文件、文件夹。3、MindX SDK安装步骤1、 Windows 场景下基于 MindStuido 的 SDK 应用开发(本地远程连接服务器端MindX SDK),请先确保远端环境上 MindX SDK 软件包已安装完成。(远程安装MindX SDK开发套件)步骤2、在 Windows 本地进入工程创建页面,工具栏点击 File > Settings > Appearance & Behavior> System Settings > MindX SDK 进入 MindX SDK 管理界面(只有安装CANN后才会出现MindX SDK按钮)。界面中 MindX SDK Location 为软件包的默认安装路径,默认安装路径为 “C:\Users\用户\Ascend\mindx_sdk”。单击 Install SDK 进入Installation settings 界面。如图所示,为 MindX SDK 的安装界面,各参数选择如下:Remote Connection:远程连接的用户及 IP。Remote CANN location:远端环境上 CANN 开发套件包的路径,请配置到版 本号一级。Remote SDK location:远端环境上 SDK 的路径,请配置到版本号一级。IDE 将同步该层级下的include、opensource、python、samples 文件夹到本地 Windows 环境,层级选择错误将导致安装失败。Local SDK location:同步远端环境上 SDK 文件夹到本地的路径。默认安装路径为“C:\Users\用户名\Ascend\mindx_sdk”。步骤 3 :单击 OK 结束,返回 SDK 管理界面如下图,可查看安装后的 SDK 的信息,可单击 OK结束安装流程。4、工程目录结构介绍在实际开发中,需要在./postprocess下编写后处理插件,在./python/Main下编写需要运行的python文件,在./python/models下放置模型相关配置文件,在./python/pipeline下编写工作流文件,本项目工程开发结束后的目录如下图所示。5、文件同步(可选)本地文件与远程文件同步一般自行决定是否需要该功能,若不进行文件同步,在后续编译文件或者运行应用时,MindStudio也会自行将项目文件同步到远端用户目录下MindStudio-WorkSpace文件夹中。在顶部菜单栏中选择 Tools > Deployment > Configuration ,如图:点击已连接的远程环境后,点击Mappings可添加需要同步的文件夹,点击Excluded Paths可添加同步的文件下不需要同步的文件。6、Faster R-CNN模型转换用户使用 Caffe/TensorFlow 等框架训练好的第三方模型,可通过 ATC 工具将其转换为昇腾 AI 处理器支持的离线模型(*.om 文件),模型转换过程中可以实现算子调度的优化、权重数据重排、内存使用优化等,可以脱离设备完成模型的预处理,详细架构如下图。在本项目中,要将 mindspore 框架下训练好的模型(.air 文件),转换为昇腾 AI 处理器支持的离线模型(.om 文件),具体步骤如下:步骤 1: 点击 Ascend > Model Converter,进入模型转换界面,参数配置如图所示,若没有CANN Machine,请参见第四章第二节 CANN 安装。各参数解释如下表所示:参数解释CANN MachineCANN 的远程服务器Model File*.air 文件的路径(可以在本地,也可以在服务器上)Target SoC Version模型转换时指定芯片型号Model Name生成的 om 模型名字Output Path生成的 om 模型保存在本地的路径Input Format输入数据格式Input Nodes模型输入节点信息步骤 2: 配置完成后,点击Next,进行数据预处理设置,配置完成后点击Next,如图:步骤 3: 进行模型转换命令及环境变量设置,该项目配置示例如图:各参数解释如下表所示:参数解释Additional Arguments执行命令时需要添加的其他参数配置Environment Variables环境变量设置Command Preview查看经过前面一系列配置后最终的命名形式步骤 4: 配置完成后,点击Finish进行模型转换。步骤 5:等待出现如下图所示的提示,模型转换成功。步骤 6:双击转换成功的 om 模型文件,可以查看网络结构。如下图所示。7、编写后处理插件并编译以下需要编写的文件均在./postprocess/目录下1、头文件FasterRcnnMindsporePost.hFasterRcnnMindsporePost.h头文件包含了类的声明(包括类里面的成员和方法的声明)、函数原型、#define 常数等。其中,#include 类及#define 常数如代码所示;定义的初始化参数结构体如代码所示;类里面的成员和方法的声明如代码所示。/* * Copyright (c) 2022. Huawei Technologies Co., Ltd. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef FASTERRCNN_MINSPORE_PORT_H #define FASTERRCNN_MINSPORE_PORT_H #include <algorithm> #include <vector> #include <map> #include <opencv4/opencv2/opencv.hpp> #include "MxBase/ErrorCode/ErrorCode.h" #include "MxBase/CV/Core/DataType.h" #include "MxBase/PostProcessBases/ObjectPostProcessBase.h" namespace MxBase { class FasterRcnnMindsporePost : public ObjectPostProcessBase { public: FasterRcnnMindsporePost() = default; ~FasterRcnnMindsporePost() = default; FasterRcnnMindsporePost(const FasterRcnnMindsporePost &other); FasterRcnnMindsporePost &operator=(const FasterRcnnMindsporePost &other); APP_ERROR Init(const std::map<std::string, std::shared_ptr<void>> &postConfig) override; APP_ERROR DeInit() override; APP_ERROR Process(const std::vector<TensorBase> &tensors, std::vector<std::vector<ObjectInfo>> &objectInfos, const std::vector<ResizedImageInfo> &resizedImageInfos = {}, const std::map<std::string, std::shared_ptr<void>> &configParamMap = {}) override; bool IsValidTensors(const std::vector<TensorBase> &tensors) const; private: void ObjectDetectionOutput(const std::vector<TensorBase> &tensors, std::vector<std::vector<ObjectInfo>> &objectInfos, const std::vector<ResizedImageInfo> &resizedImageInfos); void GetValidDetBoxes(const std::vector<TensorBase> &tensors, std::vector<DetectBox> &detBoxes, uint32_t batchNum); void ConvertObjInfoFromDetectBox(std::vector<DetectBox> &detBoxes, std::vector<ObjectInfo> &objectInfos, const ResizedImageInfo &resizedImageInfos); APP_ERROR ReadConfigParams(); private: const uint32_t DEFAULT_CLASS_NUM_MS = 8; const float DEFAULT_SCORE_THRESH_MS = 0.7; const float DEFAULT_IOU_THRESH_MS = 0.5; const uint32_t DEFAULT_RPN_MAX_NUM_MS = 1000; const uint32_t DEFAULT_MAX_PER_IMG_MS = 128; uint32_t classNum_ = DEFAULT_CLASS_NUM_MS; float scoreThresh_ = DEFAULT_SCORE_THRESH_MS; float iouThresh_ = DEFAULT_IOU_THRESH_MS; uint32_t rpnMaxNum_ = DEFAULT_RPN_MAX_NUM_MS; uint32_t maxPerImg_ = DEFAULT_MAX_PER_IMG_MS; }; extern "C" { std::shared_ptr<MxBase::FasterRcnnMindsporePost> GetObjectInstance(); } } // namespace MxBase #endif // FASTERRCNN_MINSPORE_PORT_H2、源文件FasterRcnnMindsporePost.cpp这里我们主要是实现在头文件中定义的函数,接下来做一个简要的概括ReadConfigParams函数用来读取目标检测类别信息、以及一些超参数如scoreThresh、iouThreshInit函数用来进行目标检测后处理中常用的初始化IsValidTensors函数用来判断输出结果是否有效GetValidDetBoxes函数用来获取有效的推理信息ConvertObjInfoFromDetectBox函数用来将推理信息转为标注框信息ObjectDetectionOutput函数用来输出得到的推理结果Process函数用来做预处理/* * Copyright (c) 2022. Huawei Technologies Co., Ltd. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include <boost/property_tree/json_parser.hpp> #include <opencv4/opencv2/core.hpp> #include <opencv4/opencv2/opencv.hpp> #include "acl/acl.h" #include "FasterRcnnMindsporePost.h" #include "MxBase/CV/ObjectDetection/Nms/Nms.h" namespace { // Output Tensor const int OUTPUT_TENSOR_SIZE = 3; const int OUTPUT_BBOX_SIZE = 3; const int OUTPUT_BBOX_TWO_INDEX_SHAPE = 5; const int OUTPUT_BBOX_INDEX = 0; const int OUTPUT_CLASS_INDEX = 1; const int OUTPUT_MASK_INDEX = 2; const int BBOX_INDEX_LX = 0; const int BBOX_INDEX_LY = 1; const int BBOX_INDEX_RX = 2; const int BBOX_INDEX_RY = 3; const int BBOX_INDEX_PROB = 4; const int BBOX_INDEX_SCALE_NUM = 5; } // namespace namespace MxBase { FasterRcnnMindsporePost &FasterRcnnMindsporePost::operator=(const FasterRcnnMindsporePost &other) { if (this == &other) { return *this; } ObjectPostProcessBase::operator=(other); return *this; } APP_ERROR FasterRcnnMindsporePost::ReadConfigParams() { APP_ERROR ret = configData_.GetFileValue<uint32_t>("CLASS_NUM", classNum_); if (ret != APP_ERR_OK) { LogWarn << GetError(ret) << "No CLASS_NUM in config file, default value(" << classNum_ << ")."; } ret = configData_.GetFileValue<float>("SCORE_THRESH", scoreThresh_); if (ret != APP_ERR_OK) { LogWarn << GetError(ret) << "No SCORE_THRESH in config file, default value(" << scoreThresh_ << ")."; } ret = configData_.GetFileValue<float>("IOU_THRESH", iouThresh_); if (ret != APP_ERR_OK) { LogWarn << GetError(ret) << "No IOU_THRESH in config file, default value(" << iouThresh_ << ")."; } ret = configData_.GetFileValue<uint32_t>("RPN_MAX_NUM", rpnMaxNum_); if (ret != APP_ERR_OK) { LogWarn << GetError(ret) << "No RPN_MAX_NUM in config file, default value(" << rpnMaxNum_ << ")."; } ret = configData_.GetFileValue<uint32_t>("MAX_PER_IMG", maxPerImg_); if (ret != APP_ERR_OK) { LogWarn << GetError(ret) << "No MAX_PER_IMG in config file, default value(" << maxPerImg_ << ")."; } LogInfo << "The config parameters of post process are as follows: \n" << " CLASS_NUM: " << classNum_ << " \n" << " SCORE_THRESH: " << scoreThresh_ << " \n" << " IOU_THRESH: " << iouThresh_ << " \n" << " RPN_MAX_NUM: " << rpnMaxNum_ << " \n" << " MAX_PER_IMG: " << maxPerImg_ << " \n"; } APP_ERROR FasterRcnnMindsporePost::Init(const std::map<std::string, std::shared_ptr<void>> &postConfig) { LogInfo << "Begin to initialize FasterRcnnMindsporePost."; APP_ERROR ret = ObjectPostProcessBase::Init(postConfig); if (ret != APP_ERR_OK) { LogError << GetError(ret) << "Fail to superinit in ObjectPostProcessBase."; return ret; } ReadConfigParams(); LogInfo << "End to initialize FasterRcnnMindsporePost."; return APP_ERR_OK; } APP_ERROR FasterRcnnMindsporePost::DeInit() { LogInfo << "Begin to deinitialize FasterRcnnMindsporePost."; LogInfo << "End to deinitialize FasterRcnnMindsporePost."; return APP_ERR_OK; } bool FasterRcnnMindsporePost::IsValidTensors(const std::vector<TensorBase> &tensors) const { if (tensors.size() < OUTPUT_TENSOR_SIZE) { LogError << "The number of tensor (" << tensors.size() << ") is less than required (" << OUTPUT_TENSOR_SIZE << ")"; return false; } auto bboxShape = tensors[OUTPUT_BBOX_INDEX].GetShape(); if (bboxShape.size() != OUTPUT_BBOX_SIZE) { LogError << "The number of tensor[" << OUTPUT_BBOX_INDEX << "] dimensions (" << bboxShape.size() << ") is not equal to (" << OUTPUT_BBOX_SIZE << ")"; return false; } uint32_t total_num = classNum_ * rpnMaxNum_; if (bboxShape[VECTOR_SECOND_INDEX] != total_num) { LogError << "The output tensor is mismatched: " << total_num << "/" << bboxShape[VECTOR_SECOND_INDEX] << ")."; return false; } if (bboxShape[VECTOR_THIRD_INDEX] != OUTPUT_BBOX_TWO_INDEX_SHAPE) { LogError << "The number of bbox[" << VECTOR_THIRD_INDEX << "] dimensions (" << bboxShape[VECTOR_THIRD_INDEX] << ") is not equal to (" << OUTPUT_BBOX_TWO_INDEX_SHAPE << ")"; return false; } auto classShape = tensors[OUTPUT_CLASS_INDEX].GetShape(); if (classShape[VECTOR_SECOND_INDEX] != total_num) { LogError << "The output tensor is mismatched: (" << total_num << "/" << classShape[VECTOR_SECOND_INDEX] << "). "; return false; } auto maskShape = tensors[OUTPUT_MASK_INDEX].GetShape(); if (maskShape[VECTOR_SECOND_INDEX] != total_num) { LogError << "The output tensor is mismatched: (" << total_num << "/" << maskShape[VECTOR_SECOND_INDEX] << ")."; return false; } return true; } static bool CompareDetectBoxes(const MxBase::DetectBox &box1, const MxBase::DetectBox &box2) { return box1.prob > box2.prob; } static void GetDetectBoxesTopK(std::vector<MxBase::DetectBox> &detBoxes, size_t kVal) { std::sort(detBoxes.begin(), detBoxes.end(), CompareDetectBoxes); if (detBoxes.size() <= kVal) { return; } LogDebug << "Total detect boxes: " << detBoxes.size() << ", kVal: " << kVal; detBoxes.erase(detBoxes.begin() + kVal, detBoxes.end()); } void FasterRcnnMindsporePost::GetValidDetBoxes(const std::vector<TensorBase> &tensors, std::vector<DetectBox> &detBoxes, uint32_t batchNum) { LogInfo << "Begin to GetValidDetBoxes."; auto *bboxPtr = (aclFloat16 *)GetBuffer(tensors[OUTPUT_BBOX_INDEX], batchNum); // 1 * 80000 * 5 auto *labelPtr = (int32_t *)GetBuffer(tensors[OUTPUT_CLASS_INDEX], batchNum); // 1 * 80000 * 1 auto *maskPtr = (bool *)GetBuffer(tensors[OUTPUT_MASK_INDEX], batchNum); // 1 * 80000 * 1 // mask filter float prob = 0; size_t total = rpnMaxNum_ * classNum_; for (size_t index = 0; index < total; ++index) { if (!maskPtr[index]) { continue; } size_t startIndex = index * BBOX_INDEX_SCALE_NUM; prob = aclFloat16ToFloat(bboxPtr[startIndex + BBOX_INDEX_PROB]); if (prob <= scoreThresh_) { continue; } MxBase::DetectBox detBox; float x1 = aclFloat16ToFloat(bboxPtr[startIndex + BBOX_INDEX_LX]); float y1 = aclFloat16ToFloat(bboxPtr[startIndex + BBOX_INDEX_LY]); float x2 = aclFloat16ToFloat(bboxPtr[startIndex + BBOX_INDEX_RX]); float y2 = aclFloat16ToFloat(bboxPtr[startIndex + BBOX_INDEX_RY]); detBox.x = (x1 + x2) / COORDINATE_PARAM; detBox.y = (y1 + y2) / COORDINATE_PARAM; detBox.width = x2 - x1; detBox.height = y2 - y1; detBox.prob = prob; detBox.classID = labelPtr[index]; detBoxes.push_back(detBox); } GetDetectBoxesTopK(detBoxes, maxPerImg_); } void FasterRcnnMindsporePost::ConvertObjInfoFromDetectBox(std::vector<DetectBox> &detBoxes, std::vector<ObjectInfo> &objectInfos, const ResizedImageInfo &resizedImageInfo) { for (auto &detBoxe : detBoxes) { if (detBoxe.classID < 0) { continue; } ObjectInfo objInfo = {}; objInfo.classId = (float)detBoxe.classID; objInfo.className = configData_.GetClassName(detBoxe.classID); objInfo.confidence = detBoxe.prob; objInfo.x0 = std::max<float>(detBoxe.x - detBoxe.width / COORDINATE_PARAM, 0); objInfo.y0 = std::max<float>(detBoxe.y - detBoxe.height / COORDINATE_PARAM, 0); objInfo.x1 = std::max<float>(detBoxe.x + detBoxe.width / COORDINATE_PARAM, 0); objInfo.y1 = std::max<float>(detBoxe.y + detBoxe.height / COORDINATE_PARAM, 0); objInfo.x0 = std::min<float>(objInfo.x0, resizedImageInfo.widthOriginal - 1); objInfo.y0 = std::min<float>(objInfo.y0, resizedImageInfo.heightOriginal - 1); objInfo.x1 = std::min<float>(objInfo.x1, resizedImageInfo.widthOriginal - 1); objInfo.y1 = std::min<float>(objInfo.y1, resizedImageInfo.heightOriginal - 1); LogDebug << "Find object: " << "classId(" << objInfo.classId << "), confidence(" << objInfo.confidence << "), Coordinates(" << objInfo.x0 << ", " << objInfo.y0 << "; " << objInfo.x1 << ", " << objInfo.y1 << ")."; objectInfos.push_back(objInfo); } } void FasterRcnnMindsporePost::ObjectDetectionOutput(const std::vector<TensorBase> &tensors, std::vector<std::vector<ObjectInfo>> &objectInfos, const std::vector<ResizedImageInfo> &resizedImageInfos) { LogDebug << "FasterRcnnMindsporePost start to write results."; auto shape = tensors[OUTPUT_BBOX_INDEX].GetShape(); uint32_t batchSize = shape[0]; for (uint32_t i = 0; i < batchSize; ++i) { std::vector<MxBase::DetectBox> detBoxes; std::vector<ObjectInfo> objectInfo; GetValidDetBoxes(tensors, detBoxes, i); LogInfo << "DetBoxes size: " << detBoxes.size() << " iouThresh_: " << iouThresh_; NmsSort(detBoxes, iouThresh_, MxBase::MAX); ConvertObjInfoFromDetectBox(detBoxes, objectInfo, resizedImageInfos[i]); objectInfos.push_back(objectInfo); } LogDebug << "FasterRcnnMindsporePost write results successed."; } APP_ERROR FasterRcnnMindsporePost::Process(const std::vector<TensorBase> &tensors, std::vector<std::vector<ObjectInfo>> &objectInfos, const std::vector<ResizedImageInfo> &resizedImageInfos, const std::map<std::string, std::shared_ptr<void>> &configParamMap) { LogDebug << "Begin to process FasterRcnnMindsporePost."; auto inputs = tensors; APP_ERROR ret = CheckAndMoveTensors(inputs); if (ret != APP_ERR_OK) { LogError << "CheckAndMoveTensors failed, ret=" << ret; return ret; } ObjectDetectionOutput(inputs, objectInfos, resizedImageInfos); LogInfo << "End to process FasterRcnnMindsporePost."; return APP_ERR_OK; } extern "C" { std::shared_ptr<MxBase::FasterRcnnMindsporePost> GetObjectInstance() { LogInfo << "Begin to get FasterRcnnMindsporePost instance."; auto instance = std::make_shared<FasterRcnnMindsporePost>(); LogInfo << "End to get FasterRcnnMindsporePost Instance"; return instance; } } } // namespace MxBase3、CMakeLists.txt编译脚本在编译脚本中,需要指定 CMake最低版本要求、项目信息、编译选项等参数,并且需要指定特定头文件和特定库文件的搜索路径。除此之外,要说明根据FasterRcnnMindsporePost.cpp源文件生成libfasterrcnn_mindspore_post.so可执行文件,同时需要指定可执行文件的安装位置,通常为{MX_SDK_HOME}/lib/modelpostprocessors/cmake_minimum_required(VERSION 3.5.2) project(fasterrcnnpost) add_definitions(-D_GLIBCXX_USE_CXX11_ABI=0) set(PLUGIN_NAME "fasterrcnn_mindspore_post") set(TARGET_LIBRARY ${PLUGIN_NAME}) set(ACL_LIB_PATH $ENV{ASCEND_HOME}/ascend-toolkit/latest/acllib) include_directories(${CMAKE_CURRENT_BINARY_DIR}) include_directories($ENV{MX_SDK_HOME}/include) include_directories($ENV{MX_SDK_HOME}/opensource/include) include_directories($ENV{MX_SDK_HOME}/opensource/include/opencv4) include_directories($ENV{MX_SDK_HOME}/opensource/include/gstreamer-1.0) include_directories($ENV{MX_SDK_HOME}/opensource/include/glib-2.0) include_directories($ENV{MX_SDK_HOME}/opensource/lib/glib-2.0/include) link_directories($ENV{MX_SDK_HOME}/lib) link_directories($ENV{MX_SDK_HOME}/opensource/lib/) add_compile_options(-std=c++11 -fPIC -fstack-protector-all -pie -Wno-deprecated-declarations) add_compile_options("-DPLUGIN_NAME=${PLUGIN_NAME}") add_compile_options("-Dgoogle=mindxsdk_private") add_definitions(-DENABLE_DVPP_INTERFACE) message("ACL_LIB_PATH:${ACL_LIB_PATH}.") include_directories(${ACL_LIB_PATH}/include) add_library(${TARGET_LIBRARY} SHARED ./FasterRcnnMindsporePost.cpp ./FasterRcnnMindsporePost.h) target_link_libraries(${TARGET_LIBRARY} glib-2.0 gstreamer-1.0 gobject-2.0 gstbase-1.0 gmodule-2.0) target_link_libraries(${TARGET_LIBRARY} plugintoolkit mxpidatatype mxbase) target_link_libraries(${TARGET_LIBRARY} -Wl,-z,relro,-z,now,-z,noexecstack -s) install(TARGETS ${TARGET_LIBRARY} LIBRARY DESTINATION $ENV{MX_SDK_HOME}/lib/modelpostprocessors/)4、配置编译环境步骤一:指定“CMakeLists.txt”编译配置文件在工程界面左侧目录找到“CMakeLists.txt”文件,右键弹出并单击如所示“Load CMake Project”,即可指定此配置文件进行工程编译。注:本项目编译文件CMakeLists.txt在目录./postprocess/下,上图仅作为功能展示步骤二:编译配置在MindStudio工程界面,依次选择“Build > Edit Build Configuration...”,进入编译配置页面,如图,配置完成后单击“OK”保存编译配置。5、执行编译单击“Build”编译工程。如果在编译过程中无错误提示,且编译进度到“100%”,则表示编译成功,如图。编译成功后,会在项目目录下生成build文件夹,里面有我们需要的可执行文件如图,也可在CMakeLists.txt中最后一行指定可执行文件安装的位置。8、pipeline文件编排pipeline文件编排是python版SDK最主要的推理开发步骤,作为一个目标检测任务,主要包括以下几个步骤: 图片获取 → 图片解码 → 图像缩放 → 目标检测 → 序列化 → 结果发送,以下介绍pipeline文件流程编排步骤:步骤一:在顶部菜单栏中选择“Ascend>MindX SDK Pipeline”,打开空白的pipeline绘制界面,如图:步骤二:从左方插件库中拖动所需插件,放入编辑区,如图:以下介绍本项目中,各个插件的功能:插件名称插件功能appsrc0第一个输入张量,包含了图像数据appsrc1第二个输入张量,包含了图像元数据,主要是图像原始尺寸和图像缩放比mxpi_imagedecoder0用于图像解码,当前只支持JPG/JPEG/BMP格式mxpi_imageresize0对解码后的YUV格式的图像进行指定宽高的缩放,暂时只支持YUV格式的图像mxpi_tensorinfer0对输入的两个张量进行推理mxpi_objectpostprocessor0继承图像后处理基类,用于对目标检测模型推理的输出张量进行后处理mxpi_dataserialize0将stream结果组装成json字符串输出appsink0从stream中获取数据步骤三:单击选中编辑区内的插件,在插件属性展示区自定义配置(如插件属性中的路径参数),如图:步骤四:单击编辑区空白区域,插件两端出现接口,按照一定顺序用鼠标连接以上插件,然后点击编辑区下方Format进行格式化,最后点击编辑区下方Save保存pipeline文件,编写好的pipeline文件可视化结果如下图所示:接下来展示文本代码:{ "im_fasterrcnn": { "stream_config": { "deviceId": "0" }, "appsrc0": { "props": { "blocksize": "409600" }, "factory": "appsrc", "next": "mxpi_imagedecoder0" }, "mxpi_imagedecoder0": { "factory": "mxpi_imagedecoder", "next": "mxpi_imageresize0" }, "mxpi_imageresize0": { "props": { "parentName": "mxpi_imagedecoder0", "resizeHeight": "768", "resizeWidth": "1280", "resizeType": "Resizer_KeepAspectRatio_Fit" }, "factory": "mxpi_imageresize", "next": "mxpi_tensorinfer0:0" }, "appsrc1": { "props": { "blocksize": "409600" }, "factory": "appsrc", "next": "mxpi_tensorinfer0:1" }, "mxpi_tensorinfer0": { "props": { "dataSource": "mxpi_imageresize0,appsrc1", "modelPath": "../models/conversion-scripts/fasterrcnn_mindspore.om" }, "factory": "mxpi_tensorinfer", "next": "mxpi_objectpostprocessor0" }, "mxpi_objectpostprocessor0": { "props": { "dataSource": "mxpi_tensorinfer0", "postProcessConfigPath": "../models/fasterrcnn_coco2017.cfg", "labelPath": "../models/coco2017.names", "postProcessLibPath": "../../postprocess/build/libfasterrcnn_mindspore_post.so" }, "factory": "mxpi_objectpostprocessor", "next": "mxpi_dataserialize0" }, "mxpi_dataserialize0": { "props": { "outputDataKeys": "mxpi_objectpostprocessor0" }, "factory": "mxpi_dataserialize", "next": "appsink0" }, "appsink0": { "factory": "appsink" } } }
  • [技术干货] Fast-SCNN(语义分割/Pytorch)
    语义分割,也称为全像素语义分割(full-pixel semantic segmentation),是一种典型的计算机视觉问题,其中图像中的每个像素根据其所属的感兴趣对象被分配类别ID。 早期的计算机视觉问题只发现边缘(线条和曲线)或渐变等元素,但它们从未完全按照人类感知的方式提供像素级别的图像理解。语义分割将属于同一目标的图像部分聚集在一起来解决这个问题,从而扩展了其应用领域。Fast-SCNN是一个实时的语义分割模型。其基于现有的two-branch方法(BiSeNet),引入了一个learning to downsample模块,在cityscapes上得到68.0%的miou本案例是Fast-SCNN论文复现的体验案例,模型基于Fast-SCNN: Fast Semantic Segmentation Network中提出的模型结构实现,会载入预训练模型,训练数据集为Cityscape.具体算法介绍:cid:link_0注意事项:本案例使用框架**:** PyTorch1.4.0运行代码方法**:** 点击本页面顶部菜单栏的三角形运行按钮或按Ctrl+Enter键 运行每个方块中的代码JupyterLab的详细用法**:** 请参考《ModelAtrs JupyterLab使用指导》碰到问题的解决办法**:** 请参考《ModelAtrs JupyterLab常见问题解决办法》1.数据和代码下载运行下面代码,进行数据和代码的下载和解压缩本案例使用Cityscape子集,数据位于fast-scnn/datasets中import os# 数据代码下载!wget https://obs-aigallery-zc.obs.cn-north-4.myhuaweicloud.com/algorithm/fast-scnn.zip# 解压缩os.system('unzip fast-scnn.zip -d ./')--2021-06-16 15:28:21-- https://obs-aigallery-zc.obs.cn-north-4.myhuaweicloud.com/algorithm/fast-scnn.zipResolving proxy-notebook.modelarts.com (proxy-notebook.modelarts.com)... 192.168.6.62Connecting to proxy-notebook.modelarts.com (proxy-notebook.modelarts.com)|192.168.6.62|:8083... connected.Proxy request sent, awaiting response... 200 OKLength: 2215542147 (2.1G) [application/zip]Saving to: ‘fast-scnn.zip’fast-scnn.zip 100%[===================>] 2.06G 356MB/s in 6.2s 2021-06-16 15:28:27 (343 MB/s) - ‘fast-scnn.zip’ saved [2215542147/2215542147]02.模型训练2.1依赖库安装及加载import timeimport copyimport datetimeimport sysimport osos.system('pip install thop')os.system('pip install tabulate')os.system('pip install -U PyYAML')root_path = './fast-scnn/'os.chdir(root_path)import loggingimport torchimport torch.nn as nnimport torch.utils.data as dataimport torch.nn.functional as Ffrom torchvision import transformsfrom tools.train import *from segmentron.data.dataloader import get_segmentation_datasetfrom segmentron.models.model_zoo import get_segmentation_modelfrom segmentron.solver.loss import get_segmentation_lossfrom segmentron.solver.optimizer import get_optimizerfrom segmentron.solver.lr_scheduler import get_schedulerfrom segmentron.utils.distributed import *from segmentron.utils.score import SegmentationMetricfrom segmentron.utils.filesystem import save_checkpointfrom segmentron.utils.options import parse_argsfrom segmentron.utils.default_setup import default_setupfrom segmentron.utils.visualize import show_flops_paramsfrom segmentron.utils.visualize import get_color_palletefrom segmentron.config import cfgimport argparseimport matplotlib.pyplot as pltfrom PIL import Image/home/ma-user/anaconda3/envs/Pytorch-1.4.0/lib/python3.6/site-packages/requests/__init__.py:80: RequestsDependencyWarning: urllib3 (1.26.3) or chardet (3.0.4) doesn't match a supported version! RequestsDependencyWarning)INFO:root:Using MoXing-v2.0.0.rc0-19e4d3abINFO:root:Using OBS-Python-SDK-3.20.9.12.2训练参数设置详细参数设置可以查看 fast-scnn/configs/cityscapes_fast_scnn.yaml 和 fast-scnn/segmentron/config/settings.pyparser = argparse.ArgumentParser(description='Run')parser.add_argument('--num_nodes', type=int, default=1)parser.add_argument('--cuda_visiable', type=str, default='0')parser.add_argument('--config_file', default='./configs/cityscapes_fast_scnn.yaml', help='config file path')parser.add_argument('--training_dataset', default='/home/ma-user/work/fast-scnn/datasets/', help='Training dataset directory')# cuda settingparser.add_argument('--no-cuda', action='store_true', default=False, help='disables CUDA training')parser.add_argument('--local_rank', type=int, default=0)# pre trainedparser.add_argument('--resume', type=str, default='./pre-trained_weights/best_model.pth', help='put the path to resuming file if needed')parser.add_argument('--log-iter', type=int, default=10, help='print log every log-iter') # for evaluationparser.add_argument('--val-epoch', type=int, default=1, help='run validation every val-epoch')parser.add_argument('--skip-val', action='store_true', default=False, help='skip validation during training') args, unknown = parser.parse_known_args()# get configcfg.update_from_file(args.config_file)cfg.PHASE = 'train'cfg.ROOT_PATH = root_pathcfg.check_and_freeze()# setup python train environment, logger, seed..default_setup(args)2.3开始训练trainer = Trainer(args)trainer.train()3.模型测试3.1设置测试图像路径可以上传你想要测试的图像,并修改路径args.input_img = './tools/test.png'3.2加载模型¶# image transformtransform = transforms.Compose([ transforms.ToTensor(), transforms.Normalize(cfg.DATASET.MEAN, cfg.DATASET.STD),])model = get_segmentation_model().to(args.device)model.eval()print('模型加载成功')INFO:root:load pretrained model from ./trained_model/model/best_model.pthINFO:root:Shape unmatched weights: []INFO:root:模型加载成功3.3开始测试if os.path.isdir(args.input_img): img_paths = [os.path.join(args.input_img, x) for x in os.listdir(args.input_img)]else: img_paths = [args.input_img]for img_path in img_paths: image = Image.open(img_path).convert('RGB') images = transform(image).unsqueeze(0).to(args.device) with torch.no_grad(): output = model(images) pred = torch.argmax(output[0], 1).squeeze(0).cpu().data.numpy() mask = get_color_pallete(pred).convert('RGB') plt.figure(figsize=(20,20)) # 显示缩放比例 plt.subplot(1,2,1) plt.imshow(image) plt.subplot(1,2,2) plt.imshow(mask) plt.show()
  • [技术干货] Transformer-机器翻译
    Transformer机器翻译,是指使用计算机将一种自然语言转换为另一种自然语言的过程。这里,自然语言是指日常使用的人类语言(如中文、英语),区别于人工为特定目的创造的语言(如计算机编程语言)。 机器翻译是自然语言处理(NLP)的一个研究分支,是人工智能的终极目标之一,具有重要的科学研究价值。 2017年,谷歌在论文《Attention Is All You Need》中提出了Transformer模型。这种基于自注意力机制的模型能够很好地解决序列模型的问题,比如机器翻译。Transformer应用在机器翻译任务中,不仅提高了翻译的效果,由于其高度并行化的设计,还大幅提高了训练的效率。本案例是《Attention Is All You Need》论文复现的体验案例,数据集为WMT2014 英语-德语数据集 具体算法介绍:cid:link_0注意事项:1.本案例使用框架:PyTorch1.4.02.本案例使用硬件:GPU: 1*NVIDIA-V100NV32(32GB) | CPU: 8 核 64GB3.运行代码方法: 点击本页面顶部菜单栏的三角形运行按钮或按Ctrl+Enter键 运行每个方块中的代码4.JupyterLab的详细用法: 请参考《ModelAtrs JupyterLab使用指导》5.碰到问题的解决办法**:** 请参考《ModelAtrs JupyterLab常见问题解决办法》1.下载代码和数据import moxing as mox mox.file.copy_parallel('obs://obs-aigallery-zc/algorithm/Transformer_translate','./Transformer_translate')INFO:root:Using MoXing-v1.17.3-43fbf97f INFO:root:Using OBS-Python-SDK-3.20.72.模型训练2.1依赖库的加载与安装# -*- coding: utf-8 -*- from __future__ import print_function import os root_path = './Transformer_translate' os.chdir(root_path) os.system('pip install --upgrade numpy') os.system('pip install --ignore-installed PyYAML==5.4.1') os.system('pip install fairseq') os.system('pip install sacremoses') os.system('pip install nltk') os.system('pip install subword-nmt') os.system('pip install tqdm')02.2参数设置import tqdm import argparse parser = argparse.ArgumentParser(description='Training') parser.add_argument('--resume_net', default='no', type=str, help='resume net for retraining') parser.add_argument('--training_dataset', default='./data/data-bin', help='Training dataset directory') parser.add_argument('--save_folder', default='./outputs', help='Location to save checkpoint models') parser.add_argument('--max_tokens', default=4096, type=int) parser.add_argument('--optimizer', default='adam', type=str) parser.add_argument('--weight_decay', default=0.0, type=float) parser.add_argument('--lr', default=0.0007, type=float) parser.add_argument('--clip_norm', default=0, type=float) parser.add_argument('--load_weights', type=str, default='./model/model.pth', metavar='PATH') parser.add_argument('--eval', default='False', type=str, choices=['True', 'False']) parser.add_argument('--restore', default='True', type=str, choices=['True', 'False']) # For evaluation parser.add_argument('--eval_result_path', default='./outputs/eval') args, unknown = parser.parse_known_args() import shutil def get_files_tree(src="src_path"): req_files = [] for r, d, files in os.walk(src): for file in files: src_file = os.path.join(r, file) src_file = src_file.replace('\\', '/') if src_file.endswith('.db'): continue req_files.append(src_file) return req_files def copy_tree_force(src_path="",dest_path=""): """ make sure that all the paths has correct slash characters. """ for cf in get_files_tree(src=src_path): df= cf.replace(src_path, dest_path) if not os.path.exists(os.path.dirname(df)): os.makedirs(os.path.dirname(df)) shutil.copy2(cf, df) train_input_dir = args.training_dataset if not os.path.exists(train_input_dir): os.makedirs(train_input_dir) else: print(train_input_dir, 'already exists') if not os.path.exists(args.eval_result_path): os.makedirs(args.eval_result_path) model_path=args.load_weights # Train command=''' CUDA_VISIBLE_DEVICES=0 fairseq-train '''+ train_input_dir +''' \ --restore-file '''+ model_path +''' \ --save-dir '''+ args.save_folder +''' \ --optimizer '''+ args.optimizer +''' \ --adam-betas '(0.9, 0.98)' \ --clip-norm '''+ str(args.clip_norm) +''' \ --lr-scheduler inverse_sqrt \ --warmup-init-lr 1e-07 \ --warmup-updates 4000 \ --lr '''+ str(args.lr) +''' \ --min-lr 1e-09 \ --criterion label_smoothed_cross_entropy \ --label-smoothing 0.1 \ --weight-decay '''+ str(args.weight_decay) +''' \ --max-tokens '''+ str(args.max_tokens) +''' \ --save-interval-updates 50 \ --max-update 50 \ --keep-interval-updates 20 \ --decoder-attention-heads 16 \ --decoder-embed-dim 1024 \ --decoder-ffn-embed-dim 4096 \ --decoder-layerdrop 0 \ --decoder-layers 6 \ --decoder-output-dim 1024 \ --encoder-attention-heads 16 \ --encoder-embed-dim 1024 \ --encoder-ffn-embed-dim 4096 \ --encoder-layerdrop 0 \ --encoder-layers 6 \ --source-lang en \ --share-decoder-input-output-embed \ --target-lang de \ --optimizer adam \ --optimizer-overrides {} \ --reset-optimizer \ --save-interval 0 \ --keep-last-epochs 1 \ --max-epoch 31 \ --max-source-positions 1024 \ --max-target-positions 1024 \ --max-tokens 3584 \ --min-loss-scale 0.0001 \ --min-lr 1e-09 \ --stop-time-hours 0.1 \ --arch transformer_wmt_en_de '''./data/data-bin already exists2.3开始训练print(command) ret = os.system(command) copy_tree_force('./model', args.save_folder) print('training end')CUDA_VISIBLE_DEVICES=0 fairseq-train ./data/data-bin --restore-file ./model/model.pth --save-dir ./outputs --optimizer adam --adam-betas '(0.9, 0.98)' --clip-norm 0 --lr-scheduler inverse_sqrt --warmup-init-lr 1e-07 --warmup-updates 4000 --lr 0.0007 --min-lr 1e-09 --criterion label_smoothed_cross_entropy --label-smoothing 0.1 --weight-decay 0.0 --max-tokens 4096 --save-interval-updates 50 --max-update 50 --keep-interval-updates 20 --decoder-attention-heads 16 --decoder-embed-dim 1024 --decoder-ffn-embed-dim 4096 --decoder-layerdrop 0 --decoder-layers 6 --decoder-output-dim 1024 --encoder-attention-heads 16 --encoder-embed-dim 1024 --encoder-ffn-embed-dim 4096 --encoder-layerdrop 0 --encoder-layers 6 --source-lang en --share-decoder-input-output-embed --target-lang de --optimizer adam --optimizer-overrides {} --reset-optimizer --save-interval 0 --keep-last-epochs 1 --max-epoch 31 --max-source-positions 1024 --max-target-positions 1024 --max-tokens 3584 --min-loss-scale 0.0001 --min-lr 1e-09 --stop-time-hours 0.1 --arch transformer_wmt_en_de 0 [] training end3.模型测试# -*- coding: utf-8 -*- from tqdm import tqdm from fairseq.models.transformer import TransformerModel from nltk.translate.bleu_score import sentence_bleu import os import torch import numpy as np from PIL import Image from io import BytesIO from collections import OrderedDict import torch.backends.cudnn as cudnn cudnn.benchmark = True class ModelClass(): def __init__(self, model_path): self.model_path = model_path # 本行代码必须保留,且无需修改 self.device = torch.device("cpu") print(self.model_path) path=os.getcwd() self.model= TransformerModel.from_pretrained( model_name_or_path= './', checkpoint_file='outputs/model.pth', data_name_or_path='outputs/newstest2014', bpe='subword_nmt', bpe_codes='outputs/bpecodes' ) self.model.eval() self.model = self.model.to(self.device) print('load model success') def translate(self, data): pre_text = self.model.translate(data) return pre_text 需要翻译的自然语言需要是英语,输出为德语,可自行修改成想要翻译的话text_input = "I am lucky." Translator = ModelClass('./outputs/model.pth') result = Translator.translate(text_input) print(result)INFO:fairseq.file_utils:loading archive file ./ INFO:fairseq.file_utils:loading archive file outputs/newstest2014 ./outputs/model.pth INFO:fairseq.tasks.translation:[en] dictionary: 32768 types INFO:fairseq.tasks.translation:[de] dictionary: 32768 types INFO:fairseq.models.fairseq_model:Namespace(activation_dropout=0.0, activation_fn='relu', adam_betas='(0.9, 0.98)', adam_eps=1e-08, adaptive_input=False, adaptive_softmax_cutoff=None, adaptive_softmax_dropout=0, arch='transformer_wmt_en_de_big', attention_dropout=0.1, batch_size=None, bpe='subword_nmt', bpe_codes='outputs/bpecodes', bpe_separator='@@', clip_norm=0.0, criterion='label_smoothed_cross_entropy', cross_self_attention=False, data='outputs/newstest2014', decoder_attention_heads=16, decoder_embed_dim=1024, decoder_embed_path=None, decoder_ffn_embed_dim=4096, decoder_input_dim=1024, decoder_layerdrop=0, decoder_layers=6, decoder_layers_to_keep=None, decoder_learned_pos=False, decoder_normalize_before=False, decoder_output_dim=1024, device_id=0, distributed_backend='nccl', distributed_init_method='tcp://learnfair0487:59946', distributed_port=59946, distributed_rank=0, distributed_world_size=128, dropout=0.3, encoder_attention_heads=16, encoder_embed_dim=1024, encoder_embed_path=None, encoder_ffn_embed_dim=4096, encoder_layerdrop=0, encoder_layers=6, encoder_layers_to_keep=None, encoder_learned_pos=False, encoder_normalize_before=False, eval_bleu_detok='space', eval_bleu_remove_bpe=None, eval_tokenized_bleu=False, fp16=True, ignore_prefix_size=0, label_smoothing=0.1, layernorm_embedding=False, left_pad_source=True, left_pad_target=False, log_format='json', log_interval=10, lr=[0.001], lr_scheduler='inverse_sqrt', lr_shrink=0.1, max_epoch=0, max_sentences=None, max_sentences_valid=None, max_source_positions=1024, max_target_positions=1024, max_tokens=3584, max_update=300000, min_lr=1e-09, momentum=0.99, no_cross_attention=False, no_epoch_checkpoints=False, no_progress_bar=False, no_save=False, no_scale_embedding=False, no_token_positional_embeddings=False, num_batch_buckets=0, optimizer='adam', quant_noise_pq=0, quant_noise_pq_block_size=8, quant_noise_scalar=0, relu_dropout=0.0, restore_file='checkpoint_last.pt', sample_without_replacement=256000, save_dir='/checkpoint02/myleott/2018-05-18/paracrawl_en_de.fp16.maxupd300000.upsamplewmt31.samp_wo_repl256000.transformer_wmt_en_de_big.shareemb.adam.beta0.9,0.98.initlr1e-07.warmup4000.lr0.001.clip0.0.drop0.3.wd0.0.ls0.1.maxtok3584.seed2.ngpu128', save_interval=1, secondary_train_data='/private/home/myleott/data/paracrawl/en-de/paracrawl-release1.en-de.no_url.shuf_uniq_norm.scored.filtered.preprocessed', seed=2, sentence_avg=False, share_all_embeddings=True, share_decoder_input_output_embed=True, skip_invalid_size_inputs_valid_test=False, source_lang='en', target_lang='de', task='translation', tie_adaptive_weights=False, train_subset='train', truncate_source=False, update_freq=[1.0], upsample_primary=31, use_old_adam=False, valid_subset='valid', validate_interval=1, warmup_init_lr=1e-07, warmup_updates=4000, weight_decay=0.0) load model success Ich bin Glück .
  • [技术干货] DynamicRCNN(目标检测/PyTorch)
    计算机视觉领域最基本的三个任务是:分类、目标定位、目标检测。分类的目标是要识别出给出一张图像是什么类别标签(在训练集中的所有类别标签中,给出的这张图属于那类标签的可能性最大);定位的目标不仅要识别出来是什么物体(类标签),还要给出物体的位置,位置一般用bounding box(边框)标记;目标检测是多个物体的定位,即要在一张图中定位出多个目标物体,目标检测任务包含分类和目标定位。DynamicRCNN是一种two-stage的目标检测算法。本案例是DynamicRCNN论文复现的体验案例,模型基于Dynamic R-CNN: Towards High Quality Object Detection via Dynamic Training中提出的模型结构实现,会载入预训练模型,训练数据集为COCO.具体算法介绍:cid:link_0注意事项:本案例使用框架**:** PyTorch1.0.0本案例使用硬件**:** GPU运行代码方法**:** 点击本页面顶部菜单栏的三角形运行按钮或按Ctrl+Enter键 运行每个方块中的代码JupyterLab的详细用法**:** 请参考《ModelAtrs JupyterLab使用指导》碰到问题的解决办法**:** 请参考《ModelAtrs JupyterLab常见问题解决办法》1.数据和代码下载运行下面代码,进行数据和代码的下载和解压本案例使用coco数据,共80个类别。import moxing as moximport osmox.file.copy_parallel('s3://obs-aigallery-zc/algorithm/DynamicRCNN-last','./DynamicRCNN-last')2.模型训练2.1依赖库安装及加载import osos.system('pip install pycocotools')root_path = './DynamicRCNN-last/'os.chdir(root_path)from PIL import Image, ImageDrawfrom tqdm import tqdmfrom io import BytesIOfrom collections import OrderedDictimport torch.backends.cudnn as cudnnfrom torch.utils.data import DataLoader, Datasetimport torchvision.transforms as transformsimport matplotlib.pyplot as pltimport sysimport argparseimport cv2import numpy as npimport torchfrom realTrain import trainfrom config import config as cfgfrom network import Networkfrom dynamic_rcnn.engine.checkpoint import DetectronCheckpointerfrom dynamic_rcnn.engine.comm import synchronize, get_rank, get_world_size,all_gather, is_main_processfrom dynamic_rcnn.utils.logger import setup_loggerfrom dynamic_rcnn.utils.pyt_utils import mkdir, draw_boxfrom dynamic_rcnn.datasets.structures.image_list import to_image_listcudnn.benchmark = True2.2训练参数设置详细的参数可以看DynamicRCNN-last/config.pyparser = argparse.ArgumentParser( description="PyTorch Object Detection Training")parser.add_argument("--local_rank", type=int, default=0)parser.add_argument("--training_iter", type=int, default=100)parser.add_argument("--num_gpus", type=int, default=1)parser.add_argument("--eval",type=str,default='False')parser.add_argument("--load_weight",type=str, default='std')parser.add_argument("--check_period",type=int,default=5000)## add or alter by BLBparser.add_argument('--training_dataset', default='./coco_data', help='Training dataset directory') parser.add_argument('--save_folder', default='./model', help='Location to save checkpoint models')parser.add_argument('--data_url', default='./coco_data', type=str, help='the training and validation data path')args, unknown = parser.parse_known_args()2.3开始训练train(args)world size: 12021-05-24 16:42:46,091 train INFO: Using 1 GPUsINFO:train:Using 1 GPUs2021-05-24 16:42:46,094 train INFO: Namespace(check_period=5000, data_url='./coco_data', distributed=False, eval='False', load_weight='std', local_rank=0, num_gpus=1, save_folder='./model', training_dataset='./coco_data', training_iter=100)INFO:train:Namespace(check_period=5000, data_url='./coco_data', distributed=False, eval='False', load_weight='std', local_rank=0, num_gpus=1, save_folder='./model', training_dataset='./coco_data', training_iter=100)2021-05-24 16:42:54,256 train INFO: Loading checkpoint from /home/ma-user/work/DynamicRCNN-last/trained_model/model/iteration_270000_mAP_49.2.pthINFO:train:Loading checkpoint from /home/ma-user/work/DynamicRCNN-last/trained_model/model/iteration_270000_mAP_49.2.pth2021-05-24 16:42:57,417 train INFO: 加载了本地预训练好的,达到论文精度的best_model.pth进行迁移训练INFO:train:加载了本地预训练好的,达到论文精度的best_model.pth进行迁移训练loading annotations into memory...Done (t=0.91s)creating index...index created!{1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9, 10: 10, 11: 11, 13: 12, 14: 13, 15: 14, 16: 15, 17: 16, 18: 17, 19: 18, 20: 19, 21: 20, 22: 21, 23: 22, 24: 23, 25: 24, 27: 25, 28: 26, 31: 27, 32: 28, 33: 29, 34: 30, 35: 31, 36: 32, 37: 33, 38: 34, 39: 35, 40: 36, 41: 37, 42: 38, 43: 39, 44: 40, 46: 41, 47: 42, 48: 43, 49: 44, 50: 45, 51: 46, 52: 47, 53: 48, 54: 49, 55: 50, 56: 51, 57: 52, 58: 53, 59: 54, 60: 55, 61: 56, 62: 57, 63: 58, 64: 59, 65: 60, 67: 61, 70: 62, 72: 63, 73: 64, 74: 65, 75: 66, 76: 67, 77: 68, 78: 69, 79: 70, 80: 71, 81: 72, 82: 73, 84: 74, 85: 75, 86: 76, 87: 77, 88: 78, 89: 79, 90: 80}2021-05-24 16:42:58,405 train INFO: Start trainingINFO:train:Start training2021-05-24 16:42:58,406 train INFO: max_iter:100INFO:train:max_iter:1002021-05-24 16:44:35,066 train INFO: eta: 0:06:26 iter: 20 loss: 1.1161 (1.1389) rpn_cls_loss: 0.0197 (0.0700) rpn_bbox_loss: 0.0415 (0.0787) rcnn_cls_loss: 0.6070 (0.6549) rcnn_bbox_loss: 0.3246 (0.3352) time: 5.6187 (4.8328) data: 0.0111 (0.0345) lr: 0.000200 max mem: 22685INFO:train:eta: 0:06:26 iter: 20 loss: 1.1161 (1.1389) rpn_cls_loss: 0.0197 (0.0700) rpn_bbox_loss: 0.0415 (0.0787) rcnn_cls_loss: 0.6070 (0.6549) rcnn_bbox_loss: 0.3246 (0.3352) time: 5.6187 (4.8328) data: 0.0111 (0.0345) lr: 0.000200 max mem: 226852021-05-24 16:45:19,010 train INFO: eta: 0:03:30 iter: 40 loss: 0.9624 (1.0859) rpn_cls_loss: 0.0257 (0.0521) rpn_bbox_loss: 0.0129 (0.0623) rcnn_cls_loss: 0.5040 (0.6171) rcnn_bbox_loss: 0.3610 (0.3545) time: 0.6644 (3.5150) data: 0.0101 (0.0231) lr: 0.000200 max mem: 22685INFO:train:eta: 0:03:30 iter: 40 loss: 0.9624 (1.0859) rpn_cls_loss: 0.0257 (0.0521) rpn_bbox_loss: 0.0129 (0.0623) rcnn_cls_loss: 0.5040 (0.6171) rcnn_bbox_loss: 0.3610 (0.3545) time: 0.6644 (3.5150) data: 0.0101 (0.0231) lr: 0.000200 max mem: 226852021-05-24 16:46:25,833 train INFO: eta: 0:02:18 iter: 60 loss: 0.9568 (1.0441) rpn_cls_loss: 0.0139 (0.0471) rpn_bbox_loss: 0.0165 (0.0556) rcnn_cls_loss: 0.4574 (0.5867) rcnn_bbox_loss: 0.3618 (0.3547) time: 0.6814 (3.4571) data: 0.0088 (0.0191) lr: 0.000200 max mem: 22685INFO:train:eta: 0:02:18 iter: 60 loss: 0.9568 (1.0441) rpn_cls_loss: 0.0139 (0.0471) rpn_bbox_loss: 0.0165 (0.0556) rcnn_cls_loss: 0.4574 (0.5867) rcnn_bbox_loss: 0.3618 (0.3547) time: 0.6814 (3.4571) data: 0.0088 (0.0191) lr: 0.000200 max mem: 226852021-05-24 16:47:02,932 train INFO: eta: 0:01:01 iter: 80 loss: 0.9744 (1.0196) rpn_cls_loss: 0.0375 (0.0494) rpn_bbox_loss: 0.0299 (0.0577) rcnn_cls_loss: 0.4399 (0.5507) rcnn_bbox_loss: 0.3812 (0.3619) time: 0.6615 (3.0565) data: 0.0109 (0.0174) lr: 0.000200 max mem: 22986INFO:train:eta: 0:01:01 iter: 80 loss: 0.9744 (1.0196) rpn_cls_loss: 0.0375 (0.0494) rpn_bbox_loss: 0.0299 (0.0577) rcnn_cls_loss: 0.4399 (0.5507) rcnn_bbox_loss: 0.3812 (0.3619) time: 0.6615 (3.0565) data: 0.0109 (0.0174) lr: 0.000200 max mem: 229862021-05-24 16:47:28,373 train INFO: eta: 0:00:00 iter: 100 loss: 0.9252 (1.0421) rpn_cls_loss: 0.0358 (0.0691) rpn_bbox_loss: 0.0289 (0.0606) rcnn_cls_loss: 0.4498 (0.5464) rcnn_bbox_loss: 0.3488 (0.3661) time: 0.6337 (2.6996) data: 0.0111 (0.0164) lr: 0.000200 max mem: 22986INFO:train:eta: 0:00:00 iter: 100 loss: 0.9252 (1.0421) rpn_cls_loss: 0.0358 (0.0691) rpn_bbox_loss: 0.0289 (0.0606) rcnn_cls_loss: 0.4498 (0.5464) rcnn_bbox_loss: 0.3488 (0.3661) time: 0.6337 (2.6996) data: 0.0111 (0.0164) lr: 0.000200 max mem: 229862021-05-24 16:47:28,378 train INFO: Saving checkpoint to ./model/checkpoints/model_0000100.pthINFO:train:Saving checkpoint to ./model/checkpoints/model_0000100.pth2021-05-24 16:47:29,013 train INFO: Saving checkpoint to ./model/checkpoints/final_model.pthINFO:train:Saving checkpoint to ./model/checkpoints/final_model.pth2021-05-24 16:47:31,185 train INFO: Total training time: 0:04:32.776027 (2.7278 s / it)INFO:train:Total training time: 0:04:32.776027 (2.7278 s / it)3.模型测试3.1预测类别这80类就是COCO数据集中包括的类别id2name={1: 'person', 2: 'bicycle',3: 'car',4: 'motorcycle',5: 'airplane',6: 'bus',7: 'train',8: 'truck',9: 'boat',10: 'traffic light',11: 'fire hydrant',12: 'stop sign',13: 'parking meter',14: 'bench', 15: 'bird',16: 'cat',17: 'dog',18: 'horse',19: 'sheep',20: 'cow',21: 'elephant',22: 'bear',23: 'zebra',24: 'giraffe',25: 'backpack',26: 'umbrella',27: 'handbag',28: 'tie',29: 'suitcase',30: 'frisbee', 31: 'skis',32: 'snowboard',33: 'sports ball',34: 'kite',35: 'baseball bat',36: 'baseball glove',37: 'skateboard',38: 'surfboard',39: 'tennis racket',40: 'bottle',41: 'wine glass',42: 'cup',43: 'fork',44: 'knife', 45: 'spoon',46: 'bowl',47: 'banana',48: 'apple',49: 'sandwich',50: 'orange',51: 'broccoli',52: 'carrot',53: 'hot dog',54: 'pizza',55: 'donut',56: 'cake',57: 'chair',58: 'couch',59: 'potted plant', 60: 'bed',61: 'dining table',62: 'toilet',63: 'tv',64: 'laptop',65: 'mouse',66: 'remote',67: 'keyboard',68: 'cell phone',69: 'microwave',70: 'oven',71: 'toaster',72: 'sink',73: 'refrigerator',74: 'book', 75: 'clock',76: 'vase',77: 'scissors',78: 'teddy bear',79: 'hair drier',80: 'toothbrush'}3.3展示预测结果¶if __name__ == '__main__': img_path = 'test.jpg' # 你可以选择你想测试的图片,并修改路径 model_path='./trained_model/model/iteration_270000_mAP_49.2.pth' img = predict(img_path,model_path) plt.figure(figsize=(10,10)) #设置窗口大小 plt.imshow(img) plt.show()2021-05-24 17:03:46,379 test.inference INFO: Loading checkpoint from ./trained_model/model/iteration_270000_mAP_49.2.pth2021-05-24 17:03:46,379 test.inference INFO: Loading checkpoint from ./trained_model/model/iteration_270000_mAP_49.2.pth
  • [技术干货] Stable Diffusion文字生成图像
    视频操作观看链接:cid:link_3点击Run in ModelArts,将会进入到ModelArts CodeLab中,这时需要你登录华为云账号,如果没有账号,则需要注册一个,且要进行实名认证,参考 cid:link_0 即可完成账号注册和实名认证。 登录之后,等待片刻,即可进入到CodeLab的运行环境Stable Diffusion文字生成图像 🎨Stable Diffusion 是由 CompVis、Stability AI 和 LAION 共同开发的一个文本转图像模型,它通过 LAION-5B 子集大量的 512x512 图文模型进行训练,我们只要简单的输入一段文本,Stable Diffusion 就可以迅速将其转换为图像,同样我们也可以置入图片或视频,配合文本对其进行处理。接下来 我们会展示如何将 Stable Diffusion 与 🤗 Hugging Face 🧨 Diffusers 的库一起使用。让我们一起动手试验一下吧Stable Diffusion Pipeline使用方法本案例可以使用GPU,也可以使用CPU来运行,GPU生成单张图片约20秒,CPU需6分钟您可以使用如下命令来查询当前机器的GPU是否可用,如果运行结果是一个表格,则表示GPU可用。!nvidia-smiTue Nov 22 16:03:56 2022 +-----------------------------------------------------------------------------+ | NVIDIA-SMI 440.33.01 Driver Version: 440.33.01 CUDA Version: 10.2 | |-------------------------------+----------------------+----------------------+ | GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC | | Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. | |===============================+======================+======================| | 0 Tesla P100-PCIE... On | 00000000:00:0D.0 Off | 0 | | N/A 34C P0 26W / 250W | 0MiB / 16280MiB | 0% Default | +-------------------------------+----------------------+----------------------+ +-----------------------------------------------------------------------------+ | Processes: GPU Memory | | GPU PID Type Process name Usage | |=============================================================================| | No running processes found | +-----------------------------------------------------------------------------+步骤一:安装需要的运行环境耗时约1-2分钟!pip install --upgrade pip !pip install torch==1.12.1 torchvision==0.13.1 torchaudio==0.12.1 !pip install diffusers==0.2.4 !pip install transformers==4.21.1 scipy==1.7.3 ftfy==6.1.1 !pip install "ipywidgets>=7,<8"步骤二:下载AI模型预训练权重文件,加载模型用户可访问Hugging Face Hub获取token,进行下载,下载时间约6分钟左右。本案例已将其模型转存至华为云OBS中,运行如下代码,下载权重即可。下载耗时约30秒。import os import torch import os.path as osp import moxing as mox from diffusers import StableDiffusionPipeline parent = osp.join(os.getcwd(),'CompVis') if not os.path.exists(parent): mox.file.copy_parallel('obs://modelarts-labs-bj4-v2/case_zoo/StableDiffusion/CompVis',parent) if os.path.exists(parent): print('Download success') else: raise Exception('Download Failed') else: print("Model Package already exists!") INFO:root:Using MoXing-v2.1.0.5d9c87c8-5d9c87c8 INFO:root:Using OBS-Python-SDK-3.20.9.1 /home/ma-user/anaconda3/envs/PyTorch-1.8/lib/python3.7/site-packages/requests/__init__.py:104: RequestsDependencyWarning: urllib3 (1.26.12) or chardet (5.0.0)/charset_normalizer (2.0.12) doesn't match a supported version! RequestsDependencyWarning) Model Package already exists!加载模型model_dir = osp.join(osp.join(parent,'stable-diffusion-v1-4'), "diffusers") os.environ["XDG_CACHE_HOME"] = model_dir device = 'cuda' if torch.cuda.is_available() else 'cpu' pipe = StableDiffusionPipeline.from_pretrained(model_dir, # revision="fp16", # torch_dtype=torch.float16 ).to(device) 步骤三: 生成单张图像在GPU上,单张图片生成耗时约20秒在CPU上,单张图片生成耗时约6分钟,且运行内存需16GB以上#@title 请在此处填写Prompt,运行,即可生成单张图像 torch.cuda.empty_cache() prompt = "Close up portrait photo of Megan Fox as part cyborg part human, intimidating stare, Atmospheric, 600mm lens, Sony Alpha α7, epic, dramatic, cinematic lighting, high contrast, 8k, photo realistic, character design --testp --ar 2:3 --upbeta" #@param {type:"string"} image = pipe(prompt)["sample"][0] image0it [00:00, ?it/s]海报生成和分享#@title 请在下方title_char栏填写作品名称,author_char栏填写作者姓名,中文不超过6个字,运行,即可生成海报 import os import moxing as mox from PIL import Image,ImageDraw,ImageFont,ImageFilter # 导入海报需要的素材 if not os.path.exists("/home/ma-user/work/material"): mox.file.copy_parallel('obs://modelarts-labs-bj4-v2/case_zoo/StableDiffusion/AI_paint_TOM.png',"/home/ma-user/work/material/AI_paint_TOM.png") mox.file.copy_parallel('obs://modelarts-labs-bj4-v2/case_zoo/StableDiffusion/方正兰亭准黑_GBK.ttf',"/home/ma-user/work/material/方正兰亭准黑_GBK.ttf") if os.path.exists("/home/ma-user/work/material"): print('Download success') else: raise Exception('Download Failed') else: print("Project already exists") def gen_poster(img,txt1,txt2,path): font1 = ImageFont.truetype(zt,30) font2 = ImageFont.truetype(zt,25) img_draw = ImageDraw.Draw(img) img_draw.text((180,860), txt1, font=font1,fill='#961900') img_draw.text((130,903), txt2, font=font2, fill='#252b3a') img.filter(ImageFilter.BLUR) img.save(path) template_img = "/home/ma-user/work/material/AI_paint_TOM.png" zt = r"/home/ma-user/work/material/方正兰亭准黑_GBK.ttf" temp_image = Image.open(template_img) temp_image.paste(image ,(40,266)) title_char = "CG女神" #@param {type:"string"} author_char = "魔幻少女" #@param {type:"string"} savepath = 'AI_paint_output.png' # 海报图片路径 gen_poster(temp_image,title_char,author_char,savepath) Image.open(savepath) # 显示图片步骤四:生成多张图像#@title 请在此处填写Promot,运行,即可生成3*3张图像 from PIL import Image num_cols = 3 # 图像行数 num_rows = 3 # 图像列数 prompt = "Cygames girl character concept art and illustration by akihiko yoshida , ultimate dressy , amazing detailed face in profile closeup, galaxy in blue hair, Jewelry eyes , wearing a white galaxy dress , Line Array Speaker , Extreme Explosion , Subwoofer , kyoani character face , cute ,pretty girl , dynamic pose, portrait , pixiv daily ranking , pixiv , artstation ,specatcualr details, Volumetric Lighting , Dramatic lighting —ar 9:16 --test --creative --upbeta" #@param {type:"string"} prompt_list = [prompt] * num_cols def image_grid(imgs, rows, cols): assert len(imgs) == rows * cols w, h = imgs[0].size grid = Image.new('RGB', size=(cols * w, rows * h)) grid_w, grid_h = grid.size for i, img in enumerate(imgs): grid.paste(img, box=(i % cols * w, i // cols * h)) return grid all_images = [] for i in range(num_rows): images = pipe(prompt_list)["sample"] all_images.extend(images) for index, img in enumerate(images): img.save("img_%s_%s.png" % (str(i), str(index))) grid = image_grid(all_images, rows=num_rows, cols=num_cols) grid from PIL import Image num_cols = 3 # 图像行数 num_rows = 3 # 图像列数 prompt = "Cygames girl character concept art and illustration by akihiko yoshida , ultimate dressy , amazing detailed face in profile closeup, galaxy in blue hair, Jewelry eyes , wearing a white galaxy dress , Line Array Speaker , Extreme Explosion , Subwoofer , kyoani character face , cute ,pretty girl , dynamic pose, portrait , pixiv daily ranking , pixiv , artstation ,specatcualr details, Volumetric Lighting , Dramatic lighting —ar 9:16 --test --creative --upbeta" #@param {type:"string"} prompt_list = [prompt] * num_cols def image_grid(imgs, rows, cols): assert len(imgs) == rows * cols w, h = imgs[0].size grid = Image.new('RGB', size=(cols * w, rows * h)) grid_w, grid_h = grid.size for i, img in enumerate(imgs): grid.paste(img, box=(i % cols * w, i // cols * h)) return grid all_images = [] for i in range(num_rows): torch.cuda.empty_cache() images = pipe(prompt_list)["sample"] all_images.extend(images) for index, img in enumerate(images): img.save("img_%s_%s.png" % (str(i), str(index))) grid = image_grid(all_images, rows=num_rows, cols=num_cols) grid #@title 请在此处填写Prompt,运行,即可生成3*3张图像0it [00:00, ?it/s] 0it [00:00, ?it/s] 0it [00:00, ?it/s] 0it [00:00, ?it/s] 0it [00:00, ?it/s] 0it [00:00, ?it/s]步骤五:修改prompt提示词1. 什么是 Prompt?Prompt 是生成图片的提示词,可以是一个实体,例如猫。也可以是一串富含想象力的文字,例如:『夕阳日落时,天边有巨大的云朵,海面波涛汹涌,风景,胶片感』。不同的 Prompt 对于生成的图像质量影响非常大,所以如果要生成一幅优秀的图画,就要掌握写 Prompt 的一些经验性技巧。以下是一些优秀图画及相关Promot的示范样例Cygames女孩角色,概念艺术,银河在蓝色的头发,珠宝眼睛,穿着白色的银河连衣裙,线阵列扬声器,极端爆炸promot: Cygames girl character concept art and illustration by akihiko yoshida , ultimate dressy , amazing detailed face in profile closeup, galaxy in blue hair, Jewelry eyes , wearing a white galaxy dress , Line Array Speaker , Extreme Explosion , Subwoofer , kyoani character face , cute ,pretty girl , dynamic pose, portrait , pixiv daily ranking , pixiv , artstation ,specatcualr details, Volumetric Lighting , Dramatic lighting —ar 9:16 --test --creative --upbetapromt:dark style painted, river flowing through forest of cherry blossom trees , under a galaxy filled sky, beautiful, galaxies, deep colors,ultra lighting, Bioelectric Modular Synthesizer, perfect symmetry, cinematic, volumetric lighting, --ar 9:162. 如何修改提示词2.1 Prompt 的设计如何设计 Prompt,下文大概会通过4个方面来说明:Prompt的描述可以从这四个方面入手:图片的风格,内容主体,详细的描述,再加上画家的风格。需要注意的是,这里的 Prompt 公式仅仅是个入门级别的参考,是经验的简单总结,在熟悉了 Prompt 的原理之后,可以尽情的发挥脑洞修改 Prompt。2.2 Prompt 公式Prompt框架:[图片的风格]+[内容主题]+[细节描述]+[绘画风格或者艺术家风格]图片的风格按照这个框架,简单构造一个图片风格,比如:可以是一幅美丽的画,或者是一幅美丽的山水画。内容的主体+详细描述主体可以是各种各样的选择。推荐一些可以激发大家灵感的事物,如山水,人物,建筑房屋,动物等等,尽可能细致刻画这些实体事物。如果是简单的输入“大海”两个字,模型不知道我们想要的风景是什么样子的,一段作品的相对准确的描述,比如:梦幻的大海,白沙滩岸边铺满了粉色的玫瑰花,月光轻柔的人洒在海面上,绿色发光的海浪,我们要去尽量用详细的语言,用细节清楚的描述我们幻想的场景。比如:云中的Skyrim风格的山,有一个照明螺栓击中尖端导致雪崩,山区风景。 对于详细的描述,我们可以拆分【形容词】+【视角】+【时间】+【颜色】+【其他】形容词可以是梦幻,神秘,浪漫或者写实 ……视角可以是:超广角,俯视和仰视 ……时间:秋天,清晨,黄昏,夜晚 ……颜色可以是 红黄绿蓝橙紫……其他可以包含图片的尺寸,4k,8k ,HD,光效,高细节等Prompt 绘画风格和艺术家风格如果想让生成的图片更加的艺术化、风格化,可以考虑在 Prompt 中添加绘画风格和艺术家。艺术绘画风格可以是一些美术风格:梵高风格,油画,水彩,古风,CG感,动漫,少女,赛博朋克,卡通画,中国画,黄昏等等,艺术家风格包含:现实主义,印象派,野兽派,新艺术,表现主义,立体主义,未来主义等等 提示词:这是一幅美丽的画作,描绘了夜晚一大片空旷的沙漠沙丘,中间有许多棵神秘的巨大发光的蓝色树,树的蓝色光芒照亮了周围的环境,天空中的星星,由特德·纳史密斯和托马斯·金卡德创作另外还有一些注意事项和常见的问题在使用关键词的时候,也多去使用一些明确的定义,避免使用“不是xxx”这样的描述。“不是xxx”,可选择的范围就太大了,生成出来的结果可能就和你想要的相去甚远。如果你是个新手,需要一些关于关键词的引导,那你可以去 cid:link_5 这个网站看一看。它收集了很多关键词,并且一步一步、分门别类地为你整理好了。你只需要根据网站给出的步骤,从它的关键词库里选择你想要的效果,然后把这串关键词直接复制到prompt里就好。把“填空题”变成“选择题”,非常方便。 在熟悉了 Prompt 的原理之后,就可以尽情的发挥脑洞修改它的写法,点击链接,快来Happy Prompting吧!2.5 附录:常见的风格列举古典主义 洛可可 巴洛克, 印象派, 新古典主义, 写实主义, 浪漫主义, 唯美主义, 表现主义, 现实主义, 魔幻现实主义, 奇幻现实主义, 象征主义, 抽象主义, 超扁平主义 超前卫艺术 中国风格 浮世绘 极简主义 几何风格 数字艺术, 感念艺术 装饰艺术复古未来主义风格粉彩朋克风格史前遗迹风格波普艺术风格迷幻风格赛博朋克风格未来主义风格抽象技术风格新艺术主义抽象表现主义北欧文艺复兴原始主义立体主义色域绘画波普艺术极简主义矫饰主义步骤六: 使用新的提示词生成图片在掌握了上面提示词Prompt的规则后,我们看下如何使用上面的程序生成自己想要的图片 1.用中文描述提示词,描述的越精准越好2.使用翻译软件将中文翻译成英文3.将英文的Prompt替换上面程序prompt= "......."中的内容,位置分别在程序步骤三和步骤四,例如:将上面梵高的图片替换成狗喝咖啡的内容,如:prompt = "Close-up side view portrait of Cyborg Geisha, rotobic, Machina, super intricate ornaments artwork, by Tooth Wu and wlop, by Alena Aenami, by Alphonse Mucha, by Brian Froud, by Pablo Amaringo, super detailed, large depth of field"替换成prompt ="golden retriever puppy sitting at a diner drinking a cup of coffee, looking melancholy, Edward HopperS"4.再次运行步骤三和步骤四其他参考资料prompts搜索引擎cid:link_5两个Prompts插值cid:link_2生成无缝贴图cid:link_4用 Stable Diffusion 生成的艺术家风格参考库cid:link_1
  • AI人脸编辑-代码参数化
    高保真图像编辑注意:本案例必须使用GPU运行,请查看《ModelArts JupyterLab 硬件规格使用指南》了解切换硬件规格的方法High-Fidelity GAN Inversion for Image Attribute Editing (CVPR 2022) cid:link_81 下载代码和数据import os import moxing as mox if not os.path.exists("/home/ma-user/work/ma_share/HFGI/HFGI"): mox.file.copy_parallel('obs://modelarts-labs-bj4-v2/case_zoo/HFGI/HFGI.zip',"/home/ma-user/work/ma_share/HFGI/HFGI.zip") os.system("cd /home/ma-user/work/ma_share/HFGI;unzip HFGI.zip;rm HFGI.zip") if os.path.exists("/home/ma-user/work/ma_share/HFGI/HFGI"): print('Download success') else: raise Exception('Download Failed') else: print("Project already exists")2 安装依赖环境!pip install ninja !pip install dlib !pip uninstall -y torch !pip uninstall -y torchvision !pip install torch==1.6.0 !pip install torchvision==0.7.0安装完后,需要重启一下kernel,点击上方Restart the kernelÍ HFGI3 开始运行代码#@title Setup Repository import os from argparse import Namespace import time import os import sys import numpy as np from PIL import Image import torch import torchvision.transforms as transforms # from utils.common import tensor2im from models.psp import pSp # we use the pSp framework to load the e4e encoder. %load_ext autoreload %autoreload 2def tensor2im(var): # var shape: (3, H, W) var = var.cpu().detach().transpose(0, 2).transpose(0, 1).numpy() var = ((var + 1) / 2) var[var < 0] = 0 var[var > 1] = 1 var = var * 255 return Image.fromarray(var.astype('uint8'))Step 1: 加载预训练模型model_path = "checkpoint/ckpt.pt" ckpt = torch.load(model_path, map_location='cpu') opts = ckpt['opts'] opts['is_train'] = False opts['checkpoint_path'] = model_path opts= Namespace(**opts) net = pSp(opts) net.eval() net.cuda() print('Model successfully loaded!')Step 2: 设置输入图像#@title 设置输入图像 # Setup required image transformations input_img_path = "test_imgs/1919116757.jpg" #@param {type:"string", dropdown} EXPERIMENT_ARGS = {"image_path": input_img_path} EXPERIMENT_ARGS['transform'] = transforms.Compose([ transforms.Resize((256, 256)), transforms.ToTensor(), transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])]) resize_dims = (256, 256)image_path = EXPERIMENT_ARGS["image_path"] original_image = Image.open(image_path) original_image = original_image.convert("RGB") run_align = True图像对齐import numpy as np import PIL import PIL.Image import scipy import scipy.ndimage import dlib def get_landmark(filepath, predictor): """get landmark with dlib :return: np.array shape=(68, 2) """ detector = dlib.get_frontal_face_detector() img = dlib.load_rgb_image(filepath) dets = detector(img, 1) for k, d in enumerate(dets): shape = predictor(img, d) t = list(shape.parts()) a = [] for tt in t: a.append([tt.x, tt.y]) lm = np.array(a) return lm def align_face(filepath, predictor): """ :param filepath: str :return: PIL Image """ lm = get_landmark(filepath, predictor) lm_chin = lm[0: 17] # left-right lm_eyebrow_left = lm[17: 22] # left-right lm_eyebrow_right = lm[22: 27] # left-right lm_nose = lm[27: 31] # top-down lm_nostrils = lm[31: 36] # top-down lm_eye_left = lm[36: 42] # left-clockwise lm_eye_right = lm[42: 48] # left-clockwise lm_mouth_outer = lm[48: 60] # left-clockwise lm_mouth_inner = lm[60: 68] # left-clockwise # Calculate auxiliary vectors. eye_left = np.mean(lm_eye_left, axis=0) eye_right = np.mean(lm_eye_right, axis=0) eye_avg = (eye_left + eye_right) * 0.5 eye_to_eye = eye_right - eye_left mouth_left = lm_mouth_outer[0] mouth_right = lm_mouth_outer[6] mouth_avg = (mouth_left + mouth_right) * 0.5 eye_to_mouth = mouth_avg - eye_avg # Choose oriented crop rectangle. x = eye_to_eye - np.flipud(eye_to_mouth) * [-1, 1] x /= np.hypot(*x) x *= max(np.hypot(*eye_to_eye) * 2.0, np.hypot(*eye_to_mouth) * 1.8) y = np.flipud(x) * [-1, 1] c = eye_avg + eye_to_mouth * 0.1 quad = np.stack([c - x - y, c - x + y, c + x + y, c + x - y]) qsize = np.hypot(*x) * 2 # read image img = PIL.Image.open(filepath) output_size = 256 transform_size = 256 enable_padding = True # Shrink. shrink = int(np.floor(qsize / output_size * 0.5)) if shrink > 1: rsize = (int(np.rint(float(img.size[0]) / shrink)), int(np.rint(float(img.size[1]) / shrink))) img = img.resize(rsize, PIL.Image.ANTIALIAS) quad /= shrink qsize /= shrink # Crop. border = max(int(np.rint(qsize * 0.1)), 3) crop = (int(np.floor(min(quad[:, 0]))), int(np.floor(min(quad[:, 1]))), int(np.ceil(max(quad[:, 0]))), int(np.ceil(max(quad[:, 1])))) crop = (max(crop[0] - border, 0), max(crop[1] - border, 0), min(crop[2] + border, img.size[0]), min(crop[3] + border, img.size[1])) if crop[2] - crop[0] < img.size[0] or crop[3] - crop[1] < img.size[1]: img = img.crop(crop) quad -= crop[0:2] # Pad. pad = (int(np.floor(min(quad[:, 0]))), int(np.floor(min(quad[:, 1]))), int(np.ceil(max(quad[:, 0]))), int(np.ceil(max(quad[:, 1])))) pad = (max(-pad[0] + border, 0), max(-pad[1] + border, 0), max(pad[2] - img.size[0] + border, 0), max(pad[3] - img.size[1] + border, 0)) if enable_padding and max(pad) > border - 4: pad = np.maximum(pad, int(np.rint(qsize * 0.3))) img = np.pad(np.float32(img), ((pad[1], pad[3]), (pad[0], pad[2]), (0, 0)), 'reflect') h, w, _ = img.shape y, x, _ = np.ogrid[:h, :w, :1] mask = np.maximum(1.0 - np.minimum(np.float32(x) / pad[0], np.float32(w - 1 - x) / pad[2]), 1.0 - np.minimum(np.float32(y) / pad[1], np.float32(h - 1 - y) / pad[3])) blur = qsize * 0.02 img += (scipy.ndimage.gaussian_filter(img, [blur, blur, 0]) - img) * np.clip(mask * 3.0 + 1.0, 0.0, 1.0) img += (np.median(img, axis=(0, 1)) - img) * np.clip(mask, 0.0, 1.0) img = PIL.Image.fromarray(np.uint8(np.clip(np.rint(img), 0, 255)), 'RGB') quad += pad[:2] # Transform. img = img.transform((transform_size, transform_size), PIL.Image.QUAD, (quad + 0.5).flatten(), PIL.Image.BILINEAR) if output_size < transform_size: img = img.resize((output_size, output_size), PIL.Image.ANTIALIAS) # Return aligned image. return imgif 'shape_predictor_68_face_landmarks.dat' not in os.listdir(): # !wget http://dlib.net/files/shape_predictor_68_face_landmarks.dat.bz2 !bzip2 -dk shape_predictor_68_face_landmarks.dat.bz2 def run_alignment(image_path): import dlib predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat") aligned_image = align_face(filepath=image_path, predictor=predictor) print("Aligned image has shape: {}".format(aligned_image.size)) return aligned_image if run_align: input_image = run_alignment(image_path) else: input_image = original_image input_image.resize(resize_dims)Aligned image has shape: (256, 256)img_transforms = EXPERIMENT_ARGS['transform'] transformed_image = img_transforms(input_image)Step 3: 高保真逆向映射(inversion)def display_alongside_source_image(result_image, source_image): res = np.concatenate([np.array(source_image.resize(resize_dims)), np.array(result_image.resize(resize_dims))], axis=1) return Image.fromarray(res) def get_latents(net, x, is_cars=False): codes = net.encoder(x) if net.opts.start_from_latent_avg: if codes.ndim == 2: codes = codes + net.latent_avg.repeat(codes.shape[0], 1, 1)[:, 0, :] else: codes = codes + net.latent_avg.repeat(codes.shape[0], 1, 1) if codes.shape[1] == 18 and is_cars: codes = codes[:, :16, :] return codes#@title 设置上采样模式 mode = "bilinear" #@param {type:"string", dropdown} with torch.no_grad(): x = transformed_image.unsqueeze(0).cuda() tic = time.time() latent_codes = get_latents(net, x) # calculate the distortion map imgs, _ = net.decoder([latent_codes[0].unsqueeze(0).cuda()],None, input_is_latent=True, randomize_noise=False, return_latents=True) res = x - torch.nn.functional.interpolate(torch.clamp(imgs, -1., 1.), size=(256,256) , mode=mode) # ADA img_edit = torch.nn.functional.interpolate(torch.clamp(imgs, -1., 1.), size=(256,256) , mode=mode) res_align = net.grid_align(torch.cat((res, img_edit ), 1)) # consultation fusion conditions = net.residue(res_align) result_image, _ = net.decoder([latent_codes],conditions, input_is_latent=True, randomize_noise=False, return_latents=True) toc = time.time() print('Inference took {:.4f} seconds.'.format(toc - tic)) # Display inversion: display_alongside_source_image(tensor2im(result_image[0]), input_image)Step 4: 高保真图像编辑可以编辑的内容如下:--edit_attribute 编辑属性(inversion', 'age', 'smile', 'eyes', 'lip' ,'beard' )--edit_degree 控制编辑程度(适用于“age”和“smile”)。from editings import latent_editor editor = latent_editor.LatentEditor(net.decoder)#@title 图像编辑设置 # interface-GAN age_model = "./editings/interfacegan_directions/age.pt" #@param {type:"string", dropdown} smile_model = "./editings/interfacegan_directions/smile.pt" #@param {type:"string", dropdown} interfacegan_directions = { 'age': age_model, 'smile': smile_model } edit_status = "smile" #@param {type:"string", dropdown} edit_direction = torch.load(interfacegan_directions[edit_status]).cuda() # 微笑程度 edit_degree = 0.6 #@param {type:"slider", min:-5, max:5, step:0.1}#@title 上采样模型设置 img_edit, edit_latents = editor.apply_interfacegan(latent_codes[0].unsqueeze(0).cuda(), edit_direction, factor=edit_degree) # 设置微笑 # align the distortion map mode = "bilinear" #@param {type:"string", dropdown} img_edit = torch.nn.functional.interpolate(torch.clamp(img_edit, -1., 1.), size=(256,256) , mode=mode) res_align = net.grid_align(torch.cat((res, img_edit ), 1)) # fusion conditions = net.residue(res_align) result, _ = net.decoder([edit_latents],conditions, input_is_latent=True, randomize_noise=False, return_latents=True) result = torch.nn.functional.interpolate(result, size=(256,256) , mode=mode) display_alongside_source_image(tensor2im(result[0]), input_image)#@title ganspace设置 # GANSpace model = "./editings/ganspace_pca/ffhq_pca.pt" #@param {type:"string", dropdown} ganspace_pca = torch.load(model) eyes_param = (54, 7, 8, 20) #@param {type:"raw"} beard_param = (58, 7, 9, -20) #@param {type:"raw"} lip_param = (34, 10, 11, 20) #@param {type:"raw"} ganspace_directions = { 'eyes': eyes_param, # 眼睛 'beard': beard_param, # 胡子 'lip': lip_param } # 嘴唇 edit_option = "lip" #@param {type:"string", dropdown} edit_direction = ganspace_directions[edit_option]#@title 上采样模式设置 img_edit, edit_latents = editor.apply_ganspace(latent_codes[0].unsqueeze(0).cuda(), ganspace_pca, [edit_direction]) # align the distortion map mode = "bilinear" #@param {type:"string", dropdown} img_edit = torch.nn.functional.interpolate(torch.clamp(img_edit, -1., 1.), size=(256,256) , mode=mode) res_align = net.grid_align(torch.cat((res, img_edit ), 1)) conditions = net.residue(res_align) result, _ = net.decoder([edit_latents],conditions, input_is_latent=True, randomize_noise=False, return_latents=True) result = torch.nn.functional.interpolate(result, size=(256,256) , mode=mode) display_alongside_source_image(tensor2im(result[0]), input_image)训练如果需要训练,可以按以下描述进行:准备下载数据集并相应地修改数据集路径./configs/paths_config.py .下载一些预训练模型并将它们放入 ./pretrained.ModelDescriptionStyleGAN2 (FFHQ)Pretrained face generator on FFHQ from rosinality.e4e (FFHQ)Pretrained initial encoder on FFHQ from omertov.Feature extractor (for face)Pretrained IR-SE50 model taken from TreB1eN for ID loss calculation.Feature extractor (for car)Pretrained ResNet-50 model taken from omertov for ID loss calculation.开始训练修改 option 和 training.sh ,开始运行:bash train.sh
  • [经验分享] 使用MindStudio开发铝材表面缺陷检测
    BiliBili视频链接:使用MindStudio完成铝材表面缺陷检测_哔哩哔哩_bilibili使用MindStudio开发铝材表面缺陷检测目 录使用MindStudio开发铝材表面缺陷检测 1. MindStudio介绍 2. 案例模型 3. 环境搭建 3.1 安装MindX SDK和CANN包并配置环境变量 3.2 在windows开发环境同步CANN 3.3 在windows开发环境同步MindX SDK 4. 开发过程 4.1 创建工程 4.2 配置python解释器 4.3 开发步骤 4.4 项目下载连接以及项目结构 5. 运行 5.1 配置远程映射 5.2 精度测试 6. FAQ 1 尺寸不匹配 2 模型路径未进行正确配置 3 未修改pipeline中后处理插件的postProcessLibPath属性 4 同步远端CANN开发包失败 7. 一些个人经验总结 8. Mindstuido下载连接 9. 开发过程中用到的链接 1. MindStudio介绍MindStudio提供AI开发所需的一站式开发环境,支持模型开发、算子开发以及应用开发三个主流程中的开发任务。依靠模型可视化、算力测试、IDE本地仿真调试等功能,MindStudio能够使开发者在一个工具上就能高效便捷地完成AI应用开发 ·MindStudio采用了插件化扩展机制,开发者可以通过开发插件来扩展已有功能。MindStudio-昇腾社区 (hiascend.com)2. 案例模型在本案例中,目的是基于MindX SDK,在华为云昇腾平台上,使用MindStudio开发端到端铝材缺陷检测的参考设计,实现对图像中的铝材进行缺陷类型分类和定位的功能,达到功能要求,并对精度进行测试。3. 环境搭建开发环境为windows版本的MindStudio,运行环境在远端linux上。3.1 安装MindX SDK和CANN包并配置环境变量请先确保远端环境上MindX SDK软件包已安装完成,安装方式请参见安装MindX SDK开发套件。确保远端环境上CANN包已安装完成,安装方式请参见该链接在远端服务器上配置环境变量执行如下命令,打开.bashrc文件vim ~/.bashrc# 在.bashrc文件中添加以下环境变量. ${MX_SDK_HOME}/set_env.sh. ${HOME}/Ascend/ascend-toolkit/set_env.sh# 其中${MX_SDK_HOME}为MindX SDK安装目录,${HOME}为用户目录(如果CANN 开发包装在用户目录,否则为/usr/local/),配置的时候请自行替换成相应目录# 保存退出.bashrc文件# 执行如下命令使环境变量生效source ~/.bashrc#查看环境变量env3.2 在windows开发环境同步CANN工具栏点击“File > Settings > Appearance & Behavior > System Settings > CANN”进入CANN管理界面。点击Change CANN配置CANN包。配置远程连接以及远端CANN包路径(配置到版本号一级)3.3 在windows开发环境同步MindX SDK工具栏点击“File > Settings > Appearance & Behavior > System Settings > MindX SDK”或依次点击“Ascend>MindX SDK Manager”进入MindX SDK管理界面。界面中“MindX SDK Location”为软件包的默认安装路径,默认安装路径为“C:\Users*用户名*\Ascend\mindx_sdk”。单击“Install SDK”进入“Installation settings”界面。在“Installation settings”界面“Remote Connection”:远程连接的用户及IP。“Remote CANN Location”:远端环境上CANN开发套件包的路径,请配置到版本号一级。“Remote SDK Location”:远端环境上SDK的路径,请配置到版本号一级。IDE将同步该层级下的“include”、“opensource”、“python”、“samples”文件夹到本地Windows环境,层级选择错误将导致安装失败。“Local SDK Location”:同步远端环境上SDK文件夹到本地的路径。默认安装路径为“C:\Users*用户名*\Ascend\mindx_sdk”。安装完成之后,界面如图所示:4. 开发过程4.1 创建工程工具栏点击“File > New > Project选择左侧Ascend APP,创建Ascend APP应用工程,,创建MindX SDK空白工程(提供MindX SDK开发框架,不包含代码逻辑),点击finish完成创建。创建完成之后目录结构如下图所示删除config文件夹,创建models和pipeline里的文件,以备后续开发自己的业务流程,目录结构如图所示。4.2 配置python解释器依次点击File->Project Structure,选择SDKs,添加Python SDK如下图所示:选择SSH interpreter,配置远程服务器,MindStudio会自动侦测远程python环境(如果PATH环境变量已正确配置python的路径),点击OKProject中选择配置好的远程SDK,点击Apply点击OK。完成python解释器的配置。4.3 开发步骤4.3.1 确定业务流程根据铝材表面缺陷检测SDK推理的具体需求,这里将流程依次划分为图片获取、图片解码、图像缩放、目标检测、序列化、结果发送。4.3.2 寻找合适的插件首先根据已有SDK插件的功能描述和规格限制来匹配业务功能(SDK插件列表详见已有插件介绍)。当SDK提供的插件无法满足功能需求时,用户可以参考插件开发介绍开发自定义插件,该部分为SDK高阶特性。在本案例中,已有SDK插件已经满足业务需求。铝材表面缺陷检测流程图以及pipeline编排流程图如下所示:1 铝材表面缺陷检测流程图2 铝材表面缺陷检测pipeline示意图4.3.3 准备模型推理文件和数据步骤1 训练铝材缺陷检测对应的yolov5模型,输出pt模型文件。pt模型文件链接:cid:link_2步骤2 将pt模型文件转换成onnx,也可直接通过以下链接下载onnx模型。onnx模型文件链接:cid:link_1下载yolov5官方源码6.1版本Releases · ultralytics/yolov5 (github.com),进入项目根目录,将best.pt模型文件复制到项目目录,执行命令python export.py --weights best.pt –simplify模型转换成功之后,显示的日志信息如下图所示,在项目根目录会生成best.onnx模型文件步骤3 将转化后的YOLOv5模型onnx文件存放至./models/yolov5/。步骤4 AIPP配置由于yolov5模型的输入为rgb格式,pipeline中的图像解码为yuv格式,且数据类型不同,需要在atc转换模型时使用aipp预处理,该案例所需进行的aipp预处理包括色域转化以及归一化操作,aipp配置步骤如下:在./models/yolov5文件夹创建insert_op.cfg配置文件,所需添加的配置内容的属性:参数参数说明aipp_mode每次模型推理过程采用固定的AIPP预处理参数进行处理Related_input_rankrelated_input_rank参数为可选,标识对模型的第几个输入做AIPP处理,从0开始,默认为0。例如模型有两个输入,需要对第2个输入做AIPP,则配置related_input_rank为1。# 类型: 整型Input_format输入图像格式,必选。取值范围:YUV420SP_U8、XRGB8888_U8、RGB888_U8、YUV400_U8src_image_size_wsrc_image_size_h原始图像的宽度、高度宽度取值范围为[2,4096]或0;高度取值范围为[1,4096]或0,对于YUV420SP_U8类型的图像,要求原始图像的宽和高取值是偶数cropAIPP处理图片时是否支持抠图类型:bool取值范围:true/false,true表示支持,false表示不支持Csc_switch色域转换开关,静态AIPP配置类型:bool取值范围:true/false,true表示开启色域转换,false表示关闭rbuv_swap_switch R通道与B通道交换开关/U通道与V通道交换开关类型:bool取值范围:true/false,true表示开启通道交换,false表示关闭matrix_rxcyX和y代表矩阵的行和列一旦确认了AIPP处理前与AIPP处理后的图片格式,即可确定色域转换相关的参数值(matrix_r*c*配置项的值是固定的,不需要调整)var_reci_chn归一化配置参数把需要处理的数据经过处理后限制在一定范围内,方便后面数据的处理。pixel_out_chx(i)=[pixel_in_chx(i)-mean_chn_i-min_chn_i]*var_reci_chn最终配置参数如下图所示:配置文件的教程请参考如下链接:配置文件模板 - CANN 5.0.4 ATC工具使用指南 01 - 华为 (huawei.com)5 模型转换模型转换有两种方式,一种是通过MindStudio可视化操作,另一种是通过命令行的方式,使用MindStudio进行模型转换参考该链接。使用命令方式进行模型转换步骤如下:首先开启一个SSH会话切换到项目根目录,运行如下命令:atc --input_shape="images:1,3,640,640" --out_nodes="Transpose_286:0;Transpose_336:0;Transpose_386:0" --output_type=FP32 --input_format=NCHW --output="./models/yolov5/yolov5_add_bs1_fp16" --soc_version=Ascend310 --framework=5 --model="./models/yolov5/best.onnx" --insert_op_conf=./models/yolov5/insert_op.cfg模型转换成功,模型保存在--output定义的路径下,输出结果如图所示:Atc中各个参数代表的含义请参考这个链接:参数说明 - CANN 5.0.4 ATC工具使用指南 01 - 华为 (huawei.com)。常见的报错请参考这个链接:FAQ - CANN 5.0.4 ATC工具使用指南 01 - 华为 (huawei.com)4.3.4 编写后处理配置文件在./models/yolov5创建模型后处理配置文件yolov5addbs1_fp16.cfg,对后处理参数进行配置:表1 配置文件中各个参数的意义参数名称参数介绍修改方法默认值CLASS_NUM铝材缺陷检测的类别数目。在models/yolov5/yolov5_add_bs1_fp16.cfg文件中修改CLASS_NUM的大小即可10BIASES_NUM铝材缺陷检测锚点框数量在models/yolov5/yolov5_add_bs1_fp16.cfg文件中修改BIASES_NUM的大小即可18BIASES铝材缺陷检测锚点框,用kmeans计算最合适的锚点框在models/yolov5/yolov5_add_bs1_fp16.cfg文件中修改BIASES即可17,14,161,31,113,69,649,17,637,32,636,73,625,132,640,202,626,365YOLO_TYPEYOLO输出特征向量的维度数,YOLOv5使用的是3在models/yolov5/yolov5_add_bs1_fp16.cfg文件中修改YOLO_TYPE即可3SCORE_THRESH是否为框的阈值,大于此值才认定为框在models/yolov5/yolov5_add_bs1_fp16.cfg文件中修改SCORE_THRESH的大小即可0.25IOU_THRESH两个框的IOU阈值,超过此值则被认定为同一个框,用于nms算法在models/yolov5/yolov5_add_bs1_fp16.cfg文件中修改IOU_THRESH的大小即可0.5OBJECTNESS_THRESH识别目标置信度的阈值,大于阈值才会认定为目标在models/yolov5/yolov5_add_bs1_fp16.cfg文件中修改OBJECTNESS_THRESH的大小即可0.0YOLO_VERSIONYOLO版本号,本项目使用的YOLOv5,故取值为5在models/yolov5/yolov5_add_bs1_fp16.cfg文件中修改YOLO_VERSION的大小即可54.3.5 配置names文件在./models/yolov5文件夹下创建aldefectdetection.names文件,按顺序配置相应类名,该文件为数据集中所有类别,后处理插件通过读取改文件,返回准确的类别名称,达到缺陷识别的目的:4.3.6 可视化流程编排根据已经确定的业务流程和合适的插件,利用MindStudio进行可视化插件编排,需要用到的为以下六个插件。1. appsrc # 输入2. mxpi_imagedecoder # 图像解码3. mxpi_imageresize # 图像缩放4. mxpi_tensorinfer # 模型推理(铝材缺陷检测)5. mxpi_objectpostprocessor # 模型后处理(yolov5)6. appsink # 输出用MindStudio进行可视化流程编排,工具栏依次点击“Ascend > MindX SDK Pipeline :搜索流程编排中需要用到的插件:将插件依次拖动到如下界面并连接起来,Format选项可以整理插件连接的排列,让界面更加美观。点击需要配置参数的插件,在如下区域设置合适的参数:点击save,生成相应的pipeline代码,该代码会将可视化pipeline中设置的参数也加载到对应的插件中去:{"classification+detection": {"stream_config": {"deviceId": "0"},"appsrc0": {"props": {"blocksize": "409600"},"factory": "appsrc","next": "mxpi_imagedecoder0"},"mxpi_imagedecoder0": {"factory": "mxpi_imagedecoder","next": "mxpi_imageresize0"},"mxpi_imageresize0": {"props": {"dataSource": "mxpi_imagedecoder0","resizeType": "Resizer_KeepAspectRatio_Fit","resizeWidth":"640","resizeHeight":"640","paddingType":"Padding_NO","interpolation":"2"},"factory": "mxpi_imageresize","next": "mxpi_tensorinfer0"},"mxpi_tensorinfer0": {"props": {"dataSource": "mxpi_imageresize0","modelPath": "./models/yolov5/yolov5_add_bs1_fp16.om"},"factory": "mxpi_tensorinfer","next": "mxpi_objectpostprocessor0"},"mxpi_objectpostprocessor0": {"props": {"dataSource": "mxpi_tensorinfer0","postProcessConfigPath": "./models/yolov5/yolov5_add_bs1_fp16.cfg","labelPath": "./models/yolov5/aldefectdetection.names","postProcessLibPath": "${HOME}/MindX_SDK/mxVision-2.0.4/lib/modelpostprocessors/libyolov3postprocess.so"},"factory": "mxpi_objectpostprocessor","next": "mxpi_dataserialize0"},"mxpi_dataserialize0": {"props": {"outputDataKeys": "mxpi_objectpostprocessor0"},"factory": "mxpi_dataserialize","next": "appsink0"},"appsink0": {"props": {"blocksize": "4096000"},"factory": "appsink"}}}可视化流程编排极大地提升了开发效率,通过这种方式用户可以很快的完成pipeline的编排。4.3.7 编写main.py文件main文件的编写逻辑如下图所示:按照上述流程图,完成代码开发,其中,通过SendDataWithUniqueId将数据送入流里,GetResultWithUniqueId从流里获取数据,最终用opencv将位置信息和类别信息标记在图片上并保存。主函数main.py:初始化流管理器,如果初始化失败,则提示用户并退出程序:2.通过streamManagerApi创建流,导入pipeline文件,如果失败,则提示用户并退出程序3. 构建输入数据,并对输入数据进行检查,确保输入的图片存在且不为空,否则提示用户并退出程序。4. 对输入数据进行预处理,对齐YOLOv5数据预处理操作。5. 将输入数据传入到指定流中,并通过uniqueId获取指定流的输出结果:6. 读取流中的结果,并将位置信息和类别信息输出到图片上,保存图片7. 销毁流4.4 项目下载连接以及项目结构完整项目请在此处下载:cid:link_14项目目录结构如下所示:├── models│ ├── yolov5│ │ ├── aldefectdetection.names # 铝材缺陷检测类别│ │ ├── insert_op.cfg # yolov5 aipp转换配置│ │ ├── yolov5_add_bs1_fp16.cfg # yolov5后处理配置│ │ ├── yolov5_add_bs1_fp16.om # 铝材缺陷检测模型│ │ ├── best.onnx # 用于模型转换├── pipeline│ └── AlDefectDetection.pipeline # pipeline文件├── main.py├── eval.py├── eval_pre.py # letterbox预处理├── plots.py # 绘图工具类├── utils.py # 工具类└── test.jpg5. 运行5.1 配置远程映射在工具栏"Tools > Deployment> Configuration"在Connection选项中配置远程连接。在Mappings选项中配置远程映射,同步远端和本地代码。配置远端路径之后点击OK完成映射。在工具栏点击"Tools > Deployment> Upload to"上传本地代码到远端服务器在精度测试下载的数据集中任意选择一张图片放在项目的根目录下,并命名为test.jpg在main.py文件点击右键,Modify Run Configuration,配置python解释器,选择远端python解释器,配置完成之后点击apply,点击OK。配置完成之后即可右键运行main.py文件得到结果,在程序中,通过输出流里取得的数据,我们可以看到图片的位置和类别信息。通过这些位置信息,我们进一步作出结果图:5.2 精度测试准备测试数据https://mindx.sdk.obs.cn-north-4.myhuaweicloud.com/ascend_community_projects/Aluminum_surface_defect_detection/testDatas.zip和om模型文件:https://mindx.sdk.obs.cn-north-4.myhuaweicloud.com/ascend_community_projects/Aluminum_surface_defect_detection/yolov5_add_bs1_fp16.om运行项目根目录下的eval.py,该文件是在main.py的基础上循环输入测试数据集图片得到结果。生成的位置信息和类别信息会以txt文件的形式保存在项目目录下的test/testouttxt/。在map.py界面右键,修改运行配置,添加路径参数配置命令行参数:其中--gt为测试集数据的标签路径,--testpath为模型输出结果的路径(即上述test/testpre_post/),包括分类结果、位置信息和置信度参数。结果如下图所示:mAP0.5为0.8135478,mAP0.5:0.95为0.5587293358。其中mAP是目标检测模型中常用的评价指标,它的英文全称是(Mean Average Precision),翻译过来就是平均精确率的平均。mAP0.5是指计算标准为IOU阈值大于0.5,也就是预测框和标签IOU>0.5为正样本。mAP0.5:0.95是指取IOU阈值为以0.05为步长,0.5为起始数据,一直到IOU阈值为0.95的十组数据的平均精度。6. FAQ1 尺寸不匹配问题描述:提示mxpi_tensorinfer0The input of the model does not match] The datasize of concated inputTensors0 does not match model inputTensors0. Tensor Dtype: TENSORDTYPEUINT8, model Dtype: TENSORDTYPEUINT8.解决方案:模型经过插件处理后的图像与模型输入不匹配,检查模型经过pipeline之后的尺寸大小是否和模型输入匹配。2 模型路径未进行正确配置问题描述:提示 Failed to get model, the model path is invalidate.解决方案:检查模型存放路径,正确配置模型路径。3 未修改pipeline中后处理插件的postProcessLibPath属性问题描述:提示[Object, file or other resource doesn't exist] The postprocessing DLL does not exist解决方案:修改pipeline文件中mxpi_objectpostprocessor0插件的postProcessLibPath属性,修改为{SDK安装路径}/lib/modelpostprocessors/libyolov3postprocess.so4 同步远端CANN开发包失败问题描述:提示[PermissionError: [Errno 13] Permission denied: '/usr/local/Ascend/ascend-toolkit/5.0.4/pyACL/scene.info' Command execute fail, exitStatus = 1]解决方案:将CANN开发包安装到用户目录下。7. 一些个人经验总结在编写pipeline的时候,MindStudio提供的可视化流程编排极大地提高了开发效率,在MindStudio可以通过拖动的方式完成pipeline的编写,参数也可以很方便的在可视化流程编排中配置;在开发中我们难免会遇到各种各样奇奇怪怪的问题,昇腾论坛是个不错的选择,有问必答,从大四开始已经陆陆续续问了挺多问题,答复速度比较快,开发中受阻,不妨在论坛里请求大佬寻求帮助,链接:华为云论坛云计算论坛开发者论坛_技术论坛-华为云 (huaweicloud.com)。在做模型转换前,最好用netron确定一下输出节点,找到正确输出节点,才能让om模型正确输出,netron下载链接:lutzroeder/netron: Visualizer for neural network, deep learning, and machine learning models (github.com)8. Mindstuido下载连接链接:(MindStudio下载-昇腾社区 (hiascend.com)9. 开发过程中用到的链接MindX SDK 2.0.4 mxVision 用户指南:MindX SDK 2.0.4 mxVision 用户指南 01 - 华为 (huawei.com)CANN安装指南(在用MindStudio可能会由于权限问题,导致远端CANN开发包同步不到本地,可以安装该包到用户目录下) :在昇腾设备上安装 - CANN 5.0.4 软件安装指南 01 - 华为 (huawei.com)基于MindStudio的MindX SDK应用开发全流程:基于MindStudio的MindX SDK应用开发全流程哔哩哔哩bilibili
  • [技术干货] 深度学习——VGG16模型详解-转载
     1、网络结构  VGG16模型很好的适用于分类和定位任务,其名称来自牛津大学几何组(Visual Geometry Group)的缩写。  根据卷积核的大小核卷积层数,VGG共有6种配置,分别为A、A-LRN、B、C、D、E,其中D和E两种是最为常用的VGG16和VGG19。  介绍结构图:  conv3-64 :是指第三层卷积后维度变成64,同样地,conv3-128指的是第三层卷积后维度变成128; input(224x224 RGB image) :指的是输入图片大小为224244的彩色图像,通道为3,即224224*3; maxpool :是指最大池化,在vgg16中,pooling采用的是2*2的最大池化方法(如果不懂最大池化,下面有解释); FC-4096 :指的是全连接层中有4096个节点,同样地,FC-1000为该层全连接层有1000个节点; padding:指的是对矩阵在外边填充n圈,padding=1即填充1圈,5X5大小的矩阵,填充一圈后变成7X7大小; 最后补充,vgg16每层卷积的滑动步长stride=1,padding=1,卷积核大小为333;    如上图VGG16的网络结构为,VGG由5层卷积层、3层全连接层、softmax输出层构成,层与层之间使用max-pooling(最大化池)分开,所有隐层的激活单元都采用ReLU函数。具体信息如下:  卷积-卷积-池化-卷积-卷积-池化-卷积-卷积-卷积-池化-卷积-卷积-卷积-池化-卷积-卷积-卷积-池化-全连接-全连接-全连接  通道数分别为64,128,512,512,512,4096,4096,1000。卷积层通道数翻倍,直到512时不再增加。通道数的增加,使更多的信息被提取出来。全连接的4096是经验值,当然也可以是别的数,但是不要小于最后的类别。1000表示要分类的类别数。 用池化层作为分界,VGG16共有6个块结构,每个块结构中的通道数相同。因为卷积层和全连接层都有权重系数,也被称为权重层,其中卷积层13层,全连接3层,池化层不涉及权重。所以共有13+3=16层。 对于VGG16卷积神经网络而言,其13层卷积层和5层池化层负责进行特征的提取,最后的3层全连接层负责完成分类任务。 2、VGG16的卷积核  VGG使用多个较小卷积核(3x3)的卷积层代替一个卷积核较大的卷积层,一方面可以减少参数,另一方面相当于进行了更多的非线性映射,可以增加网络的拟合/表达能力。 卷积层全部都是3*3的卷积核,用上图中conv3-xxx表示,xxx表示通道数。其步长为1,用padding=same填充。 池化层的池化核为2*2 3、卷积计算   具体的过程:  输入图像尺寸为224x224x3,经64个通道为3的3x3的卷积核,步长为1,padding=same填充,卷积两次,再经ReLU激活,输出的尺寸大小为224x224x64 经max pooling(最大化池化),滤波器为2x2,步长为2,图像尺寸减半,池化后的尺寸变为112x112x64 经128个3x3的卷积核,两次卷积,ReLU激活,尺寸变为112x112x128 max pooling池化,尺寸变为56x56x128 经256个3x3的卷积核,三次卷积,ReLU激活,尺寸变为56x56x256 max pooling池化,尺寸变为28x28x256 经512个3x3的卷积核,三次卷积,ReLU激活,尺寸变为28x28x512 max pooling池化,尺寸变为14x14x512 经512个3x3的卷积核,三次卷积,ReLU,尺寸变为14x14x512 max pooling池化,尺寸变为7x7x512 然后Flatten(),将数据拉平成向量,变成一维51277=25088。 再经过两层1x1x4096,一层1x1x1000的全连接层(共三层),经ReLU激活 最后通过softmax输出1000个预测结果 从上面的过程可以看出VGG网络结构还是挺简洁的,都是由小卷积核、小池化核、ReLU组合而成。其简化图如下(以VGG16为例):    4、权重参数(不考虑偏置)  1)输入层有0个参数,所需存储容量为224x224x3=150k 2)对于第一层卷积,由于输入图的通道数是3,网络必须要有通道数为3的的卷积核,这样的卷积核有64个,因此总共有(3x3x3)x64 = 1728个参数。 所需存储容量为224x224x64=3.2M 计算量为:输入图像224×224×3,输出224×224×64,卷积核大小3×3。  所以Times=224×224×3x3×3×64=8.7×107  3)池化层有0个参数,所需存储容量为 图像尺寸x图像尺寸x通道数=xxx k 4)全连接层的权重参数数目的计算方法为:前一层节点数×本层的节点数。因此,全连接层的参数分别为: 7x7x512x4096 = 1027,645,444 4096x4096 = 16,781,321 4096x1000 = 4096000 按上述步骤计算的VGG16整个网络总共所占的存储容量为24M*4bytes=96MB/image 。  所有参数为138M VGG16具有如此之大的参数数目,可以预期它具有很高的拟合能力;  但同时缺点也很明显: 即训练时间过长,调参难度大。 需要的存储容量大,不利于部署。 5、VGG模型所需要的内存容量  借鉴一下大佬的图:    6、总结  通过增加深度能有效地提升性能; VGG16是最佳的模型,从头到尾只有3x3卷积与2x2池化,简洁优美; 卷积可代替全连接,可适应各种尺寸的图片。 ———————————————— 版权声明:本文为CSDN博主「橙子吖21」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/qq_42012782/article/details/123222042 
  • [经验分享] 使用MindStudio利用TSM模型完成视频分类任务
    3733图4-↵目录1. 写在前面... 22. MindStudio环境搭建... 22.1本地Windows服务器环境搭建... 32.1.1 MindStudio的下载... 42.1.2 MindStudio的安装... 52.2集成MindStudio开发环境搭建... 72.2.1新建项目... 72.2.2 配置远程服务器... 112.2.3 配置项目SDK.. 142.2.4 配置MindX SDK.. 183. 模型介绍... 213.1介绍... 213.2代码目录结构与说明... 213.3环境依赖... 214. 离线推理... 224.1数据集下载... 224.2数据集预处理... 264.3模型转换... 284.4 Pipeline流程编排... 334.4.1 创建Pipeline文件... 334.4.2 设置插件... 344.4.3 配置插件参数... 354.4.4 Pipeline文件保存... 394.5离线推理和精度检测... 404.6 SDK性能测试... 425. 在线推理... 435.1安装视频流工具... 435.2生成视频流... 455.3模型转换... 475.4Pipeline流程编排5.5 程序测试... 506. FAQ.. 511. 写在前面本文进行的项目以昇腾Atlas310卡为主要的硬件平台,使用TSM模型,基于Kinetics-400数据集,在MindX SDK环境下实现视频分类功能。将测试视频传入脚本进行前处理,模型推理,后处理等功能,最终得到模型推理的精度和性能。项目主要由离线精度测试文件,在线功能测试文件,离线单视频推理性能测试文件,模型文件,测试数据集预处理文件组成。如在实践过程中遇到任何的问题,可以前往华为MindStudio论坛华为云论坛_云计算论坛_开发者论坛_技术论坛-华为云 (huaweicloud.com)寻求帮助,本文在实践过程中遇到的诸多问题均从论坛上获得答案最终解决。本项目视频案例链接如下:使用MindStudio利用TSM模型完成视频分类任务_哔哩哔哩_bilibili2. MindStudio环境搭建本项目所处的场景为纯开发场景(分部署形态),详情请参见安装方案(Windows)-安装方案-安装指南-5.0.RC3-MindStudio-文档首页-昇腾社区 (hiascend.com),该场景下在Windows服务器上安装MindStudio,在纯开发环境需要安装Ascend-cann-toolkit,两者建立连接之后,形成了集成的MindStudio的纯开发环境。昇腾AI设备上运行环境的安装部署操作请参见《CANN 软件安装指南》,此场景运行环境多为端侧、边侧设备如Atlas 500智能小站和Atlas 200 DK开发者套件等。图2-1 纯开发环境(分部署形态)CANN(Compute Architecture for Neural Networks)是华为公司针对AI场景推出的异构计算架构,通过提供多层次的编程接口,支持用户快速构建基于昇腾平台的AI应用和业务。用户根据实际使用需要,下载对应的CANN软件包,具体安装流程可以参考官网的用户手册。CANN软件包下载地址CANN 商用版下载-昇腾社区 (hiascend.com)CANN安装流程:安装须知-软件安装-环境准备-5.1.RC1-CANN商用版-文档首页-昇腾社区 (hiascend.com)2.1 本地Windows服务器环境搭建MindStudio提供了AI开发所需的一站式开发环境,提供图形化开发界面,支持模型开发、算子开发以及应用开发三个主流程中的开发任务。同时还支持网络移植、优化和分析等功能。依靠模型可视化、算力测试、IDE本地仿真调试等功能,MindStudio能够帮助用户在一个工具上就能高效便捷地完成AI应用开发。同时,MindStudio采用了插件化扩展机制,开发者可以通过开发插件来扩展已有功能。MindStudio支持Windows和Linux两大主流平台。可以根据需要,进行选择下载安装包,具体安装流程,可以参考官网:官网链接:MindStudio-昇腾社区 (hiascend.com)用户手册:成长地图-5.0.RC3-MindStudio-文档首页-昇腾社区 (hiascend.com)2.1.1 MindStudio的下载进入MindStudio官网,下拉界面,点击“立即下载”,如图2-2所示。图2-2 MindStudio下载界面进入版本选择界面,最新的版本是MindStudio_5.0.RC3,在本项目中没有选择该版本的MindStudio,下拉界面进入历史版本,在本项目中选择使用MindStudio_5.0.RC2,根据主机系统选择对应的软件包,点击软件包下载,同时需要留意其对应的CANN版本为5.1.RC2,如图2-3所示。图2-3 版本选择界面点击软件包下载之后需要在弹出界面勾选“我已阅读并已同意 MindStudio软件许可协议 的条款和条件”,如图2-4所示。图2-4 软件许可协议2.1.2 MindStudio的安装运行下载好的MindStudio安装程序,单击“Next”,进入下一步,如图2-5。图2-5 MindStudio安装界面进入下一步后,根据自身需求选取软件安装路径,在此选择默认安装路径,如图2-6.图2-6 安装路径选取进入下一界面,选择 “Create Desktop Shortcut”(创建桌面图标)、“Update Context Menu”(以工程方式打开文件夹)、“Update PATH Variable(restart needed)”(配置环境变量),之后点击“Next”如图2-7所示图2-7 设置选项默认点击install即可,如图2-8所示图2-8 安装选项安装完成,如图2-9所示。图2-9安装完成2.2 集成MindStudio开发环境搭建2.2.1 新建项目完成以上工作之后,打开MindStudio,出现以下界面,如图2-10所示。Customize为定制界面,用户可以在该界面下进行一些个性化设置,包括主题的选择等;Plugins界面为插件界面,用户可以在该界面下载插件并且查看已经下载的插件;Learn MindStudio界面可以学习MindStudio的详细用法;在此选择Projects界面,点击“New Project”选项新建项目。 图2-10 MindStudio初始界面进入新建项目界面,选择Ascend APP,“Name”部分为项目名称,“Description”为项目的相关描述,“Project Location”是项目的本地路径,输入项目名称和相关描述之后,最后点击“Change”来配置远端服务器,如图2-11所示。图2-11 新建项目选项进入页面之后,点击最右侧“+”号,在进入的界面中输入端口、用户名、密码,之后点击“Test Connection”,显示“Successfully connected”表示成功,最后点击确定退出界面即可,如图2-12所示。图2-12 配置远端服务器界面完成远端服务器配置之后,点击右侧文件夹图标,选择Ascend-cann-toolkit软件包的安装目录,之后选择到版本目录5.1.RC2,点击OK,如图2-13所示。图2-13 选择Ascend-cann-toolkit组件目录点击Finish,开始同步CANN,如图2-14所示。图2-14 同步CANN我在同步CANN的时候遇到了同步失败的问题,通过在华为论坛上进行提问CANN同步失败如何处理。_MindStudio_昇腾_华为云论坛 (huaweicloud.com),最后确定了是MindStudio版本与CANN版本不匹配的原因,因此重新安装正确版本的MindStudio,成功地同步了CANN.同步结束之后会自动退出以上界面,点击next进入项目类型选择界面,由于本项目为SDK开发项目,所以选择“MindX SDK Project(python)”,之后点击Finish按钮,完成项目的创建,如图2-15所示。图2-15 项目类型选择2.2.2 配置远程服务器此时成功地创建了一个空项目,点击“Tools”->“Start SSH session”,打开远端服务器终端,用户可以通过在此终端中输入指令,完成想要进行的操作。如图2-16所示。图2-16 启动远端服务器终端之后点击要打开的服务器,打开服务器终端窗口。如图2-17所示。图2-17 服务器选择成功打开远端服务器终端窗口,可以通过该窗口输入指令,如图2-18所示。图2-18 打开远程服务器终端之后点击“Tools”->“Deployment”->“Configuration”,如图2-19所示。图2-19 打开Configuration界面打开Configuration界面,选择相应的服务器,进入“Mappings”界面,“Local path”为本地项目的路径,“Deployment path”为项目的远端路径,选择远端服务器的项目路径,所谓远端路径,就是本地项目上传到服务器的对应路径,选择完毕后点击OK完成远端路径配置即可,如图2-20所示。图2-20 配置远端服务器项目映射路径2.2.3 配置项目SDK按照图2-21,打开“Project Structure…..”,也可通过快捷键Ctrl+Alt+Shift +S打开对应界面,配置项目SDK。图2-21 配置SDK进入界面后点击“SDKs”,之后点击“+”->“Add python SDK…”,增加SDK,如图2-22所示。图2-22 增加SDK随后点击“SSH Interpreter”,选择相应的服务器,之后会自动检测远端服务器的环境,其中interpreter为远端python解释器的路径,Name由用户自行设置,用于区分多种远端解释器,检测完毕之后点击OK退出当前界面,如图2-23所示。图2-23 检测远端环境之后点击Project,选择新增的SDK,之后点击Apply完成SDK设置,如图2-24所示。图2-24 项目解释器设置之后点击“Modules”->“Dependencies”,选择新增的SDK,点击ok完成设置,如图2-25所示。图2-25 模型依赖设置点击“Tools”->“Deployment”->“Automatic Upload”,如图2-26所示。图2-26 设置自动上传选择要上传的服务器,此处的服务器选择与mapper处选择的服务器必须保持一致,如图2-27所示。设置完毕自动上传后,在MindStudio中修改某一文件之后,使用Ctrl+s快捷键即可自动将修改的文件在服务器上进行更新。图2-27 自动上传服务器选择2.2.4 配置MindX SDK 点击“Ascend”>MindX SDK Manager,进入MindX SDK配置界面,如图2-28所示。图2-28 MindX SDK配置界面入口点击install SDK,进入SDK路径选择界面,如图2-29所示。图2-29 SDK配置界面进入SDK路径选择界面,“Remote Connection”为远端服务器选择,“Remote CANN location”为远端CANN路径,该路径与第2.2节所述路径一致。“Remote SDK location”为远端SDK路径。“Local SDK location”为本地SDK将会安装的路径。全部选择完毕后,点击“OK”进入下一步。如图2-30所示。图2-30 SDK路径选择从远端获取SDK,如图2-31所示。图2-31 从远端获取SDKSDK配置完成,集成开发环境搭建完成,如图2-32所示。图2-32 SDK配置成功3. 模型介绍3.1 介绍使用TSM模型,基于Kinetics-400数据集,在MindX SDK环境下实现视频分类功能。将测试视频传入脚本进行前处理,模型推理,后处理等功能,最终得到模型推理的精度和性能。3.2 代码目录结构与说明├── TSM ├── README.md // 所有模型相关说明 ├── model ├── pth2onnx.py // 转onnx模型脚本 ├── onnx2om.sh // 转om模型脚本 ├── pth2onnx1.py // 在线模型转onnx模型脚本 ├── onnx2om1.sh // 在线模型转om模型脚本 ├── label ├── kinetics_val.csv // label文件 ├── download_data ├── k400_extractor.sh // 解压数据集脚本 ├── online_infer.py // 在线推理精度脚本 ├── offline_infer.py // 离线推理精度脚本 ├── speed.py // 离线单视频推理NPU性能脚本 ├── speed_gpu.py // 离线单视频推理GPU性能脚本3.3 环境依赖推荐系统为ubuntu 18.04,环境依赖软件和版本如下表:软件名称版本cmake3.5+mxVision5.1RC2Python3.9torch1.10.0ffmpeg3.4.8此处以ffmpeg的安装为例,执行以下命令安装wget https://johnvansickle.com/ffmpeg/builds/ffmpeg-git-amd64-static.tar.xzxz -d ffmpeg-git-amd64-static.tar.xztar -xvf ffmpeg-git-amd64-static.tarcd ./ffmpeg-git-20190424-amd64-static./ffmpeg4. 离线推理4.1 数据集下载参考PaddleVideo/k400.md at develop · PaddlePaddle/PaddleVideo (github.com)中的Kinetics-400数据集下载方式,在“TSM/download_data/”目录下准备“download.sh”脚本、"val_link.list"验证集链接列表文件以及“k400_extractor.sh”数据集解压脚本。之后将其上传到远端服务器,如图4-1所示。图4-1 将本地脚本同步到服务器通过MindStudio运行脚本,根据图4-2,进入“Edit Configurations”界面。图4-2 运行设置入口进入界面后,选择“Ascend App”,“Name”为用于自行设置,用于区分不同的运行程序,“Deployment”为要运行的服务器;“Executable”为要运行的脚本或代码;“Command Arguments”为指令参数,参数val_link.list为需要下载的数据集压缩包链接,如图4-3所示。即运行该脚本或代码传入的参数; “Environment Variables”为环境变量的设置,完成以上所有设置后点击“Apply”即可。如图4-4所示。图4-3 val_link.list内容图4-4 运行设置设置完毕后,点击运行按钮即可,如图4-5所示。图4-5 运行下载数据集脚本下载脚本运行完毕后,数据集压缩包下载完成,共有三个文件“var_part1.tar”、“var_part2.tar”和“var_part3.tar”,运行结果如图4-6所示。图4-6 数据集下载完成结果之后进行数据解压工作,将数据解压到TSM/data目录下,对于解压脚本采用同样的操作,解压脚本不需要传入命令参数,如图4-7所示。图4-7 解压脚本运行设置之后点击运行按钮,运行数据解压脚本,运行完毕后,运行结果如图4-8所示。图4-8 数据解压脚本运行结果数据集含有共计400个类别的视频,数据集目录结构如下:├── TSM ├── data ├── abseiling ├── air_drumming ├── ... ├── zumba4.2 数据集预处理在代码根目录下创建文件夹“tools”和“ops”;在链接mit-han-lab/temporal-shift-module: [ICCV 2019] TSM: Temporal Shift Module for Efficient Video Understanding (github.com)下载代码包,并且将代码包中"tools"目录下的"vid2img_kinetics.py"、"gen_label_kinetics.py"、"kinetics_label_map.txt"三个文件拷贝至目录TSM/tools下,tools目录结构如下:├── TSM ├── tools ├── gen_label_kinetics.py // label生成脚本 ├── vid2img_kinetics.py // 视频抽帧脚本 ├── kinetics_label_map.txt将代码包中“ops”目录下的"basic_ops.py"、"dataset.py"、"dataset_config.py"、"models.py"、"temporal_shift.py"、"transforms.py"六个文件拷贝至目录TSM/ops下,ops的目录结构如下: ├── ops ├── basic_ops.py ├── dataset.py // 数据集构建脚本 ├── dataset_config.py // 数据集配置脚本 ├── models.py // 模型搭建脚本 ├── temporal_shift.py ├── transforms.py将代码包中"online_demo"目录下mobilenet_v2_tsm.py 放在参考设计代码根目录的TSM/model 目录下。model的目录结构如下:├── TSM ├── model ├── pth2onnx.py // 转onnx模型脚本 ├── onnx2om.sh // 转om模型脚本 ├── mobilenet_v2_tsm.py // 在线模型脚本 ├── pth2onnx1.py // 在线模型转onnx模型脚本 ├── onnx2om1.sh // 在线模型转om模型脚本打开"vid2img_kinetics.py"文件,该脚本为抽帧脚本,为了充分的利用内存,在代码中每对一个视频抽帧结束后,就将原视频删除,以此来节约内存,class_process为抽帧函数,抽帧结束之后,利用shutil.rmtree删除原视频。同时将最后两行代码注释,如图4-9所示。图4-9 修改代码"vid2img_kinetics.py"之后进行抽帧,代码需要传入两个参数,第一个参数../data为视频所在的路径,其中../代表该脚本所在目录的上一级目录,即根目录TSM,所以此处的视频所在路径可等效为TSM/data,第二个参数../dataset为图片储存路径。在运行设置时需要在命令参数处输入相应的路径。如图4-10所示。图4-10 抽帧脚本运行设置抽帧脚本运行结束后,结果图4-11所示,代表抽帧完成。图4-11 抽帧运行结果抽帧结束之后,在根目录下创建labels目录,用于存放标签,运行标签生成代码gen_label_kinetics,在目录TSM/labels下生成标签,生成标签脚本运行设置如图4-12所示,不需要传入参数,标签生成结果如图4-13所示。图4-12 标签生成脚本运行设置图4-13 标签生成结果4.3 模型转换下载离线模型:TSM_kinetics_RGB_resnet50_shift8_blockres_avg_segment8_e50.pth将下载好的模型放在“${TSM代码根目录}/model”目录下。之后运行模型转换代码将pth模型转换为onnx模型,模型转换脚本为TSM/model目录下的pth2onnx.py脚本,需要传入参数kinetics RGB,kinetics代表kinetics-400数据集,RGB代表RGB图像,这是因为在离线推理的过程中,将8帧图片作为一个输入进行离线推理,因此参数需要设置为kinetics RGB,模型转换脚本运行设置如图4-14所示。图4-14 pth转onnx运行设置代码运行完成后,在model目录下形成了onnx模型,代码运行结果如图4-15所示。图4-15 onnx模型转换完成点击“Ascend”->“Model Converter”打开模型转换工具,如图4-16所示。图4-16 打开模型转换工具图4-17 转om模型界面打开模型转换界面之后,“Model File”部分为onnx模型,“Model Name”为模型名称,“Output Path”为生成模型的路径,“Target SoC Version”,“Input Format”以及“Type”等信息从onnx2om.sh脚本中获取,如图4-18所示。图4-18 onnx2om脚本onnx模型的shape从脚本pth2onnx脚本中获取,如图4-19所示。图4-19 pth2onnx脚本输入相应的信息之后点击“Next”进行检验,如图4-20所示。图4-20 模型检验模型检验完毕之后点击“Next”进入下一步,“Data Preprocessing”代表是否有数据预处理过程,在本项目中不进行数据预处理,如图4-21所示。图4-21 设置是否进行数据预处理进入界面后,“Operator Fusion”选项为是否融合运营商“Auto Tune Mode”选项为是否设置为自动调优模式;“Additional Arguments”为命令参数;“Environment Variables”为环境变量,完成以上设置之后点击finish,如图4-22所示。图4-22 模型转换相关设置运行完成后,模型转换完成,运行结果如图4-23所示。图4-23 模型转换运行结果4.4 Pipeline流程编排4.4.1 创建Pipeline文件在MindStudio上方菜单栏中找到并单击“Ascend > MindX SDK Pipeline”,创建新的pipeline文件,如图4-24所示。图4-24 创建新的pipeline文件此时成功地创建了一个Pipeline文件,如图4-25所示。图4-25 成功创建Pipeline文件4.4.2 设置插件依次找到以下插件,并从左侧插件栏拖入:appsrcmxpi_tensorinfermxpi_dataserializeappsink如图4-26所示。图4-26 拖入所需插件之后通过拖动插件块边框的连接点,将各模块按序连接,如4-27所示。图4-27 按序连接各个插件4.4.3 配置插件参数点击appsrc插件,将在右侧显示插件相关属性,设置属性“blocksize“为409600,如图4-28所示。图4-28 配置appsrc插件参数点击mxpi_tensorinfer插件,在右侧显示属性,由于数据来自appsrc0插件,设置“dataSource”为“appsrc0”,同时在“modelPath”中选择TSM.om模型,如图4-29所示。图4-29 配置mxpi_tensorinfer插件参数点击mxpi_dataserialize插件,右侧显示其属性,设置“outputDataKeys”为“mxpi_tensorinfer0”,如图4-30所示。图4-30 配置mxpi_dataserialize插件参数点击appsink插件,在右侧的属性面板中修改参数“blocksize”为4096000,如图4-31所示。图4-31 配置sppsink插件参数选中全部插件,右击鼠标,在出现的选项中选取“Set Stream Name”,如图4-32所示。图4-32 进入设置名称设置名称为TSM,如图4-33所示。图4-33 文件命名再次选中全部插件,右击鼠标,在出现的选项中选取“Set Device Id”,如图4-34所示。图4-34 进入Set Device Id界面设置Device Id为0,如图4-35所示。图4-35 设置设备Id4.4.4 Pipeline文件保存单击下方工具栏中的“save as“,命名为“TSM”,单击“Save”保存当前pipeline,如图4-36、4-37所示。图4-36 保存Pipeline文件图4-37 命名Pipeline文件保存完毕后在对应目录下即可找到生成的Pipeline文件。图4-38 保存Pipeline文件4.5 离线推理和精度检测在这部分完成的是离线推理和精度检测工作,修改${TSM代码根目录}/ops/dataset_config.py 脚本中参数ROOT_DATASET、filename_imglist_train和filename_imglist_val,若仅进行离线精度测试则可忽略filename_imglist_train设置。其中ROOT_DATASET为生成标签的目录,设置为“./labels/”,filename_imglist_val为验证集。如图4-39所示。图4-39 dataset_config.py脚本代码设置从mindxsdk-referenceapps: MindX SDK Reference Apps - Gitee.com下载脚本“offline_infer.py”, ”online_infer.py”, ”speed.py” 置于项目根目录下,在项目根目录下运行离线推理脚本offline_infer.py进行离线推理和精度检验,离线推理脚本offline_infer.py的核心部分,如图4-40所示。该脚本利用for循环对下载完毕并且抽帧完毕的13416个视频逐一地进行离线推理,在离线推理的过程中,将每8帧合起来作为一个输入投入模型进行推理,获得推理结果之后,与生成的标签值进行比对,观察二者是否一致,用推理正确的视频数除以总的视频数,以此获得模型的精度信息,每完成一个视频的推理就输出一次精度信息,如代码第130行所示,直至所有视频推理完毕之后,得到最终的精度。图4-40 offline_infer.py核心代码在运行离线推理的脚本时需要输入命令参数kinetics,代表着输入的数据集是kinetics-400数据集,运行设置如图4-41所示。图4-41 offline_infer.py运行设置运行离线推理脚本,获得精度为72.31%,符合精度偏差范围,精度达标,结果如图4-42所示。图4-42 精度检测结果4.6 SDK性能测试将用来测试的单视频放于参考设计代码根目录下,如视频“test.mp4”,打开性能测试脚本“speed.py”修改参数,’./test_speed.mp4’为测试视频,需要声明的是测试视频类别需要在kinetics-400数据集的400个种类内且视频长度至少为3s。具体代码以及修改如图4-43所示。图4-43 性能测试代码修改运行speed.py脚本进行性能测试,不需传入参数,运行设置如图4-44所示。图4-44 性能测试脚本运行设置运行性能测试脚本后,获得的单视频推理性能为0.189sec/video,性能测试结果如图4-45所示。图4-45 性能测试结果5. 在线推理5.1 安装视频流工具下载安装包:cid:link_9将压缩包放置在{根目录}/live555/目录下,打开MindStudio远程终端界面,在界面中输入以下指令,将压缩包解压:tar -zxvf live555.tar.gztar -zxvf .tar.gz解压后目录为:├── live555 ├── live├── live.tar.gz├── live555.tar.gz├── starNvr.sh解压操作如图5-1所示。图5-1 解压操作之后进行编译安装操作,在上一步操作的基础上执行命令:cd live/./genMakefiles linuxmake注意第二条指令后的参数是根据live/下的config.<后缀>得到的,与服务器的架构有关。执行完毕之后就会在mediaServer 目录下生成一个live555MediaServer可执行文件。具体操作图5-2所示。图5-2 安装操作5.2 生成视频流在安装完成之后,将“startNvr.sh”、“live555MediaServer”以及要起流的视频“jester.264”放在同一目录之下。├── hailiang2 ├── starNvr.sh├── live555MediaServer├── jester.264之后在远程终端中输入指令:ps -ef | grep live555MediaServer查看已经占用的端口号,选取没有占用的端口进行起流,如图5-3所示。5-3 查看已经占用的端口如图5-3所示,1208端口并未被占用,因此选择1208端口进行起流,在远程终端中输入指令./startNvr.sh 1208进行起流,如图5-4所示。图5-4 起流操作起流完毕之后,再次输入指令查看端口占用情况,出现:00:00:00 ./live555MediaServer 1208证明起流成功,如图5-5所示。图5-5 起流成功5.3 模型转换下载在线模型mobilenetv2_jester_online.pth.tar,将下载好的模型放在参考设计代码根目录下的“model”目录下。将模型转换为onnx模型,运行“pth2onnx1”脚本将pth转化为onnx模型,该脚本不需要传入参数,脚本运行设置如图5-6所示。图5-6 pth转换onnx模型脚本运行设置Pth转换为onnx模型转换成功。结果如图5-7所示。图5-7 模型转换结果onnx模型转换为om模型的操作步骤与第4.3节中所述一致。打开onnx模型转换界面,如图5-8所示。导入onnx模型,其中“Model File”为在线推理的onnx模型文件,“Model Name”为模型的名称,“Output Path”为转换成功后模型的输出路径,“Target SoC Version”为目标SoC版本,“Input Format”为输入格式,“Type”为种类,以上信息从onnx2om1.sh脚本中获取,如图5-9所示。而“shape”为模型的输入维度,该信息从pth2onnx1.sh脚本中获取,如图5-10所示。图5-8 模型转换相关设置图5-9 onnx2om1.sh脚本图5-10 pth2onnx1.sh脚本该模型转换过程不需设置数据预处理,直接点击“Next”即可,如图5-11所示。图5-11 数据预处理设置下一界面的相关参数已经在第4.3节做过介绍,“Operator Fusion”选项为是否融合运营商“Auto Tune Mode”选项为是否设置为自动调优模式;“Additional Arguments”为命令参数;“Environment Variables”为环境变量,本项目中不需进行设置,因此点击“finish”即可,如图5-12所示。图5-12 模型转换设置完毕模型转换完成,在指定目录生成om模型,结果如图5-13所示。图5-13 om模型生成结果5.4 Pipeline流程编排在线推理部分的Pipeline流程编排与离线推理部分保持一致,在此不做介绍,详情参见本文第4.4节内容。5.5 程序测试打开TSM/online_infer.py在线推理脚本,配置rtsp地址,其中192.168.88.110为服务器,而1208为成功起流的端口,jester.264为用于在线推理的视频,如图5-14所示。图5-14 online_infer.py代码修改在线推理脚本的核心代码如图5-15所示,在线推理与离线推理的不同之处在于:离线推理是将每8个帧合起来作为一个输入,而在线推理是将1个帧和上一个输出结果合并起来作为新的输入,将新的输入放入模型中得到输出之后再和下一帧合并得到新的输出,以此类推,能够实时地推理出视频中的手势,其核心代码的主要思路是保存输出结果,与新的一帧合并,再次输入模型,获得新的输出,循环反复,对应的代码就是116行之后的内容。图5-15 在线推理脚本核心代码运行online_infer.py脚本,其运行设置如图5-16所示。图5-16在线推理脚本运行设置运行脚本后,开始进行在线推理,用于推理的视频为一系列手势,脚本运行的结果如图5-17所示。图5-17在线推理脚本运行结果6. FAQ在使用MindStudio完成项目的过程中,遇到如下几个问题,并且给出对应的解决方案。远程CANN同步失败第一次下载的MindStudio版本为最新版本,与服务器上的CANN版本不一致,导致同步失败,更换MindStudio版本之后,便可以顺利同步。这一点在第2.1节中有提及到。2. onnx模型转换om模型无法加载模型问题在利用MindStudio进行模型转换时,由于本项目的离线推理模型内存较大,所以在加载onnx模型的过程中总是无法加载,询问过工程师老师后,得知可能是网络的问题,更换了稳定的网络之后便可以顺利加载onnx模型。3. 数据集占用内存过大如何处理由于在进行离线推理时需要下载数据集,数据集占用内存非常巨大,会出现内存不足的情况下,导致抽帧不完全,造成精度不满足。一开始我尝试抽完一个视频,就删除一个视频,以此来解决内存问题,但是之后发现是抽帧图片总内存过大,一个盘放不下,为了解决该问题,建议将数据集放在其他盘下,如果其他盘的内存也无法完全容纳,则可以将数据分成两部分,放在两个盘下,比如将part1和part2放在一个盘里,part3放在另一个盘里,在生成标签时生成两次标签,之后将两次标签合并即可。4. 服务器上无摄像头如何进行在线推理利用华为拉流工具进行起流,将mp4格式的视频转化为264格式视频,之后在指定的空闲端口起流,成功起流之后即可进行在线推理。5. 在Pipeline编辑时左侧插件栏显示空白出现这种问题的原因在于SDK的版本不匹配问题,需要重新下载匹配的SDK,在远端服务器上重新安装,即可解决问题,安装指令如下:chmod +x Ascend-mindxsdk-mxvision_3.0.RC2.1_linux-aarch64.run./Ascend-mindxsdk-mxvision_3.0.RC2.1_linux-aarch64.run –install6. MindStudio点击运行脚本后长时间无响应在开发的过程中,可以顺利打开远端服务器的终端,但是运行脚本时一直无响应,对于这个问题,我认为一般是网络问题,解决方案是重新启动MindStudio,等待右下角的所有进程全部结束后,重新运行脚本,稍等片刻即可正常运行。7. 在线推理中的问题由于需要利用拉流工具来代替摄像头的作用,在起流的时候一定要提前查看被占用端口,选择未被占用的端口,否则会导致视频混乱或者端口冲突,导致最终的在线推理的结果错误。以上为在开发过程中遇到的困难,倘若读者在实践的过程中遇到了其他的困难,可以登陆昇腾社区进行求助获取解决方案。华为云论坛_云计算论坛_开发者论坛_技术论坛-华为云 (huaweicloud.com)
  • [经验分享] 基于MindStudio的PyTorch模型开发精度调优
    本文的视频讲解可在以下链接查看:基于MindStudio的PyTorch模型开发精度调优PyTorch模型开发精度调优目录一、 精度调优所需的环境依赖 1.1 系统所需环境依赖(以Ubuntu18.04为例) 1.2 PyTorch所需依赖说明 二、 Dump数据,npy数据简要介绍 2.1 dump数据简要介绍 2.2 npy数据简要介绍 三、 dump数据类型与dump、npy数据文件命名要求 3.1 精度比对支持的dump数据类型 3.2 dump、npy数据文件命名要求 四、 训练场景下待比对数据与标准数据简述 五、 比对操作的完整流程及结果 5.1 前期准备 5.2 完成pytorch框架的安装 5.3 安装Pytorch比对的Dump数据文件环境 5.4 保存基于GPU执行模型训练生成的数据文件 5.5 保存基于昇腾AI处理器执行模型训练生成的数据文件 5.6 使用get_op_map接口获取原始网络与迁移后网络内算子的映射关系 5.7 Vector比对 六、 简要介绍CosineSimilarity,MaxAbsoluteError,AccumulatedRelativeError等算法 6.1 CosineSimilarity算法: 6.2 MaxAbsoluteError算法: 6.3 AccumulateRelativeError算法: 七、 使用精度比对工具定位,将问题模型最小化,并导出子模型 八、 精度问题分析基本思路 九、 FAQ 9.1 AttributeError: type object ‘Callable’ has no attribute ‘_abc_registry’ 9.2 ImportError: libhdf5_cpp.so.103: cannot open shared object file: No such file or directory 9.3 /root/test/env_npu.sh: No such file or directory 9.4 ImportError:libhdf5.so.103.cannot open shared objrct file:No such file or directory 9.5 其他问题 一、精度调优所需的环境依赖1.1 系统所需环境依赖(以Ubuntu18.04为例)类别版本要求PythonCANN支持Python3.7.x(3.7.0~3.7.11)、Python3.8.x(3.8.0~3.8.11)、Python3.9.x(3.9.0~3.9.7)。但本案例所用模型建议使用的pytorch版本不支持Python3.9。cmake>=3.5.1make-gcc离线推理场景:要求4.8.5版本及以上gcc。在线推理、训练、Ascend Graph开发场景:要求7.3.0版本及以上gcc,若gcc版本低于7.3.0,可参考安装7.3.0版本gcc进行安装。g++zlib1gzlib1g-devlibsqlite3-devopenssllibssl-devlibffi-devunzippciutilsnet-toolslibblas-devgfortranlibblas3liblapack-devliblapack3libopenblas-dev无版本要求,安装的版本以操作系统自带的源为准。numpy>=1.14.3decorator>=4.4.0sympy>=1.4cffi>=1.12.3protobuf>=3.11.3attrspyyamlpathlib2scipyrequestspsutilabsl-py无版本要求,安装的版本以pip源为准。1.2 PyTorch所需依赖说明PyTorch版本:1.8.1类别名称安装指令(以Ubuntu系统为例)安装过程所需工具包patchapt-get install patchgitapt-get install gitPyTorch依赖环境pyyamlpip3 install pyyamlwheelpip3 install wheel二、Dump数据,npy数据简要介绍2.1 dump数据简要介绍dump文件是一个进程或者系统在某一个给定的时间的快照,又叫内存转储文件或者叫内存快照文件,是进程的内存镜像,这种文件必须用专用工具软件打开。dump文件主要分为内核模式Dump和用户模式Dump,内核模式Dump是操作系统创建的崩溃转储,主要用来分析内核相关的问题;用户模式Dump主要在调试或Troubleshooting过程中使用,主要用来分析用户态程序的问题。用户模式Dump又分为Full Dump和Mini Dump。Full Dump包含了某个进程完整的地址空间数据,和用于调试的信息,Mini Dump根据需要可以包含不同的信息。dump可以利用调试工具进行创建,可以利用任务管理器创建,也可以利用编程自动创建。对于开发者而言,利用编程创建dump文件,可以很大程度地提高对于bug的调试效率。2.2 npy数据简要介绍npy数据格式是一个四维的数组[N,H,W, C],N代表数据集的总数,H, W,C分别代表每一张图片对应的长、宽、以及通道数。npy文件是numpy专用的二进制文件,由python程序生成,可以用来保存数据和数据集。使用训练好的模型时,npy可以作为一种保存的模型文件格式,在图片数据过多存储不方便的情况下,将数据制作成npy类型的数据格式,可以很大程度上减少读取文件所需时间。三、dump数据类型与dump、npy数据文件命名要求3.1 精度比对支持的dump数据类型精度比对支持的dump数据类型有:FLOAT、FLOAT16、DT_INT8、DT_UINT8、DT_INT16、DT_UINT16、DT_INT32、DT_INT64、DT_UINT32、DT_UINT64、DT_BOOL、DT_DOUBLE3.2 dump、npy数据文件命名要求数据类型数据命名格式备注非量化离线模型在昇腾AI处理器上运行生成的dump数据{op_type}.{op_name}.{task_id}.{stream_id}.{timestamp}命名格式说明:op_type、op_name对应的名称需满足“A-Za-z0-9_-”正则表达式规则,timestamp为16位时间戳,output_index、task_id、stream_id为0~9数字组成。量化离线模型在昇腾AI处理器上运行生成的dump数据npy数据(Caffe、TensorFlow或ONNX){op_name}.{output_index}.{timestamp}.npy四、训练场景下待比对数据与标准数据简述待比对数据(My Output)标准数据(Ground Truth)模型文件/融合规则文件通过昇腾AI处理器运行生成的训练网络dump数据TensorFlow原始训练网络npy文件计算图文件(*.txt)通过昇腾AI处理器运行生成的训练网络dump数据文件(.h5文件)基于GPU运行生成的PyTorch训练网络dump数据文件(.h5文件)-五、比对操作的完整流程及结果5.1 前期准备5.1.1 安装MindStudio进入以下连接安装MindStudio,并按照页面上的提示进行后续步骤。cid:link_75.1.2 SSH连接选择File->Settings->SSH Configurations,点击+号添加新的SSH配置,将服务器IP地址、端口、密码获密钥文件填入,点击Test Connection,提示连接成功即可。 配置好SSH后,点击Tools-->Start SSH Session,即可连接服务器端。MindStudio在界面中间会出现Select Host to Connect,选择需要的远程端口,正下方会弹出Remote Terminal,就可以输入命令操作远端服务器了。5.1.3 CANN配置进入File->Settings-> Appearance & Behavior ->System Settings->CANN页面,如下图中所示。点击上图中右上方的“change CANN”,进行相应配置。根据MindStudio的版本选择合适的CANN版本,图中选择为5.1.RC2。然后就等待软件将服务器端的CANN同步到本地即可。这里Remote CANN location中填写远程服务器中CANN所在地址。填写完成后,点击Finish即可。5.2 完成pytorch框架的安装完成pytorch1.8.1版本框架的安装这里windows安装的pytorch在之后基于GPU执行模型训练生成数据文件的步骤中会用到。在NVIDIA控制面板中查看自己cuda版本进入pytorch官网cid:link_8查看下载安装指令根据官网中的指令在Anaconda Prompt中输入相应指令安装PyTorch 1.8.1除了这种安装方法外还可以选择pip安装,安装pytorch有GPU加速的版本,安装命令后面添加豆瓣源,可以提高下载速度,也可以直接用conda安装,或者用清华源进行安装。打开MindStudio,点击New Project,进入新建工程界面。选择Ascend Training。填入项目名,并配置好环境。然后配置好Module SDK,开始模型训练。5.3 安装Pytorch比对的Dump数据文件环境5.3.1 编译安装hdf5(1)获取代码。git clone https://github.com/HDFGroup/hdf5.git (2)切换到 hdf5-1_10_9分支。cd hdf5git checkout remotes/origin/hdf5_1_10_9(3)编译hdf5。./configure --prefix=/usr/local/hdf5 --enable-cxxmake -j72 #-j 后的数值可以根据CPU的核数设置make check # run test suite.make installmake check-install # verify installation. 5.3.2 添加环境变量export PATH=/usr/local/hdf5/bin:$PATHexport LD_LIBRARY_PATH=/usr/local/hdf5/lib:$LD_LIBRARY_PATHexport LIBRARY_PATH=/usr/local/hdf5/lib:$LIBRARY_PATHexport CPATH=/usr/local/hdf5/include:$CPATH 5.3.3修改Pytorch编译选项(1)进入~/pytorch/pytorch路径下编辑build.sh文件。cd pytorchvim build.sh(2)修改编译选项。NPU版本的修改当需要获取基于NPU运行生成模型训练的数据文件时,须将build.sh文件中的“DEBUG=0 USE_DISTRIBUTED=1 USE_HCCL=1 USE_MKLDNN=0 USE_CUDA=0 USE_NPU=1 BUILD_TEST=0 USE_NNPACK=0 python3 setup.py build bdist_wheel”中添加“USE_DUMP=1”字段。修改前: DEBUG=0 USE_DISTRIBUTED=1 USE_HCCL=1 USE_MKLDNN=0 USE_CUDA=0 USE_NPU=1 BUILD_TEST=0 USE_NNPACK=0 python3 setup.py build bdist_wheel修改后: DEBUG=0 USE_DISTRIBUTED=1 USE_HCCL=1 USE_MKLDNN=0 USE_CUDA=0 USE_NPU=1 BUILD_TEST=0 USE_NNPACK=0 USE_DUMP=1 python3 setup.py build bdist_wheelGPU版本的修改与NPU版本的修改操作相同。修改前:DEBUG=0 USE_DISTRIBUTED=0 USE_HCCL=0 USE_NCCL=0 USE_MKLDNN=0 USE_CUDA=1 USE_NPU=0 BUILD_TEST=0 USE_NNPACK=0 python3 setup.py build bdist_wheel DEBUG=0 USE_DISTRIBUTED=1 USE_HCCL=1 USE_MKLDNN=0 USE_CUDA=0 USE_NPU=1 BUILD_TEST=0 USE_NNPACK=0 python3 setup.py build bdist_wheel修改后: DEBUG=0 USE_DISTRIBUTED=0 USE_HCCL=0 USE_NCCL=0 USE_MKLDNN=0 USE_CUDA=1 USE_NPU=0 BUILD_TEST=0 USE_NNPACK=0 USE_DUMP=1 python3 setup.py build bdist_wheel # DEBUG=0 USE_DISTRIBUTED=1 USE_HCCL=1 USE_MKLDNN=0 USE_CUDA=0 USE_NPU=1 BUILD_TEST=0 USE_NNPACK=0 python3 setup.py build bdist_wheel 5.3.4 编译Pytorchbash build.sh5.3.5 安装whl文件编译完成后会生成Pytorch的whl文件,卸载当前的Pytorch包,安装编译完成的whl文件。pip3 uninstall torch进入dist文件夹(~/pytorch/pytorch/dist),根据dist文件夹中的.whl文件名输入pip命令。例如:pip3 install torch-1.8.1+ascend.post6-cp37-cp37m-linux_aarch64.whl5.3.6 进入Python视图,验证whl文件安装成功python3import torch如图,若执行import torch命令不提示错误,则Python环境安装成功。5.4 保存基于GPU执行模型训练生成的数据文件(1)根据安装Pytorch比对的Dump数据文件环境完成Python环境安装,其中“修改编译选项”步骤中配置为GPU版本的修改。(2)进入训练文件中trian函数中的for循环内修改训练脚本,加入如下代码with torch.utils.dumper(enabled=True, use_dump=True, use_load=False, dump_path="/home/resnet50_dump.h5") as dump:训练脚本中的运行设备字段应对应设备GPU。(3)完成脚本修改后执行训练。训练脚本中的运行设备字段应对应设备GPU。示例如下:bash $PATH/train_full_1p.sh --data_path=/home/dataset其中$PATH为训练脚本路径。(4)完成脚本修改后执行训练。5.5 保存基于昇腾AI处理器执行模型训练生成的数据文件需要在NPU上执行如下操作。(1)根据“5.3 安装Pytorch比对的Dump数据文件环境”中的讲解完成Python环境安装,其中“修改编译选项”步骤中配置为NPU版本的修改。(2)进入Python训练模型路径下修改训练脚本(xx.py文件,如:main.py),修改方式如下:打开编辑训练脚本,在train函数的for循环下添加指令:with torch.utils.dumper(enabled=True, use_dump=False, use_load=True, dump_path="/home/Jason.h5", load_file_path="/home/resnet50_dump.h5") as dump:其中load_file_path是指定保存基于GPU执行模型训练生成的数据文件,而dump_path是本次执行训练的输出文件路径。以上指令选择将对应训练函数包含在内则表示提取对应训练步骤生成的数据,须根据实际情况包含对应的训练步骤脚本,示例如下:(3)完成脚本修改后执行训练。以train_full_1p.sh启动脚本为例执行命令如下:bash $PATH/train_full_1p.sh --data_path=/home/dataset其中$PATH为train_full_1p.sh文件的的路径。训练完成后生成基于NPU运行生成的PyTorch训练网络dump数据文件(.h5文件)(5)完成以上步骤后可将生成的两个.h5文件进行比对步骤(PyTorch)。5.6 使用get_op_map接口获取原始网络与迁移后网络内算子的映射关系PyTorch网络迁移后,可能有部分算子名称发生改变,此时进行精度比对可能无法为新算子匹配到正确的标准算子完成比对。那么需要使用get_op_map接口获取原始网络与迁移后网络内算子的映射关系,为新算子匹配到正确的标准算子。需要在安装开启dump功能的torch环境上进行操作。步骤 1 完成Python环境安装。步骤 2 进入Python解释器,导入torch,调用torch.utils.get_op_map()获取映射关系, 示例如下:import torchir_map, param_map = torch.utils.get_op_map()# 返回值, ir_map是ir_name之间的映射关系,param_map是算子参数名称的映射关系ir_map = {'CudnnBatchNormBackward': 'NativeBatchNormBackward', 'NativeBatchNormBackward': 'CudnnBatchNormBackward', 'CudnnConvolutionBackward': 'NpuConvolutionBackward', 'NpuConvolutionBackward': 'CudnnConvolutionBackward'}param_map = {'CudnnBatchNormBackward': {'epsilon': 'eps'}, 'NativeBatchNormBackward': {'eps': 'epsilon'}, 'CudnnConvolutionBackward': {'self': 'input'}, 'NpuConvolutionBackward': {'input': 'self'}}执行此操作后不会输出文件,可直接执行Vector比对。5.7 Vector比对将保存基于GPU执行模型训练生成的数据文件作为标准算子的训练数据文件,将保存基于昇腾AI处理器执行模型训练生成的数据文件作为待比对算子的训练数据文件,执行Vector比对。Vector比对命令行方式操作步骤:以HwHiAiUser用户登录操作系统,然后找到msaccucmp.py文件所在路径(例如此处msaccucmp.py文件所在路径为/usr/local/Ascend/ascend-toolkit/5.1.RC2/tools/operator_cmp/compare/msaccucmp.py),并进入该路径中。执行Vector比对命令,样例命令如下(根据自己的文件路径及文件名替换指令):python3 msaccucmp.py compare -m /home/Jason.h5 -g /home/resnet50_dump.h5 -out /home/HwHiAiUser/result 最后在自己指定的文件位置中找到Vector比对结果result_*.csv文件,如图所示。其中“*”表示生成文件的时间戳。需要注意的是在执行Vector对比操作时,首先要找到msaccucmp.py文件路径,然后进入该路径中,再执行对应的操作。六、简要介绍CosineSimilarity,MaxAbsoluteError,AccumulatedRelativeError等算法6.1 CosineSimilarity算法:进行余弦相似度算法比对出来的结果,范围是[-1,1],比对的结果如果越接近1,表示两者的值越相近,越接近-1意味着两者的值越相反。余弦相似度,又称为余弦相似性,是通过计算两个向量的夹角余弦值来评估它们的相似度。余弦相似度将向量根据坐标值,绘制到向量空间中,如最常见的二维空间。定义:两个向量间的余弦值可以通过使用欧几里得点积公式求出:即给定两个属性向量,A和B,其余弦相似性θ由点积和向量长度给出,如下所示:6.2 MaxAbsoluteError算法:进行最大绝对误差算法比对出来的结果,取值范围是 0 到无穷大,值越接近于0,表明越相近,值越大,表明差距越大。6.3 AccumulateRelativeError算法:进行累积相对误差算法比对出来的结果,取值范围是 0 到无穷大,值越接近于0,表明越相近,值越大,表明差距越大。七、使用精度比对工具定位,将问题模型最小化,并导出子模型当训练网络精度未达预期时,可通过采集训练过程中各算子的运算结果(Data Dump数据),借助精度比对工具和业界标准算子(如TensorFlow)运算结果进行数据偏差对比,从而快速解决算子精度问题。首先通过NPURunConfig中的dump_config采集Data Dump数据,在创建NPURunConfig之前,实例化一个DumpConfig类进行dump的配置(包括配置dump路径、dump哪些迭代的数据、dump算子的输入还是输出数据等)。如果训练过程中采集到了Data Dump数据,则会在指定目录下生成dump文件,同时在训练脚本当前目录生成GE图文件。最后通过精度比对工具解析Data Dump数据,从而进行算子精度分析。八、精度问题分析基本思路精度问题的直接现象一般体现在模型损失值和模型度量指标上,模型损失值现象一般表现为模型损失值跑飞,不收敛、收敛慢。为0等。模型度量指标一般表现为模型的accuracy、precision等度量指标达不到预期。针对上述精度问题的现象和原因,常用的几个调优思路有检查模型损失值曲线、检查代码和超参、检查模型结构、检查输入数据。还可以采取让训练执行到最后的方式,检查精度(主要是模型度量指标)是否达到预期。检查模型结构和超参在于检查模型的静态特征,检查输入数据是将静态特征和动态训练现象结合检查,检查精度是否达到预期就是对整体精度调优过程重新审视,并考虑一些调优手段如解释模型,优化算法等。九、FAQ9.1 AttributeError: type object ‘Callable’ has no attribute ‘_abc_registry’这是在安装Dump数据文件环境时,可能出现的报错。如下图所示。此为python在3.7版本后可能会遇到的问题,只需进入如下图中红色矩形框选出的路径,然后删除typing文件夹即可(也可能为typing.py文件)。9.2 ImportError: libhdf5_cpp.so.103: cannot open shared object file: No such file or directory这也是在安装Dump数据文件环境时,“安装whl文件”步骤可能出现的报错。解决方式为:#进入hdf5cd hdf5#然后重新添加环境变量export PATH=/usr/local/hdf5/bin:$PATHexport LD_LIBRARY_PATH=/usr/local/hdf5/lib:$LD_LIBRARY_PATHexport LIBRARY_PATH=/usr/local/hdf5/lib:$LIBRARY_PATHexport CPATH=/usr/local/hdf5/include:$CPATH 9.3 /root/test/env_npu.sh: No such file or directory在“保存基于昇腾AI处理器执行模型训练生成的数据文件”操作中,当我们完成脚本修改,准备执行训练时,可能出现如下报错:解决方式为,先进入train_full_1p.sh文件所在路径(例如本案例所用为/home/MyTraining_Trial1/test/),然后再执行命令。9.4 ImportError:libhdf5.so.103.cannot open shared objrct file:No such file or directory在Vector对比执行过程中可能会遇到报错找不到libhdf5.so.103文件的问题,此时需要手动调整文件位置,找到libhdf5.so.103文件的位置,并将其放入lib中。9.5 其他问题如果还遇到其他问题,也可以登陆MindStudio昇腾论坛寻求帮助:https://bbs.huaweicloud.com/forum/forum-945-1.html
  • 使用MindStudio进行基于MindX SDK火灾识别项目开发
    视频案例点击这里:【【经验分享】使用MindStudio进行火灾识别开发】 https://www.bilibili.com/video/BV1wP411g7hX/?spm_id_from=333.999.0.0&vd_source=b8dde865c5a3eb34f8349e674724dd411 任务介绍火灾识别项目是基于MindX SDK,实现对图像中是否为火灾场景进行识别的功能。在Atlas200 DK上对火灾场景测试集进行推理,项目整体精度达到94.15%。本案例主要介绍如何利用获取的基于PyTorch框架的densenet模型(包括数据集和模型代码),在MindStudio中进行模型的转换和MindX SDK的开发部署。参照此案例,可以实现火灾识别在昇腾设备上的部署。2 环境配置整个开发环境的搭建主要分为两部分:服务器端开发环境安装和配置、本地开发环境的安装和配置。一般来说,服务器端的环境配置工作都提前完成了(比如CANN和MindX SDK的安装),因此本文主要以Windows环境为例,介绍本地开发环境安装和配置的流程。需要注意的是,关于CANN和MindX SDK的安装,网上的教程比较多,对于第一次接触的开发者来说,容易搞混的是服务器端和本地的安装教程。服务器端都是Linux操作系统,MindX SDK可以通过图形界面方式在线或离线安装,也可以通过命令行方式进行离线安装,CANN只能通过命令行方式安装;本地端我们使用的是Windows,一般都是通过MindStudio的图形界面将服务器端的CANN和MindX SDK同步到本地。对于火灾识别项目,本地环境的搭建和配置应该按如下流程:MindStudio软件安装—>SSH远程连接—>CANN配置—>推理源码和数据准备—>昇腾工程转换—>MindX SDK配置。2.1 MindStudio软件安装2.1.1 介绍MindStudio是一套基于华为自研昇腾AI处理器开发的AI全栈开发工具平台,其功能涵盖面广,可以进行网络模型训练、移植、应用开发、推理运行及自定义算子开发等多种任务。就使用而言,整体界面风格和python开发常用的PyCharm相似。熟悉PyCharm工具的开发者使用MindStudio进行开发能够很快上手。2.1.2 安装MindStudio的安装已经在其官网上的用户手册中有了详细介绍。作者使用的操作系统为window 10,点击下载上图中的exe或zip文件进行安装。注意一下MindStudio和CANN的版本对应关系:在MindStudio下载界面的最下面的版本配套中就说明了当前MindStudio版本对应的CANN版本。在历史版本下找到并安装5.0.RC1:Python版本问题:Python版本建议为3.9与MindX SDK相适配。如果在安装时没有指定python解释器的路径,在完成安装以后,进入某个python工程项目(project)以后,系统依然会提示“No Python interpreter configured for the module”,点击Configure Python interpreter进行python解释器的配置,这里选择本地python解释器。2.2 SSH连接安装了MindStudio以后就要进行SSH连接,目的是将本地的软件与服务器进行连接。点击 File->Settings->SSH Configurations,选择+号添加新的SSH配置,取一个用户名 root。将服务器IP地址、端口、密码获密钥文件填入,点击Test Connection,提示连接成功即可。这里需要注意的是授权类型有两种,一种是密码,一种是密钥文件,本文选择使用.pem格式密钥文件。服务器地址、密码或密钥文件可通过华为云申请试用或购买获得。配置好了SSH以后,点击Tools-->Start SSH Session,即可连接服务器端。选择需要连接的服务器。连接成功,点击MindStudio在界面正下方Remote Terminal,就可以输入各种命令操作远端服务器了。2.3 CANN配置2.3.1 CANN介绍CANN(Compute Architecture for Neural Networks)是华为公司针对AI场景推出的异构计算架构,通过提供多层次的编程接口,支持用户快速构建基于昇腾平台的AI应用和业务。2.3.2 CANN安装进行CANN配置前,服务器环境应存在CANN套件包,本项目中CANN使用的是5.1.RC1版本,关于CANN套件包的说明与安装可以查看CANN社区版本文档,CANN软件包可以从CANN>CANN社区版下载中获取。选择历史版本下载5.1.RC1版本(建议下载5.1.RC1.alpha005)。本项目中使用的是华为云的ECS已安装好的CANN、MindX SDK等套件包,直接从服务器拉取即可。2.3.3 CANN配置在Windows上配置CANN,实际上是使用MindStudio把服务器端的安装包同步到本地。进入File->Settings-> Appearance & Behavior ->System Settings->CANN页面,点击右边的change CANN,在弹出的对话框中填写服务器端的CANN的地址,然后就等待软件将服务器端的CANN同步到本地。重启MindStudio 激活CANN。需要注意的是,在MindStudio中,如果没有安装CANN,是不能够将下载的源码转换为Ascend Project的。点击Ascend->Convert to Ascend Project,会提示没有安装CANN,无法转换。这一步是安装MindX SDK的前提,否则在Settings中左边的菜单栏就不会有MindX SDK选项。在完成了CANN安装以后,可以点击Ascend->Convert to Ascend Project,进行工程转换的操作了。2.4 推理源码和数据准备2.4.1 介绍上面我们介绍了如何正确安装和运行 MindStudio 工具。接下来准备模型转换和 SDK 开发所需要用到的数据。主要包括:项目源码、预训练模型、数据集。2.4.2 项目代码使用 git 命令下载项目代码:git clone cid:link_5下载后的项目代码在ascend_community_projects/fire_detection目录下,项目代码结构如下。其中data文件夹下还存在other与test文件夹,分别用来当做测试用例和测试集;models文件夹下存放项目模型。将ascend_community_projects/fire_detection/figures文件夹中下的 火灾检测SDK流程图.png 更名为 pipeline.png 确保工程项目下无中文路径。2.4.3 项目模型点击链接,下载火灾识别所需的densenet模型:cid:link_1将其中的densenet.onnx,densenet.om放置在models文件夹下,densenet.onnx用于模型转换和densenet.om用于最后的推理。2.4.4 数据集下载点击链接,下载火灾识别所用的测试图片和测试集:cid:link_6other和test文件夹放置于data文件夹下,其中other用于test.py的测试,test用于main.py的测试。2.4.5 上传远端服务器首先点击Tools-->Deployment-->configuration,查看Deployment基本配置。查看Connection是否能正常连接到服务器。查看Mapping本地到服务器的映射路径。检查之后点击OK,并点击Tools-->Deployment-->Automatic Upload后选择服务器。此时已经可以将本地项目文件传送至远程服务器。右键点击左侧项目(Project)栏的项目文件fire_detection,选择Deployment-->upload to...选择需要上传的服务器。此过程需要花费比较长的时间,需要耐心等待,传输完成界面如下。如果因网络问题传输失败,重新upload即可覆盖原来的文件。这里需要注意的是,如果upload单个文件反复提示失败,可能需要检查一下服务器的硬盘空间是否已满,如果已满,需要整理一下服务器的存储空间,尽可能多空出一些空间来。2.5 Ascend工程转换2.5.1 介绍相比于PyCharm,MindStudio增加了对华为昇腾系列芯片相关的开发支持,所以在MindStudio中创建的工程可以简单分为昇腾工程和非昇腾工程,其中昇腾工程特指需要昇腾芯片的相关工程,包括训练,推理,算子开发等等。特别的,MindStudio还支持非昇腾项目到昇腾项目的一键转换,方便其他IDE项目的转移。本项目是在昇腾310推理服务器上实现基于MindSpore框架编写的densenet模型的部署推理,因此需要将代码转换为为昇腾工程。2.5.2 工程转换在源码和数据集都下载好的前提下,直接在MindStudio中点击左上角的file->open打开之前下载下来的模型代码文件夹。工程界面和目录如下:如果目前工程不是昇腾工程,单击菜单栏“Ascend > Convert To Ascend Project”,如下图所示。Project Type选择Ascend App,Sub Type选择Ascend MindX SDK App。如下图。完成工程转换后,可以看到在菜单栏多出了一栏蓝色的图标,是MindStudio为昇腾系列所特别支持的开发功能,项目中会出现.project文件。我们也可以通过Ascend下拉菜单查看这些功能,下面列出了我们用到的一些功能模块。2.6 MindX SDK 配置2.6.1 MindX SDK 介绍MindX SDK提供昇腾AI处理器加速的各类AI软件开发套件(SDK),提供极简易用的API,加速AI应用的开发。应用开发旨在使用华为提供的SDK和应用案例快速开发并部署人工智能应用,是基于现有模型、使用pyACL提供的Python语言API库开发深度神经网络应用,用于实现目标识别、图像分类等功能。通过MindStudio实现SDK应用开发分为基础开发与深入开发,通常情况下用户关注基础开发即可,基础开发主要包含如何通过现有的插件构建业务流并实现业务数据对接,采用模块化的设计理念,将业务流程中的各个功能单元封装成独立的插件,通过插件的串接快速构建推理业务。2.6.2 MindX SDK 配置和上面的CANN类似,SDK的配置指的是从服务器端将安装好的mxManufacture或者是mxVision同步到本地(这两者的差异似乎并不是特别大,很类似)。本文中使用的是mxVision 3.0.RC1。具体的配置方法如下:进入File->Settings->Appearance & Behavior ->System Settings->MindX SDK页面,在右边点击Install SDK。填写远端CANN位置,同上一步;填写远端SDK的位置:需要注意mxVision的位置要选到更下一级的linux-x86_64这个文件夹的mxVision-3.0.RC1:/usr/local/Ascend/mindx_sdk/mxVision_3.0.RC1/linux-x86_64/mxVision-3.0.RC1,很多开发者看到了第一个 mxVision_3.0.RC1就选了,这样就会报错。最后等待 SDK 同步,点击如下按钮可以验证是否已经成功配置了SDK:3 任务运行本章的工作是介绍如何使用MindStudio成功运行推理任务,有了上面的准备工作,下面的任务就变得比较直观了。MindStudio中的MindX SDK提供了多种可视化的操作,让一些需要代码编辑的工作通过可视化配置界面完成。本部分工作主要包括:模型转换—>Pipeline编写—>推理验证。3.1 模型转换3.1.1 介绍2.4.3节提到我们已经下载了一个*.onnx文件,这是训练完成以后的模型,可用于模型推理。在昇腾硬件平台实际部署时,需要使用工具将此文件转换为昇腾硬件平台支持的、后缀为*.om的文件。模型转换可以通过两种方式:一是代码的方式进行,在远端服务器运行infer/convert中的convert_om.sh文件即可;二是通过MindStudio的可视化操作界面进行转换。本文重点介绍可视化界面配置转换的方法。3.1.2 界面配置方式点击Ascend->Model Converter:进入到配置界面,其中Model file可以选择本地的模型文件也可以选择服务器端的模型文件,如果选择了本地的呢,需要耐心等待本地端的模型文件上传至服务器。Target SoC Version 选择默认的 Ascend310即可。 Output Path 选择一个文件夹作为.om文件的输出路径。在模型转换时使用了aipp配置,因此选择Type选择UNIT8后选择Next。打开aipp选项开关,选择aipp文件所在的路径,由于数据预处理信息已经由fire.cfg包含,因此不在需要Normalization等手动输入参数。点击Finish则系统进入到模型转换当中,右下角显示模型转换中。转换成功界面如下:默认om模型存储的路径和原模型的路径一致。需要注意的是,如果output path不选择默认,则需要指定本地存储路径,MindStudio直接将模型转换到本地。MindX SDK还支持om模型的可视化,如下所示:3.1.3 将生成的.om上传到服务器点击MindStudio右侧工程栏,查找转换生成的densenet.om文件。右键点击Deployment->Uploda to ...将生成的.om文件上传至服务器(如果前面选择了Deployment-->Automatic Upload生成的.om会自动同步到服务器)。上传成功后,下方Output输出界面如下。3.2 Pipeline的编写Pipeline编写可以采用直接编写代码方式或者界面配置方式。3.2.1 代码方式Pipeline 内容如下:调用发送数据插件appsrc、图像解码插件mxpi_imagedecoder、图像裁剪插件mxpi_imageresize、推理插件mxpi_tensorinfer、输出插件appsink进行编排即可,代码见fire_detection/pipeline/fire.pipeline:3.2.2 界面配置方式也可以直接使用MindX SDK的可视化操作界面拖拽各种插件进行组合。在成功连接远端服务器的前提下,首先点击Ascend->MindX SDK Pipeline。打开pipeline可视化流程编排窗口,此时在pipeline可视化流程编排窗口的左边有Input、Other、Output三个选项。我们可以点击三个选项,选择需要的组件拖拽到右边图形界面框中进行组合。发送数据插件appsrc在Input选项中;图像解码插件mxpi_imagedecoder、图像放缩插件mxpi_imageresize和推理插件mxpi_tensorinfer在Other选项中;输出插件appsink在Output选项中。组件选择好了以后,拖拽箭头将其连接起来,其中发送数据插件appsrc是pipeline头部,流从这里输入,点击该插件可以查看其参数信息。图像解码插件mxpi_imagedecoder对进入流的图像进行解码,点击该插件可以查看其参数信息。图像放缩插件mxpi_imageresize将图像放缩至特定尺寸,点击该插件,将Width和Height参数设置为224。推理插件mxpi_tensorinfer主要对流中的图像进行推理,点击该插件,填入.om模型路径。编辑好了以后,点击pipeline界面右下方的Save或者Save As进行保存并命名为fire.pipeline。3.3 推理验证推理验证是用./data/test中的测试图片进行测试,验证所用模型是否满足精度与FPS要求。3.3.1 编写main.py根据pipeline文件编排中的说明,我们在main.py中需要完成3件事——将图片传送至流+获取推理结果+输出相关精度与推理时间信息。main.py脚本文件在./fire_detection 工程目录下。3.3.2 服务器直接运行main.py步骤一:点击 MindStudio 上方 Tools->Start SSH session连接到服务器。步骤二:连接到服务器后,点击下方的 Remote Terminal,进入到命令行模式开发。步骤三:cd到项目文件夹所在的路径。步骤四:使用命令 python3 main.py 运行脚本文件,查看输出结果。运行成功,满足项目性能要求。3.3.3 使用MindStudio运行main.py步骤一:点击MindStudio上方的项目fire_detection后点击Edit Configuration。选择要运行的main.py所在位置。步骤二:设置完成后点击OK,完成后点击Run运行图标运行程序。此时会在MindStudio下方的Run界面输出运行结果。运行成功,满足项目性能要求。3.4 测试用例测试用例是用于测试异常与其他图片。3.4.1 编写test.pytest.py 脚本用于对 ./data/other 中的图片进行预测并作为异常测试。3.4.2 服务器直接运行test.py重复3.3中步骤,连接至服务器命令行界面,并且 cd 到项目所在文件夹下。输入命令测试图片 python3 test.py。运行成功。3.4.3 使用MindStudio运行test.py步骤一:点击MindStudio上方的项目fire_detection后点击Edit Configuration。选择要运行的test.py所在位置。步骤二:设置完成后点击OK,完成后点击Run运行图标运行程序。同main.py运行操作一样,此时会在MindStudio下方的Run界面输出运行结果。运行成功。4 FAQ4.1 CANN版本和MindX SDK版本需要单独下载么?如果需要在远端服务器上进行安装,则需要,如果是只需要配置本地端,则不需要。通过MindStudio可以同步到本地。4.2 SDK获取版本失败问题在选择服务器上的 SDK 时要选到 linux-x86_64 文件夹下的 SDK。4.3 使用MindStudio运行结果同步回本地失败在使用MindStudio运行项目时,运行结果如果出现同步失败的提示,其原因可能是项目中存在的中文路径或者存在中文命名的文件。由于中文名称在上传到服务器时会出现乱码,因此解决方案是点击MindStudio上方的Tools->Start SSH session,连接到服务器删除乱码文件。在本地修改原文件名称后,重新右键点击该文件选择Deployment->Upload to... 将修改后的文件重新上传至服务器。完成上述操作后,重新运行项目即可同步成功。4.4 开发过程中遇到难题如何求助可以登录MindStudio官方论坛,发帖提问,同时论坛里也有很多开发者分享的案例,可能对大家有所帮助。另外,在CSDN、B站、gitee、华为云上也有很多资源可以检索查找。当然更直接的办法是百度各种关键词。
  • [MindX SDK] 二维码风格化迁移
    二维码风格化迁移1 案例概述1.1 概要描述在本系统中,目的是基于 MindX SDK 和 MindSpore 框架,在昇腾平台上,开发端到端二维码风格化迁移的参考设计,在保证扫码软件能正确扫码的条件下,对黑白二维码实现色彩化风格迁移的功能,达到功能要求。1.2 模型结构该论文通过模拟二维码采样网络层和虚拟读码器实现了风格化二维码图像的任务,模型的总体流程如下图所示。其中,模型结构如下:(1)VGG-16 网络:用于提取输入风格图像、输入内容图像和生成风格化二维码图像的深度特征。(2)模拟采样层:如下图所示,通过将卷积核权重设置为标准高斯分布,长宽与二维码分块标准一致,符合二维码采样过程中“越靠近分块中心的点越容易被采样”的原则,将二维码采样过程拟合为卷积操作。(3)虚拟读码器:如下图所示,用于比较风格化二维码与真实二维码读码结果,如果读码结果正确则继续美化风格和样式;如果不正确则考虑鲁棒性。(4)损失函数:模型使用了三个损失函数,分别用于约束图像风格、图像内容和读码精确度,分别对应公式 (1),公式 (2) 和公式 (3)。其中 $L_s$ 为输入风格图像;$L_c$ 为输入内容图像;$Q$ 为生成的二维码图像;$C, H, W$ 为对应图像的尺寸;$f$ 为 VGG-16 网络生成的深度特征图像;$G$ 为用于风格迁移任务的格拉姆矩阵变换;$L_{code}^{M_k}$ 为虚拟读码器对不同分块的读码结果,相同为 $0$。$$ L_{\text {style }}\left(I_s, Q\right)=\frac{1}{C_s H_s W_s}\left|G\left[f_s\left(I_s\right)\right]-G\left[f_s(Q)\right]\right|_2^2 \tag{1}\ $$$$ L_{\text {content }}\left(I_c, Q\right)=\frac{1}{C_c H_c W_c}\left|f_c\left(I_c\right)-f_c(Q)\right|_2^2 \tag{2} \ $$$$ L_{\text {code }}=\sum_{M_k \in Q} L_{\text {code }}^{M_k} \tag{3} $$1.3 模型介绍本项目主要用到了两个模型,分别是:用于图像特征提取的模型 VGG-16 和用于模拟二维码扫码的 SSLayer 模型。VGG-16 模型的相关文件可在此处下载:cid:link_1SSLayer 模型参数固定,内嵌于代码中,在初始化模型时指定所使用的公开数据集可以在此处下载:cid:link_01.4 实现流程实现流程如下:1、基础环境:MindSpore、Ascend 910、Ascend-CANN-toolkit、Ascend Driver 2、业务流程编排与配置 3、Python 训练流程代码开发 4、模型效果及性能对齐1.5 技术流程技术流程图如下:1.6 代码地址本项目的代码地址为:cid:link_22 软件方案介绍2.1 项目方案架构介绍本系统的主要流程为:加载预训练的 Vgg16 模型和固定参数的 SSLayer 模型,解码载入二维码图、内容图和风格图,通过数据变换将图像 Resize 到适当大小,并根据二维码图和内容图初始化风格化图像,并将其设为梯度优化更新的参数;利用 Vgg16 模型和 SSLayer 模型得到对应的图像特征,计算 style 损失、content 损失和 code 损失,通过梯度优化更新风格化图像;迭代 100 次后输出最终的风格化二维码图像。各模块功能描述如下表所示:序号插件功能描述1图像解码调用 PIL 的 Image.open,分别读取二维码图、内容图和风格图2图像缩放调用MindSpore的mindspore.dataset.vision.Resize将图像缩放至合适大小3图像数据Tensor化调用MindSpore的mindspore.dataset.vision.ToTensor将图像数据转为Tensor数据4初始化风格化二维码图像根据加载的二维码图和内容图初始化风格化二维码图像Tensor,并调用MindSpore的mindspore.Parameter将其转为可梯度更新的参数5二维码风格化使用预训练好的Vgg16模型,并加载固定参数的SSLayer模型,Fix所有的模型参数,通过调用mindspore.nn.MSELoss计算 style、content和code损失,迭化优化风格化二维码图像6图像编码调用PIL的Image.open,将最终迭代优化的风格化二维码图像编码输出2.2 代码目录结构与说明本项目名称为 ArtCoder,其工程目录如下:. ├── datasets | └── download_datasets.sh // 数据集下载脚本 ├── mindspore // mindspore 版 │ ├── artcoder.py │ ├── main.py │ ├── model │ │ └── download_model.sh // 预训练模型下载脚本 │ ├── output // 风格化二维码图片输出目录 │ ├── requirements.txt // Python 库依赖 │ ├── run.sh // 运行脚本 │ ├── scan.py │ ├── scan.sh // 风格化二维码扫码测试 │ ├── ss_layer.py │ ├── test.sh // 批量测试生成风格化二维码 │ ├── utils.py │ ├── var_init.py │ └── vgg.py ├── .gitignore ├── LICENSE └── README.md3 开发准备支持的硬件形态和操作系统版本硬件环境操作系统版本Linux-x86_64 + CPU / GPU / Ascend910Ubuntu LTS >= 18.04.1Linux-aarch64+ CPU / GPU / Ascend310Ubuntu LTS >= 18.04.1软件依赖软件名称版本opencv4.6.0.66opencv-contrib1.23.3python3.9.2pillow9.3.0mindspore1.8.14 准备正式运行项目前,需要先根据第 2 节的要求,配置好相应的运行环境;然后根据提供的脚本下载好数据集和预训练模型。4.1 数据集下载风格化二维码的开源数据集:cd datasets bash download_datasets.sh cd ..4.2 模型下载 MindSpore 框架下的开源 VGG-16 预训模型:cd mindspore/model/ bash download_model.sh cd ../../5 运行首先进入到对应的代码目录中:cd mindspore/根据不同的硬件平台修改 Artcoder.py 文件中对应的硬件指定代码:# context.set_context(mode=context.GRAPH_MODE, device_target='CPU') # CPU 平台 # context.set_context(mode=context.GRAPH_MODE, device_target='GPU') # GPU 平台 context.set_context(mode=context.GRAPH_MODE, device_target='Ascend') # Ascend 平台然后根据以下注释编缉 run.sh 脚本:#!/bin/bash epoch=100 # 迭代优化次数 style_img_path="../datasets/style/square.jpg" # 风格图像路径 content_img_path="../datasets/content/man.jpg" # 内容图像路径 code_img_path="../datasets/code/man.jpg" # 二维码图像路径 output_dir="./output/man/" # 输出目录 export OMP_NUM_THREADS=1 python -W ignore main.py --epoch ${epoch} --style_img_path ${style_img_path} --content_img_path ${content_img_path} --code_img_path ${code_img_path} --output_dir ${output_dir}修改好对应的图像路径后,运行 run.sh 脚本:bash run.sh待程序跑完后可在输出目录下找到最终输出的风格化图像。6 测试如果想要批量地进行测试,可以运行 test.sh 脚本,根据以下注释修改对应参数:mode='some' # 测试模式 epoch=100 style_dir="../datasets/style" # 风格图片目录 content_dir="../datasets/content" # 内容图片目录 code_dir="../datasets/code" # 二维码图片目录 output_dir="./output" # 输出目录 # ...由于风格图像比较多,故提供两种测试模式:all 和 some,分别指使用所有的风格图进行测试和使用部分风格图进行测试。如果使用 some,其所使用的部分风格图列表在 test.sh 也可自行修改,即对应下面代码中的 style_list,可按需修改成自定义选定的测试图像列表:# 部分风格图测试 style_list=('candy.jpg' 'hb.jpg' 'been.jpg' 'st.jpg' 'square.jpg' 'udnie.jpg') # 选定的测试图像列表 for style in ${style_list[@]}; do style_name=$(basename ${style} .jpg) style_img_path="${style_dir}/${style_name}.jpg" output_img_path="${output_dir}/${image_name}_${style_name}" python -W ignore main.py --epoch ${epoch} --style_img_path ${style_img_path} --content_img_path ${content_img_path} --code_img_path ${code_img_path} --output_dir ${output_img_path} done然后运行 scan.sh 脚本,根据以下注释修改对应参数:scan_dir="./output" # 扫码测试目录 python scan.py --scan_dir ${scan_dir}最后会打印出能正确识别出的风格二维码的准确度。二维码识别使用了 Opencv-Contrib 中带的微信二维码扫码器。7 效率以下测速均在单进程下进行,涉及 GPU 和 NPU 也都是只使用单张卡进行测速。本测试主要对比对象为 Pytorch 版的开源 ArtCoder。针对一张 $592 \times 592$ 的二维码图风格化迁移总流程的实际硬件平台测速,包含模型载入、风格化总流程(图像读取、图像 Resize、图像变换、图像风格化迭代优化以及图像保存等步骤),每张二维码图风格化迭代优化 $100$ 个 Epoch。风格化总流程测速包含到图像读取、图像变换等 CPU 操作,受 CPU 型号及服务器上其它 CPU 任务影响较大。为了更好地比较该模型分别基于 PyTorch 的 GPU 平台,和 MindSpore 的 NPU 平台的效率,分别对模型载入、风格化总流程以及风格化流程中的迭代优化进行测速(其中 Mindspore 框架的模型载入时间不稳定,多次测量变化较大):框架硬件模型载入(s)风格化总流程(s)迭代优化(s)PyTorch 1.8.1Intel(R) Xeon(R) Gold 6226R CPU @ 2.90GHz + NVIDIA GeForce RTX 2080 Ti GPU6.6011.5211.25PyTorch 1.8.1Intel(R) Xeon(R) Gold 6226R CPU @ 2.90GHz1.96662.31656.21PyTorch 1.8.1Intel(R) Xeon(R) Gold 6226R CPU @ 2.90GHz + NVIDIA Tesla V100-PCIE GPU4.889.198.79MindSpore 1.8.1Intel(R) Xeon(R) Gold 6226R CPU @ 2.90GHz + NVIDIA GeForce RTX 2080 Ti GPU15.2911.4410.03MindSpore 1.8.1Intel(R) Xeon(R) Gold 6226R CPU @ 2.90GHz80.7821.1520.76MindSpore 1.8.1Intel(R) Xeon(R) Gold 6240 CPU @ 2.60GHz + Ascend 910 NPU17.3023.1419.498 可视化二维码图内容图风格图风格二维码图9 参考链接MindSpore 框架下预训练的 VGG-16 模型: cid:link_1二维码风格化模型代码参考:cid:link_3参考论文:@inproceedings{su2021artcoder, title={ArtCoder: An End-to-End Method for Generating Scanning-Robust Stylized QR Codes}, author={Su, Hao and Niu, Jianwei and Liu, Xuefeng and Li, Qingfeng and Wan, Ji and Xu, Mingliang and Ren, Tao}, booktitle={Proceedings of the IEEE/CVF Conference on Computer Vision and Pattern Recognition}, pages={2277--2286}, year={2021} }
  • [其他] 浅谈深度学习
    深度学习(DL, Deep Learning)是机器学习(ML, Machine Learning)领域中一个新的研究方向,它被引入机器学习使其更接近于最初的目标——人工智能(AI, Artificial Intelligence)。深度学习是学习样本数据的内在规律和表示层次,这些学习过程中获得的信息对诸如文字,图像和声音等数据的解释有很大的帮助。它的最终目标是让机器能够像人一样具有分析学习能力,能够识别文字、图像和声音等数据。 深度学习是一个复杂的机器学习算法,在语音和图像识别方面取得的效果,远远超过先前相关技术。深度学习在搜索技术,数据挖掘,机器学习,机器翻译,自然语言处理,多媒体学习,语音,推荐和个性化技术,以及其他相关领域都取得了很多成果。深度学习使机器模仿视听和思考等人类的活动,解决了很多复杂的模式识别难题,使得人工智能相关技术取得了很大进步。深度学习定义深度学习定义:一般是指通过训练多层网络结构对未知数据进行分类或回归深度学习分类:有监督学习方法——深度前馈网络、卷积神经网络、循环神经网络等;无监督学习方法——深度信念网、深度玻尔兹曼机,深度自编码器等。深度学习的思想:深度神经网络的基本思想是通过构建多层网络,对目标进行多层表示,以期通过多层的高层次特征来表示数据的抽象语义信息,获得更好的特征鲁棒性。深度学习应用图像处理领域主要应用图像分类(物体识别):整幅图像的分类或识别物体检测:检测图像中物体的位置进而识别物体图像分割:对图像中的特定物体按边缘进行分割图像回归:预测图像中物体组成部分的坐标语音识别领域主要应用语音识别:将语音识别为文字声纹识别:识别是哪个人的声音语音合成:根据文字合成特定人的语音自然语言处理领域主要应用语言模型:根据之前词预测下一个单词。情感分析:分析文本体现的情感(正负向、正负中或多态度类型)。神经机器翻译:基于统计语言模型的多语种互译。神经自动摘要:根据文本自动生成摘要。机器阅读理解:通过阅读文本回答问题、完成选择题或完型填空。自然语言推理:根据一句话(前提)推理出另一句话(结论)。综合应用图像描述:根据图像给出图像的描述句子可视问答:根据图像或视频回答问题图像生成:根据文本描述生成图像视频生成:根据故事自动生成视频