【MindStudio训练营第一季】高阶班大作业(一)
收藏回复举报
【MindStudio训练营第一季】高阶班大作业(一)
发表于2023-01-13 14:16:09
0 查看

本次利用MindStudio实现图片上色,并对模型进行分析。参考代码为colorization

模型介绍

背景

论文发表在2016ECCV,在当时图像着色方面取得了进步,主要体现在损失函数的设计维持了色彩的多样性;同时引入了一种新的着色算法评估框架;采用自监督学习在基准上取得了较好的效果。

值得注意的是,本文并不是恢复灰度图的真实颜色,而是利用灰度图中物体的纹理、语义等信息作为线索来预测图片可能的颜色,上色的结果只要合理即可,这样降低了上色的难度,同时也符合预期。

动机

本文主要解决2015年时图像着色饱和度较低的问题。因此,本文为每个像素预测一个颜色分布,鼓励探索颜色的多样性。

模型

image.png

本文模型较为简单,采用Lab色彩空间,输入图片的L通道,使用卷积神经网络预测对应的ab通道取值的概率分布,最后转为RGB图像。

Lab颜色模型由三个要素组成,一个要素是亮度(L),ab是两个颜色通道。

a包括的颜色是从深绿色(低亮度值)到灰色(中亮度值)再到亮粉红色(高亮度值);

b是从亮蓝色(低亮度值)到灰色(中亮度值)再到黄色(高亮度值)。因此,这种颜色混合后将产生具有明亮效果的色彩。

推理运行

环境配置

本次程序中采用到了第三方依赖:opencvffmpegacllite,因此在运行前需要配置环境。

安装准备

首先需要添加环境变量,确保第三方依赖编译成功。

# 打开文件

vi ~/.bashrc 

# 添加环境变量

export CPU_ARCH=`arch`

export THIRDPART_PATH=/usr/local/Ascend/thirdpart/${CPU_ARCH}     #代码编译时链接samples所依赖的相关库文件

export LD_LIBRARY_PATH=${THIRDPART_PATH}/lib:$LD_LIBRARY_PATH  #运行时链接库文件

export INSTALL_DIR=/usr/local/Ascend/ascend-toolkit/latest        #CANN软件安装后的文件存储路径

# 执行命令保存文件并退出。

:wq! 

# 执行命令使其立即生效。

source ~/.bashrc

创建第三方依赖文件夹并下载依赖公共文件

# 创建第samples相关依赖文件夹

mkdir -p ${THIRDPART_PATH}

# 下载源码并安装git

cd ~

sudo apt-get install git

git clone https://gitee.com/ascend/samples.git

# 拷贝公共文件到samples相关依赖路径中

cp -r ~/samples/common ${THIRDPART_PATH}

安装opencv

直接使用apt-get安装

sudo apt-get install libopencv-dev

安装ffmpegx246插件

源码安装x246

# 下载

cd ~

git clone https://code.videolan.org/videolan/x264.git

# 安装x264

cd x264

./configure --enable-shared --disable-asm

make

sudo make install

sudo cp /usr/local/lib/libx264.so.164 /lib

源码安装ffmpeg

# 下载

cd /root

wget http://www.ffmpeg.org/releases/ffmpeg-4.1.3.tar.gz --no-check-certificate

tar -zxvf ffmpeg-4.1.3.tar.gz

# 安装

cd ffmpeg-4.1.3

./configure --enable-shared --enable-pic --enable-static --disable-x86asm --enable-libx264 --enable-gpl --prefix=${THIRDPART_PATH}

make -j8

make install

安装acllite

# 编译并安装acllite

cd ~/samples/cplusplus/common/acllite/

make

make install

image.png

模型转换

准备代码、测试图片以及Caffe模型,得到如下文件

.

├── CMakeLists.txt                # makefile

├── data

│   └── VCG211185191288.jpg       # 测试图片

├── inc                           # 头文件

│   └── colorize_process.h     

├── model                         # 模型文件和权重文件

│   ├── colorization.caffemodel

│   ├── colorization.prototxt

├── README_CN.md

├── README.md

├── scripts                       # 执行脚本

│   ├── sample_build.sh

│   └── sample_run.sh

├── set_env.cmake

└── src                           # 源代码

    ├── acl.json

    ├── CMakeLists.txt

    ├── colorize_process.cpp

    └── main.cpp

MindStudio中配置Deployment,工具->Deployment->Configuration,之后上次文件到ECS

image.png

利用ATC进行模型转换,命令如下:

atc --input_shape="data_l:1,1,224,224" --weight="./colorization.caffemodel" --input_format=NCHW --output="colorization" --soc_version=Ascend310 --framework=0 --model="./colorization.prototxt" --op_debug_level=4

参数说明

参数名称

参数值

参数说明

input_shape

1,1,224,224

输入数据的shape

model

colorization.prototxt

模型文件路径

weight

colorization.caffemodel

权重文件路径

output

colorization

输出模型路径

framework

0

原始框架类型,0Caffe

input_format

NCHW

输入数据格式,Caffe默认为NCHW

op_debug_level

4

TBE算子编译debug功能开关

soc_version

Ascend310

芯片版本

关于framework参数值

  • 0Caffe
  • 1MindSpore
  • 3TensorFlow
  • 5ONNX

关于op_debug_level参数值:

  • 0:不开启算子debug功能,在执行atc命令当前路径不生成算子编译目录kernel_meta
  • 1:开启算子debug功能,在执行atc命令当前路径算子编译生成的kernel_meta文件夹中生成TBE指令映射文件(算子cce文件*.ccepython-cce映射文件*_loc.json),用于后续工具进行AICore Error问题定位。
  • 2:开启算子debug功能,在执行atc命令当前路径算子编译生成的kernel_meta文件夹中生成TBE指令映射文件(算子cce文件*.ccepython-cce映射文件*_loc.json),并关闭编译优化开关并且开启ccec调试功能(ccec编译器选项设置为-O0-g),用于后续工具进行AICore Error问题定位。
  • 3:不开启算子debug功能,在执行atc命令当前路径算子编译生成的kernel_meta文件夹中保留.o(算子二进制文件)和.json文件(算子描述文件)。
  • 4:不开启算子debug功能,在执行atc命令当前路径算子编译生成的kernel_meta文件夹中保留.o(算子二进制文件)和.json文件(算子描述文件),并生成TBE指令映射文件(算子cce文件*.cce)和UB融合计算描述文件({$kernel_name}_compute.json)。

更多参数见参数概览

通过MindStudio建立SSH连接,工具 -> start SSH session

image.png

使用msame工具进行性能测试

  1. 安装msame

    下载Ascend / tools,找到msame,运行编译脚本,此时出现

    image.png

    解决方法:在src/CMakeLists.txt中的include_directories中修改实际的Ascend安装位置

    image.png

    再执行编译脚本./build.sh g++ $HOME/tools/msame/out

  2. 性能测试

执行msame --model colorization.om --output output/ --loop 100

image.png

平均推理性能为9.269ms

配置编译和运行

  • 构建 -> Configuration

    image.png

    image.png

  • 运行 -> 编辑配置

    image.png

    image.png

实验结果

利用DeploymentECS同步文件

源图

着色图

image.png

image.png

精度比对

比对数据准备

生成dump数据文件

  1. 选择Ascend > Dump Configuration菜单,弹出Select Offline Model窗口,选择.om模型

    image.png

  2. 设置.om模型文件的dump配置项,所有算子开启dump,同时dump算子的输入、输出数据,设置保存dump文件的路径和acl配置文件。更多参数说明,可以参考 参数说明

    image.png

    仔细观察上图可以发现Dump Path为本地路径,并且无法设置为远程路径,这是可以手动修改acl.json文件,配置正确的路径与名称。

    image.png

  3. 设置dump完成后,重新编译和运行应用工程。

    image.png

    image.png

由此得到NPU侧的dump数据

准备Caffe模型npy数据文件

  • 安装Caffe

    这里直接使用apt install caffe-cpu,但需要注意的是python版本不能太高,一开始在提供的镜像3.9下安装成功但是import失败,后来使用Ubuntu18.04公共镜像Python3.6版本安装成功。

  • 获取输入图片

    获取caffe推理数据时需要输入.bin图片文件,同时为了保证输入到caffeom模型的图片相同这里需要了解图片预处理的过程,具体代码位于src/colorize_process.cpppreprocess方法中,代码如下

  • // read image using OPENCV
  • cv::Mat mat = cv::imread(imageFile, CV_LOAD_IMAGE_COLOR);
  • //resize
  • cv::Mat reiszeMat;
  • cv::resize(mat, reiszeMat, cv::Size(modelWidth_, modelHeight_));
  • // deal image
  • reiszeMat.convertTo(reiszeMat, CV_32FC3);
  • reiszeMat = 1.0 * reiszeMat / 255;
  • cv::cvtColor(reiszeMat, reiszeMat, CV_BGR2Lab);
  • // pull out L channel and subtract 50 for mean-centering
  • std::vector<cv::Mat> channels;
  • cv::split(reiszeMat, channels);
  • cv::Mat reiszeMatL = channels[0] - 50;

阅读代码可知,采用OPENCV读入图片,缩放至224*224大小,然后将像素值缩放[0-1]区间,BGR转为Lab色域,提取L通道数据并进行中心化,最终得到reiszeMatL,既为模型输入。对此通过保存为.bin文件

std::ofstream fout1("./test.bin", std::ios::binary | std::ios::trunc);

cv::Mat flowU = cv::Mat::zeros(224, 224, CV_32FC1);

for (int i = 0; i < 224; i++)

{

   for (int j = 0; j < 224; j++)

   {

      fout1.write(reinterpret_cast<char*>(&flowU.at<float>(i, j)), sizeof(float));

   }

}

fout1.close();

  • 去除原始Caffe模型文件中的in-place

    为确保生成符合命名要求的.npy文件,需要对原始的Caffe模型文件去除in-place,生成新的.prototxt模型文件用于生成.npy文件(例如:如果有未去除in-placeABCD四个融合算子,进行dump数据,输出的结果为D算子的结果,但命名却是A算子开头,就会导致比对时找不到文件)。

    进入ascend-toolkit安装目录,找到latest/tools/operator_cmp/compare下的inplace_layer_process.py脚本,运行

  • python3 inplace_layer_process.py -i colorization.prototxt

得到new_colorization.prototxt

  • 推理获得caffe运行结果

caffe_dump.py

# coding=utf-8

import caffe

import sys

import argparse

import os

import caffe.proto.caffe_pb2 as caffe_pb2

import google.protobuf.text_format

import json

import numpy as np

import time

TIME_LENGTH = 1000

FILE_PERMISSION_FLAG = 0o600

class CaffeProcess:

   def __init__(self):

      parse = argparse.ArgumentParser()

      parse.add_argument("-w", dest="weight_file_path",

                        help="<Required> the caffe weight file path",

                        required=True)

      parse.add_argument("-m", dest="model_file_path",

                        help="<Required> the caffe model file path",

                        required=True)

      parse.add_argument("-o", dest="output_path", help="<Required> the output path",

                        required=True)

      parse.add_argument("-i", "--input_bins", dest="input_bins", help="input_bins bins. e.g. './a.bin;./c.bin'",

                        required=True)

      parse.add_argument("-n", "--input_names", dest="input_names",

                        help="input nodes name. e.g. 'graph_input_0:0;graph_input_0:1'",

                        required=True)

      args, _ = parse.parse_known_args(sys.argv[1:])

      self.weight_file_path = os.path.realpath(args.weight_file_path)

      self.model_file_path = os.path.realpath(args.model_file_path)

      self.input_bins = args.input_bins.split(";")

      self.input_names = args.input_names.split(";")

      self.output_path = os.path.realpath(args.output_path)

      self.net_param = None

      self.cur_layer_idx = -1

   @staticmethod

   def _check_file_valid(path, is_file):

      if not os.path.exists(path):

         print('Error: The path "' + path + '" does not exist.')

         exit(-1)

      if is_file:

         if not os.path.isfile(path):

               print('Error: The path "' + path + '" is not a file.')

               exit(-1)

      else:

         if not os.path.isdir(path):

               print('Error: The path "' + path + '" is not a directory.')

               exit(-1)

   def _check_arguments_valid(self):

      self._check_file_valid(self.model_file_path, True)

      self._check_file_valid(self.weight_file_path, True)

      self._check_file_valid(self.output_path, False)

      for input_file in self.input_bins:

         self._check_file_valid(input_file, True)

   @staticmethod

   def calDataSize(shape):

      dataSize = 1

      for dim in shape:

         dataSize *= dim

      return dataSize

   def _load_inputs(self, net):

      inputs_map = {}

      for layer_name, blob in net.blobs.items():

         if layer_name in self.input_names:

               input_bin = np.fromfile(

                  self.input_bins[self.input_names.index(layer_name)], np.float32)

               input_bin_shape = blob.data.shape

               if self.calDataSize(input_bin_shape) == self.calDataSize(input_bin.shape):

                  input_bin = input_bin.reshape(input_bin_shape)

               else:

                  print("Error: input node data size %d not match with input bin data size %d.", self.calDataSize(

                     input_bin_shape), self.calDataSize(input_bin.shape))

                  exit(-1)

               inputs_map[layer_name] = input_bin

      return inputs_map

   def process(self):

      """

      Function Description:

         process the caffe net, save result as dump data

      """

      # check path valid

      self._check_arguments_valid()

      # load model and weight file

      net = caffe.Net(self.model_file_path, self.weight_file_path,

                     caffe.TEST)

      inputs_map = self._load_inputs(net)

      for key, value in inputs_map.items():

         net.blobs[key].data[...] = value

      # process

      net.forward()

      # read prototxt file

      net_param = caffe_pb2.NetParameter()

      with open(self.model_file_path, 'rb') as model_file:

         google.protobuf.text_format.Parse(model_file.read(), net_param)

      for layer in net_param.layer:

         name = layer.name.replace("/", "_").replace(".", "_")

         index = 0

         for top in layer.top:

               data = net.blobs[top].data[...]

               file_name = name + "." + str(index) + "." + str(

                  round(time.time() * 1000000)) + ".npy"

               output_dump_path = os.path.join(self.output_path, file_name)

               np.save(output_dump_path, data)

               os.chmod(output_dump_path, FILE_PERMISSION_FLAG)

               print('The dump data of "' + layer.name

                     + '" has been saved to "' + output_dump_path + '".')

               index += 1

if __name__ == "__main__":

   caffe_process = CaffeProcess()

   caffe_process.process()

运行

python3 caffe_dump.py -m new_colorization.prototxt -w colorization.caffemodel -i test.bin -n 'data:0' -o ./output_dir

得到下列文件

image.png

比对

  1. 新建比对任务

    image.png

    image.png

填入比对任务参数,具体参数说明可以查看比对操作

image.png

  1. 整网比对结果

    image.png

由上述界面可以查看精度比对,各项算法指标的散点分布图和模型可视化,可见整体而言两者精度较高。下方会提供专家系统提供的精度比对结果的结果分析,本次没有给出建议。

目前支持的分析检测类型有:FP16溢出检测、输入不一致检测、整网一致性检测(整网一致性检测包括:问题节点检测、单点误差检测和一致性检测)

点击advisor旁边的Operator Detail可以查看单算子比对结果。

本帖最后由 匿名用户2023/01/13 14:16:32 编辑

我要发帖子