В этой статье я расскажу вам о реализации пакетного градиентного спуска, стохастического градиентного спуска и мини-пакетного градиентного спуска с нуля в python. Это будет удобно для новичков. Понимание метода градиентного спуска поможет вам оптимизировать потери во время обучения модели машинного обучения. Кроме того, я объясню влияние импульса на процесс обучения.

Что вы узнаете из этой статьи:

  • Что такое потери и стоимость Функция.
  • Что такое градиентный спуск.
  • Как работает градиентный спуск.
  • Виды градиентного спуска.
  • Влияние импульса в процессе обучения.
  • Реализация с нуля на питоне.

Функция потерь и затрат

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

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

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

Градиентный спуск

Градиент — это линейная аппроксимация функции. Градиентный спуск — это итеративный процесс поиска локального максимума и минимума функции. Согласно определению IBM, «градиентный спуск — это алгоритм оптимизации, который обычно используется для обучения моделей машинного обучения и нейронных сетей».

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

Как работает градиентный спуск.

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

Формула градиентного спуска приведена ниже.

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

Типы градиентного спуска.

Пакетный градиентный спуск

При пакетном градиентном спуске потери для всех точек в обучающем наборе усредняются, а модель (вес) обновляется только после оценки всех обучающих примеров за одну итерацию обучения.

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

Стохастический градиентный спуск

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

Мини-пакетный градиентный спуск

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

Влияние импульса на процесс обучения

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

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

Реализация с нуля на Python

Полный цикл обучения с использованием алгоритма градиентного спуска будет следовать этим шагам;

- инициализировать параметры - запустить некоторое количество эпох

- использовать параметры для прогнозирования

- Расчет и хранение потерь

- Вычислить градиенты потерь по параметрам

- Используйте градиенты для обновления параметров

- Делай что-нибудь еще или конец!

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

def linear_function(X, theta):#Linear function
  assert X.ndim > 1
  assert theta.ndim > 1
  return np.dot(X, theta)

#Loss function (MSE)
def mean_squared_error(ytrue, ypred):
  return np.mean((ytrue - ypred)**2)


#Here we initialize the weight(parameter)
def initialize_theta(D): 
  return np.zeros([D, 1])

#Here we compute the gradient of lost. This is gotten by finding the derivative of the loss with respect to the weight
def batch_gradient(X, y, theta):
  return -2.0 * np.dot(X.T, (y - linear_function(X, theta)))

#Updating function: gradient descent
def update_function(theta, grads, step_size):
  return theta - step_size * grads

Пакетный градиентный спуск

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

def train_batch_gradient_descent(X, y, num_epochs, step_size=0.1, plot_every=1):

  N, D = X.shape
  theta = initialize_theta(D)
  losses = []
  for epoch in range(num_epochs): # Do some iterations
    ypred = linear_function(X, theta) # make predictions with current parameters
    loss = mean_squared_error(y, ypred) # Compute mean squared error
    grads = batch_gradient(X, y, theta) # compute gradients of loss wrt parameters
    theta = update_function(theta, grads, step_size) # Update your parameters with the gradients
    
    losses.append(loss)
    print(f"\nEpoch {epoch}, loss {loss}")
  return losses

Вы можете использовать библиотеку matplotlib для построения графика потерь.

plt.plot(losses)
plt.xlabel("epoch")
plt.ylabel("loss")
plt.title("training curve")

Стохастический градиентный спуск

Стохастический градиентный спуск, в отличие от пакетного градиентного спуска, выбирает случайные выборки или подмножества выборок и обновляет параметры с их градиентами.

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

def per_sample_gradient(xi, yi, theta):
  return -2.0 * xi * (yi - linear_function(xi, theta))

def shuffle_data(X, y):
  N, _ = X.shape
  shuffled_idx = np.random.permutation(N)
  return X[shuffled_idx], y[shuffled_idx]
def train_with_sgd(X, y, num_epochs, step_size, plot_every=1):
  """Train with stochastic gradient descent"""
  N, D = X.shape
  theta = initialize_theta(D)
  losses = []
  epoch = 0
  loss_tolerance = 0.001
  avg_loss = float("inf")

  while epoch < num_epochs and avg_loss > loss_tolerance:
    running_loss = 0.0
    shuffled_x, shuffled_y = shuffle_data(X, y)

    for idx in range(shuffled_x.shape[0]):
      sample_x = shuffled_x[idx].reshape(-1, D)
      sample_y = shuffled_y[idx].reshape(-1, 1)
      ypred = linear_function(sample_x, theta)
      loss = mean_squared_error(sample_y, ypred)
      running_loss += loss
      grads = per_sample_gradient(sample_x, sample_y, theta)
      theta = update_function(theta, grads, step_size)

    avg_loss = running_loss/ X.shape[0]
    losses.append(avg_loss)
    print(f"Epoch {epoch}, loss {avg_loss}")

    epoch += 1

  return losses

Кроме того, во введении я объяснил импульс, этот код покажет, как вы можете интегрировать импульс в ЦУР.

def get_momentum(momentum, grad, beta):
  return beta * momentum + (1. - beta) * grad

ЦУР с импульсом

def train_sgd_with_momentum(X, y, num_epochs, step_size, beta, plot_every=1):
  """Train with stochastic gradient descent"""
  N, D = X.shape
  theta = initialize_theta(D)
  losses = []
  epoch = 0
  loss_tolerance = 0.001
  avg_loss = float("inf")

  while epoch < num_epochs and avg_loss > loss_tolerance:
    momentum = 0.0
    running_loss = 0.0
    shuffled_x, shuffled_y = shuffle_data(X, y)

    for idx in range(shuffled_x.shape[0]):
      sample_x = shuffled_x[idx].reshape(-1, D)
      sample_y = shuffled_y[idx].reshape(-1, 1)
      ypred = linear_function(sample_x, theta)
      loss = mean_squared_error(sample_y, ypred)
      running_loss += loss
      grad = per_sample_gradient(sample_x, sample_y, theta)
      momentum = get_momentum(momentum, grad, beta)
      theta = update_function(theta, momentum, step_size)#in this function the gradient will be replaced by the momentum

    avg_loss = running_loss/ X.shape[0]
    losses.append(avg_loss)
    print(f"Epoch {epoch}, loss {avg_loss}")

    epoch += 1

  return losses

Мини-пакетный градиентный спуск

Давайте теперь закончим с мини-пакетным градиентным спуском.

В этом случае вместо вычисления градиентов для полного набора данных мы разбиваем данные на пакеты, за исключением последнего пакета, причем каждый пакет имеет определенный нами размер «batch_size». Вы понимаете причину?

В этом случае следует отметить несколько факторов;

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

def minibatch_gradient_descent(X, y, num_epochs, step_size=0.1, batch_size=3, plot_every=1):
  N, D = X.shape
  theta = initialize_theta(D)
  losses = []
  num_batches = N//batch_size
  X, y = shuffle_data(X, y) # shuffle the data

  for epoch in range(num_epochs): # Do some iterations
    running_loss = 0.0
    
    for batch_idx in range(0, N, batch_size):
      x_batch = X[batch_idx: batch_idx + batch_size] # select a batch of features
      y_batch = y[batch_idx: batch_idx + batch_size] # and a batch of labels

      ypred = linear_function(x_batch, theta) # make predictions with current parameters
      loss = mean_squared_error(y_batch, ypred) # Compute mean squared error
      grads = batch_gradient(x_batch, y_batch, theta) # compute gradients of loss wrt parameters
      theta = update_function(theta, grads, step_size) # Update your parameters with the gradients
      running_loss += (loss * x_batch.shape[0]) # loss is mean for a batch, dividing by N_batch gives 
                                                # us a sum for the batch so we can average later by diving 
                                                # by the full data size
    
    avg_loss = running_loss/ N
    losses.append(avg_loss)
    print(f"\nEpoch {epoch}, loss {avg_loss}")
  return losses

Заключение

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

В этой статье мы обсудили градиентный спуск с точки зрения его типа, импульса и его приложений. Мы используем Python для реализации алгоритмов с нуля в конце объяснения.

Следите за мной в:

Твиттер: @jel__ade

LinkedIn: Адежумо Абдулджалил

GitHub: джеладе