编辑:我已经取得了重大进展。我当前的问题是在我最后一次编辑之后写的,可以在没有上下文的情况下回答。
我目前在Coursera上关注Andrew Ng的Machine Learning Course,今天尝试实现logistic regression。
符号:
X
是一个(m x n)
矩阵,其中输入变量的向量为行(m
个变量的n-1
训练样本,第一列的条目等于1到处代表一个常数)。y
是预期输出样本的相应向量(具有m
项等于0
或1
的列向量)theta
是模型系数的向量(具有n
个条目的行向量)对于输入行向量x
,模型将预测为阳性结果的概率sigmoid(x * theta.T)
。
这是我的Python3 / numpy实现:
import numpy as np
def sigmoid(x):
return 1 / (1 + np.exp(-x))
vec_sigmoid = np.vectorize(sigmoid)
def logistic_cost(X, y, theta):
summands = np.multiply(y, np.log(vec_sigmoid(X*theta.T))) + np.multiply(1 - y, np.log(1 - vec_sigmoid(X*theta.T)))
return - np.sum(summands) / len(y)
def gradient_descent(X, y, learning_rate, num_iterations):
num_parameters = X.shape[1] # dim theta
theta = np.matrix([0.0 for i in range(num_parameters)]) # init theta
cost = [0.0 for i in range(num_iterations)]
for it in range(num_iterations):
error = np.repeat(vec_sigmoid(X * theta.T) - y, num_parameters, axis=1)
error_derivative = np.sum(np.multiply(error, X), axis=0)
theta = theta - (learning_rate / len(y)) * error_derivative
cost[it] = logistic_cost(X, y, theta)
return theta, cost
该实现似乎工作正常,但是在计算物流成本时遇到了问题。在某个时候,梯度下降算法收敛到非常合适的theta
,并且发生以下情况:
对于某些具有预期结果X_i
1
的输入行X * theta.T
将变为正数,并具有良好的边距(例如23.207
)。这将导致sigmoid(X_i * theta)
变得完全 1.0000
(这是因为我认为精度下降)。这是一个很好的预测(因为预期结果等于1
),但是由于np.log(1 - vec_sigmoid(X*theta.T))
的评估结果为NaN
,因此这会中断物流成本的计算。这不应该是一个问题,因为该项会与1 - y = 0
相乘,但是一旦出现NaN
的值,整个计算就会中断(0 * NaN = NaN
)。
由于np.multiply(1 - y, np.log(1 - vec_sigmoid(X*theta.T)))
是在X
的每一行中计算的(不仅在y = 0
处),我应该如何处理?
示例输入:
X = np.matrix([[1. , 0. , 0. ],
[1. , 1. , 0. ],
[1. , 0. , 1. ],
[1. , 0.5, 0.3],
[1. , 1. , 0.2]])
y = np.matrix([[0],
[1],
[1],
[0],
[1]])
然后theta, _ = gradient_descent(X, y, 10000, 10000)
(是的,在这种情况下,我们可以将学习率设置为 this 大),将theta
设置为:
theta = np.matrix([[-3000.04008972, 3499.97995514, 4099.98797308]])
这将使vec_sigmoid(X * theta.T)
成为以下各项的真正好预测:
np.matrix([[0.00000000e+00], # 0
[1.00000000e+00], # 1
[1.00000000e+00], # 1
[1.95334953e-09], # nearly zero
[1.00000000e+00]]) # 1
但是logistic_cost(X, y, theta)
的值为NaN
。
编辑:
我想出了以下解决方案。我只是将logistic_cost
函数替换为:
def new_logistic_cost(X, y, theta):
term1 = vec_sigmoid(X*theta.T)
term1[y == 0] = 1
term2 = 1 - vec_sigmoid(X*theta.T)
term2[y == 1] = 1
summands = np.multiply(y, np.log(term1)) + np.multiply(1 - y, np.log(term2))
return - np.sum(summands) / len(y)
通过使用蒙版,我只在结果将始终与零相乘的位置上计算log(1)
。现在log(0)
仅会在错误的梯度下降实现中发生。
悬而未决的问题:如何使该解决方案更干净?是否有可能以更清洁的方式达到类似的效果?
答案 0 :(得分:0)
如果您不介意使用SciPy,则可以从type ErrorSpy struct {
spies.Spy
}
func (spy *ErrorSpy) Get(code AccessCode) *ErrorSt {
res := spy.Called(code)
return res.Get(0).(*ErrorSt)
}
导入expit
和xlog1py
:
scipy.special
并替换表达式
from scipy.special import expit, xlog1py
使用
np.multiply(1 - y, np.log(1 - vec_sigmoid(X*theta.T)))
答案 1 :(得分:0)
我知道这是一个老问题,但是我遇到了同样的问题,也许它将来可以帮助其他人,实际上我通过在附加X0之前对数据实施归一化来解决了这个问题。
def normalize_data(X):
mean = np.mean(X, axis=0)
std = np.std(X, axis=0)
return (X-mean) / std
此后一切正常!