In [ ]:
#@title Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
Note: Вся информация в этом разделе переведена с помощью русскоговорящего Tensorflow сообщества на общественных началах. Поскольку этот перевод не является официальным, мы не гарантируем что он на 100% аккуратен и соответствует официальной документации на английском языке. Если у вас есть предложение как исправить этот перевод, мы будем очень рады увидеть pull request в tensorflow/docs репозиторий GitHub. Если вы хотите помочь сделать документацию по Tensorflow лучше (сделать сам перевод или проверить перевод подготовленный кем-то другим), напишите нам на docs-ru@tensorflow.org list.
Этот учебник приводит пример того как выгрузить данные в формате CSV из файла в tf.data.Dataset
Данные использованные в этом примере взяты из списка пассажиров Титаника. Модель предскажет вероятность спасения пассажира основываясь на таких характеристиках, как возраст, пол, класс билета и путешествовал ли пассажир один.
In [ ]:
import functools
import numpy as np
import tensorflow as tf
In [ ]:
TRAIN_DATA_URL = "https://storage.googleapis.com/tf-datasets/titanic/train.csv"
TEST_DATA_URL = "https://storage.googleapis.com/tf-datasets/titanic/eval.csv"
train_file_path = tf.keras.utils.get_file("train.csv", TRAIN_DATA_URL)
test_file_path = tf.keras.utils.get_file("eval.csv", TEST_DATA_URL)
In [ ]:
# Сделаем значения numpy читабельнее.
np.set_printoptions(precision=3, suppress=True)
In [ ]:
!head {train_file_path}
Вы можете загрузить данные используя pandas, и передать массивы NumPy в TensorFlow. Если Вам нужно масштабироваться до большого количества файлов или нужен загрузчик который совместим с TensorFlow и tf.data то используйте функцию tf.data.experimental.make_csv_dataset
:
Единственная колонка которую нужно указать явно - это та значение которой вы собиратесь предсказывать с помощью модели.
In [ ]:
LABEL_COLUMN = 'survived'
LABELS = [0, 1]
Сейчас прочитайте данные CSV из файла и создайте датасет.
(Для полной документации см. tf.data.experimental.make_csv_dataset
)
In [ ]:
def get_dataset(file_path, **kwargs):
dataset = tf.data.experimental.make_csv_dataset(
file_path,
batch_size=5, # Значение искусственно занижено для удобства восприятия.
label_name=LABEL_COLUMN,
na_value="?",
num_epochs=1,
ignore_errors=True,
**kwargs)
return dataset
raw_train_data = get_dataset(train_file_path)
raw_test_data = get_dataset(test_file_path)
In [ ]:
def show_batch(dataset):
for batch, label in dataset.take(1):
for key, value in batch.items():
print("{:20s}: {}".format(key,value.numpy()))
Каждый элемент в датасете это пакет представленный в виде кортежа (много примеров, много меток). Данные из примеров организованы в тензоры столбцы (а не тензоры строки), каждый с таким количеством элементов каков размер пакета (12 в этом случае).
Будет лучше увидеть это вам самим.
In [ ]:
show_batch(raw_train_data)
Как вы видите столбцы в CVS с именами. Конструктор датасета использует эти имена автоматически. Если файл с которым вы работаете не содержит имен столбцов в первой строке передайте их списком строк в аргумент column_names
функции make_csv_dataset
.
In [ ]:
CSV_COLUMNS = ['survived', 'sex', 'age', 'n_siblings_spouses', 'parch', 'fare', 'class', 'deck', 'embark_town', 'alone']
temp_dataset = get_dataset(train_file_path, column_names=CSV_COLUMNS)
show_batch(temp_dataset)
Этот пример будет использовать все возможные столбцы. Если не нужны некоторые столбцы в датасете, создайте список только из тех колонок, которые вы планируете использовать и передайте его в (опциональный) аргумент select_columns
конструктора.
In [ ]:
SELECT_COLUMNS = ['survived', 'age', 'n_siblings_spouses', 'class', 'deck', 'alone']
temp_dataset = get_dataset(train_file_path, select_columns=SELECT_COLUMNS)
show_batch(temp_dataset)
CSV файл может содержать множество видов данных. Обычно, перед тем как передать данные в вашу модель, вы хотите преобразовать эти смешанные типы в вектор фиксированной длины.
У TensorFlow есть встроенная система для описания распространенных входных преобразований: tf.feature_column
, см. этот учебник для подробностей.
Вы можете преобработать ваши данные используя любой инструмент который вам нравится (например nltk или sklearn), и просто передать обработанные данные в TensorFlow.
Главное преимущество предобработки данных внутри вашей модели это то, что когда вы экспортируете модель она включает препроцессинг. В этом случае вы можете передавать необработанные данные прямо в свою модель.
Если ваши данные уже имеют подходящий числовой формат, вы можете упаковать данные в вектор, прежде чем передать их в модель:
In [ ]:
SELECT_COLUMNS = ['survived', 'age', 'n_siblings_spouses', 'parch', 'fare']
DEFAULTS = [0, 0.0, 0.0, 0.0, 0.0]
temp_dataset = get_dataset(train_file_path,
select_columns=SELECT_COLUMNS,
column_defaults = DEFAULTS)
show_batch(temp_dataset)
In [ ]:
example_batch, labels_batch = next(iter(temp_dataset))
Вот простая функция которая упакует вместе все колонки:
In [ ]:
def pack(features, label):
return tf.stack(list(features.values()), axis=-1), label
Примените это к каждому элементу датасета:
In [ ]:
packed_dataset = temp_dataset.map(pack)
for features, labels in packed_dataset.take(1):
print(features.numpy())
print()
print(labels.numpy())
Если у вас смешанные типы данных, то вам может захотеться выделить эти простые числовые поля. API tf.feature_column
может с этим справиться, но это повлечет за собой накладные расходы, и это стоит делать только если действительно необходимо. Вернитесь к смешанному датасету:
In [ ]:
show_batch(raw_train_data)
In [ ]:
example_batch, labels_batch = next(iter(temp_dataset))
Так что выберите более общий препроцессор который выбирает список числовых свойств и упаковывает их в одну колонку:
In [ ]:
class PackNumericFeatures(object):
def __init__(self, names):
self.names = names
def __call__(self, features, labels):
numeric_freatures = [features.pop(name) for name in self.names]
numeric_features = [tf.cast(feat, tf.float32) for feat in numeric_freatures]
numeric_features = tf.stack(numeric_features, axis=-1)
features['numeric'] = numeric_features
return features, labels
In [ ]:
NUMERIC_FEATURES = ['age','n_siblings_spouses','parch', 'fare']
packed_train_data = raw_train_data.map(
PackNumericFeatures(NUMERIC_FEATURES))
packed_test_data = raw_test_data.map(
PackNumericFeatures(NUMERIC_FEATURES))
In [ ]:
show_batch(packed_train_data)
In [ ]:
example_batch, labels_batch = next(iter(packed_train_data))
In [ ]:
import pandas as pd
desc = pd.read_csv(train_file_path)[NUMERIC_FEATURES].describe()
desc
In [ ]:
MEAN = np.array(desc.T['mean'])
STD = np.array(desc.T['std'])
In [ ]:
def normalize_numeric_data(data, mean, std):
# Центрируем данные
return (data-mean)/std
Сейчас создайте числовой столбец. В API tf.feature_columns.numeric_column
можно использовать аргумент normalizer_fn
который выполнится на каждом пакете.
Добавьте MEAN
и STD
к normalizer fn с помощью functools.partial
.
In [ ]:
# See what you just created.
normalizer = functools.partial(normalize_numeric_data, mean=MEAN, std=STD)
numeric_column = tf.feature_column.numeric_column('numeric', normalizer_fn=normalizer, shape=[len(NUMERIC_FEATURES)])
numeric_columns = [numeric_column]
numeric_column
Когда вы обучаете модель добавьте этот столбец признаков чтобы выбрать и центрировать блок числовых данных:
In [ ]:
example_batch['numeric']
In [ ]:
numeric_layer = tf.keras.layers.DenseFeatures(numeric_columns)
numeric_layer(example_batch).numpy()
Использованная здесь нормализация на основе среднего требует предварительного знания средних значений каждого столбца.
In [ ]:
CATEGORIES = {
'sex': ['male', 'female'],
'class' : ['First', 'Second', 'Third'],
'deck' : ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'],
'embark_town' : ['Cherbourg', 'Southhampton', 'Queenstown'],
'alone' : ['y', 'n']
}
In [ ]:
categorical_columns = []
for feature, vocab in CATEGORIES.items():
cat_col = tf.feature_column.categorical_column_with_vocabulary_list(
key=feature, vocabulary_list=vocab)
categorical_columns.append(tf.feature_column.indicator_column(cat_col))
In [ ]:
# Посмотрите что вы только что создали.
categorical_columns
In [ ]:
categorical_layer = tf.keras.layers.DenseFeatures(categorical_columns)
print(categorical_layer(example_batch).numpy()[0])
Позже, когда вы создадите модель это станет частью обработки входных данных.
Добавьте две коллекции столбцов признаков и передайте их в tf.keras.layers.DenseFeatures
чтобы создать входной слой который извлечет и предобработает оба входных типа:
In [ ]:
preprocessing_layer = tf.keras.layers.DenseFeatures(categorical_columns+numeric_columns)
In [ ]:
print(preprocessing_layer(example_batch).numpy()[0])
Постройте tf.keras.Sequential
начиная с препроцессингового слоя preprocessing_layer
.
In [ ]:
model = tf.keras.Sequential([
preprocessing_layer,
tf.keras.layers.Dense(128, activation='relu'),
tf.keras.layers.Dense(128, activation='relu'),
tf.keras.layers.Dense(1, activation='sigmoid'),
])
model.compile(
loss='binary_crossentropy',
optimizer='adam',
metrics=['accuracy'])
Теперь модель может быть реализована и обучена.
In [ ]:
train_data = packed_train_data.shuffle(500)
test_data = packed_test_data
In [ ]:
model.fit(train_data, epochs=20)
После того как модель обучена вы можете проверить ее точность на множестве test_data
.
In [ ]:
test_loss, test_accuracy = model.evaluate(test_data)
print('\n\nTest Loss {}, Test Accuracy {}'.format(test_loss, test_accuracy))
Используйте tf.keras.Model.predict
чтобы выводить метки на пакет или датасет пакетов.
In [ ]:
predictions = model.predict(test_data)
# Покажем некоторые результаты
for prediction, survived in zip(predictions[:10], list(test_data)[0][1][:10]):
print("Predicted survival: {:.2%}".format(prediction[0]),
" | Actual outcome: ",
("SURVIVED" if bool(survived) else "DIED"))