「インタープリター」の同じインスタンスでは、同じ画像がある程度飽和するまでスコアが増加します。
Interpreter tflite = new Interpreter(loadModelFile(context));
ImageClassifier のインスタンスを作成し、同じインスタンスを使用して Frame を分類し、同じ画像の推論を実行します。
ImageClassifier(Activity activity) throws IOException {
tflite = new Interpreter(loadModelFile(activity));
labelList = loadLabelList(activity);
imgData =
ByteBuffer.allocateDirect(
DIM_BATCH_SIZE
* getImageSizeX()
* getImageSizeY()
* DIM_PIXEL_SIZE
* getNumBytesPerChannel());
imgData.order(ByteOrder.nativeOrder());
filterLabelProbArray = new float[FILTER_STAGES][getNumLabels()];
Log.d(TAG, "Created a Tensorflow Lite Image Classifier.");
}
同じ画像のフレームを分類します。Sdカードから同じ画像を取り出すことができます。
private void classifyImage() {
if (classifier == null || getActivity() == null || cameraDevice == null) {
showToast("Uninitialized Classifier or invalid context.");
return;
}
String imgPath = "/storage/emulated/0/DCIM/test.jpg";
Log.d("Image Path is %s", imgPath);
Bitmap bitmap = BitmapFactory.decodeFile(imgPath);
Bitmap newbitmap = Bitmap.createScaledBitmap(bitmap, 299, 299, false);
String textToShow = classifier.classifyFrame(newbitmap);
bitmap.recycle();
showToast(textToShow);
}
classifyFrame() ImageClassifier.java のメソッド
String classifyFrame(Bitmap bitmap) {
if (tflite == null) {
Log.e(TAG, "Image classifier has not been initialized; Skipped.");
return "Uninitialized Classifier.";
}
convertBitmapToByteBuffer(bitmap);
// Here's where the magic happens!!!
long startTime = SystemClock.uptimeMillis();
runInference();
long endTime = SystemClock.uptimeMillis();
Log.d(TAG, "Timecost to run model inference: " + Long.toString(endTime - startTime));
// Smooth the results across frames.
applyFilter();
// Print the results.
String textToShow = printTopKLabels();
textToShow = Long.toString(endTime - startTime) + "ms" + textToShow;
return textToShow;
}
ImageClassifier.java の applyFilter() メソッド
void applyFilter() {
int numLabels = getNumLabels();
// Low pass filter `labelProbArray` into the first stage of the filter.
for (int j = 0; j < numLabels; ++j) {
filterLabelProbArray[0][j] +=
FILTER_FACTOR * (getProbability(j) - filterLabelProbArray[0][j]);
}
// Low pass filter each stage into the next.
for (int i = 1; i < FILTER_STAGES; ++i) {
for (int j = 0; j < numLabels; ++j) {
filterLabelProbArray[i][j] +=
FILTER_FACTOR * (filterLabelProbArray[i - 1][j] - filterLabelProbArray[i][j]);
}
}
// Copy the last stage filter output back to `labelProbArray`.
for (int j = 0; j < numLabels; ++j) {
setProbability(j, filterLabelProbArray[FILTER_STAGES - 1][j]);
}
}
結果として UI に表示される上位 K ラベルを出力します。
private String printTopKLabels() {
for (int i = 0; i < getNumLabels(); ++i) {
sortedLabels.add(
new AbstractMap.SimpleEntry<>(labelList.get(i), getNormalizedProbability(i)));
if (sortedLabels.size() > RESULTS_TO_SHOW) {
sortedLabels.poll();
}
}
String textToShow = "";
final int size = sortedLabels.size();
for (int i = 0; i < size; ++i) {
Map.Entry<String, Float> label = sortedLabels.poll();
textToShow = String.format("\n%s: %4.2f", label.getKey(), label.getValue()) + textToShow;
}
return textToShow;
}
アプリケーションが起動された最初のスコアでは、画像分類は 0.06 です。次に、何らかのイベントで classifyImage() を呼び出すと、クリック スコアが 0.13 に増加し、同じプロセスで 0.86 (飽和) に達するまで増加し続けます。
原因はわかりませんが、TfLite モデル inceptionV3 と MobileNet の両方で発生しました。