tensorflow: TF 2.2.0: Error with model.fit; class_weight is only supported for Models with a single output.

System information

  • Have I written custom code (as opposed to using a stock example script provided in TensorFlow): Using custom loss function
  • OS Platform and Distribution (e.g., Linux Ubuntu 16.04): Ubuntu 18.04
  • TensorFlow installed from (source or binary): binary
  • TensorFlow version (use command below): 2.2.0
  • Python version: 3.6.8
  • CUDA/cuDNN version: 10.1, 7.6
  • GPU model and memory: NVIDIA T4 Tensor Core GPU, AWS g4dn.xlarge 16GB

Describe the current behavior

  • Error with model.fit function, when using class_weight as dictionary mapping class indices (integers) to a weight (float) values, for example {1.0: 0.6, 2.0, 0.4}.
  • Traceback:
Traceback (most recent call last):
  File "train.py", line 117, in <module>
    main()
  File "train.py", line 112, in main
    use_multiprocessing=True
  File "/opt/anaconda3/lib/python3.6/site-packages/tensorflow/python/keras/engine/training.py", line 66, in _method_wrapper
    return method(self, *args, **kwargs)
  File "/opt/anaconda3/lib/python3.6/site-packages/tensorflow/python/keras/engine/training.py", line 815, in fit
    model=self)
  File "/opt/anaconda3/lib/python3.6/site-packages/tensorflow/python/keras/engine/data_adapter.py", line 1117, in __init__
    dataset = dataset.map(_make_class_weight_map_fn(class_weight))
  File "/opt/anaconda3/lib/python3.6/site-packages/tensorflow/python/data/ops/dataset_ops.py", line 1621, in map
    return MapDataset(self, map_func, preserve_cardinality=True)
  File "/opt/anaconda3/lib/python3.6/site-packages/tensorflow/python/data/ops/dataset_ops.py", line 3981, in __init__
    use_legacy_function=use_legacy_function)
  File "/opt/anaconda3/lib/python3.6/site-packages/tensorflow/python/data/ops/dataset_ops.py", line 3221, in __init__
    self._function = wrapper_fn.get_concrete_function()
  File "/opt/anaconda3/lib/python3.6/site-packages/tensorflow/python/eager/function.py", line 2532, in get_concrete_function
    *args, **kwargs)
  File "/opt/anaconda3/lib/python3.6/site-packages/tensorflow/python/eager/function.py", line 2496, in _get_concrete_function_garbage_collected
    graph_function, args, kwargs = self._maybe_define_function(args, kwargs)
  File "/opt/anaconda3/lib/python3.6/site-packages/tensorflow/python/eager/function.py", line 2777, in _maybe_define_function
    graph_function = self._create_graph_function(args, kwargs)
  File "/opt/anaconda3/lib/python3.6/site-packages/tensorflow/python/eager/function.py", line 2667, in _create_graph_function
    capture_by_value=self._capture_by_value),
  File "/opt/anaconda3/lib/python3.6/site-packages/tensorflow/python/framework/func_graph.py", line 981, in func_graph_from_py_func
    func_outputs = python_func(*func_args, **func_kwargs)
  File "/opt/anaconda3/lib/python3.6/site-packages/tensorflow/python/data/ops/dataset_ops.py", line 3214, in wrapper_fn
    ret = _wrapper_helper(*args)
  File "/opt/anaconda3/lib/python3.6/site-packages/tensorflow/python/data/ops/dataset_ops.py", line 3156, in _wrapper_helper
    ret = autograph.tf_convert(func, ag_ctx)(*nested_args)
  File "/opt/anaconda3/lib/python3.6/site-packages/tensorflow/python/autograph/impl/api.py", line 262, in wrapper
    return converted_call(f, args, kwargs, options=options)
  File "/opt/anaconda3/lib/python3.6/site-packages/tensorflow/python/autograph/impl/api.py", line 492, in converted_call
    return _call_unconverted(f, args, kwargs, options)
  File "/opt/anaconda3/lib/python3.6/site-packages/tensorflow/python/autograph/impl/api.py", line 346, in _call_unconverted
    return f(*args, **kwargs)
  File "/opt/anaconda3/lib/python3.6/site-packages/tensorflow/python/keras/engine/data_adapter.py", line 1246, in _class_weights_map_fn
    "`class_weight` is only supported for Models with a single output.")
ValueError: `class_weight` is only supported for Models with a single output.
  • My model input and output:
    • Input: <tf.Tensor ‘input.base_1.t1:0’ shape=(None, 16) dtype=int32>
    • Output: <tf.Tensor ‘output.base_1.t1/Identity:0’ shape=(None, 25) dtype=float32>

Describe the expected behavior

  • This was perfectly working with TF 2.1.0 and other previous versions. After upgrading to the 2.2.0 I’m getting this error and no changes was made to model architecture or any other parts of model.fit function.

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 10
  • Comments: 31 (14 by maintainers)

Most upvoted comments

Are you satisfied with the resolution of your issue? Yes No

I’ve encountered the same problem, also on version 2.3 and 2.3.1.

I have tried in colab with TF -GPU 2.2.0,nightly versions and was able to reproduce the issue.Please, find the gist here.Thanks!

Have moved #46189 to read-for-review, if anyone here is interested in reviewing

The change proposes an extension to the Model class that enforces dense (…, 1) shape or one-hot (… n_classes) shape, when using 3+ dimensional labels. The reason the problem existed for 3+d classes is it’s ambiguous as to whether the final label dimension is a one-hot encoding or a dimension belonging to the output, so this change enforces that it’s one or the other (without impacting users currently not using the flag)

It seems that passing an array instead of the (documentation and tutorial-recommended) dictionary lets the code run, but on viewing the implementations it looks like if not isinstance(class_weight, dict) (and sample weights aren’t used) then the standardise_user_weights function just returns [1s]. This seems like a pretty major silent failure

tensorflow-gpu version 2.1 (sadly couldn’t get 2.3 working with python 3.6 conda env so don’t know if it’s fixed).

import tensorflow as tf
import tensorflow.keras.layers as kl

model = tf.keras.Sequential(kl.Dense(4))

optim = tf.keras.optimizers.Adam(
    learning_rate=0.001,
)

loss = tf.keras.losses.CategoricalCrossentropy(
    from_logits=True,
)

class_weights = {
	0: 1., 1: 0.5, 2: 0.8, 3: 1.3,
}

xs = tf.zeros((16, 5, 5, 1))  # img
ys = tf.zeros((16, 5, 5, 4))  # one hot label

model.compile(optim, loss)

# Runs but fails silently
model.fit(xs, ys, class_weight=class_weights.values())
# Broken for n_classes> 1 (but is written as-documented)
model.fit(xs, ys, class_weight=class_weights)

Hmm, I also got tripped up on this now in 2.9.1. I’m using tf.data and return minibatches on the format Tuple[Dict[str, tf.Tensor], Dict[str, tf.Tensor]] with (features, targets).

Since that format “just works” with losses, metrics and optimizers, I expected it to also work for class_weight, but alas I need an additional tf.data.Dataset.map(lambda features, targets: (features[input_key], targets[output_key])) to use class_weight. Bit of a gotcha IMO.

@niki-j thanks for the poke, good to hear there’s still a need for this feature.

I have finally cracked the rebase + got the tests running locally again, so the patch set #46189 is still open and ready for review.

I ask if any budding (or previous) contributors are following this thread and have the time, please take a look at the PR and add your review

I have raised this pull request (currently draft) - I would be interested in whether this addresses the issue for some people here.

https://github.com/tensorflow/tensorflow/pull/46189

Hello, I solve this problem by adding two lines to the library, tensorflow==2.4.0 python==3.8.5 file: venv/lib/python3.8/site-packages/tensorflow/python/keras/engine/data_adapter.py

line: 1292

before change:

  def _class_weights_map_fn(*data):
    """Convert `class_weight` to `sample_weight`."""
    x, y, sw = unpack_x_y_sample_weight(data)

    if nest.is_nested(y):
      raise ValueError(
          "`class_weight` is only supported for Models with a single output.")

after change:

 def _class_weights_map_fn(*data):
    """Convert `class_weight` to `sample_weight`."""
    x, y, sw = unpack_x_y_sample_weight(data)
    if isinstance(y, dict):
      y = y.popitem()[1]
    if nest.is_nested(y):
      raise ValueError(
          "`class_weight` is only supported for Models with a single output.")

but please do solve this problem permanently!

Note: I prepared a generator function to input for model.fit and the shape of my labels are {“output”: 0 } so I got rid of dict and use the values just by adding this two lines:

    if isinstance(y, dict):
      y = y.popitem()[1]

thanks with love for the brilliant TensorFlow .

I’ve encountered the same problem, also on version 2.5. So, Is there a solution to this problem?

@spate141 Thanks. I was able to reproduce the issue in 2.4.0-rc1. Here is the gist

With reference to this update, I am unable to download the the two files mentioned above. @spate141 can you please guide? Thanks