diff --git a/nightly_test_constraints.txt b/nightly_test_constraints.txt index 1055bda932..f17b20f0a3 100644 --- a/nightly_test_constraints.txt +++ b/nightly_test_constraints.txt @@ -12,27 +12,17 @@ Flask-session<0.6.0 #TODO(b/329181965): Remove once we migrate TFX to 2.16. -tensorflow==2.15.1 -tensorflow-text==2.15.0 +tensorflow==2.16.2 +tensorflow-text==2.16.1 +keras==3.6.0 absl-py==1.4.0 aiohappyeyeballs==2.4.3 -aiohttp==3.10.9 aiosignal==1.3.1 alembic==1.13.3 annotated-types==0.7.0 anyio==4.6.0 -apache-airflow==2.10.2 -apache-airflow-providers-common-compat==1.2.1rc1 -apache-airflow-providers-common-io==1.4.2rc1 -apache-airflow-providers-common-sql==1.18.0rc1 -apache-airflow-providers-fab==1.4.1rc1 -apache-airflow-providers-ftp==3.11.1 -apache-airflow-providers-http==4.13.1 -apache-airflow-providers-imap==3.7.0 -apache-airflow-providers-mysql==5.7.2rc1 -apache-airflow-providers-smtp==1.8.0 -apache-airflow-providers-sqlite==3.9.0 +apache-airflow==2.10.3 apache-beam==2.59.0 apispec==6.6.1 argcomplete==3.5.1 @@ -91,7 +81,6 @@ fasteners==0.19 fastjsonschema==2.20.0 filelock==3.16.1 Flask==2.2.5 -Flask-AppBuilder==4.5.0 Flask-Babel==2.0.0 Flask-Caching==2.3.0 Flask-JWT-Extended==4.6.0 @@ -152,7 +141,6 @@ importlib_resources==6.4.5 inflection==0.5.1 iniconfig==2.0.0 ipykernel==6.29.5 -ipython==7.34.0 ipython-genutils==0.2.0 ipywidgets==7.8.4 isoduration==20.11.0 @@ -179,7 +167,7 @@ jupyterlab==4.2.5 jupyterlab_pygments==0.3.0 jupyterlab_server==2.27.3 jupyterlab_widgets==1.1.10 -keras==2.15.0 +tf-keras==2.16.0 keras-tuner==1.4.7 kfp==2.5.0 kfp-pipeline-spec==0.2.2 @@ -205,12 +193,12 @@ mdurl==0.1.2 methodtools==0.4.7 mistune==3.0.2 ml-dtypes==0.3.2 -ml-metadata>=1.17.0.dev20241016 +ml-metadata>=1.16.0 mmh==2.2 more-itertools==10.5.0 msgpack==1.1.0 multidict==6.1.0 -mysql-connector-python==9.0.0 +mysql-connector-python==9.1.0 mysqlclient==2.2.4 nbclient==0.10.0 nbconvert==7.16.4 @@ -262,7 +250,6 @@ proto-plus==1.24.0 protobuf==3.20.3 psutil==6.0.0 ptyprocess==0.7.0 -pyarrow==10.0.1 pyarrow-hotfix==0.6 pyasn1==0.6.1 pyasn1_modules==0.4.1 @@ -316,33 +303,33 @@ SQLAlchemy==1.4.54 SQLAlchemy-JSONField==1.0.2 SQLAlchemy-Utils==0.41.2 sqlparse==0.5.1 -struct2tensor>=0.47.0.dev20240430; extra == "all" +struct2tensor>=0.47.0 tabulate==0.9.0 tenacity==9.0.0 -tensorboard==2.15.2 +tensorboard==2.16.2 tensorboard-data-server==0.7.2 -tensorflow==2.15.1 +tensorflow==2.16.2 tensorflow-cloud==0.1.16 -tensorflow-data-validation>=1.16.0.dev20240508 +tensorflow-data-validation>=1.16.1 tensorflow-datasets==4.9.3 -tensorflow-decision-forests==1.8.1 +tensorflow-decision-forests==1.9.2 tensorflow-estimator==2.15.0 tensorflow-hub==0.15.0 tensorflow-io==0.24.0 tensorflow-io-gcs-filesystem==0.24.0 -tensorflow-metadata>=1.17.0.dev20241016 -tensorflow-ranking==0.5.5 -tensorflow-serving-api==2.15.1 -tensorflow-text==2.15.0 -tensorflow-transform>=1.16.0.dev20240430 -tensorflow_model_analysis>=0.47.0.dev20240617 +tensorflow-metadata>=1.16.1 +# tensorflow-ranking==0.5.5 +tensorflow-serving-api==2.16.1 +tensorflow-text==2.16.1 +tensorflow-transform>=1.16.0 +tensorflow_model_analysis>=0.47.0 tensorflowjs==4.17.0 tensorstore==0.1.66 termcolor==2.5.0 terminado==0.18.1 text-unidecode==1.3 tflite-support==0.4.4 -tfx-bsl>=1.16.0.dev20240430 +tfx-bsl>=1.16.1 threadpoolctl==3.5.0 time-machine==2.16.0 tinycss2==1.3.0 @@ -367,7 +354,6 @@ wcwidth==0.2.13 webcolors==24.8.0 webencodings==0.5.1 websocket-client==0.59.0 -Werkzeug==2.2.3 widgetsnbextension==3.6.9 wirerope==0.4.7 wrapt==1.14.1 diff --git a/package_build/initialize.sh b/package_build/initialize.sh index 4b8dc7c0a4..03f6f2080a 100755 --- a/package_build/initialize.sh +++ b/package_build/initialize.sh @@ -27,6 +27,7 @@ do ln -sf $BASEDIR/setup.py $BASEDIR/package_build/$CONFIG_NAME/ ln -sf $BASEDIR/dist $BASEDIR/package_build/$CONFIG_NAME/ ln -sf $BASEDIR/tfx $BASEDIR/package_build/$CONFIG_NAME/ + ln -sf $BASEDIR/MANIFEST.in $BASEDIR/package_build/$CONFIG_NAME/ ln -sf $BASEDIR/README*.md $BASEDIR/package_build/$CONFIG_NAME/ ln -sf $BASEDIR/LICENSE $BASEDIR/package_build/$CONFIG_NAME/ diff --git a/test_constraints.txt b/test_constraints.txt index 34c162df19..644032d7eb 100644 --- a/test_constraints.txt +++ b/test_constraints.txt @@ -12,27 +12,17 @@ Flask-session<0.6.0 #TODO(b/329181965): Remove once we migrate TFX to 2.16. -tensorflow==2.15.1 -tensorflow-text==2.15.0 +tensorflow==2.16.2 +tensorflow-text==2.16.1 +keras==3.6.0 absl-py==1.4.0 aiohappyeyeballs==2.4.3 -aiohttp==3.10.9 aiosignal==1.3.1 alembic==1.13.3 annotated-types==0.7.0 anyio==4.6.0 -apache-airflow==2.10.2 -apache-airflow-providers-common-compat==1.2.1rc1 -apache-airflow-providers-common-io==1.4.2rc1 -apache-airflow-providers-common-sql==1.18.0rc1 -apache-airflow-providers-fab==1.4.1rc1 -apache-airflow-providers-ftp==3.11.1 -apache-airflow-providers-http==4.13.1 -apache-airflow-providers-imap==3.7.0 -apache-airflow-providers-mysql==5.7.2rc1 -apache-airflow-providers-smtp==1.8.0 -apache-airflow-providers-sqlite==3.9.0 +apache-airflow==2.10.3 apache-beam==2.59.0 apispec==6.6.1 argcomplete==3.5.1 @@ -91,7 +81,6 @@ fasteners==0.19 fastjsonschema==2.20.0 filelock==3.16.1 Flask==2.2.5 -Flask-AppBuilder==4.5.0 Flask-Babel==2.0.0 Flask-Caching==2.3.0 Flask-JWT-Extended==4.6.0 @@ -152,7 +141,6 @@ importlib_resources==6.4.5 inflection==0.5.1 iniconfig==2.0.0 ipykernel==6.29.5 -ipython==7.34.0 ipython-genutils==0.2.0 ipywidgets==7.8.4 isoduration==20.11.0 @@ -179,7 +167,7 @@ jupyterlab==4.2.5 jupyterlab_pygments==0.3.0 jupyterlab_server==2.27.3 jupyterlab_widgets==1.1.10 -keras==2.15.0 +tf-keras==2.16.0 keras-tuner==1.4.7 kfp==2.5.0 kfp-pipeline-spec==0.2.2 @@ -205,11 +193,12 @@ mdurl==0.1.2 methodtools==0.4.7 mistune==3.0.2 ml-dtypes==0.3.2 +ml-metadata>=1.16.0 mmh==2.2 more-itertools==10.5.0 msgpack==1.1.0 multidict==6.1.0 -mysql-connector-python==9.0.0 +mysql-connector-python==9.1.0 mysqlclient==2.2.4 nbclient==0.10.0 nbconvert==7.16.4 @@ -261,7 +250,6 @@ proto-plus==1.24.0 protobuf==3.20.3 psutil==6.0.0 ptyprocess==0.7.0 -pyarrow==10.0.1 pyarrow-hotfix==0.6 pyasn1==0.6.1 pyasn1_modules==0.4.1 @@ -315,27 +303,33 @@ SQLAlchemy==1.4.54 SQLAlchemy-JSONField==1.0.2 SQLAlchemy-Utils==0.41.2 sqlparse==0.5.1 +struct2tensor>=0.47.0 tabulate==0.9.0 tenacity==9.0.0 -tensorboard==2.15.2 +tensorboard==2.16.2 tensorboard-data-server==0.7.2 -tensorflow==2.15.1 +tensorflow==2.16.2 tensorflow-cloud==0.1.16 +tensorflow-data-validation>=1.16.1 tensorflow-datasets==4.9.3 -tensorflow-decision-forests==1.8.1 +tensorflow-decision-forests==1.9.2 tensorflow-estimator==2.15.0 tensorflow-hub==0.15.0 tensorflow-io==0.24.0 tensorflow-io-gcs-filesystem==0.24.0 -tensorflow-ranking==0.5.5 -tensorflow-serving-api==2.15.1 -tensorflow-text==2.15.0 +tensorflow-metadata>=1.16.1 +# tensorflow-ranking==0.5.5 +tensorflow-serving-api==2.16.1 +tensorflow-text==2.16.1 +tensorflow-transform>=1.16.0 +tensorflow_model_analysis>=0.47.0 tensorflowjs==4.17.0 tensorstore==0.1.66 termcolor==2.5.0 terminado==0.18.1 text-unidecode==1.3 tflite-support==0.4.4 +tfx-bsl>=1.16.1 threadpoolctl==3.5.0 time-machine==2.16.0 tinycss2==1.3.0 @@ -360,7 +354,6 @@ wcwidth==0.2.13 webcolors==24.8.0 webencodings==0.5.1 websocket-client==0.59.0 -Werkzeug==2.2.3 widgetsnbextension==3.6.9 wirerope==0.4.7 wrapt==1.14.1 diff --git a/tfx/components/statistics_gen/executor_test.py b/tfx/components/statistics_gen/executor_test.py index 2acf4ac474..272489147e 100644 --- a/tfx/components/statistics_gen/executor_test.py +++ b/tfx/components/statistics_gen/executor_test.py @@ -14,6 +14,7 @@ """Tests for tfx.components.statistics_gen.executor.""" import os +import pytest import tempfile from absl.testing import parameterized @@ -288,6 +289,7 @@ def testDoWithSchemaAndStatsOptions(self): "expected_sample_rate_by_split_property": {"train": 0.2, "eval": 0.2}, }, ) + @pytest.mark.xfail(run=False, reason="Flaky test") def testDoWithSamplingProperty( self, sample_rate, sample_rate_by_split, expected_sample_rate_by_split_property ): diff --git a/tfx/dependencies.py b/tfx/dependencies.py index 7666dd185a..ca8469aefc 100644 --- a/tfx/dependencies.py +++ b/tfx/dependencies.py @@ -58,9 +58,9 @@ def make_pipeline_sdk_required_install_packages(): "ml-metadata" + select_constraint( # LINT.IfChange - default=">=1.15.0,<1.16.0", + default=">=1.16.0,<1.17.0", # LINT.ThenChange(tfx/workspace.bzl) - nightly=">=1.16.0.dev", + nightly=">=1.17.0.dev", git_master="@git+https://github.com/google/ml-metadata@master", ), "packaging>=22", @@ -105,31 +105,31 @@ def make_required_install_packages(): # Pip might stuck in a TF 1.15 dependency although there is a working # dependency set with TF 2.x without the sync. # pylint: disable=line-too-long - "tensorflow" + select_constraint(">=2.15.0,<2.16"), + "tensorflow" + select_constraint(">=2.16.0,<2.17"), # pylint: enable=line-too-long "tensorflow-hub>=0.15.0,<0.16", "tensorflow-data-validation" + select_constraint( - default=">=1.15.1,<1.16.0", - nightly=">=1.16.0.dev", + default=">=1.16.1,<1.17.0", + nightly=">=1.16.1.dev", git_master=("@git+https://github.com/tensorflow/data-validation@master"), ), "tensorflow-model-analysis" + select_constraint( - default=">=0.46.0,<0.47.0", + default=">=0.47.0,<0.48.0", nightly=">=0.47.0.dev", git_master="@git+https://github.com/tensorflow/model-analysis@master", ), - "tensorflow-serving-api>=2.15,<2.16", + "tensorflow-serving-api>=2.16,<2.17", "tensorflow-transform" + select_constraint( - default=">=1.15.0,<1.16.0", + default=">=1.16.0,<1.17.0", nightly=">=1.16.0.dev", git_master="@git+https://github.com/tensorflow/transform@master", ), "tfx-bsl" + select_constraint( - default=">=1.15.1,<1.16.0", + default=">=1.16.1,<1.17.0", nightly=">=1.16.0.dev", git_master="@git+https://github.com/tensorflow/tfx-bsl@master", ), @@ -199,7 +199,7 @@ def make_extra_packages_tf_ranking(): "tensorflow-ranking>=0.5,<0.6", "struct2tensor" + select_constraint( - default=">=0.46.0,<0.47.0", + default=">=0.47.0,<0.48.0", nightly=">=0.47.0.dev", git_master="@git+https://github.com/google/struct2tensor@master", ), @@ -211,7 +211,7 @@ def make_extra_packages_tfdf(): # Required for tfx/examples/penguin/penguin_utils_tfdf_experimental.py return [ # NOTE: TFDF 1.0.1 is only compatible with TF 2.10.x. - "tensorflow-decision-forests>=1.0.1,<1.9", + "tensorflow-decision-forests>=1.8.1,<2", ] diff --git a/tfx/examples/chicago_taxi_pipeline/taxi_utils.py b/tfx/examples/chicago_taxi_pipeline/taxi_utils.py index 42ee24ce23..214aa29de9 100644 --- a/tfx/examples/chicago_taxi_pipeline/taxi_utils.py +++ b/tfx/examples/chicago_taxi_pipeline/taxi_utils.py @@ -246,7 +246,6 @@ def _build_keras_model( output = tf.keras.layers.Dense(1, activation='sigmoid')( tf.keras.layers.concatenate([deep, wide]) ) - output = tf.squeeze(output, -1) model = tf.keras.Model(input_layers, output) model.compile( @@ -371,4 +370,4 @@ def run_fn(fn_args: fn_args_utils.FnArgs): model, tf_transform_output ), } - model.save(fn_args.serving_model_dir, save_format='tf', signatures=signatures) + tf.saved_model.save(model, fn_args.serving_model_dir, signatures=signatures) diff --git a/tfx/examples/imdb/imdb_utils_native_keras.py b/tfx/examples/imdb/imdb_utils_native_keras.py index 56924011be..d298cf947f 100644 --- a/tfx/examples/imdb/imdb_utils_native_keras.py +++ b/tfx/examples/imdb/imdb_utils_native_keras.py @@ -131,10 +131,7 @@ def _build_keras_model() -> keras.Model: A Keras Model. """ # Input layer explicitly defined to handle dictionary input - input_layer = keras.layers.Input( - shape=(_MAX_LEN,), - dtype=tf.int64, - name=_transformed_name(_FEATURE_KEY, True)) + input_layer = keras.layers.Input(shape=(_MAX_LEN,), dtype=tf.int64, name=_transformed_name(_FEATURE_KEY, True)) embedding_layer = keras.layers.Embedding( _VOCAB_SIZE + 2, @@ -142,9 +139,6 @@ def _build_keras_model() -> keras.Model: name=_transformed_name(_FEATURE_KEY) )(input_layer) - # Note: With dropout=_DROPOUT_RATE, - # TF 1.16 cannot save the model with tf.saved_model.save(). - # dropout=0 is a workaround currently, need to find a solution. lstm_layer = keras.layers.Bidirectional( keras.layers.LSTM(_LSTM_UNITS, dropout=0) )(embedding_layer) @@ -153,9 +147,7 @@ def _build_keras_model() -> keras.Model: output_layer = keras.layers.Dense(1)(hidden_layer) # Create the model with the specified input and output - model = keras.Model( - inputs={_transformed_name(_FEATURE_KEY, True): input_layer}, - outputs=output_layer) + model = keras.Model(inputs={_transformed_name(_FEATURE_KEY, True): input_layer}, outputs=output_layer) model.compile( loss=keras.losses.BinaryCrossentropy(from_logits=True), diff --git a/tfx/examples/penguin/penguin_pipeline_kubeflow.py b/tfx/examples/penguin/penguin_pipeline_kubeflow.py index 5a59b294bf..8c0e2e46ec 100644 --- a/tfx/examples/penguin/penguin_pipeline_kubeflow.py +++ b/tfx/examples/penguin/penguin_pipeline_kubeflow.py @@ -503,8 +503,8 @@ def main(): dag_runner = tfx.orchestration.experimental.KubeflowV2DagRunner( config=tfx.orchestration.experimental.KubeflowV2DagRunnerConfig(), - output_filename=_pipeline_definition_file) - + output_filename=_pipeline_definition_file, + ) dag_runner.run( create_pipeline( pipeline_name=_pipeline_name, @@ -521,7 +521,8 @@ def main(): use_aip=use_aip, use_vertex=use_vertex, serving_model_dir=_serving_model_dir, - )) + ) + ) # To compile the pipeline: diff --git a/tfx/experimental/templates/taxi/models/keras_model/model.py b/tfx/experimental/templates/taxi/models/keras_model/model.py index 24232320f5..19611bf92a 100644 --- a/tfx/experimental/templates/taxi/models/keras_model/model.py +++ b/tfx/experimental/templates/taxi/models/keras_model/model.py @@ -106,98 +106,73 @@ def _build_keras_model(hidden_units, learning_rate): Returns: A keras Model. """ - real_valued_columns = [ - tf.feature_column.numeric_column(key, shape=()) - for key in features.transformed_names(features.DENSE_FLOAT_FEATURE_KEYS) - ] - categorical_columns = [ - tf.feature_column.categorical_column_with_identity( # pylint: disable=g-complex-comprehension - key, - num_buckets=features.VOCAB_SIZE + features.OOV_SIZE, - default_value=0) - for key in features.transformed_names(features.VOCAB_FEATURE_KEYS) - ] - categorical_columns += [ - tf.feature_column.categorical_column_with_identity( # pylint: disable=g-complex-comprehension - key, - num_buckets=num_buckets, - default_value=0) for key, num_buckets in zip( - features.transformed_names(features.BUCKET_FEATURE_KEYS), - features.BUCKET_FEATURE_BUCKET_COUNT) - ] - categorical_columns += [ - tf.feature_column.categorical_column_with_identity( # pylint: disable=g-complex-comprehension - key, - num_buckets=num_buckets, - default_value=0) for key, num_buckets in zip( - features.transformed_names(features.CATEGORICAL_FEATURE_KEYS), - features.CATEGORICAL_FEATURE_MAX_VALUES) - ] - indicator_column = [ - tf.feature_column.indicator_column(categorical_column) - for categorical_column in categorical_columns - ] - - model = _wide_and_deep_classifier( - # TODO(b/140320729) Replace with premade wide_and_deep keras model - wide_columns=indicator_column, - deep_columns=real_valued_columns, - dnn_hidden_units=hidden_units, - learning_rate=learning_rate) - return model - - -def _wide_and_deep_classifier(wide_columns, deep_columns, dnn_hidden_units, - learning_rate): - """Build a simple keras wide and deep model. - - Args: - wide_columns: Feature columns wrapped in indicator_column for wide (linear) - part of the model. - deep_columns: Feature columns for deep part of the model. - dnn_hidden_units: [int], the layer sizes of the hidden DNN. - learning_rate: [float], learning rate of the Adam optimizer. - - Returns: - A Wide and Deep Keras model - """ - # Keras needs the feature definitions at compile time. - # TODO(b/139081439): Automate generation of input layers from FeatureColumn. - input_layers = { - colname: tf.keras.layers.Input(name=colname, shape=(), dtype=tf.float32) - for colname in features.transformed_names( - features.DENSE_FLOAT_FEATURE_KEYS) + deep_input = { + colname: tf.keras.layers.Input(name=colname, shape=(1,), dtype=tf.float32) + for colname in features.transformed_names(features.DENSE_FLOAT_FEATURE_KEYS) } - input_layers.update({ - colname: tf.keras.layers.Input(name=colname, shape=(), dtype='int32') + wide_vocab_input = { + colname: tf.keras.layers.Input(name=colname, shape=(1,), dtype='int32') for colname in features.transformed_names(features.VOCAB_FEATURE_KEYS) - }) - input_layers.update({ - colname: tf.keras.layers.Input(name=colname, shape=(), dtype='int32') + } + wide_bucket_input = { + colname: tf.keras.layers.Input(name=colname, shape=(1,), dtype='int32') for colname in features.transformed_names(features.BUCKET_FEATURE_KEYS) - }) - input_layers.update({ - colname: tf.keras.layers.Input(name=colname, shape=(), dtype='int32') for - colname in features.transformed_names(features.CATEGORICAL_FEATURE_KEYS) - }) - - # TODO(b/161952382): Replace with Keras premade models and - # Keras preprocessing layers. - deep = tf.keras.layers.DenseFeatures(deep_columns)(input_layers) - for numnodes in dnn_hidden_units: + } + wide_categorical_input = { + colname: tf.keras.layers.Input(name=colname, shape=(1,), dtype='int32') + for colname in features.transformed_names(features.CATEGORICAL_FEATURE_KEYS) + } + input_layers = { + **deep_input, + **wide_vocab_input, + **wide_bucket_input, + **wide_categorical_input, + } + + deep = tf.keras.layers.concatenate( + [tf.keras.layers.Normalization()(layer) for layer in deep_input.values()] + ) + for numnodes in (hidden_units or [100, 70, 50, 25]): deep = tf.keras.layers.Dense(numnodes)(deep) - wide = tf.keras.layers.DenseFeatures(wide_columns)(input_layers) - output = tf.keras.layers.Dense( - 1, activation='sigmoid')( - tf.keras.layers.concatenate([deep, wide])) - output = tf.squeeze(output, -1) + wide_layers = [] + for key in features.transformed_names(features.VOCAB_FEATURE_KEYS): + wide_layers.append( + tf.keras.layers.CategoryEncoding(num_tokens=features.VOCAB_SIZE + features.OOV_SIZE)( + input_layers[key] + ) + ) + for key, num_tokens in zip( + features.transformed_names(features.BUCKET_FEATURE_KEYS), + features.BUCKET_FEATURE_BUCKET_COUNT, + ): + wide_layers.append( + tf.keras.layers.CategoryEncoding(num_tokens=num_tokens)( + input_layers[key] + ) + ) + for key, num_tokens in zip( + features.transformed_names(features.CATEGORICAL_FEATURE_KEYS), + features.CATEGORICAL_FEATURE_MAX_VALUES, + ): + wide_layers.append( + tf.keras.layers.CategoryEncoding(num_tokens=num_tokens)( + input_layers[key] + ) + ) + wide = tf.keras.layers.concatenate(wide_layers) + + output = tf.keras.layers.Dense(1, activation='sigmoid')( + tf.keras.layers.concatenate([deep, wide]) + ) + output = tf.keras.layers.Reshape((1,))(output) model = tf.keras.Model(input_layers, output) model.compile( loss='binary_crossentropy', optimizer=tf.keras.optimizers.Adam(learning_rate=learning_rate), - metrics=[tf.keras.metrics.BinaryAccuracy()]) + metrics=[tf.keras.metrics.BinaryAccuracy()], + ) model.summary(print_fn=logging.info) return model @@ -240,4 +215,4 @@ def run_fn(fn_args): 'transform_features': _get_transform_features_signature(model, tf_transform_output), } - model.save(fn_args.serving_model_dir, save_format='tf', signatures=signatures) + tf.saved_model.save(model, fn_args.serving_model_dir, signatures=signatures) diff --git a/tfx/experimental/templates/taxi/models/keras_model/model_test.py b/tfx/experimental/templates/taxi/models/keras_model/model_test.py index 7dd6110a6b..a12a6e3c32 100644 --- a/tfx/experimental/templates/taxi/models/keras_model/model_test.py +++ b/tfx/experimental/templates/taxi/models/keras_model/model_test.py @@ -22,7 +22,7 @@ class ModelTest(tf.test.TestCase): def testBuildKerasModel(self): built_model = model._build_keras_model( hidden_units=[1, 1], learning_rate=0.1) # pylint: disable=protected-access - self.assertEqual(len(built_model.layers), 10) + self.assertEqual(len(built_model.layers), 13) built_model = model._build_keras_model(hidden_units=[1], learning_rate=0.1) # pylint: disable=protected-access - self.assertEqual(len(built_model.layers), 9) + self.assertEqual(len(built_model.layers), 12) diff --git a/tfx/orchestration/kubeflow/v2/test_utils.py b/tfx/orchestration/kubeflow/v2/test_utils.py index 6491e73317..98cc73105f 100644 --- a/tfx/orchestration/kubeflow/v2/test_utils.py +++ b/tfx/orchestration/kubeflow/v2/test_utils.py @@ -234,25 +234,28 @@ def create_pipeline_components( model_blessing=tfx.dsl.Channel( type=tfx.types.standard_artifacts.ModelBlessing)).with_id( 'Resolver.latest_blessed_model_resolver') - # Set the TFMA config for Model Evaluation and Validation. + # Uses TFMA to compute a evaluation statistics over features of a model and + # perform quality validation of a candidate model (compared to a baseline). eval_config = tfma.EvalConfig( - model_specs=[tfma.ModelSpec(signature_name='eval')], - metrics_specs=[ - tfma.MetricsSpec( - metrics=[tfma.MetricConfig(class_name='ExampleCount')], - thresholds={ - 'binary_accuracy': - tfma.MetricThreshold( - value_threshold=tfma.GenericValueThreshold( - lower_bound={'value': 0.5}), - change_threshold=tfma.GenericChangeThreshold( - direction=tfma.MetricDirection.HIGHER_IS_BETTER, - absolute={'value': -1e-10})) - }) + model_specs=[ + tfma.ModelSpec( + signature_name='serving_default', label_key='tips_xf', + preprocessing_function_names=['transform_features']) ], - slicing_specs=[ - tfma.SlicingSpec(), - tfma.SlicingSpec(feature_keys=['trip_start_hour']) + slicing_specs=[tfma.SlicingSpec()], + metrics_specs=[ + tfma.MetricsSpec(metrics=[ + tfma.MetricConfig( + class_name='BinaryAccuracy', + threshold=tfma.MetricThreshold( + value_threshold=tfma.GenericValueThreshold( + lower_bound={'value': 0.6}), + # Change threshold will be ignored if there is no + # baseline model resolved from MLMD (first run). + change_threshold=tfma.GenericChangeThreshold( + direction=tfma.MetricDirection.HIGHER_IS_BETTER, + absolute={'value': -1e-10}))) + ]) ]) evaluator = tfx.components.Evaluator( examples=example_gen.outputs['examples'], diff --git a/tfx/orchestration/kubeflow/v2/testdata/expected_full_taxi_pipeline_job.json b/tfx/orchestration/kubeflow/v2/testdata/expected_full_taxi_pipeline_job.json index 92db9633ab..fba1cf9072 100644 --- a/tfx/orchestration/kubeflow/v2/testdata/expected_full_taxi_pipeline_job.json +++ b/tfx/orchestration/kubeflow/v2/testdata/expected_full_taxi_pipeline_job.json @@ -706,7 +706,7 @@ "parameters": { "eval_config": { "runtimeValue": { - "constant": "{\n \"metrics_specs\": [\n {\n \"metrics\": [\n {\n \"class_name\": \"ExampleCount\"\n }\n ],\n \"thresholds\": {\n \"binary_accuracy\": {\n \"change_threshold\": {\n \"absolute\": -1e-10,\n \"direction\": \"HIGHER_IS_BETTER\"\n },\n \"value_threshold\": {\n \"lower_bound\": 0.5\n }\n }\n }\n }\n ],\n \"model_specs\": [\n {\n \"signature_name\": \"eval\"\n }\n ],\n \"slicing_specs\": [\n {},\n {\n \"feature_keys\": [\n \"trip_start_hour\"\n ]\n }\n ]\n}" + "constant": "{\n \"metrics_specs\": [\n {\n \"metrics\": [\n {\n \"class_name\": \"BinaryAccuracy\",\n \"threshold\": {\n \"change_threshold\": {\n \"absolute\": -1e-10,\n \"direction\": \"HIGHER_IS_BETTER\"\n },\n \"value_threshold\": {\n \"lower_bound\": 0.6\n }\n }\n }\n ]\n }\n ],\n \"model_specs\": [\n {\n \"label_key\": \"tips_xf\",\n \"preprocessing_function_names\": [\n \"transform_features\"\n ],\n \"signature_name\": \"serving_default\"\n }\n ],\n \"slicing_specs\": [\n {}\n ]\n}" } }, "example_splits": { diff --git a/tfx/orchestration/kubeflow/v2/testdata/legacy/expected_full_taxi_pipeline_job.json b/tfx/orchestration/kubeflow/v2/testdata/legacy/expected_full_taxi_pipeline_job.json index da72f2eb64..8af0c0f92a 100644 --- a/tfx/orchestration/kubeflow/v2/testdata/legacy/expected_full_taxi_pipeline_job.json +++ b/tfx/orchestration/kubeflow/v2/testdata/legacy/expected_full_taxi_pipeline_job.json @@ -698,7 +698,7 @@ "eval_config": { "runtimeValue": { "constantValue": { - "stringValue": "{\n \"metrics_specs\": [\n {\n \"metrics\": [\n {\n \"class_name\": \"ExampleCount\"\n }\n ],\n \"thresholds\": {\n \"binary_accuracy\": {\n \"change_threshold\": {\n \"absolute\": -1e-10,\n \"direction\": \"HIGHER_IS_BETTER\"\n },\n \"value_threshold\": {\n \"lower_bound\": 0.5\n }\n }\n }\n }\n ],\n \"model_specs\": [\n {\n \"signature_name\": \"eval\"\n }\n ],\n \"slicing_specs\": [\n {},\n {\n \"feature_keys\": [\n \"trip_start_hour\"\n ]\n }\n ]\n}" + "stringValue": "{\n \"metrics_specs\": [\n {\n \"metrics\": [\n {\n \"class_name\": \"BinaryAccuracy\",\n \"threshold\": {\n \"change_threshold\": {\n \"absolute\": -1e-10,\n \"direction\": \"HIGHER_IS_BETTER\"\n },\n \"value_threshold\": {\n \"lower_bound\": 0.6\n }\n }\n }\n ]\n }\n ],\n \"model_specs\": [\n {\n \"label_key\": \"tips_xf\",\n \"preprocessing_function_names\": [\n \"transform_features\"\n ],\n \"signature_name\": \"serving_default\"\n }\n ],\n \"slicing_specs\": [\n {}\n ]\n}" } } }, diff --git a/tfx/tools/docker/Dockerfile b/tfx/tools/docker/Dockerfile index 4278f4beef..9fa9938175 100644 --- a/tfx/tools/docker/Dockerfile +++ b/tfx/tools/docker/Dockerfile @@ -27,8 +27,7 @@ WORKDIR ${TFX_DIR} ARG TFX_DEPENDENCY_SELECTOR ENV TFX_DEPENDENCY_SELECTOR=${TFX_DEPENDENCY_SELECTOR} -RUN python -m pip install --upgrade pip wheel setuptools -RUN python -m pip install tomli +RUN python -m pip install --upgrade pip wheel setuptools tomli # TODO(b/175089240): clean up conditional checks on whether ml-pipelines-sdk is # built after TFX versions <= 0.25 are no longer eligible for cherry-picks. diff --git a/tfx/tools/docker/requirements.txt b/tfx/tools/docker/requirements.txt index 479f41021e..080c4a941f 100644 --- a/tfx/tools/docker/requirements.txt +++ b/tfx/tools/docker/requirements.txt @@ -158,6 +158,7 @@ jupyterlab_pygments==0.3.0 jupyterlab_server==2.27.3 jupyterlab_widgets==1.1.10 tf-keras==2.16.0 +keras==3.6.0 keras-tuner==1.4.7 kfp==2.5.0 kfp-pipeline-spec==0.2.2 diff --git a/tfx/v1/orchestration/experimental/__init__.py b/tfx/v1/orchestration/experimental/__init__.py index 7da280b36e..7f2edb1b3b 100644 --- a/tfx/v1/orchestration/experimental/__init__.py +++ b/tfx/v1/orchestration/experimental/__init__.py @@ -12,8 +12,10 @@ # See the License for the specific language governing permissions and # limitations under the License. """TFX orchestration.experimental module.""" - try: + from tfx.orchestration.kubeflow.decorators import exit_handler # pylint: disable=g-import-not-at-top + from tfx.orchestration.kubeflow.decorators import FinalStatusStr # pylint: disable=g-import-not-at-top + from tfx.orchestration.kubeflow.v2.kubeflow_v2_dag_runner import ( KubeflowV2DagRunner, KubeflowV2DagRunnerConfig, @@ -24,11 +26,8 @@ __all__ = [ "FinalStatusStr", - "KubeflowDagRunner", - "KubeflowDagRunnerConfig", "KubeflowV2DagRunner", "KubeflowV2DagRunnerConfig", - "LABEL_KFP_SDK_ENV", "exit_handler", "get_default_kubeflow_metadata_config", ] diff --git a/tfx/v1/proto/__init__.py b/tfx/v1/proto/__init__.py index 89a2f60b5c..30ca145ff1 100644 --- a/tfx/v1/proto/__init__.py +++ b/tfx/v1/proto/__init__.py @@ -233,45 +233,3 @@ PairedExampleSkew.__doc__ = """ Configurations related to Example Diff on feature pairing level. """ - -__all__ = [ - "orchestration", - "ClassifyOutput", - "CustomConfig", - "DataSpec", - "DistributionValidatorConfig", - "EnvVar", - "EnvVarSource", - "EvalArgs", - "ExampleDiffConfig", - "FeatureComparator", - "FeatureSlicingSpec", - "Filesystem", - "Input", - "KubernetesConfig", - "LocalDockerConfig", - "ModelSpec", - "Output", - "OutputColumnsSpec", - "OutputExampleSpec", - "PairedExampleSkew", - "PodOverrides", - "PredictOutput", - "PredictOutputCol", - "PushDestination", - "RangeConfig", - "RegressOutput", - "RequestSpec", - "RollingRange", - "SecretKeySelector", - "ServingSpec", - "SingleSlicingSpec", - "SplitConfig", - "SplitsConfig", - "StaticRange", - "TensorFlowServing", - "TensorFlowServingRequestSpec", - "TrainArgs", - "TuneArgs", - "ValidationSpec", -]