1. Прежде чем начать
Удивительный прорыв AlphaGo и AlphaStar продемонстрировал потенциал использования машинного обучения для создания игровых агентов сверхчеловеческого уровня. Создание небольшой игры на базе машинного обучения — это увлекательное упражнение, позволяющее приобрести навыки, необходимые для создания мощных игровых агентов.
В этой лаборатории вы узнаете, как создать настольную игру, используя:
- Агент TensorFlow для обучения игрового агента с помощью обучения с подкреплением
- TensorFlow служит для обслуживания модели
- Flutter создаст кроссплатформенное приложение для настольных игр
Предварительные условия
- Базовые знания разработки Flutter с помощью Dart.
- Базовые знания машинного обучения с TensorFlow, например, обучение или развертывание.
- Базовые знания Python, терминалов и Docker.
Что вы узнаете
- Как обучить агента неигрового персонажа (NPC) с помощью агентов TensorFlow
- Как обслуживать обученную модель с помощью TensorFlow Serving
- Как создать кроссплатформенную настольную игру Flutter
Что вам понадобится
- Флаттер SDK
- Настройка Android и iOS для Flutter
- Настройка рабочего стола для Flutter
- Веб -настройка для Flutter
- Настройка кода Visual Studio (VS Code) для Flutter и Dart
- Докер
- Баш
- Питон 3.7+
2. Игра «Самолетный удар»
Игра, которую вы создадите в этой кодовой лаборатории, называется «Plane Strike» — небольшая настольная игра для двух игроков, напоминающая настольную игру «Морской бой» . Правила очень просты:
- Игрок-человек играет против агента NPC, обученного машинным обучением. Игрок-человек может начать игру, коснувшись любой ячейки на доске агента.
- В начале игры у игрока-человека и у агента есть объект «плоскость» (8 зеленых ячеек, образующих «плоскость», как вы можете видеть на доске игрока-человека в анимации ниже) на своих досках; эти «самолеты» располагаются случайным образом и видны только владельцам доски и скрыты для их противников.
- Игрок-человек и агент по очереди наносят удары по одной клетке доски друг друга. Игрок-человек может коснуться любой ячейки на доске агента, а агент автоматически сделает выбор на основе прогнозов модели машинного обучения. Попытавшаяся ячейка становится красной, если это «плоская» ячейка («попадание»); в противном случае он становится желтым («промахивается»).
- Тот, кто первым наберет 8 красных клеток, выигрывает игру; затем игра возобновляется с новыми досками.
Вот пример игрового процесса:
3. Настройте среду разработки Flutter.
Для разработки Flutter вам понадобятся две части программного обеспечения для выполнения этой лаборатории — Flutter SDK и редактор .
Вы можете запустить кодовую лабораторию, используя любое из этих устройств:
- Симулятор iOS (требуется установка инструментов Xcode).
- Эмулятор Android (требуется установка в Android Studio).
- Браузер (для отладки необходим Chrome).
- В качестве настольного приложения для Windows , Linux или macOS . Вы должны разрабатывать на платформе, на которой планируете развернуть. Итак, если вы хотите разработать настольное приложение для Windows, вам необходимо разработать его в Windows, чтобы получить доступ к соответствующей цепочке сборки. Существуют требования, специфичные для операционной системы, которые подробно описаны на docs.flutter.dev/desktop .
4. Настройте
Чтобы загрузить код для этой лаборатории кода:
- Перейдите в репозиторий GitHub для этой лаборатории кода.
- Нажмите «Код» > «Загрузить zip» , чтобы загрузить весь код для этой лаборатории кода.
- Разархивируйте загруженный zip-файл, чтобы распаковать
codelabs-main
со всеми необходимыми ресурсами.
Для этой лаборатории кода вам понадобятся только файлы в подкаталоге tfagents-flutter/
репозитория, который содержит несколько папок:
- Папки
step0
поstep6
содержат начальный код, который вы используете для каждого шага этой лаборатории кода. -
finished
папка содержит готовый код готового примера приложения. - Каждая папка содержит подпапку
backbend
, которая включает в себя внутренний код, и подпапкуfrontend
, которая включает в себя код внешнего интерфейса Flutter.
5. Загрузите зависимости для проекта.
Бэкэнд
Откройте терминал и перейдите в подпапку tfagents-flutter
. Запустите следующее:
pip install -r requirements.txt
Внешний интерфейс
- В VS Code нажмите «Файл» > «Открыть папку» , а затем выберите папку
step0
из исходного кода, который вы скачали ранее. - Откройте файл
step0/frontend/lib/main.dart
. Если вы увидите диалоговое окно VS Code, предлагающее загрузить необходимые пакеты для начального приложения, нажмите « Получить пакеты» . - Если вы не видите это диалоговое окно, откройте терминал и затем запустите команду
flutter pub get
в папкеstep0/frontend
.
6. Шаг 0. Запустите стартовое приложение.
- Откройте файл
step0/frontend/lib/main.dart
в VS Code, убедитесь, что эмулятор Android или симулятор iOS правильно настроен и отображается в строке состояния.
Например, вот что вы видите при использовании Pixel 5 с эмулятором Android:
Вот что вы видите, когда используете iPhone 13 с симулятором iOS:
- Нажмите Запустите отладку .
Запустите и изучите приложение
Приложение должно запуститься на вашем эмуляторе Android или симуляторе iOS. Пользовательский интерфейс довольно прост. Есть 2 игровые доски; игрок-человек может использовать любую ячейку на доске агента вверху в качестве позиции для удара. Вы научите умного агента автоматически предсказывать, куда нанести удар, основываясь на доске игрока-человека.
Под капотом приложение Flutter отправляет текущую доску игрока-человека на серверную часть, которая запускает модель обучения с подкреплением и возвращает прогнозируемую позицию ячейки для следующего удара. Интерфейс отобразит результат в пользовательском интерфейсе после получения ответа.
Если вы сейчас щелкнете любую ячейку на доске агента, ничего не произойдет, поскольку приложение еще не может взаимодействовать с серверной частью.
7. Шаг 1. Создайте среду Python для агентов TensorFlow Agents.
Основная цель этой лаборатории — разработать агент, который обучается путем взаимодействия со средой. Хотя игра Plane Strike относительно проста и в ней можно вручную создавать правила для агента NPC, вы используете обучение с подкреплением для обучения агента, чтобы вы освоили навыки и могли легко создавать агентов для других игр в будущем.
В стандартной настройке обучения с подкреплением (RL) агент получает наблюдение на каждом временном шаге и выбирает действие. Действие применяется к окружающей среде, и среда возвращает награду и новое наблюдение. Агент обучает политику выбора действий для максимизации суммы вознаграждения, также известной как доход. Играя в игру много-много раз, агент может изучить закономерности и отточить свои навыки, чтобы овладеть игрой. Чтобы сформулировать игру Plane Strike как задачу RL, подумайте о состоянии доски как о наблюдении, о позиции удара как о действии, а о сигнале попадания/промаха как о награде.
Для обучения агента NPC вы используете агенты TensorFlow — надежную, масштабируемую и простую в использовании библиотеку обучения с подкреплением для TensorFlow.
TF Agents отлично подходит для обучения с подкреплением, поскольку включает в себя обширный набор лабораторных работ по коду, примеров и обширной документации, которая поможет вам начать работу. Вы можете использовать агенты TF для решения реалистичных и сложных проблем RL с возможностью масштабирования и быстрой разработки новых алгоритмов RL. Вы можете легко переключаться между различными агентами и алгоритмами для экспериментов. Он также хорошо протестирован и прост в настройке.
В OpenAI Gym реализовано множество готовых игровых сред (например, игры Atari), Mujuco и т. д., которые агенты TF могут легко использовать. Но поскольку игра Plane Strike представляет собой полностью пользовательскую игру, вам необходимо сначала реализовать новую среду с нуля.
Чтобы реализовать среду Python Agents TF, вам необходимо реализовать следующие методы:
class YourGameEnv(py_environment.PyEnvironment): def __init__(self): """Initialize environment.""" def action_spec(self): """Return action_spec.""" def observation_spec(self): """Return observation_spec.""" def _reset(self): """Return initial_time_step.""" def _step(self, action): """Apply action and return new time_step."""
Наиболее важной из них является функция _step()
, которая выполняет действие и возвращает новый объект time_step
. В случае с игрой Plane Strike у вас есть игровое поле; когда появляется новая позиция для удара, в зависимости от состояния игрового поля окружающая среда определяет:
- Как дальше должно выглядеть игровое поле (должна ли ячейка изменить свой цвет на красный или желтый, учитывая местоположение скрытой плоскости?)
- Какую награду должен получить игрок за эту позицию (награда за попадание или штраф за промах?)
- Если игра прекратится (кто-нибудь выиграл?)
- Добавьте следующий код в функцию
_step()
в файл_planestrike_py_environment.py
:
if self._hit_count == self._plane_size: self._episode_ended = True return self.reset() if self._strike_count + 1 == self._max_steps: self.reset() return ts.termination( np.array(self._visible_board, dtype=np.float32), UNFINISHED_GAME_REWARD ) self._strike_count += 1 action_x = action // self._board_size action_y = action % self._board_size # Hit if self._hidden_board[action_x][action_y] == HIDDEN_BOARD_CELL_OCCUPIED: # Non-repeat move if self._visible_board[action_x][action_y] == VISIBLE_BOARD_CELL_UNTRIED: self._hit_count += 1 self._visible_board[action_x][action_y] = VISIBLE_BOARD_CELL_HIT # Successful strike if self._hit_count == self._plane_size: # Game finished self._episode_ended = True return ts.termination( np.array(self._visible_board, dtype=np.float32), FINISHED_GAME_REWARD, ) else: self._episode_ended = False return ts.transition( np.array(self._visible_board, dtype=np.float32), HIT_REWARD, self._discount, ) # Repeat strike else: self._episode_ended = False return ts.transition( np.array(self._visible_board, dtype=np.float32), REPEAT_STRIKE_REWARD, self._discount, ) # Miss else: # Unsuccessful strike self._episode_ended = False self._visible_board[action_x][action_y] = VISIBLE_BOARD_CELL_MISS return ts.transition( np.array(self._visible_board, dtype=np.float32), MISS_REWARD, self._discount,
8. Шаг 2. Обучите игровой агент с помощью агентов TensorFlow.
Имея среду TF Agents, вы можете обучать игрового агента. Для этой лаборатории кода вы используете агент REINFORCE. REINFORCE — это алгоритм градиента политики в RL. Его основная идея состоит в том, чтобы корректировать параметры нейронной сети политики на основе сигналов вознаграждения, собранных во время игры, чтобы сеть политики могла максимизировать отдачу в будущих играх.
- Во-первых, вам необходимо создать экземпляры сред обучения и оценки. Добавьте этот код в функцию
train_agent()
в файлеstep2/backend/training.py
:
train_py_env = planestrike_py_environment.PlaneStrikePyEnvironment( board_size=BOARD_SIZE, discount=DISCOUNT, max_steps=BOARD_SIZE**2 ) eval_py_env = planestrike_py_environment.PlaneStrikePyEnvironment( board_size=BOARD_SIZE, discount=DISCOUNT, max_steps=BOARD_SIZE**2 ) train_env = tf_py_environment.TFPyEnvironment(train_py_env) eval_env = tf_py_environment.TFPyEnvironment(eval_py_env)
- Далее вам нужно создать агент обучения с подкреплением, который будет обучен. В этой лаборатории кода вы используете агент REINFORCE, который является агентом на основе политик. Добавьте этот код прямо под приведенным выше кодом:
actor_net = tfa.networks.Sequential( [ tfa.keras_layers.InnerReshape([BOARD_SIZE, BOARD_SIZE], [BOARD_SIZE**2]), tf.keras.layers.Dense(FC_LAYER_PARAMS, activation="relu"), tf.keras.layers.Dense(BOARD_SIZE**2), tf.keras.layers.Lambda(lambda t: tfp.distributions.Categorical(logits=t)), ], input_spec=train_py_env.observation_spec(), ) optimizer = tf.keras.optimizers.Adam(learning_rate=LEARNING_RATE) train_step_counter = tf.Variable(0) tf_agent = reinforce_agent.ReinforceAgent( train_env.time_step_spec(), train_env.action_spec(), actor_network=actor_net, optimizer=optimizer, normalize_returns=True, train_step_counter=train_step_counter, )
- Наконец, обучите агента в цикле обучения. В цикле вы сначала собираете в буфер несколько эпизодов игрового процесса, а затем обучаете агента с помощью буферизованных данных. Добавьте этот код в функцию
train_agent()
в файлеstep2/backend/training.py
:
# Collect a few episodes using collect_policy and save to the replay buffer. collect_episode( train_py_env, collect_policy, COLLECT_EPISODES_PER_ITERATION, replay_buffer_observer, ) # Use data from the buffer and update the agent's network. iterator = iter(replay_buffer.as_dataset(sample_batch_size=1)) trajectories, _ = next(iterator) tf_agent.train(experience=trajectories) replay_buffer.clear()
- Теперь вы можете приступить к обучению. В своем терминале перейдите в папку
step2/backend
на своем компьютере и запустите:
python training.py
Завершение обучения занимает 8–12 часов, в зависимости от конфигурации вашего оборудования (вам не обязательно завершать все обучение самостоятельно, поскольку на step3
предоставляется предварительно обученная модель). Тем временем вы можете следить за прогрессом с помощью TensorBoard . Откройте новый терминал, перейдите в папку step2/backend
на вашем компьютере и запустите:
tensorboard --logdir tf_agents_log/
tf_agents_log
— это папка, содержащая журнал обучения. Пример тренировочного запуска выглядит следующим образом:
Вы можете видеть, что по мере прохождения обучения средняя продолжительность эпизода уменьшается, а средняя доходность увеличивается. Интуитивно вы можете понять, что если агент умнее и делает лучшие прогнозы, продолжительность игры становится короче, и агент получает больше вознаграждений. Это имеет смысл, поскольку агент хочет закончить игру за меньшее количество шагов, чтобы свести к минимуму значительную скидку на вознаграждение на последующих этапах.
После завершения обучения обученная модель экспортируется в папку policy_model
.
9. Шаг 3. Разверните обученную модель с помощью TensorFlow Serving.
Теперь, когда вы обучили игровой агент, вы можете развернуть его с помощью TensorFlow Serving.
- В своем терминале перейдите в папку
step3/backend
на своем компьютере и запустите TensorFlow Serving с Docker:
docker run -t --rm -p 8501:8501 -p 8500:8500 -v "$(pwd)/backend/policy_model:/models/policy_model" -e MODEL_NAME=policy_model tensorflow/serving
Docker сначала автоматически загружает образ TensorFlow Serving, что занимает минуту. После этого должно начаться обслуживание TensorFlow. Журнал должен выглядеть следующим образом:
2022-05-30 02:38:54.147771: I tensorflow_serving/model_servers/server.cc:89] Building single TensorFlow model file config: model_name: policy_model model_base_path: /models/policy_model 2022-05-30 02:38:54.148222: I tensorflow_serving/model_servers/server_core.cc:465] Adding/updating models. 2022-05-30 02:38:54.148273: I tensorflow_serving/model_servers/server_core.cc:591] (Re-)adding model: policy_model 2022-05-30 02:38:54.262684: I tensorflow_serving/core/basic_manager.cc:740] Successfully reserved resources to load servable {name: policy_model version: 123} 2022-05-30 02:38:54.262768: I tensorflow_serving/core/loader_harness.cc:66] Approving load for servable version {name: policy_model version: 123} 2022-05-30 02:38:54.262787: I tensorflow_serving/core/loader_harness.cc:74] Loading servable version {name: policy_model version: 123} 2022-05-30 02:38:54.265010: I external/org_tensorflow/tensorflow/cc/saved_model/reader.cc:38] Reading SavedModel from: /models/policy_model/123 2022-05-30 02:38:54.277811: I external/org_tensorflow/tensorflow/cc/saved_model/reader.cc:90] Reading meta graph with tags { serve } 2022-05-30 02:38:54.278116: I external/org_tensorflow/tensorflow/cc/saved_model/reader.cc:132] Reading SavedModel debug info (if present) from: /models/policy_model/123 2022-05-30 02:38:54.280229: I external/org_tensorflow/tensorflow/core/platform/cpu_feature_guard.cc:142] This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN) to use the following CPU instructions in performance-critical operations: AVX2 FMA To enable them in other operations, rebuild TensorFlow with the appropriate compiler flags. 2022-05-30 02:38:54.332352: I external/org_tensorflow/tensorflow/cc/saved_model/loader.cc:206] Restoring SavedModel bundle. 2022-05-30 02:38:54.337000: I external/org_tensorflow/tensorflow/core/platform/profile_utils/cpu_utils.cc:114] CPU Frequency: 2193480000 Hz 2022-05-30 02:38:54.402803: I external/org_tensorflow/tensorflow/cc/saved_model/loader.cc:190] Running initialization op on SavedModel bundle at path: /models/policy_model/123 2022-05-30 02:38:54.410707: I external/org_tensorflow/tensorflow/cc/saved_model/loader.cc:277] SavedModel load for tags { serve }; Status: success: OK. Took 145695 microseconds. 2022-05-30 02:38:54.412726: I tensorflow_serving/servables/tensorflow/saved_model_warmup_util.cc:59] No warmup data file found at /models/policy_model/123/assets.extra/tf_serving_warmup_requests 2022-05-30 02:38:54.417277: I tensorflow_serving/core/loader_harness.cc:87] Successfully loaded servable version {name: policy_model version: 123} 2022-05-30 02:38:54.419846: I tensorflow_serving/model_servers/server_core.cc:486] Finished adding/updating models 2022-05-30 02:38:54.420066: I tensorflow_serving/model_servers/server.cc:367] Profiler service is enabled 2022-05-30 02:38:54.428339: I tensorflow_serving/model_servers/server.cc:393] Running gRPC ModelServer at 0.0.0.0:8500 ... [warn] getaddrinfo: address family for nodename not supported 2022-05-30 02:38:54.431620: I tensorflow_serving/model_servers/server.cc:414] Exporting HTTP/REST API at:localhost:8501 ... [evhttp_server.cc : 245] NET_LOG: Entering the event loop ...
Вы можете отправить образец запроса на конечную точку, чтобы убедиться, что он работает должным образом:
curl -d '{"signature_name":"action","instances":[{"0/discount":0.0,"0/observation":[[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]],"0/reward":0.0,"0/step_type":0}]}' -X POST http://localhost:8501/v1/models/policy_model:predict
Конечная точка вернет прогнозируемую позицию 45
, то есть (5, 5) в центре доски (любопытные могут попытаться выяснить, почему центр доски является хорошим предположением для позиции первого удара).
{ "predictions": [45] }
Вот и все! Вы успешно создали серверную часть для прогнозирования позиции следующего удара для агента NPC.
10. Шаг 4. Создайте приложение Flutter для Android и iOS.
Бэкэнд готов. Вы можете начать отправлять ему запросы для получения прогнозов позиции удара из приложения Flutter.
- Во-первых, вам нужно определить класс, который упаковывает входные данные для отправки. Добавьте этот код в файл
step4/frontend/lib/game_agent.dart
:
class Inputs { final List<double> _boardState; Inputs(this._boardState); Map<String, dynamic> toJson() { final Map<String, dynamic> data = <String, dynamic>{}; data['0/discount'] = [0.0]; data['0/observation'] = [_boardState]; data['0/reward'] = [0.0]; data['0/step_type'] = [0]; return data; } }
Теперь вы можете отправить запрос в TensorFlow Serving, чтобы сделать прогнозы.
- Добавьте этот код в функцию
predict()
в файлеstep4/frontend/lib/game_agent.dart
:
var flattenedBoardState = boardState.expand((i) => i).toList(); final response = await http.post( Uri.parse('http://$server:8501/v1/models/policy_model:predict'), body: jsonEncode(<String, dynamic>{ 'signature_name': 'action', 'instances': [Inputs(flattenedBoardState)] }), ); if (response.statusCode == 200) { var output = List<int>.from( jsonDecode(response.body)['predictions'] as List<dynamic>); return output[0]; } else { throw Exception('Error response'); }
Как только приложение получает ответ от серверной части, вы обновляете пользовательский интерфейс игры, чтобы он отражал ход игры.
- Добавьте этот код в функцию
_gridItemTapped()
в файлеstep4/frontend/lib/main.dart
:
int agentAction = await _policyGradientAgent.predict(_playerVisibleBoardState); _agentActionX = agentAction ~/ _boardSize; _agentActionY = agentAction % _boardSize; if (_playerHiddenBoardState[_agentActionX][_agentActionY] == hiddenBoardCellOccupied) { // Non-repeat move if (_playerVisibleBoardState[_agentActionX][_agentActionY] == visibleBoardCellUntried) { _agentHitCount++; } _playerVisibleBoardState[_agentActionX][_agentActionY] = visibleBoardCellHit; } else { _playerVisibleBoardState[_agentActionX][_agentActionY] = visibleBoardCellMiss; } setState(() {});
Запусти это
- Нажмите Запустите отладку и дождитесь загрузки приложения.
- Коснитесь любой ячейки на доске агента, чтобы начать игру.
11. Шаг 5. Включите приложение Flutter для настольных платформ.
Помимо Android и iOS, Flutter также поддерживает настольные платформы, включая Linux, Mac и Windows.
Линукс
- Убедитесь, что на целевом устройстве установлено в строке состояния VSCode.
- Нажмите Запустите отладку и дождитесь загрузки приложения.
- Нажмите любую ячейку на доске агента, чтобы начать игру.
Мак
- Для Mac вам необходимо настроить соответствующие права, поскольку приложение будет отправлять HTTP-запросы на серверную часть. Дополнительную информацию см. в разделах «Права» и «Песочница приложения» .
Добавьте этот код в step4/frontend/macOS/Runner/DebugProfile.entitlements
и step4/frontend/macOS/Runner/Release.entitlements
соответственно:
<key>com.apple.security.network.client</key>
<true/>
- Убедитесь, что на целевом устройстве установлено значение в строке состояния VSCode.
- Нажмите Запустите отладку и дождитесь загрузки приложения.
- Нажмите любую ячейку на доске агента, чтобы начать игру.
Окна
- Убедитесь, что на целевом устройстве установлено значение в строке состояния VSCode.
- Нажмите Запустите отладку и дождитесь загрузки приложения.
- Нажмите любую ячейку на доске агента, чтобы начать игру.
12. Шаг 6. Включите приложение Flutter для веб-платформы.
Еще одна вещь, которую вы можете сделать, — это добавить веб-поддержку в приложение Flutter. По умолчанию веб-платформа автоматически включается для приложений Flutter, поэтому все, что вам нужно сделать, это запустить ее.
- Убедитесь, что на целевом устройстве установлено в строке состояния VSCode.
- Нажмите Запустите отладку и дождитесь загрузки приложения в браузере Chrome.
- Нажмите любую ячейку на доске агента, чтобы начать игру.
13. Поздравления
Вы создали приложение для настольной игры с агентом на базе машинного обучения, чтобы играть против игрока-человека!