我有一个包含8个参数的CSV文件,用于判断一个人是否患有糖尿病。你可以从这里获取该CSV文件。
我正在构建一个模型,用于训练和预测一个人是否患有糖尿病,而不使用TensorFlow、Scikit-learn等第三方应用程序。我是从头开始构建的。
这是我的代码:
from numpy import genfromtxtimport numpy as npmy_data = genfromtxt('E:/diabaties.csv', delimiter=',')X,Y = my_data[1: ,:-1], my_data[1: ,-1:] #striping data and output from my_datadef sigmoid(x): return (1/(1+np.exp(-x)))m = X.shape[0]def propagate(W, b, X, Y): #forward propagation A = sigmoid(np.dot(X, W) + b) cost = (- 1 / m) * np.sum(Y * np.log(A) + (1 - Y) * (np.log(1 - A))) print(cost) #backward propagation dw = (1 / m) * np.dot(X.T, (A - Y)) db = (1 / m) * np.sum(A - Y) return(dw, db, cost)def optimizer(W,b,X,Y,number_of_iterration,learning_rate): for i in range(number_of_iterration): dw, db, cost = propagate(W,b,X,Y) W = W - learning_rate*dw b = b - learning_rate*db return(W, b)W = np.zeros((X.shape[1],1))b = 0W,b = optimizer(W, b, X, Y, 100, 0.05)
生成的输出是:请查看这个链接中的内容。
我尝试过-用随机数初始化W的值。花了很多时间调试,但找不到我做错的地方
回答:
简短的回答是,你的学习率对于这个问题来说大了大约500倍。想象一下,你试图将你的W
向量引导到成本函数的峡谷中。在每一步,梯度告诉你下坡的方向,但你在这个方向上的步伐太大,以至于你跳过了峡谷,最终到了另一边。每次发生这种情况时,你的成本都会上升,因为你离峡谷越来越远,直到在2次迭代后,成本值激增。
如果你将行W,b = optimizer(W, b, X, Y, 100, 0.05)
替换为
W,b = optimizer(W, b, X, Y, 100, 0.0001)
它将会收敛,尽管速度仍然不理想。(顺便说一句,没有好的方法知道给定问题需要的学习率。你只能尝试越来越低的值,直到你的成本值不发散。)
更长的回答是,问题在于你的特征都在不同的尺度上。
col_means = X.mean(axis=0)col_stds = X.std(axis=0)print('column means: ', col_means)print('column stdevs: ', col_stds)
结果是
column means: [ 3.84505208 120.89453125 69.10546875 20.53645833 79.79947917 31.99257812 0.4718763 33.24088542]column stdevs: [ 3.36738361 31.95179591 19.34320163 15.94182863 115.16894926 7.87902573 0.33111282 11.75257265]
这意味着第二个特征的数值变化大约是倒数第二个特征的数值变化的100倍,这反过来意味着你W
向量中第二个值的调节精度需要是倒数第二个值的约100倍。
在实践中处理这个问题有两种方法。首先,你可以使用更高级的优化器。除了基本的梯度下降,你可以使用带动量的梯度下降,但这将改变你所有的代码。第二种更简单的方法是只需缩放你的特征,使它们大致相同大小。
col_means = X.mean(axis=0)col_stds = X.std(axis=0)print('column means: ', col_means)print('column stdevs: ', col_stds)X -= col_meansX /= col_stdsW, b = optimizer(W, b, X, Y, 100, 1.0)
在这里,我们从每个特征中减去其平均值,并将每个特征的值除以其标准差。有时新手会被这个方法弄糊涂——“你不能改变数据值,这会改变问题”——但如果你意识到这只是另一种数学变换,就像乘以W、加上b、取sigmoid等一样,它是有意义的。唯一的注意事项是你必须确保对未来的数据做同样的事情。就像你的W
向量的值是你的模型的学习参数一样,col_means
和col_stds
的值也是如此,所以你必须像保存W
和b
一样保存它们,并在将来使用这个模型对新数据进行推断时使用它们。
这样我们就可以使用更大的学习率1.0,因为现在所有特征的大小都大致相同了。
现在如果你尝试,你将得到以下输出:
column means: [ 3.84505208 120.89453125 69.10546875 20.53645833 79.79947917 31.99257812 0.4718763 33.24088542]column stdevs: [ 3.36738361 31.95179591 19.34320163 15.94182863 115.16894926 7.87902573 0.33111282 11.75257265]0.69314718055994520.59029575890790320.54817843781587320.5254804089153315...0.47099313212955620.47099312631935950.470993121221762730.47099311674880060.470993112823447
这就是你想要的。你的成本函数在每一步都在下降,在100次迭代结束时,成本稳定到大约8个有效数字,所以进一步降低可能不会有太大作用。
欢迎进入机器学习的世界!