C语言TensorFlow推理中图像转输入张量的异常问题排查
TensorFlow C语言推理应用:图像加载与张量构建问题
背景
我正在用TensorFlow开发C语言推理应用,已完成模型首尾层代码编写,且用模拟矩阵验证过应用逻辑。此前用固定值生成输入张量的代码运行正常:
// Specify input tensor dimensions int ndims = 4; // Number of dimensions of the input tensor int64_t dims[] = {1, 224, 224, 3}; // Dimensions of the input tensor (batch_size x height x width x channels) // Generate sample data for input tensor float data[1 * 224 * 224 * 3]; for (int i = 0; i < (1 * 224 * 224 * 3); i++) { data[i] = 1.00; } int ndata = sizeof(float) * 1 * 224 * 224 * 3;
改用stb_image库加载图像生成输入张量后,推理输出的softmax结果不符合预期(模型在Python中用相同权重验证准确率达97%)。需要确认当前图像加载方式的合理性,并找出代码中的不一致问题。
代码问题分析
第一版图像加载代码的核心问题
// Load image const char* filename = "image.png"; int width, height, channels; unsigned char *img = stbi_load(filename, &width, &height, &channels, 0); if (img == NULL) { printf("Error in loading the image\n"); return 1; } // Specify input tensor dimensions int ndims = 4; // Number of dimensions of the input tensor int64_t dims[] = {1, 224, 224, 3}; // Dimensions of the input tensor (batch_size x height x width x channels) // Aloca dinamicamente memória para armazenar os valores dos pixels da imagem float *data = (float *)malloc(sizeof(float) * height * width * channels); if (data == NULL) { printf("Error in allocating memory\n"); return 1; } // Populates the 'data' array with the values of the image's pixels for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { for (int c = 0; c < channels; c++) { data[(y * width + x) * channels + c] = img[(y * width + x) * channels + c] / 255.0f; // Normaliza os valores dos pixels para o intervalo [0, 1] } } } int ndata = sizeof(float) * 1 * 224 * 224 * 3; // Create input tensor TF_Tensor* input_tensor = TF_NewTensor(TF_FLOAT, dims, ndims, data, ndata, &NoOpDeallocator, 0); if (input_tensor != NULL) { printf("TF_NewTensor is OK\n"); } else { printf("ERROR: Failed TF_NewTensor\n"); }
- 数据尺寸不匹配:
data按加载图像的原始尺寸分配内存,但ndata却用固定的224*224*3计算。若加载图像不是224x224x3,会导致张量数据长度与实际内存不匹配,触发越界或数据缺失。 - 未处理图像尺寸适配:直接假设加载图像与模型输入尺寸一致,未做resize处理,输入维度不符必然导致推理结果错误。
第二版修改后的代码问题
// Allocate data for inputs & outputs TF_Tensor** InputValues = (TF_Tensor**)malloc(sizeof(TF_Tensor*) * NumInputs); TF_Tensor** OutputValues = (TF_Tensor**)malloc(sizeof(TF_Tensor*) * NumOutputs); // Specify input tensor dimensions int ndims = 4; // Number of dimensions of the input tensor int64_t dims[] = {1, 224, 224, 3}; // Dimensions of the input tensor (batch_size x height x width x channels) // Load the image using stb_image.h int width, height, channels; unsigned char *image_data = stbi_load("play_accept_call1.png", &width, &height, &channels, 0); // Check if the image was loaded successfully if (!image_data) { printf("Error loading the image.\n"); return 1; } // Allocate memory to store pixel values as float float *data = (float *)malloc(sizeof(float) * dims[1] * dims[2] * dims[3]); // Convert pixel values from unsigned char to float and normalize to the range [0, 1] for (int i = 0; i < dims[1] * dims[2] * dims[3]; i++) { data[i] = (float)image_data[i] / 255.0; } // Free the memory allocated for the image data stbi_image_free(image_data); // Use the image data as needed // Free the memory allocated for the float array free(data); // Calculate the total size of the data int ndata = sizeof(float) * 1 * 224 * 224 * 3; // Create input tensor TF_Tensor* input_tensor = TF_AllocateTensor(TF_FLOAT, dims, ndims, ndata);
- 提前释放关键内存:创建张量前就
free(data),导致张量指向无效内存,推理时读取垃圾数据。 - 张量未初始化数据:
TF_AllocateTensor仅分配内存,未将data中的图像值拷贝进去,张量内部为未初始化的垃圾值。 - 图像越界读取风险:直接按模型输入尺寸遍历读取
image_data,若加载图像不是224x224x3,会触发数组越界读取。
修正建议
- 添加图像resize步骤:使用stb_image_resize库将加载的图像统一缩放到224x224x3尺寸,确保输入维度与模型要求一致。
- 修正内存管理逻辑:
- 方式一:用
TF_NewTensor并指定释放器,让TensorFlow自动管理内存:// 假设已将图像resize到224x224x3,数据存在resized_img中 float *data = (float *)malloc(sizeof(float) * 224*224*3); // 转换并归一化数据... // 创建张量,指定free为释放器 TF_Tensor* input_tensor = TF_NewTensor(TF_FLOAT, dims, ndims, data, ndata, &free, NULL); - 方式二:用
TF_AllocateTensor后手动拷贝数据:TF_Tensor* input_tensor = TF_AllocateTensor(TF_FLOAT, dims, ndims, ndata); if (input_tensor) { float* tensor_data = TF_TensorData(input_tensor); memcpy(tensor_data, data, ndata); } free(data); // 数据已拷贝,可安全释放
- 方式一:用
- 统一数据尺寸计算:所有数据长度均基于模型要求的224x224x3计算,避免混用图像原始尺寸与模型输入尺寸。
- 检查图像通道数:确保加载图像为3通道(RGB),若为灰度图需转换为3通道后再输入模型。
内容的提问来源于stack exchange,提问作者Renan Saraiva
相关产品推荐
相关产品推荐

