Оценка классификации изображения TfLite не соответствует, она продолжает увеличиваться для того же изображения, пока не достигнет некоторой насыщенности (фактическая оценка)
С одним и тем же экземпляром оценка "переводчика" увеличивается для того же изображения, пока не достигнет некоторой насыщенности.
Interpreter tflite = new Interpreter(loadModelFile(context));
Создайте экземпляр для ImageClassifier и используйте тот же экземпляр, чтобы классифицировать кадр и выполнить вывод для того же изображения.
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);
}
classify Frame () Метод 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;
}
applyFilter () метод ImageClassifier.java
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]);
}
}
Печатает метки top-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 - V3 и MobileNet.
1 ответ
Результаты фильтруются по applyFilter
метод. Это простой фильтр нижних частот, поэтому оценки постепенно приходят к среднесрочному среднему значению. Закомментируйте звонок applyFilter
и он должен реагировать мгновенно, но, возможно, слишком нервный для некоторых приложений.