纯纯python实现梯度下降、随机梯度下降

最近面试有要求手撕SGD,这里顺便就把梯度下降、随机梯度下降、批次梯度下降给写出来了

有几个注意点:

1.求梯度时注意labeli和predi不要搞反,否则会导致模型发散

2.如果跑了几千个epoch,还是没有收敛,可能是学习率太小了

python 复制代码
# X:n*k
# Y: n*1

import random
import numpy

class GD:
    def __init__(self,w_dim,r):
        # 随机初始化
        self.w = [random.random() for _ in range(w_dim)]
        self.bias = random.random()
        self.learningRate = r
        print(f"original w is {self.w}, original bias is {self.bias}")
        

    def forward(self,x):
        # 前馈网络
        ans = []
        for i in range(len(x)):
            y=0
            for j in range(len(x[0])):
                y+=self.w[j]*x[i][j]
            ans.append(y+self.bias)
        return ans

    def bp(self,X,pred,label,op="GD"):
        # 计算均方差
        loss = 0
        for i in range(len(pred)):
            loss+=(label[i]-pred[i])**2
        loss = loss/len(X)
            
        
        # 计算梯度
        # 梯度下降
        if op=="GD":
            grad_w = [0 for _ in range(len(self.w))]
            grad_bias=0
            for i in range(len(X)):
                grad_bias+=-2*(label[i]-pred[i])
                for j in range(len(self.w)):
                    grad_w[j]+=-2*(label[i]-pred[i])*X[i][j]  
            # 反向传播,更新梯度
            self.bias=self.bias-self.learningRate*grad_bias/len(X)
            for i in range(len(self.w)):
                self.w[i]-=self.learningRate*grad_w[i]/len(X)
        
        # 随机梯度下降
        if op=="SGD":
            grad_w = [0 for _ in range(len(self.w))]
            grad_bias=0
            randInd = random.randint(0,len(X)-1)
            grad_bias+=-2*(label[randInd]-pred[randInd])
            for j in range(len(self.w)):
                grad_w[j]+=-2*(label[randInd]-pred[randInd])*X[randInd][j]  
            # 反向传播,更新梯度
            self.bias=self.bias-self.learningRate*grad_bias
            for i in range(len(self.w)):
                self.w[i]-=self.learningRate*grad_w[i]
        
        # 批次梯度下降
        if op=="BGD":        
            grad_w = [0 for _ in range(len(self.w))]
            grad_bias=0
            BS=8
            randInd = random.randint(0,len(X)/BS-1)
            X = X[BS*randInd:BS*(randInd+1)]
            label = label[BS*randInd:BS*(randInd+1)]
            pred = pred[BS*randInd:BS*(randInd+1)]
            
            for i in range(len(X)):
                grad_bias+=-2*(label[i]-pred[i])
                for j in range(len(self.w)):
                    grad_w[j]+=-2*(label[i]-pred[i])*X[i][j]  
            # 反向传播,更新梯度
            self.bias=self.bias-self.learningRate*grad_bias/len(X)
            for i in range(len(self.w)):
                self.w[i]-=self.learningRate*grad_w[i]/len(X)

        return loss




def testY(X,w):

    Y = []
    for x in X:
        y=0
        for i in range(len(x)):
            y+=w[i]*x[i]
        Y.append(y)
    return Y

# 构建数据
n = 1000
X=[[random.random() for _ in range(2)] for _ in range(n)]
w=[0.2,0.3]
B=0.4
Y = testY(X,w)

# 设置样本维度为2
k = 2
lr = GD(k,0.01)
Loss=0
epochs=2000

for e in range(epochs):
    Loss = 0
    pred = lr.forward(X)
    loss=lr.bp(X,pred,Y,"BGD")
    Loss+=loss 
       
    if (e%100)==0:       
        print(f"step:{e},Loss:{Loss}") 
    
    
X_test=[[random.random() for _ in range(2)] for _ in range(2)]
Y_test=testY(X_test,w)

print("X_test=",X_test)
print("Y_test=",Y_test)
print("Y_pred=",lr.forward(X_test))

测试效果如下:

也还行

相关推荐
老歌老听老掉牙2 小时前
空间曲线数据的拼接与几何变换分析
python·曲线
Cc.Y2 小时前
Java零基础入门:字符串深度掌握——从基础API到StringBuilder性能优化
java·开发语言·性能优化
databook6 小时前
使用 SciPy 库进行时间序列分析
python·数据分析·scipy
阿明66 小时前
小白入门机器学习基础【AI】
人工智能·机器学习
java资料站6 小时前
十一、评估测试
开发语言·人工智能·python
szial6 小时前
网络爬虫与 CDP 实战(二):浏览器能访问,Python 却被拒绝?拆开登录态与 CSRF
爬虫·python·csrf
左手の明天6 小时前
SLIP 协议封装与解析详解:原理、C 代码与实战案例
linux·c语言·开发语言·c++
海上小飞龙7 小时前
【KMP算法-下篇】同一道题:Java 库函数 2600 微秒,手写 KMP 16 微秒
java·开发语言·算法
青少儿编程课堂7 小时前
后缀自动机解析:本质不同子串与最长重复片段统计
c++·python·算法·bfs·信息学竞赛
朝朝辞暮i7 小时前
C++ 第 12 课:局部变量、作用域、变量生命周期
开发语言·c++·算法