From ff151c9d6627248e7c62b2ece90c43ba0b82bdd8 Mon Sep 17 00:00:00 2001 From: Andrew Harp Date: Wed, 18 Jan 2017 13:11:45 -0800 Subject: Android demo: read MultiBox priors from a txt file in Java rather than reading from a proto file in C++ code, in order to reduce code/build complexity. New model file archive with corresponding changes has been uploaded to https://storage.googleapis.com/download.tensorflow.org/models/mobile_multibox_v1a.zip Resolves #6670 Change: 144872035 --- WORKSPACE | 4 +- tensorflow/examples/android/BUILD | 18 ----- tensorflow/examples/android/jni/box_coder_jni.cc | 92 ---------------------- tensorflow/examples/android/proto/box_coder.proto | 42 ---------- .../src/org/tensorflow/demo/DetectorActivity.java | 2 +- .../demo/TensorFlowMultiBoxDetector.java | 55 +++++++++++-- 6 files changed, 52 insertions(+), 161 deletions(-) delete mode 100644 tensorflow/examples/android/jni/box_coder_jni.cc delete mode 100644 tensorflow/examples/android/proto/box_coder.proto diff --git a/WORKSPACE b/WORKSPACE index e0931512f4..a0c936af06 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -34,8 +34,8 @@ new_http_archive( new_http_archive( name = "mobile_multibox", build_file = "models.BUILD", - url = "https://storage.googleapis.com/download.tensorflow.org/models/mobile_multibox_v1.zip", - sha256 = "b4c178fd6236dcf0a20d25d07c45eebe85281263978c6a6f1dfc49d75befc45f" + url = "https://storage.googleapis.com/download.tensorflow.org/models/mobile_multibox_v1a.zip", + sha256 = "859edcddf84dddb974c36c36cfc1f74555148e9c9213dedacf1d6b613ad52b96" ) new_http_archive( diff --git a/tensorflow/examples/android/BUILD b/tensorflow/examples/android/BUILD index 0c1cea5fc3..c795ba67a8 100644 --- a/tensorflow/examples/android/BUILD +++ b/tensorflow/examples/android/BUILD @@ -39,7 +39,6 @@ cc_binary( "notap", ], deps = [ - ":demo_proto_lib_cc", "//tensorflow/contrib/android:android_tensorflow_inference_jni", "//tensorflow/core:android_tensorflow_lib", LINKER_SCRIPT, @@ -118,20 +117,3 @@ filegroup( ) exports_files(["AndroidManifest.xml"]) - -load( - "//tensorflow/core:platform/default/build_config.bzl", - "tf_proto_library", -) - -tf_proto_library( - name = "demo_proto_lib", - srcs = glob( - ["**/*.proto"], - ), - cc_api_version = 2, - visibility = ["//visibility:public"], -) - -# ----------------------------------------------------------------------------- -# Google-internal targets go here (must be at the end). diff --git a/tensorflow/examples/android/jni/box_coder_jni.cc b/tensorflow/examples/android/jni/box_coder_jni.cc deleted file mode 100644 index be85414fc1..0000000000 --- a/tensorflow/examples/android/jni/box_coder_jni.cc +++ /dev/null @@ -1,92 +0,0 @@ -/* Copyright 2016 The TensorFlow Authors. All Rights Reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -==============================================================================*/ - -// This file loads the box coder mappings. - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "tensorflow/contrib/android/jni/jni_utils.h" -#include "tensorflow/core/platform/env.h" -#include "tensorflow/core/platform/types.h" - -#include "tensorflow/examples/android/proto/box_coder.pb.h" - -#define TENSORFLOW_METHOD(METHOD_NAME) \ - Java_org_tensorflow_demo_TensorFlowMultiBoxDetector_##METHOD_NAME // NOLINT - -#ifdef __cplusplus -extern "C" { -#endif // __cplusplus - -JNIEXPORT void JNICALL TENSORFLOW_METHOD(loadCoderOptions)( - JNIEnv* env, jobject thiz, jobject java_asset_manager, jstring location, - jfloatArray priors); - -#ifdef __cplusplus -} // extern "C" -#endif // __cplusplus - -JNIEXPORT void JNICALL TENSORFLOW_METHOD(loadCoderOptions)( - JNIEnv* env, jobject thiz, jobject java_asset_manager, jstring location, - jfloatArray priors) { - AAssetManager* const asset_manager = - AAssetManager_fromJava(env, java_asset_manager); - LOG(INFO) << "Acquired AssetManager."; - - const std::string location_str = GetString(env, location); - - org_tensorflow_demo::MultiBoxCoderOptions multi_options; - - LOG(INFO) << "Reading file to proto: " << location_str; - ReadFileToProtoOrDie(asset_manager, location_str.c_str(), &multi_options); - - LOG(INFO) << "Read file. " << multi_options.box_coder_size() << " entries."; - - jboolean iCopied = JNI_FALSE; - jfloat* values = env->GetFloatArrayElements(priors, &iCopied); - - const int array_length = env->GetArrayLength(priors); - LOG(INFO) << "Array length: " << array_length - << " (/8 = " << (array_length / 8) << ")"; - CHECK_EQ(array_length % 8, 0); - - const int num_items = - std::min(array_length / 8, multi_options.box_coder_size()); - - for (int i = 0; i < num_items; ++i) { - const org_tensorflow_demo::BoxCoderOptions& options = - multi_options.box_coder(i); - - for (int j = 0; j < 4; ++j) { - const org_tensorflow_demo::BoxCoderPrior& prior = options.priors(j); - values[i * 8 + j * 2] = prior.mean(); - values[i * 8 + j * 2 + 1] = prior.stddev(); - } - } - env->ReleaseFloatArrayElements(priors, values, 0); - - LOG(INFO) << "Read " << num_items << " options"; -} diff --git a/tensorflow/examples/android/proto/box_coder.proto b/tensorflow/examples/android/proto/box_coder.proto deleted file mode 100644 index 8576294110..0000000000 --- a/tensorflow/examples/android/proto/box_coder.proto +++ /dev/null @@ -1,42 +0,0 @@ -syntax = "proto2"; - -package org_tensorflow_demo; - -// Prior for a single feature (like minimum x coordinate, width, area, etc.) -message BoxCoderPrior { - optional float mean = 1 [default = 0.0]; - optional float stddev = 2 [default = 1.0]; -}; - -// Box encoding/decoding configuration for a single box. -message BoxCoderOptions { - // Number of priors must match the number of values used to encoded - // values which is derived from the use_... flags below. - repeated BoxCoderPrior priors = 1; - - // Minimum/maximum X/Y of the four corners are used as features. - // Order: MinX, MinY, MaxX, MaxY. - // Number of values: 4. - optional bool use_corners = 2 [default = true]; - - // Width and height of the box in this order. - // Number of values: 2. - optional bool use_width_height = 3 [default = false]; - - // Coordinates of the center of the box. - // Order: X, Y. - // Number of values: 2. - optional bool use_center = 4 [default = false]; - - // Area of the box. - // Number of values: 1. - optional bool use_area = 5 [default = false]; -}; - -// Options for MultiBoxCoder which is a encoder/decoder for a fixed number of -// boxes. -// A list of BoxCoderOptions that allows for storing multiple box coder options -// in a single file. -message MultiBoxCoderOptions { - repeated BoxCoderOptions box_coder = 1; -}; diff --git a/tensorflow/examples/android/src/org/tensorflow/demo/DetectorActivity.java b/tensorflow/examples/android/src/org/tensorflow/demo/DetectorActivity.java index 9ab5a7108a..d06f2d3c0f 100644 --- a/tensorflow/examples/android/src/org/tensorflow/demo/DetectorActivity.java +++ b/tensorflow/examples/android/src/org/tensorflow/demo/DetectorActivity.java @@ -60,7 +60,7 @@ public class DetectorActivity extends CameraActivity implements OnImageAvailable private static final String MB_OUTPUT_NAMES = "output_locations/Reshape,output_scores/Reshape"; private static final String MB_MODEL_FILE = "file:///android_asset/multibox_model.pb"; private static final String MB_LOCATION_FILE = - "file:///android_asset/multibox_location_priors.pb"; + "file:///android_asset/multibox_location_priors.txt"; // Configuration values for tiny-yolo-voc. Note that the graph is not included with TensorFlow and // must be manually placed in the assets/ directory by the user. diff --git a/tensorflow/examples/android/src/org/tensorflow/demo/TensorFlowMultiBoxDetector.java b/tensorflow/examples/android/src/org/tensorflow/demo/TensorFlowMultiBoxDetector.java index e438956c7d..34a4361626 100644 --- a/tensorflow/examples/android/src/org/tensorflow/demo/TensorFlowMultiBoxDetector.java +++ b/tensorflow/examples/android/src/org/tensorflow/demo/TensorFlowMultiBoxDetector.java @@ -19,10 +19,16 @@ import android.content.res.AssetManager; import android.graphics.Bitmap; import android.graphics.RectF; import android.os.Trace; +import java.io.BufferedReader; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Comparator; import java.util.List; import java.util.PriorityQueue; +import java.util.StringTokenizer; import org.tensorflow.contrib.android.TensorFlowInferenceInterface; import org.tensorflow.demo.env.Logger; @@ -80,7 +86,7 @@ public class TensorFlowMultiBoxDetector implements Classifier { final float imageStd, final String inputName, final String outputName) { - TensorFlowMultiBoxDetector d = new TensorFlowMultiBoxDetector(); + final TensorFlowMultiBoxDetector d = new TensorFlowMultiBoxDetector(); d.inputName = inputName; d.inputSize = inputSize; d.imageMean = imageMean; @@ -89,7 +95,11 @@ public class TensorFlowMultiBoxDetector implements Classifier { d.boxPriors = new float[numLocations * 8]; - d.loadCoderOptions(assetManager, locationFilename, d.boxPriors); + try { + d.loadCoderOptions(assetManager, locationFilename, d.boxPriors); + } catch (final IOException e) { + throw new RuntimeException("Error initializing box priors from " + locationFilename); + } // Pre-allocate buffers. d.outputNames = outputName.split(","); @@ -110,9 +120,42 @@ public class TensorFlowMultiBoxDetector implements Classifier { private TensorFlowMultiBoxDetector() {} - // Load BoxCoderOptions from native code. - private native void loadCoderOptions( - AssetManager assetManager, String locationFilename, float[] boxPriors); + private void loadCoderOptions( + final AssetManager assetManager, final String locationFilename, final float[] boxPriors) + throws IOException { + // Try to be intelligent about opening from assets or sdcard depending on prefix. + final String assetPrefix = "file:///android_asset/"; + InputStream is; + if (locationFilename.startsWith(assetPrefix)) { + is = assetManager.open(locationFilename.split(assetPrefix)[1]); + } else { + is = new FileInputStream(locationFilename); + } + + // Read values. Number of values per line doesn't matter, as long as they are separated + // by commas and/or whitespace, and there are exactly numLocations * 8 values total. + // Values are in the order mean, std for each consecutive corner of each box, for a total of 8 + // per location. + final BufferedReader reader = new BufferedReader(new InputStreamReader(is)); + int priorIndex = 0; + String line; + while ((line = reader.readLine()) != null) { + final StringTokenizer st = new StringTokenizer(line, ", "); + while (st.hasMoreTokens()) { + final String token = st.nextToken(); + try { + final float number = Float.parseFloat(token); + boxPriors[priorIndex++] = number; + } catch (final NumberFormatException e) { + // Silently ignore. + } + } + } + if (priorIndex != boxPriors.length) { + throw new RuntimeException( + "BoxPrior length mismatch: " + priorIndex + " vs " + boxPriors.length); + } + } private float[] decodeLocationsEncoding(final float[] locationEncoding) { final float[] locations = new float[locationEncoding.length]; @@ -216,7 +259,7 @@ public class TensorFlowMultiBoxDetector implements Classifier { } @Override - public void enableStatLogging(boolean debug) { + public void enableStatLogging(final boolean debug) { inferenceInterface.enableStatLogging(debug); } -- cgit v1.2.3