神经网络直接逆控制:神经网络与控制的结合入门级结合
目录
1. 前言
2. 什么是直接逆控制?
2.1 直接逆控制的优点
2.2 直接逆控制的局限性
3. 直接逆控制的实现步骤
3.1 数据准备
3.2 神经网络设计
3.3 训练神经网络
3.4 控制实现
4. 使用 PyTorch 实现直接逆控制
4.1 问题描述
4.2 数据生成
4.3 神经网络设计
4.4 训练神经网络
4.5 控制实现
5. 优化与改进完整代码
6. 总结
1. 前言
神经网络直接逆控制是控制和神经网络最简单基础的结合!
在控制领域,神经网络控制是一种强大的工具,能够处理复杂的非线性系统和不确定性问题。其中,直接逆控制是一种简单而有效的神经网络控制方法,它通过训练神经网络来模拟被控对象的逆动态特性,从而实现对系统的精确控制。本文将详细介绍直接逆控制的原理,并通过一个完整的 PyTorch 实现案例,帮助读者理解和应用这一技术。
2. 什么是直接逆控制?
直接逆控制是一种基于神经网络的控制方法,其核心思想是利用神经网络学习被控对象的逆动态模型。具体来说,被控对象的动态特性可以表示为:
其中,y 是系统的输出,u 是系统的输入,f 是系统的动态模型。直接逆控制的目标是训练一个神经网络 g,使得:
其中,yref 是期望的系统输出。通过这种方式,神经网络 g 模拟了被控对象的逆动态特性,从而实现对系统的精确控制。
2.1 直接逆控制的优点
-
简单直接:直接逆控制不需要复杂的控制算法,只需训练一个神经网络即可。
-
适应性强:能够处理非线性和不确定性的系统。
-
易于实现:只需要被控对象的输入输出数据即可训练。
2.2 直接逆控制的局限性
-
依赖数据质量:训练数据的质量直接影响神经网络的性能。
-
实时性要求高:在实时控制系统中,神经网络的计算速度需要足够快。
3. 直接逆控制的实现步骤
3.1 数据准备
为了训练神经网络,我们需要被控对象的输入输出数据。这些数据可以通过实验或仿真获得。
3.2 神经网络设计
设计一个神经网络来模拟被控对象的逆动态特性。通常,可以选择多层感知机(MLP)作为网络结构。
3.3 训练神经网络
使用输入输出数据训练神经网络,使其能够准确预测系统的输入 u,给定期望输出 yref。
3.4 控制实现
在实际控制中,将期望输出 yref 输入到训练好的神经网络中,得到控制输入 u,并将其应用于被控对象。
4. 使用 PyTorch 实现直接逆控制
4.1 问题描述
假设我们有一个简单的被控对象,其动态特性可以表示为:
我们的目标是通过直接逆控制,使系统的输出 y 跟踪一个给定的参考信号 yref。
4.2 数据生成
首先,我们需要生成被控对象的输入输出数据。
import numpy as np
import torch
import torch.nn as nn
import torch.optim as optim
import matplotlib.pyplot as plt# 设置随机种子
np.random.seed(42)
torch.manual_seed(42)# 生成训练数据
def generate_data(steps=1000):y = np.zeros(steps)u = np.random.uniform(-1, 1, steps)for t in range(1, steps):y[t] = 0.5 * y[t-1] + u[t-1] + np.sin(y[t-1])# 准备输入输出数据X = y[:-1].reshape(-1, 1)y_ref = y[1:].reshape(-1, 1)u_data = u[:-1].reshape(-1, 1)return X, y_ref, u_dataX, y_ref, u_data = generate_data(steps=1000)
4.3 神经网络设计
设计一个简单的多层感知机(MLP)来模拟被控对象的逆动态特性。
class InverseModel(nn.Module):def __init__(self):super(InverseModel, self).__init__()self.fc1 = nn.Linear(1, 64)self.fc2 = nn.Linear(64, 64)self.fc3 = nn.Linear(64, 1)self.relu = nn.ReLU()def forward(self, x):x = self.relu(self.fc1(x))x = self.relu(self.fc2(x))x = self.fc3(x)return x# 初始化模型
model = InverseModel()
criterion = nn.MSELoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)
4.4 训练神经网络
使用生成的数据训练神经网络。
# 转换为 PyTorch 张量
X_tensor = torch.tensor(X, dtype=torch.float32)
y_ref_tensor = torch.tensor(y_ref, dtype=torch.float32)# 训练模型
num_epochs = 1000
losses = []for epoch in range(num_epochs):optimizer.zero_grad()outputs = model(y_ref_tensor)loss = criterion(outputs, torch.tensor(u_data, dtype=torch.float32))loss.backward()optimizer.step()losses.append(loss.item())if (epoch+1) % 100 == 0:print(f'Epoch [{epoch+1}/{num_epochs}], Loss: {loss.item():.4f}')# 绘制损失曲线
plt.plot(losses)
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.title('Training Loss')
plt.show()
结果如下:
可以看出,给定目标输出,用神经网络和用普通模型控制几乎无异。
4.5 控制实现
使用训练好的神经网络进行控制。
# 生成参考信号
def generate_reference_signal(steps=100):t = np.linspace(0, 10, steps)y_ref = np.sin(t) * 0.5 # 使用正弦波作为参考信号return y_ref# 控制过程
def control_process(model, y_ref, steps=100):y = np.zeros(steps)u = np.zeros(steps)for t in range(steps-1):# 使用神经网络计算控制输入y_ref_tensor = torch.tensor([[y_ref[t]]], dtype=torch.float32)u[t] = model(y_ref_tensor).detach().numpy()[0][0]# 更新系统状态y[t+1] = 0.5 * y[t] + u[t] + np.sin(y[t])return y, u# 生成参考信号并进行控制
y_ref_control = generate_reference_signal(steps=100)
y_control, u_control = control_process(model, y_ref_control)# 绘制结果
plt.figure(figsize=(12, 6))
plt.plot(y_ref_control, label='Reference Signal')
plt.plot(y_control, label='System Output')
plt.xlabel('Time Step')
plt.ylabel('Value')
plt.title('Control Performance')
plt.legend()
plt.show()
5. 优化与改进完整代码
即便训练部分表现优异,但是以上控制实现部分代码实际效果很不好,主要因为训练太单一,只输入一个给定目标值很难判断该系统应该如何控制,以上训练阶段实际上是过拟合。
改进后主要改进点为:
-
数据生成:
-
现在生成的数据包含当前状态和期望的下一状态
-
直接根据系统方程计算所需的控制输入
-
数据范围扩大到[-2, 2]以更好覆盖操作空间
-
-
模型结构:
-
输入层改为2个节点(当前状态 + 目标状态)
-
增加网络深度和容量以更好学习非线性关系
-
-
控制过程:
-
现在使用当前状态和下一时刻的参考信号来预测控制输入
-
初始状态与参考信号对齐
-
添加了跟踪误差的可视化
-
-
训练过程:
-
使用更合理的训练数据配对
-
增加训练数据量到10000个样本
-
代码如下:
import numpy as np
import torch
import torch.nn as nn
import torch.optim as optim
import matplotlib.pyplot as plt# 设置随机种子
np.random.seed(42)
torch.manual_seed(42)# 生成训练数据(修正后的版本)
def generate_data(num_samples=10000):# 随机生成当前状态和期望的下一个状态y_current = np.random.uniform(-2, 2, num_samples)y_ref_next = np.random.uniform(-2, 2, num_samples)# 根据系统方程计算所需的控制输入u = y_ref_next - 0.5 * y_current - np.sin(y_current)# 组合特征:当前状态 + 目标状态X = np.column_stack((y_current, y_ref_next))return X, u.reshape(-1, 1)X, u_data = generate_data(num_samples=10000)class InverseModel(nn.Module):def __init__(self):super(InverseModel, self).__init__()self.fc1 = nn.Linear(2, 64) # 输入两个特征:当前状态和目标状态self.fc2 = nn.Linear(64, 64)self.fc3 = nn.Linear(64, 1)self.relu = nn.ReLU()def forward(self, x):x = self.relu(self.fc1(x))x = self.relu(self.fc2(x))x = self.fc3(x)return x# 初始化模型
model = InverseModel()
criterion = nn.MSELoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)# 转换为 PyTorch 张量
X_tensor = torch.tensor(X, dtype=torch.float32)
u_tensor = torch.tensor(u_data, dtype=torch.float32)# 训练模型(修正后的训练循环)
num_epochs = 1000
losses = []for epoch in range(num_epochs):optimizer.zero_grad()outputs = model(X_tensor)loss = criterion(outputs, u_tensor)loss.backward()optimizer.step()losses.append(loss.item())if (epoch + 1) % 100 == 0:print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {loss.item():.4f}')# 绘制损失曲线
plt.plot(losses)
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.title('Training Loss')
plt.show()# 生成参考信号(保持相同)
def generate_reference_signal(steps=100):t = np.linspace(0, 10, steps)y_ref = np.sin(t) * 0.5 # 使用正弦波作为参考信号return y_ref# 控制过程(修正后的版本)
def control_process(model, y_ref, steps=100):y = np.zeros(steps)u = np.zeros(steps)y[0] = y_ref[0] # 初始状态与参考信号对齐u_real_control=np.zeros(steps)for t in range(steps - 1):# 使用当前状态和下一时刻的参考信号预测控制输入y_ref_next = y_ref[t + 1]input_tensor = torch.tensor([[y[t], y_ref_next]], dtype=torch.float32)u[t] = model(input_tensor).detach().numpy()[0][0]u_real_control[t]=y_ref_next - 0.5 * y[t] - np.sin(y[t])# 更新系统状态y[t + 1] = 0.5 * y[t] + u[t] + np.sin(y[t])return y, u,u_real_control# 生成参考信号并进行控制
y_ref_control = generate_reference_signal(steps=100)
y_control, u_control,u_real_control = control_process(model, y_ref_control)# 绘制结果(添加跟踪误差显示)
plt.figure(figsize=(12, 10))plt.subplot(3, 1, 1)
plt.plot(y_ref_control, label='Reference Signal', linestyle='--')
plt.plot(y_control, label='System Output')
plt.xlabel('Time Step')
plt.ylabel('Value')
plt.title('Control Performance')
plt.legend()plt.subplot(3, 1, 2)
plt.plot(y_ref_control - y_control, label='Tracking Error', color='red')
plt.xlabel('Time Step')
plt.ylabel('Error')
plt.title('Tracking Error')
plt.legend()plt.subplot(3, 1, 3)
plt.plot(u_real_control, label='u_real_control',linestyle='--')
plt.plot(u_control, label='u_control')
plt.xlabel('Time Step')
plt.ylabel('control_value')
plt.title('Control error')
plt.legend()plt.tight_layout()
plt.show()
运行后可以看出效果非常好
6. 总结
本文介绍了神经网络直接逆控制的原理,并通过一个简单的 PyTorch 实现案例展示了其应用。直接逆控制通过训练神经网络模拟被控对象的逆动态特性,能够有效地实现对复杂系统的精确控制。尽管直接逆控制具有简单直接的优点,但它对训练数据的质量和神经网络的计算速度有一定要求。在未来的工作中,可以结合其他控制方法(如自适应控制或模糊控制)来进一步提高控制性能。我是橙色小博,关注我,一起在人工智能领域学习进步!