лабы / отчет нейронные сети 2 лаба
.docx
ФЕДЕРАЛЬНОЕ
АГЕНСТВО ВОЗДУШНОГО ТРАНСПОРТА
(РОСАВИАЦИЯ)
ФЕДЕРАЛЬНОЕ ГОСУДАРСТВЕННОЕ БЮДЖЕТНОЕ ОБРАЗОВАТЕЛЬНОЕ УЧРЕЖДЕНИЕ ВЫСШЕГО ОБРАЗОВАНИЯ
«МОСКОВСКИЙ ГОСУДАРСТВЕННЫЙ ТЕХНИЧЕСКИЙ УНИВЕРСИТЕТ ГРАЖДАНСКОЙ АВИАЦИИ» (МГТУ ГА)
Кафедра вычислительных машин, комплексов, сетей и систем.
Лабораторная работа защищена с оценкой ____________________
____________________
(подпись преподавателя, дата)
ЛАБОРАТОРНАЯ РАБОТА №2
по дисциплине «Методы машинного обучения и нейронные сети».
Тема: «Обучение с подкреплением с использованием Q-Learning для обучения алгоритма Cart Pole.»
Выполнила студентка группы ИС2-1
Магальник Екатерина Борисовна
Руководитель: Романчева Нина Ивановна
МОСКВА – 2024
Целью лабораторной работы является:
Получение практических навыков в области обучения с подкреплением через реализацию и анализ алгоритма Q-Learning на примере решения классической задачи Cart Pole, так же известной как обратный маятник на тележке.
Задание: разработать программу, которая реализует алгоритм Q-Learning для обучения агента Cart Pole
Изменить параметры среды, а также, проанализировать динамику обучения, при измененных данных
В выводе представить основные закономерности, выведенные на основе полученных данных.
Листинг:
import gym import numpy as np import math import matplotlib.pyplot as plt import pandas as pd class InvertedPendulumEnv(gym.Env): def __init__(self): super(InvertedPendulumEnv, self).__init__() self.gravity = 9.8 self.masscart = 1.0 self.masspole = 0.1 self.total_mass = self.masspole + self.masscart self.length = 0.5 # actually half the pole's length self.polemass_length = self.masspole * self.length self.force_mag = 10.0 self.tau = 0.02 # seconds between state updates # Angle at which to fail the episode self.theta_threshold_radians = 24 * 2 * np.pi / 360 self.x_threshold = 2.4 # Observation space high = np.array([self.x_threshold * 2, np.finfo(np.float32).max, self.theta_threshold_radians * 2, np.finfo(np.float32).max], dtype=np.float32) self.observation_space = gym.spaces.Box(-high, high, dtype=np.float32) # Action space self.action_space = gym.spaces.Discrete(2) self.seed() self.viewer = None self.state = None self.steps_beyond_done = None def seed(self, seed=None): self.np_random, seed = gym.utils.seeding.np_random(seed) return [seed] def step(self, action): assert self.action_space.contains(action), "%r (%s) invalid" % (action, type(action)) state = self.state x, x_dot, theta, theta_dot = state force = self.force_mag if action == 1 else -self.force_mag costheta = np.cos(theta) sintheta = np.sin(theta) temp = (force + self.polemass_length * theta_dot * theta_dot * sintheta) / self.total_mass thetaacc = (self.gravity * sintheta - costheta * temp) / ( self.length * (4.0 / 3.0 - self.masspole * costheta * costheta / self.total_mass)) xacc = temp - self.polemass_length * thetaacc * costheta / self.total_mass x = x + self.tau * x_dot x_dot = x_dot + self.tau * xacc theta = theta + self.tau * theta_dot theta_dot = theta_dot + self.tau * thetaacc self.state = (x, x_dot, theta, theta_dot) done = x < -self.x_threshold \ or x > self.x_threshold \ or theta < -self.theta_threshold_radians \ or theta > self.theta_threshold_radians done = bool(done) if not done: reward = 1.0 elif self.steps_beyond_done is None: # Pole just fell! self.steps_beyond_done = 0 reward = 1.0 else: if self.steps_beyond_done == 0: print("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.state = self.np_random.uniform(low=-0.05, high=0.05, size=(4,)) self.steps_beyond_done = None return np.array(self.state) def render(self, mode='human'): screen_width = 600 screen_height = 400 world_width = self.x_threshold * 2 scale = screen_width / world_width carty = 100 # TOP OF CART polewidth = 10.0 polelen = scale * (2 * self.length) cartwidth = 50.0 cartheight = 30.0 if self.viewer is None: from gym.envs.classic_control import rendering self.viewer = rendering.Viewer(screen_width, screen_height) l, r, t, b = -cartwidth / 2, cartwidth / 2, cartheight / 2, -cartheight / 2 axleoffset = cartheight / 4.0 cart = rendering.FilledPolygon([(l, b), (l, t), (r, t), (r, b)]) self.carttrans = rendering.Transform() cart.add_attr(self.carttrans) self.viewer.add_geom(cart) l, r, t, b = -polewidth / 2, polewidth / 2, polelen - polewidth / 2, -polewidth / 2 pole = rendering.FilledPolygon([(l, b), (l, t), (r, t), (r, b)]) pole.set_color(.8, .6, .4) self.poletrans = rendering.Transform(translation=(0, axleoffset)) pole.add_attr(self.poletrans) pole.add_attr(self.carttrans) self.viewer.add_geom(pole) self.axle = rendering.make_circle(polewidth / 2) self.axle.add_attr(self.poletrans) self.axle.add_attr(self.carttrans) self.axle.set_color(.5, .5, .8) self.viewer.add_geom(self.axle) self.track = rendering.Line((0, carty), (screen_width, carty)) self.track.set_color(0, 0, 0) self.viewer.add_geom(self.track) if self.state is None: return None x = self.state cartx = x[0] * scale + screen_width / 2.0 # MIDDLE OF CART self.carttrans.set_translation(cartx, carty) self.poletrans.set_rotation(-x[2]) return self.viewer.render(return_rgb_array=mode == 'rgb_array') def close(self): if self.viewer: self.viewer.close() self.viewer = None # Пример использования среды env = InvertedPendulumEnv() state = env.reset() for _ in range(1000): action = env.action_space.sample() # выбираем случайное действие (0 или 1) state, reward, done, _ = env.step(action) env.render() if done: state = env.reset() env.close() #Создаем среду CartPole env =gym.make('CartPole-v1') #Дискретизируем пространство состояний n_buckets =(1,1,6,3) # Интервалы дискретизации для положения скорости угла угловой скорсоти state_bounds=list(zip(env.observation_space.low,env.observation_space.high)) state_bounds[1]=[-0.5,0.5] state_bounds[3]=[-math.radians(50),math.radians(50)] #Инициализация Q-таблицы n_actions= env.action_space.n q_table=np.zeros(n_buckets+(n_actions,)) #Определение эпсилон жадной стратегии epsilon=lambda i: max(0.01,min(1,1.0-math.log10((i+1)/25))) #Определение скорсоти обучения alpha=lambda i: max(0.01,min(0.5,1.0-math.log10((i+1)/25))) gamma=0.99 #коэффицент дисконтирования #Функция для дискретизации непрерывного пространства состояний def discretize_state(obs): #Преобразование непрерывных значений состояний в дискретные индексы корзин ratios = [(obs[i] + abs(state_bounds[i][0])) / (state_bounds[i][1] - state_bounds[i][0]) for i in range(len(obs))] discretized_obs = [int(round((n_buckets[i]-1) * ratios[i])) for i in range(len(obs))] discretized_obs = [min(n_buckets[i]-1, max(0, discretized_obs[i])) for i in range(len(obs))] return tuple(discretized_obs) #Алгоритм Q-обучения num_episodes =5000 rewards_per_episode = [] epsilon_values=[] for episode in range(num_episodes): state=discretize_state(env.reset()) done=False total_reward = 0 while not done: #Выбор действий с помощью эпсилон жадной стратегии if np.random.random()<epsilon(episode): action=env.action_space.sample() else: action=np.argmax(q_table[state]) #Выбор действия с помощью эпсилон жадной стратегии next_state,reward,done,_=env.step(action) next_state=discretize_state(next_state) #Применение действия и наблюдение за следующим состоянием и наградой best_next_action=np.argmax(q_table[next_state]) q_table[state][action]+=alpha(episode) * (reward+gamma*q_table[next_state][best_next_action]-q_table[state][action]) state=next_state total_reward+=reward #Сохраниение значения эпсилон и общей награды для построения графиков epsilon_values.append(epsilon(episode)) rewards_per_episode.append(total_reward) #Вывод информации о эпизоде if (episode +1)%100 ==0: print("Episode:",episode+1) #Закрытие среды env.close #Построение графика значений эпсилон plt.plot(range(num_episodes),epsilon_values) plt.title('Epsilon Decay') plt.xlabel('Episode') plt.ylabel('Epsilon Value') plt.show() #Построение графика наград за эпизод plt.plot(range(num_episodes),rewards_per_episode) plt.title('Rewards per Episode') plt.xlabel('Episode') plt.ylabel('Total Reward') plt.show() #Создание DataFrame для Q-таблицы q_table_df=pd.DataFrame(q_table.reshape(-1,n_actions),columns=[f"Action{i}"for i in range(n_actions)]) q_table_df.index.name='State' print("\nQ-table:") print(q_table_df)
Результат работы программы:
Episode: 100
Episode: 200
Episode: 300
Episode: 400
Episode: 500
Episode: 600
Episode: 700
Episode: 800
Episode: 900
Episode: 1000
Episode: 1100
Episode: 1200
Episode: 1300
Episode: 1400
Episode: 1500
Episode: 1600
Episode: 1700
Episode: 1800
Episode: 1900
Episode: 2000
Episode: 2100
Episode: 2200
Episode: 2300
Episode: 2400
Episode: 2500
Episode: 2600
Episode: 2700
Episode: 2800
Episode: 2900
Episode: 3000
Episode: 3100
Episode: 3200
Episode: 3300
Episode: 3400
Episode: 3500
Episode: 3600
Episode: 3700
Episode: 3800
Episode: 3900
Episode: 4000
Episode: 4100
Episode: 4200
Episode: 4300
Episode: 4400
Episode: 4500
Episode: 4600
Episode: 4700
Episode: 4800
Episode: 4900
Episode: 5000
Q-table:
Action0 Action1
State
0 0.000000 0.000000
1 0.000000 0.000000
2 0.000000 0.000000
3 38.381778 43.847595
4 13.559164 39.706449
5 0.000000 0.000000
6 100.000000 99.950646
7 100.000000 100.000000
8 99.999998 100.000000
9 100.000000 99.999995
10 99.999992 100.000000
11 99.981829 100.000000
12 20.921553 0.000000
13 28.985966 17.738541
14 34.264361 29.158609
15 0.000000 0.000000
16 0.000000 0.000000
17 0.000000 0.000000
Вывод:
В ходе выполнения лабораторной работы мы получили практические навыки в области обучения с подкреплением через реализацию и анализ алгоритма Q-Learning на примере решения классической задачи Cart Pole, так же известной как обратный маятник на тележке. При 5000 эпизодах алгоритм перестает искать награду примерно после 200 эпизодах, но совершает попытки примерно до 4000 эпизодов. Можно заметить переобучение так как график эпсилон не доходит до нуля.
