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. Поздравления
Вы создали приложение для настольной игры с агентом на базе машинного обучения, чтобы играть против игрока-человека!

