diff --git a/README.md b/README.md index afc790519..ff2890198 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ Note that Redis config is located at `/usr/local/etc/redis/redis.conf` which can On the client, set the model ```sh -redis-cli -x AI.MODELSET foo TF CPU INPUTS a b OUTPUTS c < test/test_data/graph.pb +redis-cli -x AI.MODELSET foo TF CPU INPUTS a b OUTPUTS c BLOB < test/test_data/graph.pb ``` Then create the input tensors, run the computation graph and get the output tensor (see `load_model.sh`). Note the signatures: diff --git a/docs/commands.md b/docs/commands.md index 7d6d181cd..13eb06f1d 100644 --- a/docs/commands.md +++ b/docs/commands.md @@ -123,7 +123,7 @@ AI.TENSORGET foo META VALUES Set a model. ```sql -AI.MODELSET model_key backend device [TAG tag] [BATCHSIZE n [MINBATCHSIZE m]] [INPUTS name1 name2 ... OUTPUTS name1 name2 ...] model_blob +AI.MODELSET model_key backend device [TAG tag] [BATCHSIZE n [MINBATCHSIZE m]] [INPUTS name1 name2 ... OUTPUTS name1 name2 ...] BLOB model_blob ``` * model_key - Key for storing the model @@ -142,28 +142,29 @@ AI.MODELSET model_key backend device [TAG tag] [BATCHSIZE n [MINBATCHSIZE m]] [I Default is 0 (no minimum batch size). * INPUTS name1 name2 ... - Name of the nodes in the provided graph corresponding to inputs [`TF` backend only] * OUTPUTS name1 name2 ... - Name of the nodes in the provided graph corresponding to outputs [`TF` backend only] -* model_blob - Binary buffer containing the model protobuf saved from a supported backend +* BLOB model_blob - Binary buffer containing the model protobuf saved from a supported backend. Since Redis supports strings + up to 512MB, blobs for very large models need to be chunked, e.g. `BLOB chunk1 chunk2 ...`. ### MODELSET Example ```sql -AI.MODELSET resnet18 TORCH GPU < foo.pt +AI.MODELSET resnet18 TORCH GPU BLOB < foo.pt ``` ```sql -AI.MODELSET resnet18 TF CPU INPUTS in1 OUTPUTS linear4 < foo.pb +AI.MODELSET resnet18 TF CPU INPUTS in1 OUTPUTS linear4 BLOB < foo.pb ``` ```sql -AI.MODELSET mnist_net ONNX CPU TAG mnist:lenet:v0.1 < mnist.onnx +AI.MODELSET mnist_net ONNX CPU TAG mnist:lenet:v0.1 BLOB < mnist.onnx ``` ```sql -AI.MODELSET mnist_net ONNX CPU BATCHSIZE 10 < mnist.onnx +AI.MODELSET mnist_net ONNX CPU BATCHSIZE 10 BLOB < mnist.onnx ``` ```sql -AI.MODELSET resnet18 TF CPU BATCHSIZE 10 MINBATCHSIZE 6 INPUTS in1 OUTPUTS linear4 < foo.pb +AI.MODELSET resnet18 TF CPU BATCHSIZE 10 MINBATCHSIZE 6 INPUTS in1 OUTPUTS linear4 BLOB < foo.pb ``` ## AI.MODELGET @@ -284,13 +285,13 @@ AI._MODELSCAN Set a script. ```sql -AI.SCRIPTSET script_key device [TAG tag] script_source +AI.SCRIPTSET script_key device [TAG tag] SOURCE script_source ``` * script_key - Key for storing the script * device - The device where the script will execute * TAG tag - Optional string tagging the script, such as a version number or other identifier -* script_source - A string containing [TorchScript](https://pytorch.org/docs/stable/jit.html) source code +* SOURCE script_source - A string containing [TorchScript](https://pytorch.org/docs/stable/jit.html) source code ### SCRIPTSET Example @@ -302,11 +303,11 @@ def addtwo(a, b): ``` ```sql -AI.SCRIPTSET addscript GPU < addtwo.txt +AI.SCRIPTSET addscript GPU SOURCE < addtwo.txt ``` ```sql -AI.SCRIPTSET addscript GPU TAG myscript:v0.1 < addtwo.txt +AI.SCRIPTSET addscript GPU TAG myscript:v0.1 SOURCE < addtwo.txt ``` ## AI.SCRIPTGET diff --git a/docs/index.md b/docs/index.md index 103f0eb9e..80aee4d0e 100644 --- a/docs/index.md +++ b/docs/index.md @@ -24,7 +24,7 @@ docker run -p 6379:6379 -it --rm redisai/redisai On the client, load a backend (TF, TORCH or ONNX), and set the model ```sh redis-cli AI.CONFIG LOADBACKEND TF install/backends/redisai_tensorflow/redisai_tensorflow.so -redis-cli -x AI.MODELSET foo TF CPU INPUTS a b OUTPUTS c < test/test_data/graph.pb +redis-cli -x AI.MODELSET foo TF CPU INPUTS a b OUTPUTS c BLOB < test/test_data/graph.pb ``` Then create the input tensors, run the computation graph and get the output tensor (see `load_model.sh`). Note the signatures: diff --git a/src/redisai.c b/src/redisai.c index d0344bd72..cf31bd17e 100644 --- a/src/redisai.c +++ b/src/redisai.c @@ -86,7 +86,7 @@ int RedisAI_TensorGet_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv } /** -* AI.MODELSET model_key backend device [TAG tag] [BATCHSIZE n [MINBATCHSIZE m]] [INPUTS name1 name2 ... OUTPUTS name1 name2 ...] model_blob +* AI.MODELSET model_key backend device [TAG tag] [BATCHSIZE n [MINBATCHSIZE m]] [INPUTS name1 name2 ... OUTPUTS name1 name2 ...] BLOB model_blob */ int RedisAI_ModelSet_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { RedisModule_AutoMemory(ctx); @@ -121,7 +121,14 @@ int RedisAI_ModelSet_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, const char* devicestr; AC_GetString(&ac, &devicestr, NULL, 0); - if (strlen(devicestr) > 10) { + if (strlen(devicestr) > 10 || + strcasecmp(devicestr, "INPUTS") == 0 || + strcasecmp(devicestr, "OUTPUTS") == 0 || + strcasecmp(devicestr, "TAG") == 0 || + strcasecmp(devicestr, "BATCHSIZE") == 0 || + strcasecmp(devicestr, "MINBATCHSIZE") == 0 || + strcasecmp(devicestr, "BLOB") == 0 + ) { return RedisModule_ReplyWithError(ctx, "ERR Invalid DEVICE"); } @@ -150,13 +157,13 @@ int RedisAI_ModelSet_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, } } - if (AC_IsAtEnd(&ac)) { return RedisModule_ReplyWithError(ctx, "ERR Insufficient arguments, missing model BLOB"); } ArgsCursor optionsac; - AC_GetSliceToOffset(&ac, &optionsac, argc-2); + const char* blob_matches[] = {"BLOB"}; + AC_GetSliceUntilMatches(&ac, &optionsac, 1, blob_matches); if (optionsac.argc == 0 && backend == RAI_BACKEND_TENSORFLOW) { return RedisModule_ReplyWithError(ctx, "ERR Insufficient arguments, INPUTS and OUTPUTS not specified"); @@ -164,7 +171,7 @@ int RedisAI_ModelSet_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, ArgsCursor inac = {0}; ArgsCursor outac = {0}; - if (optionsac.argc > 0) { + if (optionsac.argc > 0 && backend == RAI_BACKEND_TENSORFLOW) { if (!AC_AdvanceIfMatch(&optionsac, "INPUTS")) { return RedisModule_ReplyWithError(ctx, "ERR INPUTS not specified"); } @@ -202,9 +209,39 @@ int RedisAI_ModelSet_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, RAI_Model *model = NULL; + AC_AdvanceUntilMatches(&ac, 1, blob_matches); + + if (AC_IsAtEnd(&ac)) { + return RedisModule_ReplyWithError(ctx, "ERR Insufficient arguments, missing model BLOB"); + } + + AC_Advance(&ac); + + ArgsCursor blobsac; + AC_GetSliceToEnd(&ac, &blobsac); + size_t modellen; - const char *modeldef; - AC_GetString(&ac, &modeldef, &modellen, 0); + char *modeldef; + + if (blobsac.argc == 1) { + AC_GetString(&blobsac, (const char**)&modeldef, &modellen, 0); + } + else { + const char *chunks[blobsac.argc]; + size_t chunklens[blobsac.argc]; + modellen = 0; + while (!AC_IsAtEnd(&blobsac)) { + AC_GetString(&blobsac, &chunks[blobsac.offset], &chunklens[blobsac.offset], 0); + modellen += chunklens[blobsac.offset-1]; + } + + modeldef = RedisModule_Calloc(modellen, sizeof(char)); + size_t offset = 0; + for (size_t i=0; i 1) { + RedisModule_Free(modeldef); + } + if (err.code != RAI_OK) { #ifdef RAI_PRINT_BACKEND_ERRORS printf("ERR: %s\n", err.detail); @@ -502,14 +543,14 @@ int RedisAI_ScriptRun_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv ArgsCursor outac = {0}; if (!AC_AdvanceIfMatch(&ac, "INPUTS")) { - return RedisModule_ReplyWithError(ctx, "INPUTS not specified"); + return RedisModule_ReplyWithError(ctx, "ERR Insufficient arguments, INPUTS not specified"); } const char* matches[] = {"OUTPUTS"}; AC_GetSliceUntilMatches(&ac, &inac, 1, matches); if (!AC_AdvanceIfMatch(&ac, "OUTPUTS")) { - return RedisModule_ReplyWithError(ctx, "OUTPUTS not specified"); + return RedisModule_ReplyWithError(ctx, "ERR Insufficient arguments, OUTPUTS not specified"); } AC_GetSliceToEnd(&ac, &outac); @@ -541,7 +582,7 @@ int RedisAI_ScriptRun_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv if (!RAI_ScriptRunCtxAddInput(rinfo->sctx, t)) { RAI_FreeRunInfo(ctx,rinfo); RedisModule_CloseKey(key); - return RedisModule_ReplyWithError(ctx, "Input key not found"); + return RedisModule_ReplyWithError(ctx, "ERR Input key not found"); } } @@ -549,7 +590,7 @@ int RedisAI_ScriptRun_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv if (!RAI_ScriptRunCtxAddOutput(rinfo->sctx)) { RAI_FreeRunInfo(ctx,rinfo); RedisModule_CloseKey(key); - return RedisModule_ReplyWithError(ctx, "Output key not found"); + return RedisModule_ReplyWithError(ctx, "ERR Output key not found"); } RedisModule_RetainString(ctx, outputs[i]); array_append(rinfo->outkeys,outputs[i]); @@ -651,12 +692,12 @@ int RedisAI_ScriptDel_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv } /** -* AI.SCRIPTSET script_key device [TAG tag] script_source +* AI.SCRIPTSET script_key device [TAG tag] SOURCE script_source */ int RedisAI_ScriptSet_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { RedisModule_AutoMemory(ctx); - if (argc != 4 && argc != 6) return RedisModule_WrongArity(ctx); + if (argc != 5 && argc != 7) return RedisModule_WrongArity(ctx); ArgsCursor ac; ArgsCursor_InitRString(&ac, argv+1, argc-1); @@ -673,14 +714,21 @@ int RedisAI_ScriptSet_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv } if (AC_IsAtEnd(&ac)) { - return RedisModule_ReplyWithError(ctx, "Insufficient arguments, missing script definition"); + return RedisModule_ReplyWithError(ctx, "ERR Insufficient arguments, missing script SOURCE"); } - RAI_Script *script = NULL; - size_t scriptlen; - const char *scriptdef; - AC_GetString(&ac, &scriptdef, &scriptlen, 0); + const char *scriptdef = NULL; + + if (AC_AdvanceIfMatch(&ac, "SOURCE")) { + AC_GetString(&ac, &scriptdef, &scriptlen, 0); + } + + if (scriptdef == NULL) { + return RedisModule_ReplyWithError(ctx, "ERR Insufficient arguments, missing script SOURCE"); + } + + RAI_Script *script = NULL; RAI_Error err = {0}; script = RAI_ScriptCreate(devicestr, tag, scriptdef, &err); diff --git a/test/tests_dag.py b/test/tests_dag.py index 165cc9c4f..ed13fadd2 100644 --- a/test/tests_dag.py +++ b/test/tests_dag.py @@ -144,7 +144,7 @@ def test_dag_modelrun_financialNet_errors(env): model_pb, creditcard_transactions, creditcard_referencedata = load_creditcardfraud_data( env) ret = con.execute_command('AI.MODELSET', 'financialNet', 'TF', "CPU", - 'INPUTS', 'transaction', 'reference', 'OUTPUTS', 'output', model_pb) + 'INPUTS', 'transaction', 'reference', 'OUTPUTS', 'output', 'BLOB', model_pb) env.assertEqual(ret, b'OK') tensor_number=1 @@ -390,7 +390,7 @@ def test_dag_modelrun_financialNet_separate_tensorget(env): model_pb, creditcard_transactions, creditcard_referencedata = load_creditcardfraud_data( env) ret = con.execute_command('AI.MODELSET', 'financialNet', 'TF', "CPU", - 'INPUTS', 'transaction', 'reference', 'OUTPUTS', 'output', model_pb) + 'INPUTS', 'transaction', 'reference', 'OUTPUTS', 'output', 'BLOB', model_pb) env.assertEqual(ret, b'OK') tensor_number = 1 @@ -432,7 +432,7 @@ def test_dag_modelrun_financialNet(env): model_pb, creditcard_transactions, creditcard_referencedata = load_creditcardfraud_data( env) ret = con.execute_command('AI.MODELSET', 'financialNet', 'TF', "CPU", - 'INPUTS', 'transaction', 'reference', 'OUTPUTS', 'output', model_pb) + 'INPUTS', 'transaction', 'reference', 'OUTPUTS', 'output', 'BLOB', model_pb) env.assertEqual(ret, b'OK') tensor_number = 1 @@ -471,7 +471,7 @@ def test_dag_modelrun_financialNet_no_writes(env): model_pb, creditcard_transactions, creditcard_referencedata = load_creditcardfraud_data( env) ret = con.execute_command('AI.MODELSET', 'financialNet', 'TF', "CPU", - 'INPUTS', 'transaction', 'reference', 'OUTPUTS', 'output', model_pb) + 'INPUTS', 'transaction', 'reference', 'OUTPUTS', 'output', 'BLOB', model_pb) env.assertEqual(ret, b'OK') tensor_number = 1 @@ -522,7 +522,7 @@ def test_dagro_modelrun_financialNet_no_writes_multiple_modelruns(env): model_pb, creditcard_transactions, creditcard_referencedata = load_creditcardfraud_data( env) ret = con.execute_command('AI.MODELSET', 'financialNet', 'TF', DEVICE, - 'INPUTS', 'transaction', 'reference', 'OUTPUTS', 'output', model_pb) + 'INPUTS', 'transaction', 'reference', 'OUTPUTS', 'output', 'BLOB', model_pb) env.assertEqual(ret, b'OK') tensor_number = 1 diff --git a/test/tests_onnx.py b/test/tests_onnx.py index 5d612ee16..b8933f878 100644 --- a/test/tests_onnx.py +++ b/test/tests_onnx.py @@ -30,7 +30,7 @@ def test_onnx_modelrun_mnist(env): with open(sample_filename, 'rb') as f: sample_raw = f.read() - ret = con.execute_command('AI.MODELSET', 'm', 'ONNX', DEVICE, model_pb) + ret = con.execute_command('AI.MODELSET', 'm', 'ONNX', DEVICE, 'BLOB', model_pb) env.assertEqual(ret, b'OK') ensureSlaveSynced(con, env) @@ -39,7 +39,7 @@ def test_onnx_modelrun_mnist(env): env.assertEqual(len(ret), 6) env.assertEqual(ret[-1], b'') - ret = con.execute_command('AI.MODELSET', 'm', 'ONNX', DEVICE, 'TAG', 'asdf', model_pb) + ret = con.execute_command('AI.MODELSET', 'm', 'ONNX', DEVICE, 'TAG', 'asdf', 'BLOB', model_pb) env.assertEqual(ret, b'OK') ensureSlaveSynced(con, env) @@ -53,14 +53,14 @@ def test_onnx_modelrun_mnist(env): # env.assertEqual(ret[1], b'CPU') try: - con.execute_command('AI.MODELSET', 'm', 'ONNX', DEVICE, wrong_model_pb) + con.execute_command('AI.MODELSET', 'm', 'ONNX', DEVICE, 'BLOB', wrong_model_pb) except Exception as e: exception = e env.assertEqual(type(exception), redis.exceptions.ResponseError) env.assertEqual("No graph was found in the protobuf.", exception.__str__()) try: - con.execute_command('AI.MODELSET', 'm_1', 'ONNX', model_pb) + con.execute_command('AI.MODELSET', 'm_1', 'ONNX', 'BLOB', model_pb) except Exception as e: exception = e env.assertEqual(type(exception), redis.exceptions.ResponseError) @@ -163,7 +163,7 @@ def test_onnx_modelrun_mnist_autobatch(env): sample_raw = f.read() ret = con.execute_command('AI.MODELSET', 'm', 'ONNX', 'CPU', - 'BATCHSIZE', 2, 'MINBATCHSIZE', 2, model_pb) + 'BATCHSIZE', 2, 'MINBATCHSIZE', 2, 'BLOB', model_pb) env.assertEqual(ret, b'OK') con.execute_command('AI.TENSORSET', 'a', 'FLOAT', 1, 1, 28, 28, 'BLOB', sample_raw) @@ -213,10 +213,10 @@ def test_onnx_modelrun_iris(env): with open(logreg_model_filename, 'rb') as f: logreg_model = f.read() - ret = con.execute_command('AI.MODELSET', 'linear', 'ONNX', DEVICE, linear_model) + ret = con.execute_command('AI.MODELSET', 'linear', 'ONNX', DEVICE, 'BLOB', linear_model) env.assertEqual(ret, b'OK') - ret = con.execute_command('AI.MODELSET', 'logreg', 'ONNX', DEVICE, logreg_model) + ret = con.execute_command('AI.MODELSET', 'logreg', 'ONNX', DEVICE, 'BLOB', logreg_model) env.assertEqual(ret, b'OK') con.execute_command('AI.TENSORSET', 'features', 'FLOAT', 1, 4, 'VALUES', 5.1, 3.5, 1.4, 0.2) @@ -254,7 +254,7 @@ def test_onnx_modelinfo(env): with open(linear_model_filename, 'rb') as f: linear_model = f.read() - ret = con.execute_command('AI.MODELSET', 'linear', 'ONNX', DEVICE, linear_model) + ret = con.execute_command('AI.MODELSET', 'linear', 'ONNX', DEVICE, 'BLOB', linear_model) env.assertEqual(ret, b'OK') model_serialized_master = con.execute_command('AI.MODELGET', 'linear', 'META') @@ -309,7 +309,7 @@ def test_onnx_modelrun_disconnect(env): with open(linear_model_filename, 'rb') as f: linear_model = f.read() - ret = con.execute_command('AI.MODELSET', 'linear', 'ONNX', DEVICE, linear_model) + ret = con.execute_command('AI.MODELSET', 'linear', 'ONNX', DEVICE, 'BLOB', linear_model) env.assertEqual(ret, b'OK') model_serialized_master = con.execute_command('AI.MODELGET', 'linear', 'META') @@ -338,7 +338,7 @@ def test_onnx_model_rdb_save_load(env): model_pb = f.read() con = env.getConnection() - ret = con.execute_command('AI.MODELSET', 'linear', 'ONNX', DEVICE, model_pb) + ret = con.execute_command('AI.MODELSET', 'linear', 'ONNX', DEVICE, 'BLOB', model_pb) env.assertEqual(ret, b'OK') model_serialized_memory = con.execute_command('AI.MODELGET', 'linear', 'BLOB') diff --git a/test/tests_pytorch.py b/test/tests_pytorch.py index 1ad6b4438..1e0dcac36 100644 --- a/test/tests_pytorch.py +++ b/test/tests_pytorch.py @@ -7,6 +7,32 @@ ''' +def test_pytorch_chunked_modelset(env): + if not TEST_PT: + env.debugPrint("skipping {} since TEST_PT=0".format(sys._getframe().f_code.co_name), force=True) + return + + con = env.getConnection() + + test_data_path = os.path.join(os.path.dirname(__file__), 'test_data') + model_filename = os.path.join(test_data_path, 'pt-minimal.pt') + + with open(model_filename, 'rb') as f: + model = f.read() + + chunk_size = len(model) // 3 + + model_chunks = [model[i:i + chunk_size] for i in range(0, len(model), chunk_size)] + + ret = con.execute_command('AI.MODELSET', 'm1', 'TORCH', DEVICE, 'BLOB', model) + ret = con.execute_command('AI.MODELSET', 'm2', 'TORCH', DEVICE, 'BLOB', *model_chunks) + + model1 = con.execute_command('AI.MODELGET', 'm1', 'BLOB') + model2 = con.execute_command('AI.MODELGET', 'm2', 'BLOB') + + env.assertEqual(model1, model2) + + def test_pytorch_modelrun(env): if not TEST_PT: env.debugPrint("skipping {} since TEST_PT=0".format(sys._getframe().f_code.co_name), force=True) @@ -30,7 +56,7 @@ def test_pytorch_modelrun(env): with open(wrong_model_filename, 'rb') as f: wrong_model_pb = f.read() - ret = con.execute_command('AI.MODELSET', 'm', 'TORCH', DEVICE, model_pb) + ret = con.execute_command('AI.MODELSET', 'm', 'TORCH', DEVICE, 'BLOB', model_pb) env.assertEqual(ret, b'OK') ensureSlaveSynced(con, env) @@ -39,7 +65,7 @@ def test_pytorch_modelrun(env): env.assertEqual(len(ret), 6) env.assertEqual(ret[-1], b'') - ret = con.execute_command('AI.MODELSET', 'm', 'TORCH', DEVICE, 'TAG', 'asdf', model_pb) + ret = con.execute_command('AI.MODELSET', 'm', 'TORCH', DEVICE, 'TAG', 'asdf', 'BLOB', model_pb) env.assertEqual(ret, b'OK') ensureSlaveSynced(con, env) @@ -54,19 +80,19 @@ def test_pytorch_modelrun(env): # env.assertEqual(ret[1], b'CPU') try: - con.execute_command('AI.MODELSET', 'm', 'TORCH', DEVICE, wrong_model_pb) + con.execute_command('AI.MODELSET', 'm', 'TORCH', DEVICE, 'BLOB', wrong_model_pb) except Exception as e: exception = e env.assertEqual(type(exception), redis.exceptions.ResponseError) try: - con.execute_command('AI.MODELSET', 'm_1', 'TORCH', model_pb) + con.execute_command('AI.MODELSET', 'm_1', 'TORCH', 'BLOB', model_pb) except Exception as e: exception = e env.assertEqual(type(exception), redis.exceptions.ResponseError) try: - con.execute_command('AI.MODELSET', 'm_2', model_pb) + con.execute_command('AI.MODELSET', 'm_2', 'BLOB', model_pb) except Exception as e: exception = e env.assertEqual(type(exception), redis.exceptions.ResponseError) @@ -145,7 +171,7 @@ def test_pytorch_modelrun_autobatch(env): model_pb = f.read() ret = con.execute_command('AI.MODELSET', 'm', 'TORCH', 'CPU', - 'BATCHSIZE', 4, 'MINBATCHSIZE', 3, model_pb) + 'BATCHSIZE', 4, 'MINBATCHSIZE', 3, 'BLOB', model_pb) env.assertEqual(ret, b'OK') con.execute_command('AI.TENSORSET', 'a', 'FLOAT', 2, 2, 'VALUES', 2, 3, 2, 3) @@ -188,7 +214,7 @@ def test_pytorch_modelinfo(env): with open(model_filename, 'rb') as f: model_pb = f.read() - ret = con.execute_command('AI.MODELSET', 'm', 'TORCH', DEVICE, 'TAG', 'asdf', model_pb) + ret = con.execute_command('AI.MODELSET', 'm', 'TORCH', DEVICE, 'TAG', 'asdf', 'BLOB', model_pb) env.assertEqual(ret, b'OK') ret = con.execute_command('AI.TENSORSET', 'a', 'FLOAT', 2, 2, 'VALUES', 2, 3, 2, 3) @@ -238,7 +264,7 @@ def test_pytorch_scriptset(env): con = env.getConnection() try: - con.execute_command('AI.SCRIPTSET', 'ket', DEVICE, 'return 1') + con.execute_command('AI.SCRIPTSET', 'ket', DEVICE, 'SOURCE', 'return 1') except Exception as e: exception = e env.assertEqual(type(exception), redis.exceptions.ResponseError) @@ -249,6 +275,12 @@ def test_pytorch_scriptset(env): exception = e env.assertEqual(type(exception), redis.exceptions.ResponseError) + try: + con.execute_command('AI.SCRIPTSET', 'nope', 'SOURCE') + except Exception as e: + exception = e + env.assertEqual(type(exception), redis.exceptions.ResponseError) + try: con.execute_command('AI.SCRIPTSET', 'more', DEVICE) except Exception as e: @@ -261,7 +293,7 @@ def test_pytorch_scriptset(env): with open(script_filename, 'rb') as f: script = f.read() - ret = con.execute_command('AI.SCRIPTSET', 'ket', DEVICE, script) + ret = con.execute_command('AI.SCRIPTSET', 'ket', DEVICE, 'SOURCE', script) env.assertEqual(ret, b'OK') ensureSlaveSynced(con, env) @@ -269,7 +301,7 @@ def test_pytorch_scriptset(env): with open(script_filename, 'rb') as f: script = f.read() - ret = con.execute_command('AI.SCRIPTSET', 'ket', DEVICE, 'TAG', 'asdf', script) + ret = con.execute_command('AI.SCRIPTSET', 'ket', DEVICE, 'TAG', 'asdf', 'SOURCE', script) env.assertEqual(ret, b'OK') ensureSlaveSynced(con, env) @@ -297,7 +329,7 @@ def test_pytorch_scriptdel(env): with open(script_filename, 'rb') as f: script = f.read() - ret = con.execute_command('AI.SCRIPTSET', 'ket', DEVICE, script) + ret = con.execute_command('AI.SCRIPTSET', 'ket', DEVICE, 'SOURCE', script) env.assertEqual(ret, b'OK') ensureSlaveSynced(con, env) @@ -345,7 +377,7 @@ def test_pytorch_scriptrun(env): with open(script_filename, 'rb') as f: script = f.read() - ret = con.execute_command('AI.SCRIPTSET', 'ket', DEVICE, 'TAG', 'asdf', script) + ret = con.execute_command('AI.SCRIPTSET', 'ket', DEVICE, 'TAG', 'asdf', 'SOURCE', script) env.assertEqual(ret, b'OK') ret = con.execute_command('AI.TENSORSET', 'a', 'FLOAT', 2, 2, 'VALUES', 2, 3, 2, 3) @@ -485,7 +517,7 @@ def test_pytorch_scriptinfo(env): with open(script_filename, 'rb') as f: script = f.read() - ret = con.execute_command('AI.SCRIPTSET', 'ket_script', DEVICE, script) + ret = con.execute_command('AI.SCRIPTSET', 'ket_script', DEVICE, 'SOURCE', script) env.assertEqual(ret, b'OK') ret = con.execute_command('AI.TENSORSET', 'a', 'FLOAT', 2, 2, 'VALUES', 2, 3, 2, 3) @@ -542,7 +574,7 @@ def test_pytorch_scriptrun_disconnect(env): with open(script_filename, 'rb') as f: script = f.read() - ret = con.execute_command('AI.SCRIPTSET', 'ket_script', DEVICE, script) + ret = con.execute_command('AI.SCRIPTSET', 'ket_script', DEVICE, 'SOURCE', script) env.assertEqual(ret, b'OK') ret = con.execute_command('AI.TENSORSET', 'a', 'FLOAT', 2, 2, 'VALUES', 2, 3, 2, 3) @@ -573,7 +605,7 @@ def test_pytorch_modelrun_disconnect(env): with open(model_filename, 'rb') as f: model_pb = f.read() - ret = con.execute_command('AI.MODELSET', 'm', 'TORCH', DEVICE, model_pb) + ret = con.execute_command('AI.MODELSET', 'm', 'TORCH', DEVICE, 'BLOB', model_pb) env.assertEqual(ret, b'OK') ret = con.execute_command('AI.TENSORSET', 'a', 'FLOAT', 2, 2, 'VALUES', 2, 3, 2, 3) @@ -601,10 +633,10 @@ def test_pytorch_modelscan_scriptscan(env): with open(model_filename, 'rb') as f: model_pb = f.read() - ret = con.execute_command('AI.MODELSET', 'm1', 'TORCH', DEVICE, 'TAG', 'm:v1', model_pb) + ret = con.execute_command('AI.MODELSET', 'm1', 'TORCH', DEVICE, 'TAG', 'm:v1', 'BLOB', model_pb) env.assertEqual(ret, b'OK') - ret = con.execute_command('AI.MODELSET', 'm2', 'TORCH', DEVICE, 'TAG', 'm:v1', model_pb) + ret = con.execute_command('AI.MODELSET', 'm2', 'TORCH', DEVICE, 'TAG', 'm:v1', 'BLOB', model_pb) env.assertEqual(ret, b'OK') script_filename = os.path.join(test_data_path, 'script.txt') @@ -612,10 +644,10 @@ def test_pytorch_modelscan_scriptscan(env): with open(script_filename, 'rb') as f: script = f.read() - ret = con.execute_command('AI.SCRIPTSET', 's1', DEVICE, 'TAG', 's:v1', script) + ret = con.execute_command('AI.SCRIPTSET', 's1', DEVICE, 'TAG', 's:v1', 'SOURCE', script) env.assertEqual(ret, b'OK') - ret = con.execute_command('AI.SCRIPTSET', 's2', DEVICE, 'TAG', 's:v1', script) + ret = con.execute_command('AI.SCRIPTSET', 's2', DEVICE, 'TAG', 's:v1', 'SOURCE', script) env.assertEqual(ret, b'OK') ensureSlaveSynced(con, env) @@ -648,7 +680,7 @@ def test_pytorch_model_rdb_save_load(env): con = env.getConnection() - ret = con.execute_command('AI.MODELSET', 'm', 'TORCH', DEVICE, model_pb) + ret = con.execute_command('AI.MODELSET', 'm', 'TORCH', DEVICE, 'BLOB', model_pb) env.assertEqual(ret, b'OK') model_serialized_memory = con.execute_command('AI.MODELGET', 'm', 'BLOB') @@ -674,4 +706,4 @@ def test_pytorch_model_rdb_save_load(env): # Assert in memory tensor data is equal to loaded tensor data env.assertTrue(dtype_memory == dtype_after_rdbload) env.assertTrue(shape_memory == shape_after_rdbload) - env.assertTrue(data_memory == data_after_rdbload) \ No newline at end of file + env.assertTrue(data_memory == data_after_rdbload) diff --git a/test/tests_tensorflow.py b/test/tests_tensorflow.py index 272d69634..ebad693c1 100644 --- a/test/tests_tensorflow.py +++ b/test/tests_tensorflow.py @@ -30,7 +30,7 @@ def test_run_mobilenet(env): model_pb, labels, img = load_mobilenet_test_data() con.execute_command('AI.MODELSET', 'mobilenet', 'TF', DEVICE, - 'INPUTS', input_var, 'OUTPUTS', output_var, model_pb) + 'INPUTS', input_var, 'OUTPUTS', output_var, 'BLOB', model_pb) ensureSlaveSynced(con, env) @@ -99,7 +99,7 @@ def test_run_mobilenet_multiproc(env): model_pb, labels, img = load_mobilenet_test_data() con.execute_command('AI.MODELSET', 'mobilenet', 'TF', DEVICE, - 'INPUTS', input_var, 'OUTPUTS', output_var, model_pb) + 'INPUTS', input_var, 'OUTPUTS', output_var, 'BLOB', model_pb) ensureSlaveSynced(con, env) run_test_multiproc(env, 30, run_mobilenet, (img, input_var, output_var)) @@ -138,7 +138,7 @@ def test_del_tf_model(env): model_pb = f.read() ret = con.execute_command('AI.MODELSET', 'm', 'TF', DEVICE, - 'INPUTS', 'a', 'b', 'OUTPUTS', 'mul', model_pb) + 'INPUTS', 'a', 'b', 'OUTPUTS', 'mul', 'BLOB', model_pb) env.assertEqual(ret, b'OK') ensureSlaveSynced(con, env) @@ -181,7 +181,7 @@ def test_run_tf_model(env): model_pb = f.read() ret = con.execute_command('AI.MODELSET', 'm', 'TF', DEVICE, - 'INPUTS', 'a', 'b', 'OUTPUTS', 'mul', model_pb) + 'INPUTS', 'a', 'b', 'OUTPUTS', 'mul', 'BLOB', model_pb) env.assertEqual(ret, b'OK') ensureSlaveSynced(con, env) @@ -191,7 +191,7 @@ def test_run_tf_model(env): env.assertEqual(ret[-1], b'') ret = con.execute_command('AI.MODELSET', 'm', 'TF', DEVICE, 'TAG', 'asdf', - 'INPUTS', 'a', 'b', 'OUTPUTS', 'mul', model_pb) + 'INPUTS', 'a', 'b', 'OUTPUTS', 'mul', 'BLOB', model_pb) env.assertEqual(ret, b'OK') ensureSlaveSynced(con, env) @@ -252,7 +252,7 @@ def test_run_tf2_model(env): model_pb = f.read() ret = con.execute_command('AI.MODELSET', 'm', 'TF', DEVICE, - 'INPUTS', 'x', 'OUTPUTS', 'Identity', model_pb) + 'INPUTS', 'x', 'OUTPUTS', 'Identity', 'BLOB', model_pb) env.assertEqual(ret, b'OK') ensureSlaveSynced(con, env) @@ -262,7 +262,7 @@ def test_run_tf2_model(env): env.assertEqual(ret[-1], b'') ret = con.execute_command('AI.MODELSET', 'm', 'TF', DEVICE, 'TAG', 'asdf', - 'INPUTS', 'x', 'OUTPUTS', 'Identity', model_pb) + 'INPUTS', 'x', 'OUTPUTS', 'Identity', 'BLOB', model_pb) env.assertEqual(ret, b'OK') ensureSlaveSynced(con, env) @@ -322,7 +322,7 @@ def test_run_tf_model_errors(env): wrong_model_pb = f.read() ret = con.execute_command('AI.MODELSET', 'm', 'TF', DEVICE, - 'INPUTS', 'a', 'b', 'OUTPUTS', 'mul', model_pb) + 'INPUTS', 'a', 'b', 'OUTPUTS', 'mul', 'BLOB', model_pb) env.assertEqual(ret, b'OK') ensureSlaveSynced(con, env) @@ -358,7 +358,7 @@ def test_run_tf_model_errors(env): try: ret = con.execute_command('AI.MODELSET', 'm', 'TF', DEVICE, - 'INPUTS', 'a', 'b', 'OUTPUTS', 'mul', wrong_model_pb) + 'INPUTS', 'a', 'b', 'OUTPUTS', 'mul', 'BLOB', wrong_model_pb) except Exception as e: exception = e env.assertEqual(type(exception), redis.exceptions.ResponseError) @@ -366,15 +366,15 @@ def test_run_tf_model_errors(env): try: con.execute_command('AI.MODELSET', 'm_1', 'TF', - 'INPUTS', 'a', 'b', 'OUTPUTS', 'mul', model_pb) + 'INPUTS', 'a', 'b', 'OUTPUTS', 'mul', 'BLOB', model_pb) except Exception as e: exception = e env.assertEqual(type(exception), redis.exceptions.ResponseError) - env.assertEqual("INPUTS not specified", exception.__str__()) + env.assertEqual("Invalid DEVICE", exception.__str__()) try: con.execute_command('AI.MODELSET', 'm_2', 'PORCH', DEVICE, - 'INPUTS', 'a', 'b', 'OUTPUTS', 'mul', model_pb) + 'INPUTS', 'a', 'b', 'OUTPUTS', 'mul', 'BLOB', model_pb) except Exception as e: exception = e env.assertEqual(type(exception), redis.exceptions.ResponseError) @@ -382,22 +382,22 @@ def test_run_tf_model_errors(env): try: con.execute_command('AI.MODELSET', 'm_3', 'TORCH', DEVICE, - 'INPUTS', 'a', 'b', 'OUTPUTS', 'mul', model_pb) + 'INPUTS', 'a', 'b', 'OUTPUTS', 'mul', 'BLOB', model_pb) except Exception as e: exception = e env.assertEqual(type(exception), redis.exceptions.ResponseError) try: con.execute_command('AI.MODELSET', 'm_4', 'TF', - 'INPUTS', 'a', 'b', 'OUTPUTS', 'mul', model_pb) + 'INPUTS', 'a', 'b', 'OUTPUTS', 'mul', 'BLOB', model_pb) except Exception as e: exception = e env.assertEqual(type(exception), redis.exceptions.ResponseError) - env.assertEqual("INPUTS not specified", exception.__str__()) + env.assertEqual("Invalid DEVICE", exception.__str__()) try: con.execute_command('AI.MODELSET', 'm_5', 'TF', DEVICE, - 'INPUTS', 'a', 'b', 'c', 'OUTPUTS', 'mul', model_pb) + 'INPUTS', 'a', 'b', 'c', 'OUTPUTS', 'mul', 'BLOB', model_pb) except Exception as e: exception = e env.assertEqual(type(exception), redis.exceptions.ResponseError) @@ -405,14 +405,14 @@ def test_run_tf_model_errors(env): try: con.execute_command('AI.MODELSET', 'm_6', 'TF', DEVICE, - 'INPUTS', 'a', 'b', 'OUTPUTS', 'mult', model_pb) + 'INPUTS', 'a', 'b', 'OUTPUTS', 'mult', 'BLOB', model_pb) except Exception as e: exception = e env.assertEqual(type(exception), redis.exceptions.ResponseError) env.assertEqual("Output node named \"mult\" not found in TF graph", exception.__str__()) try: - con.execute_command('AI.MODELSET', 'm_7', 'TF', DEVICE, model_pb) + con.execute_command('AI.MODELSET', 'm_7', 'TF', DEVICE, 'BLOB', model_pb) except Exception as e: exception = e env.assertEqual(type(exception), redis.exceptions.ResponseError) @@ -424,7 +424,7 @@ def test_run_tf_model_errors(env): except Exception as e: exception = e env.assertEqual(type(exception), redis.exceptions.ResponseError) - env.assertEqual("Invalid GraphDef", exception.__str__()) + env.assertEqual("Insufficient arguments, missing model BLOB", exception.__str__()) try: con.execute_command('AI.MODELSET', 'm_8', 'TF', DEVICE, @@ -432,7 +432,7 @@ def test_run_tf_model_errors(env): except Exception as e: exception = e env.assertEqual(type(exception), redis.exceptions.ResponseError) - env.assertEqual("Invalid GraphDef", exception.__str__()) + env.assertEqual("Insufficient arguments, missing model BLOB", exception.__str__()) try: con.execute_command('AI.MODELSET', 'm_8', 'TF', DEVICE, @@ -440,16 +440,15 @@ def test_run_tf_model_errors(env): except Exception as e: exception = e env.assertEqual(type(exception), redis.exceptions.ResponseError) - env.assertEqual("Invalid GraphDef", exception.__str__()) + env.assertEqual("Insufficient arguments, missing model BLOB", exception.__str__()) - # ERR Invalid GraphDef try: con.execute_command('AI.MODELSET', 'm_8', 'TF', DEVICE, 'INPUTS', 'a', 'b', 'OUTPUTS') except Exception as e: exception = e env.assertEqual(type(exception), redis.exceptions.ResponseError) - env.assertEqual("Invalid GraphDef",exception.__str__()) + env.assertEqual("Insufficient arguments, missing model BLOB",exception.__str__()) try: con.execute_command('AI.MODELRUN', 'm', 'INPUTS', 'a', 'b') @@ -481,7 +480,7 @@ def test_run_tf_model_autobatch(env): ret = con.execute_command('AI.MODELSET', 'm', 'TF', 'CPU', 'BATCHSIZE', 4, 'MINBATCHSIZE', 3, - 'INPUTS', 'a', 'b', 'OUTPUTS', 'mul', model_pb) + 'INPUTS', 'a', 'b', 'OUTPUTS', 'mul', 'BLOB', model_pb) env.assertEqual(ret, b'OK') con.execute_command('AI.TENSORSET', 'a', 'FLOAT', @@ -526,7 +525,7 @@ def test_tensorflow_modelinfo(env): model_pb = f.read() ret = con.execute_command('AI.MODELSET', 'm', 'TF', DEVICE, - 'INPUTS', 'a', 'b', 'OUTPUTS', 'mul', model_pb) + 'INPUTS', 'a', 'b', 'OUTPUTS', 'mul', 'BLOB', model_pb) env.assertEqual(ret, b'OK') info = con.execute_command('AI.INFO', 'm') # Getting initial info before modelrun info_dict0 = info_to_dict(info) @@ -536,7 +535,7 @@ def test_tensorflow_modelinfo(env): # second modelset; a corner case ret = con.execute_command('AI.MODELSET', 'm', 'TF', DEVICE, - 'INPUTS', 'a', 'b', 'OUTPUTS', 'mul', model_pb) + 'INPUTS', 'a', 'b', 'OUTPUTS', 'mul', 'BLOB', model_pb) env.assertEqual(ret, b'OK') info = con.execute_command('AI.INFO', 'm') # this will fail info_dict1 = info_to_dict(info) @@ -594,7 +593,7 @@ def test_tensorflow_modelrun_disconnect(env): model_pb = f.read() ret = red.execute_command('AI.MODELSET', 'm', 'TF', DEVICE, - 'INPUTS', 'a', 'b', 'OUTPUTS', 'mul', model_pb) + 'INPUTS', 'a', 'b', 'OUTPUTS', 'mul', 'BLOB', model_pb) env.assertEqual(ret, b'OK') ret = red.execute_command( @@ -628,7 +627,7 @@ def test_tensorflow_modelrun_with_batch_and_minbatch(env): 'BATCHSIZE', batch_size, 'MINBATCHSIZE', minbatch_size, 'INPUTS', inputvar, 'OUTPUTS', outputvar, - model_pb) + 'BLOB', model_pb) con.execute_command('AI.TENSORSET', 'input', 'FLOAT', 1, img.shape[1], img.shape[0], img.shape[2], 'BLOB', img.tobytes()) @@ -651,7 +650,7 @@ def run(name=model_name, output_name='output'): 'BATCHSIZE', batch_size, 'MINBATCHSIZE', minbatch_size, 'INPUTS', inputvar, 'OUTPUTS', outputvar, - model_pb) + 'BLOB', model_pb) p1 = mp.Process(target=run, args=(another_model_name, 'final1')) p1.start() @@ -694,7 +693,7 @@ def test_tensorflow_modelrun_financialNet(env): tensor_number = tensor_number + 1 ret = con.execute_command('AI.MODELSET', 'financialNet', 'TF', DEVICE, - 'INPUTS', 'transaction', 'reference', 'OUTPUTS', 'output', model_pb) + 'INPUTS', 'transaction', 'reference', 'OUTPUTS', 'output', 'BLOB', model_pb) env.assertEqual(ret, b'OK') for tensor_number in range(1, 10001): @@ -728,7 +727,7 @@ def test_tensorflow_modelrun_financialNet_multiproc(env): tensor_number = tensor_number + 1 ret = con.execute_command('AI.MODELSET', 'financialNet', 'TF', DEVICE, - 'INPUTS', 'transaction', 'reference', 'OUTPUTS', 'output', model_pb) + 'INPUTS', 'transaction', 'reference', 'OUTPUTS', 'output', 'BLOB', model_pb) env.assertEqual(ret, b'OK') def functor_financialNet(env, key_max, repetitions): diff --git a/test/tests_tflite.py b/test/tests_tflite.py index 4c6c0c7db..4034af4a5 100644 --- a/test/tests_tflite.py +++ b/test/tests_tflite.py @@ -31,14 +31,14 @@ def test_run_tflite_model(env): with open(sample_filename, 'rb') as f: sample_raw = f.read() - ret = con.execute_command('AI.MODELSET', 'm', 'TFLITE', 'CPU', model_pb) + ret = con.execute_command('AI.MODELSET', 'm', 'TFLITE', 'CPU', 'BLOB', model_pb) env.assertEqual(ret, b'OK') ret = con.execute_command('AI.MODELGET', 'm', 'META') env.assertEqual(len(ret), 6) env.assertEqual(ret[-1], b'') - ret = con.execute_command('AI.MODELSET', 'm', 'TFLITE', 'CPU', 'TAG', 'asdf', model_pb) + ret = con.execute_command('AI.MODELSET', 'm', 'TFLITE', 'CPU', 'TAG', 'asdf', 'BLOB', model_pb) env.assertEqual(ret, b'OK') ret = con.execute_command('AI.MODELGET', 'm', 'META') @@ -89,10 +89,10 @@ def test_run_tflite_model_errors(env): with open(sample_filename, 'rb') as f: sample_raw = f.read() - ret = con.execute_command('AI.MODELSET', 'm_2', 'TFLITE', 'CPU', model_pb2) + ret = con.execute_command('AI.MODELSET', 'm_2', 'TFLITE', 'CPU', 'BLOB', model_pb2) env.assertEqual(ret, b'OK') - ret = con.execute_command('AI.MODELSET', 'm', 'TFLITE', 'CPU', 'TAG', 'asdf', model_pb) + ret = con.execute_command('AI.MODELSET', 'm', 'TFLITE', 'CPU', 'TAG', 'asdf', 'BLOB', model_pb) env.assertEqual(ret, b'OK') ret = con.execute_command('AI.TENSORSET', 'a', 'FLOAT', 1, 1, 28, 28, 'BLOB', sample_raw) @@ -108,11 +108,11 @@ def test_run_tflite_model_errors(env): env.assertEqual("Insufficient arguments, missing model BLOB", exception.__str__()) try: - con.execute_command('AI.MODELSET', 'm_2', model_pb) + con.execute_command('AI.MODELSET', 'm_2', 'BLOB', model_pb) except Exception as e: exception = e env.assertEqual(type(exception), redis.exceptions.ResponseError) - env.assertEqual("wrong number of arguments for 'AI.MODELSET' command", exception.__str__()) + env.assertEqual("unsupported backend", exception.__str__()) try: con.execute_command('AI.MODELRUN', 'm_2', 'INPUTS', 'EMPTY_TENSOR', 'OUTPUTS') @@ -213,7 +213,7 @@ def test_run_tflite_model_autobatch(env): try: ret = con.execute_command('AI.MODELSET', 'm', 'TFLITE', 'CPU', - 'BATCHSIZE', 2, 'MINBATCHSIZE', 2, model_pb) + 'BATCHSIZE', 2, 'MINBATCHSIZE', 2, 'BLOB', model_pb) except Exception as e: exception = e env.assertEqual(type(exception), redis.exceptions.ResponseError) @@ -262,7 +262,7 @@ def test_tflite_modelinfo(env): with open(sample_filename, 'rb') as f: sample_raw = f.read() - ret = con.execute_command('AI.MODELSET', 'mnist', 'TFLITE', 'CPU', model_pb) + ret = con.execute_command('AI.MODELSET', 'mnist', 'TFLITE', 'CPU', 'BLOB', model_pb) env.assertEqual(ret, b'OK') ret = con.execute_command('AI.TENSORSET', 'a', 'FLOAT', 1, 1, 28, 28, 'BLOB', sample_raw) @@ -316,7 +316,7 @@ def test_tflite_modelrun_disconnect(env): with open(sample_filename, 'rb') as f: sample_raw = f.read() - ret = red.execute_command('AI.MODELSET', 'mnist', 'TFLITE', 'CPU', model_pb) + ret = red.execute_command('AI.MODELSET', 'mnist', 'TFLITE', 'CPU', 'BLOB', model_pb) env.assertEqual(ret, b'OK') ret = red.execute_command('AI.TENSORSET', 'a', 'FLOAT', 1, 1, 28, 28, 'BLOB', sample_raw) @@ -341,7 +341,7 @@ def test_tflite_model_rdb_save_load(env): with open(model_filename, 'rb') as f: model_pb = f.read() - ret = con.execute_command('AI.MODELSET', 'mnist', 'TFLITE', 'CPU', model_pb) + ret = con.execute_command('AI.MODELSET', 'mnist', 'TFLITE', 'CPU', 'BLOB', model_pb) env.assertEqual(ret, b'OK') model_serialized_memory = con.execute_command('AI.MODELGET', 'mnist', 'BLOB') @@ -359,4 +359,4 @@ def test_tflite_model_rdb_save_load(env): # Assert in memory model binary is equal to loaded model binary env.assertTrue(model_serialized_memory == model_serialized_after_rdbload) # Assert input model binary is equal to loaded model binary - env.assertTrue(model_pb == model_serialized_after_rdbload) \ No newline at end of file + env.assertTrue(model_pb == model_serialized_after_rdbload)