Reputation: 647
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
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