Часть 4. Обзор функций потерь на Python

Реализация функций потерь на Python:

В Keras можно использовать различные функции потерь, указав их при компиляции модели.

Вот пример того, как использовать среднеквадратическую ошибку (MSE) в качестве функции потерь в нейронной сети:

model.compile(loss='mean_squared_error', optimizer='adam')

Чтобы использовать другую функцию потерь, просто замените строку потерь соответствующим значением.

Чтобы оценить производительность модели с использованием потерь MSE, вы можете использовать функцию оценки:

score = model.evaluate(x_test, y_test)
print('Test MSE:', score)

Результирующая переменная оценки представляет собой MSE для тестового набора данных.

Создание пользовательских функций потерь:

TensorFlow предоставляет широкий спектр готовых функций потерь. Могут возникнуть ситуации, когда потребуется специальная функция потерь, которая лучше соответствует конкретным требованиям конкретной проблемы. При создании пользовательской функции потерь в TensorFlow вы определяете функцию, которая принимает два аргумента: истинные метки (y_true) и прогнозы модели (y_pred), а затем вычисляет потери на основе этих входных данных и возвращает значение потерь. В следующем фрагменте кода показано, как определить пользовательскую функцию потерь.

import tensorflow as tf

def custom_loss(y_true, y_pred):
    squared_difference = tf.square(y_true - y_pred)
    return tf.reduce_mean(squared_difference, axis=-1)

В этом примере мы определяем пользовательскую функцию потерь, которая вычисляет среднеквадратическую ошибку между прогнозируемыми и истинными значениями. Сначала мы вычисляем квадрат разницы между предсказанными и истинными значениями, используя операцию tf.square. Затем мы берем среднее значение квадрата разницы, используя операцию tf.reduce_mean. Эту пользовательскую функцию потерь можно использовать как функцию потерь в модели TensorFlow, передав ее в качестве аргумента методу компиляции модели:

model.compile(optimizer='adam', loss=custom_loss)

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

import tensorflow as tf

def custom_loss_wrapper(alpha):
    def custom_loss(y_true, y_pred):
        squared_difference = tf.square(y_true - y_pred)
        penalized_difference = squared_difference + alpha * tf.square(y_pred)
        return tf.reduce_mean(penalized_difference, axis=-1)
    return custom_loss

В этом примере мы определяем функцию-оболочку под названием custom_loss_wrapper, которая принимает дополнительный аргумент альфа. Функция-обертка возвращает фактическую функцию потерь custom_loss.

Функция custom_loss вычисляет квадрат разницы между y_true и y_pred, а затем добавляет штрафной член, который зависит от значений y_pred, умноженных на альфа. Полученный тензор затем сокращается вдоль последней оси, чтобы получить среднее значение потерь.

Чтобы использовать эту пользовательскую функцию потерь в модели TensorFlow, вы можете вызвать функцию-оболочку с желаемым значением альфа, чтобы получить фактическую функцию потерь, а затем передать эту функцию потерь в качестве аргумента методу компиляции модели:

model.compile(optimizer='adam', loss=custom_loss_wrapper(alpha=0.1))

Вы также можете определить его с помощью внутренних функций Keras. Серверная часть — это, по сути, механизм, который поддерживает структуру машинного обучения и предоставляет интерфейс для быстрого и эффективного выполнения тензорных операций. Например, TensorFlow использует языки C++ и CUDA в качестве серверной части, а Keras предоставляет серверную часть, которая может использовать TensorFlow, Theano или CNTK в качестве базового механизма. Keras предоставляет набор бэкэнд-функций, которые позволяют выполнять низкоуровневые тензорные операции независимо от базового бэкэнда. Это означает, что вы можете писать код, который работает с любым бэкэндом, поддерживаемым Keras, не беспокоясь о конкретных деталях реализации бэкенда. В Keras некоторые из внутренних функций включают backend.dot(), backend.add() и backend.relu(). Причина, по которой эти операции называются бэкэнд-функциями, заключается в том, что они выполняются на более низком уровне, чем API более высокого уровня, который мы обычно используем при построении модели. Эти серверные функции не доступны нам напрямую, когда мы работаем с API высокого уровня. Вместо этого мы используем функции высокого уровня, такие как tf.keras.layers.Dense() в TensorFlow или keras.layers.Dense() в Keras, которые внутренне используют внутренние функции для выполнения вычислений. Бэкэнд-функции важны, поскольку они предоставляют интерфейс для выполнения низкоуровневых тензорных операций независимо от базового бэкэнда. Например, представьте, что вы создаете модель в Keras, которая использует пользовательскую функцию активации, не предоставляемую API высокого уровня. Вы можете написать функцию активации, используя NumPy, но это ограничит работу вашей модели на процессорах. Если вместо этого вы используете серверную функцию Keras для определения функции активации, ваша модель также сможет работать на графических процессорах, что может значительно повысить производительность. Как уже говорилось, они не доступны нам напрямую, когда мы работаем с высокоуровневым API платформы машинного обучения, но они используются внутри компании для выполнения вычислений.

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

# Define a custom loss function using a Python function
def custom_loss(y_true, y_pred):
    # This will raise an error because we are trying to use a Python function on TensorFlow tensors
    squared_difference = (y_true - y_pred) ** 2
    return squared_difference

Однако когда мы пытаемся использовать эту функцию для вычисления потерь, мы получаем ошибку:

TypeError: неподдерживаемые типы операндов для ** или pow(): «Tensor» и «int».

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

from tensorflow.keras import backend as K

# Define a custom loss function using backend functions
def custom_loss(y_true, y_pred):
    squared_difference = K.square(y_true - y_pred) # Use K.square() instead of **
    return squared_difference

Давайте рассмотрим другой пример. Предположим, мы хотим определить пользовательскую функцию потерь, которая наказывает модель за то, что она делает прогнозы, слишком далекие от истинных меток. Один из способов определить эту функцию потерь — использовать функцию tf.norm() для вычисления евклидова расстояния между истинными и прогнозируемыми метками. Однако если мы попытаемся использовать tf.norm() непосредственно в функции потерь, мы получим ValueError, поскольку функция предполагает работать с тензорами одной и той же формы, но y_true и y_pred имеют разные формы.

import tensorflow as tf

def custom_loss(y_true, y_pred):
    distance = tf.norm(y_true - y_pred) # This line will raise a ValueError
    return distance

Чтобы решить эту проблему, мы можем использовать внутренние функции Keras для выполнения тех же вычислений, что и tf.norm(), но с поддержкой тензоров различной формы. Вот обновленный пример, в котором используются функции K.sqrt() и K.sum() для реализации тех же вычислений, что и tf.norm():

import tensorflow as tf
from tensorflow.keras import backend as K

def custom_loss(y_true, y_pred):
    squared_difference = K.square(y_true - y_pred)
    sum_squared_difference = K.sum(squared_difference, axis=-1)
    distance = K.sqrt(sum_squared_difference)
    return distance

В этой обновленной версии мы используем K.square() для вычисления поэлементного квадрата разницы между истинными и предсказанными метками. Затем мы используем K.sum() для суммирования квадратов разностей вдоль последней оси тензора. Наконец, мы используем K.sqrt() для вычисления квадратного корня из суммированных квадратов разностей, что эквивалентно евклидову расстоянию между истинными и предсказанными метками.

Вы также можете использовать другие функции TensorFlow для преодоления ValueError при создании пользовательских функций потерь. Одной из таких функций является tf.reduce_sum(), которую можно использовать для вычисления суммы квадратов разностей между истинными и предсказанными метками. Вот пример того, как использовать tf.reduce_sum() для определения пользовательской функции потерь:

import tensorflow as tf

def custom_loss(y_true, y_pred):
    squared_difference = tf.square(y_true - y_pred)
    sum_squared_difference = tf.reduce_sum(squared_difference, axis=-1)
    distance = tf.sqrt(sum_squared_difference)
    return distance

В этом примере мы используем tf.square() для вычисления поэлементного квадрата разницы между истинными и предсказанными метками. Затем мы используем tf.reduce_sum() для суммирования квадратов разностей вдоль последней оси тензора. Наконец, мы используем tf.sqrt() для вычисления квадратного корня из суммированных квадратов разностей, что эквивалентно евклидову расстоянию между истинными и предсказанными метками.

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

Помимо использования внутренних функций Keras, TensorFlow также предоставляет другой способ определения пользовательских функций потерь с помощью класса tf.keras.losses.Loss. Чтобы определить пользовательскую функцию потерь с помощью tf.keras.losses.Loss, вам необходимо создать новый класс, который наследуется от tf.keras.losses.Loss, и реализовать два метода: __init__() и call(). Метод __init__() используется для определения любых гиперпараметров или аргументов, которые будут использоваться функцией потерь. Метод call() используется для фактического вычисления значения потерь с учетом истинных и прогнозируемых меток.

Вот пример того, как определить пользовательскую функцию потерь с помощью tf.keras.losses.Loss:

import tensorflow as tf

class CustomLoss(tf.keras.losses.Loss):
    def __init__(self):
        super().__init__()

    def call(self, y_true, y_pred):
        return tf.reduce_mean(tf.math.square(y_pred - y_true))

# Compile the model using the custom loss function
model.compile(loss=CustomLoss(), optimizer='adam', metrics=['accuracy'])
model.fit(x_train, x_train, epochs=100)

В этом примере мы создаем пользовательскую функцию потерь под названием CustomLoss, которая принимает истинные значения и прогнозируемые значения в качестве входных данных и возвращает среднеквадратическую ошибку между ними. Класс CustomLoss(tf.keras.losses.Loss) определяет пользовательскую функцию потерь, которая наследуется от класса tf.keras.losses.Loss. Класс CustomLoss является подклассом класса tf.keras.losses.Loss. Это означает, что он наследует все методы и свойства класса Loss, необходимые для использования в качестве функции потерь в модели Keras. Это позволяет вам легко интегрировать вашу пользовательскую функцию потерь в конвейер обучения модели Keras.

#Custom Loss Function Visualization:
plt.plot(model.history['loss'])
plt.title('Custom Loss Function')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.show()

Бонусный балл: Разница между классификацией по нескольким классам и классификацией по нескольким меткам. Классификация по нескольким классам — это задача классификации, в которой выходными данными является один из нескольких классов. Она также известна как классификация по одной метке, поскольку каждому экземпляру присваивается один класс. Напротив, классификация по нескольким меткам представляет собой проблему, когда экземпляру может быть присвоено несколько классов. Чтобы проиллюстрировать разницу:

Пример многоклассовой классификации: классификация животных по таким категориям, как «кошка», «собака», «птица», «рыба» и т. д., где каждое животное принадлежит только к одной из этих категорий.

Пример классификации по нескольким меткам: пометка изображений такими метками, как «пляж», «закат», «семья», «собака» и т. д., при этом изображение может иметь несколько меток в зависимости от его содержания.

Заключительное примечание. На этом мы подходим к последней главе нашего путешествия по функциям потерь. Я надеюсь, что эта серия пролила свет на важную роль, которую функции потерь играют в основе глубокого обучения.

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