Commit 0f343bbb authored by Oleg Dzhimiev's avatar Oleg Dzhimiev

store my changes

parent b234dbef
This diff is collapsed.
This diff is collapsed.
/* 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.
==============================================================================*/
package org.tensorflow;
/** Static utility methods describing the TensorFlow runtime. */
public final class TensorFlow {
/** Returns the version of the underlying TensorFlow runtime. */
public static native String version();
/** Returns the version of the underlying TensorFlow runtime. */
public static native String elphelVersion();
/**
* All the TensorFlow operations available in this address space.
*
* @return A serialized representation of an <a
* href="https://www.tensorflow.org/code/tensorflow/core/framework/op_def.proto">OpList</a>
* protocol buffer, which lists all the available TensorFlow operations.
*/
public static native byte[] registeredOpList();
/**
* Load the dynamic library in filename and register the operations and kernels present in that
* library.
*
* @param filename Path of the dynamic library containing operations and kernels to load.
* @return Serialized bytes of the <a
* href="https://www.tensorflow.org/code/tensorflow/core/framework/op_def.proto">OpList</a>
* protocol buffer message defining the operations defined in the library.
* @throws UnsatisfiedLinkError if filename cannot be loaded.
*/
public static byte[] loadLibrary(String filename) {
long h = 0;
try {
h = libraryLoad(filename);
} catch (RuntimeException e) {
throw new UnsatisfiedLinkError(e.getMessage());
}
try {
return libraryOpList(h);
} finally {
libraryDelete(h);
}
}
private static native long libraryLoad(String filename);
private static native void libraryDelete(long handle);
private static native byte[] libraryOpList(long handle);
private TensorFlow() {}
/** Load the TensorFlow runtime C library. */
static void init() {
try {
NativeLibrary.load();
} catch (Exception e) {
/*
* This code is called during static initialization of this and of other classes.
* If this fails then a NoClassDefFoundError is thrown however this does not
* include a cause. Printing the exception manually here ensures that the
* necessary information to fix the problem is available.
*/
System.err.println("Failed to load TensorFlow native library");
e.printStackTrace();
throw e;
}
}
static {
init();
}
}
/* 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.
==============================================================================*/
#include <string.h>
#include <memory>
#include "tensorflow/c/c_api.h"
#include "tensorflow/c/c_api_internal.h"
#include "tensorflow/java/src/main/native/utils_jni.h"
#include "tensorflow/java/src/main/native/exception_jni.h"
#include "tensorflow/java/src/main/native/session_jni.h"
#include "tensorflow/core/common_runtime/direct_session.h"
//#include "tensorflow/cc/client/client_session.h"
#include "cuda_runtime_api.h"
namespace {
TF_Session* requireHandle(JNIEnv* env, jlong handle) {
static_assert(sizeof(jlong) >= sizeof(TF_Session*),
"Cannot package C object pointers as a Java long");
if (handle == 0) {
throwException(env, kNullPointerException,
"close() has been called on the Session");
return nullptr;
}
return reinterpret_cast<TF_Session*>(handle);
}
template <class T>
void resolveHandles(JNIEnv* env, const char* type, jlongArray src_array,
T** dst, jint n) {
if (env->ExceptionCheck()) return;
jint len = env->GetArrayLength(src_array);
if (len != n) {
throwException(env, kIllegalArgumentException, "expected %d, got %d %s", n,
len, type);
return;
}
jlong* src_start = env->GetLongArrayElements(src_array, nullptr);
jlong* src = src_start;
for (int i = 0; i < n; ++i, ++src, ++dst) {
if (*src == 0) {
throwException(env, kNullPointerException, "invalid %s (#%d of %d)", type,
i, n);
break;
}
*dst = reinterpret_cast<T*>(*src);
}
env->ReleaseLongArrayElements(src_array, src_start, JNI_ABORT);
}
void TF_MaybeDeleteBuffer(TF_Buffer* buf) {
if (buf == nullptr) return;
TF_DeleteBuffer(buf);
}
typedef std::unique_ptr<TF_Buffer, decltype(&TF_MaybeDeleteBuffer)>
unique_tf_buffer;
unique_tf_buffer MakeUniqueBuffer(TF_Buffer* buf) {
return unique_tf_buffer(buf, TF_MaybeDeleteBuffer);
}
} // namespace
JNIEXPORT jlong JNICALL Java_org_tensorflow_Session_allocate(
JNIEnv* env, jclass clazz, jlong graph_handle) {
return Java_org_tensorflow_Session_allocate2(env, clazz, graph_handle,
nullptr, nullptr);
}
JNIEXPORT jlong JNICALL Java_org_tensorflow_Session_allocate2(
JNIEnv* env, jclass clazz, jlong graph_handle, jstring target,
jbyteArray config) {
if (graph_handle == 0) {
throwException(env, kNullPointerException, "Graph has been close()d");
return 0;
}
TF_Graph* graph = reinterpret_cast<TF_Graph*>(graph_handle);
TF_Status* status = TF_NewStatus();
TF_SessionOptions* opts = TF_NewSessionOptions();
jbyte* cconfig = nullptr;
if (config != nullptr) {
cconfig = env->GetByteArrayElements(config, nullptr);
TF_SetConfig(opts, cconfig,
static_cast<size_t>(env->GetArrayLength(config)), status);
if (!throwExceptionIfNotOK(env, status)) {
env->ReleaseByteArrayElements(config, cconfig, JNI_ABORT);
TF_DeleteSessionOptions(opts);
TF_DeleteStatus(status);
return 0;
}
}
const char* ctarget = nullptr;
if (target != nullptr) {
ctarget = env->GetStringUTFChars(target, nullptr);
}
TF_Session* session = TF_NewSession(graph, opts, status);
if (config != nullptr) {
env->ReleaseByteArrayElements(config, cconfig, JNI_ABORT);
}
if (target != nullptr) {
env->ReleaseStringUTFChars(target, ctarget);
}
TF_DeleteSessionOptions(opts);
bool ok = throwExceptionIfNotOK(env, status);
TF_DeleteStatus(status);
return ok ? reinterpret_cast<jlong>(session) : 0;
}
JNIEXPORT void JNICALL Java_org_tensorflow_Session_delete(JNIEnv* env,
jclass clazz,
jlong handle) {
TF_Session* session = requireHandle(env, handle);
if (session == nullptr) return;
TF_Status* status = TF_NewStatus();
TF_CloseSession(session, status);
// Result of close is ignored, delete anyway.
TF_DeleteSession(session, status);
throwExceptionIfNotOK(env, status);
TF_DeleteStatus(status);
}
JNIEXPORT jbyteArray JNICALL Java_org_tensorflow_Session_run(
JNIEnv* env, jclass clazz, jlong handle, jbyteArray jrun_options,
jlongArray input_tensor_handles, jlongArray input_op_handles,
jintArray input_op_indices, jlongArray output_op_handles,
jintArray output_op_indices, jlongArray target_op_handles,
jboolean want_run_metadata, jlongArray output_tensor_handles) {
TF_Session* session = requireHandle(env, handle);
if (session == nullptr) return nullptr;
const jint ninputs = env->GetArrayLength(input_tensor_handles);
const jint noutputs = env->GetArrayLength(output_tensor_handles);
const jint ntargets = env->GetArrayLength(target_op_handles);
std::unique_ptr<TF_Output[]> inputs(new TF_Output[ninputs]);
std::unique_ptr<TF_Tensor* []> input_values(new TF_Tensor*[ninputs]);
std::unique_ptr<TF_Output[]> outputs(new TF_Output[noutputs]);
std::unique_ptr<TF_Tensor* []> output_values(new TF_Tensor*[noutputs]);
std::unique_ptr<TF_Operation* []> targets(new TF_Operation*[ntargets]);
unique_tf_buffer run_metadata(
MakeUniqueBuffer(want_run_metadata ? TF_NewBuffer() : nullptr));
resolveHandles(env, "input Tensors", input_tensor_handles, input_values.get(),
ninputs);
resolveOutputs(env, "input", input_op_handles, input_op_indices, inputs.get(),
ninputs);
resolveOutputs(env, "output", output_op_handles, output_op_indices,
outputs.get(), noutputs);
resolveHandles(env, "target Operations", target_op_handles, targets.get(),
ntargets);
if (env->ExceptionCheck()) return nullptr;
TF_Status* status = TF_NewStatus();
unique_tf_buffer run_options(MakeUniqueBuffer(nullptr));
jbyte* jrun_options_data = nullptr;
if (jrun_options != nullptr) {
size_t sz = env->GetArrayLength(jrun_options);
if (sz > 0) {
jrun_options_data = env->GetByteArrayElements(jrun_options, nullptr);
run_options.reset(
TF_NewBufferFromString(static_cast<void*>(jrun_options_data), sz));
}
}
TF_SessionRun(session, run_options.get(), inputs.get(), input_values.get(),
static_cast<int>(ninputs), outputs.get(), output_values.get(),
static_cast<int>(noutputs), targets.get(),
static_cast<int>(ntargets), run_metadata.get(), status);
if (jrun_options_data != nullptr) {
env->ReleaseByteArrayElements(jrun_options, jrun_options_data, JNI_ABORT);
}
if (!throwExceptionIfNotOK(env, status)) {
TF_DeleteStatus(status);
return nullptr;
}
jlong* t = env->GetLongArrayElements(output_tensor_handles, nullptr);
for (int i = 0; i < noutputs; ++i) {
t[i] = reinterpret_cast<jlong>(output_values[i]);
}
env->ReleaseLongArrayElements(output_tensor_handles, t, 0);
jbyteArray ret = nullptr;
if (run_metadata != nullptr) {
ret = env->NewByteArray(run_metadata->length);
env->SetByteArrayRegion(ret, 0, run_metadata->length,
reinterpret_cast<const jbyte*>(run_metadata->data));
}
TF_DeleteStatus(status);
return ret;
}
JNIEXPORT jstring JNICALL Java_org_tensorflow_Session_elphelGetGPUDeviceName(JNIEnv* env,
jclass clazz,
jlong handle) {
TF_Session* session = requireHandle(env, handle);
if (session == nullptr) return env->NewStringUTF("");
using namespace tensorflow;
std::vector<DeviceAttributes> devices;
TF_CHECK_OK(session->session->ListDevices(&devices));
for (const DeviceAttributes& d : devices) {
LOG(INFO) << "Device: " << d.name();
if (d.device_type() == "GPU" || d.device_type() == "gpu") {
return env->NewStringUTF(d.name().c_str());
}
}
return env->NewStringUTF("");
}
/* 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.
==============================================================================*/
#ifndef TENSORFLOW_JAVA_SRC_MAIN_NATIVE_SESSION_JNI_H_
#define TENSORFLOW_JAVA_SRC_MAIN_NATIVE_SESSION_JNI_H_
#include <jni.h>
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: org_tensorflow_Session
* Method: allocate
* Signature: (J)J
*/
JNIEXPORT jlong JNICALL Java_org_tensorflow_Session_allocate(JNIEnv *, jclass,
jlong);
/*
* Class: org_tensorflow_Session
* Method: allocate2
* Signature: (JLjava/lang/String;[B)J
*/
JNIEXPORT jlong JNICALL Java_org_tensorflow_Session_allocate2(JNIEnv *, jclass,
jlong, jstring,
jbyteArray);
/*
* Class: org_tensorflow_Session
* Method: delete
* Signature: (J)V
*/
JNIEXPORT void JNICALL Java_org_tensorflow_Session_delete(JNIEnv *, jclass,
jlong);
/*
* Class: org_tensorflow_Session
* Method: run
* Signature: (J[B[J[J[I[J[I[JZ[J)[B
*/
JNIEXPORT jbyteArray JNICALL Java_org_tensorflow_Session_run(
JNIEnv *, jclass, jlong, jbyteArray, jlongArray, jlongArray, jintArray,
jlongArray, jintArray, jlongArray, jboolean, jlongArray);
JNIEXPORT jstring JNICALL Java_org_tensorflow_Session_elphelGetGPUDeviceName(
JNIEnv* env, jclass clazz, jlong handle);
#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus
#endif // TENSORFLOW_JAVA_SRC_MAIN_NATIVE_SESSION_JNI_H_
This diff is collapsed.
/* 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.
==============================================================================*/
#ifndef TENSORFLOW_JAVA_SRC_MAIN_NATIVE_TENSOR_JNI_H_
#define TENSORFLOW_JAVA_SRC_MAIN_NATIVE_TENSOR_JNI_H_
#include <jni.h>
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: org_tensorflow_Tensor
* Method: allocate
* Signature: (I[JJ)J
*/
JNIEXPORT jlong JNICALL Java_org_tensorflow_Tensor_allocate(JNIEnv *, jclass,
jint, jlongArray,
jlong);
JNIEXPORT jlong JNICALL Java_org_tensorflow_Tensor_elphelAllocateGPUTensor(JNIEnv *, jclass,
jlongArray, jint);
JNIEXPORT jlong JNICALL Java_org_tensorflow_Tensor_elphelGetGPUTensorPointer(JNIEnv*, jclass,
jlong);
/*
* Class: org_tensorflow_Tensor
* Method: allocateScalarBytes
* Signature: ([B)J
*/
JNIEXPORT jlong JNICALL
Java_org_tensorflow_Tensor_allocateScalarBytes(JNIEnv *, jclass, jbyteArray);
/*
* Class: org_tensorflow_Tensor
* Method: allocateNonScalarBytes
* Signature: ([J[Ljava/lang/Object;)J
*/
JNIEXPORT jlong JNICALL Java_org_tensorflow_Tensor_allocateNonScalarBytes(
JNIEnv *, jclass, jlongArray, jobjectArray);
/*
* Class: org_tensorflow_Tensor
* Method: delete
* Signature: (J)V
*/
JNIEXPORT void JNICALL Java_org_tensorflow_Tensor_delete(JNIEnv *, jclass,
jlong);
/*
* Class: org_tensorflow_Tensor
* Method: buffer
* Signature: (J)Ljava/nio/ByteBuffer;
*/
JNIEXPORT jobject JNICALL Java_org_tensorflow_Tensor_buffer(JNIEnv *, jclass,
jlong);
/*
* Class: org_tensorflow_Tensor
* Method: dtype
* Signature: (J)I
*/
JNIEXPORT jint JNICALL Java_org_tensorflow_Tensor_dtype(JNIEnv *, jclass,
jlong);
/*
* Class: org_tensorflow_Tensor
* Method: shape
* Signature: (J)[J
*/
JNIEXPORT jlongArray JNICALL Java_org_tensorflow_Tensor_shape(JNIEnv *, jclass,
jlong);
/*
* Class: org_tensorflow_Tensor
* Method: setValue
* Signature: (JLjava/lang/Object;)V
*
* REQUIRES: The jobject's type and shape are compatible the with the DataType
* and shape of the Tensor referred to by the jlong handle.
*/
JNIEXPORT void JNICALL Java_org_tensorflow_Tensor_setValue(JNIEnv *, jclass,
jlong, jobject);
/*
* Class: org_tensorflow_Tensor
* Method: scalarFloat
* Signature: (J)F
*
*/
JNIEXPORT jfloat JNICALL Java_org_tensorflow_Tensor_scalarFloat(JNIEnv *,
jclass, jlong);
/*
* Class: org_tensorflow_Tensor
* Method: scalarDouble
* Signature: (J)D
*/
JNIEXPORT jdouble JNICALL Java_org_tensorflow_Tensor_scalarDouble(JNIEnv *,
jclass,
jlong);
/*
* Class: org_tensorflow_Tensor
* Method: scalarInt
* Signature: (J)I
*/
JNIEXPORT jint JNICALL Java_org_tensorflow_Tensor_scalarInt(JNIEnv *, jclass,
jlong);
/*
* Class: org_tensorflow_Tensor
* Method: scalarLong
* Signature: (J)J
*/
JNIEXPORT jlong JNICALL Java_org_tensorflow_Tensor_scalarLong(JNIEnv *, jclass,
jlong);
/*
* Class: org_tensorflow_Tensor
* Method: scalarBoolean
* Signature: (J)Z
*/
JNIEXPORT jboolean JNICALL Java_org_tensorflow_Tensor_scalarBoolean(JNIEnv *,
jclass,
jlong);
/*
* Class: org_tensorflow_Tensor
* Method: scalarBytes
* Signature: (J)[B
*/
JNIEXPORT jbyteArray JNICALL Java_org_tensorflow_Tensor_scalarBytes(JNIEnv *,
jclass,
jlong);
/*
* Class: org_tensorflow_Tensor
* Method: readNDArray
* Signature: (JLjava/lang/Object;)V
*/
JNIEXPORT void JNICALL Java_org_tensorflow_Tensor_readNDArray(JNIEnv *, jclass,
jlong, jobject);
JNIEXPORT int JNICALL Java_org_tensorflow_Tensor_elphelIsCUDATensor(JNIEnv *,
jclass,
jlong);
JNIEXPORT int JNICALL Java_org_tensorflow_Tensor_elphelTestCUDAPointer(JNIEnv *,
jclass);
#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus
#endif // TENSORFLOW_JAVA_SRC_MAIN_NATIVE_TENSOR_JNI_H_
/* 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.
==============================================================================*/
#include "tensorflow/java/src/main/native/tensorflow_jni.h"
#include <limits>
#include "tensorflow/c/c_api.h"
#include "tensorflow/java/src/main/native/exception_jni.h"
JNIEXPORT jstring JNICALL Java_org_tensorflow_TensorFlow_version(JNIEnv* env,
jclass clazz) {
return env->NewStringUTF(TF_Version());
}
JNIEXPORT jstring JNICALL Java_org_tensorflow_TensorFlow_elphelVersion(JNIEnv* env,
jclass clazz) {
return env->NewStringUTF("Elphel TensorFlow JNI call 1.0");
}
JNIEXPORT jbyteArray JNICALL
Java_org_tensorflow_TensorFlow_registeredOpList(JNIEnv* env, jclass clazz) {
TF_Buffer* buf = TF_GetAllOpList();
jint length = static_cast<int>(buf->length);
jbyteArray ret = env->NewByteArray(length);
env->SetByteArrayRegion(ret, 0, length, static_cast<const jbyte*>(buf->data));
TF_DeleteBuffer(buf);
return ret;
}
JNIEXPORT jlong JNICALL Java_org_tensorflow_TensorFlow_libraryLoad(
JNIEnv* env, jclass clazz, jstring filename) {
TF_Status* status = TF_NewStatus();
const char* cname = env->GetStringUTFChars(filename, nullptr);
TF_Library* h = TF_LoadLibrary(cname, status);
throwExceptionIfNotOK(env, status);
env->ReleaseStringUTFChars(filename, cname);
TF_DeleteStatus(status);
return reinterpret_cast<jlong>(h);
}
JNIEXPORT void JNICALL Java_org_tensorflow_TensorFlow_libraryDelete(
JNIEnv* env, jclass clazz, jlong handle) {
if (handle != 0) {
TF_DeleteLibraryHandle(reinterpret_cast<TF_Library*>(handle));
}
}
JNIEXPORT jbyteArray JNICALL Java_org_tensorflow_TensorFlow_libraryOpList(
JNIEnv* env, jclass clazz, jlong handle) {
TF_Buffer buf = TF_GetOpList(reinterpret_cast<TF_Library*>(handle));
if (buf.length > std::numeric_limits<jint>::max()) {
throwException(env, kIndexOutOfBoundsException,
"Serialized OpList is too large for a byte[] array");
return nullptr;
}
auto ret_len = static_cast<jint>(buf.length);
jbyteArray ret = env->NewByteArray(ret_len);
env->SetByteArrayRegion(ret, 0, ret_len, static_cast<const jbyte*>(buf.data));
return ret;
}
/* 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.
==============================================================================*/
#ifndef TENSORFLOW_JAVA_SRC_MAIN_NATIVE_TENSORFLOW_JNI_H_
#define TENSORFLOW_JAVA_SRC_MAIN_NATIVE_TENSORFLOW_JNI_H_
#include <jni.h>
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
/*
* Class: org_tensorflow_TensorFlow
* Method: version
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_org_tensorflow_TensorFlow_version(JNIEnv *,
jclass);
/*
* Class: org_tensorflow_TensorFlow
* Method: version2
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_org_tensorflow_TensorFlow_elphelVersion(JNIEnv *,
jclass);
/*
* Class: org_tensorflow_TensorFlow
* Method: registeredOpList
* Signature: ()[B
*/
JNIEXPORT jbyteArray JNICALL
Java_org_tensorflow_TensorFlow_registeredOpList(JNIEnv *, jclass);
/*
* Class: org_tensorflow_TensorFlow
* Method: libraryLoad
* Signature: (Ljava/lang/String;)J
*/
JNIEXPORT jlong JNICALL Java_org_tensorflow_TensorFlow_libraryLoad(JNIEnv *,
jclass,
jstring);
/*
* Class: org_tensorflow_TensorFlow
* Method: libraryDelete
* Signature: (J)V
*/
JNIEXPORT void JNICALL Java_org_tensorflow_TensorFlow_libraryDelete(JNIEnv *,
jclass,
jlong);
/*
* Class: org_tensorflow_TensorFlow
* Method: libraryOpList
* Signature: (J)[B
*/
JNIEXPORT jbyteArray JNICALL
Java_org_tensorflow_TensorFlow_libraryOpList(JNIEnv *, jclass, jlong);
#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus
#endif // TENSORFLOW_JAVA_SRC_MAIN_NATIVE_TENSORFLOW_JNI_H_
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