Nanosecond latency measurement for OVIC.
PiperOrigin-RevId: 308144385 Change-Id: I19c5942789110ad1ab92130c0d9914e78dfed1c0
This commit is contained in:
parent
d2a5485e83
commit
9533f3f841
|
@ -45,6 +45,7 @@ public class OvicBenchmarkerActivity extends Activity {
|
||||||
|
|
||||||
/** Name of the task-dependent data files stored in Assets. */
|
/** Name of the task-dependent data files stored in Assets. */
|
||||||
private static String labelPath = null;
|
private static String labelPath = null;
|
||||||
|
|
||||||
private static String testImagePath = null;
|
private static String testImagePath = null;
|
||||||
private static String modelPath = null;
|
private static String modelPath = null;
|
||||||
/**
|
/**
|
||||||
|
@ -91,7 +92,7 @@ public class OvicBenchmarkerActivity extends Activity {
|
||||||
labelPath = "labels.txt";
|
labelPath = "labels.txt";
|
||||||
testImagePath = "test_image_224.jpg";
|
testImagePath = "test_image_224.jpg";
|
||||||
modelPath = "quantized_model.lite";
|
modelPath = "quantized_model.lite";
|
||||||
} else { // Benchmarking detection.
|
} else { // Benchmarking detection.
|
||||||
benchmarker = new OvicDetectorBenchmarker(WALL_TIME);
|
benchmarker = new OvicDetectorBenchmarker(WALL_TIME);
|
||||||
labelPath = "coco_labels.txt";
|
labelPath = "coco_labels.txt";
|
||||||
testImagePath = "test_image_224.jpg";
|
testImagePath = "test_image_224.jpg";
|
||||||
|
@ -145,6 +146,7 @@ public class OvicBenchmarkerActivity extends Activity {
|
||||||
public void detectPressed(View view) throws IOException {
|
public void detectPressed(View view) throws IOException {
|
||||||
benchmarkSession(false);
|
benchmarkSession(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void classifyPressed(View view) throws IOException {
|
public void classifyPressed(View view) throws IOException {
|
||||||
benchmarkSession(true);
|
benchmarkSession(true);
|
||||||
}
|
}
|
||||||
|
@ -194,7 +196,7 @@ public class OvicBenchmarkerActivity extends Activity {
|
||||||
displayText
|
displayText
|
||||||
+ modelPath
|
+ modelPath
|
||||||
+ ": Average latency="
|
+ ": Average latency="
|
||||||
+ df2.format(benchmarker.getTotalRunTime() / testIter)
|
+ df2.format(benchmarker.getTotalRuntimeNano() * 1.0e-6 / testIter)
|
||||||
+ "ms after "
|
+ "ms after "
|
||||||
+ testIter
|
+ testIter
|
||||||
+ " runs.");
|
+ " runs.");
|
||||||
|
@ -204,12 +206,15 @@ public class OvicBenchmarkerActivity extends Activity {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(b/153429929) Remove with resolution of issue (see below).
|
||||||
|
@SuppressWarnings("RuntimeExec")
|
||||||
private static void setProcessorAffinity(int mask) throws IOException {
|
private static void setProcessorAffinity(int mask) throws IOException {
|
||||||
int myPid = Process.myPid();
|
int myPid = Process.myPid();
|
||||||
Log.i(TAG, String.format("Setting processor affinity to 0x%02x", mask));
|
Log.i(TAG, String.format("Setting processor affinity to 0x%02x", mask));
|
||||||
|
|
||||||
String command = String.format("taskset -a -p %x %d", mask, myPid);
|
String command = String.format("taskset -a -p %x %d", mask, myPid);
|
||||||
try {
|
try {
|
||||||
|
// TODO(b/153429929) This is deprecated, but updating is not safe while verification is hard.
|
||||||
Runtime.getRuntime().exec(command).waitFor();
|
Runtime.getRuntime().exec(command).waitFor();
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
throw new IOException("Interrupted: " + e);
|
throw new IOException("Interrupted: " + e);
|
||||||
|
|
|
@ -43,6 +43,7 @@ public abstract class OvicBenchmarker {
|
||||||
|
|
||||||
/** Dimensions of inputs. */
|
/** Dimensions of inputs. */
|
||||||
protected static final int DIM_BATCH_SIZE = 1;
|
protected static final int DIM_BATCH_SIZE = 1;
|
||||||
|
|
||||||
protected static final int DIM_PIXEL_SIZE = 3;
|
protected static final int DIM_PIXEL_SIZE = 3;
|
||||||
protected int imgHeight = 224;
|
protected int imgHeight = 224;
|
||||||
protected int imgWidth = 224;
|
protected int imgWidth = 224;
|
||||||
|
@ -53,38 +54,38 @@ public abstract class OvicBenchmarker {
|
||||||
/** A ByteBuffer to hold image data, to be feed into classifier as inputs. */
|
/** A ByteBuffer to hold image data, to be feed into classifier as inputs. */
|
||||||
protected ByteBuffer imgData = null;
|
protected ByteBuffer imgData = null;
|
||||||
|
|
||||||
/** Total runtime in ms. */
|
/** Total runtime in ns. */
|
||||||
protected double totalRuntime = 0.0;
|
protected double totalRuntimeNano = 0.0;
|
||||||
/** Total allowed runtime in ms. */
|
/** Total allowed runtime in ms. */
|
||||||
protected double wallTime = 20000 * 30.0;
|
protected double wallTimeNano = 20000 * 30 * 1.0e6;
|
||||||
/** Record whether benchmark has started (used to skip the first image). */
|
/** Record whether benchmark has started (used to skip the first image). */
|
||||||
protected boolean benchmarkStarted = false;
|
protected boolean benchmarkStarted = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes an {@link OvicBenchmarker}
|
* Initializes an {@link OvicBenchmarker}
|
||||||
*
|
*
|
||||||
* @param wallTime: a double number specifying the total amount of time to benchmark.
|
* @param wallTimeNano: a double number specifying the total amount of time to benchmark.
|
||||||
*/
|
*/
|
||||||
public OvicBenchmarker(double wallTime) {
|
public OvicBenchmarker(double wallTimeNano) {
|
||||||
benchmarkStarted = false;
|
benchmarkStarted = false;
|
||||||
totalRuntime = 0.0;
|
totalRuntimeNano = 0.0;
|
||||||
this.wallTime = wallTime;
|
this.wallTimeNano = wallTimeNano;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Return the cumulative latency of all runs so far. */
|
/** Return the cumulative latency of all runs so far. */
|
||||||
public double getTotalRunTime() {
|
public double getTotalRuntimeNano() {
|
||||||
return totalRuntime;
|
return totalRuntimeNano;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Check whether the benchmarker should stop. */
|
/** Check whether the benchmarker should stop. */
|
||||||
public Boolean shouldStop() {
|
public Boolean shouldStop() {
|
||||||
if (totalRuntime >= wallTime) {
|
if (totalRuntimeNano >= wallTimeNano) {
|
||||||
Log.e(
|
Log.e(
|
||||||
TAG,
|
TAG,
|
||||||
"Total runtime "
|
"Total runtime (ms) "
|
||||||
+ Double.toString(totalRuntime)
|
+ (totalRuntimeNano * 1.0e-6)
|
||||||
+ " exceeded walltime "
|
+ " exceeded wall-time "
|
||||||
+ Double.toString(wallTime));
|
+ (wallTimeNano * 1.0e-6));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -120,9 +121,9 @@ public abstract class OvicBenchmarker {
|
||||||
public abstract String getLastResultString();
|
public abstract String getLastResultString();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads input buffer from intValues into ByteBuffer for the interpreter.
|
* Loads input buffer from intValues into ByteBuffer for the interpreter. Input buffer must be
|
||||||
* Input buffer must be loaded in intValues and output will be placed in imgData.
|
* loaded in intValues and output will be placed in imgData.
|
||||||
*/
|
*/
|
||||||
protected void loadsInputToByteBuffer() {
|
protected void loadsInputToByteBuffer() {
|
||||||
if (imgData == null || intValues == null) {
|
if (imgData == null || intValues == null) {
|
||||||
throw new RuntimeException("Benchmarker is not yet ready to test.");
|
throw new RuntimeException("Benchmarker is not yet ready to test.");
|
||||||
|
|
|
@ -21,34 +21,39 @@ public class OvicClassificationResult {
|
||||||
|
|
||||||
/** Top K classes and probabilities. */
|
/** Top K classes and probabilities. */
|
||||||
public final ArrayList<String> topKClasses;
|
public final ArrayList<String> topKClasses;
|
||||||
|
|
||||||
public final ArrayList<Float> topKProbs;
|
public final ArrayList<Float> topKProbs;
|
||||||
public final ArrayList<Integer> topKIndices;
|
public final ArrayList<Integer> topKIndices;
|
||||||
|
|
||||||
/** Latency (ms). */
|
/** Latency (ms). */
|
||||||
public Long latency;
|
public Long latencyMilli;
|
||||||
|
|
||||||
|
/** Latency (ns). */
|
||||||
|
public Long latencyNano;
|
||||||
|
|
||||||
OvicClassificationResult() {
|
OvicClassificationResult() {
|
||||||
topKClasses = new ArrayList<>();
|
topKClasses = new ArrayList<>();
|
||||||
topKProbs = new ArrayList<>();
|
topKProbs = new ArrayList<>();
|
||||||
topKIndices = new ArrayList<>();
|
topKIndices = new ArrayList<>();
|
||||||
latency = -1L;
|
latencyMilli = -1L;
|
||||||
|
latencyNano = -1L;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
String textToShow = latency + "ms";
|
String textToShow = latencyMilli + "ms";
|
||||||
|
textToShow += "\n" + latencyNano + "ns";
|
||||||
for (int k = 0; k < topKProbs.size(); ++k) {
|
for (int k = 0; k < topKProbs.size(); ++k) {
|
||||||
textToShow +=
|
textToShow +=
|
||||||
"\nPrediction ["
|
"\nPrediction ["
|
||||||
+ k
|
+ k
|
||||||
+ "] = Class "
|
+ "] = Class "
|
||||||
+ Integer.toString(topKIndices.get(k))
|
+ topKIndices.get(k)
|
||||||
+ " ("
|
+ " ("
|
||||||
+ topKClasses.get(k)
|
+ topKClasses.get(k)
|
||||||
+ ") : "
|
+ ") : "
|
||||||
+ Float.toString(topKProbs.get(k));
|
+ topKProbs.get(k);
|
||||||
}
|
}
|
||||||
return textToShow;
|
return textToShow;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,13 +14,14 @@ limitations under the License.
|
||||||
==============================================================================*/
|
==============================================================================*/
|
||||||
package org.tensorflow.ovic;
|
package org.tensorflow.ovic;
|
||||||
|
|
||||||
|
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.MappedByteBuffer;
|
import java.nio.MappedByteBuffer;
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.AbstractMap;
|
import java.util.AbstractMap;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
@ -44,7 +45,7 @@ public class OvicClassifier {
|
||||||
private Interpreter tflite;
|
private Interpreter tflite;
|
||||||
|
|
||||||
/** Labels corresponding to the output of the vision model. */
|
/** Labels corresponding to the output of the vision model. */
|
||||||
private List<String> labelList;
|
private final List<String> labelList;
|
||||||
|
|
||||||
/** An array to hold inference results, to be feed into Tensorflow Lite as outputs. */
|
/** An array to hold inference results, to be feed into Tensorflow Lite as outputs. */
|
||||||
private byte[][] inferenceOutputArray = null;
|
private byte[][] inferenceOutputArray = null;
|
||||||
|
@ -56,19 +57,18 @@ public class OvicClassifier {
|
||||||
/** Whether the model runs as float or quantized. */
|
/** Whether the model runs as float or quantized. */
|
||||||
private Boolean outputIsFloat = null;
|
private Boolean outputIsFloat = null;
|
||||||
|
|
||||||
private PriorityQueue<Map.Entry<Integer, Float>> sortedLabels =
|
private final PriorityQueue<Map.Entry<Integer, Float>> sortedLabels =
|
||||||
new PriorityQueue<>(
|
new PriorityQueue<>(
|
||||||
RESULTS_TO_SHOW,
|
RESULTS_TO_SHOW,
|
||||||
new Comparator<Map.Entry<Integer, Float>>() {
|
new Comparator<Map.Entry<Integer, Float>>() {
|
||||||
@Override
|
@Override
|
||||||
public int compare(Map.Entry<Integer, Float> o1, Map.Entry<Integer, Float> o2) {
|
public int compare(Map.Entry<Integer, Float> o1, Map.Entry<Integer, Float> o2) {
|
||||||
return (o1.getValue()).compareTo(o2.getValue());
|
return o1.getValue().compareTo(o2.getValue());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
/** Initializes an {@code OvicClassifier}. */
|
/** Initializes an {@code OvicClassifier}. */
|
||||||
public OvicClassifier(InputStream labelInputStream, MappedByteBuffer model)
|
public OvicClassifier(InputStream labelInputStream, MappedByteBuffer model) throws IOException {
|
||||||
throws IOException, RuntimeException {
|
|
||||||
if (model == null) {
|
if (model == null) {
|
||||||
throw new RuntimeException("Input model is empty.");
|
throw new RuntimeException("Input model is empty.");
|
||||||
}
|
}
|
||||||
|
@ -80,12 +80,12 @@ public class OvicClassifier {
|
||||||
throw new RuntimeException("The model's input dimensions must be 4 (BWHC).");
|
throw new RuntimeException("The model's input dimensions must be 4 (BWHC).");
|
||||||
}
|
}
|
||||||
if (inputDims[0] != 1) {
|
if (inputDims[0] != 1) {
|
||||||
throw new RuntimeException("The model must have a batch size of 1, got "
|
throw new IllegalStateException(
|
||||||
+ inputDims[0] + " instead.");
|
"The model must have a batch size of 1, got " + inputDims[0] + " instead.");
|
||||||
}
|
}
|
||||||
if (inputDims[3] != 3) {
|
if (inputDims[3] != 3) {
|
||||||
throw new RuntimeException("The model must have three color channels, got "
|
throw new IllegalStateException(
|
||||||
+ inputDims[3] + " instead.");
|
"The model must have three color channels, got " + inputDims[3] + " instead.");
|
||||||
}
|
}
|
||||||
int minSide = Math.min(inputDims[1], inputDims[2]);
|
int minSide = Math.min(inputDims[1], inputDims[2]);
|
||||||
int maxSide = Math.max(inputDims[1], inputDims[2]);
|
int maxSide = Math.max(inputDims[1], inputDims[2]);
|
||||||
|
@ -93,12 +93,15 @@ public class OvicClassifier {
|
||||||
throw new RuntimeException("The model's resolution must be between (0, 1000].");
|
throw new RuntimeException("The model's resolution must be between (0, 1000].");
|
||||||
}
|
}
|
||||||
String outputDataType = TestHelper.getOutputDataType(tflite, 0);
|
String outputDataType = TestHelper.getOutputDataType(tflite, 0);
|
||||||
if (outputDataType.equals("float")) {
|
switch (outputDataType) {
|
||||||
outputIsFloat = true;
|
case "float":
|
||||||
} else if (outputDataType.equals("byte")) {
|
outputIsFloat = true;
|
||||||
outputIsFloat = false;
|
break;
|
||||||
} else {
|
case "byte":
|
||||||
throw new RuntimeException("Cannot process output type: " + outputDataType);
|
outputIsFloat = false;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalStateException("Cannot process output type: " + outputDataType);
|
||||||
}
|
}
|
||||||
inferenceOutputArray = new byte[1][labelList.size()];
|
inferenceOutputArray = new byte[1][labelList.size()];
|
||||||
labelProbArray = new float[1][labelList.size()];
|
labelProbArray = new float[1][labelList.size()];
|
||||||
|
@ -123,7 +126,8 @@ public class OvicClassifier {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
OvicClassificationResult iterResult = computeTopKLabels();
|
OvicClassificationResult iterResult = computeTopKLabels();
|
||||||
iterResult.latency = getLastNativeInferenceLatencyMilliseconds();
|
iterResult.latencyMilli = getLastNativeInferenceLatencyMilliseconds();
|
||||||
|
iterResult.latencyNano = getLastNativeInferenceLatencyNanoseconds();
|
||||||
return iterResult;
|
return iterResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,6 +158,18 @@ public class OvicClassifier {
|
||||||
return (latency == null) ? null : (Long) (latency / 1000000);
|
return (latency == null) ? null : (Long) (latency / 1000000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get native inference latency of last image classification run.
|
||||||
|
* @throws RuntimeException if model is uninitialized.
|
||||||
|
*/
|
||||||
|
public Long getLastNativeInferenceLatencyNanoseconds() {
|
||||||
|
if (tflite == null) {
|
||||||
|
throw new IllegalStateException(
|
||||||
|
TAG + ": ImageNet classifier has not been initialized; Failed.");
|
||||||
|
}
|
||||||
|
return tflite.getLastNativeInferenceDurationNanoseconds();
|
||||||
|
}
|
||||||
|
|
||||||
/** Closes tflite to release resources. */
|
/** Closes tflite to release resources. */
|
||||||
public void close() {
|
public void close() {
|
||||||
tflite.close();
|
tflite.close();
|
||||||
|
@ -162,9 +178,9 @@ public class OvicClassifier {
|
||||||
|
|
||||||
/** Reads label list from Assets. */
|
/** Reads label list from Assets. */
|
||||||
private static List<String> loadLabelList(InputStream labelInputStream) throws IOException {
|
private static List<String> loadLabelList(InputStream labelInputStream) throws IOException {
|
||||||
List<String> labelList = new ArrayList<String>();
|
List<String> labelList = new ArrayList<>();
|
||||||
try (BufferedReader reader =
|
try (BufferedReader reader =
|
||||||
new BufferedReader(new InputStreamReader(labelInputStream, StandardCharsets.UTF_8))) {
|
new BufferedReader(new InputStreamReader(labelInputStream, UTF_8))) {
|
||||||
String line;
|
String line;
|
||||||
while ((line = reader.readLine()) != null) {
|
while ((line = reader.readLine()) != null) {
|
||||||
labelList.add(line);
|
labelList.add(line);
|
||||||
|
|
|
@ -88,16 +88,17 @@ public final class OvicClassifierBenchmarker extends OvicBenchmarker {
|
||||||
Log.e(TAG, e.getMessage());
|
Log.e(TAG, e.getMessage());
|
||||||
Log.e(TAG, "Failed to classify image.");
|
Log.e(TAG, "Failed to classify image.");
|
||||||
}
|
}
|
||||||
if (iterResult == null || iterResult.latency == null) {
|
if (iterResult == null || iterResult.latencyMilli == null || iterResult.latencyNano == null) {
|
||||||
throw new RuntimeException("Classification result or timing is invalid.");
|
throw new RuntimeException("Classification result or timing is invalid.");
|
||||||
}
|
}
|
||||||
Log.d(TAG, "Native inference latency: " + iterResult.latency);
|
Log.d(TAG, "Native inference latency (ms): " + iterResult.latencyMilli);
|
||||||
|
Log.d(TAG, "Native inference latency (ns): " + iterResult.latencyNano);
|
||||||
Log.i(TAG, iterResult.toString());
|
Log.i(TAG, iterResult.toString());
|
||||||
|
|
||||||
if (!benchmarkStarted) { // Skip the first image to discount warming-up time.
|
if (!benchmarkStarted) { // Skip the first image to discount warming-up time.
|
||||||
benchmarkStarted = true;
|
benchmarkStarted = true;
|
||||||
} else {
|
} else {
|
||||||
totalRuntime += ((double) iterResult.latency);
|
totalRuntimeNano += ((double) iterResult.latencyNano);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,9 @@ public class OvicDetectionResult {
|
||||||
// Top K classes and probabilities.
|
// Top K classes and probabilities.
|
||||||
public final ArrayList<BoundingBox> detections;
|
public final ArrayList<BoundingBox> detections;
|
||||||
// Latency (ms).
|
// Latency (ms).
|
||||||
public Long latency = -1L;
|
public Long latencyMilli = -1L;
|
||||||
|
// Latency (ns).
|
||||||
|
public Long latencyNano = -1L;
|
||||||
// id of the image.
|
// id of the image.
|
||||||
public int id = -1;
|
public int id = -1;
|
||||||
// Number of valid detections (separately maintained, maybe different from detections.size()).
|
// Number of valid detections (separately maintained, maybe different from detections.size()).
|
||||||
|
@ -37,9 +39,10 @@ public class OvicDetectionResult {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void resetTo(Long latency, int id) {
|
public void resetTo(Long latencyMilli, Long latencyNano, int id) {
|
||||||
count = 0;
|
count = 0;
|
||||||
this.latency = latency;
|
this.latencyMilli = latencyMilli;
|
||||||
|
this.latencyNano = latencyNano;
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,7 +67,8 @@ public class OvicDetectionResult {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
String textToShow = latency + "ms";
|
String textToShow = latencyMilli + "ms";
|
||||||
|
textToShow += "\n" + latencyNano + "ns";
|
||||||
int k = 0;
|
int k = 0;
|
||||||
for (BoundingBox box : detections) {
|
for (BoundingBox box : detections) {
|
||||||
textToShow +=
|
textToShow +=
|
||||||
|
|
|
@ -14,13 +14,14 @@ limitations under the License.
|
||||||
==============================================================================*/
|
==============================================================================*/
|
||||||
package org.tensorflow.ovic;
|
package org.tensorflow.ovic;
|
||||||
|
|
||||||
|
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.MappedByteBuffer;
|
import java.nio.MappedByteBuffer;
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -105,7 +106,7 @@ public class OvicDetector implements AutoCloseable {
|
||||||
private static List<String> loadLabelList(InputStream labelInputStream) throws IOException {
|
private static List<String> loadLabelList(InputStream labelInputStream) throws IOException {
|
||||||
List<String> labelList = new ArrayList<>();
|
List<String> labelList = new ArrayList<>();
|
||||||
try (BufferedReader reader =
|
try (BufferedReader reader =
|
||||||
new BufferedReader(new InputStreamReader(labelInputStream, StandardCharsets.UTF_8))) {
|
new BufferedReader(new InputStreamReader(labelInputStream, UTF_8))) {
|
||||||
String line;
|
String line;
|
||||||
while ((line = reader.readLine()) != null) {
|
while ((line = reader.readLine()) != null) {
|
||||||
labelList.add(line);
|
labelList.add(line);
|
||||||
|
@ -131,10 +132,11 @@ public class OvicDetector implements AutoCloseable {
|
||||||
Object[] inputArray = {imgData};
|
Object[] inputArray = {imgData};
|
||||||
tflite.runForMultipleInputsOutputs(inputArray, outputMap);
|
tflite.runForMultipleInputsOutputs(inputArray, outputMap);
|
||||||
|
|
||||||
Long latency = getLastNativeInferenceLatencyMilliseconds();
|
Long latencyMilli = getLastNativeInferenceLatencyMilliseconds();
|
||||||
|
Long latencyNano = getLastNativeInferenceLatencyNanoseconds();
|
||||||
|
|
||||||
// Update the results.
|
// Update the results.
|
||||||
result.resetTo(latency, imageId);
|
result.resetTo(latencyMilli, latencyNano, imageId);
|
||||||
for (int i = 0; i < NUM_RESULTS; i++) {
|
for (int i = 0; i < NUM_RESULTS; i++) {
|
||||||
// The model returns normalized coordinates [start_y, start_x, end_y, end_x].
|
// The model returns normalized coordinates [start_y, start_x, end_y, end_x].
|
||||||
// The boxes expect pixel coordinates [x1, y1, x2, y2].
|
// The boxes expect pixel coordinates [x1, y1, x2, y2].
|
||||||
|
@ -154,7 +156,7 @@ public class OvicDetector implements AutoCloseable {
|
||||||
/*
|
/*
|
||||||
* Get native inference latency of last image detection run.
|
* Get native inference latency of last image detection run.
|
||||||
* @throws RuntimeException if model is uninitialized.
|
* @throws RuntimeException if model is uninitialized.
|
||||||
* @return The inference latency in millisecond.
|
* @return The inference latency in milliseconds.
|
||||||
*/
|
*/
|
||||||
public Long getLastNativeInferenceLatencyMilliseconds() {
|
public Long getLastNativeInferenceLatencyMilliseconds() {
|
||||||
if (tflite == null) {
|
if (tflite == null) {
|
||||||
|
@ -164,6 +166,19 @@ public class OvicDetector implements AutoCloseable {
|
||||||
return (latency == null) ? null : (Long) (latency / 1000000);
|
return (latency == null) ? null : (Long) (latency / 1000000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get native inference latency of last image detection run.
|
||||||
|
* @throws RuntimeException if model is uninitialized.
|
||||||
|
* @return The inference latency in nanoseconds.
|
||||||
|
*/
|
||||||
|
public Long getLastNativeInferenceLatencyNanoseconds() {
|
||||||
|
if (tflite == null) {
|
||||||
|
throw new IllegalStateException(
|
||||||
|
TAG + ": ImageNet classifier has not been initialized; Failed.");
|
||||||
|
}
|
||||||
|
return tflite.getLastNativeInferenceDurationNanoseconds();
|
||||||
|
}
|
||||||
|
|
||||||
public int[] getInputDims() {
|
public int[] getInputDims() {
|
||||||
return inputDims;
|
return inputDims;
|
||||||
}
|
}
|
||||||
|
|
|
@ -98,7 +98,7 @@ public final class OvicDetectorBenchmarker extends OvicBenchmarker {
|
||||||
if (!benchmarkStarted) { // Skip the first image to discount warming-up time.
|
if (!benchmarkStarted) { // Skip the first image to discount warming-up time.
|
||||||
benchmarkStarted = true;
|
benchmarkStarted = true;
|
||||||
} else {
|
} else {
|
||||||
totalRuntime += ((double) detector.result.latency);
|
totalRuntimeNano += ((double) detector.result.latencyNano);
|
||||||
}
|
}
|
||||||
return true; // Indicating that result is ready.
|
return true; // Indicating that result is ready.
|
||||||
}
|
}
|
||||||
|
|
|
@ -116,7 +116,7 @@ public final class OvicClassifierTest {
|
||||||
public void ovicClassifier_latencyNotNull() throws Exception {
|
public void ovicClassifier_latencyNotNull() throws Exception {
|
||||||
classifier = new OvicClassifier(labelsInputStream, floatModel);
|
classifier = new OvicClassifier(labelsInputStream, floatModel);
|
||||||
testResult = classifier.classifyByteBuffer(testImage);
|
testResult = classifier.classifyByteBuffer(testImage);
|
||||||
assertThat(testResult.latency).isNotNull();
|
assertThat(testResult.latencyNano).isNotNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
Loading…
Reference in New Issue