【问题标题】:Implementing Linear Regression using numpy使用 numpy 实现线性回归
【发布时间】:2023-10-03 05:49:01
【问题描述】:

我正在尝试学习线性方程 y = x1 + x2 + e,其中 e 是 0 到 0.5 之间的随机误差。 数据定义如下:

X1 = np.random.randint(1, 10000, 5000)
X2 = np.random.randint(1, 10000, 5000)
e = np.array([random.uniform(0, 0.5) for i in range(5000)])
y = X1 + X2 + e

当我实现一个简单的梯度下降来查找参数时,损失和梯度都在爆炸。我哪里错了?梯度下降的代码:

w1, w2, b = 1, 1, 0
n = X1.shape[0]
alpha = 0.01
for i in range(5):
    y_pred = w1 * X1 + w2 * X2 + b
    L = np.sum(np.square(y - y_pred))/(2 * n)
    dL_dw1 = (-1/n) * np.sum((y - y_pred) * X1)
    dL_dw2 = (-1/n) * np.sum((y - y_pred) * X2)
    dL_db = (-1/n) * np.sum((y - y_pred))
    w1 = w1 - alpha * dL_dw1
    w2 = w2 - alpha * dL_dw2
    b = b - alpha * dL_db
    print(L, w1, w2, b)

这个的输出是:

0.042928723015982384 ,  13.7023102434034 ,  13.670617201430483 ,  0.00254938447277222 

9291487188.8259 ,  -7353857.489486973 ,  -7293941.123714662 ,  -1261.9252592161051 

3.096713445664372e+21 ,  4247172241132.3584 ,  4209117175658.749 ,  728518135.2857293 

1.0320897597938595e+33 ,  -2.4520737800716524e+18 ,  -2.4298158059267333e+18 ,  -420579738783719.2 

3.4398058610314825e+44 ,  1.415615899689713e+24 ,  1.402742160404974e+24 ,  2.428043942370682e+20 

【问题讨论】:

    标签: python numpy machine-learning linear-regression


    【解决方案1】:

    您所缺少的只是数据规范化。对于基于梯度的学习算法,您必须确保数据是标准化的,即它具有 mean=0std=1

    让我们通过不断的错误来验证这一点(比如e=33)。

    X1 = np.random.randint(1, 10000, 5000)
    X2 = np.random.randint(1, 10000, 5000)
    e = 33
    
    # Normalize data
    X1 = (X1 - np.mean(X1))/np.std(X1)
    X2 = (X2 - np.mean(X2))/np.std(X2)
    
    y = X1 + X2 + e
    
    
    w1, w2, b = np.random.rand(), np.random.rand(), np.random.rand()
    
    n = X1.shape[0]
    alpha = 0.01
    for i in range(1000):
        y_pred = w1 * X1 + w2 * X2 + b
        L = np.sum(np.square(y - y_pred))/(2 * n)
        dL_dw1 = (-1/n) * np.sum((y - y_pred) * X1)
        dL_dw2 = (-1/n) * np.sum((y - y_pred) * X2)
        dL_db = (-1/n) * np.sum((y - y_pred))
        w1 = w1 - alpha * dL_dw1
        w2 = w2 - alpha * dL_dw2
        b = b - alpha * dL_db
        
        if (i)%100 == 0:
            print(L)
        
    print (w1, w2, b)
    

    输出:

    Loss: 517.7575710514508
    Loss: 69.36601211594098
    Loss: 9.29326322560041
    Loss: 1.2450619081931993
    Loss: 0.16680720657514425
    Loss: 0.022348057963833764
    Loss: 0.002994096883392299
    Loss: 0.0004011372165515275
    Loss: 5.374289796164062e-05
    Loss: 7.2002934167549005e-06
    0.9999609731610163 0.9999911458582055 32.99861157362915
    

    如您所见,它确实收敛了。

    除了您必须对数据进行规范化之外,您的代码没有任何问题。

    现在您可以弥补错误并找到最佳估计值。

    【讨论】:

    • 谢谢。我尝试了标准化,它奏效了。但我实际上使用 sklearn 的默认 LinearRegression 模型做了同样的问题,它能够在没有标准化的情况下处理同样的问题。我以为我错过了什么。这里 normalize 的默认参数是 False,它解决了这个问题而没有明确提到 True。见 [scikit-learn.org/stable/modules/generated/…。我想知道它如何能够在没有标准化的情况下解决这个问题。有什么想法吗?
    • @dudefrmbgr sklearn LR 模型不使用梯度体面进行学习,而是使用函数形式的优化。
    • 知道了..谢谢
    【解决方案2】:

    好的,问题表述有一些问题

    1. 缩放:梯度下降通常需要很好地缩放变量,以确保可以正确设置 alpha。在大多数情况下,一切都是相对的,您始终可以将问题乘以固定常数。但是,由于权重是由 alpha 值直接操作的,因此很难达到非常高或非常低的权重值,我特此将您的机制缩小约 10000,并减少随机误差以进行缩放
    import numpy as np
    import random
    X1 = np.random.random(5000)
    X2 = np.random.random(5000)
    e = np.array([random.uniform(0, 0.0005) for i in range(5000)])
    y = X1 + X2 + e
    
    1. y_pred 对 b 的依赖:B 的值我不确定它应该做什么以及为什么要明确地向y_pred 引入错误。您的预测应该假设没有错误:D

    2. 如果 X 和 Ys 缩放良好,使用超参数进行几次尝试会产生良好的值

    for i in range(5):
        y_pred = w1 * X1 + w2 * X2
        L = np.sum(np.square(y - y_pred))/(2 * n)
        dL_dw1 = -(1/n) * np.sum((y - y_pred) * X1)
        dL_dw2 = -(1/n) * np.sum((y - y_pred) * X2)
        dL_db = -(1/n) * np.sum((y - y_pred))
        w1 = w1 - alpha * dL_dw1
        w2 = w2 - alpha * dL_dw2
        print(L, w1, w2)
        
    

    您可以使用这些值,但它们会收敛

    w1, w2, b = 1.1, 0.9, 0.01
    alpha = 1
    0.0008532534726479387 1.0911950693892498 0.9082610891021278
    0.0007137567968828647 1.0833134985852988 0.9159869797801239
    0.0005971536415151483 1.0761750602775175 0.9231234590515701
    0.0004996145120126794 1.0696746682185534 0.9296797694772246
    0.0004180103133293466 1.0637407602096771 0.9356885401106588
    

    【讨论】:

    • 谢谢。我不确定第 2 点。在这种情况下,仅出于学习目的,我根据自己的意愿设置了函数,我认为即使我建模了一个附加参数,它也应该自动学习使其为零。另外,我对 Sklearns 默认模型“sklearn.linear_model.LinearRegression”进行了同样的尝试,它在不考虑标准化的情况下解决了这个问题。我想知道它如何能够在不根据此链接将参数 normalize 显式设置为 True 的情况下处理此问题。 [scikit-learn.org/stable/modules/generated/….
    • @dudefrmbgr 我认为 Sklearn 是一个最小二乘封闭形式表达式求解器(它不使用 SGD)kaggle.com/general/22793。另请注意,您引用的 sklearn 回归方法还提供了归一化参数。
    最近更新 更多