Error for adversarial training with Sequential model
victorconan opened this issue · 2 comments
I have a base model using tf.feature_column:
def build_base_model(hparams):
feature_cols = [tf.feature_column.numeric_column(colname) for colname in hparams.feature_names]
feature_layer = tf.keras.layers.DenseFeatures(feature_cols)
l = []
l.append(feature_layer)
for num_units in hparams.layers:
l.append(tf.keras.layers.Dense(num_units, activation='relu'))
pred = tf.keras.layers.Dense(hparams.num_classes, activation='sigmoid')
l.append(pred)
model = tf.keras.Sequential(l)
return model
And I have parser function to feed data from TFRecords (there are 500 feature columns in the file):
def parse_fn2(serialized_example, primary_keys, features, label_type):
feature_dict = {}
for primary_key in primary_keys:
feature_dict[primary_key] = tf.io.FixedLenFeature([], tf.string)
for f in features:
feature_dict[f] = tf.io.FixedLenFeature([], tf.float32, default_value=0.0)
if label_type == "float":
feature_dict["label"] = tf.io.FixedLenFeature([], tf.float32, default_value=0.0)
else: # int
feature_dict["label"] = tf.io.FixedLenFeature([], tf.int64, default_value=0)
parsed = tf.io.parse_example(serialized_example, features=feature_dict)
for k in primary_keys:
primary_k = parsed.pop(k)
#target = parsed.pop("label")
return parsed #, target
def tfrecords_input_fn2(
files_name_pattern, primary_keys, features, label_type, batch_size=1024
):
shuffle = True if label_type else False
file_names = tf.io.matching_files(files_name_pattern)
dataset = tf.data.TFRecordDataset(filenames=file_names)
if shuffle:
dataset = dataset.shuffle(buffer_size=2 * batch_size + 1)
dataset = dataset.batch(batch_size)
dataset = dataset.map(
lambda tf_example: parse_fn2(
tf_example, primary_keys, features, label_type
)
)
dataset = dataset.repeat()
return dataset
My base model can run successfully when uncommenting the target. When I tried to run the adversarial regularization:
adv_config = nsl.configs.make_adv_reg_config(
multiplier=HPARAMS.adv_multiplier,
adv_step_size=HPARAMS.adv_step_size,
adv_grad_norm=HPARAMS.adv_grad_norm
)
base_adv_model = build_base_model(HPARAMS)
adv_model = nsl.keras.AdversarialRegularization(
base_adv_model,
label_keys=["label"],
adv_config=adv_config
)
adv_model.compile(optimizer='adam', loss='binary_crossentropy',
metrics=[tf.keras.metrics.AUC(name="auc"),
tf.keras.metrics.Precision(name="precision"),
tf.keras.metrics.Recall(name="recall"),])
adv_model.fit(tfrecords_input_fn2(
files_name_pattern, ["user_id"], feature_names, "integer", batch_size=1024
), epochs=100, steps_per_epoch=300)
I got error:
TypeError: in user code:
/databricks/python/lib/python3.7/site-packages/tensorflow/python/keras/engine/training.py:571 train_function *
outputs = self.distribute_strategy.run(
/databricks/python/lib/python3.7/site-packages/neural_structured_learning/keras/adversarial_regularization.py:667 call *
outputs, labeled_loss, metrics, tape = self._forward_pass(
/databricks/python/lib/python3.7/site-packages/neural_structured_learning/keras/adversarial_regularization.py:646 _forward_pass *
outputs = self._call_base_model(inputs, **base_model_kwargs)
/databricks/python/lib/python3.7/site-packages/neural_structured_learning/keras/adversarial_regularization.py:621 _call_base_model *
if (isinstance(self.base_model, tf.keras.Sequential) and
TypeError: 'NoneType' object is not iterable
I don't understand this error. Is it because my sequential model does not build until training is running? Any suggestions for workarounds?
Thanks @victorconan for raising the issue and for the detailed reproduction instructions.
AdversarialRegularization expects Sequential base models to provide a list of feature names in order to distinguish input features and target labels, but unfortunately the feature names specified in feature columns (the DenseFeatures layer) aren't populated to the model.
Here's a workaround using a Keras functional model and explicit Input layers:
def build_base_model(hparams):
feature_cols = [tf.feature_column.numeric_column(name) for name in hparams.feature_names]
feature_layer = tf.keras.layers.DenseFeatures(feature_cols)
x_input = [tf.keras.Input(shape=[], name=name, dtype=tf.float32) for name in hparams.feature_names]
x_dict = dict(zip(hparams.feature_names, x_input))
x_dense = feature_layer(x_dict)
for num_units in hparams.layers:
x_dense = tf.keras.layers.Dense(num_units, activation='relu')(x_dense)
pred = tf.keras.layers.Dense(hparams.num_classes, activation='sigmoid')(x_dense)
return tf.keras.Model(inputs=x_input, outputs=pred)Please let me know whether this works for you.
Thanks! It's working!