ryandu
ryandu

Reputation: 647

AttributeError: 'list' object has no attribute 'rank' When converting Keras Model To CoreML

I am trying to convert my Keras model that contains GRU layers to generate Shakespeares text to a coreml model, although when I try to convert it, I get the error "AttributeError: 'list' object has no attribute 'rank'". I followed the instructions on this website. Here is my code:

import tensorflow as tf
from tensorflow import keras
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import coremltools as ct
model = keras.models.load_model("checkpointshakespear.h5")
mlmodel = ct.convert(model)

This is my model layer:

model = keras.models.Sequential([
    keras.layers.GRU(128, return_sequences=True, input_shape=[None, max_id],
                 dropout=0.2, recurrent_dropout=0.2),
    keras.layers.GRU(128, return_sequences=True,
                 dropout=0.2, recurrent_dropout=0.2),
    keras.layers.TimeDistributed(keras.layers.Dense(max_id,
                                                activation="softmax"))
])
model.compile(loss="sparse_categorical_crossentropy", optimizer="adam")

This is the full error:

    Running TensorFlow Graph Passes: 100%|██████████| 5/5 [00:00<00:00,  9.78 passes/s]
Converting Frontend ==> MIL Ops:   0%|          | 0/84 [00:00<?, ? ops/s]
Converting Frontend ==> MIL Ops:   0%|          | 0/95 [00:00<?, ? ops/s]
Converting Frontend ==> MIL Ops:   0%|          | 0/84 [00:00<?, ? ops/s]
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-2-8240f4ae502a> in <module>
      6 import coremltools as ct
      7 model = keras.models.load_model("checkpointshakespear.h5")
----> 8 mlmodel = ct.convert(model)

~/opt/anaconda3/lib/python3.7/site-packages/coremltools/converters/_converters_entry.py in convert(model, source, inputs, outputs, classifier_config, minimum_deployment_target, **kwargs)
    256             outputs=outputs,
    257             classifier_config=classifier_config,
--> 258             **kwargs
    259         )
    260 

~/opt/anaconda3/lib/python3.7/site-packages/coremltools/converters/mil/converter.py in _convert(model, convert_from, convert_to, converter_registry, **kwargs)
    118     backend_converter = backend_converter_type()
    119 
--> 120     prog = frontend_converter(model, **kwargs)
    121     common_pass(prog)
    122     out = backend_converter(prog, **kwargs)

~/opt/anaconda3/lib/python3.7/site-packages/coremltools/converters/mil/converter.py in __call__(self, *args, **kwargs)
     50 
     51         tf2_loader = TF2Loader(*args, **kwargs)
---> 52         return tf2_loader.load()
     53 
     54 

~/opt/anaconda3/lib/python3.7/site-packages/coremltools/converters/mil/frontend/tensorflow/load.py in load(self)
     78             )
     79 
---> 80         program = self._program_from_tf_ssa()
     81         logging.debug("program:\n{}".format(program))
     82         return program

~/opt/anaconda3/lib/python3.7/site-packages/coremltools/converters/mil/frontend/tensorflow2/load.py in _program_from_tf_ssa(self)
    179 
    180         converter = TF2Converter(self._tf_ssa, **self.kwargs)
--> 181         return converter.convert()
    182 
    183     def _populate_sub_graph_input_shapes(self, graph, graph_fns):

~/opt/anaconda3/lib/python3.7/site-packages/coremltools/converters/mil/frontend/tensorflow/converter.py in convert(self)
    392         for g_name in self.graph_stack[1:]:
    393             self.context.add_graph(g_name, self.tfssa.functions[g_name].graph)
--> 394         self.convert_main_graph(prog, graph)
    395 
    396         # Apply TF frontend passes on Program. These passes are different

~/opt/anaconda3/lib/python3.7/site-packages/coremltools/converters/mil/frontend/tensorflow/converter.py in convert_main_graph(self, prog, graph)
    337             for name in func_inputs.keys():
    338                 self.context.add(name, ssa_func.inputs[name])
--> 339             outputs = convert_graph(self.context, graph, self.outputs)
    340             ssa_func.set_outputs(outputs)
    341             prog.add_function("main", ssa_func)

~/opt/anaconda3/lib/python3.7/site-packages/coremltools/converters/mil/frontend/tensorflow/convert_utils.py in convert_graph(context, graph, outputs)
    179             )
    180             raise NotImplementedError(msg)
--> 181         _add_op(context, node)
    182 
    183         if len(node.outputs) > 0:

~/opt/anaconda3/lib/python3.7/site-packages/coremltools/converters/mil/frontend/tensorflow2/ops.py in StatelessWhile(context, node)
     98         return body_output_vars
     99 
--> 100     x = mb.while_loop(_cond=cond, _body=body, loop_vars=loop_vars, name=node.name)
    101 
    102     # wraps x as tuple for get_tuple that always follow the while node.

~/opt/anaconda3/lib/python3.7/site-packages/coremltools/converters/mil/mil/ops/registry.py in add_op(cls, **kwargs)
     60             @classmethod
     61             def add_op(cls, **kwargs):
---> 62                 return cls._add_op(op_cls, **kwargs)
     63 
     64             setattr(Builder, op_type, add_op)

~/opt/anaconda3/lib/python3.7/site-packages/coremltools/converters/mil/mil/builder.py in _add_op(cls, op_cls, **kwargs)
    188         new_op = op_cls(**kwargs)
    189         curr_block()._insert_op_before(new_op, before_op=before_op)
--> 190         new_op.build_nested_blocks()
    191         new_op.type_value_inference()
    192         if len(new_op.outputs) == 1:

~/opt/anaconda3/lib/python3.7/site-packages/coremltools/converters/mil/mil/ops/defs/control_flow.py in build_nested_blocks(self)
    302             v.consuming_blocks = list()
    303 
--> 304         block, exit_vars = self.build_block(block_inputs)
    305 
    306         # Verify exit_vars has the same types as loop_vars

~/opt/anaconda3/lib/python3.7/site-packages/coremltools/converters/mil/mil/ops/defs/control_flow.py in build_block(self, block_inputs)
    271             # Body func
    272             body_func = self._body.val
--> 273             exit_vars = body_func(*block.inputs)
    274 
    275             # Cond func:

~/opt/anaconda3/lib/python3.7/site-packages/coremltools/converters/mil/frontend/tensorflow2/ops.py in body(*loop_vars)
     94     def body(*loop_vars):
     95         context.stack_func_inputs(loop_vars)
---> 96         body_output_vars = convert_graph(context, body_graph)
     97         context.unstack_func_inputs()
     98         return body_output_vars

~/opt/anaconda3/lib/python3.7/site-packages/coremltools/converters/mil/frontend/tensorflow/convert_utils.py in convert_graph(context, graph, outputs)
    179             )
    180             raise NotImplementedError(msg)
--> 181         _add_op(context, node)
    182 
    183         if len(node.outputs) > 0:

~/opt/anaconda3/lib/python3.7/site-packages/coremltools/converters/mil/frontend/tensorflow/ops.py in StridedSlice(context, node)
   1351         squeeze_mask,
   1352         ellipsis_mask,
-> 1353         new_axis_mask,
   1354     )
   1355 

~/opt/anaconda3/lib/python3.7/site-packages/coremltools/converters/mil/frontend/tensorflow/ops.py in _pad_mask(x, begin, end, stride, begin_mask, end_mask, squeeze_mask, ellipsis_mask, new_axis_mask)
   1257             x_rank = x.rank + new_dims
   1258         else:
-> 1259             x_rank = x.rank
   1260 
   1261         def pad_array(arr, max_rank, idx, default_value):

AttributeError: 'list' object has no attribute 'rank'

Upvotes: 2

Views: 1166

Answers (1)

Iswariya Manivannan
Iswariya Manivannan

Reputation: 724

Looks like the error is because of the recurrent_dropout parameter. Removing this parameter solves the error.

Also note that I have added batch_size parameter to the first GRU layer. This is necessary because CoreML inputs should be either rank 3 (Seq,B,C) or rank 5 (Seq,B,C,H,W) for RNNs.

This is the working code snippet.

import tensorflow.keras as keras
import coremltools as ct

max_id = 1000

model = keras.models.Sequential([
    keras.layers.GRU(128, return_sequences=True, input_shape=[None, max_id], batch_size=64,
                 dropout=0.2),
    keras.layers.GRU(128, return_sequences=True,
                dropout=0.2),
    keras.layers.TimeDistributed(keras.layers.Dense(max_id,
                                                activation="softmax"))
])

model.save('tf_keras_model.h5')
mlmodel = ct.convert('tf_keras_model.h5', source="tensorflow")

Upvotes: 1

Related Questions