1. Объяснить и реализовать линейный слой

Линейный слой в глубоком обучении — это слой, который выполняет линейную комбинацию входных данных и применяет термин смещения.

В этой реализации параметры input_dim и output_dim задают количество входных и выходных единиц соответственно для слоя. Параметр смещения — это логическое значение, которое определяет, должен ли слой иметь член смещения или нет. Веса инициализируются случайным образом с использованием распределения Гаусса, а смещение инициализируется равным нулю. Прямой метод вычисляет линейную комбинацию входных данных и применяет член смещения, если он указан.

import numpy as np
class Linear:
    def __init__(self, input_dim, output_dim, bias=True):
        self.input_dim = input_dim
        self.output_dim = output_dim
        self.bias = bias
        
        self.weights = np.random.randn(input_dim, output_dim)
        if self.bias:
            self.bias = np.zeros((1, output_dim))
    
    def forward(self, x):
        out = np.dot(x, self.weights)
        if self.bias:
            out += self.bias
        return out

2. Объясните и осознайте сигмовидную активацию

Сигмовидная функция активации — популярная функция активации, используемая во многих моделях глубокого обучения. Он отображает любой ввод в диапазоне от 0 до 1, что делает его полезным для задач бинарной классификации.

В этой реализации функция принимает входные данные x и возвращает сигмовидную активацию. Сигмовидная активация вычисляется путем применения экспоненциальной функции np.exp к отрицательному входному значению x, а затем взятия обратной суммы 1 и результата. Результирующее значение всегда находится в диапазоне от 0 до 1 включительно.

import numpy as np
def sigmoid(x):
    return 1 / (1 + np.exp(-x))

3. Объясните и реализуйте вывод потерь l2 и график его вычислений.

Потеря L2, также известная как среднеквадратическая ошибка (MSE), является популярной функцией потерь, используемой для задач регрессии. Он измеряет разницу между прогнозируемым выходом и истинным выходом путем вычисления суммы квадратов разностей и деления на количество выборок.

В этой реализации функция принимает два входа: y_true и y_pred. y_true — это истинный результат, а y_pred — прогнозируемый результат. Сначала функция вычисляет разницу между y_true и y_pred, используя поэлементное вычитание. Затем он возводит разницу в квадрат и вычисляет сумму по всем образцам. Наконец, он делит сумму на количество выборок n, чтобы вычислить среднеквадратичную ошибку. Полученное значение представляет собой потери L2, которые можно использовать для оценки производительности модели.

import numpy as np
def l2_loss(y_true, y_pred):
    n = y_true.shape[0]
    loss = np.sum((y_true - y_pred)**2) / n
    return loss

4. Объясните и реализуйте передачу вперед и назад.

В глубоком обучении прямой проход относится к процессу вычисления выходных данных нейронной сети с учетом входных данных. Обратный проход, также известный как обратное распространение, относится к процессу вычисления градиентов потерь по отношению к параметрам модели, которые затем используются для обновления параметров модели.

Вот простой пример прямого прохода и обратного прохода для нейронной сети с одним линейным слоем и сигмовидной функцией активации, за которой следует функция потери среднеквадратичной ошибки.

В этом примере функция forward_pass принимает входные данные x, истинные выходные данные y_true и линейный слой linear и возвращает предсказанные выходные данные y_pred и среднеквадратичную ошибку потерь. Функция back_pass принимает входные данные x, истинные выходные данные y_true, предсказанные выходные данные y_pred и линейный слой linear и возвращает градиенты потерь относительно входных данных линейного слоя d_linear, весов d_weights и смещения.

import numpy as np
def sigmoid(x):
    return 1 / (1 + np.exp(-x))
def l2_loss(y_true, y_pred):
    n = y_true.shape[0]
    loss = np.sum((y_true - y_pred)**2) / n
    return loss
class Linear:
    def __init__(self, input_dim, output_dim, bias=True):
        self.input_dim = input_dim
        self.output_dim = output_dim
        self.bias = bias
        
        self.weights = np.random.randn(input_dim, output_dim)
        if self.bias:
            self.bias = np.zeros((1, output_dim))
    
    def forward(self, x):
        out = np.dot(x, self.weights)
        if self.bias:
            out += self.bias
        return out
def forward_pass(x, y_true, linear, activation=sigmoid):
    y_pred = activation(linear.forward(x))
    loss = l2_loss(y_true, y_pred)
    return y_pred, loss
def backward_pass(x, y_true, y_pred, linear):
    d_y_pred = 2 * (y_pred - y_true) / x.shape[0]
    d_linear = np.dot(d_y_pred, linear.weights.T)
    d_weights = np.dot(x.T, d_y_pred)
    d_bias = np.sum(d_y_pred, axis=0, keepdims=True)
    
    return d_linear, d_weights, d_bias
# Example usage
input_dim = 10
output_dim = 1
x = np.random.randn(100, input_dim)
y_true = np.random.randn(100, output_dim)
linear = Linear(input_dim, output_dim)
y_pred, loss = forward_pass(x, y_true, linear)
d_linear, d_weights, d_bias = backward_pass(x, y_true, y_pred, linear)

5. Что такое исчезновение градиента, какие методы могут решить эту проблему (активация xavier, пакетная норма, остаточный блок, relu вместо сигмовидной и т. д.)

Исчезновение градиента — это явление, которое может происходить в глубоких нейронных сетях, где градиенты параметров по отношению к потерям становятся очень малыми в процессе обратного распространения, что затрудняет обновление параметров оптимизатором. Это может привести к медленной сходимости или даже к невозможности сходимости.

Существует несколько методов решения проблемы исчезновения градиента в глубоких нейронных сетях, в том числе:

  • Функции активации. Использование функций активации, таких как ReLU, дырявый ReLU или ELU, может помочь справиться с исчезновением градиента, поскольку они имеют ненулевые градиенты для положительных входных данных.
  • Пакетная нормализация. Пакетная нормализация нормализует активации каждого слоя в пакете, что помогает предотвратить слишком большое или слишком малое количество активаций.
  • Пропустить/Остаточные соединения: Пропустить соединения позволяют градиентам обходить один или несколько слоев и переходить непосредственно от вывода к более ранним слоям в сети, что может помочь предотвратить исчезновение градиента.
  • Отсечение градиента: Отсечение градиента — это метод, который ограничивает величину градиентов, что может помочь предотвратить их слишком большой размер и взрыв.
  • Инициализация весов: правильная инициализация весов сети может помочь предотвратить исчезновение градиента, так как малые значения веса могут привести к тому, что градиенты станут маленькими.

Вот пример реализации нейронной сети с активацией ReLU и пакетной нормализацией на Python:

import numpy as np

def relu(x):
    return np.maximum(0, x)
def l2_loss(y_true, y_pred):
    n = y_true.shape[0]
    loss = np.sum((y_true - y_pred)**2) / n
    return loss
class Linear:
    def __init__(self, input_dim, output_dim, bias=True):
        self.input_dim = input_dim
        self.output_dim = output_dim
        self.bias = bias
        
        self.weights = np.random.randn(input_dim, output_dim)
        if self.bias:
            self.bias = np.zeros((1, output_dim))
    
    def forward(self, x):
        out = np.dot(x, self.weights)
        if self.bias:
            out += self.bias
        return out
'''
In this example, the BatchNorm class implements batch normalization. 
The forward method takes an input x and a boolean training flag, and returns the normalized output. 
If the training flag is True, the method computes the mean and variance of the mini-batch and updates the running mean and variance. 
If the training flag is False, the method uses the running mean and variance to normalize the input. 
The beta and gamma parameters can be learned during training to adjust
'''
class BatchNorm:
    def __init__(self, num_features, epsilon=1e-5, momentum=0.9):
        self.num_features = num_features
        self.epsilon = epsilon
        self.momentum = momentum
        
        self.running_mean = np.zeros(num_features)
        self.running_var = np.zeros(num_features)
        
        self.gamma = np.ones(num_features)
        self.beta = np.zeros(num_features)
    
    def forward(self, x, training=True):
        if training:
            mean = x.mean(axis=0)
            var = x.var(axis=0)
            
            self.running_mean = self.momentum * self.running_mean + (1 - self.momentum) * mean
            self.running_var = self.momentum * self.running_var + (1 - self.momentum) * var
            
            x_hat = (x - mean) / np.sqrt(var + self.epsilon)
        else:
            x_hat = (x - self.running_mean) / np.sqrt(self.running_var + self.epsilon)
        
        out = self.gamma * x_hat + self.beta
        return out

6. Что такое оценка максимального правдоподобия,Как ее реализовать,Как она связана с градиентным спуском

Оценка максимального правдоподобия (MLE) — это распространенный метод, используемый в статистическом моделировании и машинном обучении для оценки параметров модели, которые лучше всего объясняют наблюдаемые данные. В MLE цель состоит в том, чтобы найти значения параметров, которые максимизируют функцию правдоподобия, которая представляет вероятность наблюдения данных с заданными параметрами.

MLE можно рассматривать как задачу оптимизации, целью которой является максимизация функции правдоподобия по отношению к параметрам. Одним из распространенных способов решения этой задачи оптимизации является градиентный спуск, при котором градиент функции правдоподобия по отношению к параметрам вычисляется и используется для обновления параметров в направлении максимального правдоподобия.

Вот простой пример того, как MLE можно реализовать в Python для оценки параметров распределения Гаусса:

В этом примере функция Гаусса вычисляет функцию плотности вероятности распределения Гаусса. Функция правдоподобия вычисляет вероятность данных с заданными параметрами. Функции grad_mu и grad_sigma вычисляют градиент вероятности по отношению к среднему и стандартному отклонению соответственно. Функция MLE реализует алгоритм MLE с использованием градиентного спуска. Функция обновляет среднее значение и стандартное отклонение на каждой итерации, пока не будет достигнуто максимальное количество итераций или не будут выполнены критерии сходимости.

import numpy as np
def gaussian(x, mu, sigma):
    return np.exp(-(x - mu)**2 / (2 * sigma**2)) / (np.sqrt(2 * np.pi) * sigma)
def likelihood(x, mu, sigma):
    return np.prod(gaussian(x, mu, sigma))
def grad_mu(x, mu, sigma):
    return np.sum((x - mu) * gaussian(x, mu, sigma)) / sigma**2
def grad_sigma(x, mu, sigma):
    return np.sum(((x - mu)**2 / sigma**2 - 1) * gaussian(x, mu, sigma)) / (2 * sigma)
def MLE(x, mu, sigma, learning_rate=0.01, max_iter=100):
    for i in range(max_iter):
        grad_mu_val = grad_mu(x, mu, sigma)
        grad_sigma_val = grad_sigma(x, mu, sigma)
        
        mu = mu + learning_rate * grad_mu_val
        sigma = sigma + learning_rate * grad_sigma_val
        
        if i % 10 == 0:
            print(f"Iteration {i}: mu = {mu:.4f}, sigma = {sigma:.4f}, likelihood = {likelihood(x, mu, sigma):.4f}")
    
    return mu, sigma
# Example usage
np.random.seed(0)
data = np.random.normal(0, 1, 100)
mu, sigma = MLE(data, 0, 1)
print(f"Estimated mu: {mu:.4f}")
print(f"Estimated sigma: {sigma:.4f}")

7. В чем разница между Batchnorm, layernorm и instancenorm? Как их реализовать?

Пакетная нормализация (BatchNorm), нормализация уровня (LayerNorm) и нормализация экземпляра (InstanceNorm) — все это методы нормализации, используемые в глубоком обучении для нормализации активаций сети перед применением функции активации. Основное различие между этими методами нормализации заключается в способе нормализации активаций и количестве параметров нормализации.

BatchNorm нормализует активации мини-партии путем вычитания среднего значения и деления на стандартное отклонение. BatchNorm имеет два обучаемых параметра для каждой активации: параметр масштаба (гамма) и параметр сдвига (бета). Эти параметры используются для масштабирования и сдвига нормализованных активаций, позволяя сети изучить оптимальные параметры нормализации.

LayerNorm нормализует активации всех нейронов в одном слое, а не в мини-пакете. Это делает LayerNorm более стабильным по сравнению с BatchNorm, поскольку статистика нормализации меньше зависит от размера мини-пакета. Как и BatchNorm, LayerNorm также имеет два обучаемых параметра для каждой активации.

InstanceNorm нормализует активацию каждого отдельного экземпляра или точки данных, а не мини-пакета или слоя. Это делает InstanceNorm хорошо подходящим для передачи стиля изображения, когда нормализация выполняется для каждого изображения, а не для пакета изображений. В отличие от BatchNorm и LayerNorm, InstanceNorm не имеет обучаемых параметров.

# Here's an example of how to implement BatchNorm in Python using the keras library:
from keras.layers import BatchNormalization
model.add(BatchNormalization())
# here's an example of how to implement LayerNorm in Python using the tensorflow library:
import tensorflow as tf
def layer_norm(x):
    return tf.contrib.layers.layer_norm(x, begin_norm_axis=-1)
output = layer_norm(input)

# here's an example of how to implement InstanceNorm in Python using the tensorflow library:
import tensorflow as tf
def instance_norm(x):
    mean, variance = tf.nn.moments(x, axes=[1, 2], keepdims=True)
    return tf.divide(tf.subtract(x, mean), tf.sqrt(variance + 1e-5))
output = instance_norm(input)

8. зачем использовать позиционное кодирование во внимании? сколько способов? Каковы плюсы и минусы?

Позиционное кодирование используется в моделях, основанных на внимании, для предоставления модели информации об относительном или абсолютном положении токенов в последовательности. Это особенно полезно для последовательностей переменной длины, таких как предложения или последовательности в НЛП, где модель может по своей природе не понимать порядок или положение токенов.

Существует несколько методов вычисления позиционных кодировок, в том числе:

  • Синусоидальные функции: в этом методе позиционные кодировки генерируются путем применения синусоидальных функций к положению маркеров.
  • Изученные вложения: в этом методе модель изучает набор вложений специально для позиций токенов во время обучения.
  • Фиксированные вложения: в этом методе к вложениям токенов добавляется набор фиксированных вложений для предоставления информации о местоположении.

Плюсы использования позиционных кодировок:

  • Улучшенная производительность: позиционное кодирование может помочь повысить производительность моделей на основе внимания при выполнении определенных задач, особенно тех, где важен порядок токенов.
  • Гибкость: позиционное кодирование можно добавить к любой модели, основанной на внимании, независимо от ее архитектуры или типа выполняемой задачи.

Минусы использования позиционных кодировок:

  • Повышенная сложность: добавление позиционных кодировок может увеличить сложность модели, усложнив ее обучение и потребовав дополнительных вычислительных ресурсов.
  • Переобучение: в некоторых случаях модель может слишком сильно полагаться на позиционное кодирование, что приводит к переобучению и снижению производительности на данных вне выборки.

В целом, использование позиционного кодирования в моделях, основанных на внимании, может быть полезным инструментом для повышения производительности при выполнении определенных задач, но важно тщательно взвесить все «за» и «против» и выбрать подходящий метод на основе специфических требований задачи в момент ее выполнения. рука.

примечание: я получил образцы вопросов из Интернета, я внес некоторые изменения в исходный пост.