Версия Python¶
!python -V
Python 3.12.6
Импорт необходимых библиотек¶
# Подавление предупреждений
import warnings
for warn in [UserWarning, FutureWarning]: warnings.filterwarnings("ignore", category = warn)
import os
import numpy as np
import torch
import torch.nn as nn
import pandas as pd
import jupyterlab as jlab
Версии необходимых библиотек¶
packages = [
"Torch", "NumPy", "Pandas", "JupyterLab",
]
package_objects = [
torch, np, pd, jlab
]
versions = list(map(lambda obj: obj.__version__, package_objects))
pkgs = {"Библиотека": packages, "Версия": versions}
df_pkgs = pd.DataFrame(data = pkgs)
df_pkgs.index.name = "№"
df_pkgs.index += 1
display(df_pkgs)
path_to_reqs = "."
reqs_name = "requirements.txt"
def get_packages_and_versions():
"""Генерация строк с библиотеками и их версиями в формате: библиотека==версия"""
for package, version in zip(packages, versions):
yield f"{package.lower()}=={version}\n"
with open(os.path.join(path_to_reqs, reqs_name), "w", encoding = "utf-8") as f:
f.writelines(get_packages_and_versions())
Библиотека | Версия | |
---|---|---|
№ | ||
1 | Torch | 2.2.2 |
2 | NumPy | 1.26.4 |
3 | Pandas | 2.2.3 |
4 | JupyterLab | 4.2.5 |
ReLU (Rectified Linear Unit)¶
Замена всех отрицательных значений на 0, при этом положительные значения остаются без изменений
$$ \text{ReLU}(x) = \begin{cases} 0 & \text{если } x \leq 0 \\ x & \text{если } x > 0 \end{cases} $$
# Создание объекта ReLU
g = nn.ReLU()
# Генерация случайного тензора
input = torch.tensor([-2.3526, 1.1458]) # torch.randn(2)
# Применение функции активации ReLU к входным данным
output = g(input)
# Вывод входных и выходных данных
print("Входные данные:", input)
print("Выходные данные:", output)
Входные данные: tensor([-2.3526, 1.1458]) Выходные данные: tensor([0.0000, 1.1458])
ELU (Exponential Linear Unit)¶
Преобразование отрицательных значений на $\alpha (\exp(x) - 1)$, делающее их менее агрессивными по сравнению с ReLU, с сохранением положительных значений без изменений
$$ \text{ELU}(x) = \begin{cases} x & \text{если } x > 0 \\ \alpha (\exp(x) - 1) & \text{если } x \leq 0 \end{cases} $$
# Создание объекта ELU
g = nn.ELU(alpha = 1.0)
# Генерация случайного тензора
input = torch.tensor([-2.3526, 1.1458]) # torch.randn(2)
# Применение функции активации ELU к входным данным
output = g(input)
# Вывод входных и выходных данных
print("Входные данные:", input)
print("Выходные данные:", output)
Входные данные: tensor([-2.3526, 1.1458]) Выходные данные: tensor([-0.9049, 1.1458])
PReLU (Parametric ReLU)¶
Преобразование значений, оставляя положительные значения без изменений, и умножая отрицательные значения на обучаемый параметр $\alpha$ $\text{где } \alpha \text{ — обучаемый параметр}$
$$ \text{PReLU}(x) = \begin{cases} x & \text{если } x \geq 0 \\ \alpha x & \text{если } x < 0 \end{cases} $$
# Создание объекта PReLU
g = nn.PReLU(num_parameters = 4, init = 0.25)
# Генерация случайного тензора
input = torch.tensor([
[ 0.6465, -0.9450, -0.5559, -1.5250],
[-1.4968, -1.1030, 0.5872, -0.7036]
]) # torch.randn(2, 4)
# Применение функции активации PReLU к входным данным
output = g(input)
# Вывод входных и выходных данных
print("Входные данные:", input)
print("Выходные данные:", output)
Входные данные: tensor([[ 0.6465, -0.9450, -0.5559, -1.5250], [-1.4968, -1.1030, 0.5872, -0.7036]]) Выходные данные: tensor([[ 0.6465, -0.2362, -0.1390, -0.3812], [-0.3742, -0.2758, 0.5872, -0.1759]], grad_fn=<PreluKernelBackward0>)
LeakyReLU¶
Преобразование значений, оставляя положительные значения без изменений, и умножая отрицательные значения на коэффициент $\alpha$, $\text{где } \alpha = \text{negative_slope}$
$$ \text{LeakyReLU}(x) = \begin{cases} x & \text{если } x \geq 0 \\ \alpha x & \text{если } x < 0 \end{cases} $$
# Создание объекта LeakyReLU
g = nn.LeakyReLU(negative_slope = 0.01)
# Генерация случайного тензора
input = torch.tensor([-2.3526, 1.1458]) # torch.randn(2)
# Применение функции активации LeakyReLU к входным данным
output = g(input)
# Вывод входных и выходных данных
print("Входные данные:", input)
print("Выходные данные:", output)
Входные данные: tensor([-2.3526, 1.1458]) Выходные данные: tensor([-0.0235, 1.1458])
ReLU6¶
Преобразование значений меньше 0 в 0, больше 6 в 6, и оставляя остальные значения без изменений
$$ \text{ReLU6}(x) = \min(\max(0, x), 6) $$
# Создание объекта ReLU6
g = nn.ReLU6()
# Генерация случайного тензора
input = torch.tensor([-2.3526, 1.1458, 6.2345]) # torch.randn(3)
# Применение функции активации ReLU6 к входным данным
output = g(input)
# Вывод входных и выходных данных
print("Входные данные:", input)
print("Выходные данные:", output)
Входные данные: tensor([-2.3526, 1.1458, 6.2345]) Выходные данные: tensor([0.0000, 1.1458, 6.0000])
RReLU (Randomized Leaky ReLU)¶
Преобразование значений, оставляя положительные значения без изменений, и умножая отрицательные значения на случайно выбранный коэффициент $\alpha$
$$ \text{RReLU}(x) = \begin{cases} x & \text{если } x \geq 0 \\ \alpha x & \text{если } x < 0 \end{cases} $$
# Создание объекта RReLU
g = nn.RReLU(lower = 0.125, upper = 0.333)
# Генерация случайного тензора
input = torch.tensor([-2.3526, 1.1458, 6.2345]) # torch.randn(3)
# Применение функции активации RReLU к входным данным
output = g(input)
# Вывод входных и выходных данных
print("Входные данные:", input)
print("Выходные данные:", output)
Входные данные: tensor([-2.3526, 1.1458, 6.2345]) Выходные данные: tensor([-0.6328, 1.1458, 6.2345])
SELU (Scaled Exponential Linear Unit)¶
Преобразование значений, сохраняя положительные без изменений и масштабируя их параметром $scale$, а отрицательные параметрами $\alpha$ и $scale$ $\text{где } \text{scale} \approx 1.0507 \text{ и } \alpha \approx 1.6733$
$$ \text{SELU}(x) = \text{scale} \times (\max(0, x) + \min(0, \alpha \times (\exp(x) - 1))) $$
# Создание объекта SELU
g = nn.SELU()
# Генерация случайного тензора
input = torch.tensor([-2.3526, 1.1458]) # torch.randn(2)
# Применение функции активации SELU к входным данным
output = g(input)
# Вывод входных и выходных данных
print("Входные данные:", input)
print("Выходные данные:", output)
Входные данные: tensor([-2.3526, 1.1458]) Выходные данные: tensor([-1.5909, 1.2039])
CELU (Continuously Differentiable Exponential Linear Unit)¶
Преобразование отрицательных значений с использованием экспоненциальной функции и параметра $\alpha$ и сохраняя положительные значения без изменений
$$ \text{CELU}(x) = \begin{cases} x & \text{если } x \geq 0 \\ \alpha \times (\exp(x / \alpha) - 1) & \text{если } x < 0 \end{cases} $$
# Создание объекта CELU
g = nn.CELU(alpha = 1.0)
# Генерация случайного тензора
input = torch.tensor([-2.3526, 1.1458]) # torch.randn(2)
# Применение функции активации CELU к входным данным
output = g(input)
# Вывод входных и выходных данных
print("Входные данные:", input)
print("Выходные данные:", output)
Входные данные: tensor([-2.3526, 1.1458]) Выходные данные: tensor([-0.9049, 1.1458])
GELU (Gaussian Error Linear Unit)¶
Преобразование значений, приближая их к гауссовому распределению
$$ \text{GELU}(x) = x \times \Phi(x) \quad \text{где } \Phi(x) \text{ - функция кумулятивного распределения для нормального распределения (}approximate=none\text{)} $$
$$ \text{GELU}(x) = 0.5 \times x \times \left(1 + \tanh\left(\sqrt{\frac{2}{\pi}} \left(x + 0.044715 x^3\right)\right)\right) \quad \text{где } approximate=tanh $$
# Создание объекта GELU
g = nn.GELU(approximate = "none") # none | tanh
# Генерация случайного тензора
input = torch.tensor([-2.3526, 1.1458]) # torch.randn(2)
# Применение функции активации GELU к входным данным
output = g(input)
# Вывод входных и выходных данных
print("Входные данные:", input)
print("Выходные данные:", output)
Входные данные: tensor([-2.3526, 1.1458]) Выходные данные: tensor([-0.0219, 1.0015])
Sigmoid¶
Преобразование значений в диапазоне от 0 до 1
$$ \text{Sigmoid}(x) = \sigma(x) = \frac{1}{1 + e^{-x}} $$
# Создание объекта Sigmoid
g = nn.Sigmoid()
# Генерация случайного тензора
input = torch.tensor([-2.3526, 1.1458]) # torch.randn(2)
# Применение функции активации Sigmoid к входным данным
output = g(input)
# Вывод входных и выходных данных
print("Входные данные:", input)
print("Выходные данные:", output)
Входные данные: tensor([-2.3526, 1.1458]) Выходные данные: tensor([0.0869, 0.7587])
SiLU (Sigmoid Linear Unit)¶
Комбинирование значений $x$ с их сигмоидными преобразованиями $\sigma(x) = \frac{1}{1 + e^{-x}}$
$$ \text{SiLU}(x) = x \times \sigma(x) \quad \text{где } \sigma(x) = \frac{1}{1 + e^{-x}} \text{ - сигмоидная функция} $$
# Создание объекта SiLU
g = nn.SiLU()
# Генерация случайного тензора
input = torch.tensor([-2.3526, 1.1458]) # torch.randn(2)
# Применение функции активации SiLU к входным данным
output = g(input)
# Вывод входных и выходных данных
print("Входные данные:", input)
print("Выходные данные:", output)
Входные данные: tensor([-2.3526, 1.1458]) Выходные данные: tensor([-0.2043, 0.8694])
LogSigmoid¶
Преобразование значений с помощью логарифма сигмоидной функции
$$ \text{LogSigmoid}(x) = \log \left( \frac{1}{1 + \exp(-x)} \right) $$
# Создание объекта LogSigmoid
g = nn.LogSigmoid()
# Генерация случайного тензора
input = torch.tensor([-2.3526, 1.1458]) # torch.randn(2)
# Применение функции активации LogSigmoid к входным данным
output = g(input)
# Вывод входных и выходных данных
print("Входные данные:", input)
print("Выходные данные:", output)
Входные данные: tensor([-2.3526, 1.1458]) Выходные данные: tensor([-2.4435, -0.2761])
Hardsigmoid¶
Преобразование значений, которые меньше или равны $−3$, в 0, значения, которые больше или равны $3$, в 1, и значения между $−3$ и $3$, с помощью функции $\frac{x}{6} + 0.5$
$$ \text{Hardsigmoid}(x) = \begin{cases} 0 & \text{если } x \leq -3 \\ 1 & \text{если } x \geq 3 \\ \frac{x}{6} + 0.5 & \text{иначе} \end{cases} $$
# Создание объекта Hardsigmoid
g = nn.Hardsigmoid()
# Генерация случайного тензора
input = torch.tensor([-3.3526, 3.1458, -2.0256, 1.7843]) # torch.randn(4)
# Применение функции активации Hardsigmoid к входным данным
output = g(input)
# Вывод входных и выходных данных
print("Входные данные:", input)
print("Выходные данные:", output)
Входные данные: tensor([-3.3526, 3.1458, -2.0256, 1.7843]) Выходные данные: tensor([0.0000, 1.0000, 0.1624, 0.7974])
Tanh¶
Преобразование значений в диапазоне от -1 до 1
$$ \text{Tanh}(x) = \tanh(x) = \frac{\exp(x) - \exp(-x)}{\exp(x) + \exp(-x)} $$
# Создание объекта Tanh
g = nn.Tanh()
# Генерация случайного тензора
input = torch.tensor([-2.3526, 1.1458]) # torch.randn(2)
# Применение функции активации Tanh к входным данным
output = g(input)
# Вывод входных и выходных данных
print("Входные данные:", input)
print("Выходные данные:", output)
Входные данные: tensor([-2.3526, 1.1458]) Выходные данные: tensor([-0.9821, 0.8164])
Tanhshrink¶
Преобразование значений, где из самих входных значений вычитается гиперболический $tanh$
$$ \text{Tanhshrink}(x) = x - \tanh(x) $$
# Создание объекта Tanhshrink
g = nn.Tanhshrink()
# Генерация случайного тензора
input = torch.tensor([-2.3526, 1.1458]) # torch.randn(2)
# Применение функции активации Tanhshrink к входным данным
output = g(input)
# Вывод входных и выходных данных
print("Входные данные:", input)
print("Выходные данные:", output)
Входные данные: tensor([-2.3526, 1.1458]) Выходные данные: tensor([-1.3705, 0.3294])
Hardtanh¶
Преобразование значений, которые меньше $min\_val$, в $min\_val$, которые больше $max\_val$, в $max\_val$, и оставляя значения между $min\_val$ и $max\_val$ без изменений
$$ \text{HardTanh}(x) = \begin{cases} min\_val & \text{если } x < min\_val \\ max\_val & \text{если } x > max\_val \\ x & \text{иначе} \end{cases} $$
# Создание объекта Hardtanh
g = nn.Hardtanh(min_val = -1.0, max_val = 1.0)
# Генерация случайного тензора
input = torch.tensor([-1.1383, 1.1630, -0.8715, 0.7228]) # torch.randn(4)
# Применение функции активации Hardtanh к входным данным
output = g(input)
# Вывод входных и выходных данных
print("Входные данные:", input)
print("Выходные данные:", output)
Входные данные: tensor([-1.1383, 1.1630, -0.8715, 0.7228]) Выходные данные: tensor([-1.0000, 1.0000, -0.8715, 0.7228])
Hardshrink¶
Преобразование значений, которые находятся между $-\lambda$ и $\lambda$ включительно, в 0, и оставляя значения, которые меньше $-\lambda$ или больше $\lambda$, без изменений
$$ \text{HardShrink}(x) = \begin{cases} x & \text{если } x > \lambda \\ x & \text{если } x < -\lambda \\ 0 & \text{иначе} \end{cases} $$
# Создание объекта Hardshrink
g = nn.Hardshrink(lambd = 1.1458)
# Генерация случайного тензора
input = torch.tensor([-2.3526, 1.1458]) # torch.randn(2)
# Применение функции активации Hardshrink к входным данным
output = g(input)
# Вывод входных и выходных данных
print("Входные данные:", input)
print("Выходные данные:", output)
Входные данные: tensor([-2.3526, 1.1458]) Выходные данные: tensor([-2.3526, 0.0000])
Hardswish¶
Преобразование значений, которые меньше или равны $−3$, в 0, значения, которые больше или равны $3$, остаются без изменений, и значения между $−3$ и $3$ преобразуются с помощью функции $x \left(\frac{x+3}{6}\right)$
$$ \text{Hardswish}(x) = \begin{cases} 0 & \text{если } x \leq -3 \\ x & \text{если } x \geq 3 \\ x \left(\frac{x+3}{6}\right) & \text{иначе} \end{cases} $$
# Создание объекта Hardswish
g = nn.Hardswish()
# Генерация случайного тензора
input = torch.tensor([-3.3526, 3.1458, -2.0256, 1.7843]) # torch.randn(4)
# Применение функции активации Hardswish к входным данным
output = g(input)
# Вывод входных и выходных данных
print("Входные данные:", input)
print("Выходные данные:", output)
Входные данные: tensor([-3.3526, 3.1458, -2.0256, 1.7843]) Выходные данные: tensor([-0.0000, 3.1458, -0.3290, 1.4228])
Mish¶
Преобразование значений, комбинируя значения $x$ с их $softplus$-преобразованиями ($\text{Softplus}(x) = \frac{1}{\beta} \log(1 + \exp(\beta \times x))$) и примененым гиперболическим тангенсом
$$ \text{Mish}(x) = x \times \tanh(\text{Softplus}(x)) $$
# Создание объекта Mish
g = nn.Mish()
# Генерация случайного тензора
input = torch.tensor([-2.3526, 1.1458]) # torch.randn(2)
# Применение функции активации Mish к входным данным
output = g(input)
# Вывод входных и выходных данных
print("Входные данные:", input)
print("Выходные данные:", output)
Входные данные: tensor([-2.3526, 1.1458]) Выходные данные: tensor([-0.2132, 1.0198])
Softplus¶
Преобразование значений, сглаживая их, обеспечивая плавный переход между линейными и нелинейными областями, контролируемый параметром $\beta$
$$ \text{Softplus}(x) = \frac{1}{\beta} \log(1 + \exp(\beta \times x)) $$
# Создание объекта Softplus
g = nn.Softplus(beta = 1.0, threshold = 20.0)
# Генерация случайного тензора
input = torch.tensor([-2.3526, 1.1458]) # torch.randn(2)
# Применение функции активации Softplus к входным данным
output = g(input)
# Вывод входных и выходных данных
print("Входные данные:", input)
print("Выходные данные:", output)
Входные данные: tensor([-2.3526, 1.1458]) Выходные данные: tensor([0.0909, 1.4219])
Softshrink¶
Преобразование значений, уменьшая их на величину $\lambda$ и устанавливая их в ноль, если значения по абсолютной величине меньше $\lambda$
$$ \text{Softshrink}(x) = \begin{cases} x - \lambda & \text{если } x > \lambda \\ x + \lambda & \text{если } x < -\lambda \\ 0 & \text{иначе} \end{cases} $$
# Создание объекта Softshrink
g = nn.Softshrink(lambd = 0.5)
# Генерация случайного тензора
input = torch.tensor([-2.3526, 1.1458, 0.4320, -0.3791]) # torch.randn(4)
# Применение функции активации Softshrink к входным данным
output = g(input)
# Вывод входных и выходных данных
print("Входные данные:", input)
print("Выходные данные:", output)
Входные данные: tensor([-2.3526, 1.1458, 0.4320, -0.3791]) Выходные данные: tensor([-1.8526, 0.6458, 0.0000, 0.0000])
Softsign¶
Преобразование значений, уменьшая их величину, где входные значения делятся на сумму 1 и их абсолютного значения
$$ \text{Softsign}(x) = \frac{x}{1 + |x|} $$
# Создание объекта Softsign
g = nn.Softsign()
# Генерация случайного тензора
input = torch.tensor([-2.3526, 1.1458, 0.4320, -0.3791]) # torch.randn(4)
# Применение функции активации Softsign к входным данным
output = g(input)
# Вывод входных и выходных данных
print("Входные данные:", input)
print("Выходные данные:", output)
Входные данные: tensor([-2.3526, 1.1458, 0.4320, -0.3791]) Выходные данные: tensor([-0.7017, 0.5340, 0.3017, -0.2749])
Threshold¶
Преобразование значений, при котором значения, большие заданного порога ($threshold$) остаются без изменений, а значения, меньшие порога, заменяются на заданное значение ($value$)
$$ \text{Threshold}(x) = \begin{cases} x & \text{если } x > threshold \\ value & \text{иначе} \end{cases} $$
# Создание объекта Threshold
g = nn.Threshold(threshold = 0.1, value = 20)
# Генерация случайного тензора
input = torch.tensor([-2.3526, 1.1458, 0.4320, -0.3791]) # torch.randn(4)
# Применение функции активации Threshold к входным данным
output = g(input)
# Вывод входных и выходных данных
print("Входные данные:", input)
print("Выходные данные:", output)
Входные данные: tensor([-2.3526, 1.1458, 0.4320, -0.3791]) Выходные данные: tensor([20.0000, 1.1458, 0.4320, 20.0000])
GLU (Gated Linear Unit)¶
Преобразование значений, при котором данные разделяется на две половины по последнему размеру, первая половина остается неизменной, а ко второй применяется сигмоидная функция, и перемножение этих частей дает результат
$$ \text{GLU}(x) = x_1 \times \sigma(x_2) $$
# Создание объекта GLU
g = nn.GLU(dim = -1)
# Генерация случайного тензора
input = torch.tensor([
[-0.0915, 0.2352],
[ 2.2440, 0.5817],
[ 0.4528, 0.6410],
[ 0.5200, 0.5567]
]) # torch.randn(4, 2)
# Применение функции активации GLU к входным данным
output = g(input)
# Вывод входных и выходных данных
print("Входные данные:", input)
print("Выходные данные:", output)
Входные данные: tensor([[-0.0915, 0.2352], [ 2.2440, 0.5817], [ 0.4528, 0.6410], [ 0.5200, 0.5567]]) Выходные данные: tensor([[-0.0511], [ 1.4394], [ 0.2966], [ 0.3306]])
MultiheadAttention¶
Преобразование значений, используя механизм многоголового внимания, где входные $query$, $key$ и $value$ проходят через несколько голов внимания, объединяются и линейно преобразуются в окончательный результат
$$ \text{MultiHead}(Q, K, V) = \text{Concat}(\text{head}_1, \dots, \text{head}_h) W^O \quad \text{где } \text{head}_i = \text{Attention}(Q W_i^Q, K W_i^K, V W_i^V) $$
# Параметры
embed_dim = 3 # Размерность эмбеддинга
num_heads = 1 # Количество голов
# Создание объекта MultiheadAttention
multihead_attn = nn.MultiheadAttention(
embed_dim = embed_dim,
num_heads = num_heads,
dropout = 0.0,
bias = True,
add_bias_kv = False,
batch_first = True
)
# Генерацие случайных тензоров для query, key и value
query = torch.tensor([
[
[-1.4025, 0.4318, 0.3431],
[ 1.0711, 1.3455, 0.3277]],
[
[ 1.3409, 1.2159, 0.9589],
[ 0.5137, 0.4977, -0.6646]],
[
[-1.0612, 2.0423, 0.6509],
[-1.0072, 0.3578, -1.0799]
]
]) # (batch size, target sequence length, embed_dim)
key = torch.tensor([
[
[-1.4025, 0.4318, 0.3431],
[ 1.0711, 1.3455, 0.3277]],
[
[ 1.3409, 1.2159, 0.9589],
[ 0.5137, 0.4977, -0.6646]],
[
[-1.0612, 2.0423, 0.6509],
[-1.0072, 0.3578, -1.0799]
]
]) # (batch size, source sequence length, embed_dim)
value = torch.tensor([
[
[-1.4025, 0.4318, 0.3431],
[ 1.0711, 1.3455, 0.3277]],
[
[ 1.3409, 1.2159, 0.9589],
[ 0.5137, 0.4977, -0.6646]],
[
[-1.0612, 2.0423, 0.6509],
[-1.0072, 0.3578, -1.0799]
]
]) # (batch size, source sequence length, embed_dim)
# Применение функции активации MultiheadAttention к входным данным
# attn_output = (batch size, target sequence length, embed_dim)
# attn_output_weights = (batch size, target sequence length, source sequence length)
attn_output, attn_output_weights = multihead_attn(query, key, value)
# Выходных данных
print("Результат внимания:", attn_output)
print("Веса внимания:", attn_output_weights)
Результат внимания: tensor([[[-0.0590, -0.0616, 0.0548], [-0.0655, -0.0732, 0.0653]], [[ 0.0648, 0.1393, -0.1462], [ 0.0690, 0.1480, -0.1414]], [[-0.0708, -0.0367, 0.2673], [-0.0543, -0.0098, 0.2601]]], grad_fn=<TransposeBackward0>) Веса внимания: tensor([[[0.4234, 0.5766], [0.4468, 0.5532]], [[0.5683, 0.4317], [0.5315, 0.4685]], [[0.2942, 0.7058], [0.2290, 0.7710]]], grad_fn=<MeanBackward1>)