• 仅使用python标准库(不使用numpy)写一个小批量梯度下降的线性回归算法


    看到一个有意思的题目:仅使用python的标准库,完成一个小批量梯度下降的线性回归算法

    平常使用numpy这样的计算库习惯了,只允许使用标准库还有点不习惯,下面就使用这个过程来写一个。

    import random
    from typing import List
    
    
    # 生成测试数据
    def generate_data(num_samples: int, weights: List[float], bias: float, noise=0.1) -> (List[List[float]], List[float]):
        X = [[random.uniform(-10, 10) for _ in range(len(weights))] for _ in range(num_samples)]
        y = [sum(w * x for w, x in zip(weights, x_i)) + bias + random.uniform(-noise, noise) for x_i in X]
        return X, y
    
    # 计算损失
    def mse(y_true: List[float], y_pred: List[float]):
        return 0.5 * sum((yt - yp) for yt, yp in zip(y_true, y_pred)) ** 2
    
    # 将矩阵转置
    def transpose(mat: List[List[float]]):
        row, col = len(mat), len(mat[0])
        # 固定列,访问行
        result = [
            [mat[r][c] for r in range(row)] for c in range(col)
        ]
        return result
    
    # 计算矩阵乘法
    def matmul(mat: List[List[float]], vec: List[float]):
        return [sum(r * c for r, c in zip(row, vec)) for row in mat]
    
    # 计算梯度
    def compute_grad(y_true_batch: List[float], y_pred_batch: List[float], x_batch: List[List[float]]):
        batch_size = len(y_true_batch)
        residual = [yt - yp for yt, yp in zip(y_true_batch, y_pred_batch)]
        # 根据 y = x @ w + b
        # grad_w = -x.T @ residual
        grad_w = matmul(transpose(x_batch), residual)
        grad_w = [-gw / batch_size for gw in grad_w]
        grad_b = -sum(residual) / batch_size
        
        # grad_w: List[float]
        # grad_b: float
        return grad_w, grad_b
    
    # 开启训练
    def train():
        lr = 0.01
        epochs = 50
        batch_size = 16
        dim_feat = 3
        num_samples = 500
        
        weights = [random.random() * 0.1 for _ in range(dim_feat)]
        bias = random.random() * 0.1
        
        print('original params')
        print('w:', weights)
        print('b:', bias)
        
        X, y = generate_data(num_samples, weights, bias, noise=0.1)
        
        for epoch in range(epochs):
            for i in range(0, num_samples, batch_size):
                x_batch = X[i:i+batch_size]
                y_batch = y[i:i+batch_size]
                
                y_pred = [item + bias for item in matmul(x_batch, weights)]
                
                loss = mse(y_batch, y_pred)
                
                grad_w, grad_b = compute_grad(y_batch, y_pred, x_batch)
                
                weights = [w - lr * gw for w, gw in zip(weights, grad_w)]
                bias -= lr * grad_b
                
            print(f'Epoch: {epoch + 1}, Loss = {loss:.3f}')
            
    
        print('trained params')
        print('w:', weights)
        print('b:', bias)
        
    train()
    '
    运行

    输出结果如下

    original params
    w: [0.04845598598148951, 0.007741816562531545, 0.02436678108587098]
    b: 0.01644073086522535
    Epoch: 1, Loss = 0.000
    Epoch: 2, Loss = 0.000
    Epoch: 3, Loss = 0.000
    Epoch: 4, Loss = 0.000
    Epoch: 5, Loss = 0.000
    Epoch: 6, Loss = 0.000
    Epoch: 7, Loss = 0.000
    Epoch: 8, Loss = 0.000
    Epoch: 9, Loss = 0.000
    Epoch: 10, Loss = 0.000
    Epoch: 11, Loss = 0.000
    Epoch: 12, Loss = 0.000
    Epoch: 13, Loss = 0.000
    Epoch: 14, Loss = 0.000
    Epoch: 15, Loss = 0.000
    Epoch: 16, Loss = 0.000
    Epoch: 17, Loss = 0.000
    Epoch: 18, Loss = 0.000
    Epoch: 19, Loss = 0.000
    Epoch: 20, Loss = 0.000
    Epoch: 21, Loss = 0.000
    Epoch: 22, Loss = 0.000
    Epoch: 23, Loss = 0.000
    Epoch: 24, Loss = 0.000
    Epoch: 25, Loss = 0.000
    Epoch: 26, Loss = 0.000
    Epoch: 27, Loss = 0.000
    Epoch: 28, Loss = 0.000
    Epoch: 29, Loss = 0.000
    Epoch: 30, Loss = 0.000
    Epoch: 31, Loss = 0.000
    Epoch: 32, Loss = 0.000
    Epoch: 33, Loss = 0.000
    Epoch: 34, Loss = 0.000
    Epoch: 35, Loss = 0.000
    Epoch: 36, Loss = 0.000
    Epoch: 37, Loss = 0.000
    Epoch: 38, Loss = 0.000
    Epoch: 39, Loss = 0.000
    Epoch: 40, Loss = 0.000
    Epoch: 41, Loss = 0.000
    Epoch: 42, Loss = 0.000
    Epoch: 43, Loss = 0.000
    Epoch: 44, Loss = 0.000
    Epoch: 45, Loss = 0.000
    Epoch: 46, Loss = 0.000
    Epoch: 47, Loss = 0.000
    Epoch: 48, Loss = 0.000
    Epoch: 49, Loss = 0.000
    Epoch: 50, Loss = 0.000
    trained params
    w: [0.05073234817652038, 0.007306286342947243, 0.023218625946243507]
    b: 0.016648404245261664
    

    可以看到,结果还是不错的

  • 相关阅读:
    Spring入门须知
    什么是异常规格(Exception Specification)
    HTX 与 Zebec Protocol 展开深度合作,并将以质押者的身份参与 ZBC Staking
    “羊了个羊”是如何吸引住你的
    初始Linux(2):Shell、文件权限
    用Spring Cloud Alibaba构建用户中心!只要5分钟
    vue中babel-plugin-component按需引入和element-ui 的主题定制,支持发布,上线
    Python量化交易实战:获取股票数据并做分析处理
    Java集合+泛型:练习
    Linux(Ubuntu)用户与用户组(入门必看)
  • 原文地址:https://blog.csdn.net/weixin_43589323/article/details/139483544