Textaufbereitung für große Sprachmodelle.

Wir zeigen, welche Daten große Sprachmodelle verwenden und wie man eigene Textdaten aufbereiten kann.

LLM Frage & Antwort

branche
divers
Thema
NLP, LLM
Tools
Torch, Transformers, DeepSpeed
Projektdauer
2 Wochen

LLM-Datensatz

Um ein großes Sprachmodell zu trainieren, wird ein großer Datensatz verwendet. Die meisten großen Sprachmodelle haben gemeinsam, dass diese zum Großteil auf Website-Daten trainiert werden. Wir schauen uns den Datensatz des zurzeit bekanntesten Sprachmodells LLaMA von Meta/Facebook, genauer an.LLaMA Paper

Die wichtigsten Fakten über den für das LLaMA-Training verwendeten Datensatz sind:

Datensatz des LLaMa Trainigs
  • Unterschiedliche Quellen
    Der Datensatz besteht aus einer Mischung von Daten aus verschiedenen Quellen, darunter CommonCrawl (en), C4, GitHub, Wikipedia, Gutenberg und Books3, ArXiv und Stack Exchange. Die Daten sind hierbei relativ unterschiedlich und umfassen neben normalen Website-Daten auch Bücher, Code und wissenschaftliche Texte.
  • Öffentlich verfügbare Daten
    Die für das Training von LLaMA verwendeten Daten stammen aus öffentlich zugänglichen Datensätzen, was bezüglich der Lizenzbedingungen und weiterer rechtlicher Grundlagen wichtig ist.
  • Unterschiedliche Sprachen
    Der Großteil der verwendeten Daten sind in Englisch. Bei dem CommonCrawl und C4-Datensatz zum Beispiel werden nicht englische Seiten entfernt. Die wissenschaftlichen Paper sind ebenfalls hauptsächlich auf Englisch, ebenso wie die Kommentare im GitHub-Code, Beiträge auf StackExchange, ... . Lediglich Bestandteile von Wikipedia umfassen 20 unterschiedliche Sprachen, darunter Deutsch, Spanisch, Französisch und Italienisch.
  • Datenaufbereitung
    Bei jedem Datensatz werden aufwendigen Aufbereitungsschritte durchgeführt. Hierzu zählen die Deduplizierung, bei dem ähnliche Texte entfernt werden, die Filterung nach englischer Sprache (außer Wikipedia), das Herausfiltern von Inhalten geringer Qualität, das Entfernen von Hyperlinks oder Kommentaren und das Filtern nach Lizenzen von Code.

Zusammenfassend lässt sich sagen, dass der LLaMA-Trainingsdatensatz verschiedene Datensätze umfasst und diese aufwendige Aufbereitungsschritte durchlaufen, um einen qualitativ hochwertigen Datensatz zu erzeugen. Generell hat das Modell eine Kenntnis über verschiedenste Sprachen, wenn auch nur sehr begrenzt.

Open-Source-Datensatz

Die einzelnen Bestandteile des Datensatzes für das LLaMA-Training sind zwar frei verfügbar, der Datensatz selber nach der Aufbereitung jedoch nicht. Möchte man sich einen eigenen Datensatz zusammenstellen, folgen hier die Links zu den einzelnen Bestandteilen:


Wir werden hier immer wieder den Begriff Huggingface lesen: Huggingface ist ein Unternehmen, das sich auf die Entwicklung von Werkzeugen und Bibliotheken für Natural Language Processing (NLP) spezialisiert hat. Ihre bekannteste Bibliothek, Transformers, ermöglicht die Implementierung von State-of-the-Art-NLP-Modellen. Darüber hinaus stellen sie auch eine Austauschplattform zur Verfügung, auf der vortrainierte Modelle und Datensätze von der Community geteilt werden können.

Es gibt verschiedene Projekte, die einen vergleichbaren Datensatz zu dem des LLaMA-Netzes aufgebaut haben:
RedPajama Datensatz auf Huggingface
Hier ist der Nachteil, dass ebenfalls wieder hauptsächlich englische Texte verwendet wurden. Lediglich die Wikipedia-Artikel hatten unterschiedliche Sprachen.

Darüber hinaus wurde ein vergleichbares Sprachmodell zu den LLaMA-Modellen trainiert namens Falcon, der Datensatz hierzu wurde ebenfalls veröffentlicht: Huggingface

Der Vorteil gegenüber den oben vorgestellten Datensätzen ist, dass bei der großen Variante des Netzes ein weiterer (leider nicht veröffentlichter) Datensatz verwendet wurde, bei dem europäische Sprachen mit 7 % Anteil verwendet wurden. Hiervon sind 26 % der Daten Deutsch. Was einem Gesamtanteil von 1,82 % entspricht. Dies entspricht immerhin einem Gesamtanteil von 1,82 % was aber natürlich immer noch eher gering ist.

Datenerzeugung

Die Web-Datensätze werden durch Webscraping über Crawling erzeugt. Hierbei werden große Mengen an Internetseiten heruntergeladen und der Text extrahiert. In Europa gibt es ebenfalls ein Projekt namens OSCAR (Open Super-large Crawled Aggregated coRpus), welcher einen großen Open Source Datensatz erzeugt.Oscar Datensatz
Generell muss das Scraping bedacht angegangen werden und aktuell gibt es noch rechtliche Bedenken. Bei StableDiffusion zum Beispiel (eine KI zur Bilderzeugung) wurde erst vor kurzem ein mögliches opt out Verfahren eingeführt, damit die Bilder nicht für das Training verwendet werden.MIT Technology Review Außerdem zeigt sich, dass Scraping von den Websitebetreibern kritisch angesehen wird und die Zugriffe nicht mehr kostenfrei erfolgen sollen.Heise Artikel über StackExchanget3n Artikel über Reddit Möchte man ein eigenes Webscraping aufbauen, kann dies mit bereits vorhandenen Tools wie Scrapy, StormCrawler o.ä. aufgebaut werden.

Eigene Daten

Wie können wir nun eigene Dokumente in die großen Sprachmodelle bringen? Generell gibt es unterschiedliche Herangehensweisen. Entweder können diese Texte in das Sprachmodell eintrainiert werden, oder man verwendet ein allgemeines Sprachmodell und nutzt Text-Embedding. Dabei werden ähnliche Textbausteine zu der Anfrage in vorhandenen Dokumenten gesucht und dem Sprachmodell zugeführt. Im ersten Schritt zeigen wir, wie man die Daten in das Sprachmodell eintrainieren kann.

HTML

import requests 
from bs4 import BeautifulSoup

URL = "https://www.gutenberg.org/files/2229/2229-h/2229-h.htm"

# Herunterladen der .html Website 
r = requests.get(URL)
soup = BeautifulSoup(r.content, "html.parser")

# Entfernen des Inhaltsverzeichnisses, der Überschriften, ...  
text = soup.find_all("p")
text = [p.text for p in text]

# Entfernen der Einleitung am Anfang
text = text[5:]
print(" ".join(text[:1]))

Output
DIREKTOR.
Ihr beiden, die ihr mir so oft,
In Not und Trübsal, beigestanden,
Sagt, was ihr wohl in deutschen Landen
Von unsrer Unternehmung hofft?
[...]

Anschließende Datenaufbereitung:

# Filtern des Textes, damit nur die Konversationen und keine weiteren Einleitungen o.ä. verwendet wird: 
final_text = []
for raw_text in text:
    split_txt = raw_text.lstrip().split("\r\n", 1)
    if split_txt[0].replace(".", "").isupper():
        final_text.append("\n".join(split_txt)) 
        
final_text[:2]

Output
['DIREKTOR.\nIhr beiden, die ihr mir so oft,\r\n [...]',
'DICHTER.\nIhr fühlet nicht, wie schlecht ein solches Handwerk sei!\r\n [...]']

EPUB

import requests
import ebooklib
from ebooklib import epub
from bs4 import BeautifulSoup

URL = "https://www.gutenberg.org/ebooks/2229.epub.noimages"
r = requests.get(URL)

with open('Faust.epub', 'wb') as f: 
    f.write(r.content)

book = epub.read_epub("Faust.epub")
items = list(book.get_items_of_type(ebooklib.ITEM_DOCUMENT))

# Ab hier vergleichbar zu html-Dateien
final_text = []
for item in items: 
    soup = BeautifulSoup(item.get_body_content().decode('utf-8'), "html.parser")

    # Entfernen des Inhaltsverzeichnisses, der Überschriften, ..., u.ä.  
    text = soup.find_all("p")
    text = [p.text for p in text]

    # Filtern des Textes, damit nur die Konversationen und keine weiteren Einleitungen o.ä. verwendet wird: 
    for raw_text in text:
        split_txt = raw_text.lstrip().split("\n", 1)
        if split_txt[0].isupper():
            final_text.append("\n".join(split_txt)) 
            
final_text[:2]

Output
['DIREKTOR.\nIhr beiden, die ihr mir so oft,\nIn Not und Trübsal, beigestanden,\n [...]',
'DICHTER.\nIhr fühlet nicht, wie schlecht ein solches Handwerk sei!\n [...]']

PDF

Für die PDF verwenden wir einen PDF-Ausdruck der bereits verwendeten Website. Hier wurde der Text nur relativ einfach extrahiert und manche Abschnitte zur Vereinfachung verworfen. Der Aufwand, PDF-Dateien aufzubereiten, ist deutlich größer, insbesondere wenn der Text nicht eingebettet ist. Hierbei müsste dann in einem ersten Schritt noch eine OCR-Umwandlung erfolgen.

def get_sprecher(text_list:list)->list:
    """Gibt die einzelnen Sprecher zurück. Der Anfang wird verworfen!"""
    sprecher_list = []

    for i, text in enumerate(text_list): 
        if text.isupper(): 
            sprecher_list.append(i)
            
    merged_sprecher = []
    for sprecher, _ in enumerate(sprecher_list): 
        try:
            merged_sprecher.append("\n".join(text_list[sprecher_list[sprecher]: sprecher_list[sprecher+1]]))
        except IndexError:
            merged_sprecher.append("\n".join(text_list[sprecher_list[sprecher]:]))            
    return merged_sprecher

import fitz

doc = fitz.open("Faust.pdf")

alle_konversationen = []
for page in range(3, 130): 
    text = doc[page].get_text()
    text = text.split("/139")[1].lstrip().split("\n")
    alle_konversationen.extend(get_sprecher(text))
alle_konversationen[:2]

Output
['DIREKTOR.\nIhr beiden, die ihr mir so oft,\nIn Not und Trübsal, beigestanden,\n [...]',
'DICHTER.\nIhr fühlet nicht, wie schlecht ein solches Handwerk sei!\n [...]']

In unserem nächsten Blogbeitrag zeigen wir, wie die aufbereiteten Daten verwendet werden können um ein großes Sprachmodell an Faust anzupassen.

Transformieren Sie Ihre Dokumente!

Kontakt