You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python实现最小均方(LMS)自适应滤波器参数更新问题求助

实现LMS自适应滤波器时变量更新错误,求问题所在

我正尝试在Python中实现类似Scipy库least_squares的最小均方(LMS)自适应滤波器,遵循维基百科定义的LMS算法,但无法正确更新独立变量,请问我的实现中缺失了什么?

代码:

import numpy as np
from scipy.optimize import least_squares

def desiredFunc(x):
    """期望响应"""
    aa0 = 1.39
    bb0 = 4.43
    return aa0*np.power(x,3) + bb0

def myFunc(x, a0, b0):
    return a0*np.power(x,3) + b0

def myMinFunc(a0, b0, x):
    """最小化函数"""
    return desiredFunc(x) - myFunc(x, a0, b0)

def mse(errors):
    """均方误差"""
    return sum(np.square(errors))/len(errors)

if __name__ == '__main__':
    a0_bounds = [-3, 3] # [下界, 上界]
    b0_bounds = [-5, 5] # [下界, 上界]
    a0_scale = 10
    b0_scale = 10

    x0 = [0, 0] # 自变量初始猜测值
    # scipy实现的边界
    #bounds = ([a0_bounds[0], b0_bounds[0]], [a0_bounds[1], b0_bounds[1]])
    f = np.arange(-10, 11)

    ########################
    #### scipy least_squares
    ########################
    #ans = least_squares(lambda param: myMinFunc(param[0], param[1], f), x0, bounds=bounds, x_scale=[a0_scale, b0_scale], verbose = 2)
    #print(ans.x)

    ########################
    #### 自定义实现
    ########################
    # 自定义实现的边界
    bounds = [a0_bounds, b0_bounds]

    # 初始误差数组
    errors = myMinFunc(x0[0], x0[1], f)
    print(f'MSE: {mse(errors):.2f}\t(Sum of err)/N: {sum(errors)/len(errors):.2f}\t自变量: [{x0[0]:.2f},{x0[1]:.2f}]')

    while mse(errors) > 10:
        # 调整自变量
        for i, param in enumerate(x0):

            x0[i] =  x0[i] + 1/len(errors)/a0_scale*sum(errors) # 维基百科中的无偏估计量

            # 检查是否违反边界:
            if x0[i] > bounds[i][1]:
                x0[i] = bounds[i][1]
            if x0[i] < bounds[i][0]:
                x0[i] = bounds[i][0]

        # 测量系统误差
        errors = myMinFunc(x0[0], x0[1], f)
        print(f'MSE: {mse(errors):.2f}\t(Sum of err)/N: {sum(errors)/len(errors):.2f}\t自变量: [{x0[0]:.2f},{x0[1]:.2f}]')
        input('按回车继续...')

输出:

$ python3 least-squares-implementation.py 
MSE: 364064.99  (Sum of err)/N: 4.43    自变量: [0.00,0.00]
MSE: 168992.22  (Sum of err)/N: 3.99    自变量: [0.44,0.44]
按回车继续...
MSE: 56657.98   (Sum of err)/N: 3.59    自变量: [0.84,0.84]
按回车继续...
MSE: 6774.48    (Sum of err)/N: 3.23    自变量: [1.20,1.20]
按回车继续...
MSE: 3365.35    (Sum of err)/N: 2.91    自变量: [1.52,1.52]
按回车继续...
MSE: 33900.81   (Sum of err)/N: 2.62    自变量: [1.81,1.81]
按回车继续...

问题分析与修复

你的核心问题是LMS权重更新公式完全错误,没有针对每个参数的偏导项,导致两个参数被用完全相同的方式更新,最终无法收敛到正确值(a=1.39,b=4.43)。

错误点详解

你当前的更新代码只是简单用误差均值乘以固定系数更新所有参数,完全不符合LMS算法的核心逻辑。LMS的更新规则是每个参数沿着误差对该参数的负梯度方向更新,公式为:
$$ w_{k+1} = w_k + \mu \cdot e_k \cdot x_k $$
其中$\mu$是学习率,$e_k$是当前误差,$x_k$是对应参数的输入特征。

对于你的模型$y = a \cdot x^3 + b$:

  • 参数a对应的输入特征是$x^3$(每个样本的三次方值)
  • 参数b对应的输入特征是1(常数项的特征为1)

修复后的代码修改

把参数更新部分替换为:

# 预计算特征:第一列是x^3,第二列是全1
learning_rate = 0.0001  # 学习率需适中,避免发散

while mse(errors) > 0.01:
    # 计算每个参数的梯度更新量
    grad_a = np.sum(errors * np.power(f, 3)) / len(errors)
    grad_b = np.sum(errors * 1) / len(errors)
    
    # 更新参数
    x0[0] += learning_rate * grad_a
    x0[1] += learning_rate * grad_b
    
    # 边界检查(用numpy的clip更简洁)
    x0[0] = np.clip(x0[0], bounds[0][0], bounds[0][1])
    x0[1] = np.clip(x0[1], bounds[1][0], bounds[1][1])
    
    # 更新误差
    errors = myMinFunc(x0[0], x0[1], f)
    print(f'MSE: {mse(errors):.4f}\t自变量: [{x0[0]:.4f},{x0[1]:.4f}]')

其他注意事项

  1. 学习率选择:学习率不能太大,否则会导致参数发散(比如你之前出现MSE突然上升的情况)。对于你的数据,0.0001是合适的初始值,也可根据MSE变化动态调整。
  2. 特征归一化:原代码中用到了x_scale但未做特征归一化,会导致不同参数的更新步长不均衡。可先把$x^3$归一化到[-1,1]区间,让学习率对两个参数更友好。
  3. 停止条件:原代码MSE>10的阈值太高,建议降到0.01左右,确保收敛到足够接近真实值的参数。

修复后运行,参数会逐步收敛到a≈1.39,b≈4.43,MSE也会持续下降到接近0。


内容的提问来源于stack exchange,提问作者EarthIsHome

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 06:10:25