-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathanalyze_reward_components_v04.py
More file actions
185 lines (150 loc) · 7.08 KB
/
analyze_reward_components_v04.py
File metadata and controls
185 lines (150 loc) · 7.08 KB
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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
"""
報酬関数の3要素(安全性、コスト効率、費用平準化)の詳細分析
Analyze the 3-component reward function balance
"""
import json
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from pathlib import Path
import yaml
# Set Japanese font for matplotlib
plt.rcParams['font.family'] = ['DejaVu Sans']
plt.rcParams['font.size'] = 10
def load_results():
"""学習結果をロード"""
results_dir = Path("outputs_hvac202_mvp_v04_enhanced")
# Training history
with open(results_dir / "training_history.json", 'r') as f:
training_data = json.load(f)
return training_data
def analyze_reward_components():
"""報酬の3要素を詳細分析"""
print("=" * 80)
print("📊 MVP v0.4 - 報酬関数の3要素バランス分析")
print("🎯 1) 正常な状態を保持する(安全性)")
print("💰 2) コスト効率をよくする")
print("⚖️ 3) 保全費用の平準化")
print("=" * 80)
# データロード
data = load_results()
# 基本統計
rewards = data['episode_rewards']
costs = data['episode_costs']
variances = data['episode_cost_variances']
losses = data['loss_history']
print(f"\n📈 基本統計:")
print(f" エピソード数: {len(rewards)}")
print(f" 平均報酬: {np.mean(rewards):.2f}")
print(f" 最終報酬: {rewards[-1]:.2f}")
print(f" 報酬の標準偏差: {np.std(rewards):.2f}")
# 費用分析
print(f"\n💰 コスト分析:")
print(f" 平均コスト: {np.mean(costs):.4f}")
print(f" 最終コスト: {costs[-1]:.4f}")
print(f" コストが0のエピソード: {sum(1 for c in costs if c == 0.0)}/{len(costs)}")
print(f" コストが0でないエピソード: {sum(1 for c in costs if c > 0.0)}/{len(costs)}")
# 費用平準化の詳細確認
print(f"\n⚖️ 費用平準化分析:")
print(f" 平均分散: {np.mean(variances):.4f}")
print(f" 最終分散: {variances[-1]:.4f}")
print(f" 分散が0のエピソード: {sum(1 for v in variances if v == 0.0)}/{len(variances)}")
# 問題点の特定
print(f"\n🔍 重要な問題:")
# 1. コストが常に0 = 「何もしない」戦略
zero_cost_ratio = sum(1 for c in costs if c == 0.0) / len(costs)
if zero_cost_ratio > 0.9:
print(f" ❌ 致命的: {zero_cost_ratio*100:.1f}%のエピソードでコスト0")
print(" -> AIが「何もしない」戦略しか学習していない")
print(" -> 保全行動を取るインセンティブが不足")
# 2. 負の報酬が大きすぎるか?
if np.mean(rewards) < -1000:
print(" ⚠️ 報酬が非常に負で大きい -> ペナルティが強すぎる可能性")
# 3. 改善傾向があるか?
early_rewards = rewards[:20]
late_rewards = rewards[-20:]
improvement = np.mean(late_rewards) - np.mean(early_rewards)
print(f"\n📊 学習進捗:")
print(f" 初期20エピソード平均: {np.mean(early_rewards):.2f}")
print(f" 最終20エピソード平均: {np.mean(late_rewards):.2f}")
print(f" 改善度: {improvement:.2f}")
if improvement > 0:
print(" ✅ 報酬が改善しています")
else:
print(" ⚠️ 報酬の改善が見られません")
# 可視化
create_detailed_analysis_plots(data)
# 推奨事項
print("\n" + "=" * 80)
print("💡 緊急対応策:")
print("1. 🚨 現在の問題: AIが保全を全く行わない")
print("2. 💡 解決策: 報酬バランスの根本的再設計が必要")
print("3. 🎯 推奨アクション:")
if zero_cost_ratio > 0.9:
print(" a) 異常状態のペナルティを大幅減 (-50.0 -> -10.0)")
print(" b) 正常状態の報酬を増加 (5.0 -> 20.0)")
print(" c) 保全実行にボーナス追加 (+5.0)")
print(" d) 「何もしない」のリスクコストを大幅増 (1.0 -> 10.0)")
print("=" * 80)
def create_detailed_analysis_plots(data):
"""詳細分析プロット作成"""
rewards = data['episode_rewards']
costs = data['episode_costs']
variances = data['episode_cost_variances']
fig, axes = plt.subplots(2, 2, figsize=(15, 12))
fig.suptitle('MVP v0.4 - 報酬関数詳細分析', fontsize=16, fontweight='bold')
# 1. 報酬の推移
axes[0, 0].plot(rewards, 'b-', alpha=0.7, linewidth=1)
axes[0, 0].plot(np.convolve(rewards, np.ones(10)/10, mode='valid'), 'r-', linewidth=2, label='10-episode average')
axes[0, 0].set_title('報酬の推移')
axes[0, 0].set_xlabel('エピソード')
axes[0, 0].set_ylabel('報酬')
axes[0, 0].grid(True, alpha=0.3)
axes[0, 0].legend()
# 2. 報酬の分布
axes[0, 1].hist(rewards, bins=30, alpha=0.7, color='skyblue', edgecolor='black')
axes[0, 1].axvline(np.mean(rewards), color='red', linestyle='--', label=f'平均: {np.mean(rewards):.1f}')
axes[0, 1].set_title('報酬の分布')
axes[0, 1].set_xlabel('報酬')
axes[0, 1].set_ylabel('頻度')
axes[0, 1].legend()
axes[0, 1].grid(True, alpha=0.3)
# 3. コストの推移 (重要!)
axes[1, 0].plot(costs, 'g-', linewidth=2, label='エピソードコスト')
axes[1, 0].set_title('エピソードコスト推移 (重要指標)')
axes[1, 0].set_xlabel('エピソード')
axes[1, 0].set_ylabel('コスト')
axes[1, 0].grid(True, alpha=0.3)
axes[1, 0].legend()
axes[1, 0].set_ylim(bottom=0)
# コストが0の場合の警告表示
zero_cost_count = sum(1 for c in costs if c == 0.0)
if zero_cost_count > len(costs) * 0.9:
axes[1, 0].text(0.5, 0.8, f'⚠️ WARNING\n{zero_cost_count}/{len(costs)} episodes\nwith ZERO cost!',
ha='center', va='center', transform=axes[1, 0].transAxes,
bbox=dict(boxstyle="round,pad=0.3", facecolor="red", alpha=0.7),
fontsize=12, fontweight='bold', color='white')
# 4. 学習損失の推移
if 'loss_history' in data:
losses = data['loss_history']
axes[1, 1].plot(losses, 'm-', alpha=0.7, linewidth=1)
if len(losses) > 50:
axes[1, 1].plot(np.convolve(losses, np.ones(50)/50, mode='valid'), 'r-', linewidth=2, label='50-step average')
axes[1, 1].set_title('学習損失の推移')
axes[1, 1].set_xlabel('更新ステップ')
axes[1, 1].set_ylabel('損失')
axes[1, 1].grid(True, alpha=0.3)
axes[1, 1].legend()
else:
axes[1, 1].text(0.5, 0.5, '損失データなし', ha='center', va='center', transform=axes[1, 1].transAxes)
axes[1, 1].set_title('損失データなし')
plt.tight_layout()
# 保存
save_path = Path("outputs_hvac202_mvp_v04_enhanced") / "reward_component_analysis_v04.png"
plt.savefig(save_path, dpi=300, bbox_inches='tight')
print(f"\n✅ 詳細分析プロット保存: {save_path}")
plt.show()
def main():
analyze_reward_components()
if __name__ == "__main__":
main()