Repository navigation
Expand file tree
/
Copy pathagent.py
More file actions
150 lines (138 loc) · 6.49 KB
/
Copy pathagent.py
File metadata and controls
150 lines (138 loc) · 6.49 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
############################################################################
############################################################################
# THIS IS THE ONLY FILE YOU SHOULD EDIT
#
#
# Agent must always have these five functions:
# __init__(self)
# has_finished_episode(self)
# get_next_action(self, state)
# set_next_state_and_distance(self, next_state, distance_to_goal)
# get_greedy_action(self, state)
#
#
# You may add any other functions as you wish
############################################################################
############################################################################
import numpy as np
import torch
from Network import DQN
from replayBuffer import ReplayBuffer
class Agent:
# Function to initialise the agent
def __init__(self):
# Set the episode length (you will need to increase this)
self.episode_length = 350
# Reset the total number of steps which the agent has taken
self.num_steps_taken = 0
# The state variable stores the latest state of the agent in the environment
self.state = None
# The action variable stores the latest action which the agent has applied to the environment
self.action = None
# The deep Q network
self.dqn = DQN(0.9)
# Replay buffer
self.replay_buffer = ReplayBuffer()
# Batch size
self.batch_size = 450
# Epsilon
self.epsilon = 1
# Delta
self.delta = 0.00008
self.last_distance = None
self.last_state = None
# Random on episode
self.epsilon_episode = 0
self.delta_episode = 0.1
# Function to check whether the agent has reached the end of an episode
def has_finished_episode(self):
if self.num_steps_taken % self.episode_length == 0:
print(self.epsilon)
print(self.last_distance)
self.epsilon_episode = 0.0
return True
else:
return False
# Function to get the next action, using whatever method you like
def get_next_action(self, state, discrete_action=None):
# Here, the action is random, but you can change this
#action = np.random.uniform(low=-0.01, high=0.01, size=2).astype(np.float32)
# Choose an action with e-greedy policy
if discrete_action is None:
if np.random.uniform(0, 1) <= self.epsilon_episode and self.epsilon < 0:
discrete_action = np.random.randint(0, 4, 1)[0]
# Store the discrete action
self.action = discrete_action
# Decrease epsilon
self.epsilon_episode = max(0, self.epsilon_episode - self.delta_episode)
self.epsilon = max(0, self.epsilon - self.delta)
# Convert discrete action into continuous action
action = self.discrete_action_to_continuous(discrete_action)
if (self.last_state == self.state).all():
self.epsilon_episode = 1
elif np.random.uniform(0, 1) <= self.epsilon or self.state is None:
discrete_action = np.random.randint(0, 4, 1)[0]
# Store the discrete action
self.action = discrete_action
# Decrease epsilon
self.epsilon = max(0, self.epsilon - self.delta)
# Convert discrete action into continuous action
action = self.discrete_action_to_continuous(discrete_action)
elif (self.last_state == self.state).all():
self.epsilon_episode = 0.8
discrete_action = np.random.randint(0, 4, 1)[0]
# Store the discrete action
self.action = discrete_action
# Convert discrete action into continuous action
action = self.discrete_action_to_continuous(discrete_action)
else:
action = self.get_greedy_action(self.state)
# Update the number of steps which the agent has taken
self.num_steps_taken += 1
# Store the state; this will be used later, when storing the transition
self.last_state = self.state
self.state = state
return action
# Function to convert discrete action (as used by a DQN) to a continuous action (as used by the environment).
def discrete_action_to_continuous(self, discrete_action):
if discrete_action == 0: # Move right
continuous_action = np.array([0.02, 0], dtype=np.float32)
elif discrete_action == 1: # Move left
continuous_action = np.array([-0.02, 0], dtype=np.float32)
elif discrete_action == 2: # Move up
continuous_action = np.array([0, 0.02], dtype=np.float32)
elif discrete_action == 3: # Move down
continuous_action = np.array([0, -0.02], dtype=np.float32)
return continuous_action
# Function to set the next state and distance, which resulted from applying action self.action at state self.state
def set_next_state_and_distance(self, next_state, distance_to_goal):
# Convert the distance to a reward
reward = self.compute_reward(distance_to_goal)
# Create a transition
transition = (self.state, self.action, reward, next_state)
# We add the transition to the replay buffer
self.replay_buffer.append_transition(transition)
# We get a sample of transition
transition = self.replay_buffer.sample_random_replay_batch(self.batch_size)
# Train network with this transition
if transition is not None:
loss, weight = self.dqn.train_q_network(transition)
# Every 25 steps, we update the target network
if self.num_steps_taken % 150 == 0:
self.dqn.update_target_network()
# Function that compute the reward
def compute_reward(self, distance_to_goal):
self.last_distance = distance_to_goal
if distance_to_goal < 0.1:
return 2 - distance_to_goal
return 1 - distance_to_goal
# Function to get the greedy action for a particular state
def get_greedy_action(self, state):
state_tensor = torch.unsqueeze(torch.tensor(state), 0)
predicted_values = self.dqn.q_network.forward(state_tensor).cpu().detach().numpy()
discrete_action = np.argmax(predicted_values)
# Store the discrete action
self.action = discrete_action
# Convert discrete action into continuous action
action = self.discrete_action_to_continuous(discrete_action)
return action