Skip to content

Commit a2be098

Browse files
Merge pull request #384 from RedisAI/modelget.fix
Fixes AI.MODELGET to return INPUTS,OUTPUTS, BATCHSIZE, and MINBATCHSIZE
2 parents 439f956 + 74bddac commit a2be098

File tree

6 files changed

+124
-51
lines changed

6 files changed

+124
-51
lines changed

docs/commands.md

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,10 @@ An array of alternating key-value pairs as follows:
216216
1. **BACKEND**: the backend used by the model as a String
217217
1. **DEVICE**: the device used to execute the model as a String
218218
1. **TAG**: the model's tag as a String
219+
1. **BATCHSIZE**: The maximum size of any batch of incoming requests. If `BATCHSIZE` is equal to 0 each incoming request is served immediately. When `BATCHSIZE` is greater than 0, the engine will batch incoming requests from multiple clients that use the model with input tensors of the same shape.
220+
1. **MINBATCHSIZE**: The minimum size of any batch of incoming requests.
221+
1. **INPUTS**: array reply with one or more names of the model's input nodes (applicable only for TensorFlow models)
222+
1. **OUTPUTS**: array reply with one or more names of the model's output nodes (applicable only for TensorFlow models)
219223
1. **BLOB**: a blob containing the serialized model (when called with the `BLOB` argument) as a String
220224

221225
**Examples**
@@ -224,12 +228,21 @@ Assuming that your model is stored under the 'mymodel' key, you can obtain its m
224228

225229
```
226230
redis> AI.MODELGET mymodel META
227-
1) "backend"
228-
2) TF
229-
3) "device"
230-
4) CPU
231-
5) "tag"
232-
6) imagenet:5.0
231+
1) "backend"
232+
2) "TF"
233+
3) "device"
234+
4) "CPU"
235+
5) "tag"
236+
6) "imagenet:5.0"
237+
7) "batchsize"
238+
8) (integer) 0
239+
9) "minbatchsize"
240+
10) (integer) 0
241+
11) "inputs"
242+
12) 1) "a"
243+
2) "b"
244+
13) "outputs"
245+
14) 1) "c"
233246
```
234247

235248
You can also save it to the local file 'model.ext' with [`redis-cli`](https://redis.io/topics/cli) like so:

src/redisai.c

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -368,7 +368,7 @@ int RedisAI_ModelGet_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv,
368368

369369
RAI_Model *mto;
370370
RedisModuleKey *key;
371-
const int status = RAI_GetModelFromKeyspace( ctx, argv[1], &key, &mto, REDISMODULE_READ | REDISMODULE_WRITE);
371+
const int status = RAI_GetModelFromKeyspace( ctx, argv[1], &key, &mto, REDISMODULE_READ );
372372
if (status == REDISMODULE_ERR) {
373373
return REDISMODULE_ERR;
374374
}
@@ -418,12 +418,12 @@ int RedisAI_ModelGet_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv,
418418
return REDISMODULE_OK;
419419
}
420420

421-
int outentries = blob ? 8 : 6;
421+
const int outentries = blob ? 16 : 14;
422422

423423
RedisModule_ReplyWithArray(ctx, outentries);
424424

425425
RedisModule_ReplyWithCString(ctx, "backend");
426-
const char* backendstr = RAI_BackendName(mto->backend);
426+
const char *backendstr = RAI_BackendName(mto->backend);
427427
RedisModule_ReplyWithCString(ctx, backendstr);
428428

429429
RedisModule_ReplyWithCString(ctx, "device");
@@ -432,6 +432,28 @@ int RedisAI_ModelGet_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv,
432432
RedisModule_ReplyWithCString(ctx, "tag");
433433
RedisModule_ReplyWithCString(ctx, mto->tag ? mto->tag : "");
434434

435+
RedisModule_ReplyWithCString(ctx, "batchsize");
436+
RedisModule_ReplyWithLongLong(ctx, (long)mto->opts.batchsize);
437+
438+
RedisModule_ReplyWithCString(ctx, "minbatchsize");
439+
RedisModule_ReplyWithLongLong(ctx, (long)mto->opts.minbatchsize);
440+
441+
RedisModule_ReplyWithCString(ctx, "inputs");
442+
const size_t ninputs = array_len(mto->inputs);
443+
RedisModule_ReplyWithArray(ctx, (long)ninputs);
444+
445+
for (size_t i = 0; i < ninputs; i++) {
446+
RedisModule_ReplyWithCString(ctx, mto->inputs[i]);
447+
}
448+
449+
RedisModule_ReplyWithCString(ctx, "outputs");
450+
const size_t noutputs = array_len(mto->outputs);
451+
RedisModule_ReplyWithArray(ctx, (long)noutputs);
452+
453+
for (size_t i = 0; i < noutputs; i++) {
454+
RedisModule_ReplyWithCString(ctx, mto->outputs[i]);
455+
}
456+
435457
if (meta && blob) {
436458
RedisModule_ReplyWithCString(ctx, "blob");
437459
RedisModule_ReplyWithStringBuffer(ctx, buffer, len);

test/tests_onnx.py

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,21 +36,27 @@ def test_onnx_modelrun_mnist(env):
3636
ensureSlaveSynced(con, env)
3737

3838
ret = con.execute_command('AI.MODELGET', 'm', 'META')
39-
env.assertEqual(len(ret), 6)
40-
env.assertEqual(ret[-1], b'')
39+
env.assertEqual(len(ret), 14)
40+
env.assertEqual(ret[5], b'')
41+
# assert there are no inputs or outputs
42+
env.assertEqual(len(ret[11]), 0)
43+
env.assertEqual(len(ret[13]), 0)
4144

42-
ret = con.execute_command('AI.MODELSET', 'm', 'ONNX', DEVICE, 'TAG', 'asdf', 'BLOB', model_pb)
45+
ret = con.execute_command('AI.MODELSET', 'm', 'ONNX', DEVICE, 'TAG', 'version:2', 'BLOB', model_pb)
4346
env.assertEqual(ret, b'OK')
4447

4548
ensureSlaveSynced(con, env)
4649

4750
ret = con.execute_command('AI.MODELGET', 'm', 'META')
48-
env.assertEqual(len(ret), 6)
49-
env.assertEqual(ret[-1], b'asdf')
50-
51-
# TODO: enable me
52-
# env.assertEqual(ret[0], b'ONNX')
53-
# env.assertEqual(ret[1], b'CPU')
51+
env.assertEqual(len(ret), 14)
52+
# TODO: enable me. CI is having issues on GPU asserts of ONNX and CPU
53+
if DEVICE == "CPU":
54+
env.assertEqual(ret[1], b'ONNX')
55+
env.assertEqual(ret[3], b'CPU')
56+
env.assertEqual(ret[5], b'version:2')
57+
# assert there are no inputs or outputs
58+
env.assertEqual(len(ret[11]), 0)
59+
env.assertEqual(len(ret[13]), 0)
5460

5561
try:
5662
con.execute_command('AI.MODELSET', 'm', 'ONNX', DEVICE, 'BLOB', wrong_model_pb)
@@ -166,6 +172,19 @@ def test_onnx_modelrun_mnist_autobatch(env):
166172
'BATCHSIZE', 2, 'MINBATCHSIZE', 2, 'BLOB', model_pb)
167173
env.assertEqual(ret, b'OK')
168174

175+
ret = con.execute_command('AI.MODELGET', 'm', 'META')
176+
env.assertEqual(len(ret), 14)
177+
# TODO: enable me. CI is having issues on GPU asserts of ONNX and CPU
178+
if DEVICE == "CPU":
179+
env.assertEqual(ret[1], b'ONNX')
180+
env.assertEqual(ret[3], b'CPU')
181+
env.assertEqual(ret[5], b'')
182+
env.assertEqual(ret[7], 2)
183+
env.assertEqual(ret[9], 2)
184+
# assert there are no inputs or outputs
185+
env.assertEqual(len(ret[11]), 0)
186+
env.assertEqual(len(ret[13]), 0)
187+
169188
con.execute_command('AI.TENSORSET', 'a', 'FLOAT', 1, 1, 28, 28, 'BLOB', sample_raw)
170189
con.execute_command('AI.TENSORSET', 'c', 'FLOAT', 1, 1, 28, 28, 'BLOB', sample_raw)
171190

test/tests_pytorch.py

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -62,22 +62,31 @@ def test_pytorch_modelrun(env):
6262
ensureSlaveSynced(con, env)
6363

6464
ret = con.execute_command('AI.MODELGET', 'm', 'META')
65-
env.assertEqual(len(ret), 6)
66-
env.assertEqual(ret[-1], b'')
67-
68-
ret = con.execute_command('AI.MODELSET', 'm', 'TORCH', DEVICE, 'TAG', 'asdf', 'BLOB', model_pb)
65+
ret = con.execute_command('AI.MODELGET', 'm', 'META')
66+
env.assertEqual(len(ret), 14)
67+
# TODO: enable me. CI is having issues on GPU asserts of TORCH and CPU
68+
if DEVICE == "CPU":
69+
env.assertEqual(ret[1], b'TORCH')
70+
env.assertEqual(ret[3], b'CPU')
71+
env.assertEqual(ret[5], b'')
72+
env.assertEqual(ret[7], 0)
73+
env.assertEqual(ret[9], 0)
74+
# assert there are no inputs or outputs
75+
env.assertEqual(len(ret[11]), 0)
76+
env.assertEqual(len(ret[13]), 0)
77+
78+
ret = con.execute_command('AI.MODELSET', 'm', 'TORCH', DEVICE, 'TAG', 'my:tag:v3', 'BLOB', model_pb)
6979
env.assertEqual(ret, b'OK')
7080

7181
ensureSlaveSynced(con, env)
7282

7383
ret = con.execute_command('AI.MODELGET', 'm', 'META')
74-
env.assertEqual(len(ret), 6)
75-
env.assertEqual(ret[-1], b'asdf')
76-
77-
78-
# TODO: enable me
79-
# env.assertEqual(ret[0], b'TORCH')
80-
# env.assertEqual(ret[1], b'CPU')
84+
env.assertEqual(len(ret), 14)
85+
env.assertEqual(ret[5], b'my:tag:v3')
86+
# TODO: enable me. CI is having issues on GPU asserts of TORCH and CPU
87+
if DEVICE == "CPU":
88+
env.assertEqual(ret[1], b'TORCH')
89+
env.assertEqual(ret[3], b'CPU')
8190

8291
try:
8392
con.execute_command('AI.MODELSET', 'm', 'TORCH', DEVICE, 'BLOB', wrong_model_pb)

test/tests_tensorflow.py

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -187,23 +187,28 @@ def test_run_tf_model(env):
187187
ensureSlaveSynced(con, env)
188188

189189
ret = con.execute_command('AI.MODELGET', 'm', 'META')
190-
env.assertEqual(len(ret), 6)
191-
env.assertEqual(ret[-1], b'')
190+
env.assertEqual(len(ret), 14)
191+
env.assertEqual(ret[5], b'')
192+
env.assertEqual(ret[11][0], b'a')
193+
env.assertEqual(ret[11][1], b'b')
194+
env.assertEqual(ret[13][0], b'mul')
192195

193-
ret = con.execute_command('AI.MODELSET', 'm', 'TF', DEVICE, 'TAG', 'asdf',
196+
ret = con.execute_command('AI.MODELSET', 'm', 'TF', DEVICE, 'TAG', 'version:1',
194197
'INPUTS', 'a', 'b', 'OUTPUTS', 'mul', 'BLOB', model_pb)
195198
env.assertEqual(ret, b'OK')
196199

197200
ensureSlaveSynced(con, env)
198201

199202
ret = con.execute_command('AI.MODELGET', 'm', 'META')
200-
env.assertEqual(len(ret), 6)
201-
env.assertEqual(ret[-1], b'asdf')
202-
203-
204-
# TODO: enable me
205-
# env.assertEqual(ret[0], b'TF')
206-
# env.assertEqual(ret[1], b'CPU')
203+
env.assertEqual(len(ret), 14)
204+
# TODO: enable me. CI is having issues on GPU asserts of TF and CPU
205+
if DEVICE == "CPU":
206+
env.assertEqual(ret[1], b'TF')
207+
env.assertEqual(ret[3], b'CPU')
208+
env.assertEqual(ret[5], b'version:1')
209+
env.assertEqual(ret[11][0], b'a')
210+
env.assertEqual(ret[11][1], b'b')
211+
env.assertEqual(ret[13][0], b'mul')
207212

208213
con.execute_command('AI.TENSORSET', 'a', 'FLOAT',
209214
2, 2, 'VALUES', 2, 3, 2, 3)
@@ -258,8 +263,10 @@ def test_run_tf2_model(env):
258263
ensureSlaveSynced(con, env)
259264

260265
ret = con.execute_command('AI.MODELGET', 'm', 'META')
261-
env.assertEqual(len(ret), 6)
262-
env.assertEqual(ret[-1], b'')
266+
env.assertEqual(len(ret), 14)
267+
env.assertEqual(ret[5], b'')
268+
env.assertEqual(ret[11][0], b'x')
269+
env.assertEqual(ret[13][0], b'Identity')
263270

264271
ret = con.execute_command('AI.MODELSET', 'm', 'TF', DEVICE, 'TAG', 'asdf',
265272
'INPUTS', 'x', 'OUTPUTS', 'Identity', 'BLOB', model_pb)
@@ -268,8 +275,10 @@ def test_run_tf2_model(env):
268275
ensureSlaveSynced(con, env)
269276

270277
ret = con.execute_command('AI.MODELGET', 'm', 'META')
271-
env.assertEqual(len(ret), 6)
272-
env.assertEqual(ret[-1], b'asdf')
278+
env.assertEqual(len(ret), 14)
279+
env.assertEqual(ret[5], b'asdf')
280+
env.assertEqual(ret[11][0], b'x')
281+
env.assertEqual(ret[13][0], b'Identity')
273282

274283
zero_values = [0] * (28 * 28)
275284

test/tests_tflite.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,26 +35,27 @@ def test_run_tflite_model(env):
3535
env.assertEqual(ret, b'OK')
3636

3737
ret = con.execute_command('AI.MODELGET', 'm', 'META')
38-
env.assertEqual(len(ret), 6)
39-
env.assertEqual(ret[-1], b'')
38+
env.assertEqual(len(ret), 14)
39+
env.assertEqual(ret[5], b'')
4040

4141
ret = con.execute_command('AI.MODELSET', 'm', 'TFLITE', 'CPU', 'TAG', 'asdf', 'BLOB', model_pb)
4242
env.assertEqual(ret, b'OK')
4343

4444
ret = con.execute_command('AI.MODELGET', 'm', 'META')
45-
env.assertEqual(len(ret), 6)
46-
env.assertEqual(ret[-1], b'asdf')
45+
env.assertEqual(len(ret), 14)
46+
env.assertEqual(ret[5], b'asdf')
4747

4848
ret = con.execute_command('AI.TENSORSET', 'a', 'FLOAT', 1, 1, 28, 28, 'BLOB', sample_raw)
4949
env.assertEqual(ret, b'OK')
5050

5151
ensureSlaveSynced(con, env)
5252

5353
ret = con.execute_command('AI.MODELGET', 'm', 'META')
54-
env.assertEqual(len(ret), 6)
55-
# TODO: enable me
56-
# env.assertEqual(ret[0], b'TFLITE')
57-
# env.assertEqual(ret[1], b'CPU')
54+
env.assertEqual(len(ret), 14)
55+
# TODO: enable me. CI is having issues on GPU asserts of TFLITE and CPU
56+
if DEVICE == "CPU":
57+
env.assertEqual(ret[1], b'TFLITE')
58+
env.assertEqual(ret[3], b'CPU')
5859

5960
con.execute_command('AI.MODELRUN', 'm', 'INPUTS', 'a', 'OUTPUTS', 'b', 'c')
6061

0 commit comments

Comments
 (0)