В предыдущих сообщениях я представил несколько простых развертываний с использованием Tensorflow. В этом посте больше внимания будет уделено преобразованию Tensorflow и Apache Beam. В репозитории TensorFlow Transform Github я опубликовал некоторые проблемы (и решения), связанные с census_example. Поскольку вы можете обратиться к этой ссылке для получения более подробной информации, я не буду публиковать весь код, только то, что необходимо для пояснительных целей.
В этом примере используются данные переписи, чтобы предсказать, сможет ли конкретный человек заработать больше или равно 50 тысяч или меньше 50 тысяч. Входные функции подразделяются на:
CATEGORICAL_FEATURE_KEYS,
NUMERIC_FEATURE_KEYS,
OPTIONAL_NUMERIC_FEATURE_KEYS.
Нам нужно это знать, потому что нам нужно преобразовать данные в соответствующие типы данных с помощью преобразования Tensorflow.
RAW_DATA_FEATURE_SPEC = dict([(name, tf.io.FixedLenFeature([], tf.string)) RAW_DATA_METADATA = dataset_metadata.DatasetMetadata(for name schema_utils.schema_from_feature_spec(RAW_DATA_FEATURE_SPEC)) in CATEGORICAL_FEATURE_KEYS] + [(name, tf.io.FixedLenFeature([], tf.float32)) for name in NUMERIC_FEATURE_KEYS] + [(name, tf.io.VarLenFeature(tf.float32)) for name in OPTIONAL_NUMERIC_FEATURE_KEYS] + [(LABEL_KEY, tf.io.FixedLenFeature([], tf.string))])
Нам нужно это знать, потому что нам нужно преобразовать данные в соответствующие типы данных с помощью преобразования Tensorflow.
RAW_DATA_FEATURE_SPEC.
На основе спецификаций функций функция tf_metadata tensorflow_transform создает схему входных типов объектов. Характеристики и схема функций выглядят следующим образом:
def preprocessing_fn(inputs): outputs = inputs.copy() for key in NUMERIC_FEATURE_KEYS: outputs[key] = tft.scale_to_0_1(outputs[key]) for key in OPTIONAL_NUMERIC_FEATURE_KEYS: dense = tf.compat.v1.sparse_to_dense( outputs[key].indices, [outputs[key].dense_shape[0], 1], outputs[key].values, default_value=0.) dense = tf.squeeze(dense, axis=1) outputs[key] = tft.scale_to_0_1(dense) for key in CATEGORICAL_FEATURE_KEYS: tft.vocabulary(inputs[key], vocab_filename=key) table_keys = ['>50K', '<=50K'] initializer = tf.lookup.KeyValueTensorInitializer( keys=table_keys, values=tf.cast(tf.range(len(table_keys)), tf.int64), key_dtype=tf.string, value_dtype=tf.int64) table = tf.lookup.StaticHashTable(initializer, default_value=-1) outputs[LABEL_KEY] = table.lookup(outputs[LABEL_KEY]) return outputs
Самый важный аспект, который следует учитывать перед обучением модели с этими данными, - это преобразование данных. Иногда это называют функцией предварительной обработки. Мы передадим это во время обучения как функцию-оболочку.
После этого мы будем использовать Apache Beam для преобразования наших обучающих или оценочных данных в TFRecord. Apache Beam - это высокоуровневый API, созданный для обработки пакетных данных и потоковой передачи данных для быстрой обработки (здесь не будем вдаваться в подробности, поскольку это для другой публикации):
with beam.Pipeline() as pipeline: with tft_beam.Context(temp_dir=tempfile.mktemp()): ordered_columns = ['age', 'workclass', 'fnlwgt','education', 'education-num','marital-status', 'occupation', 'relationship', 'race', 'sex','capital-gain', 'capital-loss', 'hours-per-week', 'native-country','label'] converter = tft.coders.CsvCoder(ordered_columns, RAW_DATA_METADATA.schema) raw_data = ( pipeline | "ReadTrainData" >> beam.io.ReadFromText(train_data_file) | "FixCommasTrainData" >> beam.Map(lambda line: line.replace(', ', ',')) | "DecodeTrainData" >> MapAndFilterErrors(converter.decode) ) raw_dataset = (raw_data, RAW_DATA_METADATA) transformed_dataset , transform_fn = (raw_dataset | tft_beam.AnalyzeAndTransformDataset(preprocessing_fn)) transformed_data, transformed_metadata = transformed_dataset transformed_data_coder = tft.coders.ExampleProtoCoder(transformed_metadata.schema) _ = ( transformed_data | "EncodeTrainData" >> beam.Map(transformed_data_coder.encode) | "WriteTrainData" >> beam.io.WriteToTFRecord(os.path.join(working_dir, TRANSFORMED_TRAIN_DATA_FILEBASE)) )
Функция ReadFromText Apache Beam будет читать текстовый файл, исправлять запятые в каждой строке (записи) и использовать класс MapAndFilterErrors для декодирования данных в формате .csv. Затем мы можем очень просто создать набор данных с необработанными данными и схемой, как показано выше. Затем мы хотим выполнить преобразование с помощью AnalyzeAndTransformDataset с нашей функцией предварительной обработки в качестве оболочки. Наконец, мы записываем преобразованные данные на диск в виде файла типа данных TFRecord. Мы делаем то же самое для набора оценочных данных.
Здесь мы покажем, как создать обучающую оболочку с преобразованным набором данных в качестве входного параметра:
def _make_training_input_fn(tf_transform_output, transformed_examples, batch_size): def input_fn(): dataset = tf.data.experimental.make_batched_features_dataset( file_pattern=transformed_examples, batch_size=batch_size, features=tf_transform_output.transformed_feature_spec(), reader=tf.data.TFRecordDataset, shuffle=) transformed_features = tf.compat.v1.data.make_one_shot_iterator(dataset).get_next() transformed_labels = transformed_features.pop(LABEL_KEY) return transformed_features, transformed_labels return input_fn
Мы также можем создать оболочку для функции обслуживания, которую можно использовать как во время оценки, так и во время последующего обслуживания. Разница в том, что нам не нужны функции ярлыков, которые противоречат цели обучения!
Здесь мы используем API оценщика для обучения, и мы используем LinearClassifier, но не стесняйтесь использовать любой другой, например DNNClassifier:
estimator = tf.estimator.LinearClassifier( feature_columns=get_feature_columns(tf_transformed_output), config=run_config, loss_reduction=tf.losses.Reduction.SUM ) train_input_fn = _make_training_input_fn( tf_transformed_output, os.path.join(working_dir, TRANSFORMED_TRAIN_DATA_FILEBASE + '*'), batch_size=TRAIN_BATCH_SIZE ) estimator.train(input_fn=train_input_fn, max_steps=TRAIN_NUM_EPOCHS * num_train_instances / TRAIN_BATCH_SIZE)
После завершения обучения у нас будет модель вывода, сохраненная в нашем working_dir, и мы сможем проверить определение сигнатуры нашей сохраненной модели, используя saved_model_cli TensorFlow.
рисунок: определение сигнатуры сохраненной модели
Теперь мы готовы обслуживать модель, обученную на основе набора данных переписи, с использованием обслуживания TensorFlow.
рисунок: обслуживание модели с использованием модели Tensorflow
Конечно, неплохо создать клиента для вывода. В предыдущих сообщениях я использовал python для создания клиента для вывода. На самом деле мы можем использовать Curl для вывода, и это самый простой способ сделать это:
$ curl -d '{"examples": [{"age":30.0, "workclass":"Self-emp-not-inc", "education":"Bachelors", "education-num":17.0, "marital-status":"Married-civ-spouse", "occupation":"Exec-managerial", "relationship":"Husband", "race":"White", "sex":"Male", "capital-gain":0.0, "capital-loss":0.0, "hours-per-week":40.0, "native-country":"United-States"}]}' -X POSThttp://localhost:8501/v1/models/census:classify { "results": [[["0", 0.498906225], ["1", 0.501093805]] ]
Надеюсь, вам понравились эти сообщения.
Tensorflow и Tensorflow Extended - мощные инструменты. В этой серии постов я попытался показать несколько простых реализаций, которые помогут вам начать использовать эти инструменты.
Пожалуйста, присылайте нам свои комментарии, исправления и дальнейшие обсуждения по адресу [email protected]
Готовы узнать больше?
Свяжитесь с нашей командой экспертов, чтобы узнать, как мы можем помочь вам в создании интеллектуальных решений для прогнозирования вашего бизнеса.