同一TFLite分类模型在Python与Kotlin中输出结果不一致排查
问题:Keras转TFLite后Python与Android预测结果不一致
将Keras序列分类模型转为TFLite模型,用于Android人体活动识别应用(Kotlin开发)。模型接收39个浮点特征,输出22类的0/1结果,特征基于加速度计x/y/z数据转换。使用完全相同的输入特征时,Python中运行TFLite模型输出类别1,但Kotlin端输出类别4。已设置ByteBuffer为native顺序,附上两端测试代码,请求排查结果不一致的原因。
Python测试代码
# manual debugging of the Android code test_features = np.array([15.121523, 134.00166, 118.880135, 16.775457, 7.369391, 54.307922, 2.4611068, 0.7021117, 0.5910131, -6.358347, 131.46619, 137.82454, -5.3617373, 8.590351, 73.79413, 0.5156907, 3.3576744, 0.5754766, -24.99669, -6.4506474, 18.546043, -6.7344146, 1.1799959, 1.3923903, 0.36815187, 0.14375915, 0.1254036, -14.355868, 6.9462624, 21.30213, -13.576304, 1.4869289, 2.2109578, 1.4814577, 0.051293932, 0.19250752, -0.9708634, 0.855468, -0.93450075]) test_features_reshaped = test_features.reshape(1, 39) this_activity = activity_model.predict(test_features_reshaped) # Load TFLite model and allocate tensors. interpreter = tf.lite.Interpreter(model_path="MyNeuralNetModel.tflite") interpreter.allocate_tensors() # Get input and output tensors. input_details = interpreter.get_input_details() output_details = interpreter.get_output_details() # Test model on random input data. input_shape = input_details[0]['shape'] input_data = np.array(test_features_reshaped, dtype=np.float32) interpreter.set_tensor(input_details[0]['index'], input_data) interpreter.invoke() # The function `get_tensor()` returns a copy of the tensor data. # Use `tensor()` in order to get a pointer to the tensor. output_data = interpreter.get_tensor(output_details[0]['index']) print(output_data)
Kotlin测试代码
var byteBuffer: ByteBuffer = ByteBuffer.allocateDirect(4 * 39) byteBuffer.order(ByteOrder.nativeOrder()) for ( obj in combinedFeatureObjects){ byteBuffer = assembleByteBuffer(byteBuffer, obj.accelNormFeatures) byteBuffer = assembleByteBuffer(byteBuffer, obj.accelXFeatures) byteBuffer = assembleByteBuffer(byteBuffer, obj.accelYFeatures) byteBuffer = assembleByteBuffer(byteBuffer, obj.accelZFeatures) byteBuffer.putFloat(obj.corrxy.toFloat()) byteBuffer.putFloat(obj.corrxz.toFloat()) byteBuffer.putFloat(obj.corryz.toFloat()) var model = MyNeuralNetModel.newInstance(context) val inputFeature0 = TensorBufferFloat.createFixedSize(intArrayOf(1, 39), DataType.FLOAT32) inputFeature0.loadBuffer(byteBuffer) val outputs = model.process(inputFeature0) val outputFeature0 = outputs.outputFeature0AsTensorBuffer.floatArray model.close() var activityNumber: Int? = 25 for ((index, value) in outputFeature0.withIndex()) { if(value > .4999f) { activityNumber = index break } else if( value > 0) { activityNumber = index * 100 } } if ( activityNumber == 25 ) { var x = 0 }
排查关键点
- 特征顺序一致性:核对Kotlin中
assembleByteBuffer拼接的特征顺序,是否和Pythontest_features数组的顺序完全匹配,需逐位对应确认。 - ByteBuffer状态问题:每次循环填充特征前,ByteBuffer未重置position,导致后续输入数据叠加在之前的缓冲区后,实际输入长度超过39个特征。需在填充前调用
byteBuffer.rewind()或重新创建ByteBuffer。 - 数据精度匹配:确认Kotlin中所有特征转换为Float时无精度丢失,比如
corrxy等变量原始类型若为Double,转换为Float后是否和Python的float32数值一致。 - 输出解析逻辑差异:Python取输出数组最大值对应的索引,而Kotlin先判断是否有值>0.4999,无匹配则取第一个>0的索引*100,逻辑不统一。需两端采用相同的结果解析规则,比如均取最大值对应的索引。
- 模型文件一致性:确保Python转换的TFLite模型和Android端使用的是同一个文件,避免模型版本或参数不一致。
内容的提问来源于stack exchange,提问作者Jupiter Io
相关产品推荐
相关产品推荐

