美文网首页
PaddleLite使用

PaddleLite使用

作者: samychen | 来源:发表于2023-06-22 20:35 被阅读0次

    PaddleLite模型使用
    PaddleLite使用流程基本上和TensorflowLite大体类似,只不过输入Tensor的shape信息需要用户自行分配,否则输入和输出Tensor的shape信息全都是默认值0

    1、配置 Config 信息:创建 MobileConfig ,用于配置模型路径、运行设备环境等相关信息
    2、通过 set_model_from_file 接口配置模型路径

      paddle::lite_api::MobileConfig config;
      config.set_model_from_file(model_path);
      config.set_threads(CPU_THREAD_NUM);
      config.set_power_mode(CPU_POWER_MODE);
    

    3、通过 CreatePaddlePredictor 接口创建 Predictor 对像,完成模型解析和环境初始化。

    p->predictor = paddle::lite_api::CreatePaddlePredictor<paddle::lite_api::MobileConfig>(config);
    

    4、推理之前需要向输入 Tensor 中填充数据。即通过 predictor->GetInput(num) 接口获取第 num 个输入 tensor,也可以通过name来获取,获取输入Tensor后先做 Resize 处理,给 tensor 分配相应的空间;然后通过获取 input_tensor->mutable_data<Dtype>() 输入数据地址进行赋值处理

    const std::vector<int64_t> INPUT_SHAPE = {1, 426, 640, 3};// NHWC格式
    std::unique_ptr<paddle::lite_api::Tensor> input_tensor(
          std::move(predictor->GetInput(0)));
    input_tensor->Resize(INPUT_SHAPE);
    
    auto *input_data = input_tensor->mutable_data<float>();//这里模型输入类型fp32
    uint8_t *image_data = reinterpret_cast<uint8_t *>(resize_image.data);
    cv::Mat out_img = cv::Mat::ones(input_height, input_width, CV_8UC3);
    for (int i = 0; i < input_height; ++i) {
        for (int j = 0; j < input_width; ++j) {
            float r = image_data[(i * input_width + j) * 3 + 0];
            float g = image_data[(i * input_width + j) * 3 + 1];
            float b = image_data[(i * input_width + j) * 3 + 2];
            float rr = std::max(-1.0f, std::min(r / 127.5f - 1.0f, 1.0f));//具体模型处理不同
            float gg = std::max(-1.0f, std::min(g / 127.5f - 1.0f, 1.0f));
            float bb = std::max(-1.0f, std::min(b / 127.5f - 1.0f, 1.0f));
            *input_data++ = rr;
            *input_data++ = gg;
            *input_data++ = bb;
            out_img.at<cv::Vec3b>(i, j)[0] = (uint8_t) (r * 255);
            out_img.at<cv::Vec3b>(i, j)[1] = (uint8_t) (g * 255);
            out_img.at<cv::Vec3b>(i, j)[2] = (uint8_t) (b * 255);
        }
    }
    cv::imwrite("../input.png", out_img);
    

    5、使用 Predictor 对像的成员函数 Run 进行模型推理

    predictor->Run();
    

    6、推理执行结束后,通过 predictor->GetOutput(num) 接口获取第 num 个输出 tensor

    std::unique_ptr<const paddle::lite_api::Tensor> output_tensor(
          std::move(predictor->GetOutput(0)));  
    const float *output_data = output_tensor->mutable_data<float>();
    // NHWC
    int h = output_tensor->shape().at(1);
    int w = output_tensor->shape().at(2);
    int c = output_tensor->shape().at(3);
    static uint8_t *s_texbuf = nullptr;//纹理内存
    if (s_texbuf == nullptr) {
        s_texbuf = (uint8_t *) calloc(1, w * h * 4);
    }
    uint8_t *d = s_texbuf; 
    for (int y = 0; y < h; y++) {
        for (int x = 0; x < w; x++) {
            float r = *output_data++;
            float g = *output_data++;
            float b = *output_data++;
            r = (uint8_t) ((r + 1.0f) / 2.0f * 255);//具体模型处理这里不同
            g = (uint8_t) ((g + 1.0f) / 2.0f * 255);
            b = (uint8_t) ((b + 1.0f) / 2.0f * 255);
            r = std::min(255.0f, r);
            g = std::min(255.0f, g);
            b = std::min(255.0f, b);
            *d++ = r;
            *d++ = g;
            *d++ = b;
            *d++ = 0xFF; 
        }
    } 
    

    使用过程遇到问题
    如何确定模型预处理和后处理所做的操作
    PaddleHub项目提供的待优化的模型压缩包python脚本包含了图像预处理和后处理过程,只需要将python代码中必须的代码转化为c++版本即可,以animegan_v2_shinkai_33模型为例,解压后的目录格式

    animegan_v2_shinkai_33                                              
    │   ├── animegan_v2_shinkai_33                                       
    │   │   ├── __model__
    │   │   ├── generator_G_MODEL_A_Conv_1_weights
    │   │   ├── generator_G_MODEL_A_Conv_2_weights
    │   │   ├── generator_G_MODEL_A_Conv_weights
    │   │   ├── generator_G_MODEL_A_LayerNorm_1_beta
    │   │   ├── generator_G_MODEL_A_LayerNorm_1_gamma
    │   │   └── ......
        └── model.py
        └── module.py
        └── processor.py
    

    module.py脚本中推断逻辑

    加载数据处理器

    processor = Processor(
        images, 
        paths,  
        output_dir, 
        min_size, 
        max_size
    )
    
    # 模型预测
    outputs = self.model.predict(processor.input_datas)
    
    # 结果后处理
    results = processor.postprocess(outputs, visualization)
    
    # 返回结果
    return results
    

    processor.py中预处理和后处理逻辑

        # 数据预处理函数
        def preprocess(self):
            input_datas = []
    
            # 数据预处理
            for i, img in enumerate(self.datas):
                # 格式转换
                img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
                
                # 缩放图片
                h, w = img.shape[:2]
                if max(h,w)>self.max_size:
                    img = cv2.resize(img, (self.max_size, int(h/w*self.max_size))) if h<w else cv2.resize(img, (int(w/h*self.max_size), self.max_size))
                elif min(h,w)<self.min_size:
                    img = cv2.resize(img, (self.min_size, int(h/w*self.min_size))) if h>w else cv2.resize(img, (int(w/h*self.min_size), self.min_size))
    
                # 裁剪图片
                h, w = img.shape[:2]
                img = img[:h-(h%32), :w-(w%32), :]
    
                # 归一化
                img = img/127.5 - 1.0
    
                # 新建维度
                img = np.expand_dims(img, axis=0).astype('float32')
    
                # 加入输入数据列表
                input_datas.append(img)
    
            # 数据按batch_size切分
            input_datas = np.concatenate(input_datas, 0)
            split_num = len(self.datas)//self.batch_size+1 if len(self.datas)%self.batch_size!=0 else len(self.datas)//self.batch_size
            input_datas = np.array_split(input_datas, split_num)   
    
            # 返回预处理完成的数据
            return input_datas
        
        # 后处理函数
        def postprocess(self, outputs, visualization):
            results = []
    
            for im_id, output in enumerate(outputs):
                # 反归一化
                image = (output.squeeze() + 1.) / 2 * 255
    
                # 限幅
                image = np.clip(image, 0, 255).astype(np.uint8)
    
                # 格式转换
                image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
    
                # 可视化
                if visualization:
                    # 检查输出目录
                    check_dir(self.output_dir)
    
                    # 写入输出图片
                    cv2.imwrite(os.path.join(self.output_dir, '%d_%d.jpg' % (im_id, time.time())), image)
    
                results.append(image)
    
            # 返回结果
            return results
    

    CUDA和OpenCL支持问题

    PaddleLite CUDA和OpenCL支持的op不是很完善,PaddleLite不像TensorflowLite完善,目前没找到什么方式可以在不支持的op情况下自动切换到CPU方式,在加载模型这一步就会出错,提示有不支持的op,并且在模型转化为nb模型这一步如果出现不支持的op就会报错,必须添加对应架构下的op实现,并重新编译PaddleLite和opt导出工具

    相关文章

      网友评论

          本文标题:PaddleLite使用

          本文链接:https://www.haomeiwen.com/subject/pxryedtx.html