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}]')
其他注意事项
- 学习率选择:学习率不能太大,否则会导致参数发散(比如你之前出现MSE突然上升的情况)。对于你的数据,
0.0001是合适的初始值,也可根据MSE变化动态调整。 - 特征归一化:原代码中用到了
x_scale但未做特征归一化,会导致不同参数的更新步长不均衡。可先把$x^3$归一化到[-1,1]区间,让学习率对两个参数更友好。 - 停止条件:原代码MSE>10的阈值太高,建议降到0.01左右,确保收敛到足够接近真实值的参数。
修复后运行,参数会逐步收敛到a≈1.39,b≈4.43,MSE也会持续下降到接近0。
内容的提问来源于stack exchange,提问作者EarthIsHome
相关产品推荐
相关产品推荐

