Мы собрали данные с машины в какой-то пищевой компании. Задача состоит в том, чтобы использовать эти данные и предсказать, в плохом состоянии машина или нет.

Для этого мы будем обучать модель на хороших данных (когда машина находится в нормальном рабочем состоянии). Мы не будем обучать модель на плохих данных (когда машина требует обслуживания). Вместо этого мы прогнозируем по оперативным данным. Мы предполагаем, что при наличии достаточного количества хороших данных для моделирования он научится отличать хорошее состояние от плохого, а затем прогнозировать на основе реальных данных.

Мы уже преобразовали необработанные данные в функции, а также очистили их. Эти функции хранятся в виде файлов NumPy. В настоящее время нам все равно, что это за функции. Некоторый случайный массив NumPy сможет выполнить то, что мы хотим сделать здесь. Существуют различные руководства по использованию API tf.data для CSV, изображений, текстовых данных. Но очень немногие обсуждают, как обрабатывать файлы NumPy.

В примерах мы подгоняем случайные данные к автоэнкодеру. То, как автоэнкодер предсказывает, хорошие или плохие входящие данные, выходит за рамки этого поста.

Нам не важна точность или производительность модели, наша задача — ускорить обучение автоэнкодера на большом количестве данных.

Что вы узнаете из этого поста?

Прочитав этот пост, вы получите ответы на эти вопросы.

  1. Как создать конвейер TensorFlow.data (tf.data) специально для файлов NumPy?
  2. Как эффективно использовать TensorBoard для построения конвейеров tf.data?
  3. Как применить предварительную обработку, такую ​​как минимальное/максимальное масштабирование, к конвейеру tf.data?
  4. Как использовать генераторы в tf.data?
  5. Как мы сравниваем различные подходы к обработке файлов NumPy?

Весь код доступен в этой записной книжке.

Установить зависимости

Установите следующие зависимости в вашей среде. Если вы используете блокнот Jupyter, выполните следующее.

! pip install tensorflow==2.8.0
! pip install scikit-learn==0.24.2
! pip install numpy==1.21.5
! pip установить tensorboard-plugin-profile == 2.5.0

Начало работы с TensorBoard

Нам нужно использовать TensorBoard для просмотра времени, затраченного на обработку данных.

Чтобы запустить TensorBoard, вам необходимо установить вышеуказанные пакеты pip, а затем в терминале использовать

tensorboard --logdir <path to the directory where tensorflow writes logs >

Например, я запускаю этот блокнот по пути ~/articles/tf_data, и весь код создает каталог с именем logs для записи этих журналов. Так что я дам команду

tensorboard --logdir ~/articles/tf_data/logs

Доска запустится, и в вашем браузере введите http://localhost:6006/ и нажмите Enter.

Теперь в раскрывающемся списке в правом верхнем углу выберите профиль, как показано ниже.

Вы перейдете на страницу обзора профилировщика, как показано ниже. Теперь вы готовы с TensorBoard.

Начиная

Мы создадим поддельный набор данных, а также напишем обучающий скрипт с использованием API tensorflow.keras.

Набор данных состоит из файлов NumPy. Количество функций в каждом файле фиксировано. Однако количество строк является переменным.

Мы обучим автоэнкодер идентифицировать аномалию. Мы также подгоним к данным мин/макс масштабатор. Вот код для создания автоэнкодера.

Мы будем использовать три подхода для подачи данных в модель. Мы будем использовать профилировщик TensorBoard, чтобы сравнить все три подхода.

1. Загрузить все данные прямо в ОЗУ

2. Используйте генераторы

3. Используйте конвейер TF.data

Подход 1 — загрузить все данные в ОЗУ

В этом подходе подача данных в модель ML является самой быстрой. Однако все выходит из-под контроля, когда данные огромны, а оперативная память ограничена. Тем не менее, мы попробуем этот подход, и он работает для наборов данных, которые могут поместиться в ОЗУ.

Настройте некоторые обратные вызовы для TensorBoard.

from tensorflow.keras.callbacks import TensorBoard, ReduceLROnPlateau, ModelCheckpoint, EarlyStopping
model_path = os.path.join(os.getcwd(), 'model')

# We won't get anything in tensorboard unless we setup callbacks for # writing logs.
callbacks = [
    EarlyStopping(monitor='val_loss', mode='min', patience=61, verbose=1, min_delta=1e-07),
    ReduceLROnPlateau(monitor='val_loss', mode='min', patience=12, factor=0.25, verbose=True, min_lr=1e-05,
                      min_delta=1e-07),
    ModelCheckpoint(model_path, monitor='val_loss', mode='auto', save_best_only=True, verbose=0,
                    save_weights_only=False),
    TensorBoard(log_dir='./logs', histogram_freq=1, write_graph=True, write_images=True, 
                profile_batch = '1,10')
    
]

Наконец, обучите модель

import multiprocessing

# Finally we fit the model.
autoencoder = create_ae_model()

history = autoencoder.fit(X_train_scaled,X_train_scaled, steps_per_epoch=X_train_scaled.shape[0]//BATCH_SIZE,
                          validation_data=(X_validation_scaled, X_validation_scaled),
                          epochs=NO_OF_EPOCHS, batch_size=BATCH_SIZE, callbacks=callbacks,
                          validation_steps=X_validation_scaled.shape[0]//BATCH_SIZE,
                          use_multiprocessing=True,
                          workers=multiprocessing.cpu_count() * 3)
Model: "sequential"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 dense (Dense)               (None, 64)                64064     
                                                                 
 dense_1 (Dense)             (None, 64)                4160      
                                                                 
 dense_2 (Dense)             (None, 64)                4160      
                                                                 
 dense_3 (Dense)             (None, 64)                4160      
                                                                 
 dense_4 (Dense)             (None, 64)                4160      
                                                                 
 dense_5 (Dense)             (None, 1000)              65000     
                                                                 
=================================================================
Total params: 145,704
Trainable params: 145,704
Non-trainable params: 0
_________________________________________________________________
Epoch 1/3
7399/7407 [============================>.] - ETA: 0s - loss: 0.6932 - mae: 0.2500 - mse: 0.0833INFO:tensorflow:Assets written to: /home/deepanshu/foglamp_workspace/gcp/articles/tf_data/model/assets
7407/7407 [==============================] - 163s 21ms/step - loss: 0.6932 - mae: 0.2500 - mse: 0.0833 - val_loss: 0.6932 - val_mae: 0.2500 - val_mse: 0.0833 - lr: 0.0010
Epoch 2/3
7407/7407 [==============================] - 46s 6ms/step - loss: 0.6932 - mae: 0.2500 - mse: 0.0833 - val_loss: 0.6932 - val_mae: 0.2500 - val_mse: 0.0833 - lr: 0.0010
Epoch 3/3
7407/7407 [==============================] - 44s 6ms/step - loss: 0.6932 - mae: 0.2500 - mse: 0.0833 - val_loss: 0.6932 - val_mae: 0.2500 - val_mse: 0.0833 - lr: 0.0010

Журналы TensorBoard

Заметим, что среднее время загрузки данных здесь составляет 4,4 миллисекунды. Пожалуйста, обновите браузер после обучения, чтобы просмотреть это в TensorBoard.

Подход 2 — использование генераторов

Проблема с первым методом заключается в том, что он не будет работать, когда у нас есть большие наборы данных. Вместо этого мы можем попробовать следующий подход.

Мы можем составить список кортежей. Каждый кортеж — это имя файла, метка класса (в нашем случае всегда равна нулю), индекс строки в этом файле.

Например, если у нас есть файл с формой (360, 1000).

Тогда для этого файла у нас есть

(имя_файла, 0, 0)
(имя_файла, 0, 1)
(имя_файла, 0, 2)


(имя_файла, 0, 357)
(имя_файла, 0, 358)
(имя_файла, 0, 359)

Точно так же мы будем иметь эти значения для остальных файлов. Мы объединим все эти значения в один большой список.

Загрузка этого гигантского списка в память теперь не будет большой проблемой.

Класс для генераторов

Мы напишем класс, который будет обрабатывать генераторы.

Теперь мы создадим генераторы;

Обратные вызовы для Tensoroard

from tensorflow.keras.callbacks import TensorBoard, ReduceLROnPlateau, ModelCheckpoint, EarlyStopping
model_path = os.path.join(os.getcwd(), 'model')

# As usual set up the callbacks. 
callbacks = [
    EarlyStopping(monitor='val_loss', mode='min', patience=61, verbose=1, min_delta=1e-07),
    ReduceLROnPlateau(monitor='val_loss', mode='min', patience=12, factor=0.25, verbose=True, min_lr=1e-05,
                      min_delta=1e-07),
    ModelCheckpoint(model_path, monitor='val_loss', mode='auto', save_best_only=True, verbose=0,
                    save_weights_only=False),
    TensorBoard(log_dir='./logs', histogram_freq=1, write_graph=True, write_images=True, 
                profile_batch = '1,10')
    
]

Обучите модель с помощью генераторов

import multiprocessing

autoencoder = create_ae_model()

# Fit the model.
history = autoencoder.fit(dataset_train, steps_per_epoch=train_gen.len,
                          validation_data=dataset_valid,
                          epochs=NO_OF_EPOCHS, batch_size=BATCH_SIZE, callbacks=callbacks,
                          validation_steps=valid_gen.len,
                          use_multiprocessing=True,
                          workers=multiprocessing.cpu_count() * 3)
Model: "sequential_1"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 dense_6 (Dense)             (None, 64)                64064     
                                                                 
 dense_7 (Dense)             (None, 64)                4160      
                                                                 
 dense_8 (Dense)             (None, 64)                4160      
                                                                 
 dense_9 (Dense)             (None, 64)                4160      
                                                                 
 dense_10 (Dense)            (None, 64)                4160      
                                                                 
 dense_11 (Dense)            (None, 1000)              65000     
                                                                 
=================================================================
Total params: 145,704
Trainable params: 145,704
Non-trainable params: 0
_________________________________________________________________
Epoch 1/3
7401/7407 [============================>.] - ETA: 0s - loss: 0.6932 - mae: 0.2500 - mse: 0.0833INFO:tensorflow:Assets written to: /home/deepanshu/foglamp_workspace/gcp/articles/tf_data/model/assets
7407/7407 [==============================] - 108s 14ms/step - loss: 0.6932 - mae: 0.2500 - mse: 0.0833 - val_loss: 0.6932 - val_mae: 0.2500 - val_mse: 0.0833 - lr: 0.0010
Epoch 2/3
7407/7407 [==============================] - 85s 12ms/step - loss: 0.6932 - mae: 0.2500 - mse: 0.0833 - val_loss: 0.6932 - val_mae: 0.2500 - val_mse: 0.0833 - lr: 0.0010
Epoch 3/3
7407/7407 [==============================] - 85s 11ms/step - loss: 0.6932 - mae: 0.2500 - mse: 0.0833 - val_loss: 0.6932 - val_mae: 0.2500 - val_mse: 0.0833 - lr: 0.0010

Очевидно, что сейчас нам требуется больше времени на подготовку. Эта разница станет огромной, когда данные станут большими. Нам нужно разработать интеллектуальный конвейер данных для обучения на больших объемах данных. Для этого tf.data (следующий подход) будет служить нашей цели.

Журналы TensorBoard

Если мы используем генераторы, время увеличилось до 7 миллисекунд. Пожалуйста, обновите браузер после тренировки.

Подход 3 — Используйте TF.data

Поскольку наши файлы NumPy имеют фиксированное количество функций, мы можем использовать класс FixedLengthRecordDataset для их загрузки. Этот подход действителен только в том случае, если у нас есть фиксированное количество функций. Также это справедливо для любого двоичного файла, а не только для файлов NumPy.

Подготовьте данные

Настройка конвейера

Теперь давайте создадим конвейер сборки. Следите за комментариями в коде, чтобы получить представление о том, что происходит на каждом этапе.

Настройка обратных вызовов

from tensorflow.keras.callbacks import TensorBoard, ReduceLROnPlateau, ModelCheckpoint, EarlyStopping
model_path = os.path.join(os.getcwd(), 'model')

# Set up callbacks.
callbacks = [
    EarlyStopping(monitor='val_loss', mode='min', patience=61, verbose=1, min_delta=1e-07),
    ReduceLROnPlateau(monitor='val_loss', mode='min', patience=12, factor=0.25, verbose=True, min_lr=1e-05,
                      min_delta=1e-07),
    ModelCheckpoint(model_path, monitor='val_loss', mode='auto', save_best_only=True, verbose=0,
                    save_weights_only=False),
    TensorBoard(log_dir='./logs', histogram_freq=1, write_graph=True, write_images=True, 
                profile_batch = '1,10')
    
]

Подходит для модели

import multiprocessing

autoencoder = create_ae_model()

# Fit the model. 
history = autoencoder.fit(dataset_train, steps_per_epoch=total_examples_train//BATCH_SIZE,
                          validation_data=dataset_valid,
                          epochs=NO_OF_EPOCHS, batch_size=BATCH_SIZE, callbacks=callbacks,
                          validation_steps=total_examples_validation//BATCH_SIZE,
                          use_multiprocessing=True,
                          workers=multiprocessing.cpu_count() * 3)
Model: "sequential_2"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 dense_12 (Dense)            (None, 64)                64064     
                                                                 
 dense_13 (Dense)            (None, 64)                4160      
                                                                 
 dense_14 (Dense)            (None, 64)                4160      
                                                                 
 dense_15 (Dense)            (None, 64)                4160      
                                                                 
 dense_16 (Dense)            (None, 64)                4160      
                                                                 
 dense_17 (Dense)            (None, 1000)              65000     
                                                                 
=================================================================
Total params: 145,704
Trainable params: 145,704
Non-trainable params: 0
_________________________________________________________________
Epoch 1/3
7405/7407 [============================>.] - ETA: 0s - loss: 0.6932 - mae: 0.2500 - mse: 0.0833INFO:tensorflow:Assets written to: /home/deepanshu/foglamp_workspace/gcp/articles/tf_data/model/assets
7407/7407 [==============================] - 61s 8ms/step - loss: 0.6932 - mae: 0.2500 - mse: 0.0833 - val_loss: 0.6932 - val_mae: 0.2500 - val_mse: 0.0833 - lr: 0.0010
Epoch 2/3
7407/7407 [==============================] - 47s 6ms/step - loss: 0.6932 - mae: 0.2500 - mse: 0.0833 - val_loss: 0.6932 - val_mae: 0.2500 - val_mse: 0.0833 - lr: 0.0010
Epoch 3/3
7407/7407 [==============================] - 52s 7ms/step - loss: 0.6932 - mae: 0.2500 - mse: 0.0833 - val_loss: 0.6932 - val_mae: 0.2500 - val_mse: 0.0833 - lr: 0.0010

Как мы видим, это почти сравнимо с первым случаем.

Журналы TensorBoard

Теперь время подошло к 4.9, что похоже на случай, когда мы загружались из оперативной памяти. Пожалуйста, обновите браузер после обучения, чтобы просмотреть это.

Некоторое исследование, которое можно сделать, - это попробовать некоторые другие методы, такие как чередование для повышения производительности, или даже попробовать tf.data.AUTO_TUNE для автоматического выбора лучших параметров. Я оставляю эту задачу читателю.

Рекомендации

См. этот отличный путеводитель, чтобы узнать больше.

Это — еще одна полезная ссылка.

Сообщение StackOverflow для этого примера — это.