本文目录导读:

Python脚本在数据自适应控制中的在线学习通常需要结合增量学习、在线优化或强化学习的方法,以便在数据流中持续更新模型,无需从头开始训练。
以下是几种常见的实现思路和代码示例,涵盖从简单的统计自适应到基于神经网络的在线学习。
核心思想:在线学习 vs 批量学习
- 批量学习:一次性使用全部数据训练模型,模型固定后不再变化。
- 在线学习:数据逐个或小批量到达,模型每处理一个样本或一小批后立即更新,模型能够适应数据分布的变化(概念漂移)。
常用算法与Python实现
1 简单的统计自适应(滑动窗口 + 均值/方差)
适用于数据平稳但受环境噪声影响的场景(如传感器校准、简单PID参数的自动调整)。
思路:维护一个固定大小的滑动窗口,只使用最近N个数据点来计算统计量(均值、方差、中位数),并据此自适应调整控制参数。
import numpy as np
from collections import deque
class SlidingWindowAdaptiveFilter:
"""滑动窗口自适应滤波器,用于在线估计信号均值和方差"""
def __init__(self, window_size=100):
self.window = deque(maxlen=window_size)
self.window_size = window_size
self.mean = 0.0
self.var = 0.0
def update(self, new_data_point):
"""
在线更新滑动窗口并重新计算均值和方差
Args:
new_data_point: 新到达的数据点(标量)
Returns:
current_mean, current_std: 更新后的均值和标准差
"""
self.window.append(new_data_point)
if len(self.window) > 0:
self.mean = np.mean(self.window)
self.var = np.var(self.window)
return self.mean, np.sqrt(self.var)
# 示例:模拟传感器数据,存在缓慢漂移
if __name__ == "__main__":
adaptive_filter = SlidingWindowAdaptiveFilter(window_size=50)
true_value = 100.0
drift = 0.01
for t in range(500):
# 模拟带漂移和噪声的数据
measurement = true_value + drift * t + np.random.normal(0, 2)
current_mean, current_std = adaptive_filter.update(measurement)
if t % 50 == 0:
print(f"Time {t}: Raw Value={measurement:.2f}, Estimated Mean={current_mean:.2f}, Std={current_std:.2f}")
# 控制逻辑:使用估计的均值作为基准值进行控制
2 在线线性回归(梯度下降法)
适用于需要在线学习输入输出映射关系的场景(如自适应前馈控制)。
思路:使用随机梯度下降(SGD)或小批量梯度下降,每来一个样本,计算损失梯度,并更新模型参数。
import numpy as np
class OnlineLinearRegression:
"""在线线性回归,使用梯度下降持续更新权重"""
def __init__(self, feature_dim=1, learning_rate=0.01):
self.w = np.random.randn(feature_dim) * 0.01
self.b = 0.0
self.lr = learning_rate
def predict(self, x):
"""预测"""
return np.dot(x, self.w) + self.b
def partial_fit(self, x, y):
"""
在线学习:使用单个样本更新模型
Args:
x: 特征向量 (numpy array)
y: 目标值 (标量)
"""
# 预测
y_pred = self.predict(x)
# 误差
error = y_pred - y
# 计算梯度
grad_w = 2 * error * x
grad_b = 2 * error
# 更新参数
self.w -= self.lr * grad_w
self.b -= self.lr * grad_b
return self.w, self.b
# 示例:在线学习一个简单的线性关系 y = 2*x1 + 3*x2 + 1
if __name__ == "__main__":
model = OnlineLinearRegression(feature_dim=2, learning_rate=0.001)
true_w = np.array([2.0, 3.0])
true_b = 1.0
for t in range(1000):
# 生成随机输入
x = np.random.randn(2)
# 生成目标值(可能有轻微噪声)
y = np.dot(x, true_w) + true_b + np.random.normal(0, 0.1)
# 在线更新模型
w, b = model.partial_fit(x, y)
if t % 100 == 0:
mse = np.mean((model.predict(x) - y)**2)
print(f"Step {t}: w={model.w}, b={model.b:.3f}, loss={mse:.6f}")
print(f"Final weights: {model.w}")
print(f"True weights: {true_w}")
3 基于树的增量学习(River库)
适用于分类、回归和异常检测,且对数据分布变化(概念漂移)鲁棒。
推荐使用专门的库 River(pip install river),它提供了丰富的在线学习算法。
# 首先安装:pip install river
from river import linear_model
from river import optim
from river import preprocessing
# 构建在线学习流水线
model = (
preprocessing.StandardScaler() | # 在线标准化
linear_model.LinearRegression(
optimizer=optim.SGD(0.01), # 随机梯度下降
loss='squared'
)
)
# 模拟在线数据流
import numpy as np
true_w = np.array([2.0, 3.0])
true_b = 1.0
for t in range(1000):
x = {'feat0': np.random.randn(), 'feat1': np.random.randn()}
y = 2.0 * x['feat0'] + 3.0 * x['feat1'] + 1.0 + np.random.normal(0, 0.1)
# 在线学习(先预测,后更新)
y_pred = model.predict_one(x) # 预测
model.learn_one(x, y) # 学习
if t % 200 == 0:
print(f"Step {t}: prediction={y_pred:.3f}, true={y:.3f}")
# 查看最终模型参数
print(f"Weight: {model['LinearRegression'].weights}")
4 基于轻量级神经网络的在线学习(PyTorch)
适用于复杂非线性关系的自适应控制,但需要严格控制计算量,避免频繁全量回传。
思路:使用小型网络 + 单步或小批量更新 + 学习率衰减。
import torch
import torch.nn as nn
import torch.optim as optim
class TinyNet(nn.Module):
"""小型全连接网络,用于在线学习"""
def __init__(self, input_size=2, hidden_size=10):
super().__init__()
self.fc = nn.Sequential(
nn.Linear(input_size, hidden_size),
nn.ReLU(),
nn.Linear(hidden_size, 1)
)
def forward(self, x):
return self.fc(x)
class OnlineNeuralController:
"""在线神经网络控制器"""
def __init__(self, input_dim=2, lr=0.01):
self.model = TinyNet(input_dim)
self.optimizer = optim.SGD(self.model.parameters(), lr=lr)
self.loss_fn = nn.MSELoss()
def update(self, x, y_actual):
"""
使用单个样本进行在线更新
Args:
x: 输入特征 (list or array)
y_actual: 期望输出
"""
self.model.train()
x_tensor = torch.FloatTensor(x).unsqueeze(0) # shape (1, input_dim)
y_tensor = torch.FloatTensor([y_actual])
# 前向传播
y_pred = self.model(x_tensor)
loss = self.loss_fn(y_pred, y_tensor)
# 反向传播并更新参数
self.optimizer.zero_grad()
loss.backward()
self.optimizer.step()
return loss.item()
# 模拟使用
if __name__ == "__main__":
controller = OnlineNeuralController(input_dim=2, lr=0.001)
true_w = torch.tensor([2.0, 3.0])
true_b = 1.0
for t in range(500):
x = torch.randn(2)
y = (true_w * x).sum() + true_b + torch.randn(1).item() * 0.1
loss = controller.update(x.tolist(), y)
if t % 100 == 0:
print(f"Step {t}: Loss = {loss:.6f}")
自适应控制与在线学习的结合策略
在实际控制系统中,在线学习的应用通常需要与控制器结构结合:
| 控制策略 | 在线学习方式 | 典型应用 |
|---|---|---|
| 模型参考自适应 | 在线估计被控对象模型参数(如用递推最小二乘法),然后调整控制器参数。 | 电机控制、飞行器控制 |
| 自整定PID | 在线学习工艺过程的增益、时间常数等,更新PID参数。 | 工业过程控制 |
| 前馈+反馈自适应 | 在线学习前馈模型(如神经网络),补偿已知扰动;反馈用于消除残余误差。 | 机器人轨迹跟踪 |
| 强化学习(策略梯度) | 通过不断试错,在线更新策略网络(Actor)和价值网络(Critic)。 | 复杂的非线性系统控制 |
关键注意事项
- 概念漂移检测:数据分布可能突然或逐渐变化,可以使用 ADWIN(自适应滑动窗口)等算法检测并重置模型。
- 计算延迟:在线更新的计算必须在采样周期内完成,对于高频率控制(>1kHz),优先选择简单模型(线性、岭回归)或使用专门的硬件(FPGA、DSP)。
- 稳定性保证:在线学习可能导致模型发散,可以引入:
- 学习率衰减:
learning_rate = initial_lr / (1 + decay_rate * t) - 参数限制:为模型权重设置上下限(clip)。
- 结合离线预训练:先用历史数据预训练,再在线微调。
- 学习率衰减:
- 数据归一化:使用在线标准差(Welford算法)进行归一化,避免重新扫描历史数据。
完整示例:自适应PID参数在线调整(滑动窗口法)
以下是一个结合滑动窗口统计量自适应调整P增益的简单例子。
import numpy as np
import matplotlib.pyplot as plt
class AdaptivePID:
"""一个简单的自适应PID控制器,根据误差的统计特性在线调整P增益"""
def __init__(self, Kp_base=1.0, Ki=0.1, Kd=0.05, window_size=50):
self.Kp_base = Kp_base
self.Ki = Ki
self.Kd = Kd
self.window = [] # 存储最近误差
self.window_size = window_size
self.prev_error = 0
self.integral = 0
self.last_time = None
def compute(self, setpoint, measurement, dt):
error = setpoint - measurement
self.window.append(error)
if len(self.window) > self.window_size:
self.window.pop(0)
# 在线计算误差的滑动标准差,用于调整P增益
if len(self.window) > 1:
std_error = np.std(self.window)
else:
std_error = 1.0
# 自适应规则:误差变化大时增大P,稳定时减小P(避免振荡)
Kp_adaptive = self.Kp_base * (1.0 + 0.5 * np.clip(std_error - 0.1, -0.5, 0.5))
# 标准PID计算
self.integral += error * dt
derivative = (error - self.prev_error) / dt
output = Kp_adaptive * error + self.Ki * self.integral + self.Kd * derivative
self.prev_error = error
return output
# 模拟一个简单的一阶滞后系统
def plant(input_signal, state, dt, tau=0.1):
"""一阶系统:dy/dt = (u - y)/tau"""
state += (input_signal - state) / tau * dt
return state
if __name__ == "__main__":
controller = AdaptivePID(Kp_base=0.5, Ki=0.2, Kd=0.05)
setpoint = 1.0
state = 0.0
dt = 0.01
history = []
for t in range(1000):
control_signal = controller.compute(setpoint, state, dt)
# 添加过程噪声
control_signal += np.random.normal(0, 0.02)
state = plant(control_signal, state, dt)
history.append((t*dt, setpoint, state, control_signal))
# 绘图
times, sps, states, controls = zip(*history)
plt.figure(figsize=(10,4))
plt.plot(times, sps, 'r--', label='Setpoint')
plt.plot(times, states, 'b-', label='System Output')
plt.xlabel('Time (s)')
plt.ylabel('Value')
plt.legend()
plt.title('Adaptive PID Control with Online Learning')
plt.show()
Python脚本实现数据自适应控制的方法取决于系统复杂度和实时性要求:
- 简单统计自适应:使用
collections.deque+numpy实现滑动窗口。 - 线性模型在线学习:手写梯度下降或使用
river库。 - 非线性在线学习:使用轻量级 PyTorch 网络 + 单步更新。
- 工业级鲁棒性:考虑概念漂移、参数限制和计算延迟。
建议从最简单的滑动窗口统计量开始,验证效果后逐步引入更复杂的模型,对于实际工程应用,强烈推荐 River 库,它专门为在线学习而设计,并内置了概念漂移检测。