Cannot copy to a TensorFlowLite tensor (serving_default_sequential_1_input:0) with 602112 bytes from a Java Buffer with 200704 bytes.
추론하려고 하는 모델의 인풋 속성이 INPUT 이미지에 속성이 224 x 224 x 3 크기로 사용했어야 하는데 모델 정보를 확인 안 하고 추론을 진행하였다. 오류 내용처럼 602112 바이트의 크기로 ByteBuffer를 만들어야 했었는 에 아래 코드는 224 x 224 * 1 의 크기로 ByteBuffer를 만들어서 전달하였다.
private ByteBuffer convertBitmapToGrayByteBuffer(Bitmap bitmap) {
ByteBuffer byteByffer = ByteBuffer.allocateDirect(bitmap.getByteCount());
byteByffer.order(ByteOrder.nativeOrder());
int[] pixels = new int[bitmap.getWidth() * bitmap.getHeight()];
bitmap.getPixels(pixels, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight());
for (int pixel : pixels) {
int r = pixel >> 16 & 0xFF;
int g = pixel >> 8 & 0xFF;
int b = pixel & 0xFF;
float avgPixelValue = (r + g + b) / 3.0f;
float normalizedPixelValue = avgPixelValue / 255.0f;
byteByffer.putFloat(normalizedPixelValue);
}
return byteByffer;
}
스택오버플로우에 검색해보니 아래와 같은 설명이 있다.
이것은 모델의 INPUT 불일치로 인해 발생합니다. 모델 설명에 따르면 정수형 입력/출력, 아마도 양자화된 모델이 있습니다. 공급할 부동 소수점 데이터 버퍼를 준비하려고 합니다. 가장 일반적인 2가지 설루션이 있습니다.
1) uint8 데이터를 준비합니다. 비트맵 픽셀을 1바이트 uint8s로 바이트 버퍼를 사용한다.
2) 부동 소수점 입력이 있는 모델을 찾고 코드 사용
imgData = ByteBuffer.allocateDirect(DIM_BATCH_SIZE * DIM_IMG_SIZE_X * DIM_IMG_SIZE_Y * DIM_PIXEL_SIZE); // now buffer size and input size match
imgData.order(ByteOrder.nativeOrder());
Bitmap reshapeBitmap = Bitmap.createScaledBitmap(bitmap, 224, 224, false);
convertBitmapToByteBuffer(reshapeBitmap);
private void convertBitmapToByteBuffer(Bitmap bitmap) {
if (imgData == null) {
return;
}
imgData.rewind();
bitmap.getPixels(intValues, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight());
// Convert the image to floating point.
int pixel = 0;
long startTime = SystemClock.uptimeMillis();
for (int i = 0; i < DIM_IMG_SIZE_X; ++i) {
for (int j = 0; j < DIM_IMG_SIZE_Y; ++j) {
final int val = intValues[pixel++];
imgData.putChar((byte)((((val >> 16) & 0xFF)-IMAGE_MEAN)/IMAGE_STD*255));
imgData.putChar((byte)((((val >> 8) & 0xFF)-IMAGE_MEAN)/IMAGE_STD*255));
imgData.putChar((byte)((((val) & 0xFF)-IMAGE_MEAN)/IMAGE_STD*255));
}
}
long endTime = SystemClock.uptimeMillis();
//Log.d("Timecost to put values into ByteBuffer: " + Long.toString(endTime - startTime));
}
혹시 누군가 비슷한 문제를 겪을지 몰라 포스팅을 남긴다. TensorFlow Lite에서 모델을 추론할 때 모델의 INPUT 사이즈를 꼭 확인하고 처리해야 한다. 안드로이드 스튜디오에서 tflite 모델 파일을 클릭하면 모델정보를 알 수 있다. 하지만 모델을 만든 개발자가 메타데이터를 입력을 하지 않으면 아래 처럼 모델에 대한 정보를 알 수 없다. 메타데이터를 넣어 주는 것이 추후에 디버깅하거나 모델을 사용할때 유추하게 편할거같다.
메타데이터를 알 수 없을 때는 Tensor 를 통하여 모델 정보를 확인 할 수 있다.
public Classifier(Context context) {
this.context = context;
}
// 1. 모델 로드 하는 코드(1)
public void init() throws IOException {
ByteBuffer model = loadModelFile(MODEL_NAME);
model.order(ByteOrder.nativeOrder());
interpreter = new Interpreter(model);
initModelShape();
}
// 2. 모델 로드 하는 코드(2)
private ByteBuffer loadModelFile(String modelName) throws IOException {
AssetManager am = context.getAssets();
AssetFileDescriptor afd = am.openFd(modelName);
FileInputStream fis = new FileInputStream(afd.getFileDescriptor());
FileChannel fc = fis.getChannel();
long startOffset = afd.getStartOffset();
long declaredLength = afd.getDeclaredLength();
return fc.map(FileChannel.MapMode.READ_ONLY, startOffset, declaredLength);
}
// 3. interpreter를 통하여 0 번째 인덱스의 Tensor 를 가져오는 코드
private void initModelShape() {
Tensor inputTensor = interpreter.getInputTensor(0);
int[] inputShape = inputTensor.shape();
modelInputChannel = inputShape[0];
modelInputWidth = inputShape[1];
modelInputHeight = inputShape[2];
Tensor outputTensor = interpreter.getOutputTensor(0);
int[] outputShape = outputTensor.shape();
modelOutputClasses = outputShape[1];
}
모델을 로드하고 getInputTensor(0) 0 은 index 첫번째 층의 tensor 를 가져 온다. 아래처럼 inputShape 을 확인 추론하려는 모델의 입력정보를 확인 할 수 있다.
https://www.tensorflow.org/lite/api_docs/java/org/tensorflow/lite/Interpreter
BIC로 인상적인 이미지와 글자를 생성해보세요!(1) (0) | 2023.10.04 |
---|---|
efficientnet + amp BCE (0) | 2023.07.06 |
CNN 구현 논문 조사 (0) | 2021.08.07 |
구글 Colab 또는 기타 클라우드 환경에서 데이터 다운 받기 (0) | 2021.07.04 |
YOLO Annotation 생성 혹은 라벨링 도구 (0) | 2021.06.30 |
댓글 영역