RedisAI / JRedisAI

Java client for RedisAI
https://redisai.io
BSD 3-Clause "New" or "Revised" License
12 stars 4 forks source link

ai.setTensor with tensor of doubles throws casting exception #54

Open bsbodden opened 3 years ago

bsbodden commented 3 years ago

In this branch https://github.com/redis-developer/redisai-iris/pull/1 I have an updated example of creating a SciKit model, train it, and converting it into a Pytorch's TorchScript model using MS Hummingbird.ml.

Here's an example of the converted Torch model working in RedisAI via the CLI:

$ redis-cli -x AI.MODELSTORE iris TORCH CPU BLOB < iris.pt
AI.TENSORSET iris:in FLOAT 2 4 VALUES 5.0 3.4 1.6 0.4 6.0 2.2 5.0 1.5
AI.MODELEXECUTE iris INPUTS 1 iris:in OUTPUTS 2 iris:inferences iris:scores

AI.TENSORGET iris:inferences VALUES
    1) (integer) 0
    2) (integer) 2

AI.TENSORGET iris:scores VALUES
    1) "0.96567678451538086"
    2) "0.034322910010814667"
    3) "3.4662525649764575e-07"
    4) "0.00066925224382430315"
    5) "0.45369619131088257"
    6) "0.54563456773757935"

In JRedisAI I am trying the following:

 @Test
  public void testTorchScriptModelRun() {
    // $ redis-cli -x AI.MODELSTORE iris TORCH CPU BLOB < iris.pt
    AIOperations<String> ai = modulesOperations.opsForAI();

    ClassLoader classLoader = getClass().getClassLoader();
    File file = new File(classLoader.getResource("ai/iris.pt").getFile());
    String modelPath = file.getAbsolutePath();

    ai.setModel("iris-torch", Backend.TORCH, Device.CPU, new String[] {"iris:in"}, new String[] {"iris:inferences", "iris:scores"}, modelPath);

    // AI.TENSORSET iris:in FLOAT 2 4 VALUES 5.0 3.4 1.6 0.4 6.0 2.2 5.0 1.5
    ai.setTensor("iris:in", new double[] {5.0, 3.4, 1.6, 0.4, 6.0, 2.2, 5.0, 1.5}, new int[]{2, 4});

    // AI.MODELEXECUTE iris INPUTS 1 iris:in OUTPUTS 2 iris:inferences iris:scores
    Assert.assertTrue(ai.runModel("iris-torch", new String[] {"iris:in"}, new String[] {"iris:inferences", "iris:scores"}));

    //    Check the predictions:
    Tensor inferences = ai.getTensor("iris:inferences");
    float[] values = (float[]) inferences.getValues();
    float[] expected = new float[] {0, 2};

    Assert.assertEquals("Assert same shape of values", 2, values.length);
    Assert.assertArrayEquals(expected, values, (float) 0.1);
  }

I get the following ClassCastException from the ai.setTensor("iris:in", new double[] {5.0, 3.4, 1.6, 0.4, 6.0, 2.2, 5.0, 1.5}, new int[]{2, 4}); line:

java.lang.ClassCastException: class java.lang.Double cannot be cast to class [D (java.lang.Double and [D are in module java.base of loader 'bootstrap')
    at com.redislabs.redisai.DataType$4.toByteArray(DataType.java:75)
    at com.redislabs.redisai.DataType.toByteArray(DataType.java:151)
    at com.redislabs.redisai.DataType.toByteArray(DataType.java:148)
    at com.redislabs.redisai.DataType.toByteArray(DataType.java:165)
    at com.redislabs.redisai.Tensor.tensorSetFlatArgs(Tensor.java:111)
    at com.redislabs.redisai.RedisAI.setTensor(RedisAI.java:126)
    at com.redislabs.redisai.RedisAI.setTensor(RedisAI.java:114)
    at com.redislabs.spring.ai.AIOperationsImpl.setTensor(AIOperationsImpl.java:24)
    at com.redislabs.spring.OpsForAITest.testTorchScriptModelRun(OpsForAITest.java:57)
...

Any hints on how to write this particular input Tensor would be appreciated. Thanks!

DvirDukhan commented 3 years ago

Thanks, @bsbodden we will check this

bsbodden commented 3 years ago

Thanks @sazzad16 ....

For posterity, the answer is:

// AI.TENSORSET iris:in FLOAT 2 4 VALUES 5.0 3.4 1.6 0.4 6.0 2.2 5.0 1.5
ai.setTensor("iris:in", new double[][] {{5.0, 3.4, 1.6, 0.4}, {6.0, 2.2, 5.0, 1.5}}, new int[]{2, 4});