Skip to content

Commit b558e39

Browse files
authored
Merge branch 'main' into add_helper_to_check_valid_extension
2 parents 26d7371 + b80c7f5 commit b558e39

File tree

8 files changed

+267
-17
lines changed

8 files changed

+267
-17
lines changed

java/android/nnstreamer/src/androidTest/assets/README.txt

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@ $ tree .
77
│   ├── config_pipeline_imgclf.conf
88
│   ├── config_pipeline_imgclf_key.conf
99
│   ├── config_single_imgclf.conf
10-
│   └── config_single_imgclf_key.conf
10+
│   ├── config_single_imgclf_key.conf
11+
│   └── config_single_llamacpp_async.conf
12+
├── llamacpp_data
13+
│   └── tinyllama-1.1b-chat-v1.0.Q2_K.gguf
1114
├── pytorch_data
1215
│   ├── mobilenetv2-quant_core-nnapi.pt
1316
│   └── orange_float.raw
@@ -28,3 +31,23 @@ $ tree .
2831
├── orange.png
2932
├── orange.raw
3033
└── test_video.mp4
34+
35+
36+
Configuration example:
37+
The configuration file is a json formatted string for ML-service feature, which describes the configuration to run an inference application with model-agnostic method.
38+
If you implement new Android application with ML-service and need to get a model from application's internal storage, you can set the predefined entity string '@APP_DATA_PATH@'.
39+
Then it will be replaced with the application's data path.
40+
41+
Below is an example of asynchronous inference using LLaMA C++.
42+
43+
config_single_llamacpp_async.conf
44+
{
45+
"single" :
46+
{
47+
"framework" : "llamacpp",
48+
"model" : ["@APP_DATA_PATH@/nnstreamer/llamacpp_data/tinyllama-1.1b-chat-v1.0.Q2_K.gguf"],
49+
"custom" : "num_predict:32",
50+
"invoke_dynamic" : "true",
51+
"invoke_async" : "true"
52+
}
53+
}

java/android/nnstreamer/src/androidTest/java/org/nnsuite/nnstreamer/APITestMLService.java

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1025,4 +1025,55 @@ public void testRunSingleShotRegistered() {
10251025
MLService.Model.delete(name, 0);
10261026
}
10271027
}
1028+
1029+
@Test
1030+
public void testRunAsyncInvoke() {
1031+
if (!NNStreamer.isAvailable(NNStreamer.NNFWType.LLAMACPP)) {
1032+
/* cannot run the test */
1033+
return;
1034+
}
1035+
1036+
String config = APITestCommon.getConfigPath() + "/config_single_llamacpp_async.conf";
1037+
1038+
try {
1039+
MLService.EventListener asyncEventListener = new MLService.EventListener() {
1040+
@Override
1041+
public void onNewDataReceived(String name, TensorsData data) {
1042+
if (data == null || data.getTensorsCount() != 1) {
1043+
mInvalidState = true;
1044+
return;
1045+
}
1046+
1047+
mReceived++;
1048+
}
1049+
};
1050+
1051+
MLService service = new MLService(config, asyncEventListener);
1052+
1053+
service.start();
1054+
1055+
/* push input buffer */
1056+
String inputText = "Hello my name is";
1057+
ByteBuffer buffer = TensorsData.allocateByteBuffer(inputText);
1058+
1059+
TensorsInfo info = service.getInputInformation(null);
1060+
assertEquals(NNStreamer.TensorFormat.FLEXIBLE, info.getFormat());
1061+
1062+
TensorsData input = TensorsData.allocate(info);
1063+
input.setTensorData(0, buffer);
1064+
1065+
service.inputData(null, input);
1066+
1067+
/* sleep 3 seconds to invoke */
1068+
Thread.sleep(3000);
1069+
1070+
/* check received data from output node */
1071+
assertFalse(mInvalidState);
1072+
assertTrue(mReceived > 1);
1073+
1074+
service.close();
1075+
} catch (Exception e) {
1076+
fail();
1077+
}
1078+
}
10281079
}

java/android/nnstreamer/src/androidTest/java/org/nnsuite/nnstreamer/APITestTensorsInfo.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ public void tearDown() {
3030
@Test
3131
public void testAddInfo() {
3232
try {
33+
/* Default format is static. */
34+
assertEquals(NNStreamer.TensorFormat.STATIC, mInfo.getFormat());
35+
3336
mInfo.addTensorInfo("name1", NNStreamer.TensorType.INT8, new int[]{1});
3437
assertEquals(1, mInfo.getTensorsCount());
3538

@@ -251,4 +254,14 @@ public void testAddMaxInfo_n() {
251254
/* expected */
252255
}
253256
}
257+
258+
@Test
259+
public void testInvalidFormat_n() {
260+
try {
261+
new TensorsInfo(NNStreamer.TensorFormat.UNKNOWN);
262+
fail();
263+
} catch (Exception e) {
264+
/* expected */
265+
}
266+
}
254267
}

java/android/nnstreamer/src/main/java/org/nnsuite/nnstreamer/NNStreamer.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,15 @@ public enum TensorType {
118118
/** Unknown data type (usually error) */ UNKNOWN
119119
}
120120

121+
/**
122+
* The enumeration for possible data format of tensor in NNStreamer.
123+
*/
124+
public enum TensorFormat {
125+
/** Static tensor stream */ STATIC,
126+
/** Flexible tensor stream */ FLEXIBLE,
127+
/** Unknown data format (usually error) */ UNKNOWN
128+
}
129+
121130
private static native boolean nativeInitialize(Object app);
122131
private static native boolean nativeCheckNNFWAvailability(int fw);
123132
private static native String nativeGetVersion();

java/android/nnstreamer/src/main/java/org/nnsuite/nnstreamer/TensorsData.java

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ public static TensorsData allocate(TensorsInfo info) {
9090
int count = info.getTensorsCount();
9191

9292
for (int i = 0; i < count; i++) {
93+
/* If tensor format is flexible, data size would be 0. */
9394
data.addTensorData(allocateBuffer(info.getTensorSize(i)));
9495
}
9596

@@ -181,6 +182,15 @@ private Object[] getDataArray() {
181182
return mDataList.toArray();
182183
}
183184

185+
/**
186+
* Internal method called from native to reallocate buffer.
187+
*/
188+
private void updateData(int index, int size) {
189+
checkIndexBounds(index);
190+
191+
mDataList.set(index, allocateByteBuffer(size));
192+
}
193+
184194
/**
185195
* Internal method to check the index.
186196
*
@@ -224,10 +234,15 @@ private void checkByteBuffer(int index, ByteBuffer data) {
224234
throw new IndexOutOfBoundsException("Current information has " + count + " tensors");
225235
}
226236

227-
int size = mInfo.getTensorSize(index);
237+
NNStreamer.TensorFormat format = mInfo.getFormat();
238+
239+
/* The size of input buffer should be matched if data format is static. */
240+
if (format == NNStreamer.TensorFormat.STATIC) {
241+
int size = mInfo.getTensorSize(index);
228242

229-
if (data.capacity() != size) {
230-
throw new IllegalArgumentException("Invalid buffer size, required size is " + size);
243+
if (data.capacity() != size) {
244+
throw new IllegalArgumentException("Invalid buffer size, required size is " + size);
245+
}
231246
}
232247
}
233248
}

java/android/nnstreamer/src/main/java/org/nnsuite/nnstreamer/TensorsInfo.java

Lines changed: 89 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,42 @@
1414
*
1515
* @see NNStreamer#TENSOR_RANK_LIMIT
1616
* @see NNStreamer#TENSOR_SIZE_LIMIT
17+
* @see NNStreamer.TensorFormat
1718
* @see NNStreamer.TensorType
1819
*/
1920
public final class TensorsInfo implements AutoCloseable, Cloneable {
2021
private ArrayList<TensorInfo> mInfoList = new ArrayList<>();
22+
private NNStreamer.TensorFormat mFormat;
23+
24+
/**
25+
* Creates a new {@link TensorsInfo} instance.
26+
* Default tensor format is static.
27+
*/
28+
public TensorsInfo() {
29+
this(NNStreamer.TensorFormat.STATIC);
30+
}
31+
32+
/**
33+
* Creates a new {@link TensorsInfo} instance with given tensor format.
34+
*
35+
* @param format The format of tensors information
36+
*
37+
* @throws IllegalArgumentException if tensor format is invalid
38+
*/
39+
public TensorsInfo(NNStreamer.TensorFormat format) {
40+
if (format == NNStreamer.TensorFormat.UNKNOWN) {
41+
throw new IllegalArgumentException("Given tensor format is invalid");
42+
}
43+
44+
mFormat = format;
45+
}
46+
47+
/**
48+
* Private constructor to convert tensor format value and create a new instance.
49+
*/
50+
private TensorsInfo(int value) {
51+
this(convertFormat(value));
52+
}
2153

2254
/**
2355
* Allocates a new {@link TensorsData} instance with the tensors information.
@@ -41,7 +73,7 @@ public TensorsData allocate() {
4173
*/
4274
@Override
4375
public TensorsInfo clone() {
44-
TensorsInfo cloned = new TensorsInfo();
76+
TensorsInfo cloned = new TensorsInfo(mFormat);
4577

4678
for (TensorInfo info : mInfoList) {
4779
cloned.addTensorInfo(info.getName(), info.getType(), info.getDimension());
@@ -50,6 +82,15 @@ public TensorsInfo clone() {
5082
return cloned;
5183
}
5284

85+
/**
86+
* Gets the format of tensors information.
87+
*
88+
* @return The format of tensors information
89+
*/
90+
public NNStreamer.TensorFormat getFormat() {
91+
return mFormat;
92+
}
93+
5394
/**
5495
* Gets the number of tensors.
5596
* The maximum number of tensors is {@link NNStreamer#TENSOR_SIZE_LIMIT}.
@@ -90,7 +131,7 @@ public void addTensorInfo(String name, NNStreamer.TensorType type, int[] dimensi
90131
throw new IndexOutOfBoundsException("Max number of the tensors is " + NNStreamer.TENSOR_SIZE_LIMIT);
91132
}
92133

93-
mInfoList.add(new TensorInfo(name, type, dimension));
134+
mInfoList.add(new TensorInfo(mFormat, name, type, dimension));
94135
}
95136

96137
/**
@@ -190,8 +231,12 @@ public int getTensorSize(int index) {
190231
checkIndexBounds(index);
191232

192233
int size = mInfoList.get(index).getSize();
193-
if (size <= 0) {
194-
throw new IllegalStateException("Unknown data type or invalid dimension");
234+
235+
/* The tensor size should be a positive value if data format is static. */
236+
if (mFormat == NNStreamer.TensorFormat.STATIC) {
237+
if (size <= 0) {
238+
throw new IllegalStateException("Unknown data type or invalid dimension");
239+
}
195240
}
196241

197242
return size;
@@ -211,6 +256,34 @@ private Object[] getInfoArray() {
211256
return mInfoList.toArray();
212257
}
213258

259+
/**
260+
* Internal method called from native to get the data format as integer value.
261+
*/
262+
private int getFormatValue() {
263+
return mFormat.ordinal();
264+
}
265+
266+
/**
267+
* Internal method to get the tensor format from int value.
268+
*/
269+
private static NNStreamer.TensorFormat convertFormat(int value) {
270+
NNStreamer.TensorFormat format = NNStreamer.TensorFormat.UNKNOWN;
271+
272+
switch (value) {
273+
case 0:
274+
format = NNStreamer.TensorFormat.STATIC;
275+
break;
276+
case 1:
277+
format = NNStreamer.TensorFormat.FLEXIBLE;
278+
break;
279+
default:
280+
/* unknown tensor format */
281+
break;
282+
}
283+
284+
return format;
285+
}
286+
214287
/**
215288
* Internal method to check the index.
216289
*
@@ -231,11 +304,14 @@ public void close() {
231304
* Internal class for tensor information.
232305
*/
233306
private static class TensorInfo {
307+
private NNStreamer.TensorFormat format;
234308
private String name = null;
235309
private int type = NNStreamer.TensorType.UNKNOWN.ordinal();
236310
private int[] dimension = new int[NNStreamer.TENSOR_RANK_LIMIT];
237311

238-
public TensorInfo(String name, NNStreamer.TensorType type, int[] dimension) {
312+
public TensorInfo(NNStreamer.TensorFormat format, String name, NNStreamer.TensorType type, int[] dimension) {
313+
this.format = format;
314+
239315
setName(name);
240316
setType(type);
241317
setDimension(dimension);
@@ -251,7 +327,10 @@ public String getName() {
251327

252328
public void setType(NNStreamer.TensorType type) {
253329
if (type == NNStreamer.TensorType.UNKNOWN) {
254-
throw new IllegalArgumentException("Given tensor type is unknown or unsupported type");
330+
/* The tensor type should be valid if data format is static. */
331+
if (format == NNStreamer.TensorFormat.STATIC) {
332+
throw new IllegalArgumentException("Given tensor type is unknown or unsupported type");
333+
}
255334
}
256335

257336
this.type = type.ordinal();
@@ -281,7 +360,10 @@ public void setDimension(int[] dimension) {
281360
if (rank > 0) {
282361
System.arraycopy(dimension, 0, this.dimension, 0, rank);
283362
} else {
284-
throw new IllegalArgumentException("The rank of given dimension is 0");
363+
/* The tensor dimension should be valid if data format is static. */
364+
if (format == NNStreamer.TensorFormat.STATIC) {
365+
throw new IllegalArgumentException("The rank of given dimension is 0");
366+
}
285367
}
286368

287369
/* fill default value */

0 commit comments

Comments
 (0)