Создание слоев, функций активации и функции потерь для нейронной сети¶
В настоящее время существует достаточно ограниченное количество слоев, функций активации и функций потерь для нейронных сетей. Необходимо разрабатывать свои функции для того, чтобы сделать более или менее серьезный проект.
Пример, который я привожу будет решен с помощью PyTorch. Мы будем делать линейный слой.
Официальный туториал находиться на сайте PyTorch
Этот ноутбук доступен в моем Github репозитории:
git clone https://github.com/andreiliphd/reinforcement-content.git
Если нет Git, то его нужно установить.
Linux:
sudo apt-get update
sudo apt-get install git
Windows: скачайте Git с сайта git-scm.com.
Если вы нашли ошибку на сайте, ее можно исправить самостоятельно сделав Pull Request в Git.
Этапы решения задачи¶
- Определяем класс с собственным алгоритмом дифференцирования.
- Переопределяем
forward
. - Переопределяем
backward
. - Определяем модуль.
- Переопределяем
__init__
. - Переопределяем
forward
. - Тестирование.
In [15]:
import torch
from torch import nn
Определяем класс с собственным алгоритмом дифференцирования.¶
In [9]:
# Inherit from Function
class LinearFunction(torch.autograd.Function):
# Note that both forward and backward are @staticmethods
@staticmethod
# bias is an optional argument
def forward(ctx, input, weight, bias=None):
ctx.save_for_backward(input, weight, bias)
output = input.mm(weight.t())
if bias is not None:
output += bias.unsqueeze(0).expand_as(output)
return output
# This function has only a single output, so it gets only one gradient
@staticmethod
def backward(ctx, grad_output):
# This is a pattern that is very convenient - at the top of backward
# unpack saved_tensors and initialize all gradients w.r.t. inputs to
# None. Thanks to the fact that additional trailing Nones are
# ignored, the return statement is simple even when the function has
# optional inputs.
input, weight, bias = ctx.saved_tensors
grad_input = grad_weight = grad_bias = None
# These needs_input_grad checks are optional and there only to
# improve efficiency. If you want to make your code simpler, you can
# skip them. Returning gradients for inputs that don't require it is
# not an error.
if ctx.needs_input_grad[0]:
grad_input = grad_output.mm(weight)
if ctx.needs_input_grad[1]:
grad_weight = grad_output.t().mm(input)
if bias is not None and ctx.needs_input_grad[2]:
grad_bias = grad_output.sum(0).squeeze(0)
return grad_input, grad_weight, grad_bias
Определяем модуль¶
Модуль - это компонента, которую мы будем вставлять в нашу нейронную сеть.
In [10]:
class Linear(torch.nn.Module):
def __init__(self, input_features, output_features, bias=True):
super(Linear, self).__init__()
self.input_features = input_features
self.output_features = output_features
# nn.Parameter is a special kind of Tensor, that will get
# automatically registered as Module's parameter once it's assigned
# as an attribute. Parameters and buffers need to be registered, or
# they won't appear in .parameters() (doesn't apply to buffers), and
# won't be converted when e.g. .cuda() is called. You can use
# .register_buffer() to register buffers.
# nn.Parameters require gradients by default.
self.weight = nn.Parameter(torch.Tensor(output_features, input_features))
if bias:
self.bias = nn.Parameter(torch.Tensor(output_features))
else:
# You should always register all possible parameters, but the
# optional ones can be None if you want.
self.register_parameter('bias', None)
# Not a very smart way to initialize weights
self.weight.data.uniform_(-0.1, 0.1)
if bias is not None:
self.bias.data.uniform_(-0.1, 0.1)
def forward(self, input):
# See the autograd section for explanation of what happens here.
return LinearFunction.apply(input, self.weight, self.bias)
def extra_repr(self):
# (Optional)Set the extra information about this module. You can test
# it by printing an object of this class.
return 'in_features={}, out_features={}, bias={}'.format(
self.in_features, self.out_features, self.bias is not None
)
Тестирование¶
In [16]:
tensor = torch.randn([3,64])
In [12]:
fc = Linear(64,100)
In [13]:
fc(tensor)
Out[13]:
In [ ]: