还记得刚开始看吴恩达老师的机器学习课程的时候,经常看不懂的就是梯度下降,随机梯度下降和批量梯度下降的区别老是看不明白。迷迷糊糊的,说不清楚吧,还知道大概是什么个意思;说清楚吧,具体怎么个计算细节也不了解。
今天以 y = 3 x + ϵ y = 3x +\epsilon y=3x+ϵ 曲线的回归作为数据集,这里 ϵ \epsilon ϵ 表示一个较小的误差。
数据集构造
数据集根据 y = 3 x y=3x y=3x 构造,并加一定的随机数构造出数据集
## 使用jupyter notebook完成
LEN = 50
X = np.arange(0, LEN)
# rand从-5到+5
np.random.seed(1)
rand = (np.random.random(LEN) * 2 - 1) * 5
Y = X * 3 + rand
# X、Y分布如下图所示
plt.scatter(X, Y)
# X、Y 连接
X = X.reshape(LEN, 1)
Y = Y.reshape(LEN, 1)
allData = np.concatenate((X, Y), axis = 1)
划分训练集、测试机
np.random.shuffle(allData)
# 训练集:测试机 = 4:1
ratio = 0.8
index = (int)(allData.shape[0] * ratio)
trainData = allData[:index]
testData = allData[index:]
算法实现
超参数设置
# 超参数设置
# 学习率
lr = 0.0005
# 训练集大小(每个batch随机梯度下降迭代次数)
N = trainData.shape[0]
# 误差大小
epsilon = 200
模型训练
# 待估及参数(theta)
theta = np.random.rand()
# 迭代次数标识
iter = 1
# 参数记录列表,包括loss、迭代次数以及theta
loss_list = []
iter_list = []
theta_list = []
loss = np.inf
while True:
# 打乱训练集词序
np.random.shuffle(trainData)
for i in range(N):
# 随机样本
x = trainData[i, 0]
y = trainData[i, 1]
# 计算梯度
grad = (theta * x - y) * x
# 更新参数
theta = theta - lr * grad
# print("x: %.2f\t\t y:%.2f\t\t\tgrad: %.4f\t\t\ttheta: %.4f" % (x, y, grad, theta))
# 一个batch结束后,对所有测试样本进行loss求和
loss = np.sum(0.5 * (trainData[:, 0] * theta - trainData[:, 1]) ** 2)
theta_list.append(theta)
loss_list.append(loss)
iter_list.append(iter)
print("No.%d:\t grad = %f\t theta: %f\tloss: %f" %(iter, grad, theta, loss))
iter += 1
# 达到允许的误差,结束训练
if loss < epsilon:
print("Traing Completed!")
break
训练结果
迭代参数变化
结果展示
结果分析
可以看到由于随机梯度下降每次在参数的迭代过程中参考的只有一个样本,样本的分布不均匀就会导致参数收敛较慢,虽然这样可以避免陷入局部极小值,但是在调参的过程中,学习率lr(learning rate)稍微调大一点,theta就会变得无穷大,导致学习过程无法收敛的结果。