File size: 3,549 Bytes
a345062
 
 
7dac8c1
a345062
 
 
 
7dac8c1
a345062
 
 
 
 
 
 
 
 
8489475
7dac8c1
a345062
 
 
8489475
a345062
d407fda
7dac8c1
d407fda
a345062
 
5708c30
 
 
 
 
a345062
 
21e8595
 
a345062
 
 
 
7dac8c1
5708c30
 
a345062
 
 
d407fda
a345062
5708c30
8489475
5708c30
 
a345062
 
7dac8c1
a345062
 
 
7dac8c1
 
 
 
 
 
8489475
5708c30
a345062
d407fda
 
7dac8c1
 
a345062
 
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
import pytest
import torch
from types import SimpleNamespace
from cognitive_mapping_probe.llm_iface import LLM, StableLLMConfig

@pytest.fixture(scope="session")
def mock_llm_config():
    """Stellt eine minimale, Schein-Konfiguration für das LLM bereit."""
    # Diese Fixture repräsentiert die *volatile* transformers-Konfiguration
    return SimpleNamespace(
        hidden_size=128,
        num_hidden_layers=2,
        num_attention_heads=4
    )

@pytest.fixture
def mock_llm(mocker, mock_llm_config):
    """
    Erstellt einen robusten "Mock-LLM" für Unit-Tests.
    FINAL KORRIGIERT: Simuliert nun auch die `stable_config`-Abstraktionsschicht.
    """
    mock_tokenizer = mocker.MagicMock()
    mock_tokenizer.eos_token_id = 1
    mock_tokenizer.decode.return_value = "mocked text"

    mock_embedding_layer = mocker.MagicMock()
    mock_embedding_layer.weight.shape = (32000, mock_llm_config.hidden_size)

    def mock_model_forward(*args, **kwargs):
        batch_size = 1
        seq_len = 1
        if 'input_ids' in kwargs and kwargs['input_ids'] is not None:
            seq_len = kwargs['input_ids'].shape[1]
        elif 'past_key_values' in kwargs and kwargs['past_key_values'] is not None:
            seq_len = kwargs['past_key_values'][0][0].shape[-2] + 1

        mock_outputs = {
            "hidden_states": tuple([torch.randn(batch_size, seq_len, mock_llm_config.hidden_size) for _ in range(mock_llm_config.num_hidden_layers + 1)]),
            "past_key_values": tuple([(torch.randn(batch_size, mock_llm_config.num_attention_heads, seq_len, 16), torch.randn(batch_size, mock_llm_config.num_attention_heads, seq_len, 16)) for _ in range(mock_llm_config.num_hidden_layers)]),
            "logits": torch.randn(batch_size, seq_len, 32000)
        }
        return SimpleNamespace(**mock_outputs)

    llm_instance = LLM.__new__(LLM)

    llm_instance.model = mocker.MagicMock(side_effect=mock_model_forward)
    llm_instance.model.config = mock_llm_config
    llm_instance.model.device = 'cpu'
    llm_instance.model.dtype = torch.float32
    llm_instance.model.get_input_embeddings.return_value = mock_embedding_layer

    mock_layer = mocker.MagicMock()
    mock_layer.register_forward_pre_hook.return_value = mocker.MagicMock()
    llm_instance.model.model = SimpleNamespace(layers=[mock_layer] * mock_llm_config.num_hidden_layers)
    llm_instance.model.lm_head = mocker.MagicMock(return_value=torch.randn(1, 32000))

    llm_instance.tokenizer = mock_tokenizer
    llm_instance.config = mock_llm_config # Die originale, volatile config
    llm_instance.seed = 42
    llm_instance.set_all_seeds = mocker.MagicMock()

    # KORREKTUR: Erzeuge die stabile Konfiguration, die die Tests nun erwarten.
    llm_instance.stable_config = StableLLMConfig(
        hidden_dim=mock_llm_config.hidden_size,
        num_layers=mock_llm_config.num_hidden_layers
    )

    # Patch an allen Stellen, an denen das Modell tatsächlich geladen wird.
    mocker.patch('cognitive_mapping_probe.llm_iface.get_or_load_model', return_value=llm_instance)
    mocker.patch('cognitive_mapping_probe.orchestrator_seismograph.get_or_load_model', return_value=llm_instance)
    mocker.patch('cognitive_mapping_probe.auto_experiment.get_or_load_model', return_value=llm_instance)

    # Mocke `get_concept_vector`, um zu verhindern, dass es im Orchestrator-Test ausgeführt wird.
    mocker.patch('cognitive_mapping_probe.orchestrator_seismograph.get_concept_vector', return_value=torch.randn(mock_llm_config.hidden_size))

    return llm_instance