Я использую Tensorflow (TF) и его C API для написания пользовательского конвейера TF. Я загружаю изображения с помощью OpenCV, меняю их размер и нормализую (на процессоре с помощью cv :: Mat) и загружаю их в TF_Tensor (на графическом процессоре). Все это работает на удивление хорошо, и конвейер работает достаточно быстро.
Недавно я решил, что хочу еще большего ускорения и загрузки изображений непосредственно в память графического процессора, используя cv :: cuda:: GpuMat. Таким образом, нет ненужного копирования между процессором и графическим процессором. Снова, я заставил это работать - но только при загрузке единственного изображения за один раз. Мой вопрос: как мне загрузить целую серию изображений?
Пример кода для загрузки одного изображения:
void runGPUStuff(Session& session, Status& status)
{
int rows = 359, cols = 240, newDim = 224;
/* Dimensions {batchSize, with, height, numOfColors */
std::vector<std::int64_t> dimensions{1, newDim, newDim, 1};
TF_Tensor* tensorPtr = TF_AllocateTensor(
TF_FLOAT,
dimensions.data(),
dimensions.size(),
newDim * newDim * sizeof(float));
auto gpuDataPtr = TF_TensorData(tensorPtr);
/* I set the new GpuMat with the Tensor's pointer */
GpuMat newGpuMat(rows, cols, CV_32FC1, gpuDataPtr);
GpuMat oldGpuMat;
oldGpuMat.upload(cv::imread(imagePath, cv::IMREAD_UNCHANGED));
cv::cuda::resize(
oldGpuMat, newGpuMat, cv::Size(224, 224), 0, 0, cv::INTER_CUBIC);
cv::cuda::normalize(newGpuMat, newGpuMat, 1, 0, cv::NORM_MINMAX, CV_32FC1);
Tensor inputTensor;
inputTensor.setTensorPtr(tensorPtr);
Tensor outputTensor;
runSession(inputTensor, outputTensor, session, status);
}
Я пытаюсь заставить эту работу работать с двумя (и более поздними) изображениями,Вот моя попытка, которая не компилируется:
void runGPUStuff(Session& session, Status& status)
{
int rows = 359, cols = 240, newDim = 224;
/* Changing the batch size to two */
std::vector<std::int64_t> dimensions{2, newDim, newDim, 1};
TF_Tensor* tensorPtr = TF_AllocateTensor(
TF_FLOAT,
dimensions.data(),
dimensions.size(),
newDim * newDim * sizeof(float));
auto gpuDataPtr = TF_TensorData(tensorPtr);
GpuMat newGpuMat1(rows, cols, CV_32FC1, gpuDataPtr);
/* The following line complains that "expression must be
a pointer to a complete object type" */
GpuMat newGpuMat2(rows, cols, CV_32FC1, gpuDataPtr + (newDim*newDim*sizeof(float)));
GpuMat oldGpuMat;
oldGpuMat.upload(cv::imread(imagePath, cv::IMREAD_UNCHANGED));
cv::cuda::resize(
oldGpuMat, newGpuMat1, cv::Size(224, 224), 0, 0, cv::INTER_CUBIC);
cv::cuda::normalize(newGpuMat1, newGpuMat1, 1, 0, cv::NORM_MINMAX, CV_32FC1);
Tensor inputTensor;
inputTensor.setTensorPtr(tensorPtr);
Tensor outputTensor;
runSession(inputTensor, outputTensor, session, status);
}
Я думаю, что я действительно спрашиваю - как работает арифметика указателей на GPU? Если я выделяю TF_Tensor размером двух изображений, почему я не могу создать экземпляр второго GpuMat с указателем, который указывает на середину TF_Tensor?