Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

лабы / отчет нейронные сети 2 лаба

.docx
Скачиваний:
0
Добавлен:
11.02.2026
Размер:
143.57 Кб
Скачать

ФЕДЕРАЛЬНОЕ АГЕНСТВО ВОЗДУШНОГО ТРАНСПОРТА

(РОСАВИАЦИЯ)

ФЕДЕРАЛЬНОЕ ГОСУДАРСТВЕННОЕ БЮДЖЕТНОЕ ОБРАЗОВАТЕЛЬНОЕ УЧРЕЖДЕНИЕ ВЫСШЕГО ОБРАЗОВАНИЯ

«МОСКОВСКИЙ ГОСУДАРСТВЕННЫЙ ТЕХНИЧЕСКИЙ УНИВЕРСИТЕТ ГРАЖДАНСКОЙ АВИАЦИИ» (МГТУ ГА)

Кафедра вычислительных машин, комплексов, сетей и систем.

Лабораторная работа защищена с оценкой ____________________

____________________

(подпись преподавателя, дата)

ЛАБОРАТОРНАЯ РАБОТА №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 эпизодов. Можно заметить переобучение так как график эпсилон не доходит до нуля.