📢本篇文章是博主强化学习RL领域学习时,用于个人学习、研究或者欣赏使用,并基于博主对相关等领域的一些理解而记录的学习摘录和笔记,若有不当和侵权之处,指出后将会立即改正,还望谅解。文章分类在👉强化学习专栏: 【强化学习】(17)---《基于迁移学习的强化学习(RL-TL)算法》
基于迁移学习的强化学习(Reinforcement Learning with Transfer Learning,简称 RL-TL)是将迁移学习(Transfer Learning)的概念应用于强化学习(Reinforcement Learning,简称 RL)中的一种方法。其核心思想是在强化学习的环境中,利用已有的经验或在其他任务中学到的知识来提升学习效率和表现。这样可以减少从零开始学习的时间和样本需求,尤其在数据稀缺或任务复杂的场景中。
下面是一些关于**基于强化学习的迁移学习(Reinforcement Learning with Transfer Learning, RL-TL)**的重要研究论文的详细介绍:
摘要: 该论文提供了关于强化学习中迁移学习技术的全面综述。作者对现有的迁移学习方法进行了分类,并讨论了迁移学习在强化学习领域中的理论和实证基础。文章重点探讨了迁移的关键组成部分,如迁移的知识类型(策略、值函数、特征等)以及任务的性质(源任务和目标任务)。
关键概念:
应用:
结论: 如果源任务与目标任务足够相关,迁移学习可以显著减少强化学习任务所需的训练量。
摘要: 这篇论文扩展了迁移学习在**深度强化学习(Deep Reinforcement Learning, DRL)**中的应用,重点介绍了在深度强化学习中使用的迁移机制,如网络微调、共享表示以及卷积网络中提取的特征迁移。
关键概念:
挑战:
应用:
结论: 深度强化学习从迁移学习中获益显著,特别是当任务具有结构相似性时。然而,负迁移的防止和稳健性仍是需要进一步解决的挑战。
这些论文展示了**基于强化学习的迁移学习(RL-TL)**在传统强化学习到深度学习场景中的各种方法,涵盖了任务间策略迁移、值函数迁移和多任务学习等内容。它们是理解 RL-TL 最新技术的宝贵资源。
基于迁移学习的强化学习(RL-TL)是一种高效的学习方法,通过从源任务中借鉴经验或知识,提升目标任务的学习速度和性能。随着强化学习在复杂环境中的应用日益增多,RL-TL 提供了一种减少训练时间、提高数据效率的途径。然而,RL-TL 的成功实施依赖于任务相似性、迁移策略的合理选择等因素,需要针对具体问题进行设计和优化。
以下是一个基于 迁移学习 的强化学习(Reinforcement Learning with Transfer Learning)代码示例,使用 PyTorch
和 OpenAI Gym
。我们将先在一个简单的环境中(如 CartPole
)训练一个 Q-learning 算法,并将其学到的策略迁移到另一个稍微不同的环境(如 MountainCar
),通过微调来适应目标环境。
首先,确保安装了以下依赖:
pip install torch gym numpy
我们使用深度 Q 网络(DQN)算法进行迁移学习。
CartPole-v1
)"""《基于迁移学习的强化学习代码示例》
时间:2024.09.22
作者:不去幼儿园
"""
import gym
import torch
import torch.nn as nn
import torch.optim as optim
import numpy as np
import random
from collections import deque
# 定义 Q 网络
class QNetwork(nn.Module):
def __init__(self, state_dim, action_dim):
super(QNetwork, self).__init__()
self.fc1 = nn.Linear(state_dim, 128)
self.fc2 = nn.Linear(128, 128)
self.fc3 = nn.Linear(128, action_dim)
def forward(self, x):
x = torch.relu(self.fc1(x))
x = torch.relu(self.fc2(x))
return self.fc3(x)
# Replay buffer,用于存储经验
class ReplayBuffer:
def __init__(self, capacity):
self.buffer = deque(maxlen=capacity)
def add(self, transition):
self.buffer.append(transition)
def sample(self, batch_size):
transitions = random.sample(self.buffer, batch_size)
# 从 transitions 中解压各个元素
states, actions, rewards, next_states, dones = zip(*transitions)
# 将 states 和 next_states 转换为 numpy 数组时保持维度一致,使用 np.stack 而不是 np.array
states = np.stack(states) # 将状态堆叠为多维数组
next_states = np.stack(next_states) # 保证 next_states 也被堆叠为多维数组
actions = np.array(actions, dtype=np.int64) # 动作通常是整数
rewards = np.array(rewards, dtype=np.float32) # 奖励通常是浮点数
dones = np.array(dones, dtype=np.float32) # dones 是布尔值,用浮点数表示
return states, actions, rewards, next_states, dones
def size(self):
return len(self.buffer)
# 选择动作
def select_action(state, policy_net, epsilon, action_dim):
if random.random() < epsilon:
return random.choice(np.arange(action_dim))
else:
with torch.no_grad():
state = torch.FloatTensor(state).unsqueeze(0)
q_values = policy_net(state)
return q_values.argmax().item()
# Q-learning 更新
def update_model(policy_net, target_net, optimizer, replay_buffer, batch_size, gamma):
if replay_buffer.size() < batch_size:
return
states, actions, rewards, next_states, dones = replay_buffer.sample(batch_size)
states = torch.FloatTensor(states)
actions = torch.LongTensor(actions)
rewards = torch.FloatTensor(rewards)
next_states = torch.FloatTensor(next_states)
dones = torch.FloatTensor(dones)
q_values = policy_net(states).gather(1, actions.unsqueeze(1)).squeeze(1)
next_q_values = target_net(next_states).max(1)[0]
target_q_values = rewards + gamma * next_q_values * (1 - dones)
loss = (q_values - target_q_values.detach()).pow(2).mean()
optimizer.zero_grad()
loss.backward()
optimizer.step()
# 训练模型
def train_dqn(env_name, num_episodes=500, gamma=0.99, epsilon_start=1.0, epsilon_end=0.01, epsilon_decay=0.995, batch_size=64):
env = gym.make(env_name)
state_dim = env.observation_space.shape[0]
action_dim = env.action_space.n
policy_net = QNetwork(state_dim, action_dim)
target_net = QNetwork(state_dim, action_dim)
target_net.load_state_dict(policy_net.state_dict())
target_net.eval()
optimizer = optim.Adam(policy_net.parameters())
replay_buffer = ReplayBuffer(10000)
epsilon = epsilon_start
for episode in range(num_episodes):
state, _ = env.reset() # 只获取 state,忽略 info
total_reward = 0
while True:
action = select_action(state, policy_net, epsilon, action_dim)
next_state, reward, done, _, __ = env.step(action) # 只获取 next_state,忽略其他
replay_buffer.add((state, action, reward, next_state, done))
state = next_state
total_reward += reward
update_model(policy_net, target_net, optimizer, replay_buffer, batch_size, gamma)
if done:
print(f"Episode {episode + 1}/{num_episodes}, Total Reward: {total_reward}")
break
epsilon = max(epsilon_end, epsilon_decay * epsilon)
if episode % 10 == 0:
target_net.load_state_dict(policy_net.state_dict())
return policy_net
# 在源环境(CartPole)中训练模型
policy_net_cartpole = train_dqn(env_name='CartPole-v1')
MountainCar-v0
) 并进行微调 接下来,将在 CartPole-v1
环境中训练的 Q 网络迁移到另一个目标环境 MountainCar-v0
,并通过微调适应新环境。
由于源环境 CartPole-v1
和目标环境 MountainCar-v0
之间的状态空间和动作空间的维度不同,导致模型在迁移时无法直接加载预训练的权重。具体来说:
CartPole-v1
的状态维度是 4,而 MountainCar-v0
的状态维度是 2。这导致模型的输入层权重维度不匹配。CartPole-v1
的动作维度是 2,而 MountainCar-v0
的动作维度是 3。这导致模型输出层的权重和偏置不匹配。需要保留预训练模型中可迁移的部分(如隐藏层的权重),而重新初始化输入层和输出层,以适应目标环境的状态和动作空间。
# 定义函数以匹配网络的结构,进行部分权重的迁移
def transfer_weights(policy_net, target_env_state_dim, target_env_action_dim):
# 获取预训练的网络
pretrained_dict = policy_net.state_dict()
# 创建新网络,适应目标环境的状态和动作维度
new_policy_net = QNetwork(target_env_state_dim, target_env_action_dim)
# 获取新网络的权重
new_dict = new_policy_net.state_dict()
# 仅保留在预训练网络和新网络中都有的层(即隐藏层的参数)
pretrained_dict = {k: v for k, v in pretrained_dict.items() if k in new_dict and 'fc1' not in k and 'fc3' not in k}
# 更新新网络的权重
new_dict.update(pretrained_dict)
# 将更新后的字典加载到新模型中
new_policy_net.load_state_dict(new_dict)
return new_policy_net
# 微调模型
def fine_tune_dqn(policy_net, env_name, num_episodes=200, gamma=0.99, epsilon_start=0.1, epsilon_end=0.01, epsilon_decay=0.995, batch_size=64):
env = gym.make(env_name)
target_state_dim = env.observation_space.shape[0]
target_action_dim = env.action_space.n
# 调用 transfer_weights 函数,将权重从 CartPole 模型迁移到新的 MountainCar 模型
policy_net = transfer_weights(policy_net, target_state_dim, target_action_dim)
target_net = QNetwork(target_state_dim, target_action_dim)
target_net.load_state_dict(policy_net.state_dict())
target_net.eval()
optimizer = optim.Adam(policy_net.parameters())
replay_buffer = ReplayBuffer(10000)
epsilon = epsilon_start
for episode in range(num_episodes):
state, _ = env.reset() # 只获取 state,忽略 info
total_reward = 0
while True:
action = select_action(state, policy_net, epsilon, target_action_dim)
next_state, reward, done, _, __ = env.step(action) # 只获取 next_state,忽略其他
replay_buffer.add((state, action, reward, next_state, done))
state = next_state
total_reward += reward
update_model(policy_net, target_net, optimizer, replay_buffer, batch_size, gamma)
if done:
print(f"Episode {episode + 1}/{num_episodes}, Total Reward: {total_reward}")
break
epsilon = max(epsilon_end, epsilon_decay * epsilon)
if episode % 10 == 0:
target_net.load_state_dict(policy_net.state_dict())
return policy_net
# 微调源环境训练的策略网络到目标环境 MountainCar
fine_tuned_policy_net = fine_tune_dqn(policy_net_cartpole, env_name='MountainCar-v0')
3. 测试模型在 MountainCar-v0
环境中的表现
运行此代码将会显示模型在 MountainCar-v0
环境中的测试表现,你可以根据结果评估模型的迁移学习效果。
# 测试微调后的策略并显示动画
def test_policy_with_animation(policy_net, env_name, num_episodes=5, max_steps=200):
# 初始化环境并启用动画显示
env = gym.make(env_name, render_mode="human")
total_rewards = []
for episode in range(num_episodes):
state, _ = env.reset() # 获取初始状态
total_reward = 0
for step in range(max_steps):
# 选择动作,不使用探索
action = select_action(state, policy_net, epsilon=0.0, action_dim=env.action_space.n)
next_state, reward, done, _, __ = env.step(action) # 执行动作
total_reward += reward
state = next_state # 更新状态
if done:
break # 结束当前回合
total_rewards.append(total_reward)
print(f"Episode {episode + 1}/{num_episodes}, Total Reward: {total_reward}")
# 关闭环境
env.close()
print(f"Average Total Reward over {num_episodes} episodes: {np.mean(total_rewards)}")
return total_rewards
# 测试微调后的策略网络在 MountainCar 环境中的表现
test_rewards = test_policy_with_animation(fine_tuned_policy_net, env_name='MountainCar-v0')
可直接运行的项目python代码: RL基于迁移学习的强化学习(RL-TL) 🔥若是代码复现困难或者有问题,欢迎评论区留言;需要以整个项目形式的代码,请在评论区留下您的邮箱📌,以便于及时分享给您(私信难以及时回复)。
QNetwork
是一个简单的前馈神经网络,用于估计状态动作值(Q 值)。
ReplayBuffer
存储经验,以便进行经验回放,减少样本的相关性。
CartPole-v1
环境上使用 DQN 训练模型。QNetwork
模型迁移到 MountainCar-v0
环境,并在新的环境上进行微调,适应新的任务。epsilon
值(例如从 0.1 开始),表示我们对新任务有部分知识,并减少探索。随着训练的进行,epsilon
会逐渐衰减。
MountainCar-v0
环境中的测试表现,你可以根据结果评估模型的迁移学习效果。
CartPole-v1
环境中训练 Q 网络策略,积累源任务的经验。MountainCar-v0
环境,通过少量微调适应目标任务。MountainCar-v0
环境中的表现 这个代码示例展示了如何使用迁移学习的思想,将在一个环境中学到的策略迁移到另一个相关的环境中。我们在 CartPole-v1
中训练了一个深度 Q 网络,并通过迁移学习在 MountainCar-v0
中对其进行微调,使模型能够适应新任务。
迁移学习后在
MountainCar-v0
环境中的奖励值结果较差,并且奖励值为负值,负值奖励是因为MountainCar
环境本身的设计以及与CartPole
环境的差异。这种情况常见于迁移学习中的两个任务差异较大时,源任务的学习策略并不适合直接应用于目标任务。
这具体体现在以下几个方面:
因此,CartPole
中学到的策略很难直接应用到 MountainCar
,因为两个环境的动力学、目标和奖励机制都有很大差异。
在 MountainCar-v0
环境中,智能体每执行一步就会收到 -1 的奖励,直到车达到目标位置(山顶),奖励累积自然为负数。特别是在迁移初期,智能体没有学会正确的爬坡策略,因此会在山谷中反复移动,得到更多的负奖励。
由于源环境(CartPole
)和目标环境(MountainCar
)的状态、动作空间以及任务目标差异较大,迁移的初期效果往往较差,甚至表现比随机策略还差。CartPole
的策略试图通过平衡,而在 MountainCar
中,成功的策略则需要激进的左右移动来获得足够的动能爬到山顶。
要提高迁移学习的效果,可以尝试以下方法:
MountainCar
环境中的最佳策略。延长微调的训练时间可以帮助智能体逐渐学习如何在目标任务中表现得更好。
epsilon
初期值(如 0.5 或 0.9),并减缓其衰减速率,这样智能体可以更多地探索不同的动作。
奖励值较低的情况主要是由于
CartPole
和MountainCar
两个环境差异太大,导致迁移学习策略初期表现不好。这是正常的情况,随着更长时间的微调和探索策略的调整,智能体在MountainCar
中的表现应该会逐渐改善。文章若有不当和不正确之处,还望理解与指出。由于部分文字、图片等来源于互联网,无法核实真实出处,如涉及相关争议,请联系博主删除。如有错误、疑问和侵权,欢迎评论留言联系作者