Skip to content

Commit

Permalink
Add timeouted agents save feature
Browse files Browse the repository at this point in the history
  • Loading branch information
emnigma committed Jul 20, 2023
1 parent a848766 commit 1362a3a
Show file tree
Hide file tree
Showing 6 changed files with 43 additions and 14 deletions.
2 changes: 1 addition & 1 deletion VSharp.ML.AIAgent/.gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# python cache and venv
.env
__pycache__/
epochs_best/
report/
*.pkl
*.onnx
19 changes: 19 additions & 0 deletions VSharp.ML.AIAgent/config.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import logging
from dataclasses import dataclass
from pathlib import Path
from shutil import rmtree

import ml.models

Expand All @@ -18,9 +21,25 @@ class ServerConfig:
VSHARP_INSTANCES_START_PORT = 8100


@dataclass(slots=True, frozen=True)
class DumpByTimeoutFeature:
enabled: bool
timeout_seconds: int
save_path: Path

def create_save_path_if_not_exists(self):
if self.enabled:
if self.save_path.exists():
rmtree(self.save_path)
self.save_path.mkdir()


class FeatureConfig:
VERBOSE_TABLES = True
SHOW_SUCCESSORS = True
NAME_LEN = 7
N_BEST_SAVED_EACH_GEN = 2
DISABLE_MESSAGE_CHECKS = True
DUMP_BY_TIMEOUT = DumpByTimeoutFeature(
enabled=True, timeout_seconds=1200, save_path=Path("./report/timeouted_agents/")
)
3 changes: 2 additions & 1 deletion VSharp.ML.AIAgent/learning/genetic_alorithm.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from torch.multiprocessing import set_start_method

from common.constants import APP_LOG_FILE, BASE_REPORT_DIR
from config import GeneralConfig
from config import FeatureConfig, GeneralConfig
from epochs_statistics.utils import (
create_report_dir,
init_epochs_best_dir,
Expand Down Expand Up @@ -59,6 +59,7 @@ def run(
init_tables_file()
init_log_file()
init_epochs_best_dir()
FeatureConfig.DUMP_BY_TIMEOUT.create_save_path_if_not_exists()

ga_instance = pygad.GA(
num_generations=num_generations,
Expand Down
23 changes: 14 additions & 9 deletions VSharp.ML.AIAgent/learning/r_learn.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
rewrite_best_tables_file,
)
from ml.model_wrappers.nnwrapper import NNWrapper
from ml.model_wrappers.protocols import Predictor
from selection.classes import AgentResultsOnGameMaps, GameResult, Map2Result
from selection.scorer import straight_scorer
from timer.resources_manager import manage_map_inference_times_array
Expand All @@ -44,7 +43,7 @@


def play_map(
with_agent: NAgent, with_model: Predictor
with_agent: NAgent, with_model: NNWrapper
) -> tuple[GameResult, TimeDuration]:
steps_count = 0
game_state = None
Expand Down Expand Up @@ -90,6 +89,12 @@ def play_map(

end_time = perf_counter()

if (
FeatureConfig.DUMP_BY_TIMEOUT.enabled
and end_time - start_time > FeatureConfig.DUMP_BY_TIMEOUT.timeout_seconds
):
save_weights(with_model.weights, to=FeatureConfig.DUMP_BY_TIMEOUT.save_path)

if actual_coverage != 100 and steps_count != steps:
logging.error(
f"<{with_model.name()}>: not all steps exshausted on {with_agent.map.MapName} with non-100% coverage"
Expand Down Expand Up @@ -211,35 +216,35 @@ def fitness_function(ga_inst, solution, solution_idx) -> float:
model.load_state_dict(model_weights_dict)
model.to(DEVICE)
model.eval()
predictor = NNWrapper(model, weights_flat=solution)
nnwrapper = NNWrapper(model, weights_flat=solution)

with game_server_socket_manager() as ws:
maps = get_maps(websocket=ws, type=maps_type)
with tqdm.tqdm(
total=len(maps),
desc=f"{predictor.name():20}: {maps_type.value}",
desc=f"{nnwrapper.name():20}: {maps_type.value}",
**TQDM_FORMAT_DICT,
) as pbar:
rst: list[GameResult] = []
list_of_map2result: list[Map2Result] = []
for game_map in maps:
logging.info(f"<{predictor.name()}> is playing {game_map.MapName}")
logging.info(f"<{nnwrapper.name()}> is playing {game_map.MapName}")

game_result, time = play_map(
with_agent=NAgent(ws, game_map, max_steps), with_model=predictor
with_agent=NAgent(ws, game_map, max_steps), with_model=nnwrapper
)
rst.append(game_result)
list_of_map2result.append(Map2Result(game_map, game_result))

logging.info(
f"<{predictor.name()}> finished map {game_map.MapName} "
f"<{nnwrapper.name()}> finished map {game_map.MapName} "
f"in {game_result.steps_count} steps, {time} seconds, "
f"actual coverage: {game_result.actual_coverage_percent:.2f}"
)
pbar.update(1)
send_game_results(Agent2ResultsOnMaps(predictor, list_of_map2result))
send_game_results(Agent2ResultsOnMaps(nnwrapper, list_of_map2result))

dump_and_reset_epoch_times(
f"{predictor.name()}_epoch{ga_inst.generations_completed}_pid{getpid()}"
f"{nnwrapper.name()}_epoch{ga_inst.generations_completed}_pid{getpid()}"
)
return straight_scorer(rst)
1 change: 1 addition & 0 deletions VSharp.ML.AIAgent/ml/model_wrappers/nnwrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
class NNWrapper(Predictor):
def __init__(self, model: torch.nn.Module, weights_flat: list[float]) -> None:
self.model = model
self.weights = weights_flat
self._name = str(sum(weights_flat))
self._hash = tuple(weights_flat).__hash__()

Expand Down
9 changes: 6 additions & 3 deletions VSharp.ML.AIAgent/weights_dump/weights_dump.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import json
from pathlib import Path

from numpy import typing as npt


def save_weights(w: npt.NDArray, to: str):
with open(to / f"{sum(w)}.txt", "w+") as weights_file:
json.dump(list(w), weights_file)
def save_weights(w: npt.NDArray, to: Path):
file_to_create = to / f"{sum(w)}.txt"
if not file_to_create.exists():
with open(file_to_create, "w+") as weights_file:
json.dump(list(w), weights_file)

0 comments on commit 1362a3a

Please sign in to comment.