File size: 6,302 Bytes
348749a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
# app.py

import gradio as gr
import torch
from transformers import pipeline, AutoTokenizer, AutoModelForCausalLM
import pandas as pd

# --- 1. Modelle laden ---
# Wir laden die Modelle einmal beim Start der Anwendung, um die Ladezeit bei jeder Anfrage zu vermeiden.

# Modell 1: German GPT-2 für Text-Vervollständigung
# Wir laden hier Tokenizer und Modell manuell, da wir die Logits für das nächste Wort brauchen,
# was die Standard-Pipeline nicht direkt so ausgibt.
gpt2_model_name = "dbmdz/german-gpt2"
gpt2_tokenizer = AutoTokenizer.from_pretrained(gpt2_model_name)
# AutoModelWithLMHead ist veraltet, wir benutzen stattdessen AutoModelForCausalLM
gpt2_model = AutoModelForCausalLM.from_pretrained(gpt2_model_name)

# Modell 2: BERT für Masken-Füllung
# Hier können wir die Pipeline direkt nutzen, da sie genau das tut, was wir wollen.
unmasker = pipeline('fill-mask', model='bert-base-multilingual-uncased', top_k=5)


# --- 2. Logik-Funktionen für die Modelle ---

def predict_next_word(text):
    """
    Diese Funktion nimmt einen Text entgegen, tokenisiert ihn, gibt ihn an das GPT-2 Modell
    und berechnet die Wahrscheinlichkeitsverteilung für das *unmittelbar* folgende Wort.
    """
    if not text or not text.strip():
        return {}

    # Text in Token-IDs umwandeln
    inputs = gpt2_tokenizer(text, return_tensors='pt')

    # Modell-Vorhersage ohne Gradientenberechnung (schneller)
    with torch.no_grad():
        logits = gpt2_model(**inputs).logits

    # Wir interessieren uns nur für die Logits des letzten Tokens im Input
    # Shape: [batch_size, sequence_length, vocab_size] -> wir nehmen das letzte Token
    last_token_logits = logits[0, -1, :]

    # Wende Softmax an, um Wahrscheinlichkeiten zu erhalten
    probabilities = torch.nn.functional.softmax(last_token_logits, dim=-1)

    # Finde die Top 5 wahrscheinlichsten Token-IDs und ihre Wahrscheinlichkeiten
    top_k_probs, top_k_indices = torch.topk(probabilities, 5)

    # Konvertiere die Token-IDs zurück in lesbare Tokens (Wörter)
    top_k_tokens = gpt2_tokenizer.convert_ids_to_tokens(top_k_indices)

    # Bereinige die Tokens (z.B. 'Ġ' entfernen, das für ein Leerzeichen steht)
    cleaned_tokens = [token.replace('Ġ', '') for token in top_k_tokens]

    # Erstelle ein Dictionary für die Ausgabe in Gradio
    result_dict = {token: prob.item() for token, prob in zip(cleaned_tokens, top_k_probs)}

    return result_dict


def fill_the_mask(text):
    """
    Diese Funktion nutzt die fill-mask Pipeline, um die wahrscheinlichsten Wörter für
    das [MASK]-Token im Text zu finden.
    """
    # Überprüfen, ob das Masken-Token vorhanden ist
    mask_token = unmasker.tokenizer.mask_token
    if mask_token not in text:
        # Einen Fehler in der Gradio-UI anzeigen
        raise gr.Error(f"Die Eingabe muss das Masken-Token '{mask_token}' enthalten.")

    # Pipeline aufrufen
    predictions = unmasker(text)

    # Die Ausgabe der Pipeline in ein Dictionary für Gradio umwandeln
    # Die Pipeline liefert eine Liste von Dictionaries, wir formatieren sie um.
    result_dict = {pred['token_str']: pred['score'] for pred in predictions}

    return result_dict


# --- 3. Gradio Interface erstellen ---

with gr.Blocks(theme=gr.themes.Soft()) as demo:
    gr.Markdown(
        """
        # Funktionalität von Language Models demonstrieren
        Diese Anwendung zeigt die Kernfähigkeiten von zwei verschiedenen Arten von Transformer-Modellen:
        1.  **Causal Language Models (z.B. GPT-2):** Diese Modelle sind darauf trainiert, das nächste Wort in einer Sequenz vorherzusagen. Sie sind ideal für die Textgenerierung.
        2.  **Masked Language Models (z.B. BERT):** Diese Modelle lernen, fehlende Wörter in einem Satz zu ergänzen. Sie verstehen den Kontext in beide Richtungen (bidirektional) und sind stark in Klassifikations- oder Extraktionsaufgaben.
        """
    )

    with gr.Tabs():
        # --- Tab 1: Causal LM (GPT-2) ---
        with gr.TabItem("1. Causal LM (Text-Vervollständigung)"):
            gr.Markdown(
                """
                ## German GPT-2 (`dbmdz/german-gpt2`)
                Dieses Modell sagt das wahrscheinlichste *nächste* Wort voraus.
                ### Anleitung
                Gib einen deutschen Satzanfang in das Textfeld ein und klicke auf "Nächstes Wort vorhersagen".
                """
            )
            with gr.Row():
                text_input_gpt = gr.Textbox(
                    label="Dein Satzanfang",
                    placeholder="Tippe hier...",
                    value="Der Sinn des Lebens ist",
                    lines=3
                )

            predict_button_gpt = gr.Button("Nächstes Wort vorhersagen")

            gr.Markdown("### Wahrscheinlichste Folgewörter")
            output_label_gpt = gr.Label(num_top_classes=5)

        # --- Tab 2: Masked LM (BERT) ---
        with gr.TabItem("2. Masked LM (Masken-Füllung)"):
            gr.Markdown(
                f"""
                ## Multilingual BERT (`bert-base-multilingual-uncased`)
                Dieses Modell füllt die Lücke, die durch ein sogenanntes "Masken-Token" (`{unmasker.tokenizer.mask_token}`) markiert ist.
                ### Anleitung
                Gib einen Satz mit dem Masken-Token `{unmasker.tokenizer.mask_token}` ein und klicke auf "Maske füllen".
                """
            )
            with gr.Row():
                text_input_bert = gr.Textbox(
                    label="Satz mit Maske",
                    placeholder="Tippe hier...",
                    value=f"Berlin ist die Hauptstadt von {unmasker.tokenizer.mask_token}.",
                    lines=3
                )

            fill_mask_button_bert = gr.Button("Maske füllen")

            gr.Markdown("### Wahrscheinlichste Füllwörter")
            output_label_bert = gr.Label(num_top_classes=5)

    # --- 4. Events verknüpfen ---
    predict_button_gpt.click(
        fn=predict_next_word,
        inputs=text_input_gpt,
        outputs=output_label_gpt,
        api_name="predict_next_word"
    )

    fill_mask_button_bert.click(
        fn=fill_the_mask,
        inputs=text_input_bert,
        outputs=output_label_bert,
        api_name="fill_mask"
    )

# Anwendung starten
demo.launch()