本节我们通过实战训练单输入神经元线性模型。首先我们需要采样自真实模型的多组数据,我们直接自从指定的w=1.477,b=0.089的真实模型中直接采样:
y = 1.477x+0.089
1、 采样数据
为了能够很好地模拟真实样本的观测误差,我们给模型添加误差自变量ε,它采样自均值为0,标准差为0.1 的高斯分布:
y=1.477x+0.089+ε, ε~N(0,0.1^2)
通过随机采样n = 1000 次,我们获得n个样本的训练数据集。代码如下:
data = [] #保存样本集的列表
for i in range(100): #循环采样100个点
x = np.random.uniform(-10., 10.) #随机采样输入x
# mean=0, std=0.1
# 采样高斯噪声
eps = np.random.normal(0., 0.1)
#得到模型的输出
y = 1.566 * x + 0.079 + eps
#保存样本点
data.append([x, y])
#转换为2D Numpy数组
data = np.array(data)
np.savetxt("data.csv",data)
2、 计算误差
循环计算在每个点(x^(i), y^(j))处的预测值与真实值之间差的平方并累加,从而获得训练集上的均方误差损失值。代码如下
def mse(b, w, points):
#根据当前的w,b参数计算均方差损失
totalError = 0
for i in range(0, len(points)): #循环迭代所有点
x = points[i, 0] #获得i号点的输入x
y = points[i, 1] #获得i号的输出y
# computer mean-squared-error
#计算差的平方,并累加
totalError += (y - (w * x + b)) ** 2
# average loss for each point
#将累加的误差求平均,得到均分差
return totalError / float(len(points))
3、 计算梯度
def step_gradient(b_current, w_current, points, learningRate):
#计算误差函数在所有点上的导数,并更新w,b
b_gradient = 0
w_gradient = 0
N = float(len(points)) #总样本数
for i in range(0, len(points)):
x = points[i, 0]
y = points[i, 1]
# grad_b = 2(wx+b-y)
#误差函数对b的导数:grad_b = 2(wx+b-y)
b_gradient += (2/N) * ((w_current * x + b_current) - y)
# grad_w = 2(wx+b-y)*x
#误差函数对x的导数:grad_w = 2(wx+b-y)*x
w_gradient += (2/N) * x * ((w_current * x + b_current) - y)
# update w'
#根据梯度下降算法更新w,b,其中learningRate 为学习率
new_b = b_current - (learningRate * b_gradient)
new_w = w_current - (learningRate * w_gradient)
return [new_b, new_w]
4、 梯度更新
在计算出误差函数在w和b处的梯度后,我们根据梯度公式更新w和b的值。我们把对数据集的所有样本训练一次称为一个Epoch,共循环迭代 num_iterations 个 Epoch。代码如下:
def gradient_descent_runner(points, starting_b, starting_w, learning_rate, num_iterations):
#循环更新w,b多次
b = starting_b #b的初始值
w = starting_w #w的初始值
# update for several times
#根据梯度下降算法更新多次
for i in range(num_iterations):
#计算梯度并更新一次
b, w = step_gradient(b, w, np.array(points), learning_rate)
loss = compute_error_for_line_given_points(b,w,points)
if i%100 == 0:
print(f"iterations:{i},loss:{loss},w:{w},b:{b}")
return [b, w] #返回最后一次的w,b
5、 主训练函数
def run():
#加载训练集数据,这些数据是通过真实模型添加观测误差采样得到的
points = np.genfromtxt("data.csv", delimiter=",")
learning_rate = 0.01 #学习率
initial_b = 0 # initial y-intercept guess #初始化b为0
initial_w = 0 # initial slope guess #初始化w为0
num_iterations = 1000
#训练优化1000次,返回最优w,b和训练Loss的下降过程
[b, w] = gradient_descent_runner(data, initial_b, initial_w, learning_rate, num_iterations)
loss = compute_error_for_line_given_points(b, w, data)
print(f'Final loss:{loss},w:{w},b:{b}')
if __name__ == '__main__':
run()
经过 1000 的迭代更新后,保存最后的w和b值,此时的w和b的值就是我们要找的数值解。运行结果如下: