这是一个使用PyTorch实现DDPG算法的例程:
```python
import torch
import torch.nn as nn
import torch.optim as optim
import torch.nn.functional as F
import numpy as np
# 定义Actor网络
class Actor(nn.Module):
def __init__(self, state_dim, action_dim, max_action):
super(Actor, self).__init__()
self.layer1 = nn.Linear(state_dim, 400)
self.layer2 = nn.Linear(400, 300)
self.layer3 = nn.Linear(300, action_dim)
self.max_action = max_action
def forward(self, x):
x = F.relu(self.layer1(x))
x = F.relu(self.layer2(x))
x = self.max_action * torch.tanh(self.layer3(x))
return x
# 定义Critic网络
class Critic(nn.Module):
def __init__(self, state_dim, action_dim):
super(Critic, self).__init__()
self.layer1 = nn.Linear(state_dim + action_dim, 400)
self.layer2 = nn.Linear(400, 300)
self.layer3 = nn.Linear(300, 1)
def forward(self, x, u):
xu = torch.cat([x, u], 1)
x = F.relu(self.layer1(xu))
x = F.relu(self.layer2(x))
x = self.layer3(x)
return x
# 定义DDPG算法
class DDPG(object):
def __init__(self, state_dim, action_dim, max_action):
self.actor = Actor(state_dim, action_dim, max_action).to(device)
self.actor_target = Actor(state_dim, action_dim, max_action).to(device)
self.actor_target.load_state_dict(self.actor.state_dict())
self.actor_optimizer = optim.Adam(self.actor.parameters(), lr=1e-4)
self.critic = Critic(state_dim, action_dim).to(device)
self.critic_target = Critic(state_dim, action_dim).to(device)
self.critic_target.load_state_dict(self.critic.state_dict())
self.critic_optimizer = optim.Adam(self.critic.parameters(), lr=1e-3)
self.max_action = max_action
def select_action(self, state):
state = torch.FloatTensor(state.reshape(1, -1)).to(device)
return self.actor(state).cpu().data.numpy().flatten()
def train(self, replay_buffer, iterations, batch_size=100, discount=0.99, tau=0.005):
for it in range(iterations):
# 从replay buffer中随机采样一个batch的数据
batch_states, batch_next_states, batch_actions, batch_rewards, batch_dones = replay_buffer.sample(batch_size)
state = torch.FloatTensor(batch_states).to(device)
next_state = torch.FloatTensor(batch_next_states).to(device)
action = torch.FloatTensor(batch_actions).to(device)
reward = torch.FloatTensor(batch_rewards).to(device)
done = torch.FloatTensor(batch_dones).to(device)
# 训练Critic网络
target_Q = self.critic_target(next_state, self.actor_target(next_state))
target_Q = reward + ((1 - done) * discount * target_Q).detach()
current_Q = self.critic(state, action)
critic_loss = F.mse_loss(current_Q, target_Q)
self.critic_optimizer.zero_grad()
critic_loss.backward()
self.critic_optimizer.step()
# 训练Actor网络
actor_loss = -self.critic(state, self.actor(state)).mean()
self.actor_optimizer.zero_grad()
actor_loss.backward()
self.actor_optimizer.step()
# 更新target网络
for param, target_param in zip(self.critic.parameters(), self.critic_target.parameters()):
target_param.data.copy_(tau * param.data + (1 - tau) * target_param.data)
for param, target_param in zip(self.actor.parameters(), self.actor_target.parameters()):
target_param.data.copy_(tau * param.data + (1 - tau) * target_param.data)
def save(self, filename):
torch.save(self.actor.state_dict(), filename + "_actor")
torch.save(self.critic.state_dict(), filename + "_critic")
def load(self, filename):
self.actor.load_state_dict(torch.load(filename + "_actor"))
self.critic.load_state_dict(torch.load(filename + "_critic"))
# 定义Replay Buffer
class ReplayBuffer(object):
def __init__(self, max_size=1000000):
self.storage = []
self.max_size = max_size
self.ptr = 0
def add(self, state, next_state, action, reward, done):
data = (state, next_state, action, reward, done)
if len(self.storage) == self.max_size:
self.storage[int(self.ptr)] = data
self.ptr = (self.ptr + 1) % self.max_size
else:
self.storage.append(data)
def sample(self, batch_size):
ind = np.random.randint(0, len(self.storage), size=batch_size)
batch_states = []
batch_next_states = []
batch_actions = []
batch_rewards = []
batch_dones = []
for i in ind:
state, next_state, action, reward, done = self.storage[i]
batch_states.append(np.array(state, copy=False))
batch_next_states.append(np.array(next_state, copy=False))
batch_actions.append(np.array(action, copy=False))
batch_rewards.append(np.array(reward, copy=False))
batch_dones.append(np.array(done, copy=False))
return np.array(batch_states), np.array(batch_next_states), np.array(batch_actions), np.array(batch_rewards).reshape(-1, 1), np.array(batch_dones).reshape(-1, 1)
# 定义环境
class Environment(object):
def __init__(self):
self.state_dim = 3
self.action_dim = 1
self.max_action = 2.0
def step(self, action):
next_state = np.zeros(3)
next_state[0] = 0.5
next_state[1] = 0.5 * np.sin(3 * next_state[0]) + 0.5 * np.sin(2 * next_state[1])
next_state[2] = 0.5 * np.sin(2 * next_state[0]) + 0.5 * np.sin(3 * next_state[1])
reward = -np.linalg.norm(next_state - np.array([1, 0, 0])) # 奖励函数为到目标点的欧式距离的相反数
done = False
return next_state, reward, done
def reset(self):
state = np.zeros(3)
state[0] = np.random.uniform(low=-0.1, high=0.1)
state[1] = np.random.uniform(low=-0.1, high=0.1)
state[2] = np.random.uniform(low=-0.1, high=0.1)
return state
# 训练DDPG
env = Environment()
replay_buffer = ReplayBuffer()
ddpg = DDPG(env.state_dim, env.action_dim, env.max_action)
for i in range(100000):
state = env.reset()
done = False
while not done:
action = ddpg.select_action(state)
next_state, reward, done = env.step(action)
replay_buffer.add(state, next_state, action, reward, done)
state = next_state
if len(replay_buffer.storage) > 1000:
ddpg.train(replay_buffer, 100)
# 测试DDPG
state = env.reset()
done = False
while not done:
action = ddpg.select_action(state)
next_state, reward, done = env.step(action)
state = next_state
print(state)
# 保存DDPG模型
ddpg.save("ddpg")
```