PyTorch
PyTorch – это библиотека Машинного обучения (ML) с открытым исходным кодом, позволяющая решать огромное количество задач, в числе которых:
- Распознавание изображений (Image Recognition)
- Обнаружение мошеннических операций (Fraud Detection)
- Распознавание рукописного текста (Hadrwriting Recognition) и проч.

Основные преимущества:
- Готовность к развертыванию: сопутствующие сервисы TorchScript – программа для создания и оптимизации Модели (Model) и TorchServe – фреймворк для развертывания обученной модели
- Оптимизация производительности
- Надежная экосистема расширяет PyTorch и поддерживает разработку в области Компьютерного зрения (CV), Обработки естественного языка (NLP) и других областях.
- Облачная поддержка: PyTorch хорошо поддерживается на основных облачных платформах, обеспечивая беспроблемную разработку и легкое масштабирование.
Простейшая модель на PyTorch
Посмотрим, как работает фреймворк и насколько кратким может быть код. Для начала импортируем необходимые библиотеки:
import numpy as np
Мы инициируем линейную регрессию. Мы используем функцию, которая комбинирует входные значения x и веса w линейно. Создадим обучающие выборки x и y: тип данных – ‘numpy.float32’. Y – это просто удвоенные значения x. Инициализируем наши веса, равные нулю для начала:
X = np.array([1, 2, 3, 4], dtype=np.float32)
Y = np.array([2, 4, 6, 8], dtype=np.float32)
w = 0.0
А теперь нам нужно создать прогноз, рассчитать потери и градиент. Каждый из этих шагов мы выполним вручную. Инициализируем функцию "Прямой проход" (Forward Pass), и она получит x в качестве аргумента. "На выходе" у нашей функции W, умноженный на X
def forward(x):
return w * x
Здесь мы определяем потерю функции, которая зависит от прогнозируемых y. В случае линейной регрессии, это среднеквадратическая ошибка. Мы можем рассчитать это, возведя разницы между предсказанными и реальными значениями y в квадрат и взяв среднее от полученного:
Нам предстоит теперь вручную рассчитать градиент потерь согласно нашим параметрам.
def loss(y, y_pred):
return ((y_pred - y)**2).mean()
Давайте посмотрим на среднеквадратичную ошибку. Формула выглядит так:
У нас есть производная. Частное производных J и весов равно отношению единицы к N, умноженное на 2x и (w * x - y):
Мы реализуем это с помощью функции gradient следующим образом. Мы можем сделать это в одной строке, поэтому возвращаем numpy., умноженное на два X, разница между предсказанным и реальным y. И, конечно, нам также понадобится среднее:
# # MSE = 1 / N * (w* x - y) ** 2
# dJ / dw = 1 / N * 2x * (w * x - y)
def gradient(x, y, y_pred):
return np.dot(2*x, y_pred - y).mean()
Выведем наш прогноз перед обучением:
print(f'Предсказание перед обучением: f(5) = {forward(5):.3f}')
До наших тренировок прогноз равен нулю.
Предсказание перед обучением: f(5) = 0.000
А теперь приступим к обучению и определим некоторые параметры. Нам нужна скорость обучения, которая равна нулю. Определим число итераций, равное 20:
learning_rate = 0.01
n_iters = 20
Теперь давайте выполним наш цикл обучения. Выполним прямой проход, функцией forward(). Затем рассчитаем потери, потому Y теперь нам нужен, чтобы получить градиенты. И теперь мы должны обновить наши веса. Формула обновления в алгоритме градиентного спуска заключается в том, что мы просто меняем на противоположное скорость обучения градиента, а затем умножаем ее на наш градиент.
Итак, это формула обновления. Допустим, мы также хотим вывести здесь некоторую информацию, поэтому мы выводим на экран каждый шаг, если он не равен 0. Мы хотим отобразить данные о каждой эпохе. Мы инкриминируем число эпох на один, потому что нумерация смещена, а затем отображаем веса с тремя знаками после запятой. Потери отобразим по восьмой знак после запятой:
for epoch in range(n_iters):
y_pred = forward(X)
l = loss(Y, y_pred)
dw = gradient(X, Y, y_pred)
w -= learning_rate * dw
if epoch % 2 == 0:
print(f'Эпоха {epoch+1}: w = {w:.3f}, потери = {l:.8f}')
Смотрите, как снижаются потери с каждой эпохой:
Эпоха 1: w = 1.200, потери = 30.00000000
Эпоха 3: w = 1.872, потери = 0.76800019
Эпоха 5: w = 1.980, потери = 0.01966083
Эпоха 7: w = 1.997, потери = 0.00050331
Эпоха 9: w = 1.999, потери = 0.00001288
Эпоха 11: w = 2.000, потери = 0.00000033
Эпоха 13: w = 2.000, потери = 0.00000001
Эпоха 15: w = 2.000, потери = 0.00000000
Эпоха 17: w = 2.000, потери = 0.00000000
Эпоха 19: w = 2.000, потери = 0.00000000
Напомню, наша формула y равен 2 на X, поэтому наша W равна двум в начале. Мы видим, что с каждым шагом тренировки увеличиваются веса и уменьшаются потери.
Давайте используем интерполяцию – смешение текстовых данных и вычисляемого значения. Предположим, что мы хотим предсказать значение y при х, равное 5; это 10. Отобразим результат как число с трем знаками после запятой:
print(f'Предсказание после обучением: f(5) = {forward(5):.3f}')
После обучения наша модель предсказывает с точностью 1,9999:
Предсказание после обучением: f(5) = 10.000
Ноутбук, не требующий дополнительной настройки на момент написания статьи, можно скачать здесь.