1   2   3   4   5
Ім'я файлу: 2021_M_EOM_Suprunenko_M_Iu.pdf
Розширення: pdf
Розмір: 2211кб.
Дата: 30.05.2022
скачати
Пов'язані файли:
9._POKAZHCHIKI.doc
КОВИД КОРОНА.docx
104.doc
Лабораторная работа №1.docx
курсова робота Облік запасів (1).docx
Перескладання.docx
Лабораторна робота 2.docx
банковское страхование.docx
Стан ОП з розвитку музичних здібностей дітей.docx
Види конфіскації майна.docx
[UAReferats.com]_C39N1549.doc
Лекція 3.docx
являється тангенс.
Лістинг 3.2 – Клас нейроної мережі ігрового агента class GeeseNet(nn.Module):
def __init__(self):
super().__init__()
layers, filters = 12, 32
self.conv0 = TorusConv2d(17, filters, (3, 3), True)
self.blocks = nn.ModuleList([TorusConv2d(filters, filters, (3, 3),
True) for _ in range(layers)])
self.head_p = nn.Linear(filters, 4, bias=False)
self.head_v = nn.Linear(filters * 2, 1, bias=False)
def forward(self, x, _=None):
h = F.relu_(self.conv0(x))
for block in self.blocks:
h = F.relu_(h + block(h))
h_head = (h * x[:,:1]).view(h.size(0), h.size(1), -1).sum(-1)
h_
v}
Особливість архітектури нейронної мережі (рисунок 3.6) полягає у тому, що шари отримання політики та значення мають комплексне отримання особливостей з шарів остатків (residuals). Вони складаються з слою head extraction і head expansion. Таким чином, цей модуль перетворює
кожну клітинку, на якій знаходиться ігровий агент, в голову агенту, що дозволило нейронній мережі рахувати взаємодію між різними агентами і
зменшити шанси зіткнення із іншими агентами (змійками) на ігровому полі
(рисунок 3.7).

42
Рисунок 3.6 – Візуальне представлення повноцінної нейронної мережі для
ігрового агенту
Рисунок 3.7 – Візуальне представлення head extraction і head expansion

43
Для налаштування параметрів нейронної мережі використовуються конфігураційний файл config.yaml (лістинг 3.3). Головними параметрами є
розрахунок функції політики та функції значення за допомогою Monte Carlo
Search Tree і це указано в параметрах policy_target та value_target. Параметр batch_size означає розмір пакету, тобто кількість спостережень, які будуть використані під час тренування протягом однієї епохи. Gamma і lambda параметри вказуються на коефіцієнт регуляції L1 та L2 відповідно.
Лістинг 3.3 – Налаштування тренування нейронної мережі
train_args:
turn_based_training: False # always False for Hungry Geese observation: False gamma: 0.8
forward_steps: 32
compress_steps: 4
entropy_regularization: 2.0e-3
entropy_regularization_decay: 0.3
update_episodes: 500
batch_size: 400 # GPU memory 10GB
minimum_episodes: 100
maximum_episodes: 5000 # RAM 32GB
eval_rate: 0.1
epochs: 120
num_batchers: 7
worker:
num_parallel: 6
lambda: 0.7
policy_target: 'MC'
value_target: 'MC'
seed: 0
restart_epoch: 0 3.3 Реалізація тестового ігрового середовища
Реалізація тестового ігрового середовища представлена файлом environment.py і побудована на основі бібліотеки HandyRL, що спрощує
інтеграцію ігрового середовища і агентів. Дане середовище представлене в класі Environment.
Клас Environment наслідує клас BaseEnvironment з бібліотеки HandyRL.
BaseEnvironment надає спрощений інтерфейс представлення багатьох агентів на ігровому полі, і вказує,
які методи необхідно реалізувати для

44
використання даного класу. BaseEnvironment також виконує налаштування параметрів нейронної мережі та особливості тренування моделі в файлі
config.yaml.
Для наслідування класу BaseEnvironment реалізовано наступні методи:
- конструктор, який створює поле для ігри «Змійка» за допомогою бібліотеки kaggle_environments;
- метод rule_based_action, що відповідає за врегулювання дій до правил для агенту «Змійка»;
- метод observation, що виконує попередню обробку даних перед тренуванням нейронної мережі;
- метод step, що виконує прогнозовані дії від нейронної мережі для кожного агенту;
- метод turns, що виконує фільтрацію тільки активних агентів які
спроможні виконувати наступний крок;
- метод terminal, який виконує розрахунок того, чи може агент бути присутнім на ігровому полі;
- метод outcomes, що виконує розрахунок винагороди для кожного із агентів.
На початку класу задаються константні поля (лістинг 3.4), які
характеризують кількість агентів, поведінку агентів та матрицю зміщення агенту при виборі дії агенту.
ACTION відповідає за дії, що прийнята агентами після отримання результату від нейронної мережі.
Змінна DIRECTION – це матриця, де перше значення в рядку відповідає за зміщення по вертикалі, а друге значення – по горизонталі.
Наприклад, при виборі дії повернути направо, тобто дії «SOUTH», агент спуститься на одну клітинку вниз.
NUM_AGENTS відповідає за кількість агентів, які будуть створені на
ігровому полі.

45
Лістинг 3.4 – Константні поля в класі environment.py
ACTION = ['NORTH', 'SOUTH', 'WEST', 'EAST']
DIRECTION = [[-1, 0], [1, 0], [0, -1], [0, 1]]
NUM_AGENTS = 4
В конструкторі створюється ігрове середовище, що надано бібліотекою kaggle_environments (лістинг 3.5). Щоб створити ігрове середовище для агентів ігри «Змійка» передається назва «hungry_geese» в функцію make.
Дане середовище дозволяє створити ігрове поле та відображення агентів на
ігровому полі.
Лістинг 3.5 – Метод створення середовища def __init__(self, args={}):
super().__init__()
self.env = make("hungry_geese")
self.reset()
Дії агенту контролюються функцією rule_based_action (лістинг 3.6),
тому що отримана дія від нейронної мережі може відрізнятися від тих, які
прописані в правилах. Щоб уникнути даних ситуацій, використано клас
GreedyAgent який на вхід отримує останній крок та дію, що надана від ШНМ,
а на вихід отримується дія, яка регульована за правилам.
Лістинг 3.6 – Метод врегулювання дій агенту для ігр «Змійка» на основі
прогнозування дії від нейроної мережі
def rule_based_action(self, player):
from kaggle_environments.envs.hungry_geese.hungry_geese import
Observation, Configuration, Action, GreedyAgent action_map = {'N': Action.NORTH, 'S': Action.SOUTH, 'W': Action.WEST,
'E': Action.EAST}
agent = GreedyAgent(Configuration({'rows': 7, 'columns': 11}))
agent.last_action =
action_map[self.ACTION[self.last_actions[player]][0]] if player in self.last_actions else None obs = {**self.obs_list[-1][0]['observation'], **self.obs_list[-
1][player]['observation']} action = agent(Observation(obs))
return self.ACTION.index(action)

46
Функція observation (лістинг 3.7) відповідає за підготовку масиву даних для тренування нейронної мережі. Функція формує положення їжі на полі,
положення голови, тіла, хвоста на ігровому полі у вигляді матриці.
Сформована двомірна матриця подається у функцію net. Це сформована нейрона мережа GeeseNet на основі торусних згорток. Під час тренування
HandyRL автоматично включить метод observation до запланованих дій попередньої обробки даних перед тренуванням основної нейронної мережі.
Лістинг 3.7 – Метод врегулювання дій агенту для ігри «Змійка» на основі
прогнозування дії від нейронної мережі
def observation(self, player=None):
if player is None:
player = 0
b = np.zeros((self.NUM_AGENTS * 4 + 1, 7 * 11), dtype=np.float32)
obs = self.obs_list[-1][0]['observation']
for p, geese in enumerate(obs['geese']):
# head position for pos in geese[:1]:
b[0 + (p - player) % self.NUM_AGENTS, pos] = 1
# tip position for pos in geese[-1:]:
b[4 + (p - player) % self.NUM_AGENTS, pos] = 1
# whole position for pos in geese:
b[8 + (p - player) % self.NUM_AGENTS, pos] = 1
# previous head position if len(self.obs_list) > 1:
obs_prev = self.obs_list[-2][0]['observation']
for p, geese in enumerate(obs_prev['geese']):
for pos in geese[:1]:
b[12 + (p - player) % self.NUM_AGENTS, pos] = 1
# food for pos in obs['food']:
b[16, pos] = 1
return b.reshape(-1, 7, 11)
def net(self):
return GeeseNet
Метод turns (лістинг 3.8) відповідальний за те, щоб на ігровому полі
відображалися тільки активні агенти. Розрахунок поточного статусу агенту виконуються в функції terminal.

47
Лістинг 3.8 – Методи надання можливості виконання наступного кроку def turns(self):
# players to move return [p for p in self.players() if self.obs_list[-1][p]['status']
== 'ACTIVE']
def terminal(self):
# check whether terminal state or not for obs in self.obs_list[-1]:
if obs['status'] == 'ACTIVE':
return False return True
Оскільки «Змійка» є покроковою грою, кожна змійка повинна виконувати один крок вперед, і для виконання даного кроку потрібно оновити поле і це забезпечується в функції step (лістинг 3.9). Функція виконує перехід до наступної дії і відображає обновлений результат на
ігровому полі.
Лістинг 3.9 – Метод обновлення ігрового поля і перехід до наступної дії
def step(self, actions):
# state transition obs = self.env.step([self.action2str(actions.get(p, None) or 0) for p in self.players()])
self.update((obs, actions), False)
Функція outcome (лістинг 3.10) відповідає за остаточний результат і
робить розрахунок набраних фруктів для кожного агенту. Перемагає агент,
який зібрав найбільшу кількість фруктів.
HandyRL автоматично використовує дану функцію для інтерпретації результату нейронної мережі,
щоб покращити остаточні дії агенту.
Лістинг 3.10 – Метод розрахунку винаогороди для кожного агента def outcome(self):
# return terminal outcomes
# 1st: 1.0 2nd: 0.33 3rd: -0.33 4th: -1.00
rewards = {o['observation']['index']: o['reward'] for o in self.obs_list[-1]}

48
outcomes = {p: 0 for p in self.players()}
for p, r in rewards.items():
for pp, rr in rewards.items():
if p != pp:
if r > rr:
outcomes[p] += 1 / (self.NUM_AGENTS - 1)
elif r < rr:
outcomes[p] -= 1 / (self.NUM_AGENTS - 1)
return outcomes
Останнім етапом є запуск агентів в ігровому середовищі. Запуск програми виконується в файлі main.py (лістинг 3.11). Вона створює ігрове середовище для ігри «Змійка» та стартує роботу агентів в ігровому полі.
Лістинг 3.11 – Функція запуску ігрового середовища та агентів if __name__ == '__main__':
e = Environment()
for _ in range(200):
e.reset()
while not e.terminal():
print(e)
actions = {p: e.legal_actions(p) for p in e.turns()}
print([[e.action2str(a, p) for a in alist] for p, alist in actions.items()])
e.step({p: random.choice(alist) for p, alist in actions.items()})
print(e)
print(e.outcome())
В застосунок додано клас FloodfullResult. Алгоритм Floodfill дозволяє
виявити, які місця на ігровому полі є наявними для переходу в наступний стан (лістинг 3.12).
Лістинг 3.12 – Функція запуску ігрового середовища та агентів всередині
@dataclass class FloodfillResult:
field_dist: np.ndarray frontiers: List[List[Tuple[int, int]]]
def flood_fill(is_occupied: np.ndarray, seeds: List[Pos]) -> FloodfillResult:
"""
Flood will start with distance 0 at seeds and only flow where is_occupied[x,y]==0
"""
size_x, size_y = is_occupied.shape

49
field_dist = np.full(fill_value=-1, shape=(size_x, size_y))
frontier = [(s.x, s.y) for s in seeds]
frontiers = [frontier]
for seed in seeds:
field_dist[seed] = 0
dist = 1
while frontier:
new_frontier: List[Tuple[int, int]] = []
for x, y in frontier:
for dx, dy in [(0, 1), (0, -1), (1, 0), (-1, 0)]:
new_x = (x + dx) % size_x new_y = (y + dy) % size_y if is_occupied[new_x, new_y] == 0 and field_dist[new_x,
new_y] == -1:
field_dist[new_x, new_y] = dist new_frontier.append((new_x, new_y))
frontier = new_frontier frontiers.append(frontier)
dist += 1
return FloodfillResult(field_dist=field_dist, frontiers=frontiers)
def get_dist(
floodfill_result: FloodfillResult, test_func: Callable[[Tuple[int, int]],
bool]
) -> Optional[int]:
for dist, frontier in enumerate(floodfill_result.frontiers):
for pos in frontier:
if test_func(pos):
return dist return None
Алгоритм визначає, якщо клітинка занята другим агентом, то поточна змійка виконує крок в іншу сторону і планує кроки до 4 навколишніх точок,
пока всі клітинки не будуть дослідженими.

50 4 АНАЛІЗ РЕЗУЛЬТАТІВ ЕКСПЕРИМЕНТАЛЬНИХ ДОСЛІДЖЕНЬ
4.1 Порівняння статичних та адаптивних ігрових агентів
Дослідження ефективності роботи адаптивного ігрового клієнта проводилося на основі значень метрик, що зібрані під час навчання нейронної мережі. Для дослідження використовувалися статичні та адаптивні
агенти штучного ігрового інтелекту.
Побудовано графік залежності кількості перемог створеного агенту з агентом побудованим на правилах (рисунок 4.1), від кількості зіграних партій, що використані для навчання агенту. Rulebase модель представляє
собою найменш ефективну статичну модель. Це простий агент, який тільки націлений збір фруктів. Графік надає інформацію, що після проведення більше 20 000 ігор адаптивний агент, здатний перемагати статичний інтелект майже в кожній грі (вірогідність перемоги близько 100%).
Також побудовано графік залежності перемоги агенту, створеного з використанням генетичного алгоритму
(рисунок
4.1). Shared модель представляє собою найменш ефективну адаптивну модель. Адаптивний
ігровий агент, побудований з використанням генетичного алгоритму показує
значно кращий результат, ніж алгоритм побудований на правилах, але програє алгоритму створеного в ході кваліфікаційної роботи. Згідно графіку створений агент має 70 відсотків шансу перемоги при проведені 40000
зіграних ігор з агентом, побудованим на основі генетичного алгоритму.
40000 є оптимальною кількістю проведених ігор з агентом, для отримання достатнього досвіду для представлення фінального результату.
Подальше навчання моделі є недоцільним з точки зору споживання комп’ютерних ресурсів. Щоб покращити шанс перемоги створеного агенту з
0.7 до 0.8 відсотків, потребувалося в 4 рази більше часу навчання моделі. Це показує, що модель досягла стабільного результату і щоб покращити шанс

51
перемоги моделі необхідно розглянути нові підходи до вирішення проблем створення ігрового агенту. Також необхідна додаткова зміна параметрів, для отримання нового результату.
Рисунок 4.1 – Графік залежності Rulebase-агенту та Shared-агенту
Для наступного дослідження на тестове ігрове поле було добавлено 3
сторонні агенти, ігровий штучний інтелект яких побудований на основі таких підходів:
- жадібна політика та нейронна мережа на основі згорткових шарів;
- жадібна політики зі схильністю використовувати ризик та нейронна мережа на основі згорткових шарів;
- генетичний алгоритм.
Агенти, що використані у ході дослідження, представлені в ігровому середовищі на платформі Kaggle і мають можливість взаємодії між собою. У
ході дослідження агенти могли виконувати до 200 кроків, і вигравав той агент, який зібрав найбільшу кількість фруктів.

52
Порівняння графіків залежності кількості виграних ігор від кількості
зіграних партій наведено на рисунку 4.2. Для згладжування графіка було використано ковзна середня функція на 10, 25, 100 епохах. Згідно графіку
ігровий агент має середній шанс перемоги приблизно 60 відсотків.
Максимальний шанс перемоги був оцінений в 65 відсотків, а мінімальне значення шансу дорівнює 55 відсоткам. Також графік надає інформацію, що для досягання стабільного результату в 60 відсотків потрібно не більше 1000
епох. Це означає, що нейрона мережа досягає прийнятного результату саме при такому значенні і для покращення результату потрібно виконати додаткові дії по оптимізації алгоритму.
Рисунок 4.2 – Функція запуску ігрового середовища та агентів всередині
Також було проведено 2 дослідження для оцінки роботи створеного агенту. Перше дослідження – це створення 2 агентів на полі: нового агенту
(Smart Geese) та найбільш популярних статичних агентів на платформі
Kaggle. Розглянемо ефективність роботи у порівнянні з агентами із статичним ігровим інтелектом (таблиця 4.1).

53
Таблиця 4.1 – Ефективність роботи у порівнянні з агентами із статичним
ігровим інтелектом
Назва суперника
Опис
Ймовірність перемоги
Smart Geese simple_toward
Простий агент, який тільки націлений збір фруктів
96%
greedy
Жадібний агент
91%
risk_averse_greedy
Жадібний агент, який не схильний до ризику
(позначає всі клітини, які
можуть бути небезпечними на наступному кроці, як перешкоди)
94%
simple_bfs
Великий список евристик для уникнення перешкод
95%
crazy_goose
Жадібний агент, який не схильний до ризику
(позначає всі клітини, які
можуть бути небезпечними на наступному кроці, як перешкоди) та має
великий список евристик для уникнення перешкод
82%
Також результати проведених ігор зібрані у формі heatmap (рисунок
4.3):

54
Рисунок 4.3 – Heatmap ймовірності перемоги агентів
Для ускладнення ігрового процесу, створено 3 агентів на основі
статичного
ігрового
інтелекту проти агенту, створеного в ході
кваліфікаційної роботи (таблиця 4.2).
Таблиця 4.2 – Порівняльна таблиця існуючих рішень по створенню штучного
інтелекту для ігри «Змійка»
Назва суперника
Опис
Ймовірність перемоги Smart
Geese simple_toward
Простий агент який тільки націлений збір фруктів
96%
greedy
Жадібний агент
89%

55
Продовження таблиці 4.2
risk_averse_greedy
Жадібний агент, який не схильний до ризику (позначає всі клітини, які можуть бути небезпечними на наступному кроці,
як перешкоди)
82%
simple_bfs
Великий список евристик для уникнення перешкод
98%
crazy_goose
Жадібний агент який не схильний до ризику (позначає всі клітини, які можуть бути небезпечними на наступному кроці,
як перешкоди) та має великий список евристик для уникнення перешкод
79%
Також результати проведених ігор зібраних у формі heatmap (рисунок
4.4).
Рисунок 4.4 – Heatmap ймовірності перемоги агентів

56
Згідно отриманих результатів,
новий агент показує незначне погіршення результатів порівняно з попереднім дослідженням, де було представлено тільки два агенти. Жадібні агенти, які не схильні до ризику,
мають значно більшу кількість правил, які націлені на уникнення колізії з
іншими змійками, порівняно з іншими статичними ігровими агентами, тому вони показують значно кращий результат порівняно з простим агентом, який тільки націлений збір фруктів, жадібним інтелектом та інтелектом з великою кількістю евристик. Більшисть алгоритмів, які націлені на ризик, мають значно менші шанси на виживання.
Проведено дослідження ефективності створеного агенту з динамічним

1   2   3   4   5

скачати

© Усі права захищені
написати до нас