Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updated Text Classification Android to use Task Library (BertNLClassifier + NLClassifier) #336

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:visibility="gone">
>

<TextView
android:id="@+id/api"
Expand Down
64 changes: 31 additions & 33 deletions lite/examples/text_classification/android/README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
# TensorFlow Lite text classification sample

<img src="https://www.tensorflow.org/lite/examples/text_classification/images/screenshot.gif" width="400px" alt="Video">

## Overview

This is an end-to-end example of movie review sentiment classification built
with TensorFlow 2.0 (Keras API), and trained on IMDB dataset. The demo app
with TensorFlow 2.0 (Keras API), and trained on [IMDB dataset](http://ai.stanford.edu/%7Eamaas/data/sentiment/) version 1.0. The demo app
processes input movie review texts, and classifies its sentiment into negative
(0) or positive (1).

Expand All @@ -14,19 +16,23 @@ mobile app.
## Model

See
[Text Classification with Movie Reviews](https://www.tensorflow.org/tutorials/keras/basic_text_classification)
[Text Classification with Movie Reviews](https://www.tensorflow.org/tutorials/keras/text_classification)
for a step-by-step instruction of building a simple text classification model.

## Android app

Follow the steps below to build and run the sample Android app.
## Build the demo using Android Studio
### Prerequisites

### Requirements
* If you don't have already, install
[Android Studio](https://developer.android.com/studio/index.html), following
the instructions on the website.

* Android Studio 3.2 or later. Install instructions can be found on
[Android Studio](https://developer.android.com/studio/index.html) website.
* Android Studio 3.2 or later.
- Gradle 4.6 or higher.
- SDK Build Tools 29.0.2 or higher.

* An Android device or an Android emulator and with API level higher than 15.
* You need an Android device or Android emulator and Android development
environment with minimum API 21.

### Building

Expand All @@ -53,34 +59,26 @@ Follow the steps below to build and run the sample Android app.

* Click `Run` to run the demo app on your Android device.

#### Switch between inference solutions (Task library vs TFLite Interpreter)
## Build the demo using gradle (command line)

### Building and Installing

This Text Classification Android reference app demonstrates two implementation
solutions:
* Use the following command to build a demo apk:

(1)
[`lib_task_api`](https://github.com/tensorflow/examples/tree/master/lite/examples/nl_classification/android/lib_task_api)
that leverages the out-of-box API from the
[TensorFlow Lite Task Library](https://www.tensorflow.org/lite/inference_with_metadata/task_library/text_classifier);
```
cd lite/examples/bert_qa/android # Folder for Android app.

(2)
[`lib_interpreter`](https://github.com/tensorflow/examples/tree/master/lite/examples/text_classification/android/lib_interpreter)
that creates the custom inference pipleline using the
[TensorFlow Lite Interpreter Java API](https://www.tensorflow.org/lite/guide/inference#load_and_run_a_model_in_java).
./gradlew build
```

The [`build.gradle`](app/build.gradle) inside `app` folder shows how to change
`flavorDimensions "tfliteInference"` to switch between the two solutions.
* Use the following command to install the apk onto your connected device:

Inside **Android Studio**, you can change the build variant to whichever one you
want to build and run—just go to `Build > Select Build Variant` and select one
from the drop-down menu. See
[configure product flavors in Android Studio](https://developer.android.com/studio/build/build-variants#product-flavors)
for more details.
```
adb install app/build/outputs/apk/debug/app-debug.apk
```

For gradle CLI, running `./gradlew build` can create APKs for both solutions
under `app/build/outputs/apk`.
## Assets folder

*Note: If you simply want the out-of-box API to run the app, we recommend
`lib_task_api`for inference. If you want to customize your own models and
control the detail of inputs and outputs, it might be easier to adapt your model
inputs and outputs by using `lib_interpreter`.*
_Do not delete the assets folder content_. If you explicitly deleted the files,
choose `Build -> Rebuild` to re-download the deleted model files into the assets
folder.
32 changes: 14 additions & 18 deletions lite/examples/text_classification/android/app/build.gradle
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
apply plugin: 'com.android.application'
apply plugin: 'de.undercouch.download'

android {
compileSdkVersion 28
buildToolsVersion "29.0.0"
compileSdkVersion 29
buildToolsVersion "29.0.2"
defaultConfig {
applicationId "org.tensorflow.lite.examples.textclassification"
minSdkVersion 21
targetSdkVersion 28
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
Expand All @@ -29,27 +30,22 @@ android {
includeAndroidResources = true
}
}

flavorDimensions "tfliteInference"
productFlavors {
// The TFLite inference is built using the TFLite Java interpreter.
interpreter {
dimension "tfliteInference"
}
// Default: The TFLite inference is built using the TFLite Task library (high-level API).
taskApi {
getIsDefault().set(true)
dimension "tfliteInference"
}
}
}

// Download the pre-trained model from the internet
project.ext.ASSET_DIR = projectDir.toString() + '/src/main/assets'
apply from:'download_model.gradle'

dependencies {
interpreterImplementation project(":lib_interpreter")
taskApiImplementation project(":lib_task_api")
implementation fileTree(dir: 'libs', include: ['*.jar'])

implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'org.jetbrains:annotations:15.0'
implementation 'com.google.android.material:material:1.0.0'

//Task Text Library dependency
implementation 'org.tensorflow:tensorflow-lite-task-text:0.2.0'

testImplementation 'androidx.test:core:1.2.0'
testImplementation 'junit:junit:4.12'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package org.tensorflow.lite.examples.textclassification;


import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.tensorflow.lite.examples.textclassification.ml.Result;
import org.tensorflow.lite.examples.textclassification.ml.TextClassificationClient;

import static org.junit.Assert.*;

import android.content.Context;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;

/** Tests of {@link TextClassificationClient} */
@RunWith(AndroidJUnit4.class)
public final class UnitTest {
private TextClassificationClient client;
private String api = "NLCLASSIFIER";

@Before
public void setUp() {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();

client = new TextClassificationClient(appContext, api);
client.load();
}
//
// @Test
// public void loadModelTest() {
// assertNotNull(client.classifier);
// }

@Test
public void predictTest() {
Result positiveText =
client
.classify("This is an interesting film. My family and I all liked it very much.")
.get(0);
assertEquals("Positive", positiveText.getTitle());
assertTrue(positiveText.getConfidence() > 0.55);
Result negativeText =
client.classify("This film cannot be worse. It is way too boring.").get(0);
assertEquals("Negative", negativeText.getTitle());
assertTrue(negativeText.getConfidence() > 0.6);
}
}
Loading