Unverified Commit 1d83ece5 by Yagna Srinath Reddy Battula Committed by GitHub

TVM android camera demo (#5005)

parent a94f69fa
*.iml
.gradle
/local.properties
/.idea/workspace.xml
/.idea/libraries
.DS_Store
/build
/captures
.externalNativeBuild
/app/src/main/jni/jni_helper_func.h
/app/src/main/jni/org_apache_tvm_native_c_api.cc
/app/src/main/jni/org_apache_tvm_native_c_api.h
/app/src/main/obj/
gradle/
app/src/main/assets/models
[//]: # Licensed to the Apache Software Foundation (ASF) under one
[//]: # or more contributor license agreements. See the NOTICE file
[//]: # distributed with this work for additional information
[//]: # regarding copyright ownership. The ASF licenses this file
[//]: # to you 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.
Android Camera Demo Sample App
==============================
The Android Camera Demo Sample App provides a basic implementation of an Android
app that uses the tvm runtime to perform image classification in real time.
Converting Models
-----------------
The `models/prepare_models.py` script provides a example flow for dumping model
parameter files for use by the app.
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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.
apply plugin: 'com.android.application'
task buildJni(type: Exec, description: 'Build JNI libs') {
commandLine 'sh', 'src/main/jni/build.sh'
}
tasks.withType(JavaCompile) {
//compileTask -> compileTask.dependsOn buildJni
}
android {
compileSdkVersion 29
defaultConfig {
applicationId "ml.apache.tvm.android.androidcamerademo"
minSdkVersion 24
targetSdkVersion 29
renderscriptTargetApi 18
renderscriptSupportModeEnabled true
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
sourceSets {
main {
jni.srcDirs = []
jniLibs.srcDirs = ['src/main/libs']
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
buildToolsVersion = '29.0.3'
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
androidTestImplementation('androidx.test.espresso:espresso-core:3.2.0', {
exclude group: 'com.android.support', module: 'support-annotations'
})
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'com.google.android.material:material:1.1.0'
implementation 'org.apache.tvm:tvm4j-core:0.0.1-SNAPSHOT'
testImplementation 'junit:junit:4.13'
implementation("androidx.concurrent:concurrent-futures:1.0.0")
implementation "androidx.camera:camera-core:1.0.0-beta01"
implementation "androidx.camera:camera-camera2:1.0.0-beta01"
// If you want to use the CameraX View class
implementation "androidx.camera:camera-view:1.0.0-alpha08"
// If you want to use the CameraX Extensions library
implementation "androidx.camera:camera-extensions:1.0.0-alpha08"
// If you want to use the CameraX Lifecycle library
implementation "androidx.camera:camera-lifecycle:1.0.0-beta01"
}
<?xml version="1.0" encoding="utf-8"?><!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You 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.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="org.apache.tvm.android.androidcamerademo">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />
<application
android:allowBackup="true"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme"
tools:ignore="AllowBackup,MissingApplicationIcon">
<activity
android:name="org.apache.tvm.android.androidcamerademo.MainActivity"
android:label="@string/app_name"
android:screenOrientation="portrait"
android:theme="@style/AppTheme.NoActionBar"
tools:ignore="LockedOrientationActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths" />
</provider>
</application>
</manifest>
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
package org.apache.tvm.android.androidcamerademo;
import android.annotation.SuppressLint;
import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.media.Image;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.SystemClock;
import android.util.Log;
import android.util.Size;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.AppCompatTextView;
import androidx.camera.core.Camera;
import androidx.camera.core.CameraSelector;
import androidx.camera.core.ImageAnalysis;
import androidx.camera.core.ImageProxy;
import androidx.camera.core.Preview;
import androidx.camera.lifecycle.ProcessCameraProvider;
import androidx.camera.view.PreviewView;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import androidx.renderscript.Allocation;
import androidx.renderscript.Element;
import androidx.renderscript.RenderScript;
import androidx.renderscript.Script;
import androidx.renderscript.Type;
import com.google.common.util.concurrent.ListenableFuture;
import org.apache.tvm.Function;
import org.apache.tvm.Module;
import org.apache.tvm.NDArray;
import org.apache.tvm.TVMContext;
import org.apache.tvm.TVMType;
import org.apache.tvm.TVMValue;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.util.PriorityQueue;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.Semaphore;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class Camera2BasicFragment extends Fragment {
private static final String TAG = Camera2BasicFragment.class.getSimpleName();
// TVM constants
private static final int OUTPUT_INDEX = 0;
private static final int IMG_CHANNEL = 3;
private static final boolean EXE_GPU = false;
private static final int MODEL_INPUT_SIZE = 224;
private static final String MODEL_CL_LIB_FILE = "deploy_lib_opencl.so";
private static final String MODEL_CPU_LIB_FILE = "deploy_lib_cpu.so";
private static final String MODEL_GRAPH_FILE = "deploy_graph.json";
private static final String MODEL_PARAM_FILE = "deploy_param.params";
private static final String MODEL_LABEL_FILE = "image_net_labels.json";
private static final String MODELS = "models";
private static String INPUT_NAME = "input_1";
private static String[] models;
private static String mCurModel = "";
private final float[] mCHW = new float[MODEL_INPUT_SIZE * MODEL_INPUT_SIZE * IMG_CHANNEL];
private final float[] mCHW2 = new float[MODEL_INPUT_SIZE * MODEL_INPUT_SIZE * IMG_CHANNEL];
private final Semaphore isProcessingDone = new Semaphore(1);
private final ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
3,
3,
1,
TimeUnit.SECONDS,
new LinkedBlockingQueue<>()
);
// rs creation just for demo. Create rs just once in onCreate and use it again.
private RenderScript rs;
private ScriptC_yuv420888 mYuv420;
private boolean mRunClassifier = false;
private AppCompatTextView mResultView;
private AppCompatTextView mInfoView;
private ListView mModelView;
private AssetManager assetManager;
private Module graphRuntimeModule;
private JSONObject labels;
private ListenableFuture<ProcessCameraProvider> cameraProviderFuture;
private PreviewView previewView;
private ImageAnalysis imageAnalysis;
static Camera2BasicFragment newInstance() {
return new Camera2BasicFragment();
}
private static Matrix getTransformationMatrix(
final int srcWidth,
final int srcHeight,
final int dstWidth,
final int dstHeight,
final int applyRotation,
final boolean maintainAspectRatio) {
final Matrix matrix = new Matrix();
if (applyRotation != 0) {
if (applyRotation % 90 != 0) {
Log.w(TAG, "Rotation of %d % 90 != 0 " + applyRotation);
}
// Translate so center of image is at origin.
matrix.postTranslate(-srcWidth / 2.0f, -srcHeight / 2.0f);
// Rotate around origin.
matrix.postRotate(applyRotation);
}
// Account for the already applied rotation, if any, and then determine how
// much scaling is needed for each axis.
final boolean transpose = (Math.abs(applyRotation) + 90) % 180 == 0;
final int inWidth = transpose ? srcHeight : srcWidth;
final int inHeight = transpose ? srcWidth : srcHeight;
// Apply scaling if necessary.
if (inWidth != dstWidth || inHeight != dstHeight) {
final float scaleFactorX = dstWidth / (float) inWidth;
final float scaleFactorY = dstHeight / (float) inHeight;
if (maintainAspectRatio) {
// Scale by minimum factor so that dst is filled completely while
// maintaining the aspect ratio. Some image may fall off the edge.
final float scaleFactor = Math.max(scaleFactorX, scaleFactorY);
matrix.postScale(scaleFactor, scaleFactor);
} else {
// Scale exactly to fill dst from src.
matrix.postScale(scaleFactorX, scaleFactorY);
}
}
if (applyRotation != 0) {
// Translate back from origin centered reference to destination frame.
matrix.postTranslate(dstWidth / 2.0f, dstHeight / 2.0f);
}
return matrix;
}
private String[] getModels() {
String[] models;
try {
models = getActivity().getAssets().list(MODELS);
} catch (IOException e) {
return null;
}
return models;
}
@SuppressLint("DefaultLocale")
private String[] inference(float[] chw) {
NDArray inputNdArray = NDArray.empty(new long[]{1, IMG_CHANNEL, MODEL_INPUT_SIZE, MODEL_INPUT_SIZE}, new TVMType("float32"));
inputNdArray.copyFrom(chw);
Function setInputFunc = graphRuntimeModule.getFunction("set_input");
setInputFunc.pushArg(INPUT_NAME).pushArg(inputNdArray).invoke();
// release tvm local variables
inputNdArray.release();
setInputFunc.release();
// get the function from the module(run it)
Function runFunc = graphRuntimeModule.getFunction("run");
runFunc.invoke();
// release tvm local variables
runFunc.release();
// get the function from the module(get output data)
NDArray outputNdArray = NDArray.empty(new long[]{1, 1000}, new TVMType("float32"));
Function getOutputFunc = graphRuntimeModule.getFunction("get_output");
getOutputFunc.pushArg(OUTPUT_INDEX).pushArg(outputNdArray).invoke();
float[] output = outputNdArray.asFloatArray();
// release tvm local variables
outputNdArray.release();
getOutputFunc.release();
if (null != output) {
String[] results = new String[5];
// top-5
PriorityQueue<Integer> pq = new PriorityQueue<>(1000, (Integer idx1, Integer idx2) -> output[idx1] > output[idx2] ? -1 : 1);
// display the result from extracted output data
for (int j = 0; j < output.length; ++j) {
pq.add(j);
}
for (int l = 0; l < 5; l++) {
//noinspection ConstantConditions
int idx = pq.poll();
if (idx < labels.length()) {
try {
results[l] = String.format("%.2f", output[idx]) + " : " + labels.getString(Integer.toString(idx));
} catch (JSONException e) {
Log.e(TAG, "index out of range", e);
}
} else {
results[l] = "???: unknown";
}
}
return results;
}
return new String[5];
}
private void updateActiveModel() {
Log.i(TAG, "updating active model...");
new LoadModelAsyncTask().execute();
}
@Override
public void onViewCreated(final View view, Bundle savedInstanceState) {
mResultView = view.findViewById(R.id.resultTextView);
mInfoView = view.findViewById(R.id.infoTextView);
mModelView = view.findViewById(R.id.modelListView);
if (assetManager == null) {
assetManager = getActivity().getAssets();
}
mModelView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
models = getModels();
ArrayAdapter<String> modelAdapter =
new ArrayAdapter<>(
getContext(), R.layout.listview_row, R.id.listview_row_text, models);
mModelView.setAdapter(modelAdapter);
mModelView.setItemChecked(0, true);
mModelView.setOnItemClickListener(
(parent, view1, position, id) -> updateActiveModel());
new LoadModelAsyncTask().execute();
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
@Override
public void onDestroy() {
// release tvm local variables
if (null != graphRuntimeModule)
graphRuntimeModule.release();
super.onDestroy();
}
/**
* Read file from assets and return byte array.
*
* @param assets The asset manager to be used to load assets.
* @param fileName The filepath of read file.
* @return byte[] file content
* @throws IOException
*/
private byte[] getBytesFromFile(AssetManager assets, String fileName) throws IOException {
InputStream is = assets.open(fileName);
int length = is.available();
byte[] bytes = new byte[length];
// Read in the bytes
int offset = 0;
int numRead;
try {
while (offset < bytes.length
&& (numRead = is.read(bytes, offset, bytes.length - offset)) >= 0) {
offset += numRead;
}
} finally {
is.close();
}
// Ensure all the bytes have been read in
if (offset < bytes.length) {
throw new IOException("Could not completely read file " + fileName);
}
return bytes;
}
/**
* Get application cache path where to place compiled functions.
*
* @param fileName library file name.
* @return String application cache folder path
* @throws IOException
*/
private String getTempLibFilePath(String fileName) throws IOException {
File tempDir = File.createTempFile("tvm4j_demo_", "");
if (!tempDir.delete() || !tempDir.mkdir()) {
throw new IOException("Couldn't create directory " + tempDir.getAbsolutePath());
}
return (tempDir + File.separator + fileName);
}
private Bitmap YUV_420_888_toRGB(Image image, int width, int height) {
// Get the three image planes
Image.Plane[] planes = image.getPlanes();
ByteBuffer buffer = planes[0].getBuffer();
byte[] y = new byte[buffer.remaining()];
buffer.get(y);
buffer = planes[1].getBuffer();
byte[] u = new byte[buffer.remaining()];
buffer.get(u);
buffer = planes[2].getBuffer();
byte[] v = new byte[buffer.remaining()];
buffer.get(v);
int yRowStride = planes[0].getRowStride();
int uvRowStride = planes[1].getRowStride();
int uvPixelStride = planes[1].getPixelStride();
// Y,U,V are defined as global allocations, the out-Allocation is the Bitmap.
// Note also that uAlloc and vAlloc are 1-dimensional while yAlloc is 2-dimensional.
Type.Builder typeUcharY = new Type.Builder(rs, Element.U8(rs));
typeUcharY.setX(yRowStride).setY(height);
Allocation yAlloc = Allocation.createTyped(rs, typeUcharY.create());
yAlloc.copyFrom(y);
mYuv420.set_ypsIn(yAlloc);
Type.Builder typeUcharUV = new Type.Builder(rs, Element.U8(rs));
// note that the size of the u's and v's are as follows:
// ( (width/2)*PixelStride + padding ) * (height/2)
// = (RowStride ) * (height/2)
typeUcharUV.setX(u.length);
Allocation uAlloc = Allocation.createTyped(rs, typeUcharUV.create());
uAlloc.copyFrom(u);
mYuv420.set_uIn(uAlloc);
Allocation vAlloc = Allocation.createTyped(rs, typeUcharUV.create());
vAlloc.copyFrom(v);
mYuv420.set_vIn(vAlloc);
// handover parameters
mYuv420.set_picWidth(width);
mYuv420.set_uvRowStride(uvRowStride);
mYuv420.set_uvPixelStride(uvPixelStride);
Bitmap outBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Allocation outAlloc = Allocation.createFromBitmap(rs, outBitmap, Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
Script.LaunchOptions lo = new Script.LaunchOptions();
lo.setX(0, width); // by this we ignore the y’s padding zone, i.e. the right side of x between width and yRowStride
lo.setY(0, height);
mYuv420.forEach_doConvert(outAlloc, lo);
outAlloc.copyTo(outBitmap);
return outBitmap;
}
private float[] getFrame(ImageProxy imageProxy) {
@SuppressLint("UnsafeExperimentalUsageError")
Image image = imageProxy.getImage();
// extract the jpeg content
if (image == null) {
return null;
}
Bitmap imageBitmap = YUV_420_888_toRGB(image, image.getWidth(), image.getHeight());
imageProxy.close();
// crop input image at centre to model input size
Bitmap cropImageBitmap = Bitmap.createBitmap(MODEL_INPUT_SIZE, MODEL_INPUT_SIZE, Bitmap.Config.ARGB_8888);
Matrix frameToCropTransform = getTransformationMatrix(imageBitmap.getWidth(), imageBitmap.getHeight(),
MODEL_INPUT_SIZE, MODEL_INPUT_SIZE, 0, true);
Canvas canvas = new Canvas(cropImageBitmap);
canvas.drawBitmap(imageBitmap, frameToCropTransform, null);
// image pixel int values
int[] pixelValues = new int[MODEL_INPUT_SIZE * MODEL_INPUT_SIZE];
// image RGB float values
// pre-process the image data from 0-255 int to normalized float based on the
// provided parameters.
cropImageBitmap.getPixels(pixelValues, 0, MODEL_INPUT_SIZE, 0, 0, MODEL_INPUT_SIZE, MODEL_INPUT_SIZE);
for (int j = 0; j < pixelValues.length; ++j) {
mCHW2[j * 3 + 0] = ((pixelValues[j] >> 16) & 0xFF) / 255.0f;
mCHW2[j * 3 + 1] = ((pixelValues[j] >> 8) & 0xFF) / 255.0f;
mCHW2[j * 3 + 2] = (pixelValues[j] & 0xFF) / 255.0f;
}
// pre-process the image rgb data transpose based on the provided parameters.
for (int k = 0; k < IMG_CHANNEL; ++k) {
for (int l = 0; l < MODEL_INPUT_SIZE; ++l) {
for (int m = 0; m < MODEL_INPUT_SIZE; ++m) {
int dst_index = m + MODEL_INPUT_SIZE * l + MODEL_INPUT_SIZE * MODEL_INPUT_SIZE * k;
int src_index = k + IMG_CHANNEL * m + IMG_CHANNEL * MODEL_INPUT_SIZE * l;
mCHW[dst_index] = mCHW2[src_index];
}
}
}
return mCHW;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
cameraProviderFuture = ProcessCameraProvider.getInstance(getActivity());
}
@SuppressLint({"RestrictedApi", "UnsafeExperimentalUsageError"})
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_camera2_basic, container, false);
previewView = v.findViewById(R.id.textureView);
rs = RenderScript.create(getActivity());
mYuv420 = new ScriptC_yuv420888(rs);
cameraProviderFuture.addListener(() -> {
try {
ProcessCameraProvider cameraProvider = cameraProviderFuture.get();
bindPreview(cameraProvider);
} catch (ExecutionException | InterruptedException e) {
// No errors need to be handled for this Future. This should never be reached
}
}, ContextCompat.getMainExecutor(getActivity()));
imageAnalysis = new ImageAnalysis.Builder()
.setTargetResolution(new Size(224, 224))
.setMaxResolution(new Size(300, 300))
.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
.build();
imageAnalysis.setAnalyzer(threadPoolExecutor, image -> {
Log.e(TAG, "w: " + image.getWidth() + " h: " + image.getHeight());
if (mRunClassifier && isProcessingDone.tryAcquire()) {
long t1 = SystemClock.uptimeMillis();
//float[] chw = getFrame(image);
//float[] chw = YUV_420_888_toRGBPixels(image);
float[] chw = getFrame(image);
if (chw != null) {
long t2 = SystemClock.uptimeMillis();
String[] results = inference(chw);
long t3 = SystemClock.uptimeMillis();
StringBuilder msgBuilder = new StringBuilder();
for (int l = 1; l < 5; l++) {
msgBuilder.append(results[l]).append("\n");
}
String msg = msgBuilder.toString();
msg += "getFrame(): " + (t2 - t1) + "ms" + "\n";
msg += "inference(): " + (t3 - t2) + "ms" + "\n";
String finalMsg = msg;
this.getActivity().runOnUiThread(() -> {
mResultView.setText(String.format("model: %s \n %s", mCurModel, results[0]));
mInfoView.setText(finalMsg);
});
}
isProcessingDone.release();
}
image.close();
});
return v;
}
private void bindPreview(@NonNull ProcessCameraProvider cameraProvider) {
@SuppressLint("RestrictedApi") Preview preview = new Preview.Builder()
.setMaxResolution(new Size(800, 800))
.setTargetName("Preview")
.build();
preview.setSurfaceProvider(previewView.getPreviewSurfaceProvider());
CameraSelector cameraSelector =
new CameraSelector.Builder()
.requireLensFacing(CameraSelector.LENS_FACING_BACK)
.build();
Camera camera = cameraProvider.bindToLifecycle(this, cameraSelector, preview, imageAnalysis);
}
@Override
public void onDestroyView() {
threadPoolExecutor.shutdownNow();
super.onDestroyView();
}
private void setInputName(String modelName) {
if (modelName.equals("mobilenet_v2")) {
INPUT_NAME = "input_1";
} else if (modelName.equals("resnet18_v1")) {
INPUT_NAME = "data";
} else {
throw new RuntimeException("Model input may not be right. Please set INPUT_NAME here explicitly.");
}
}
/*
Load precompiled model on TVM graph runtime and init the system.
*/
private class LoadModelAsyncTask extends AsyncTask<Void, Void, Integer> {
@Override
protected Integer doInBackground(Void... args) {
mRunClassifier = false;
// load synset name
int modelIndex = mModelView.getCheckedItemPosition();
setInputName(models[modelIndex]);
String model = MODELS + "/" + models[modelIndex];
String labelFilename = MODEL_LABEL_FILE;
Log.i(TAG, "Reading labels from: " + model + "/" + labelFilename);
try {
labels = new JSONObject(new String(getBytesFromFile(assetManager, model + "/" + labelFilename)));
} catch (IOException | JSONException e) {
Log.e(TAG, "Problem reading labels name file!", e);
return -1;//failure
}
// load json graph
String modelGraph;
String graphFilename = MODEL_GRAPH_FILE;
Log.i(TAG, "Reading json graph from: " + model + "/" + graphFilename);
try {
modelGraph = new String(getBytesFromFile(assetManager, model + "/" + graphFilename));
} catch (IOException e) {
Log.e(TAG, "Problem reading json graph file!", e);
return -1;//failure
}
// upload tvm compiled function on application cache folder
String libCacheFilePath;
String libFilename = EXE_GPU ? MODEL_CL_LIB_FILE : MODEL_CPU_LIB_FILE;
Log.i(TAG, "Uploading compiled function to cache folder");
try {
libCacheFilePath = getTempLibFilePath(libFilename);
byte[] modelLibByte = getBytesFromFile(assetManager, model + "/" + libFilename);
FileOutputStream fos = new FileOutputStream(libCacheFilePath);
fos.write(modelLibByte);
fos.close();
} catch (IOException e) {
Log.e(TAG, "Problem uploading compiled function!", e);
return -1;//failure
}
// load parameters
byte[] modelParams;
try {
modelParams = getBytesFromFile(assetManager, model + "/" + MODEL_PARAM_FILE);
} catch (IOException e) {
Log.e(TAG, "Problem reading params file!", e);
return -1;//failure
}
Log.i(TAG, "creating java tvm context...");
// create java tvm context
TVMContext tvmCtx = EXE_GPU ? TVMContext.opencl() : TVMContext.cpu();
Log.i(TAG, "loading compiled functions...");
Log.i(TAG, libCacheFilePath);
// tvm module for compiled functions
Module modelLib = Module.load(libCacheFilePath);
// get global function module for graph runtime
Log.i(TAG, "getting graph runtime create handle...");
Function runtimeCreFun = Function.getFunction("tvm.graph_runtime.create");
Log.i(TAG, "creating graph runtime...");
Log.i(TAG, "ctx type: " + tvmCtx.deviceType);
Log.i(TAG, "ctx id: " + tvmCtx.deviceId);
TVMValue runtimeCreFunRes = runtimeCreFun.pushArg(modelGraph)
.pushArg(modelLib)
.pushArg(tvmCtx.deviceType)
.pushArg(tvmCtx.deviceId)
.invoke();
Log.i(TAG, "as module...");
graphRuntimeModule = runtimeCreFunRes.asModule();
Log.i(TAG, "getting graph runtime load params handle...");
// get the function from the module(load parameters)
Function loadParamFunc = graphRuntimeModule.getFunction("load_params");
Log.i(TAG, "loading params...");
loadParamFunc.pushArg(modelParams).invoke();
// release tvm local variables
modelLib.release();
loadParamFunc.release();
runtimeCreFun.release();
mCurModel = model;
mRunClassifier = true;
return 0;//success
}
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
package org.apache.tvm.android.androidcamerademo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
public class MainActivity extends AppCompatActivity implements
ActivityCompat.OnRequestPermissionsResultCallback {
private static final int PERMISSIONS_REQUEST_CODE = 1;
private String[] getRequiredPermissions() {
try {
PackageInfo info = getPackageManager()
.getPackageInfo(getPackageName(), PackageManager.GET_PERMISSIONS);
String[] ps = info.requestedPermissions;
if (ps != null && ps.length > 0) {
return ps;
} else {
return new String[0];
}
} catch (Exception e) {
return new String[0];
}
}
private boolean allPermissionsGranted() {
for (String permission : getRequiredPermissions()) {
if (ContextCompat.checkSelfPermission(this, permission)
!= PackageManager.PERMISSION_GRANTED) {
return false;
}
}
return true;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (!allPermissionsGranted()) {
requestPermissions(getRequiredPermissions(), PERMISSIONS_REQUEST_CODE);
return;
}
startFragment();
}
private void startFragment() {
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.container, Camera2BasicFragment.newInstance())
.commit();
}
@Override
public void onRequestPermissionsResult(
int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (allPermissionsGranted()) {
startFragment();
} else {
Toast.makeText(this, "Required permissions are not granted. App may not run", Toast.LENGTH_SHORT).show();
finish();
}
}
}
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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.
LOCAL_PATH := $(call my-dir)
MY_PATH := $(LOCAL_PATH)
include $(CLEAR_VARS)
LOCAL_PATH := $(MY_PATH)
ROOT_PATH := $(MY_PATH)/../../../../../..
ifndef config
ifneq ("$(wildcard ./config.mk)","")
config ?= config.mk
else
config ?= make/config.mk
endif
endif
include $(config)
LOCAL_SRC_FILES := org_apache_tvm_native_c_api.cc
LOCAL_LDFLAGS := -L$(SYSROOT)/usr/lib/ -llog
LOCAL_C_INCLUDES := $(ROOT_PATH)/include \
$(ROOT_PATH)/3rdparty/dlpack/include \
$(ROOT_PATH)/3rdparty/dmlc-core/include \
$(ROOT_PATH)/3rdparty/HalideIR/src \
$(ROOT_PATH)/topi/include
LOCAL_MODULE = tvm4j_runtime_packed
LOCAL_CPP_FEATURES += exceptions
LOCAL_LDLIBS += -latomic
LOCAL_ARM_MODE := arm
ifdef ADD_C_INCLUDES
LOCAL_C_INCLUDES += $(ADD_C_INCLUDES)
endif
ifdef ADD_LDLIBS
LOCAL_LDLIBS += $(ADD_LDLIBS)
endif
include $(BUILD_SHARED_LIBRARY)
\ No newline at end of file
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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.
ifndef config
ifneq ("$(wildcard ./config.mk)","")
config ?= config.mk
else
config ?= make/config.mk
endif
endif
include $(config)
# We target every architecture except armeabi here, for two reasons:
# 1) armeabi is deprecated in NDK r16 and removed in r17
# 2) vulkan is not supported in armeabi
APP_ABI ?= all
APP_STL := c++_shared
APP_CPPFLAGS += -DDMLC_LOG_STACK_TRACE=0 -DTVM4J_ANDROID=1 -std=c++11 -Oz -frtti
ifeq ($(USE_OPENCL), 1)
APP_CPPFLAGS += -DTVM_OPENCL_RUNTIME=1
endif
ifeq ($(USE_VULKAN), 1)
APP_CPPFLAGS += -DTVM_VULKAN_RUNTIME=1
APP_LDFLAGS += -lvulkan
endif
ifeq ($(USE_SORT), 1)
APP_CPPFLAGS += -DUSE_SORT=1
endif
\ No newline at end of file
#!/bin/bash
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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.
set -x
PATH="$PATH:/usr/local/bin"
CURR_DIR=$(cd `dirname $0`; pwd)
ROOT_DIR="$CURR_DIR/../../../../../.."
javah -o $CURR_DIR/org_apache_tvm_native_c_api.h -cp "$ROOT_DIR/jvm/core/target/*" org.apache.tvm.LibInfo || exit -1
cp -f $ROOT_DIR/jvm/native/src/main/native/org_apache_tvm_native_c_api.cc $CURR_DIR/ || exit -1
cp -f $ROOT_DIR/jvm/native/src/main/native/jni_helper_func.h $CURR_DIR/ || exit -1
rm -rf $CURR_DIR/../libs
ndk-build --directory=$CURR_DIR
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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.
#-------------------------------------------------------------------------------
# Template configuration for compiling
#
# If you want to change the configuration, please use the following
# steps. Assume you are on the root directory. First copy the this
# file so that any local changes will be ignored by git
#
# cp make/config.mk .
#
# Next modify the according entries, and then compile by
#
# ./build.sh
#
#-------------------------------------------------------------------------------
APP_ABI = all
APP_PLATFORM = android-24
# whether enable OpenCL during compile
USE_OPENCL = 0
# whether to enable Vulkan during compile
USE_VULKAN = 0
# whether to enable contrib sort functions during compile
USE_SORT = 1
ifeq ($(USE_VULKAN), 1)
# Statically linking vulkan requires API Level 24 or higher
APP_PLATFORM = android-24
endif
# the additional include headers you want to add, e.g., SDK_PATH/adrenosdk/Development/Inc
ADD_C_INCLUDES =
# the additional link libs you want to add, e.g., ANDROID_LIB_PATH/libOpenCL.so
ADD_LDLIBS =
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
/*!
* \file tvm_runtime.h
* \brief Pack all tvm runtime source files
*/
#include <sys/stat.h>
#include <fstream>
/* Enable custom logging - this will cause TVM to pass every log message
* through CustomLogMessage instead of LogMessage. By enabling this, we must
* implement dmlc::CustomLogMessage::Log. We use this to pass TVM log
* messages to Android logcat.
*/
#define DMLC_LOG_CUSTOMIZE 1
/* Ensure that fatal errors are passed to the logger before throwing
* in LogMessageFatal
*/
#define DMLC_LOG_BEFORE_THROW 1
#include "../src/runtime/c_runtime_api.cc"
#include "../src/runtime/cpu_device_api.cc"
#include "../src/runtime/workspace_pool.cc"
#include "../src/runtime/library_module.cc"
#include "../src/runtime/system_library.cc"
#include "../src/runtime/module.cc"
#include "../src/runtime/registry.cc"
#include "../src/runtime/file_util.cc"
#include "../src/runtime/dso_library.cc"
#include "../src/runtime/rpc/rpc_session.cc"
#include "../src/runtime/rpc/rpc_event_impl.cc"
#include "../src/runtime/rpc/rpc_server_env.cc"
#include "../src/runtime/rpc/rpc_module.cc"
#include "../src/runtime/rpc/rpc_socket_impl.cc"
#include "../src/runtime/thread_pool.cc"
#include "../src/runtime/threading_backend.cc"
#include "../src/runtime/graph/graph_runtime.cc"
#include "../src/runtime/ndarray.cc"
#include "../src/runtime/object.cc"
#ifdef TVM_OPENCL_RUNTIME
#include "../src/runtime/opencl/opencl_device_api.cc"
#include "../src/runtime/opencl/opencl_module.cc"
#endif
#ifdef TVM_VULKAN_RUNTIME
#include "../src/runtime/vulkan/vulkan.cc"
#endif
#ifdef USE_SORT
#include "../src/runtime/contrib/sort/sort.cc"
#endif
#include <android/log.h>
void dmlc::CustomLogMessage::Log(const std::string& msg) {
// This is called for every message logged by TVM.
// We pass the message to logcat.
__android_log_write(ANDROID_LOG_DEBUG, "TVM_RUNTIME", msg.c_str());
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?><!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You 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.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- pressed -->
<item android:drawable="@color/colorPrimaryDark" android:state_pressed="true" />
<!-- focused -->
<item android:drawable="@color/colorAccent" android:state_activated="true" />
<!-- default -->
<item android:drawable="@color/colorPrimary" />
</selector>
<?xml version="1.0" encoding="utf-8"?><!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You 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.
-->
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#000"
tools:context="org.apache.tvm.android.androidcamerademo.MainActivity" />
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?><!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You 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.
-->
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<androidx.camera.view.PreviewView
android:id="@+id/textureView"
android:layout_width="0dp"
android:layout_height="0dp"
android:gravity="center"
app:layout_constraintBottom_toTopOf="@id/resultTextView"
app:layout_constraintDimensionRatio="H,1:1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/resultTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:shadowColor="#000000"
android:shadowDx="2"
android:shadowDy="2"
android:shadowRadius="2"
android:textColor="#ffffff"
android:textSize="24sp"
app:layout_constraintBottom_toTopOf="@id/infoTextView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textureView" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/infoTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:shadowColor="#000000"
android:shadowDx="1"
android:shadowDy="1"
android:shadowRadius="1"
android:textColor="#ffffff"
android:textSize="16sp"
app:layout_constraintBottom_toTopOf="@+id/modelListView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/resultTextView" />
<ListView
android:id="@+id/modelListView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/infoTextView"
app:layout_constraintVertical_bias="1.0" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
<?xml version="1.0" encoding="utf-8"?><!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You 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.
-->
<androidx.appcompat.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/listview_row_text"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginRight="2dp"
android:background="@drawable/item_selector"
android:padding="10dp"
android:textSize="18sp"
android:textStyle="bold" />
</androidx.appcompat.widget.LinearLayoutCompat>
<?xml version="1.0" encoding="utf-8"?><!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You 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.
-->
<resources>
<color name="colorPrimary">#DA6A84</color>
<color name="colorPrimaryDark">#F6F6F6</color>
<color name="colorAccent">#72BF3A</color>
</resources>
<?xml version="1.0" encoding="utf-8"?><!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You 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.
-->
<resources>
<string name="app_name">TVM Android Demo</string>
</resources>
<?xml version="1.0" encoding="utf-8"?><!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You 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.
-->
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
<style name="AppTheme.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
</style>
</resources>
<?xml version="1.0" encoding="utf-8"?><!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You 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.
-->
<paths>
<external-path
name="external_files"
path="." />
</paths>
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
// Source: https://stackoverflow.com/questions/36212904/yuv-420-888-interpretation-on-samsung-galaxy-s7-camera2
#pragma version(1)
#pragma rs java_package_name(org.apache.tvm.android.androidcamerademo);
#pragma rs_fp_relaxed
int32_t width;
int32_t height;
uint picWidth, uvPixelStride, uvRowStride ;
rs_allocation ypsIn,uIn,vIn;
// The LaunchOptions ensure that the Kernel does not enter the padding zone of Y, so yRowStride can be ignored WITHIN the Kernel.
uchar4 __attribute__((kernel)) doConvert(uint32_t x, uint32_t y) {
// index for accessing the uIn's and vIn's
uint uvIndex= uvPixelStride * (x/2) + uvRowStride*(y/2);
// get the y,u,v values
uchar yps= rsGetElementAt_uchar(ypsIn, x, y);
uchar u= rsGetElementAt_uchar(uIn, uvIndex);
uchar v= rsGetElementAt_uchar(vIn, uvIndex);
// calc argb
int4 argb;
argb.r = yps + v * 1436 / 1024 - 179;
argb.g = yps -u * 46549 / 131072 + 44 -v * 93604 / 131072 + 91;
argb.b = yps +u * 1814 / 1024 - 227;
argb.a = 255;
uchar4 out = convert_uchar4(clamp(argb, 0, 255));
return out;
}
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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.
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
jcenter()
maven {
url 'https://maven.google.com'
}
google()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.6.1'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
jcenter()
maven {
url 'https://maven.google.com'
}
mavenLocal()
mavenCentral()
google()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
\ No newline at end of file
#!/bin/bash
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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.
CURR_DIR=$(cd `dirname $0`; pwd)
keytool -genkey -keystore $CURR_DIR/tvmdemo.keystore -alias tvmdemo -keyalg RSA -validity 10000
#!/bin/bash
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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.
CURR_DIR=$(cd `dirname $0`; pwd)
APK_DIR=$CURR_DIR/../app/build/outputs/apk/release
UNSIGNED_APK=$APK_DIR/app-release-unsigned.apk
SIGNED_APK=$APK_DIR/tv8mdemo-release.apk
jarsigner -verbose -keystore $CURR_DIR/tv8mdemo.keystore -signedjar $SIGNED_APK $UNSIGNED_APK 'tv8mdemo'
echo $SIGNED_APK
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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.
org.gradle.jvmargs=-Xmx4608M
android.useAndroidX=true
android.enableJetifier=true
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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.
import logging
import pathlib
from pathlib import Path
from typing import Union
import os
from os import environ
import json
import tvm
import tvm.relay as relay
from tvm.contrib import util, ndk, graph_runtime as runtime
from tvm.contrib.download import download_testdata, download
target = 'llvm -target=arm64-linux-android'
target_host = None
def del_dir(target: Union[Path, str], only_if_empty: bool = False):
target = Path(target).expanduser()
assert target.is_dir()
for p in sorted(target.glob('**/*'), reverse=True):
if not p.exists():
continue
p.chmod(0o666)
if p.is_dir():
p.rmdir()
else:
if only_if_empty:
raise RuntimeError(f'{p.parent} is not empty!')
p.unlink()
target.rmdir()
def get_model(model_name, batch_size=1):
if model_name == 'resnet18_v1':
import mxnet as mx
from mxnet import gluon
from mxnet.gluon.model_zoo import vision
gluon_model = vision.get_model(model_name, pretrained=True)
img_size = 224
data_shape = (batch_size, 3, img_size, img_size)
net, params = relay.frontend.from_mxnet(gluon_model, {"data": data_shape})
return (net, params)
elif model_name == 'mobilenet_v2':
import keras
from keras.applications.mobilenet_v2 import MobileNetV2
keras.backend.clear_session() # Destroys the current TF graph and creates a new one.
weights_url = ''.join(['https://github.com/JonathanCMitchell/',
'mobilenet_v2_keras/releases/download/v1.1/',
'mobilenet_v2_weights_tf_dim_ordering_tf_kernels_0.5_224.h5'])
weights_file = 'mobilenet_v2_weights.h5'
weights_path = download_testdata(weights_url, weights_file, module='keras')
keras_mobilenet_v2 = MobileNetV2(alpha=0.5, include_top=True, weights=None,
input_shape=(224, 224, 3), classes=1000)
keras_mobilenet_v2.load_weights(weights_path)
img_size = 224
data_shape = (batch_size, 3, img_size, img_size)
mod, params = relay.frontend.from_keras(keras_mobilenet_v2, {'input_1': data_shape})
return (mod, params)
def main(model_str, output_path):
if output_path.exists():
del_dir(output_path)
output_path.mkdir()
output_path_str = os.fspath(output_path)
print(model_str)
print("getting model...")
net, params = get_model(model_str)
try:
os.mkdir(model_str)
except FileExistsError:
pass
print("building...")
with relay.build_config(opt_level=3):
graph, lib, params = relay.build(net, target, target_host=target_host, params=params)
print("dumping lib...")
lib.export_library(output_path_str + '/' + 'deploy_lib_cpu.so', ndk.create_shared)
print("dumping graph...")
with open(output_path_str + '/' + 'deploy_graph.json', 'w') as f:
f.write(graph)
print("dumping params...")
with open(output_path_str + '/' + 'deploy_param.params', 'wb') as f:
f.write(relay.save_param_dict(params))
print("dumping labels...")
synset_url = ''.join(['https://gist.githubusercontent.com/zhreshold/',
'4d0b62f3d01426887599d4f7ede23ee5/raw/',
'596b27d23537e5a1b5751d2b0481ef172f58b539/',
'imagenet1000_clsid_to_human.txt'])
synset_path = output_path_str + '/image_net_labels'
download(synset_url, output_path_str + '/image_net_labels')
with open(synset_path) as fi:
synset = eval(fi.read())
with open(output_path_str + '/image_net_labels.json', "w") as fo:
json.dump(synset, fo, indent=4)
os.remove(synset_path)
if __name__ == '__main__':
if environ.get('TVM_NDK_CC') is None:
raise RuntimeError("Require environment variable TVM_NDK_CC")
models_path = Path().absolute().parent.joinpath('app/src/main/assets/models/')
if not models_path.exists():
models_path.mkdir()
models = {'mobilenet_v2': models_path.joinpath('mobilenet_v2'),
'resnet18_v1': models_path.joinpath('resnet18_v1')
}
for model, output_path in models.items():
main(model, output_path)
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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.
include ':app'
......@@ -177,7 +177,6 @@ def add_header(fname, header):
print("Skip file %s ..." % fname)
return
with open(fname, "w") as outfile:
skipline = False
ext = os.path.splitext(fname)[1][1:]
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment