@fsfzp888
2018-05-20T21:13:47.000000Z
字数 3956
阅读 1544
线性代数
机器学习基础
在前一篇的总结中,从矩阵的视角回顾了最小二乘,最终还得到了如下求解最小二乘的解的方程:
在进一步之前,我们先换一种表达方式,前边等式的表达方式换成下边的形式:
- (1) 初始化参数
- (2) 计算
- (3) 判断是否成立,若成立则跳转到步骤(5),否则执行步骤(4)
- (4) 使用等式更新参数,并跳转到步骤(2)
- (5) 输出待估参数
可以看到,整个过程并不复杂,只不过,不同的模型,损失函数是不一样的。在任何梯度下降过程中,都是要先定义好模型,模型有各个参数,然后再依据一些原则,比如说最大似然等,得到损失函数,然后在不断迭代知道损失小于某一个阈值为止,可以选用二范数等标准衡量阈值是否满足。这一个过程都是通用的,只不过不同的模型,具体的计算方法都是不一样的。而且学习率的设置也是非常关键的。太大太小都是不行的。对于大样本的情况下,一次取所有数据去计算也是不现实的,所以一般会随机的取部分的样本去计算步骤(2)中的值,这个过程称为随机梯度下降,但是本质上,和梯度下降之间的差别也就是怎么取样本的问题,大体的步骤也就只是这样而已。
关于梯度下降,我想总还是有些局限性的。
这篇总结文档中的示例仅仅只是作为演示,去实现最小二乘拟合一些伪造数据,也不具备通用性,只是起到示意作用。
首先,来定义模型,假定我们想要使用下边的方程去拟合数据:
# -*- coding: utf-8 -*-
import numpy as np
LEARNING_RATE = 0.2
TOLERANCE = 0.00001
def compute_grad(w, x, y):
grad = [0, 0, 0]
diff = w[0] + w[1] * x + w[2] * x * x - y
grad[0] = 2.0 * np.mean(diff)
x_diff = x * diff
grad[1] = 2.0 * np.mean(x_diff)
x_x_diff = np.square(x) * diff
grad[2] = 2.0 * np.mean(x_x_diff)
return np.array(grad)
def update_weight(w, learning_rate, grad):
new_w = np.array(w) - learning_rate * grad
return new_w
def loss_err(w, x, y):
loss = np.sqrt(np.mean(np.square(w[0] + w[1] * x + w[2] * np.square(x) - y)))
return loss
def estimate_weight(x, y):
w = np.array([1, 1, 1])
grad = compute_grad(w, x, y)
loss = loss_err(w, x, y)
w = update_weight(w, LEARNING_RATE, grad)
loss_new = loss_err(w, x, y)
i = 1
while np.abs(loss_new) > TOLERANCE:
grad = compute_grad(w, x, y)
w = update_weight(w, LEARNING_RATE, grad)
loss = loss_new
loss_new = loss_err(w, x, y)
i += 1
if i % 5 == 0:
print("Iterate %s: loss error is %s" % (i, loss_new))
print("Final loss error %s after %s iterations" % (loss_new, i))
return w
def generate_sample():
x_list = [i for i in range(5000)]
max_x = max(x_list) # normalized to one to prevent overflow
x_list = [x / max_x for x in x_list]
y_list = [1 + 2 * x + x * x for x in x_list]
for y in y_list:
y += np.random.random(1) * 0.1 # add some noise
return np.array(x_list), np.array(y_list)
if __name__ == '__main__':
x_data, y_data = generate_sample()
weight = estimate_weight(x_data, y_data)
print(weight)
上边的代码没有什么好说的,只不过,在处理输入数据的时候,必须要归一化,否则会溢出,这是非常关键的。在实际应用中,我想也需要这么做。输出的结果:
...
Iterate 7615: loss error is 1.0201223917743257e-05
Iterate 7620: loss error is 1.0146469766079486e-05
Iterate 7625: loss error is 1.009200950241291e-05
Iterate 7630: loss error is 1.0037841549308142e-05
Final loss error 9.99471659581732e-06 after 7634 iterations
[1.0000246 1.99986244 1.00013272]
@fsfzp888
2018 年 05月 20日