Ответ 1
Есть две возможные причины, почему это может происходить с вами.
Данные не нормализованы
Это связано с тем, что когда вы применяете сигмоидную/логитную функцию к своей гипотезе, вероятность выхода почти равна приблизительно 0 или 1, а с вашей функцией затрат log(1 - 1)
или log(0)
будет выдавать -Inf
. Накопление всех этих индивидуальных условий в вашей функции стоимости в конечном итоге приведет к NaN
.
В частности, если y = 0
для примера обучения и если вывод вашей гипотезы log(x)
, где x
- очень небольшое число, близкое к 0, рассмотрение первой части функции стоимости даст нам 0*log(x)
и на самом деле произведет NaN
. Аналогично, если y = 1
для примера обучения, и если результат вашей гипотезы также log(x)
, где x
- очень маленькое число, это снова даст нам 0*log(x)
и произведет NaN
. Проще говоря, вывод вашей гипотезы либо очень близок к 0, либо очень близок к 1.
Это, скорее всего, связано с тем, что динамический диапазон каждой функции сильно отличается, и поэтому часть вашей гипотезы, в частности, взвешенная сумма x*theta
для каждого учебного примера, который у вас есть, даст вам либо очень большой отрицательный результат или положительные значения, и если вы примените сигмоидную функцию к этим значениям, вы окажетесь очень близко к 0 или 1.
Один из способов борьбы с этим - нормализовать данные в вашей матрице перед началом обучения с использованием градиентного спуска. Типичным подходом является нормализация с нулевым средним и единичным изменением. Учитывая функцию ввода x_k
где k = 1, 2, ... n
, где у вас есть функции n
, новая нормализованная функция x_k^{new}
может быть найдена:
m_k
является средним значением функции k
и s_k
является стандартным отклонением функции k
. Это также известно как стандартизация данных. Вы можете прочитать более подробную информацию об этом в другом ответе, который я привел здесь: Как работает этот код для стандартизации данных?
Поскольку вы используете подход линейной алгебры к градиентному спуску, я предполагаю, что вы добавили свою матрицу данных со столбцом всех. Зная это, мы можем нормализовать ваши данные следующим образом:
mX = mean(x,1);
mX(1) = 0;
sX = std(x,[],1);
sX(1) = 1;
xnew = bsxfun(@rdivide, bsxfun(@minus, x, mX), sX);
Среднее и стандартное отклонения каждой функции сохраняются в mX
и sX
соответственно. Вы можете узнать, как работает этот код, прочитав сообщение, которое я связал с вами выше. Я не буду повторять этот материал здесь, потому что это не объем этой публикации. Чтобы обеспечить нормальную нормализацию, я сделал среднее и стандартное отклонение первого столбца равным 0 и 1 соответственно. xnew
содержит новую нормированную матрицу данных. Используйте xnew
с вашим алгоритмом спуска градиента. Теперь, когда вы найдете параметры, для выполнения любых прогнозов вы должны нормализовать любые новые тестовые экземпляры со средним и стандартным отклонением от набора обучения. Поскольку полученные параметры являются статистическими данными набора тренировок, вы также должны применять те же преобразования к любым тестовым данным, которые вы хотите отправить в модель прогнозирования.
Предполагая, что у вас есть новые точки данных, хранящиеся в матрице с именем xx
, вы должны выполнить нормализацию, а затем выполнить предсказания:
xxnew = bsxfun(@rdivide, bsxfun(@minus, xx, mX), sX);
Теперь, когда у вас есть это, вы можете выполнить свои прогнозы:
pred = sigmoid(xxnew*theta) >= 0.5;
Вы можете изменить порог 0,5, чтобы быть тем, что, по вашему мнению, лучше всего определяет, относятся ли примеры к положительному или отрицательному классу.
Слишком большая скорость обучения
Как вы упомянули в комментариях, как только вы нормализуете данные, затраты кажутся конечными, но затем внезапно перейдите к NaN после нескольких итераций. Нормализация может довести вас до сих пор. Если ваша скорость обучения или alpha
слишком велика, каждая итерация будет превышать по направлению к минимуму, и, таким образом, стоимость каждой итерации будет колебаться или даже расходиться, что и происходит. В вашем случае стоимость расходится или увеличивается на каждой итерации до такой степени, что она не может быть представлена с использованием точности с плавающей запятой.
Таким образом, еще один вариант - уменьшить скорость обучения alpha
, пока вы не увидите, что функция затрат уменьшается на каждой итерации. Популярным методом определения наилучшей скорости обучения является выполнение градиентного спуска в диапазоне значений с логарифмически разнесенными значениями alpha
и просмотр значения конечной стоимости функции и выбор скорости обучения, которая привела к наименьшей стоимости.
Использование двух приведенных выше фактов должно позволить сгладить градиентный спуск довольно хорошо, предполагая, что функция стоимости является выпуклой. В этом случае для логистической регрессии это, безусловно, есть.