Как определить пользовательский слой, функцию активации и функцию потерь в TensorFlow
Пошаговое объяснение и примеры с полным кодом
У меня есть несколько руководств по Tensorflow, где всегда использовались встроенные функции потерь и слои. Но Tensorflow намного динамичнее этого. Это позволяет нам писать собственные пользовательские функции потерь и создавать собственные пользовательские слои. Итак, есть много способов создавать высокоэффективные модели в Tensorflow.
Лучший способ учиться — это делать. Итак, мы будем учиться с помощью упражнений с использованием бесплатного общедоступного набора данных, который я использовал в своем последнем руководстве по модели с несколькими выходами.
Я предполагаю, что вы уже знакомы с основами анализа данных, очистки данных и Tensorflow. Итак, вначале мы будем двигаться немного быстрее.
Обработка данных
Открытый общедоступный набор данных, который я буду использовать в этом руководстве, довольно чистый. Но все же, немного очистки необходимо.
Вот ссылка на набор данных:
Я уже очистил набор данных по мере необходимости. Пожалуйста, не стесняйтесь загружать чистый набор данных отсюда, чтобы следовать:
Давайте начнем.
Сначала импортируйте сюда все необходимые пакеты:
import numpy as np import pandas as pd import tensorflow as tf from tensorflow.keras import Sequential from tensorflow.keras.layers import Dense from tensorflow.keras.optimizers import Adam from tensorflow.keras import backend as K from tensorflow.keras.layers import Layer
Вот набор данных:
df = pd.read_csv("auto_price.csv")
Хотя я сказал, что это чистый набор данных, в нем все еще есть два ненужных столбца, которые нужно удалить:
df = df.drop(columns=['Unnamed: 0', 'symboling'])
Мы разделим набор данных на три части. Один для обучения, один для тестирования и один для проверки.
from sklearn.model_selection import train_test_split train, test = train_test_split(df, test_size=0.2, random_state=2) train, val = train_test_split(train, test_size=0.2, random_state=23)
Чтобы нормализовать данные обучения с использованием метода z-оценки, нам нужно знать среднее значение и стандартное отклонение всех функций обучения. Вот как я это понял:
train_stats = train.describe() train_stats= train_stats.transpose() train_stats
Также есть дополнительная информация, но также есть среднее значение и стандартное отклонение.
Эта функция нормы берет данные и нормализует их, используя среднее значение и стандартное отклонение, которые мы получили на предыдущем шаге:
def norm(x): return (x - train_stats['mean']) / train_stats['std']
Давайте нормализуем данные обучения, тестирования и проверки:
train_x = norm(train) test_x = norm(test) val_x = norm(val)
В этом упражнении цена автомобиля будет использоваться как целевая переменная, а остальные переменные — как обучающие признаки.
train_x = train_x.drop(columns='price') test_x = test_x.drop(columns='price') val_x=val_x.drop(columns='price') train_y = train['price'] test_y = test['price'] val_y = val['price']
Обучающие и целевые переменные готовы.
Пользовательские потери и пользовательский слой
Начнем с функции потерь, которую мы все знаем. Это среднеквадратическая ошибка. Мы определим его как функцию и передадим эту функцию при компиляции модели.
def rmse(y_true, y_pred): return K.sqrt(K.mean(K.square(y_pred - y_true)))
Выглядит очень знакомо, правда? Давайте сохраним эту функцию под рукой, чтобы использовать ее позже. Есть много других видов функций потерь, которые вы можете попробовать.
Теперь перейдем к пользовательскому слою. Для этого мы также будем использовать простую линейную формулу Y=WX+B в качестве формулы. Эта формула требует весов, которые являются коэффициентами X и Bias (обозначаются как «B» в формуле). Я объясню более подробно после того, как вы увидите код для этого:
class SimpleLinear(Layer): def __init__(self, units=64, activation=None): super(SimpleLinear, self).__init__() self.units = units self.activation=tf.keras.activations.get(activation) def weightsAndBias(self, input_shape): w_init = tf.random_normal_initializer() self.w = tf.Variable(name="kernel", initial_value=w_init(shape=(input_shape[-1], self.units), dtype='float32'), trainable=True) b_init = tf.zeros_initializer() self.b = tf.Variable(name="bias", initial_value=b_init(shape=(self.units,), dtype='float32'), trainable=True) def call(self, inputs): return self.activation(tf.matmul(inputs, self.w) + self.b)
В приведенном выше коде мы начали с передачи единиц измерения и активации в качестве параметров. Здесь я использовал единицы измерения 64, что означает 64 нейрона. В конечном итоге мы укажем разные числа в качестве нейронов в модели. Здесь активации нет. Мы также будем использовать активацию в модели.
В приведенном выше «weightsAndBias» мы инициируем веса и смещения, где веса инициируются как случайные числа, а смещения как нули.
В функции вызова мы умножаем наши входные данные и веса, используя матричное умножение (метод matmul выполняет матричное умножение) и добавляем к нему смещение (помните формулу wx+b)
Это самый основной. Пожалуйста, не стесняйтесь попробовать некоторые нелинейные слои, это могут быть квадратичные или кубические формулы.
Разработка модели
Разработка модели — более простая часть. У нас есть 24 переменных в качестве обучающих функций. Таким образом, входная форма (24, ). Вот полная модель:
model = tf.keras.models.Sequential([ tf.keras.layers.Flatten(input_shape=(24,)), SimpleLinear(512, activation='relu'), tf.keras.layers.Dropout(0.2), SimpleLinear(256, activation='relu'), SimpleLinear(128, activation='relu'), tf.keras.layers.Dense(1, activation='relu') ])
Как видите, мы просто вызвали метод SimpleLinear, который мы определили ранее как слои. 512, 256 и 128 — это единицы измерения, а активация — «relu».
Хотя также можно использовать собственный метод активации, который будет в следующей части.
Давайте скомпилируем модель и воспользуемся функцией потерь «rmse», которую мы определили ранее:
model.compile(optimizer='adam', loss = rmse, metrics=tf.keras.metrics.RootMeanSquaredError()) h = model.fit(train_x, train_y, epochs=3) model.evaluate(val_x, val_y)
Выход:
Epoch 1/3 4/4 [==============================] - 0s 3ms/step - loss: 13684.0762 - root_mean_squared_error: 13726.8496 Epoch 2/3 4/4 [==============================] - 0s 3ms/step - loss: 13669.2314 - root_mean_squared_error: 13726.8496 Epoch 3/3 4/4 [==============================] - 0s 3ms/step - loss: 13537.3682 - root_mean_squared_error: 13726.8496
В следующей части мы поэкспериментируем с некоторыми пользовательскими функциями активации.
Пользовательская функция активации
Здесь я объясню два способа использования пользовательской функции активации. Первый заключается в использовании лямбда-слоя. Лямбда-слой определяет функцию прямо в слое.
Например, в следующей модели слой лямбда берет выходные данные метода SimpleLinear и принимает его абсолютные значения, поэтому мы не получаем никаких отрицательных значений.
model = tf.keras.models.Sequential([ tf.keras.layers.Flatten(input_shape=(24,)), SimpleLinear(512), tf.keras.layers.Lambda(lambda x: tf.abs(x)), tf.keras.layers.Dropout(0.2), SimpleLinear(256), tf.keras.layers.Lambda(lambda x: tf.abs(x)), tf.keras.layers.Dense(1), tf.keras.layers.Lambda(lambda x: tf.abs(x)), ])
Пожалуйста, не стесняйтесь пробовать любые другие виды операций на лямбда-слое.
Вам не нужно определять операцию в самом лямбда-слое. Его можно определить в функции и передать на уровень лямбда.
Вот функция, которая берет данные и возводит их в квадрат:
def active1(x): return x**2
Теперь эту функцию можно просто передать в лямбда-слой следующим образом:
model = tf.keras.models.Sequential([ tf.keras.layers.Flatten(input_shape=(24,)), SimpleLinear(512), tf.keras.layers.Lambda(active1), tf.keras.layers.Dropout(0.2), SimpleLinear(256), tf.keras.layers.Lambda(active1), tf.keras.layers.Dense(1), tf.keras.layers.Lambda(active1), ])
Есть так много других различных функций, которые можно использовать в зависимости от вашего проекта и ваших потребностей.
Заключение
Tensorflow может быть таким динамичным в использовании. Есть так много разных способов, которыми можно манипулировать. В этой статье я хотел поделиться некоторыми методами, позволяющими сделать Tensorflow более гибким для вас. Я надеюсь, что это полезно, и вы попробуете это в своих собственных проектах.
Не стесняйтесь подписываться на меня в Twitter и лайкать мою страницу Facebook.