Как правильно выполнить вывод под 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
Заранее благодарю за любую помощь!