File size: 4,242 Bytes
f8364f0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
"""
evaluate.py
ํ•™์Šต ์™„๋ฃŒ๋œ Pusher-v5 PPO ๋ชจ๋ธ์„ ๋กœ๋“œํ•˜์—ฌ ์„ฑ๋Šฅ์„ ์ •๋ฐ€ ํ‰๊ฐ€ํ•˜๊ณ  ๊ณ ํ™”์งˆ ๋น„๋””์˜ค/GIF๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
"""

import os
import argparse
import numpy as np
import gymnasium as gym
from stable_baselines3 import PPO
import visualizer


def evaluate_model(
    model_path: str,
    episodes: int = 5,
    output_dir: str = "./eval_results",
    seed: int = 100,
    fps: int = 30,
):
    """
    ์ €์žฅ๋œ PPO ๋ชจ๋ธ์„ ๋กœ๋“œํ•˜์—ฌ ํ…Œ์ŠคํŠธ ์—ํ”ผ์†Œ๋“œ๋ฅผ ์ˆ˜ํ–‰ํ•˜๊ณ  ๊ฒฐ๊ณผ๋ฅผ ์‹œ๊ฐํ™”ํ•ฉ๋‹ˆ๋‹ค.
    """
    os.makedirs(output_dir, exist_ok=True)

    print("=" * 65)
    print(f" [Evaluation] ๋ชจ๋ธ ๋กœ๋“œ ์ค‘: {model_path}")
    print(f" - ํ‰๊ฐ€ ์—ํ”ผ์†Œ๋“œ ์ˆ˜: {episodes}")
    print(f" - ์ถœ๋ ฅ ๋””๋ ‰ํ† ๋ฆฌ    : {output_dir}")
    print("=" * 65)

    # ํ™˜๊ฒฝ ๋ฐ ๋ชจ๋ธ ๋กœ๋“œ
    env = gym.make("Pusher-v5", render_mode="rgb_array")
    model = PPO.load(model_path, env=env)

    all_rewards = []
    all_dists_goal = []
    all_dists_arm = []

    for ep in range(episodes):
        obs, info = env.reset(seed=seed + ep)
        done = False
        ep_reward = 0.0
        ep_step = 0
        frames = []

        final_dist_goal = 0.0
        final_dist_arm = 0.0

        while not done:
            action, _ = model.predict(obs, deterministic=True)
            next_obs, reward, terminated, truncated, step_info = env.step(action)
            ep_reward += float(reward)
            ep_step += 1
            done = terminated or truncated

            reward_dist = step_info.get("reward_dist", 0.0)
            reward_near = step_info.get("reward_near", 0.0)
            final_dist_goal = abs(reward_dist) / 1.25 if reward_dist <= 0 else reward_dist
            final_dist_arm = abs(reward_near) if reward_near <= 0 else reward_near

            raw_frame = env.render()
            if raw_frame is not None:
                hud_frame = visualizer.draw_hud_on_frame(
                    frame=raw_frame,
                    timestep=-1,
                    episode=ep + 1,
                    step=ep_step,
                    step_reward=float(reward),
                    total_reward=ep_reward,
                    reward_dist=reward_dist,
                    reward_near=reward_near,
                    actions=action,
                    tag=f"Eval Ep {ep+1}",
                )
                frames.append(hud_frame)

            obs = next_obs

        all_rewards.append(ep_reward)
        all_dists_goal.append(final_dist_goal)
        all_dists_arm.append(final_dist_arm)

        # ์—ํ”ผ์†Œ๋“œ๋ณ„ ๋น„๋””์˜ค/GIF ์ €์žฅ
        out_base = os.path.join(output_dir, f"eval_episode_{ep+1}")
        gif_path, mp4_path = visualizer.save_video_and_gif(frames, out_base, fps=fps)

        print(f"Episode {ep+1:02d} | Return: {ep_reward:+.2f} | Final Goal Dist: {final_dist_goal:.3f}m | Arm Dist: {final_dist_arm:.3f}m")
        print(f"   -> ๋น„๋””์˜ค: {mp4_path} | GIF: {gif_path}")

    env.close()

    print("\n" + "=" * 65)
    print(" [Evaluation Summary]")
    print(f" - ํ‰๊ท  ๋ณด์ƒ (Mean Return)          : {np.mean(all_rewards):+.2f} ยฑ {np.std(all_rewards):.2f}")
    print(f" - ํ‰๊ท  ๋ชฉํ‘œ ๊ฑฐ๋ฆฌ (Mean Goal Dist)   : {np.mean(all_dists_goal):.3f}m")
    print(f" - ํ‰๊ท  ํŒ”-๋ฌผ์ฒด ๊ฑฐ๋ฆฌ (Mean Arm Dist): {np.mean(all_dists_arm):.3f}m")
    print("=" * 65)


def main():
    parser = argparse.ArgumentParser(description="Pusher-v5 PPO ๋ชจ๋ธ ๋…๋ฆฝ ํ‰๊ฐ€ ๋ฐ ๋น„๋””์˜ค ์ƒ์„ฑ")
    parser.add_argument("--model_path", type=str, default="./results/ppo_pusher.zip", help="ํ‰๊ฐ€ํ•  ๋ชจ๋ธ ํŒŒ์ผ ๊ฒฝ๋กœ (.zip)")
    parser.add_argument("--episodes", type=int, default=3, help="ํ‰๊ฐ€ํ•  ์—ํ”ผ์†Œ๋“œ ์ˆ˜ (๊ธฐ๋ณธ: 3)")
    parser.add_argument("--output_dir", type=str, default="./eval_results", help="ํ‰๊ฐ€ ๊ฒฐ๊ณผ๋ฌผ ์ €์žฅ ๋””๋ ‰ํ† ๋ฆฌ")
    parser.add_argument("--seed", type=int, default=100, help="ํ‰๊ฐ€ ๋žœ๋ค ์‹œ๋“œ")
    parser.add_argument("--fps", type=int, default=30, help="๋น„๋””์˜ค ์žฌ์ƒ FPS")
    args = parser.parse_args()

    evaluate_model(
        model_path=args.model_path,
        episodes=args.episodes,
        output_dir=args.output_dir,
        seed=args.seed,
        fps=args.fps,
    )


if __name__ == "__main__":
    main()