-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdropout.py
74 lines (65 loc) · 3.15 KB
/
dropout.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
from typing import Any
import torch
import torch.nn as nn
class DropoutFunction(torch.autograd.Function):
"""
Функция для реализации прямого и обратного прохода
Dropout слоя нейронной сети
"""
@staticmethod
def forward(ctx: Any, *args: Any, **kwargs: Any) -> Any:
"""
Реализация прямого прохода Dropout с вероятностью зануления p
:param ctx: контекст для сохранения производных при прямом обходе
:param args: аргументы в порядке [X, p]
:param kwargs:
:return:
"""
inputs = args[0]
probability = args[1]
dropout_mask = torch.where(torch.rand(inputs.shape) < probability,
torch.zeros_like(inputs),
torch.ones_like(inputs)
)
ctx.save_for_backward(dropout_mask)
return inputs * dropout_mask
@staticmethod
def backward(ctx: Any, *grad_outputs: Any) -> Any:
"""
Обратное распростанение градиента для Dropout
dL/dX = dL/dz * dz/dX = dL/dz * dropout_mask
:param ctx: контекст с сохраненными значениями при прямом проходе
:param grad_outputs: приходящий градиент
:return: градиенты по dX
"""
dropout_mask = ctx.saved_tensors[0]
return grad_outputs[0] * dropout_mask, None
class Dropout(nn.Module):
def __init__(self, probability: float = 0.5):
"""
Реализация Dropout слоя нейронной сети.
Для переопределения метода backward требуется создать свою функцию
и вызывать ее методы.
Зануление нейрона с вероятностью probability
"""
super().__init__()
assert (probability >= 0) and (probability < 1)
self.probability = probability
self.dropout = DropoutFunction.apply
def forward(self, x):
"""
Теоретическая реализация предполагает расчет на
- training: y = f(WX) * m
- testing: y = (1 - p) * f(WX)
m - маскирующиая матрица из {0, 1} для отключения нейрона.
Элемент принимает 0 с вероятностью p = self.probability
Для практической реализации поделим оба выражения на (1 - p)
:param x:
:return:
"""
if self.training:
# сразу нормируем выход на обучении, поскольку нейрон в среднем принимает (1 - p) информации
return self.dropout(x, self.probability) / (1 - self.probability)
else:
# отключаем Dropout на тесте
return self.dropout(x, 0)