线性回归
1 模型定义
线性回归是个非常简单的模型,它的形式如下:
y
=
A
x
+
b
y=Ax+b
y=Ax+b
其中
x
∈
R
n
,
A
∈
R
m
×
n
,
b
∈
R
m
,
y
∈
R
m
x \in R^n,A\in R^{m\times n},b\in R^m,y\in R^m
x∈Rn,A∈Rm×n,b∈Rm,y∈Rm
假设输入
x
x
x和输出
y
y
y之间是线性关系,根据训练数据集合
Y
Y
Y和
X
X
X来学习出最优的参数
A
A
A和
b
b
b。
2 准备数据
简单起见,假设x和y都是一维的实数。我们希望生成的数据中是“真实”的,所以在数据上加上了随机的高斯噪声,模拟真实情况下存在的噪声。
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
x_vals = np.linspace(0,10,100) # 生成100个在区间[1,10]的实数
print(x_vals) # 输出查看
realA = 2.5
realb = -5
y_reals = realA * x_vals + realb # 假设真实的y和x符合一维线性分布
y_vals = y_reals + np.random.normal(0, 1, 100) # 在y上加上随机的高斯噪声
# Plot the reasults,查看生成的训练数据
plt.plot(x_vals, y_vals, 'o', label='Data')
plt.plot(x_vals, y_vals, 'r-', label='Best fit line', linewidth=3)
plt.legend(loc='upper left')
plt.show()
生成的数据集如下图所示
SGD训练
下面的公式是简单的梯度计算
y
^
i
=
A
x
i
+
b
\widehat{y}_i = Ax_i + b
y
i=Axi+b
L
(
y
^
i
,
y
j
)
=
1
2
∑
i
(
y
^
i
−
y
i
)
2
L(\widehat{y}_i,y_j) = \frac{1}{2}\sum_{i}(\widehat{y}_i-y_i)^2
L(y
i,yj)=21i∑(y
i−yi)2
d
L
d
A
=
∑
i
(
y
^
i
−
y
i
)
x
i
\frac{dL}{dA}=\sum_i(\widehat{y}_i-y_i)x_i
dAdL=i∑(y
i−yi)xi
d
L
d
b
=
∑
i
(
y
^
i
−
y
i
)
\frac{dL}{db}=\sum_i(\widehat{y}_i-y_i)
dbdL=i∑(y
i−yi)
# SGD训练
A = np.random.normal(0,1)
b = 0
print("init A={0},b={1}".format(A, b)) # 生成初始的参数A和b
epoches=1000 # 设置训练迭代次数,总共迭代1000次,每次都进行loss计算
losses = [] # 设置losses列表记录每次迭代后loss的变化
batch_size = 10 # 设置批处理大小,每次从所有的数据点中随机出10个计算损失函数梯度
learning_rate = 0.001 # 设置学习率
for i in range(epoches):
rand_index = np.random.choice(len(x_vals), size=batch_size) # 随机生成10个点的索引
rand_x = x_vals[rand_index]
rand_y = y_vals[rand_index]
#forward 前驱函数
pred_y = A * rand_x + b # 按照当前的参数进行预测
loss = np.sum((pred_y - rand_y)*(pred_y - rand_y))/2 # 计算当前结果的损失
losses.append(loss) # 记录损失
dLdA = np.sum((pred_y - rand_y)*rand_x) # 计算参数A的梯度
dLdb = np.sum(pred_y - rand_y) # 计算参数b的梯度
A = A - learning_rate * dLdA
b = b - learning_rate * dLdb # 将参数A和b进行微调修改
print("final A={0}, b={1}".format(A,b)) # 输出训练以后的参数
训练结果如图
3 结果显示
# 结果显示plot the reasult
y_pred = A * x_vals + b
plt.plot(x_vals, y_vals, 'o', label='Data Points')
plt.plot(x_vals, y_reals, 'r-', label='Best fit line', linewidth=3)
plt.plot(x_vals, y_pred, 'b-', label='learning line', linewidth=3)
plt.legend(loc='upper left')
plt.title('Linear Regression')
plt.show() # 红线为真实线性分布,蓝线为预测出的线性分布
# Plot loss over time
plt.plot(losses, 'k-')
plt.title('L2 Loss per Generation')
plt.xlabel('Generation')
plt.ylabel('L2 Loss')
plt.show() # 查看所有轮次的loss值
展示结果如图。
4 完整代码
import numpy as np
import matplotlib.pyplot as plt
# %matplotlib inline
x_vals = np.linspace(0,10,100) # 生成100个在区间[1,10]的实数
print(x_vals) # 输出查看
realA = 2.5
realb = -5
y_reals = realA * x_vals + realb # 假设真实的y和x符合一维线性分布
y_vals = y_reals + np.random.normal(0, 1, 100) # 在y上加上随机的高斯噪声
# Plot the reasults,查看生成的训练数据
plt.plot(x_vals, y_vals, 'o', label='Data')
plt.plot(x_vals, y_vals, 'r-', label='Best fit line', linewidth=3)
plt.legend(loc='upper left')
plt.show()
# SGD训练
A = np.random.normal(0,1)
b = 0
print("init A={0},b={1}".format(A, b)) # 生成初始的参数A和b
epoches=1000 # 设置训练迭代次数,总共迭代1000次,每次都进行loss计算
losses = [] # 设置losses列表记录每次迭代后loss的变化
batch_size = 10 # 设置批处理大小,每次从所有的数据点中随机出10个计算损失函数梯度
learning_rate = 0.001 # 设置学习率
for i in range(epoches):
rand_index = np.random.choice(len(x_vals), size=batch_size) # 随机生成10个点的索引
rand_x = x_vals[rand_index]
rand_y = y_vals[rand_index]
#forward 前驱函数
pred_y = A * rand_x + b # 按照当前的参数进行预测
loss = np.sum((pred_y - rand_y)*(pred_y - rand_y))/2 # 计算当前结果的损失
losses.append(loss) # 记录损失
dLdA = np.sum((pred_y - rand_y)*rand_x) # 计算参数A的梯度
dLdb = np.sum(pred_y - rand_y) # 计算参数b的梯度
A = A - learning_rate * dLdA
b = b - learning_rate * dLdb # 将参数A和b进行微调修改
print("final A={0}, b={1}".format(A,b)) # 输出训练以后的参数
# 结果显示plot the reasult
y_pred = A * x_vals + b
plt.plot(x_vals, y_vals, 'o', label='Data Points')
plt.plot(x_vals, y_reals, 'r-', label='Best fit line', linewidth=3)
plt.plot(x_vals, y_pred, 'b-', label='learning line', linewidth=3)
plt.legend(loc='upper left')
plt.title('Linear Regression')
plt.show() # 红线为真实线性分布,蓝线为预测出的线性分布
# Plot loss over time
plt.plot(losses, 'k-')
plt.title('L2 Loss per Generation')
plt.xlabel('Generation')
plt.ylabel('L2 Loss')
plt.show() # 查看所有轮次的loss值