代码所用数据:代码中x代表Ones(x0)和Population(x1),yi代表Profits(利润)
代码实现
# SGD(随机梯度下降法)
import numpy as np
np.seterr(divide='ignore', invalid='ignore')
class SGD:
def __init__(self, learning_rate, w):
self.lr = learning_rate # 学习率
self.w = np.array(w) # 权重
@staticmethod
def training_data(train_data): # train_data:包括特征值和真实值
cols = train_data.shape[1]
xt, yi = train_data[:, 0:cols - 1], train_data[:, cols - 1:cols]
return [xt, yi, train_data]
def linear_func(self, x):
y_pre = []
for i in range(len(x)):
y = np.dot(self.w, x[i]) # 线性单元
y_pre.append(y)
print(f'这是进行随机梯度下降前的线性模型得到的预测值: {y_pre}')
def loss_func(self, x, yi):
diff_sqrs = [] # 存储预测值与真实值差的平方
for i in range(len(x)):
diff_sqr = (np.dot(self.w, x[i]) - yi[i]) ** 2
diff_sqrs.append(diff_sqr)
Loss = (1 / (2 * len(yi))) * np.sum(diff_sqrs)
Loss_aver = Loss / len(yi)
print(f'这是进行随机梯度下降前的线性模型的平均损失值: {Loss_aver}')
# @staticmethod
# def getRandomIndex(n, x):
# index = np.random.choice(np.arange(n), size=x, replace=False)
# return index
def sgd(self, train_data, epoch):
count = 1
while count < epoch:
np.random.shuffle(train_data) # 将train_data乱序
tda = SGD.training_data(train_data)
x, yi = tda[0], tda[1]
for i in range(len(x)):
self.lr = self.lr / count # 更新学习率
self.w -= self.lr * (np.dot(self.w, x[i]) - yi[i]) * x[i]
for j in range(len(x[0])):
if 0 <= ((np.dot(self.w, x[i]) - yi[i]) * x[i])[j] <= 0.1:
break
count += 1
return self.w
@staticmethod
def test(w, x, yi):
diff_sqrs, y_test = [], []
for i in range(len(x)):
y = np.dot(w, x[i])
diff_sqr = (y - yi[i]) ** 2
y_test.append(y)
diff_sqrs.append(diff_sqr)
Loss = (1 / (2 * len(yi))) * np.sum(diff_sqrs)
Loss_aver = Loss / len(yi)
print(f'这是进行随机梯度下降后的线性模型得到的预测值: {y_test},\n'
f'这是进行随机梯度下降后的线性模型的平均损失值: {Loss_aver},\n'
f'这是进行随机梯度下降后的线性模型的权重: {w}')
if __name__ == '__main__':
SGD = SGD(0.03, np.array([1, 0.5]))
td = SGD.training_data(np.array([[1, 6.1101, 17.5920], [1, 5.5277, 9.1302], [1, 8.5186, 13.6620],
[1, 7.0032, 11.8540], [1, 5.8598, 6.8233]]))
SGD.linear_func(td[0])
SGD.loss_func(td[0], td[1])
W = SGD.sgd(td[2], 2000000)
SGD.test(W, td[0], td[1])
运行结果
这是进行随机梯度下降前的线性模型得到的预测值: [4.05505, 3.76385, 5.2593, 4.5016, 3.9299]
这是进行随机梯度下降前的线性模型的平均损失值: 6.9016328847
这是进行随机梯度下降后的线性模型得到的预测值: [9.908140274362793, 14.57381770427882, 10.426202220424216, 12.209857833572762, 10.816659628130253],
这是进行随机梯度下降后的线性模型的平均损失值: 1.208987579173057,
这是进行随机梯度下降后的线性模型的权重: [1.2851622 1.55995768]
总结
我虽然在大二时在大三学长的影响下就接触了机器学习和深度学习,但实际的学习和编程到了大三才真正开始。在任老师的亲身传授下,我相继完成了感知器和随机梯度下降算法的学习和编程。(感兴趣的小伙伴可以进入我的主页浏览感知机(代码实现)和线性单元与随机梯度下降算法。本人编程能力有限,代码可能有逻辑上的错误或者不够简洁,烦请各路大神给小生指点一二,在评论区留个言,本人将不胜感激)感知器的编程相对比较简单,但随机梯度下降算法的编程让我犯了难。首先是对于随机的理解上,一开始在对权重w进行梯度下降时,梯度我采用了求和的形式。我后来在查阅了一些资料并结合老师的讲解才逐渐的明白了“随机”的含义。依照我个人的理解,整个的随机梯度下降法的实现流程是这样的:
(1)首先初始化一个训练次数epoch用于循环以及缩小学习率。
(2)将训练数据(包含输入和输出)打乱顺序放在循环之中,每一次循环,训练数据的顺序都会被重新打乱。
(3)将打乱的训练数据分成输入和输出。
(4)进行梯度下降,每一次更新权重w时只使用一个训练数据的梯度,而不是采用梯度和的形式
代码如下
count = 1
while count < epoch:
np.random.shuffle(train_data) # 将train_data乱序
tda = SGD.training_data(train_data)
x, yi = tda[0], tda[1]
for i in range(len(x)):
self.lr = self.lr / count # 更新学习率
self.w -= self.lr * (np.dot(self.w, x[i]) - yi[i]) * x[i]
for j in range(len(x[0])):
if 0 <= ((np.dot(self.w, x[i]) - yi[i]) * x[i])[j] <= 0.1:
break
count += 1