DQN дрожит во время учебы
я просто хочу, чтобы продолжить свое образование в области нейронных сетей и в настоящее время нахожусь в процессе проектирования свой собственный сценарий на основе на cartpole примере ( cartpole тренажерный зал-окр). Я использую tenorflow с пакетом Huskarl и средой спортзала.
Я создал свою среду. Это одномерное поле фиксированного размера (10). На одном из них яблоко, а на другом агент (оба случайные при запуске). Его цель - пройти прямо к яблоку и не покинуть 1D-поле. Его возможные действия - влево или вправо. Если он дошел до поля с яблоком, яблоко помещается на новое поле (случайное поле (!= Поле агента)). Собственная позиция агентов и позиция яблока служат входными данными.
К сожалению, NN на самом деле не учится, но, кажется, снова и снова учится правильным и неправильным шагам (см. График шаг-вознаграждение). Я пробовал разные слои NN и награды в зависимости от расстояния до цели, но, к сожалению, безуспешно. Такое ощущение, что неправильно награждаю агента, но точно сказать не могу. У кого-нибудь есть подсказка, где я могу сделать ошибку?
Вот мой код запуска:
from tensorflow.python.keras.models import Sequential
from tensorflow.python.keras.layers import Dense
import matplotlib.pyplot as plt
import gym
import huskarl as hk
from OneD_Env import OneD_Env
if __name__ == '__main__':
create_env = lambda: OneD_Env()
dummy_env = create_env()
model = Sequential([
Dense(16, activation='relu', input_shape=dummy_env.observation_space.shape),
Dense(16, activation='relu'),
Dense(16, activation='relu')
])
agent = hk.agent.DQN(model, actions=dummy_env.action_space.n, nsteps=2)
def plot_rewards(episode_rewards, episode_steps, done=False):
plt.clf()
plt.xlabel('Step')
plt.ylabel('Reward')
for ed, steps in zip(episode_rewards, episode_steps):
plt.plot(steps, ed)
plt.show() if done else plt.pause(0.001) # Pause a bit so that the graph is updated
sim = hk.Simulation(create_env, agent)
sim.train(max_steps=10000, visualize=True, plot=plot_rewards)
и моя индивидуальная среда
import math
import gym
from gym import spaces, logger
from gym.utils import seeding
import numpy as np
import random
class OneD_Env(gym.Env):
metadata = {
'render.modes': ['human', 'rgb_array'],
'video.frames_per_second' : 50
}
def __init__(self):
self.boardSize = 10
self.board = np.zeros((self.boardSize), dtype=int)
self.apple_pos_x = 0
self.my_pos_x = 0
self.stepCount = 0
self.maxSteps = 0
input_low = np.array([
0, # my position
0 # apple position
])
input_high = np.array([
self.boardSize-1,
self.boardSize-1
])
self.action_space = spaces.Discrete(2)
self.observation_space = spaces.Box(-input_high, input_high, dtype=np.int)
self.viewer = None
self.state = None
self.steps_beyond_done = None
def getDistance(self):
a = self.my_pos_x
b = self.apple_pos_x
if a > b: return a - b
else : return b - a
def step(self, action):
assert self.action_space.contains(action), "%r (%s) invalid"%(action, type(action))
self.stepCount += 1
if action == 0: #right
self.my_pos_x += 1
else: #left
self.my_pos_x -= 1
done = False
staysOnApple = bool(self.my_pos_x == self.apple_pos_x)
if staysOnApple:
self.apple_pos_x = random.randint(0, self.boardSize-1)
if self.my_pos_x == self.apple_pos_x:
if self.apple_pos_x == self.boardSize-1:
self.apple_pos_x -= 1
else:
self.apple_pos_x += 1
self.stepCount = 0
self.maxSteps = self.getDistance()
else:
if self.my_pos_x < 0 or self.my_pos_x >= self.boardSize or self.stepCount > self.maxSteps:
done = True
self.state = (self.my_pos_x, self.apple_pos_x)
reward = 0.0
if not done:
reward = 1.0
elif self.steps_beyond_done is None:
self.steps_beyond_done = 0
reward = 1.0
else:
if self.steps_beyond_done == 0:
logger.warn("You are calling 'step()' even though this environment has already returned done = True. You should always call 'reset()' once you receive 'done = True' -- any further steps are undefined behavior.")
self.steps_beyond_done += 1
reward = 0.0
return np.array(self.state), reward, done, {}
def reset(self):
self.apple_pos_x = random.randint(0, self.boardSize-1)
self.my_pos_x = random.randint(0, self.boardSize-1)
if self.my_pos_x == self.apple_pos_x:
if self.apple_pos_x == self.boardSize-1:
self.apple_pos_x -= 1
else:
self.apple_pos_x += 1
self.maxSteps = self.getDistance()
self.stepCount = 0
self.steps_beyond_done = None
self.state = (self.my_pos_x, self.apple_pos_x)
return np.array(self.state)
def render(self, mode='human'):
screen_width = 700
screen_height = 700
size = 60
if self.viewer is None:
from gym.envs.classic_control import rendering
self.viewer = rendering.Viewer(screen_width, screen_height)
for x in range(self.boardSize):
poly = rendering.FilledPolygon([
(50 + (x * size -28), 50 + ( +28)),
(50 + (x * size -28), 50 + ( -28)),
(50 + (x * size +28), 50 + ( -28)),
(50 + (x * size +28), 50 + ( +28))
])
poly.set_color(.9, .9, .9)
self.viewer.add_geom(poly)
my = rendering.FilledPolygon([
(-5, 5),
(-5, -5),
(5, -5),
(5, 5)
])
apple = rendering.FilledPolygon([
(-5, 5),
(-5, -5),
(5, -5),
(5, 5)
])
my.set_color(.1, .1, .1)
apple.set_color(.8, .2, .2)
self.myTrans = rendering.Transform()
my.add_attr(self.myTrans)
self.appleTrans = rendering.Transform()
apple.add_attr(self.appleTrans)
self.viewer.add_geom(my)
self.viewer.add_geom(apple)
if self.state is None: return None
self.myTrans.set_translation(50 + self.my_pos_x * size, 50)
self.appleTrans.set_translation(50 + self.apple_pos_x * size, 50)
return self.viewer.render(return_rgb_array = mode=='rgb_array')
def close(self):
if self.viewer:
self.viewer.close()
self.viewer = None