neuralworm commited on
Commit
8049238
·
1 Parent(s): be6c085

memory management

Browse files
app.py CHANGED
@@ -1,6 +1,8 @@
1
  import gradio as gr
2
  import pandas as pd
3
  import traceback
 
 
4
 
5
  from cognitive_mapping_probe.orchestrator_seismograph import run_seismic_analysis
6
  from cognitive_mapping_probe.auto_experiment import run_auto_suite, get_curated_experiments
@@ -9,6 +11,14 @@ from cognitive_mapping_probe.utils import dbg
9
 
10
  theme = gr.themes.Soft(primary_hue="indigo", secondary_hue="blue").set(body_background_fill="#f0f4f9", block_background_fill="white")
11
 
 
 
 
 
 
 
 
 
12
  def run_single_analysis_display(*args, progress=gr.Progress(track_tqdm=True)):
13
  """Wrapper für ein einzelnes manuelles Experiment."""
14
  try:
@@ -17,16 +27,26 @@ def run_single_analysis_display(*args, progress=gr.Progress(track_tqdm=True)):
17
  deltas = results.get("state_deltas", [])
18
  df = pd.DataFrame({"Internal Step": range(len(deltas)), "State Change (Delta)": deltas})
19
  stats_md = f"### Statistical Signature\n- **Mean Delta:** {stats.get('mean_delta', 0):.4f}\n- **Std Dev Delta:** {stats.get('std_delta', 0):.4f}\n- **Max Delta:** {stats.get('max_delta', 0):.4f}\n"
 
 
 
 
20
  return f"{results.get('verdict', 'Error')}\n\n{stats_md}", df, results
21
  except Exception:
 
22
  return f"### ❌ Analysis Failed\n```\n{traceback.format_exc()}\n```", pd.DataFrame(), {}
23
 
24
  def run_auto_suite_display(model_id, num_steps, seed, experiment_name, progress=gr.Progress(track_tqdm=True)):
25
  """Wrapper für die automatisierte Experiment-Suite mit Visualisierung."""
26
  try:
27
  summary_df, plot_df, all_results = run_auto_suite(model_id, int(num_steps), int(seed), experiment_name, progress)
 
 
 
 
28
  return summary_df, plot_df, all_results
29
  except Exception:
 
30
  return pd.DataFrame(), pd.DataFrame(), f"### ❌ Auto-Experiment Failed\n```\n{traceback.format_exc()}\n```"
31
 
32
  with gr.Blocks(theme=theme, title="Cognitive Seismograph 2.2") as demo:
@@ -49,7 +69,6 @@ with gr.Blocks(theme=theme, title="Cognitive Seismograph 2.2") as demo:
49
  with gr.Column(scale=2):
50
  gr.Markdown("### Single Run Results")
51
  manual_verdict = gr.Markdown("Die Analyse erscheint hier.")
52
- # KORREKTUR: `interactive=True` für Legende hinzugefügt
53
  manual_plot = gr.LinePlot(x="Internal Step", y="State Change (Delta)", title="Internal State Dynamics", show_label=True, height=400, interactive=True)
54
  with gr.Accordion("Raw JSON Output", open=False):
55
  manual_raw_json = gr.JSON()
@@ -72,7 +91,6 @@ with gr.Blocks(theme=theme, title="Cognitive Seismograph 2.2") as demo:
72
  auto_run_btn = gr.Button("Run Curated Auto-Experiment", variant="primary")
73
  with gr.Column(scale=2):
74
  gr.Markdown("### Suite Results Summary")
75
- # KORREKTUR: `interactive=True` für Legende hinzugefügt
76
  auto_plot_output = gr.LinePlot(
77
  x="Step", y="Delta", color="Experiment",
78
  title="Comparative Cognitive Dynamics",
 
1
  import gradio as gr
2
  import pandas as pd
3
  import traceback
4
+ import gc
5
+ import torch
6
 
7
  from cognitive_mapping_probe.orchestrator_seismograph import run_seismic_analysis
8
  from cognitive_mapping_probe.auto_experiment import run_auto_suite, get_curated_experiments
 
11
 
12
  theme = gr.themes.Soft(primary_hue="indigo", secondary_hue="blue").set(body_background_fill="#f0f4f9", block_background_fill="white")
13
 
14
+ def cleanup_memory():
15
+ """Eine zentrale Funktion zum Aufräumen des Speichers nach einem Lauf."""
16
+ dbg("Cleaning up memory...")
17
+ gc.collect()
18
+ if torch.cuda.is_available():
19
+ torch.cuda.empty_cache()
20
+ dbg("Memory cleanup complete.")
21
+
22
  def run_single_analysis_display(*args, progress=gr.Progress(track_tqdm=True)):
23
  """Wrapper für ein einzelnes manuelles Experiment."""
24
  try:
 
27
  deltas = results.get("state_deltas", [])
28
  df = pd.DataFrame({"Internal Step": range(len(deltas)), "State Change (Delta)": deltas})
29
  stats_md = f"### Statistical Signature\n- **Mean Delta:** {stats.get('mean_delta', 0):.4f}\n- **Std Dev Delta:** {stats.get('std_delta', 0):.4f}\n- **Max Delta:** {stats.get('max_delta', 0):.4f}\n"
30
+
31
+ # WICHTIG: Speicher aufräumen, BEVOR die Ergebnisse an Gradio zurückgegeben werden.
32
+ cleanup_memory()
33
+
34
  return f"{results.get('verdict', 'Error')}\n\n{stats_md}", df, results
35
  except Exception:
36
+ cleanup_memory()
37
  return f"### ❌ Analysis Failed\n```\n{traceback.format_exc()}\n```", pd.DataFrame(), {}
38
 
39
  def run_auto_suite_display(model_id, num_steps, seed, experiment_name, progress=gr.Progress(track_tqdm=True)):
40
  """Wrapper für die automatisierte Experiment-Suite mit Visualisierung."""
41
  try:
42
  summary_df, plot_df, all_results = run_auto_suite(model_id, int(num_steps), int(seed), experiment_name, progress)
43
+
44
+ # WICHTIG: Speicher auch hier aufräumen.
45
+ cleanup_memory()
46
+
47
  return summary_df, plot_df, all_results
48
  except Exception:
49
+ cleanup_memory()
50
  return pd.DataFrame(), pd.DataFrame(), f"### ❌ Auto-Experiment Failed\n```\n{traceback.format_exc()}\n```"
51
 
52
  with gr.Blocks(theme=theme, title="Cognitive Seismograph 2.2") as demo:
 
69
  with gr.Column(scale=2):
70
  gr.Markdown("### Single Run Results")
71
  manual_verdict = gr.Markdown("Die Analyse erscheint hier.")
 
72
  manual_plot = gr.LinePlot(x="Internal Step", y="State Change (Delta)", title="Internal State Dynamics", show_label=True, height=400, interactive=True)
73
  with gr.Accordion("Raw JSON Output", open=False):
74
  manual_raw_json = gr.JSON()
 
91
  auto_run_btn = gr.Button("Run Curated Auto-Experiment", variant="primary")
92
  with gr.Column(scale=2):
93
  gr.Markdown("### Suite Results Summary")
 
94
  auto_plot_output = gr.LinePlot(
95
  x="Step", y="Delta", color="Experiment",
96
  title="Comparative Cognitive Dynamics",
cognitive_mapping_probe/auto_experiment.py CHANGED
@@ -1,4 +1,6 @@
1
  import pandas as pd
 
 
2
  from typing import Dict, List, Tuple
3
 
4
  from .llm_iface import get_or_load_model
@@ -8,7 +10,6 @@ from .utils import dbg
8
  def get_curated_experiments() -> Dict[str, List[Dict]]:
9
  """
10
  Definiert die vordefinierten, wissenschaftlichen Experiment-Protokolle.
11
- ERWEITERT um zusätzliche, aussagekräftige Experimente.
12
  """
13
  experiments = {
14
  "Calm vs. Chaos": [
@@ -61,6 +62,7 @@ def run_auto_suite(
61
  summary_data = []
62
  plot_data_frames = []
63
 
 
64
  llm = get_or_load_model(model_id, seed)
65
 
66
  total_runs = len(protocol)
@@ -69,40 +71,29 @@ def run_auto_suite(
69
  dbg(f"--- Running Auto-Experiment: '{label}' ({i+1}/{total_runs}) ---")
70
 
71
  results = run_seismic_analysis(
72
- model_id=model_id,
73
- prompt_type=run_spec["prompt_type"],
74
- seed=seed,
75
- num_steps=num_steps,
76
- concept_to_inject=run_spec["concept"],
77
- injection_strength=run_spec["strength"],
78
  progress_callback=progress_callback,
79
- llm_instance=llm
80
  )
81
 
82
  all_results[label] = results
83
  stats = results.get("stats", {})
84
 
85
- summary_data.append({
86
- "Experiment": label,
87
- "Mean Delta": stats.get("mean_delta"),
88
- "Std Dev Delta": stats.get("std_delta"),
89
- "Max Delta": stats.get("max_delta"),
90
- })
91
 
92
  deltas = results.get("state_deltas", [])
93
-
94
- # Verwende das Label direkt für die Legende. Der vorherige Fix war nicht nötig,
95
- # solange die Labels einzigartig pro Experiment sind.
96
- df = pd.DataFrame({
97
- "Step": range(len(deltas)),
98
- "Delta": deltas,
99
- "Experiment": label
100
- })
101
  plot_data_frames.append(df)
102
 
103
  summary_df = pd.DataFrame(summary_data)
104
  plot_df = pd.concat(plot_data_frames, ignore_index=True) if plot_data_frames else pd.DataFrame()
105
 
 
106
  del llm
 
 
 
107
 
108
  return summary_df, plot_df, all_results
 
1
  import pandas as pd
2
+ import torch
3
+ import gc
4
  from typing import Dict, List, Tuple
5
 
6
  from .llm_iface import get_or_load_model
 
10
  def get_curated_experiments() -> Dict[str, List[Dict]]:
11
  """
12
  Definiert die vordefinierten, wissenschaftlichen Experiment-Protokolle.
 
13
  """
14
  experiments = {
15
  "Calm vs. Chaos": [
 
62
  summary_data = []
63
  plot_data_frames = []
64
 
65
+ # Lade das Modell einmal zu Beginn der Suite
66
  llm = get_or_load_model(model_id, seed)
67
 
68
  total_runs = len(protocol)
 
71
  dbg(f"--- Running Auto-Experiment: '{label}' ({i+1}/{total_runs}) ---")
72
 
73
  results = run_seismic_analysis(
74
+ model_id=model_id, prompt_type=run_spec["prompt_type"],
75
+ seed=seed, num_steps=num_steps,
76
+ concept_to_inject=run_spec["concept"], injection_strength=run_spec["strength"],
 
 
 
77
  progress_callback=progress_callback,
78
+ llm_instance=llm # Wiederverwende die geladene LLM-Instanz
79
  )
80
 
81
  all_results[label] = results
82
  stats = results.get("stats", {})
83
 
84
+ summary_data.append({ "Experiment": label, "Mean Delta": stats.get("mean_delta"), "Std Dev Delta": stats.get("std_delta"), "Max Delta": stats.get("max_delta"), })
 
 
 
 
 
85
 
86
  deltas = results.get("state_deltas", [])
87
+ df = pd.DataFrame({ "Step": range(len(deltas)), "Delta": deltas, "Experiment": f"{i}: {label}" })
 
 
 
 
 
 
 
88
  plot_data_frames.append(df)
89
 
90
  summary_df = pd.DataFrame(summary_data)
91
  plot_df = pd.concat(plot_data_frames, ignore_index=True) if plot_data_frames else pd.DataFrame()
92
 
93
+ # WICHTIG: Explizites Aufräumen am Ende der gesamten Suite
94
  del llm
95
+ gc.collect()
96
+ if torch.cuda.is_available():
97
+ torch.cuda.empty_cache()
98
 
99
  return summary_df, plot_df, all_results
cognitive_mapping_probe/orchestrator_seismograph.py CHANGED
@@ -1,5 +1,6 @@
1
  import torch
2
  import numpy as np
 
3
  from typing import Dict, Any, Optional
4
 
5
  from .llm_iface import get_or_load_model
@@ -15,39 +16,35 @@ def run_seismic_analysis(
15
  concept_to_inject: str,
16
  injection_strength: float,
17
  progress_callback,
18
- llm_instance: Optional[Any] = None # Ermöglicht Wiederverwendung des Modells
19
  ) -> Dict[str, Any]:
20
  """
21
- Orchestriert eine einzelne seismische Analyse. Kann optional eine bestehende
22
- LLM-Instanz wiederverwenden, um das Neuladen in automatisierten Suiten zu beschleunigen.
23
  """
24
- # Lade das Modell nur, wenn keine Instanz übergeben wurde
25
  if llm_instance is None:
26
  progress_callback(0.1, desc="Loading model...")
27
  llm = get_or_load_model(model_id, seed)
28
- created_llm = True
29
  else:
30
  llm = llm_instance
31
- llm.set_all_seeds(seed) # Setze den Seed für diesen spezifischen Lauf
32
- created_llm = False
33
 
34
  injection_vector = None
35
  if concept_to_inject and concept_to_inject.strip():
36
- if not created_llm: progress_callback(0.2, desc=f"Vectorizing '{concept_to_inject}'...")
37
  injection_vector = get_concept_vector(llm, concept_to_inject.strip())
38
 
39
- if not created_llm: progress_callback(0.3, desc=f"Recording dynamics...")
40
 
41
  state_deltas = run_silent_cogitation_seismic(
42
- llm=llm,
43
- prompt_type=prompt_type,
44
- num_steps=num_steps,
45
- temperature=0.1,
46
- injection_vector=injection_vector,
47
- injection_strength=injection_strength
48
  )
49
 
50
- if not created_llm: progress_callback(0.9, desc="Analyzing...")
51
 
52
  if state_deltas:
53
  deltas_np = np.array(state_deltas)
@@ -60,9 +57,14 @@ def run_seismic_analysis(
60
 
61
  results = { "verdict": verdict, "stats": stats, "state_deltas": state_deltas }
62
 
63
- # Gib das Modell nur frei, wenn es in dieser Funktion erstellt wurde
64
- if created_llm:
 
 
65
  del llm
66
- if torch.cuda.is_available(): torch.cuda.empty_cache()
 
 
 
67
 
68
  return results
 
1
  import torch
2
  import numpy as np
3
+ import gc
4
  from typing import Dict, Any, Optional
5
 
6
  from .llm_iface import get_or_load_model
 
16
  concept_to_inject: str,
17
  injection_strength: float,
18
  progress_callback,
19
+ llm_instance: Optional[Any] = None
20
  ) -> Dict[str, Any]:
21
  """
22
+ Orchestriert eine einzelne seismische Analyse. Stellt sicher, dass das Modell
23
+ nur dann entladen wird, wenn es auch hier geladen wurde.
24
  """
25
+ local_llm_instance = False
26
  if llm_instance is None:
27
  progress_callback(0.1, desc="Loading model...")
28
  llm = get_or_load_model(model_id, seed)
29
+ local_llm_instance = True
30
  else:
31
  llm = llm_instance
32
+ llm.set_all_seeds(seed)
 
33
 
34
  injection_vector = None
35
  if concept_to_inject and concept_to_inject.strip():
36
+ if not local_llm_instance: progress_callback(0.2, desc=f"Vectorizing '{concept_to_inject}'...")
37
  injection_vector = get_concept_vector(llm, concept_to_inject.strip())
38
 
39
+ if not local_llm_instance: progress_callback(0.3, desc=f"Recording dynamics...")
40
 
41
  state_deltas = run_silent_cogitation_seismic(
42
+ llm=llm, prompt_type=prompt_type,
43
+ num_steps=num_steps, temperature=0.1,
44
+ injection_vector=injection_vector, injection_strength=injection_strength
 
 
 
45
  )
46
 
47
+ if not local_llm_instance: progress_callback(0.9, desc="Analyzing...")
48
 
49
  if state_deltas:
50
  deltas_np = np.array(state_deltas)
 
57
 
58
  results = { "verdict": verdict, "stats": stats, "state_deltas": state_deltas }
59
 
60
+ # WICHTIG: Gib das Modell und den Speicher nur frei, wenn es in dieser
61
+ # Funktion auch erstellt wurde. Ansonsten ist die übergeordnete Funktion
62
+ # (z.B. `run_auto_suite`) für das Speichermanagement verantwortlich.
63
+ if local_llm_instance:
64
  del llm
65
+ del injection_vector
66
+ gc.collect()
67
+ if torch.cuda.is_available():
68
+ torch.cuda.empty_cache()
69
 
70
  return results