tensorflowtensorflow-federated

tensorflow federated : TypeError when using customized dataset and model


I am following the tutorial 'Federated Learning for Image Classification', but using my own dataset and resnet50. I got this error, when running iterative_process.next.

I believe it was caused by tf.data.Dataset.from_generator here is my code:


par1_train_data_dir = './par1/train'
par2_train_data_dir = './par2/train'
input_shape = (img_height, img_width, 3)

img_gen = ImageDataGenerator(preprocessing_function=preprocess_input)

ds_par1 = tf.data.Dataset.from_generator(
    img_gen.flow_from_directory,  args=[par1_train_data_dir,(img_height,img_width)],
    output_types=(tf.float32, tf.float32), 
    output_shapes=([batch_size,img_height,img_width,3], [batch_size,num_classes])
)
ds_par2 = tf.data.Dataset.from_generator(
    img_gen.flow_from_directory,  args=[par2_train_data_dir,(img_height,img_width)],
    output_types=(tf.float32, tf.float32), 
    output_shapes=([batch_size,img_height,img_width,3], [batch_size,num_classes])
)

dataset_dict={}
dataset_dict['1'] = ds_par1
dataset_dict['2'] = ds_par2

def create_tf_dataset_for_client_fn(client_id):
    return dataset_dict[client_id]

train_data = tff.simulation.ClientData.from_clients_and_fn(['1','2'],create_tf_dataset_for_client_fn)

def make_federated_data(client_data, client_ids):
    return [client_data.create_tf_dataset_for_client(x)
          for x in client_ids]

federated_train_data = make_federated_data(train_data, train_data.client_ids)

images, labels = next(img_gen.flow_from_directory(par1_train_data_dir,batch_size=batch_size,target_size=(img_height,img_width)))
sample_batch = (images,labels)

def create_compiled_keras_model():
    pretrain_model = tf.keras.applications.resnet.ResNet50(include_top=False, weights='imagenet', 
                                                input_tensor=tf.keras.layers.Input(shape=(img_height, 
                                                img_width, 3)), pooling=None)

    Inp = Input((img_height, img_width, 3))
    x = pretrain_model(Inp)

    x = GlobalAveragePooling2D()(x)
    x = Dense(1024, activation='relu')(x)
    predictions = Dense(10, activation='softmax')(x)
    model = Model(inputs=Inp, outputs=predictions,name='resnet50_transfer')    

    model.compile(
      loss=tf.keras.losses.categorical_crossentropy,
      optimizer=tf.keras.optimizers.SGD(learning_rate=0.02))
    return model

def model_fn():
    keras_model = create_compiled_keras_model()
    return tff.learning.from_compiled_keras_model(keras_model, sample_batch)

iterative_process = tff.learning.build_federated_averaging_process(model_fn)
state = iterative_process.initialize()

NUM_ROUNDS = 11
for round_num in range(2, NUM_ROUNDS):
    state, metrics = iterative_process.next(state, federated_train_data)
    print('round {:2d}, metrics={}'.format(round_num, metrics))

I got the error InvalidArgumentError: TypeError: endswith first arg must be bytes or a tuple of bytes, not str here is more information

InvalidArgumentError                      Traceback (most recent call last)
<ipython-input-48-b01b66dc0dcd> in <module>
      1 NUM_ROUNDS = 11
      2 for round_num in range(2, NUM_ROUNDS):
----> 3     state, metrics = iterative_process.next(state, federated_train_data)
      4     print('round {:2d}, metrics={}'.format(round_num, metrics))

~/miniconda3/lib/python3.6/site-packages/tensorflow_federated/python/core/impl/utils/function_utils.py in __call__(self, *args, **kwargs)

~/miniconda3/lib/python3.6/site-packages/tensorflow_federated/python/core/impl/utils/function_utils.py in pack_args(parameter_type, args, kwargs, context)

~/miniconda3/lib/python3.6/site-packages/tensorflow_federated/python/core/impl/utils/function_utils.py in pack_args_into_anonymous_tuple(args, kwargs, type_spec, context)

~/miniconda3/lib/python3.6/site-packages/tensorflow_federated/python/core/impl/reference_executor.py in ingest(self, arg, type_spec)
    627         intrinsic_defs.FEDERATED_MEAN.uri:
    628             self._federated_mean,
--> 629         intrinsic_defs.FEDERATED_BROADCAST.uri:
    630             self._federated_broadcast,
    631         intrinsic_defs.FEDERATED_COLLECT.uri:

~/miniconda3/lib/python3.6/site-packages/tensorflow_federated/python/core/impl/reference_executor.py in to_representation_for_type(value, type_spec, callable_handler)
    239     else:
    240       return [
--> 241           to_representation_for_type(v, type_spec.member, callable_handler)
    242           for v in value
    243       ]

~/miniconda3/lib/python3.6/site-packages/tensorflow_federated/python/core/impl/reference_executor.py in <listcomp>(.0)
    239     else:
    240       return [
--> 241           to_representation_for_type(v, type_spec.member, callable_handler)
    242           for v in value
    243       ]

~/miniconda3/lib/python3.6/site-packages/tensorflow_federated/python/core/impl/reference_executor.py in to_representation_for_type(value, type_spec, callable_handler)
    198       if tf.executing_eagerly():
    199         return [
--> 200             to_representation_for_type(v, type_spec.element, callable_handler)
    201             for v in value
    202         ]

~/miniconda3/lib/python3.6/site-packages/tensorflow_federated/python/core/impl/reference_executor.py in <listcomp>(.0)
    197     if isinstance(value, tf.data.Dataset):
    198       if tf.executing_eagerly():
--> 199         return [
    200             to_representation_for_type(v, type_spec.element, callable_handler)
    201             for v in value

~/miniconda3/lib/python3.6/site-packages/tensorflow_core/python/data/ops/iterator_ops.py in __next__(self)
    620 
    621   def __next__(self):  # For Python 3 compatibility
--> 622     return self.next()
    623 
    624   def _next_internal(self):

~/miniconda3/lib/python3.6/site-packages/tensorflow_core/python/data/ops/iterator_ops.py in next(self)
    664     """Returns a nested structure of `Tensor`s containing the next element."""
    665     try:
--> 666       return self._next_internal()
    667     except errors.OutOfRangeError:
    668       raise StopIteration

~/miniconda3/lib/python3.6/site-packages/tensorflow_core/python/data/ops/iterator_ops.py in _next_internal(self)
    649             self._iterator_resource,
    650             output_types=self._flat_output_types,
--> 651             output_shapes=self._flat_output_shapes)
    652 
    653       try:

~/miniconda3/lib/python3.6/site-packages/tensorflow_core/python/ops/gen_dataset_ops.py in iterator_get_next_sync(iterator, output_types, output_shapes, name)
   2671   _ctx = _context._context or _context.context()
   2672   if _ctx is not None and _ctx._thread_local_data.is_eager:
-> 2673     try:
   2674       _result = _pywrap_tensorflow.TFE_Py_FastPathExecute(
   2675         _ctx._context_handle, _ctx._thread_local_data.device_name,

~/miniconda3/lib/python3.6/site-packages/six.py in raise_from(value, from_value)

InvalidArgumentError: TypeError: endswith first arg must be bytes or a tuple of bytes, not str
Traceback (most recent call last):

  File "/root/miniconda3/lib/python3.6/site-packages/tensorflow_core/python/data/ops/dataset_ops.py", line 464, in get_iterator
    self._next_id += 1

KeyError: 2


During handling of the above exception, another exception occurred:


Traceback (most recent call last):

  File "/root/miniconda3/lib/python3.6/site-packages/tensorflow_core/python/ops/script_ops.py", line 221, in __call__
    """

  File "/root/miniconda3/lib/python3.6/site-packages/tensorflow_core/python/data/ops/dataset_ops.py", line 585, in generator_py_func

  File "/root/miniconda3/lib/python3.6/site-packages/tensorflow_core/python/data/ops/dataset_ops.py", line 466, in get_iterator
    # NOTE(mrry): Explicitly create an array of `np.int64` because implicit

  File "/root/miniconda3/lib/python3.6/site-packages/keras_preprocessing/image/image_data_generator.py", line 540, in flow_from_directory
    interpolation=interpolation

  File "/root/miniconda3/lib/python3.6/site-packages/keras_preprocessing/image/directory_iterator.py", line 126, in __init__
    classes, filenames = res.get()

  File "/root/miniconda3/lib/python3.6/multiprocessing/pool.py", line 644, in get
    raise self._value

  File "/root/miniconda3/lib/python3.6/multiprocessing/pool.py", line 119, in worker
    result = (True, func(*args, **kwds))

  File "/root/miniconda3/lib/python3.6/site-packages/keras_preprocessing/image/utils.py", line 216, in _list_valid_filenames_in_directory
    for root, fname in valid_files:

  File "/root/miniconda3/lib/python3.6/site-packages/keras_preprocessing/image/utils.py", line 172, in _iter_valid_files
    if fname.lower().endswith('.tiff'):

TypeError: endswith first arg must be bytes or a tuple of bytes, not str


     [[{{node PyFunc}}]] [Op:IteratorGetNextSync]

my environment

tensorboard==1.15.0
tensorcache==0.4.2
tensorflow==1.15.2
tensorflow-addons==0.6.0
tensorflow-estimator==1.15.1
tensorflow-federated==0.4.0

UPDATE

I've upgraded tf==2.1.0 and tff==0.12.0, the error disappeared, but I got another error.

It seems that the generator reaches the last batch and does not match the input shape.

But ImageDataGenerator does not need to set drop_remainder.Is there anything wrong with my code?

InvalidArgumentError:  ValueError: `generator` yielded an element of shape (50, 224, 224, 3) where an element of shape (64, 224, 224, 3) was expected.
Traceback (most recent call last):

  File "/root/miniconda3/lib/python3.6/site-packages/tensorflow_core/python/ops/script_ops.py", line 236, in __call__
    ret = func(*args)

  File "/root/miniconda3/lib/python3.6/site-packages/tensorflow_core/python/data/ops/dataset_ops.py", line 825, in generator_py_func
    "of shape %s was expected." % (ret_array.shape, expected_shape))

ValueError: `generator` yielded an element of shape (50, 224, 224, 3) where an element of shape (64, 224, 224, 3) was expected.


     [[{{node PyFunc}}]]
     [[import/StatefulPartitionedCall_1/ReduceDataset]] [Op:__inference_wrapped_function_277930]

Function call stack:
wrapped_function

Solution

  • TensorFlow Federated version 0.4.0 has only been tested to work with TensorFlow version 1.13.1 (see the TensorFlow Federated Compatibility table). Is it possible to upgrade to the newest 0.12.0 version of TensorFlow Federated?

    UPDATE:

    I believe your analysis is correct, the code is setting up a dataset from a generator that expects to produce exactly batch_size batches, but is receiving a batch of different size from the img_gen.flow_from_directory generator.

    During setup of the dataset, passing None for the batchsize to indicate that the batch size may be variable could possibly work.

    Concretely, change these lines:

    ... = tf.data.Dataset.from_generator(
        img_gen.flow_from_directory,  args=[par1_train_data_dir,(img_height,img_width)],
        output_types=(tf.float32, tf.float32), 
        output_shapes=([batch_size,img_height,img_width,3], [batch_size,num_classes])
    )
    

    To:

    ... = tf.data.Dataset.from_generator(
        img_gen.flow_from_directory,  args=[par1_train_data_dir,(img_height,img_width)],
        output_types=(tf.float32, tf.float32), 
        output_shapes=([None,img_height,img_width,3], [None,num_classes])
    )