Я недавно начал работать с Pytorch , Python Framework для нейронных сетей и машинного обучения. Поскольку машинное обучение включает в себя обработку большого количества данных, иногда может быть трудно понять результаты, которые получают от сети. Прежде чем попасть во что-то сложное, давайте повторим действительно базовую обратную обработку в качестве достоверности чека. Чтобы запустить код в этой статье, вам нужно установить Numpy и Pytorch Отказ
В праймеру нейронных сетей мы увидели, как вручную рассчитать распространение вперед и назад для крошечной сети, состоящей из одного входного нейрона, одного скрытого нейрона и одного выходного нейрона:
Мы провели вход 0,8 Через сеть, затем обратно использовать использование 1 Как целевое значение, с темпом обучения 0,1 Отказ Мы использовали Sigmoid в качестве функции активации и функцию квадратичной стоимости для сравнения фактической вывода из сети с желаемым выходом.
Ниже приведен код Pytorch, чтобы сделать то же самое:
import torch import torch.nn as nn import torch.optim as optim class Net(nn.Module): def __init__(self): super(Net, self).__init__() self.hidden_layer = nn.Linear(1, 1) self.hidden_layer.weight = torch.nn.Parameter(torch.tensor([[1.58]])) self.hidden_layer.bias = torch.nn.Parameter(torch.tensor([-0.14])) self.output_layer = nn.Linear(1, 1) self.output_layer.weight = torch.nn.Parameter(torch.tensor([[2.45]])) self.output_layer.bias = torch.nn.Parameter(torch.tensor([-0.11])) def forward(self, x): x = torch.sigmoid(self.hidden_layer(x)) x = torch.sigmoid(self.output_layer(x)) return x net = Net() print(f"network topology: {net}") print(f"w_l1 = {round(net.hidden_layer.weight.item(), 4)}") print(f"b_l1 = {round(net.hidden_layer.bias.item(), 4)}") print(f"w_l2 = {round(net.output_layer.weight.item(), 4)}") print(f"b_l2 = {round(net.output_layer.bias.item(), 4)}") # run input data forward through network input_data = torch.tensor([0.8]) output = net(input_data) print(f"a_l2 = {round(output.item(), 4)}") # backpropagate gradient target = torch.tensor([1.]) criterion = nn.MSELoss() loss = criterion(output, target) net.zero_grad() loss.backward() # update weights and biases optimizer = optim.SGD(net.parameters(), lr=0.1) optimizer.step() print(f"updated_w_l1 = {round(net.hidden_layer.weight.item(), 4)}") print(f"updated_b_l1 = {round(net.hidden_layer.bias.item(), 4)}") print(f"updated_w_l2 = {round(net.output_layer.weight.item(), 4)}") print(f"updated_b_l2 = {round(net.output_layer.bias.item(), 4)}") output = net(input_data) print(f"updated_a_l2 = {round(output.item(), 4)}")
Некоторые заметки по этому коду:
посадка Линейный
используется для полностью подключенных или плотных, слоев. Для этого простого случая у нас есть один вход и один вывод для каждого слоя.-
вперед
Способ вызывается, когда мы передаем ввод в сеть с помощьюВыход (input_data)
Отказ - По умолчанию Pytorch устанавливает случайные веса и предубеждения. Однако здесь мы инициализируем их напрямую, поскольку мы хотим, чтобы результаты соответствовали нашему ручному расчету (позже в статье).
- В питорче,
тензор
аналогиченМассив
в Numpy. критерий. MSELOSS ()
Настраивает функцию квадратичной стоимости – хотя она называется функцией потери ошибок в квадрате в Pyyorch.потеря (вывод, цель)
рассчитывает стоимость, также известную как потери.- Далее мы используем
net.zero_grad ()
Для сброса градиента до нуля (в противном случае обратная обработка кумулятивна). Здесь не нужно строго, но приятно держать это в виду при запуске обратной обработки в цикле. потеря. Backward ()
Вычисляет градиент, то есть производная стоимости в отношении всех весов и предубеждений.- Наконец мы используем этот градиент для обновления весов и предубеждений в сети, используя
SGD
(Стохастический градиентный спуск) Оптимизатор, с учебной скоростью 0,1 Отказ
Результаты ниже:
C:\Dev\python\pytorch>python backprop_pytorch.py network topology: Net( (hidden_layer): Linear(in_features=1, out_features=1, bias=True) (output_layer): Linear(in_features=1, out_features=1, bias=True) ) w_l1 = 1.58 b_l1 = -0.14 w_l2 = 2.45 b_l2 = -0.11 a_l2 = 0.8506 updated_w_l1 = 1.5814 updated_b_l1 = -0.1383 updated_w_l2 = 2.4529 updated_b_l2 = -0.1062 updated_a_l2 = 0.8515
Мы распечатаем топологию сети, а также веса, смещения и вывод, как до, так и после шага обратной задачи.
Ниже давайте повторим этот расчет простым питоном. Этот расчет почти такой же, как тот, который мы видели в грунтовке нейронных сетей. Единственное отличие состоит в том, что Pytorch’s MSELOSS
Функция не имеет дополнительного подразделения на 2, поэтому в код ниже я настроил dc_da_l2 * (a_l2-1)
Чтобы соответствовать тому, что делает Pytorch:
import numpy as np def sigmoid(z_value): return 1.0/(1.0+np.exp(-z_value)) def z(w, a, b): return w * a + b def sigmoid_prime(z_value): return sigmoid(z_value)*(1-sigmoid(z_value)) def dc_db(z_value, dc_da): return sigmoid_prime(z_value) * dc_da def dc_dw(a_prev, dc_db_value): return a_prev * dc_db_value def dc_da_prev(w, dc_db_value): return w * dc_db_value a_l0 = 0.8 w_l1 = 1.58 b_l1 = -0.14 print(f"w_l1 = {round(w_l1, 4)}") print(f"b_l1 = {round(b_l1, 4)}") z_l1 = z(w_l1, a_l0, b_l1) a_l1 = sigmoid(z_l1) w_l2 = 2.45 b_l2 = -0.11 print(f"w_l2 = {round(w_l2, 4)}") print(f"b_l2 = {round(b_l2, 4)}") z_l2 = z(w_l2, a_l1, b_l2) a_l2 = sigmoid(z_l2) print(f"a_l2 = {round(a_l2, 4)}") dc_da_l2 = 2 * (a_l2-1) dc_db_l2 = dc_db(z_l2, dc_da_l2) dc_dw_l2 = dc_dw(a_l1, dc_db_l2) dc_da_l1 = dc_da_prev(w_l2, dc_db_l2) step_size = 0.1 updated_b_l2 = b_l2 - dc_db_l2 * step_size updated_w_l2 = w_l2 - dc_dw_l2 * step_size dc_db_l1 = dc_db(z_l1, dc_da_l1) dc_dw_l1 = dc_dw(a_l0, dc_db_l1) updated_b_l1 = b_l1 - dc_db_l1 * step_size updated_w_l1 = w_l1 - dc_dw_l1 * step_size print(f"updated_w_l1 = {round(updated_w_l1, 4)}") print(f"updated_b_l1 = {round(updated_b_l1, 4)}") print(f"updated_w_l2 = {round(updated_w_l2, 4)}") print(f"updated_b_l2 = {round(updated_b_l2, 4)}") updated_z_l1 = z(updated_w_l1, a_l0, updated_b_l1) updated_a_l1 = sigmoid(updated_z_l1) updated_z_l2 = z(updated_w_l2, updated_a_l1, updated_b_l2) updated_a_l2 = sigmoid(updated_z_l2) print(f"updated_a_l2 = {round(updated_a_l2, 4)}")
Вот результаты:
C:\Dev\python\pytorch>python backprop_manual_calculation.py w_l1 = 1.58 b_l1 = -0.14 w_l2 = 2.45 b_l2 = -0.11 a_l2 = 0.8506 updated_w_l1 = 1.5814 updated_b_l1 = -0.1383 updated_w_l2 = 2.4529 updated_b_l2 = -0.1062 updated_a_l2 = 0.8515
Мы видим, что результаты совпадают с теми из сети Pytorch! В следующей статье мы будем использовать Pytorch для распознавания цифр из базы данных Mnist.
Код доступен на GitHub:
NestedSoftware/pytorch.
Демонстрации базового использования Pytorch. Включает распознавание Mnist, используя плотные, а также сверточные сети.
Этот проект содержит скрипты для демонстрации базового использования Pytorch. Код требует Python 3, Numpy и Pytorch.
Руководство по сравнению с Pyyorch CallProp
Для сравнения ручного расчета Backprop с эквивалентной версией Pytorch, запустите:
python backprop_manual_calculation.py w_l1 = 1.58 b_l1 = -0.14 w_l2 = 2.45 b_l2 = -0.11 a_l2 = 0.8506 updated_w_l1 = 1.5814 updated_b_l1 = -0.1383 updated_w_l2 = 2.4529 updated_b_l2 = -0.1062 updated_a_l2 = 0.8515
и
python backprop_pytorch.py network topology: Net( (hidden_layer): Linear(in_features=1, out_features=1, bias=True) (output_layer): Linear(in_features=1, out_features=1, bias=True) ) w_l1 = 1.58 b_l1 = -0.14 w_l2 = 2.45 b_l2 = -0.11 a_l2 = 0.8506 updated_w_l1 = 1.5814 updated_b_l1 = -0.1383 updated_w_l2 = 2.4529 updated_b_l2 = -0.1062 updated_a_l2 = 0.8515
Blog Post: Pytorch Hello World
Мнист признание
Следующие примеры распознают цифры Mnist, используя плотную сеть сначала, а затем несколько конструкций ключевых сетей (примеры адаптированы из книги Михаила Нильсена, нейронные сети и глубокому обучению).
Я добавил…
Связанный
- Грунтовка нейронных сетей
Оригинал: “https://dev.to/nestedsoftware/pytorch-hello-world-37mo”