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

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

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

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

Что такое оптимизация и зачем она нужна?

Оптимизация относится к процессу минимизации или максимизации целевой функции f(x) как функции x. Он включает в себя минимизацию функции стоимости/потери J(w), параметризованной параметрами модели w ∈ R^d. Алгоритмы оптимизации преследуют следующие цели (в случае минимизации):

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

Алгоритмы оптимизации делятся на три категории:

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

Машинное обучение и глубокое обучение используют градиентный спуск в качестве основного алгоритма оптимизации, а градиентный спуск — это алгоритм оптимизации первого порядка. Это означает, что он обновляет параметры только с использованием первой производной. Для каждой итерации параметры обновляются напротив градиента целевой функции J(w) с учетом параметров, где градиент определяет наискорейший подъем. Для достижения локального минимума размер шага на каждой итерации зависит от скорости обучения α. В результате следим за наклоном склона вниз, пока не достигнем локального минимума. (См. схему ниже).

Теперь давайте обсудим различные типы/варианты градиентного спуска.

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

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

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

Следующие шаги связаны с выполнением пакетного градиентного спуска:

  • Создайте случайное значение для скорости обучения и коэффициентов модели.
  • Вычислить прогнозируемые значения (y-hat).
  • Определить функцию потерь и член ошибки.
  • Обновите коэффициенты модели.
  • Повторяйте шаги, пока не будет достигнута конвергенция.

Реализация Python:

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

Чтобы обучить нашу модель, мы создали несколько случайных точек данных с 500 строками и 2 столбцами (x и y).

data = np.random.randn(500, 2) 
## Column one=X values; Column two=Y values
theta = np.zeros(2) 
## Model Parameters(Weights)

Использование MSE для определения функции потерь:

def loss_function(data,theta):
#getting m and b
m = theta[0]
b = theta[1]
loss = 0
#Now, on each data point, getting x and y
for i in range(0, len(data)):
x = data[i, 0]
y = data[i, 1]
#predicting the value of y
y_hat = (m*x + b)
#computing the loss
loss = loss + ((y - (y_hat)) ** 2)
#mean sqaured loss
mean_squared_loss = loss / float(len(data))
return mean_squared_loss

Нахождение градиента функции потерь для параметров модели:

def compute_gradients(data, theta):
gradients = np.zeros(2)
#the total number of data points
N = float(len(data))
m = theta[0]
b = theta[1]
#Now, for each data point
for i in range(len(data)):
x = data[i, 0]
y = data[i, 1]
#finding the gradient of loss function with respect to m
gradients[0] += - (2 / N) * x * (y - (( m* x) + b))
#finding the gradient of loss funcction with respect to b
gradients[1] += - (2 / N) * (y - ((theta[0] * x) + b))
#adding the epsilon to avoid division by zero error
epsilon = 1e-6
gradients = np.divide(gradients, N + epsilon)
return gradients

После расчета градиентов мы должны обновить параметр модели.

theta = np.zeros(2)
gr_loss=[]
for t in range(50000):
#computing the gradients
gradients = compute_gradients(data, theta)
#updating the parameters
theta = theta - (1e-2*gradients)
#storing the loss
gr_loss.append(loss_function(data,theta))

Какие советы дают известные компании студентам и стартапам? Мы попросили их! Прочитайте или посмотрите наши отраслевые вопросы и ответы, чтобы получить советы от команд из Стэнфорда, Google и HuggingFace.

2. Стохастический градиентный спуск (SGD)

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

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

Вот шаги процесса стохастического градиентного спуска:

  1. Начнем с инициализации весового вектора w.
  2. Затем, пока не будет достигнуто условие завершения (т. е. достаточно малое значение J или количество итераций), выполните:
  3. Рандомизируйте выборки в наборе обучающих данных.
  4. Обновите каждый wi, чтобы он был wi = wi + η(t-o) xi для одного обучающего примера.

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

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

Реализация Python:

# Here (xy) is the (training_set,target) pair
def stochastic_gradient_descent(max_epochs,threshold,w_init, obj_func,grad_func,xy,learning_rate=0.05,momentum=0.8):(x_train,y_train) = xy
w = w_init
w_history = w
f_history = obj_func(w,xy)
delta_w = np.zeros(w.shape)
i = 0
diff = 1.0e10
rows = x_train.shape[0]
# Running epochs
while  i<max_epochs and diff>threshold:
# Shuffling rows using the fixed seed to reproduce the results
np.random.seed(i)
p = np.random.permutation(rows)
# Running for each instance/example in training set
for x,y in zip(x_train[p,:],y_train[p]):
delta_w = -learning_rate*grad_func(w,(np.array([x]),y)) + momentum*delta_w
w = w+delta_w
i+=1
w_history = np.vstack((w_history,w))
f_history = np.vstack((f_history,obj_func(w,xy)))
diff = np.absolute(f_history[-1]-f_history[-2])
return w_history,f_history

Теперь давайте посмотрим на результаты стохастической версии градиентного спуска:

rand = np.random.RandomState(19)
w_init = rand.uniform(-1,1,x_train.shape[1])*.000001
w_history_stoch,mse_history_stoch = stochastic_gradient_descent(100, 0.1,w_init, mse,grad_mse,(x_train,y_train), learning_rate=1e-6,momentum=0.7)
# Plotting the MSE
plt.plot(np.arange(mse_history_stoch.size),mse_history_stoch)
plt.xlabel(‘Iteration No.’)
plt.ylabel(‘Mean Square Error’)
plt.title(‘Gradient Descent on Digits Data (Stochastic Version)’)
plt.show()

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

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

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

Реализация Python:

def minibatch(data, theta, lr = 1e-2, minibatch_ratio = 0.01, num_iterations = 5000):
loss = []
minibatch_size = int(math.ceil(len(data) * minibatch_ratio)) #Calculates batch_size
for t in range(num_iterations):
sample_size = random.sample(range(len(data)), minibatch_size)
np.random.shuffle(data)
#sampling batch of data
sample_data = data[0:sample_size[0], :]
#computing gradients
grad = compute_gradients(sample_data, theta)
#updating parameters
theta = theta — (lr * grad)
loss.append(loss_function(data,theta))
return loss

Заключение

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

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

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

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

Если вы хотите внести свой вклад, перейдите к нашему призыву к участию. Вы также можете подписаться на получение наших еженедельных информационных бюллетеней (Еженедельник глубокого обучения и Информационный бюллетень Comet), присоединиться к нам в Slack и следить за Comet в Twitter и LinkedIn, чтобы получать ресурсы, события и многое другое, что поможет вам быстрее создавать лучшие модели машинного обучения.