Я думаю, что в целом ваш код работает.Скорее всего, то, что вы наблюдаете, связано с настройкой вашей альфы.Это кажется слишком высоким, поэтому тэта расходится.В какой-то момент он получает inf
или -inf
, и после этого вы получаете NaN
s в следующей итерации.Я распознал ту же проблему.
Вы можете проверить это, используя простую настройку:
# output theta in your function
def gradient(x, y, theta, alpha, iterations):
cost_history = [0] * iterations
for i in range(iterations):
h = theta.dot(x.T) #hypothesis
#print('h:', h)
loss = h - y
#print('loss:', loss)
g = loss.dot(x) / len(y)
#print('g:', g)
theta = theta - alpha * g
print('theta:', theta)
cost_history[i] = costfn(x, y, theta)
#print(theta)
return theta, cost_history
# set up example data with a simple linear relationship
# where we can play around with different numbers of parameters
# conveniently
# with some noise
num_params= 2 # how many params do you want to estimate (up to 5)
# take some fixed params (we only take num_params of them)
real_params= [2.3, -0.1, 8.5, -1.8, 3.2]
# now generate the data for the number of parameters chosen
x_train= np.random.randint(-100, 100, size=(80, num_params))
x_noise= np.random.randint(-100, 100, size=(80, num_params)) * 0.001
y_train= (x_train + x_noise).dot(np.array(real_params[:num_params]))
theta= np.zeros(num_params)
Теперь попробуйте с высокой скоростью обучения
theta, cost_history = gradient(x_train, y_train, theta, 0.1, 1000)
Скорее всего, вызаметим, что показатели ваших тэта-значений будут становиться все выше и выше, пока они, наконец, не достигнут inf
или -inf
.После этого вы получите NaN
значения.
Если вы установите его на низкое значение, например 0,00001, вы увидите, что оно сходится:
theta: [ 0.07734451 -0.00357339]
theta: [ 0.15208803 -0.007018 ]
theta: [ 0.22431803 -0.01033852]
theta: [ 0.29411905 -0.01353942]
theta: [ 0.36157275 -0.01662507]
theta: [ 0.42675808 -0.01959962]
theta: [ 0.48975132 -0.02246712]
theta: [ 0.55062617 -0.02523144]
...
theta: [ 2.29993382 -0.09981407]
theta: [ 2.29993382 -0.09981407]
theta: [ 2.29993382 -0.09981407]
theta: [ 2.29993382 -0.09981407]
Что очень близко к реальномупараметры 2.3
и -0.1
.
Таким образом, вы можете поэкспериментировать с кодом, который адаптирует скорость обучения, чтобы значения сходились быстрее и риск расхождения был ниже.Вы также можете реализовать что-то вроде ранней остановки, чтобы прекратить итерации по выборкам, если ошибка не меняется или изменение ниже порогового значения.
Например, вы можете использовать следующую модификацию вашей функции:
def gradient(
x,
y,
theta=None,
alpha=0.1,
alpha_factor=0.1 ** (1/5),
change_threshold=1e-10,
max_iterations=500,
verbose=False):
cost_history = list()
if theta is None:
# theta was not passed explicitely
# so initialize it
theta= np.zeros(x.shape[1])
last_loss_sum= float('inf')
len_y= len(y)
for i in range(1, max_iterations+1):
h = theta.dot(x.T) #hypothesis
loss = h - y
loss_sum= np.sum(np.abs(loss))
if last_loss_sum <= loss_sum:
# the loss didn't decrease
# so decrease alpha
alpha= alpha * alpha_factor
if verbose:
print(f'pass: {i:4d} loss: {loss_sum:.8f} / alpha: {alpha}')
theta_old= theta
g= loss.dot(x) / len_y
if loss_sum <= last_loss_sum and last_loss_sum < float('inf'):
# only apply the change if the loss is
# finite to avoid infinite entries in theta
theta = theta - alpha * g
theta_change= np.sum(np.abs(theta_old - theta))
if theta_change < change_threshold:
# Maybe this seems a bit awkward, but
# the comparison of change_threshold
# takes the relationship between theta and g
# into account. Note that g will not have
# an effect if theta is orders of magnitude
# larger than g, even if g itself is large.
# (I mean if you consider g and theta elementwise)
cost_history.append(costfn(x, y, theta))
break
cost_history.append(costfn(x, y, theta))
last_loss_sum= loss_sum
return theta, cost_history
Изменения адреса ранней остановки, автоматической настройки alpha
и кодирования theta
для получения бесконечных значений.Вам нужно только передать X
и y
в минимальном случае, все остальные параметры имеют значения по умолчанию.Установите verbose=True
, если хотите увидеть, как убыток уменьшается в каждом итераторе.