Spaces:
Sleeping
Sleeping
Commit
·
d8f82fc
1
Parent(s):
2f5b07d
pre-flight tests
Browse files- cognitive_mapping_probe/__pycache__/concepts.cpython-310.pyc +0 -0
- cognitive_mapping_probe/__pycache__/llm_iface.cpython-310.pyc +0 -0
- cognitive_mapping_probe/__pycache__/orchestrator.cpython-310.pyc +0 -0
- cognitive_mapping_probe/__pycache__/resonance.cpython-310.pyc +0 -0
- cognitive_mapping_probe/__pycache__/verification.cpython-310.pyc +0 -0
- cognitive_mapping_probe/pre_flight_checks.py +72 -37
- cognitive_mapping_probe/resonance.py +23 -36
- cognitive_mapping_probe/verification.py +6 -2
cognitive_mapping_probe/__pycache__/concepts.cpython-310.pyc
CHANGED
|
Binary files a/cognitive_mapping_probe/__pycache__/concepts.cpython-310.pyc and b/cognitive_mapping_probe/__pycache__/concepts.cpython-310.pyc differ
|
|
|
cognitive_mapping_probe/__pycache__/llm_iface.cpython-310.pyc
CHANGED
|
Binary files a/cognitive_mapping_probe/__pycache__/llm_iface.cpython-310.pyc and b/cognitive_mapping_probe/__pycache__/llm_iface.cpython-310.pyc differ
|
|
|
cognitive_mapping_probe/__pycache__/orchestrator.cpython-310.pyc
CHANGED
|
Binary files a/cognitive_mapping_probe/__pycache__/orchestrator.cpython-310.pyc and b/cognitive_mapping_probe/__pycache__/orchestrator.cpython-310.pyc differ
|
|
|
cognitive_mapping_probe/__pycache__/resonance.cpython-310.pyc
CHANGED
|
Binary files a/cognitive_mapping_probe/__pycache__/resonance.cpython-310.pyc and b/cognitive_mapping_probe/__pycache__/resonance.cpython-310.pyc differ
|
|
|
cognitive_mapping_probe/__pycache__/verification.cpython-310.pyc
CHANGED
|
Binary files a/cognitive_mapping_probe/__pycache__/verification.cpython-310.pyc and b/cognitive_mapping_probe/__pycache__/verification.cpython-310.pyc differ
|
|
|
cognitive_mapping_probe/pre_flight_checks.py
CHANGED
|
@@ -6,13 +6,15 @@ from .llm_iface import get_or_load_model
|
|
| 6 |
from .concepts import get_concept_vector
|
| 7 |
from .resonance import run_silent_cogitation
|
| 8 |
from .verification import generate_spontaneous_text
|
|
|
|
| 9 |
from .utils import dbg
|
| 10 |
|
| 11 |
def run_pre_flight_checks(model_id: str, seed: int):
|
| 12 |
"""
|
| 13 |
Führt eine Reihe von kritischen Integrationstests mit einem ECHTEN LLM durch,
|
| 14 |
-
um die Validität der gesamten experimentellen Kette sicherzustellen
|
| 15 |
-
|
|
|
|
| 16 |
"""
|
| 17 |
|
| 18 |
print(f"1. Loading model '{model_id}'...")
|
|
@@ -23,15 +25,12 @@ def run_pre_flight_checks(model_id: str, seed: int):
|
|
| 23 |
raise AssertionError(f"Model loading failed: {e}")
|
| 24 |
|
| 25 |
print("\n2. Testing basic text generation...")
|
| 26 |
-
# Dieser einfache Test fängt Tokenizer-, Chat-Template- und grundlegende I/O-Probleme ab.
|
| 27 |
try:
|
| 28 |
-
# Erzeuge einen Dummy-Prompt, um eine einfache Antwort zu provozieren
|
| 29 |
inputs = llm.tokenizer("Hello, are you working?", return_tensors="pt").to(llm.model.device)
|
| 30 |
outputs = llm.model.generate(inputs.input_ids, max_new_tokens=5)
|
| 31 |
text = llm.tokenizer.decode(outputs[0], skip_special_tokens=True)
|
| 32 |
-
assert isinstance(text, str) and len(text) > 0
|
| 33 |
print(f" ✅ Basic generation successful. Model responded.")
|
| 34 |
-
dbg(f"Response snippet: '{text[:50]}...'")
|
| 35 |
except Exception as e:
|
| 36 |
raise AssertionError(f"Basic text generation failed: {e}")
|
| 37 |
|
|
@@ -45,67 +44,103 @@ def run_pre_flight_checks(model_id: str, seed: int):
|
|
| 45 |
|
| 46 |
print("\n4. Testing resonance loop (short run)...")
|
| 47 |
try:
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
|
|
|
| 51 |
except Exception as e:
|
| 52 |
raise AssertionError(f"Resonance loop failed: {e}")
|
| 53 |
|
| 54 |
print("\n5. CRITICAL TEST: Hook causal efficacy...")
|
| 55 |
-
# Dies ist der wichtigste Test. Er stellt sicher, dass unsere Aktivations-Injektionen
|
| 56 |
-
# tatsächlich eine kausale Wirkung auf die Berechnungen des Modells haben.
|
| 57 |
handle = None
|
| 58 |
try:
|
| 59 |
inputs = llm.tokenizer("Test", return_tensors="pt").to(llm.model.device)
|
| 60 |
-
|
| 61 |
-
# Lauf 1: Ohne Hook, um den Originalzustand zu erhalten
|
| 62 |
outputs_no_hook = llm.model(**inputs, output_hidden_states=True)
|
| 63 |
target_layer_idx = llm.config.num_hidden_layers // 2
|
| 64 |
state_no_hook = outputs_no_hook.hidden_states[target_layer_idx + 1].clone().detach()
|
| 65 |
-
|
| 66 |
-
# Definiere einen einfachen, starken Hook
|
| 67 |
def test_hook(module, layer_input):
|
| 68 |
return (layer_input[0] + 99.0,) + layer_input[1:]
|
| 69 |
-
|
| 70 |
target_layer = llm.model.model.layers[target_layer_idx]
|
| 71 |
handle = target_layer.register_forward_pre_hook(test_hook)
|
| 72 |
-
|
| 73 |
-
# Lauf 2: Mit Hook
|
| 74 |
outputs_with_hook = llm.model(**inputs, output_hidden_states=True)
|
| 75 |
state_with_hook = outputs_with_hook.hidden_states[target_layer_idx + 1].clone().detach()
|
| 76 |
-
|
| 77 |
-
handle.remove() # Hook sofort entfernen
|
| 78 |
handle = None
|
| 79 |
-
|
| 80 |
-
# Die entscheidende Behauptung: Die Zustände DÜRFEN NICHT identisch sein.
|
| 81 |
-
assert not torch.allclose(state_no_hook, state_with_hook), \
|
| 82 |
-
"Hook had no causal effect on subsequent hidden states. The injection mechanism is broken."
|
| 83 |
-
|
| 84 |
print(" ✅ Hook causal efficacy verified.")
|
| 85 |
-
|
| 86 |
except Exception as e:
|
| 87 |
raise AssertionError(f"Hook efficacy test failed: {e}")
|
| 88 |
finally:
|
| 89 |
-
|
| 90 |
-
if handle:
|
| 91 |
-
handle.remove()
|
| 92 |
-
print(" ⚠️ Hook handle was removed during exception handling.")
|
| 93 |
|
| 94 |
print("\n6. Testing verification (spontaneous text) loop...")
|
| 95 |
try:
|
| 96 |
-
|
| 97 |
-
|
| 98 |
-
dummy_kv =
|
| 99 |
-
|
| 100 |
-
torch.randn(1, llm.config.num_attention_heads, 10, llm.config.hidden_size // llm.config.num_attention_heads).to(llm.model.device))
|
| 101 |
-
for _ in range(llm.config.num_hidden_layers)
|
| 102 |
-
)
|
| 103 |
text = generate_spontaneous_text(llm, dummy_state, dummy_kv, max_new_tokens=5)
|
| 104 |
assert isinstance(text, str)
|
| 105 |
print(" ✅ Spontaneous text generation loop executed without errors.")
|
| 106 |
except Exception as e:
|
| 107 |
raise AssertionError(f"Verification loop failed: {e}")
|
| 108 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 109 |
# Aufräumen
|
| 110 |
del llm
|
| 111 |
if torch.cuda.is_available():
|
|
|
|
| 6 |
from .concepts import get_concept_vector
|
| 7 |
from .resonance import run_silent_cogitation
|
| 8 |
from .verification import generate_spontaneous_text
|
| 9 |
+
from .orchestrator import run_cognitive_titration_experiment
|
| 10 |
from .utils import dbg
|
| 11 |
|
| 12 |
def run_pre_flight_checks(model_id: str, seed: int):
|
| 13 |
"""
|
| 14 |
Führt eine Reihe von kritischen Integrationstests mit einem ECHTEN LLM durch,
|
| 15 |
+
um die Validität der gesamten experimentellen Kette sicherzustellen.
|
| 16 |
+
Diese Version enthält feingranulare Assertions in Test 7, um die gesamte
|
| 17 |
+
wissenschaftliche Hypothese (Konvergenz -> Verhalten) zu validieren.
|
| 18 |
"""
|
| 19 |
|
| 20 |
print(f"1. Loading model '{model_id}'...")
|
|
|
|
| 25 |
raise AssertionError(f"Model loading failed: {e}")
|
| 26 |
|
| 27 |
print("\n2. Testing basic text generation...")
|
|
|
|
| 28 |
try:
|
|
|
|
| 29 |
inputs = llm.tokenizer("Hello, are you working?", return_tensors="pt").to(llm.model.device)
|
| 30 |
outputs = llm.model.generate(inputs.input_ids, max_new_tokens=5)
|
| 31 |
text = llm.tokenizer.decode(outputs[0], skip_special_tokens=True)
|
| 32 |
+
assert isinstance(text, str) and len(text) > 0, "Basic generation produced no text."
|
| 33 |
print(f" ✅ Basic generation successful. Model responded.")
|
|
|
|
| 34 |
except Exception as e:
|
| 35 |
raise AssertionError(f"Basic text generation failed: {e}")
|
| 36 |
|
|
|
|
| 44 |
|
| 45 |
print("\n4. Testing resonance loop (short run)...")
|
| 46 |
try:
|
| 47 |
+
# Führe diesen Test mit deterministischer Temperatur durch, um Konvergenz zu prüfen
|
| 48 |
+
_, _, _, reason = run_silent_cogitation(llm, "control_long_prose", num_steps=250, temperature=0.01)
|
| 49 |
+
assert reason == "converged", f"Resonance loop failed to converge even in a simple test. Reason: {reason}"
|
| 50 |
+
print(" ✅ Resonance loop executed and converged as expected.")
|
| 51 |
except Exception as e:
|
| 52 |
raise AssertionError(f"Resonance loop failed: {e}")
|
| 53 |
|
| 54 |
print("\n5. CRITICAL TEST: Hook causal efficacy...")
|
|
|
|
|
|
|
| 55 |
handle = None
|
| 56 |
try:
|
| 57 |
inputs = llm.tokenizer("Test", return_tensors="pt").to(llm.model.device)
|
|
|
|
|
|
|
| 58 |
outputs_no_hook = llm.model(**inputs, output_hidden_states=True)
|
| 59 |
target_layer_idx = llm.config.num_hidden_layers // 2
|
| 60 |
state_no_hook = outputs_no_hook.hidden_states[target_layer_idx + 1].clone().detach()
|
|
|
|
|
|
|
| 61 |
def test_hook(module, layer_input):
|
| 62 |
return (layer_input[0] + 99.0,) + layer_input[1:]
|
|
|
|
| 63 |
target_layer = llm.model.model.layers[target_layer_idx]
|
| 64 |
handle = target_layer.register_forward_pre_hook(test_hook)
|
|
|
|
|
|
|
| 65 |
outputs_with_hook = llm.model(**inputs, output_hidden_states=True)
|
| 66 |
state_with_hook = outputs_with_hook.hidden_states[target_layer_idx + 1].clone().detach()
|
| 67 |
+
handle.remove()
|
|
|
|
| 68 |
handle = None
|
| 69 |
+
assert not torch.allclose(state_no_hook, state_with_hook), "Hook had no causal effect."
|
|
|
|
|
|
|
|
|
|
|
|
|
| 70 |
print(" ✅ Hook causal efficacy verified.")
|
|
|
|
| 71 |
except Exception as e:
|
| 72 |
raise AssertionError(f"Hook efficacy test failed: {e}")
|
| 73 |
finally:
|
| 74 |
+
if handle: handle.remove()
|
|
|
|
|
|
|
|
|
|
| 75 |
|
| 76 |
print("\n6. Testing verification (spontaneous text) loop...")
|
| 77 |
try:
|
| 78 |
+
initial_context = llm.tokenizer("dummy context", return_tensors="pt").to(llm.model.device)
|
| 79 |
+
initial_outputs = llm.model(**initial_context, use_cache=True, output_hidden_states=True)
|
| 80 |
+
dummy_kv = initial_outputs.past_key_values
|
| 81 |
+
dummy_state = initial_outputs.hidden_states[-1][:, -1:, :]
|
|
|
|
|
|
|
|
|
|
| 82 |
text = generate_spontaneous_text(llm, dummy_state, dummy_kv, max_new_tokens=5)
|
| 83 |
assert isinstance(text, str)
|
| 84 |
print(" ✅ Spontaneous text generation loop executed without errors.")
|
| 85 |
except Exception as e:
|
| 86 |
raise AssertionError(f"Verification loop failed: {e}")
|
| 87 |
|
| 88 |
+
# --- FINAL GRANULAR END-TO-END TEST (Test 7) ---
|
| 89 |
+
print("\n7. CRITICAL TEST: End-to-End scientific validation...")
|
| 90 |
+
try:
|
| 91 |
+
class MockProgress:
|
| 92 |
+
def __call__(self, progress, desc=""): pass
|
| 93 |
+
|
| 94 |
+
print(" - 7a. Validating STABLE BASELINE (Convergence -> Response)...")
|
| 95 |
+
stable_results = run_cognitive_titration_experiment(
|
| 96 |
+
model_id=model_id,
|
| 97 |
+
prompt_type="control_long_prose",
|
| 98 |
+
seed=seed,
|
| 99 |
+
concepts_str="test",
|
| 100 |
+
strength_levels_str="0.0",
|
| 101 |
+
num_steps=250,
|
| 102 |
+
temperature=0.01, # Use deterministic temp
|
| 103 |
+
progress_callback=MockProgress()
|
| 104 |
+
)
|
| 105 |
+
|
| 106 |
+
stable_run = stable_results["runs"][0]
|
| 107 |
+
# GRANULAR ASSERT 1: State must converge
|
| 108 |
+
assert stable_run['termination_reason'] == 'converged', \
|
| 109 |
+
f"VALIDATION FAILED (7a-1): Baseline with 'control' prompt MUST converge. Got '{stable_run['termination_reason']}'."
|
| 110 |
+
# GRANULAR ASSERT 2: Behavioral flag must be True
|
| 111 |
+
assert stable_run['responded'] is True, \
|
| 112 |
+
"VALIDATION FAILED (7a-2): Baseline converged, but the 'responded' flag is False. Orchestrator logic is flawed."
|
| 113 |
+
# GRANULAR ASSERT 3: Actual text content must exist
|
| 114 |
+
assert isinstance(stable_run['generated_text'], str) and len(stable_run['generated_text']) > 0, \
|
| 115 |
+
"VALIDATION FAILED (7a-3): Baseline converged, but produced an empty response text. Verification logic failed."
|
| 116 |
+
print(" ✅ Baseline converges AND responds. Causal chain validated.")
|
| 117 |
+
|
| 118 |
+
print(" - 7b. Validating UNSTABLE CONTRAST (Non-Convergence -> No Response)...")
|
| 119 |
+
unstable_results = run_cognitive_titration_experiment(
|
| 120 |
+
model_id=model_id,
|
| 121 |
+
prompt_type="resonance_prompt",
|
| 122 |
+
seed=seed,
|
| 123 |
+
concepts_str="test",
|
| 124 |
+
strength_levels_str="0.0",
|
| 125 |
+
num_steps=50,
|
| 126 |
+
temperature=0.7, # Use stochastic temp to ensure non-convergence
|
| 127 |
+
progress_callback=MockProgress()
|
| 128 |
+
)
|
| 129 |
+
|
| 130 |
+
unstable_run = unstable_results["runs"][0]
|
| 131 |
+
# GRANULAR ASSERT 1: State must NOT converge
|
| 132 |
+
assert unstable_run['termination_reason'] == 'max_steps_reached', \
|
| 133 |
+
f"VALIDATION FAILED (7b-1): Complex 'resonance' prompt was expected to fail, but it converged. The core hypothesis is challenged."
|
| 134 |
+
# GRANULAR ASSERT 2: Behavioral flag must be False
|
| 135 |
+
assert unstable_run['responded'] is False, \
|
| 136 |
+
"VALIDATION FAILED (7b-2): Unstable run was not expected to respond, but it did. Orchestrator logic is flawed."
|
| 137 |
+
print(" ✅ Complex prompt fails to converge AND does not respond. Contrast validated.")
|
| 138 |
+
|
| 139 |
+
print(" ✅ Full orchestration logic is scientifically sound and validated end-to-end.")
|
| 140 |
+
|
| 141 |
+
except Exception as e:
|
| 142 |
+
raise AssertionError(f"Full orchestration logic failed its scientific validation: {e}")
|
| 143 |
+
|
| 144 |
# Aufräumen
|
| 145 |
del llm
|
| 146 |
if torch.cuda.is_available():
|
cognitive_mapping_probe/resonance.py
CHANGED
|
@@ -17,69 +17,57 @@ def run_silent_cogitation(
|
|
| 17 |
injection_layer: Optional[int] = None,
|
| 18 |
) -> Tuple[torch.Tensor, tuple, torch.Tensor, str]:
|
| 19 |
"""
|
| 20 |
-
Simulates the "silent thought" process
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
- final_kv_cache: The past_key_values cache after the final step.
|
| 26 |
-
- final_token_id: The ID of the last generated token.
|
| 27 |
-
- termination_reason: A string indicating why the loop ended.
|
| 28 |
"""
|
| 29 |
prompt = RESONANCE_PROMPTS[prompt_type]
|
| 30 |
inputs = llm.tokenizer(prompt, return_tensors="pt").to(llm.model.device)
|
| 31 |
|
| 32 |
-
# Initial forward pass to establish the starting state
|
| 33 |
outputs = llm.model(**inputs, output_hidden_states=True, use_cache=True)
|
| 34 |
|
| 35 |
-
hidden_state
|
|
|
|
| 36 |
kv_cache = outputs.past_key_values
|
| 37 |
-
last_token_id = inputs.input_ids[:, -1].unsqueeze(-1)
|
| 38 |
|
| 39 |
previous_hidden_state = hidden_state.clone()
|
| 40 |
-
termination_reason = "max_steps_reached"
|
| 41 |
|
| 42 |
-
# Prepare injection if provided
|
| 43 |
hook_handle = None
|
| 44 |
if injection_vector is not None and injection_strength > 0:
|
| 45 |
-
# Move vector to the correct device and dtype once
|
| 46 |
injection_vector = injection_vector.to(device=llm.model.device, dtype=llm.model.dtype)
|
| 47 |
-
|
| 48 |
-
# Default to a middle layer if not specified
|
| 49 |
if injection_layer is None:
|
| 50 |
injection_layer = llm.config.num_hidden_layers // 2
|
| 51 |
|
| 52 |
-
dbg(f"Injection enabled: Layer {injection_layer}, Strength {injection_strength:.2f}
|
| 53 |
|
| 54 |
-
# Define the hook function that performs the activation addition
|
| 55 |
def injection_hook(module, layer_input):
|
| 56 |
-
|
| 57 |
-
original_hidden_states = layer_input[0]
|
| 58 |
-
# Add the scaled vector to the hidden states
|
| 59 |
-
modified_hidden_states = original_hidden_states + (injection_vector * injection_strength)
|
| 60 |
return (modified_hidden_states,) + layer_input[1:]
|
| 61 |
|
| 62 |
-
|
| 63 |
-
for i in tqdm(range(num_steps), desc=f"Simulating Thought (Strength {injection_strength:.2f})", leave=False, bar_format="{l_bar}{bar:10}{r_bar}"):
|
| 64 |
-
# Predict the next token from the current hidden state
|
| 65 |
next_token_logits = llm.model.lm_head(hidden_state)
|
| 66 |
|
| 67 |
-
#
|
| 68 |
-
if temperature
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
else: # Use argmax for deterministic behavior at low temperatures
|
| 72 |
next_token_id = torch.argmax(next_token_logits, dim=-1).unsqueeze(-1)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 73 |
|
|
|
|
| 74 |
last_token_id = next_token_id
|
| 75 |
|
| 76 |
-
# --- Activation Injection via Hook ---
|
| 77 |
try:
|
| 78 |
if injection_vector is not None and injection_strength > 0:
|
| 79 |
target_layer = llm.model.model.layers[injection_layer]
|
| 80 |
hook_handle = target_layer.register_forward_pre_hook(injection_hook)
|
| 81 |
|
| 82 |
-
# Perform the next forward pass
|
| 83 |
outputs = llm.model(
|
| 84 |
input_ids=next_token_id,
|
| 85 |
past_key_values=kv_cache,
|
|
@@ -87,17 +75,15 @@ def run_silent_cogitation(
|
|
| 87 |
use_cache=True,
|
| 88 |
)
|
| 89 |
finally:
|
| 90 |
-
# IMPORTANT: Always remove the hook after the forward pass
|
| 91 |
if hook_handle:
|
| 92 |
hook_handle.remove()
|
| 93 |
hook_handle = None
|
| 94 |
|
| 95 |
-
hidden_state = outputs.hidden_states[-1][:, -1
|
| 96 |
kv_cache = outputs.past_key_values
|
| 97 |
|
| 98 |
-
# Check for convergence
|
| 99 |
delta = torch.norm(hidden_state - previous_hidden_state).item()
|
| 100 |
-
if delta < 1e-4 and i > 10:
|
| 101 |
termination_reason = "converged"
|
| 102 |
dbg(f"State converged after {i+1} steps (delta={delta:.6f}).")
|
| 103 |
break
|
|
@@ -105,4 +91,5 @@ def run_silent_cogitation(
|
|
| 105 |
previous_hidden_state = hidden_state.clone()
|
| 106 |
|
| 107 |
dbg(f"Silent cogitation finished. Reason: {termination_reason}")
|
|
|
|
| 108 |
return hidden_state, kv_cache, last_token_id, termination_reason
|
|
|
|
| 17 |
injection_layer: Optional[int] = None,
|
| 18 |
) -> Tuple[torch.Tensor, tuple, torch.Tensor, str]:
|
| 19 |
"""
|
| 20 |
+
Simulates the "silent thought" process.
|
| 21 |
+
|
| 22 |
+
FINAL PATCH: Ensures dimensional consistency between stochastic (`multinomial`)
|
| 23 |
+
and deterministic (`argmax`) sampling paths. This was the root cause of the
|
| 24 |
+
non-convergence issue.
|
|
|
|
|
|
|
|
|
|
| 25 |
"""
|
| 26 |
prompt = RESONANCE_PROMPTS[prompt_type]
|
| 27 |
inputs = llm.tokenizer(prompt, return_tensors="pt").to(llm.model.device)
|
| 28 |
|
|
|
|
| 29 |
outputs = llm.model(**inputs, output_hidden_states=True, use_cache=True)
|
| 30 |
|
| 31 |
+
# Wichtig: hidden_state behält die `seq_len`-Dimension bei, um konsistent zu bleiben.
|
| 32 |
+
hidden_state = outputs.hidden_states[-1][:, -1:, :]
|
| 33 |
kv_cache = outputs.past_key_values
|
|
|
|
| 34 |
|
| 35 |
previous_hidden_state = hidden_state.clone()
|
| 36 |
+
termination_reason = "max_steps_reached"
|
| 37 |
|
|
|
|
| 38 |
hook_handle = None
|
| 39 |
if injection_vector is not None and injection_strength > 0:
|
|
|
|
| 40 |
injection_vector = injection_vector.to(device=llm.model.device, dtype=llm.model.dtype)
|
|
|
|
|
|
|
| 41 |
if injection_layer is None:
|
| 42 |
injection_layer = llm.config.num_hidden_layers // 2
|
| 43 |
|
| 44 |
+
dbg(f"Injection enabled: Layer {injection_layer}, Strength {injection_strength:.2f}")
|
| 45 |
|
|
|
|
| 46 |
def injection_hook(module, layer_input):
|
| 47 |
+
modified_hidden_states = layer_input[0] + (injection_vector * injection_strength)
|
|
|
|
|
|
|
|
|
|
| 48 |
return (modified_hidden_states,) + layer_input[1:]
|
| 49 |
|
| 50 |
+
for i in tqdm(range(num_steps), desc=f"Simulating (Temp {temperature:.2f}, Strength {injection_strength:.2f})", leave=False, bar_format="{l_bar}{bar:10}{r_bar}"):
|
|
|
|
|
|
|
| 51 |
next_token_logits = llm.model.lm_head(hidden_state)
|
| 52 |
|
| 53 |
+
# Bei sehr niedriger Temperatur erzwingen wir `argmax` (Determinismus)
|
| 54 |
+
if temperature <= 0.1:
|
| 55 |
+
# `argmax` gibt einen 1D-Tensor zurück. Wir müssen ihn zu einem 2D-Tensor
|
| 56 |
+
# der Form [batch_size, 1] erweitern, um konsistent mit `multinomial` zu sein.
|
|
|
|
| 57 |
next_token_id = torch.argmax(next_token_logits, dim=-1).unsqueeze(-1)
|
| 58 |
+
else:
|
| 59 |
+
probabilities = torch.nn.functional.softmax(next_token_logits / temperature, dim=-1)
|
| 60 |
+
# `multinomial` erwartet 2D [batch, vocab], also quetschen wir die mittlere Dimension
|
| 61 |
+
next_token_id = torch.multinomial(probabilities.squeeze(1), num_samples=1)
|
| 62 |
|
| 63 |
+
# `last_token_id` wird am Ende des Loops für die Verifikation zurückgegeben
|
| 64 |
last_token_id = next_token_id
|
| 65 |
|
|
|
|
| 66 |
try:
|
| 67 |
if injection_vector is not None and injection_strength > 0:
|
| 68 |
target_layer = llm.model.model.layers[injection_layer]
|
| 69 |
hook_handle = target_layer.register_forward_pre_hook(injection_hook)
|
| 70 |
|
|
|
|
| 71 |
outputs = llm.model(
|
| 72 |
input_ids=next_token_id,
|
| 73 |
past_key_values=kv_cache,
|
|
|
|
| 75 |
use_cache=True,
|
| 76 |
)
|
| 77 |
finally:
|
|
|
|
| 78 |
if hook_handle:
|
| 79 |
hook_handle.remove()
|
| 80 |
hook_handle = None
|
| 81 |
|
| 82 |
+
hidden_state = outputs.hidden_states[-1][:, -1:, :]
|
| 83 |
kv_cache = outputs.past_key_values
|
| 84 |
|
|
|
|
| 85 |
delta = torch.norm(hidden_state - previous_hidden_state).item()
|
| 86 |
+
if delta < 1e-4 and i > 10:
|
| 87 |
termination_reason = "converged"
|
| 88 |
dbg(f"State converged after {i+1} steps (delta={delta:.6f}).")
|
| 89 |
break
|
|
|
|
| 91 |
previous_hidden_state = hidden_state.clone()
|
| 92 |
|
| 93 |
dbg(f"Silent cogitation finished. Reason: {termination_reason}")
|
| 94 |
+
|
| 95 |
return hidden_state, kv_cache, last_token_id, termination_reason
|
cognitive_mapping_probe/verification.py
CHANGED
|
@@ -32,9 +32,13 @@ def generate_spontaneous_text(
|
|
| 32 |
# Apply temperature and sample the next token ID
|
| 33 |
if temperature > 0.01:
|
| 34 |
probabilities = torch.nn.functional.softmax(next_token_logits / temperature, dim=-1)
|
| 35 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 36 |
else:
|
| 37 |
-
next_token_id = torch.argmax(next_token_logits, dim=-1).unsqueeze(-1)
|
| 38 |
|
| 39 |
# Check for End-of-Sequence token
|
| 40 |
if next_token_id.item() == llm.tokenizer.eos_token_id:
|
|
|
|
| 32 |
# Apply temperature and sample the next token ID
|
| 33 |
if temperature > 0.01:
|
| 34 |
probabilities = torch.nn.functional.softmax(next_token_logits / temperature, dim=-1)
|
| 35 |
+
|
| 36 |
+
# KORREKTUR: Der `probabilities`-Tensor hat die Form [1, 1, vocab_size].
|
| 37 |
+
# `torch.multinomial` erwartet eine 1D- oder 2D-Verteilung.
|
| 38 |
+
# Wir entfernen die mittlere Dimension, um die Form [1, vocab_size] zu erhalten.
|
| 39 |
+
next_token_id = torch.multinomial(probabilities.squeeze(1), num_samples=1)
|
| 40 |
else:
|
| 41 |
+
next_token_id = torch.argmax(next_token_logits, dim=-1) # .unsqueeze(-1) wird durch den Loop unten wieder hinzugefügt
|
| 42 |
|
| 43 |
# Check for End-of-Sequence token
|
| 44 |
if next_token_id.item() == llm.tokenizer.eos_token_id:
|