TFLite Android Kotlin开发ByteBuffer尺寸与形状不匹配报错如何解决
问题原因分析
你遇到的The size of byte buffer and the shape do not match报错核心原因是输入缓冲区的字节大小和你定义的张量形状要求的大小不匹配,具体对应代码里的问题:
- TensorImage.fromBitmap()默认输出的是UINT8类型的缓冲区,每个像素通道占1字节,总大小为
1*224*224*3=150528字节 - 你定义的TensorBuffer是FLOAT32类型,每个像素通道占4字节,要求的总大小为
1*224*224*3*4=602112字节
两种数据类型的缓冲区大小差了4倍,直接加载就会触发崩溃。
额外注意:如果你的FLOAT32模型训练时做了像素值归一化,就算把大小匹配上,直接加载UINT8的原始像素值也会得到错误的推理结果。
解决方案
根据你自行训练的模型的输入类型选择对应方案即可:
方案1:模型输入为FLOAT32类型(绝大多数自定义训练的浮点模型都用这个类型)
不要通过TensorImage转缓冲区,直接用TensorBuffer加载Bitmap并适配归一化规则,替换原有从resized创建到loadBuffer的代码段即可:
var resized = Bitmap.createScaledBitmap(bitmap, 224, 224, true) val model = ModelUnquant.newInstance(requireActivity()) val inputFeature0 = TensorBuffer.createFixedSize(intArrayOf(1, 224, 224, 3), DataType.FLOAT32) // 这里的归一化参数要和你训练模型时的预处理规则一致 // 如果训练时是像素值除以255归一化到0~1,用NormalizeOp(0.0f, 255.0f) // 如果训练时是像素值减127.5再除以127.5归一化到-1~1,用NormalizeOp(127.5f, 127.5f) inputFeature0.loadBitmap(resized, NormalizeOp(0.0f, 255.0f)) // 后续直接跑推理即可,不需要再调用loadBuffer val outputs = model.process(inputFeature0)
方案2:模型输入为UINT8量化类型
直接修改TensorBuffer的类型定义即可匹配缓冲区大小:
val inputFeature0 = TensorBuffer.createFixedSize(intArrayOf(1, 224, 224, 3), DataType.UINT8)
可选排查校验
如果修改后仍有问题,可以添加日志打印两个缓冲区的大小做对比:
Log.d("BufferCheck", "现有缓冲区大小: ${byteBuffer.remaining()}") Log.d("BufferCheck", "要求缓冲区大小: ${inputFeature0.buffer.remaining()}")
两个数值完全相等才不会触发大小不匹配的报错。
可选优化
你当前通过相机Intent获取的data?.extras?.get("data")是系统返回的拍照缩略图,分辨率很低,缩放成224*224后会非常模糊,会严重影响识别准确率,建议后续自行实现相机拍照逻辑存储原图后再做预处理。
内容的提问来源于stack exchange,提问作者antnbaranov
相关产品推荐
相关产品推荐

