使用TF 2.0beta C API训练Fashion-MNIST时Tensor输入报错求助
从你描述的错误和代码来看,这个问题大概率是由数据传递方式错误、模型导出时训练操作缺失或者节点输入形状/类型不匹配导致的,下面逐个分析并给出修复方案:
1. 紧急修复:二维数组的内存拷贝错误
你的代码中memcpy(TF_TensorData(x), train_data, nbytesT);存在严重问题:train_data是float**类型(二维指针),而TF_Tensor要求的是连续的一维内存块。直接memcpy会把指针的地址值复制到张量里,而不是实际的像素数据,这会导致张量内容完全是垃圾值,进而触发各种异常。
修复方式:
- 先把二维的
train_data和label_data转换成连续的一维数组,再复制到张量中:
// 先准备连续的内存块 float* train_flat = (float*)malloc(numPoints * 784 * sizeof(float)); float* label_flat = (float*)malloc(numPoints * 10 * sizeof(float)); // 把二维数据拷贝到一维数组 for (int i = 0; i < numPoints; i++) { memcpy(train_flat + i*784, train_data[i], 784*sizeof(float)); memcpy(label_flat + i*10, label_data[i], 10*sizeof(float)); } // 再复制到张量 memcpy(TF_TensorData(x), train_flat, nbytesT); memcpy(TF_TensorData(y), label_flat, nbytesL); // 用完释放临时内存 free(train_flat); free(label_flat);
如果你的train_data本来就是连续内存(比如用单块malloc分配的),那可以直接用*train_data作为源地址,但如果是二维指针数组,必须先扁平化。
2. 验证模型导出时是否包含训练操作
在Python中用keras.experimental.export_saved_model导出模型时,默认可能只保存推理图,没有包含训练相关的操作(比如train_op)。你需要确保导出的SavedModel包含训练所需的节点:
- 改用
tf.keras.models.save_model,并明确设置save_format='tf',同时在导出前确保模型已经编译过(包含损失函数、优化器等训练相关组件):
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', # 或者 categorical_crossentropy,看你的标签格式 metrics=['accuracy']) # 导出包含训练图的模型 tf.keras.models.save_model(model, './saved_model', save_format='tf')
另外,在C中加载模型后,要确认model->train_op是正确的训练操作节点。你可以用TF_GraphGetOperationByName来手动获取训练op,而不是依赖自定义的model结构体:
const TF_Operation* train_op = TF_GraphGetOperationByName(model->graph, "train_op"); if (train_op == NULL) { // 说明模型里没有train_op,导出时出问题了 fprintf(stderr, "Failed to find train_op in model\n"); return -1; }
3. 确认标签输入的形状与模型期望一致
你的错误提到dense_2_target这个Placeholder节点,需要确认这个节点的输入形状是否和你传递的张量匹配:
- 先在Python中查看模型的输入和目标形状:
print("Model input shape:", model.input_shape) print("Model target shape:", model.output_shape) # 或者查看损失函数对应的输入形状
- 如果模型用的是
sparse_categorical_crossentropy,标签应该是一维的(shape=(numPoints,)),也就是每个样本是0-9的标量,此时你的dimLabel应该是{numPoints}而不是{numPoints,10}。 - 如果用的是
categorical_crossentropy,标签才是one-hot编码的二维数组(shape=(numPoints,10)),这时候你的dimLabel是对的,但要确保保存的labels.txt是one-hot格式。
如果是标签形状不匹配,调整C代码中的dimLabel和张量分配逻辑,同时确保Python保存的标签格式和模型期望一致。
4. 确认TF_Output节点的正确性
你代码中的TF_Output inputs[2] = {model->input, model->target};需要确保model->input和model->target是正确的节点输出:
model->input应该对应模型的输入节点(比如名称是input_1之类的),model->target应该对应训练时的标签输入节点(比如dense_2_target)。- 可以用
TF_OperationName(model->input.oper)和TF_OperationName(model->target.oper)打印节点名称,确认是否和模型中的节点一致。 - 如果节点名称不对,用
TF_GraphGetOperationByName手动获取正确的节点:
// 获取输入节点 TF_Operation* input_op = TF_GraphGetOperationByName(model->graph, "input_1"); TF_Output input = {input_op, 0}; // 0表示节点的第一个输出 // 获取标签输入节点 TF_Operation* target_op = TF_GraphGetOperationByName(model->graph, "dense_2_target"); TF_Output target = {target_op, 0};
最后验证步骤
修复后,建议先在C中打印张量的形状和部分数据,确认数据正确传入:
// 打印输入张量的形状 int num_dims = TF_NumDims(x); printf("Input tensor dims: "); for (int i=0; i<num_dims; i++) { printf("%lld ", TF_Dim(x, i)); } printf("\n"); // 打印第一个样本的前10个像素值 float* data = (float*)TF_TensorData(x); printf("First sample pixels: "); for (int i=0; i<10; i++) { printf("%.2f ", data[i]); } printf("\n");
这样可以快速确认数据是否正确加载到张量中,排除数据传递的问题。
内容的提问来源于stack exchange,提问作者jregalad

