Как правильно выполнить вывод под float16 с помощью Tensorflow на C++?

Я работаю над проектом, который очень требует скорости вывода.

Я выполнил процесс вывода с помощью float32, но скорость не достигла цели, поэтому я пытаюсь сделать вывод с половинной точностью, чтобы увидеть, ускорит ли это процесс.

У меня есть предварительно обученный вес модели с типом данных float32, и я преобразовал вес с типом данных float16 с этим источником. Пока что я могу завершить процесс вывода с помощью следующего фрагмента кода с типом данных float32:

//ref: http://www.programmersought.com/article/3007934751/
UnetInterface::UnetInterface(std::string model_path)
{
    std::vector<int>MD_size_init = config["model_image_size"];
    MD_size = MD_size_init;

    std::cout << "loading model->" << model_path << std::endl;
    auto options = tensorflow::SessionOptions();
    // loading model to graph
    Status status_load = ReadBinaryProto(Env::Default(), model_path, &graphdef);
    options.config.mutable_gpu_options()->set_per_process_gpu_memory_fraction(config["GPU_usage"].get<float>());
    options.config.mutable_gpu_options()->set_allow_growth(true);

    // assign model's input & output Tensor name
    int node_count = graphdef.node_size();
    for (int i = 0; i < node_count; i++)
    {
        auto n = graphdef.node(i);
        if (n.name().find("input_") != string::npos)
        {
            inp_tensor_name = n.name();
            MD_size.push_back(n.attr().at("shape").shape().dim(1).size()); // MD_H
            MD_size.push_back(n.attr().at("shape").shape().dim(2).size()); // MD_W
            MD_size.push_back(n.attr().at("shape").shape().dim(3).size()); // input channel
        }
        else if (i == node_count - 1)
        {
            out_tensor_name = n.name();
        }

    }
    if (!status_load.ok()) {
        std::cout << "ERROR: Loading model failed..." << std::endl;
        std::cout << model_path << status_load.ToString() << "\n";
    }

    img_sideh = MD_size[0];
    img_sidew = MD_size[1];
    img_dim = MD_size[2];

    outImage = cv::Mat(img_sideh, img_sidew, CV_8UC(md_out_ch + 1));
    inpTensor = Tensor(DT_FLOAT, TensorShape({ 1, img_sideh, img_sidew, img_dim })); //*****revise part

    // create session
    Status status_newsess = NewSession(options, &session); //for the usage of gpu setting
    if (!status_newsess.ok()) {
        std::cout << "ERROR: status_newsess session failed.." << status_newsess.ToString() << std::endl;
    }

    Status status_create = session->Create(graphdef);
    if (!status_create.ok()) {
        std::cout << "ERROR: Creating graph in session failed.." << status_create.ToString() << std::endl;
    }
    else {
        std::cout << "----------- Successfully created session and load graph -------------" << std::endl;
    }
}

// -------------------------model inference-------------------------
int UnetInterface::predict(cv::Mat srcImage, cv::Mat& dstImage)
{
    // read image -> input image
    if (srcImage.empty())   // check if image can open correctly
    {
        std::cout << "can't open the image!!!!!!!" << std::endl;
        return -1;
    }

    convertCVMatToTensor(srcImage);
    Status status_run = session->Run({ { this->inp_tensor_name, inpTensor } }, { out_tensor_name }, {}, &outTensor);

    if (!status_run.ok()) {
        std::cout << "ERROR: RUN failed..." << std::endl;
        std::cout << status_run.ToString() << "\n";
        return -1;
    }

    // output tensor -> output image
    convertTensorToCVMat();
    outImage.copyTo(dstImage);

    return 0;
}

// ------------------copy image to input Tensor------------
void UnetInterface::convertCVMatToTensor(cv::Mat srcImage)
{
    srcImage.copyTo(inpFloatMat);
    inpFloatMat.convertTo(inpFloatMat, CV_32FC(img_dim));
    inpFloatMat = inpFloatMat / 255;  // normalize values
    
    //*****revise part
    float *p = (&inpTensor)->flat<float>().data();  //create a pointer point to inpTensor  
    cv::Mat tensorMat(img_sideh, img_sidew, CV_16FC(img_dim), p);  // create a tensorMat(w,h) bound with inpTensor
    inpFloatMat.convertTo(tensorMat, CV_16FC(img_dim));  // copy inpFloatMat to tensorMat to fill inpTensor

}

// -------------------------output Tensor to image------------
void UnetInterface::convertTensorToCVMat()
{
    if (outTensor[0].dims() < 4)
    {
        cv::Mat rotMatrix(outTensor[0].dim_size(0), outTensor[0].dim_size(1), CV_32FC(md_out_ch + 1), outTensor[0].flat<float>().data());
        rotMatrix = (rotMatrix * 255);
        rotMatrix.convertTo(outImage, CV_8UC(md_out_ch + 1));
    }
    else
    {
        cv::Mat rotMatrix(outTensor[0].dim_size(1), outTensor[0].dim_size(2), CV_32FC(md_out_ch + 1), outTensor[0].flat<float>().data());
        rotMatrix = (rotMatrix * 255);
        rotMatrix.convertTo(outImage, CV_8UC(md_out_ch + 1));
    }

}

void main()
{
    UnetInterface unet = UnetInterface(config["model"].get<std::string>())
    cv::Mat input = cv::imread("012.png");
    cv::cvtColor(input, input, cv::COLOR_BGR2GRAY);
    unet.predict(input, infer_res);
    cv::Mat rt_data;
    cv::extractChannel(infer_res, rt_data, 0);
    cv::imwrite("result.png", rt_data);
}

Я пытаюсь изменить часть типа данных с float32 на HALF, как это, но логический вывод не удался. Q_Q

(Обе версии не могут быть выведены успешно...)

Если я исправлю исправленную часть следующим образом:(и изменю все CV_32FC(x) на CV_16FC(x))

inpTensor = Tensor(DT_HALF, TensorShape({ 1, img_sideh, img_sidew, img_dim }));
Eigen::half *p = (&inpTensor)->flat<Eigen::half>().data();

результат показывает:

loading model->./sys/model/20200824_Lens_fp16.pb
2020-08-24 18:11:03.813444: I tensorflow/core/platform/cpu_feature_guard.cc:141] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2
2020-08-24 18:11:03.926194: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1433] Found device 0 with properties:
name: GeForce RTX 2080 Ti major: 7 minor: 5 memoryClockRate(GHz): 1.545
pciBusID: 0000:01:00.0
totalMemory: 11.00GiB freeMemory: 9.03GiB
2020-08-24 18:11:03.930141: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1512] Adding visible gpu devices: 0
2020-08-24 18:11:04.193075: I tensorflow/core/common_runtime/gpu/gpu_device.cc:984] Device interconnect StreamExecutor with strength 1 edge matrix:
2020-08-24 18:11:04.195960: I tensorflow/core/common_runtime/gpu/gpu_device.cc:990]      0
2020-08-24 18:11:04.198264: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1003] 0:   N
2020-08-24 18:11:04.199687: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1115] Created TensorFlow device (/job:localhost/replica:0/task:0/device:GPU:0 with 5632 MB memory) -> physical GPU (device: 0, name: GeForce RTX 2080 Ti, pci bus id: 0000:01:00.0, compute capability: 7.5)
----------- Successfully created session and load graph -------------
2020-08-24 18:11:07.462043: F tensorflow/core/framework/tensor.cc:626] Check failed: dtype() == expected_dtype (19 vs. 1) float expected, got half

но если я исправлю исправленную часть следующим образом:(и изменю все CV_32FC(x) на CV_16FC(x))

inpTensor = Tensor(DT_FLOAT, TensorShape({ 1, img_sideh, img_sidew, img_dim }));
Eigen::half *p = (&inpTensor)->flat<Eigen::half>().data();

результат показывает:

loading model->./sys/model/20200824_Lens_fp16.pb
2020-08-24 18:09:53.373426: I tensorflow/core/platform/cpu_feature_guard.cc:141] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2
2020-08-24 18:09:53.486965: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1433] Found device 0 with properties:
name: GeForce RTX 2080 Ti major: 7 minor: 5 memoryClockRate(GHz): 1.545
pciBusID: 0000:01:00.0
totalMemory: 11.00GiB freeMemory: 9.03GiB
2020-08-24 18:09:53.491858: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1512] Adding visible gpu devices: 0
2020-08-24 18:09:53.756802: I tensorflow/core/common_runtime/gpu/gpu_device.cc:984] Device interconnect StreamExecutor with strength 1 edge matrix:
2020-08-24 18:09:53.759252: I tensorflow/core/common_runtime/gpu/gpu_device.cc:990]      0
2020-08-24 18:09:53.761550: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1003] 0:   N
2020-08-24 18:09:53.763129: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1115] Created TensorFlow device (/job:localhost/replica:0/task:0/device:GPU:0 with 5632 MB memory) -> physical GPU (device: 0, name: GeForce RTX 2080 Ti, pci bus id: 0000:01:00.0, compute capability: 7.5)
----------- Successfully created session and load graph -------------
2020-08-24 18:09:53.784313: F tensorflow/core/framework/tensor.cc:626] Check failed: dtype() == expected_dtype (1 vs. 19) half expected, got float

Я проверил преобразованную модель с помощью этой функции, и она показывает, что вес действительно изменился на float16.

def printTensors(pb_file):

    with tf.gfile.GFile(pb_file, "rb") as f:
        graph_def = tf.GraphDef()
        graph_def.ParseFromString(f.read())
        
    with tf.Graph().as_default() as graph:
        tf.import_graph_def(graph_def)

    count = 0
    for op in graph.get_operations():
        print(count, ")---", op.values())
        count += 1

Я также пробовал некоторые другие методы, такие как использование TensorRT, onnxruntime, pytorch, но все они не получили лучшей производительности, чем метод с tenorflow(float32)...

И я редко вижу использование float16 только с Tensorflow через Интернет после долгих поисков, поэтому я решил попросить помощи здесь...

Вот некоторая информация об аппаратном / программном обеспечении:

  • ОС: Windows10
  • версия tenorflow: 1.13.1 (сборка из исходников)
  • версия opencv: 4.1.0
  • Графический процессор: Nvidia RTX2080Ti
  • CUDA / cuDNN: 10.0 / 7.4.2

Заранее благодарю за любую помощь!

0 ответов

Другие вопросы по тегам