Základy NLP: tokenizace, vkládání a moderní potrubí
Pokaždé, když o něco požádáte hlasového asistenta, přeložte text pomocí Překladače Google, filtrovat spam ve své e-mailové schránce nebo číst automatické titulky videa, používáte Zpracování přirozeného jazyka (NLP). Tato disciplína, na průniku lingvistiky, informatiky a umělé inteligence, se zabývá učí stroje chápat, interpretovat a vytvářet lidský jazyk.
V posledních letech prošla oblast NLP radikální proměnou. Prošli jsme kolem ručně psaná pravidla a statické slovníky k neurálním modelům schopným porozumět nuancím, kontextu a dokonce i ironie. BERT, GPT, Lama a modely nové generace by nebyly možné bez základů, které prozkoumáme v tomto článku: tokenizace, The vložení e la Moderní potrubí NLP.
Toto je první článek ze série Moderní NLP: od BERT po LLM. Začneme od úplných základů, krok za krokem budeme budovat potřebné intuice porozumět pokročilejším jazykovým modelům. Budeme věnovat zvláštní pozornost ke specifikům italského jazyka, často přehlíženého v anglofonních zdrojích.
Co se naučíte
- Co je NLP a proč je základem téměř každé moderní AI aplikace
- Jak je text předzpracován: malá písmena, ignorovaná slova, stemming a lemmatizace
- Různé přístupy k tokenizaci: na úrovni slova, na úrovni znaků a podslovu (BPE, WordPiece, SentencePiece)
- Klasické reprezentace textu: Bag of Words a TF-IDF
- Vložení slov: Word2Vec, GloVe a geometrická intuice významu
- Kontextové vložení: od statických reprezentací po BERT
- Vkládání vět a jejich praktické aplikace
- Moderní kanál NLP: od surového textu k predikci
- Specifičnost předzpracování pro italský jazyk
- Kompletní end-to-end příklad s kódem Python
Přehled série
| # | Položka | Soustředit |
|---|---|---|
| 1 | Jste zde - Základy NLP | Tokenizace, vkládání, potrubí |
| 2 | BERT a transformátory | Pozornost Architektura, Pre-školení |
| 3 | Analýza sentimentu | Klasifikace textu pomocí BERT |
| 4 | Rozpoznávání pojmenované entity | Extrakce entit z textu |
| 5 | Transformátory HuggingFace | Předtrénovaná knihovna a modely |
| 6 | Jemné ladění modelů | Přizpůsobte BERT vaší doméně |
| 7 | NLP pro italštinu | Šablony a prostředky pro italský jazyk |
| 8 | Od BERT po LLM | GPT, LLaMA a generování textu |
1. Předzpracování textu: Připravte data
Než může jakýkoli model NLP pracovat s textem, musí to tak být čisté a normalizované. Hrubý a hlučný text: interpunkce, velká písmena, zkratky, emotikony, HTML, URL. Předzpracování změní tento chaos na a strukturovaný a koherentní formát.
1.1 Malá písmena a normalizace
Prvním krokem je převést veškerý text na malá písmena. Pro počítač "Home", "home" a „HOME“ jsou tři zcela odlišné struny. Malá písmena je sjednocují.
import re
import unicodedata
def normalize_text(text: str) -> str:
"""Normalizzazione base del testo."""
# Lowercasing
text = text.lower()
# Rimozione accenti (opzionale, NON consigliato per italiano)
# text = unicodedata.normalize('NFKD', text)
# Rimozione punteggiatura
text = re.sub(r'[^\w\s]', '', text)
# Rimozione spazi multipli
text = re.sub(r'\s+', ' ', text).strip()
return text
testo = "L'NLP e FANTASTICO! Analizza testi in 50+ lingue."
print(normalize_text(testo))
# Output: "lnlp e fantastico analizza testi in 50 lingue"
Věnujte pozornost přízvukům v italštině
V mnoha anglicky mluvících kanálech NLP je odstranění přízvuku standardním krokem. v italštině akcenty však mění význam slov: "ale" (konjunkce) vs "ale" (strom), "A" (konjunkce) vs "A" (sloveso být). Nikdy neodstraňujte akcenty při práci s italským textem.
1.2 Stopwords: Slova bez informačního obsahu
Le stopwords Jsou to velmi frekventovaná slova, která mají malý sémantický význam: členy, předložky, spojky. Jejich odstraněním se sníží rozměrnost dat pomáhá modelům zaměřit se na smysluplná slova.
Italská vs anglická stopwords
| Jazyk | Příklady ignorovaných slov | Typický hrabě |
|---|---|---|
| angličtina | the, is, at, which, on, a, an, and, or | ~180 slov |
| italština | the, the, the, of, to, from, in, with, on, for, that, and not, a | ~300 slov |
Italština má více ignorovaných slov než angličtina díky větší bohatosti článků (il, lo, la, i, gli, le), artikulované předložky (del, dello, della, nei, nei, nelle) a pomocné slovesné tvary.
# Approccio 1: NLTK
from nltk.corpus import stopwords
import nltk
nltk.download('stopwords')
stop_it = set(stopwords.words('italian'))
print(f"Stopwords italiane NLTK: {len(stop_it)}")
# Output: Stopwords italiane NLTK: 279
testo = "il gatto mangia il pesce sul tavolo della cucina"
tokens = testo.split()
filtrato = [t for t in tokens if t not in stop_it]
print(filtrato)
# Output: ['gatto', 'mangia', 'pesce', 'tavolo', 'cucina']
# Approccio 2: spaCy (più completo)
import spacy
nlp = spacy.load("it_core_news_lg")
doc = nlp("il gatto mangia il pesce sul tavolo della cucina")
filtrato_spacy = [token.text for token in doc if not token.is_stop]
print(filtrato_spacy)
# Output: ['gatto', 'mangia', 'pesce', 'tavolo', 'cucina']
1.3 Stemming vs lemmatizace
Obě techniky redukují slova do jejich základní formy, ale dělají to velmi odlišnými způsoby.
Stemming vs Lemmatization - Srovnání
| čekám | Odvozování | Lematizace |
|---|---|---|
| Metoda | Ořízněte přípony pomocí heuristických pravidel | Použijte slovník a morfologický rozbor |
| Výsledek | Stonek (ne vždy skutečné slovo) | Lemma (skutečné slovo ze slovníku) |
| IT příklad | "jíst" -> "jíte" | "jíst" -> "jíst" |
| Rychlost | Velmi rychle | Pomalejší (vyžaduje slovník) |
| Přesnost | Nízká (běžné přetěžování) | Vysoká (správné tvary) |
| Pro italštinu | Snowball Stemmer (italský Porter) | spaCy it_core_news_lg |
from nltk.stem.snowball import SnowballStemmer
import spacy
# Stemming con Snowball
stemmer = SnowballStemmer("italian")
parole = ["mangiando", "mangiare", "mangiato", "correre", "correndo", "bellissimo"]
stems = [stemmer.stem(p) for p in parole]
print(dict(zip(parole, stems)))
# {'mangiando': 'mang', 'mangiare': 'mang', 'mangiato': 'mang',
# 'correre': 'corr', 'correndo': 'corr', 'bellissimo': 'bellissim'}
# Lemmatization con spaCy
nlp = spacy.load("it_core_news_lg")
doc = nlp("Le ragazze stavano mangiando le mele più belle")
lemmi = [(token.text, token.lemma_, token.pos_) for token in doc]
for testo, lemma, pos in lemmi:
print(f" {testo:15s} -> {lemma:15s} ({pos})")
# le -> il (DET)
# ragazze -> ragazza (NOUN)
# stavano -> stare (AUX)
# mangiando -> mangiare (VERB)
# le -> il (DET)
# mele -> mela (NOUN)
# più -> più (ADV)
# belle -> bello (ADJ)
Pro italštinu, lemmatizace pomocí spaCy a téměř vždy lepší
ke stopování. Modelka it_core_news_lg obsahuje 500 000 slovních vektorů
a podporuje tokenizaci, značkování POS, analýzu závislostí, NER a lemmatizaci.
2. Tokenizace: Jak stroje čtou text
La tokenizace a proces dělení textu na samostatné jednotky hovory žeton. A první a nejkritičtější krok každého potrubí NLP: kvalita tokenizace přímo ovlivňuje výkon každého následujícího modelu.
Existují tři základní přístupy, z nichž každý má různé výhody a kompromisy.
2.1 Tokenizace na úrovni slov
Nejintuitivnější přístup: každé slovo se stává žetonem.
# Approccio naive: split per spazio
testo = "L'intelligenza artificiale cambia il mondo"
tokens_naive = testo.split()
print(tokens_naive)
# ["L'intelligenza", 'artificiale', 'cambia', 'il', 'mondo']
# Problema: "L'intelligenza" e un singolo token!
# Approccio migliore: spaCy
import spacy
nlp = spacy.load("it_core_news_lg")
doc = nlp(testo)
tokens_spacy = [token.text for token in doc]
print(tokens_spacy)
# ["L'", 'intelligenza', 'artificiale', 'cambia', 'il', 'mondo']
# spaCy gestisce correttamente le elisioni italiane
Limity tokenizace na úrovni slov
- Obrovská slovní zásoba: Každé jedinečné slovo vyžaduje vstup do slovní zásoby. Italština má statisíce skloňovaných tvarů
- Slova mimo slovní zásobu (OOV): Slova, která během tréninku nikdy neviděla, se stanou <UNK> (neznámé)
- Žádné morfologické sdílení: „jíst“, „jíst“, „jíst“ jsou tři zcela samostatné, nesouvisející žetony
2.2 Tokenizace na úrovni postavy
V druhém extrému se každá postava stává žetonem. Slovní zásoba je malá (26 písmen + číslic + interpunkce), ale sekvence jsou velmi dlouhé.
Testo: "ciao mondo"
Word-level: ["ciao", "mondo"] -> 2 token
Char-level: ["c","i","a","o"," ","m","o","n","d","o"] -> 10 token
Testo di 1000 parole:
Word-level: ~1.000 token
Char-level: ~5.000 token (5x più lungo!)
Tokenizace znaků řeší problém neznámých slov (jakékoli slovo mohou být reprezentovány), ale velmi dlouhé sekvence to modelkám znesnadňují zachytit v textu dlouhodobé vztahy.
2.3 Tokenizace podslov: Optimální kompromis
La tokenizace podslov a metoda používaná všemi moderními modely (BERT, GPT, LLaMA, T5). Myšlenka je skvělá: běžná slova zůstávají celistvá, zatímco slova vzácné jsou rozděleny do podjednotek (podslov), které model již viděl.
Algoritmy tokenizace podslov
| Algoritmus | Použité | Strategie | Směr |
|---|---|---|---|
| BPE (Byte Pair Encoding) | GPT-2, GPT-3, GPT-4, LLaMA, RoBERTa | Iterativní slučování nejčastějších dvojic | zdola nahoru |
| WordPiece | BERT, DistilBERT, ELECTRA | Sloučení, které maximalizuje pravděpodobnost | zdola nahoru |
| SentencePiece | T5, ALBERT, XLNet, mBART | Zacházejte s textem jako s nezpracovaným proudem znaků | Jazykově nezávislý |
| Unigram | SentencePiece (volitelné), ALBERT | Vychází z velké slovní zásoby, odstraňuje méně užitečné tokeny | Shora dolů |
Jak funguje BPE (Byte Pair Encoding).
BPE začíná od jednotlivých znaků a iterativně spojuje nejčastější páry dokud nedosáhnete požadované velikosti slovní zásoby.
Corpus: "basso basso bassa basso"
Passo 0 - Vocabolario iniziale (caratteri):
b, a, s, o
Passo 1 - Coppia più frequente: (s, s) -> "ss"
b a ss o b a ss o b a ss a b a ss o
Passo 2 - Coppia più frequente: (a, ss) -> "ass"
b ass o b ass o b ass a b ass o
Passo 3 - Coppia più frequente: (b, ass) -> "bass"
bass o bass o bass a bass o
Passo 4 - Coppia più frequente: (bass, o) -> "basso"
basso basso bass a basso
Vocabolario finale: [b, a, s, o, ss, ass, bass, basso]
WordPiece vs BPE
WordPiece používá podobný přístup jako BPE, ale místo výběru dvojice plus
časté, vyberte ten, který maximalizuje pravděpodobnost korpusu
školení. V praxi WordPiece preferuje sloučení, které produkuje užitečnější tokeny
pro jazykový model, nejen ty nejběžnější. Tokeny, které se nespustí
slovo má předponu ##.
SentencePiece: Jazyková nezávislost
Klíčový rozdíl SentencePiece je v tom nevyžaduje předběžnou tokenizaci. BPE a WordPiece předpokládají, že text je již rozdělen na slova (obvykle mezerou), která funguje dobře pro angličtinu a italštinu, ale selhává u jazyků, jako je čínština, japonština nebo thajština nepoužívají mezery mezi slovy. SentencePiece zachází s textem jako s nezpracovaným proudem bajtů, aby byla skutečně jazykově nezávislá.
3. Praktický příklad: Tokenizace pomocí HuggingFace
Podívejme se konkrétně, jak BERT a GPT-2 tokenizují stejný italský text.
Využijeme knihovnu transformers od HuggingFace.
from transformers import AutoTokenizer
# Testo di esempio in italiano
testo = "L'intelligenza artificiale sta rivoluzionando il mondo"
# --- BERT (WordPiece) ---
bert_tok = AutoTokenizer.from_pretrained("dbmdz/bert-base-italian-cased")
bert_tokens = bert_tok.tokenize(testo)
bert_ids = bert_tok.encode(testo)
print("BERT tokens:", bert_tokens)
print("BERT IDs: ", bert_ids)
# BERT tokens: ['L', "'", 'intelligenza', 'artificiale', 'sta',
# 'rivoluzionando', 'il', 'mondo']
# BERT IDs: [102, 55, 7, 5765, 6892, 379, 28648, 42, 1601, 103]
# --- GPT-2 (BPE) ---
gpt2_tok = AutoTokenizer.from_pretrained("gpt2")
gpt2_tokens = gpt2_tok.tokenize(testo)
gpt2_ids = gpt2_tok.encode(testo)
print("\nGPT-2 tokens:", gpt2_tokens)
print("GPT-2 IDs: ", gpt2_ids)
# GPT-2 tokens: ['L', "'", 'int', 'ell', 'ig', 'enza', ' art',
# 'ific', 'iale', ' sta', ' riv', 'oluz', 'ion',
# 'ando', ' il', ' mondo']
# --- Confronto ---
print(f"\nBERT: {len(bert_tokens)} token")
print(f"GPT-2: {len(gpt2_tokens)} token")
Klíčové postřehy
- BERT italsky (
dbmdz/bert-base-italian-cased) uznává „inteligence“ a „rivoluzionando“ jako celočíselné tokeny, protože jeho slovní zásoba byla trénována na italském textu - GPT-2 rozděluje italská slova na mnohem více podslov, protože jeho slovní zásoba byla trénována hlavně na anglickém textu
- Tokenizér natrénovaný na cílový jazyk produkuje méně tokenů, což znamená více kontextu v okně pozornosti e nižší náklady na token
- BERT přidává speciální tokeny:
[CLS]na začátku a[SEP]nakonec. GPT-2 ne
from transformers import AutoTokenizer
tok = AutoTokenizer.from_pretrained("dbmdz/bert-base-italian-cased")
# Dimensione vocabolario
print(f"Vocabolario BERT italiano: {tok.vocab_size} token")
# Output: Vocabolario BERT italiano: 31102 token
# Token speciali
print(f"[CLS] = {tok.cls_token} (ID: {tok.cls_token_id})")
print(f"[SEP] = {tok.sep_token} (ID: {tok.sep_token_id})")
print(f"[PAD] = {tok.pad_token} (ID: {tok.pad_token_id})")
print(f"[UNK] = {tok.unk_token} (ID: {tok.unk_token_id})")
print(f"[MASK] = {tok.mask_token} (ID: {tok.mask_token_id})")
# Decodifica: da token IDs -> testo
ids = tok.encode("NLP e fantastico")
print(f"\nEncode: {ids}")
print(f"Decode: {tok.decode(ids)}")
# Decode: [CLS] NLP e fantastico [SEP]
4. Bag of Words a TF-IDF: Classical Representations
Před vložením slov byl text reprezentován jako řídké vektory na základě četnosti slov. Tyto metody se stále používají v mnoha kontextech a pochopení jejich omezení pomáhá pochopit, proč bylo vkládání revolucí.
4.1 Bag of Words (BoW)
Modelka Pytel slov představuje dokument jako vektor kde každá pozice odpovídá slovu ve slovní zásobě a jeho hodnotě a počtu výskytů tohoto slova v dokumentu.
from sklearn.feature_extraction.text import CountVectorizer
documenti = [
"il gatto mangia il pesce",
"il cane mangia la carne",
"il gatto insegue il cane"
]
vectorizer = CountVectorizer()
bow_matrix = vectorizer.fit_transform(documenti)
print("Vocabolario:", vectorizer.get_feature_names_out())
# ['cane', 'carne', 'gatto', 'il', 'insegue', 'la', 'mangia', 'pesce']
print("\nMatrice BoW:")
print(bow_matrix.toarray())
# [[0, 0, 1, 2, 0, 0, 1, 1], # doc 1
# [1, 1, 0, 1, 0, 1, 1, 0], # doc 2
# [1, 0, 1, 2, 1, 0, 0, 0]] # doc 3
4.2 TF-IDF (Termínová frekvence – Inverzní frekvence dokumentu)
TF-IDF zlepšuje BoW vážením slov pro jejich vlastní relativní důležitost. Slova, která jsou v dokumentu častá, ale v celkovém korpusu vzácná, mají větší váhu. Všude běžná slova (jako „ten“, „ten“) mají nízkou váhu.
TF-IDF(t, d) = TF(t, d) x IDF(t)
dove:
TF(t, d) = frequenza del termine t nel documento d
IDF(t) = log(N / df(t))
N = numero totale di documenti
df(t) = numero di documenti che contengono il termine t
Esempio:
Parola "gatto" in documento 1:
TF = 1/5 = 0.2 (1 occorrenza su 5 parole)
IDF = log(3/2) = 0.405 (appare in 2 documenti su 3)
TF-IDF = 0.2 x 0.405 = 0.081
from sklearn.feature_extraction.text import TfidfVectorizer
import numpy as np
documenti = [
"il gatto mangia il pesce",
"il cane mangia la carne",
"il gatto insegue il cane"
]
tfidf = TfidfVectorizer()
tfidf_matrix = tfidf.fit_transform(documenti)
print("Feature:", tfidf.get_feature_names_out())
print("\nMatrice TF-IDF (arrotondata):")
print(np.round(tfidf_matrix.toarray(), 3))
# "pesce" e "carne" hanno pesi più alti perchè appaiono
# in un solo documento (più discriminanti)
Limity BoW a TF-IDF
- Žádná sémantika: „pes“ a „psí“ jsou zcela odlišné; „banka“ (řeka) a „banka“ (instituce) jsou totožné
- Žádná objednávka: „kočka žere myš“ a „myš žere kočku“ mají stejné zastoupení
- Vysoká rozměrnost: Slovní zásoba 100 000 slov vytváří 100 000-rozměrné vektory, téměř všechny nuly (řídké vektory)
- Žádná generalizace: Nezachycují vztahy mezi slovy ("král" a "královna" nemají žádnou blízkost)
5. Vložení slov: Význam jako geometrie
I vložení slov způsobili revoluci v NLP přeměnou slov v hustých nízkorozměrných vektorech (typicky 100-300 rozměrů), které zachycují sémantické vztahy mezi slovy. Dvě slova s podobným významem budou mít vektory sousedé ve vektorovém prostoru.
5.1 Word2Vec: Vynález, který všechno změnil
Představil Tomas Mikolov a kolegové (Google, 2013), Word2Old se učí vektory slov počínaje kontextem, ve kterém se objevují. Intuice základní a distribuční hypotéza: „slovo se vyznačuje společnost, kterou drží“ (J.R. Firth, 1957).
Dvě architektury Word2Vec
| Architektura | Vstup | Výstupy | Intuice |
|---|---|---|---|
| CBOW (Nepřetržitý pytlík slov) | Kontext (okolní slova) | Cílové slovo | Vzhledem ke kontextu „ten ___ jí“ předpovězte „kočka“ |
| Přeskočit gram | Cílové slovo | Kontext (okolní slova) | Vzhledem ke slovu "kočka", předvídat "the", "jíst" atd. |
v praxi Přeskočit gram funguje nejlépe s malými datovými sadami a zachycenými soubory vzácná slova jsou lepší. CBOW a rychlejší a dobře funguje s častými slovy.
Frase: "il gatto nero mangia il pesce fresco"
^
parola target
Con window_size = 2, Skip-gram impara:
gatto -> il (contesto a sinistra, distanza 1)
gatto -> nero (contesto a destra, distanza 1)
gatto -> mangia (contesto a destra, distanza 2)
Dopo milioni di frasi, parole che appaiono in contesti
simili avranno vettori simili:
gatto ~ felino ~ micio (contesti simili: "il ___ mangia")
cane ~ canino ~ cucciolo (contesti simili: "il ___ corre")
5.2 Aritmetika slov
Nejpřekvapivější vlastností vkládání slov je, že jsou sémantické vztahy stávají se algebraickými operacemi na nosičích. Slavné přirovnání:
král - muž + žena = královna
Není to náhoda: vektor, který vede od „muže“ k „ženě“, je tentýž, který vede od „krále“ po „královnu“. To funguje pro mnoho vztahů: země-kapitál, sloveso-minulý čas, superlativní přídavné jméno.
import gensim.downloader as api
# Carica word embeddings pre-addestrati
model = api.load("word2vec-google-news-300")
# Analogia: re - uomo + donna = ?
result = model.most_similar(
positive=["king", "woman"],
negative=["man"],
topn=3
)
print("king - man + woman =")
for word, score in result:
print(f" {word}: {score:.4f}")
# king - man + woman =
# queen: 0.7118
# monarch: 0.6189
# princess: 0.5902
# Similarità tra parole
print(f"\ncat ~ dog: {model.similarity('cat', 'dog'):.4f}")
print(f"cat ~ car: {model.similarity('cat', 'car'):.4f}")
# cat ~ dog: 0.7609
# cat ~ car: 0.2004
5.3 Rukavice: Globální vektory pro reprezentaci slov
Rukavice (Stanford, 2014) volí jiný přístup: místo předpovídání kontext slova po slovu jako Word2Vec, GloVe vytváří první globální matice společného výskytu celého korpusu, pak faktorizovat tuto matici získat vektory. Kombinuje výhody metod založených na globální statistiky s lokálními statistikami Word2Vec.
Word2Vec vs GloVe
| čekám | Word2Old | Rukavice |
|---|---|---|
| Metoda | Prediktivní (neuronová síť) | Na základě počtu (maticová faktorizace) |
| Kontext | Místní okno | Globální korpusové statistiky |
| Výcvik | Online (posouvání textu) | Dávka (celé pole) |
| Běžné velikosti | 100, 200, 300 | 50, 100, 200, 300 |
| Výkon | Skvělé pro analogie | Vynikající pro podobnost |
6. Kontextová vložení: stejné slovo, různé významy
Word2Vec a GloVe mají zásadní omezení: přiřazují jeden vektor s každým slovem, bez ohledu na kontext. Ale jazyk je plný nejednoznačnost: slovo „banka“ má úplně jiný význam v „školní lavice“ a „neapolská lavice“.
The kontextová vložení vyřešit tento problém: vektor slova závisí na celé větě, ve které se vyskytuje. Tento přístup používá BERT, GPT a všechny modely založené na Transformeru.
Statické vs. kontextové vkládání
| čekám | Statické (Word2Vec, GloVe) | Kontextové (BERT, GPT) |
|---|---|---|
| Vektor pro slovo | Pevný, vždy stejný | Různé na základě kontextu |
| Polysémie | Nespravováno ("banka" má pouze jednoho operátora) | Managed ("dohoda" má různé vektory pro každý význam) |
| Model | Vyhledávací tabulka | Hluboká neuronová síť (transformátor) |
| Velikost modelu | Málo MB | Stovky MB nebo GB |
| Rychlost | Okamžitý | Vyžaduje průchod vpřed |
from transformers import AutoTokenizer, AutoModel
import torch
import torch.nn.functional as F
# Carica BERT italiano
tokenizer = AutoTokenizer.from_pretrained("dbmdz/bert-base-italian-cased")
model = AutoModel.from_pretrained("dbmdz/bert-base-italian-cased")
def get_word_embedding(sentence: str, word: str):
"""Ottieni l'embedding contestuale di una parola nella frase."""
inputs = tokenizer(sentence, return_tensors="pt")
tokens = tokenizer.tokenize(sentence)
with torch.no_grad():
outputs = model(**inputs)
# outputs.last_hidden_state: [batch, seq_len, hidden_dim]
embeddings = outputs.last_hidden_state[0] # [seq_len, 768]
# Trova l'indice del token target
word_idx = tokens.index(word) + 1 # +1 per [CLS]
return embeddings[word_idx]
# "banco" in contesti diversi
emb_scuola = get_word_embedding("Il banco di scuola e rotto", "banco")
emb_banca = get_word_embedding("Il banco di Napoli e storico", "banco")
emb_pesce = get_word_embedding("Il banco del pesce e fresco", "banco")
# Calcola similarità coseno
sim_12 = F.cosine_similarity(emb_scuola.unsqueeze(0), emb_banca.unsqueeze(0))
sim_13 = F.cosine_similarity(emb_scuola.unsqueeze(0), emb_pesce.unsqueeze(0))
sim_23 = F.cosine_similarity(emb_banca.unsqueeze(0), emb_pesce.unsqueeze(0))
print(f"banco(scuola) ~ banco(banca): {sim_12.item():.4f}")
print(f"banco(scuola) ~ banco(pesce): {sim_13.item():.4f}")
print(f"banco(banca) ~ banco(pesce): {sim_23.item():.4f}")
# I vettori saranno DIVERSI perchè BERT capisce il contesto!
Toto je zásadní koncepční skok: s BERT již slovo „banka“ neexistuje pevný význam. Jeho vektor se mění na základě jeho okolí, stejně jako se děje v lidském chápání jazyka.
7. Vkládání vět: Jeden vektor pro celou větu
Často nepotřebujeme vložení jediného slova, ale acelou větu nebo odstavec. THE vložení vět stlačují význam textu libovolné délky v jediném vektoru pevné velikosti.
Referenční model e Věta-BERT (SBERT), která se mění
architektura BERT pro vytváření vložení vět optimalizovaných pro srovnání
podobnosti. Pro italštinu model paraphrase-multilingual-MiniLM-L12-v2
podporuje více než 50 jazyků s 384 rozměrovými vektory.
Aplikace vkládání vět
| Aplikace | Popis | Jak to funguje |
|---|---|---|
| Sémantické vyhledávání | Hledejte podle významu, ne podle klíčových slov | Vložte dotaz, vyhledejte nejbližší dokumenty |
| Shlukování | Automaticky seskupovat podobné texty | K-means nebo HDBSCAN na vložení |
| Detekce duplicit | Najděte duplikáty nebo téměř duplikáty | Práh podobnosti kosinu > 0,9 |
| Klasifikace Zero-Shot | Pořadí bez tréninkových údajů | Porovnejte vkládání textu s vkládáním štítků |
from sentence_transformers import SentenceTransformer, util
# Modello multilingue (supporta italiano)
model = SentenceTransformer("paraphrase-multilingual-MiniLM-L12-v2")
# Frasi in italiano
frasi = [
"Il gatto dorme sul divano",
"Il felino riposa sul sofa",
"La borsa e salita oggi",
"I mercati finanziari sono in crescita",
"Ho comprato un nuovo computer portatile"
]
# Genera embeddings (1 vettore per frase, 384 dimensioni)
embeddings = model.encode(frasi, convert_to_tensor=True)
print(f"Shape: {embeddings.shape}") # [5, 384]
# Calcola matrice di similarità
cosine_scores = util.cos_sim(embeddings, embeddings)
print("\nMatrice di Similarità:")
for i in range(len(frasi)):
for j in range(i + 1, len(frasi)):
print(f" {frasi[i][:40]:40s} <-> {frasi[j][:40]:40s}")
print(f" Similarità: {cosine_scores[i][j]:.4f}")
# Risultati attesi:
# "gatto dorme" <-> "felino riposa" : ~0.85 (molto simili)
# "borsa salita" <-> "mercati crescita": ~0.70 (correlati)
# "gatto dorme" <-> "borsa salita" : ~0.10 (non correlati)
8. Moderní potrubí NLP
Viděli jsme jednotlivé komponenty. Nyní je dáme dohromady, abychom pochopili, jak to funguje jeden Moderní end-to-end potrubí NLP, který používají BERT, GPT a všechny modely založené na Transformeru.
Testo Grezzo
|
v
[1. TOKENIZZAZIONE]
Input: "L'intelligenza artificiale e fantastica"
Output: ["L'", "intelligenza", "artificiale", "e", "fantastica"]
|
v
[2. ENCODING (Token -> ID)]
Input: ["L'", "intelligenza", "artificiale", "e", "fantastica"]
Output: [102, 55, 5765, 6892, 15, 23456, 103]
^[CLS] ^[SEP]
|
v
[3. EMBEDDING LAYER]
Input: [102, 55, 5765, 6892, 15, 23456, 103]
Output: Matrice [7 x 768] - un vettore 768-dim per ogni token
|
v
[4. TRANSFORMER ENCODER/DECODER]
Self-Attention: ogni token "guarda" tutti gli altri
Input: Matrice [7 x 768]
Output: Matrice [7 x 768] (vettori contestualizzati)
|
v
[5. TASK HEAD]
Classificazione: [CLS] embedding -> softmax -> classe
NER: ogni token -> etichetta entità
Generazione: ultimo token -> prossimo token
QA: posizione inizio/fine risposta
Role tokenu [CLS]
V BERT, speciální token [CLS] se vkládá na začátek každého vstupu.
Po průchodu všemi vrstvami Transformeru představuje jeho zapuštění
celou sekvenci. A používá se jako vstup pro klasifikační úkoly
(analýza sentimentu, detekce spamu atd.).
9. NLP pro italštinu: Specifika a nástroje
Italština představuje pro NLP jedinečné výzvy, které ji odlišují od angličtiny a z jiných jazyků. Znalost těchto specifik je pro budování systémů zásadní Efektivní NLP pro italštinu.
9.1 Lingvistické výzvy italštiny
Speciální funkce italštiny pro NLP
| Výzva | Popis | Příklad |
|---|---|---|
| Bohatá morfologie | Každé sloveso má desítky konjugovaných tvarů | "jíst" má 50+ forem (jím, jím, jím, jíme...) |
| Elise a apostrofy | Členy a předložky splývají | "muž", "umění", "přítel", "tento rok" |
| Členité předložky | Předložka + člen ve slově | "del" (di+il), "nello" (in+lo), "sulla" (su+la) |
| Výrazné akcenty | Mění význam | "e" (a) vs "e" (je), "da" (od) vs "da" (dává) |
| Klitická zájmena | Drží se slovesa | "dej mi to" (dej+mně+to), "přines mu to" |
| Objednávka zdarma | SVO není povinné | "Marco jí dort" = "Marco jí dort" |
9.2 Předtrénované modely pro italštinu
Hlavní italské modely
| Model | Základní | Úkoly | Úložiště |
|---|---|---|---|
| dbmdz/bert-base-italian-cased | BERT | Italské NLP pro všeobecné použití | Objímání tváře |
| Alberto | BERT | Italská sociální média (Twitter) | Objímání tváře |
| cit-it-italský-sentiment | UmBERTo | Analýza italského sentimentu | MilanNLProc |
| cítit-to-italsky-emoce | UmBERTo | Detekce emocí (radost, vztek, strach, smutek) | MilanNLProc |
| Italsko-právní-BERT | BERT | Italské právní texty | dlicari |
| DeepMount00/Italian_NER_XXL | BERT | Italské rozpoznávání jmenovaných entit | Objímání tváře |
| it_core_news_lg | prostor CNN | Tokenizace, POS, NER, lemma, parsování | prostorovost |
9.3 Předzpracování Specifické pro italštinu
import spacy
import re
class ItalianPreprocessor:
"""Pipeline di preprocessing specifica per l'italiano."""
def __init__(self):
self.nlp = spacy.load("it_core_news_lg")
# Stopwords aggiuntive regionali/informali
self.custom_stops = {
"cioe", "quindi", "comunque", "praticamente",
"allora", "insomma", "magari", "ecco", "tipo",
"boh", "mah", "vabbe", "ok", "okay"
}
def preprocess(self, text: str, remove_stops: bool = True,
lemmatize: bool = True) -> list[str]:
"""Preprocessing completo per testo italiano."""
# 1. Normalizzazione base
text = text.lower()
text = re.sub(r'http\S+|www\.\S+', '', text) # rimuovi URL
text = re.sub(r'[^\w\s\']', '', text) # mantieni apostrofi
text = re.sub(r'\d+', '', text) # rimuovi numeri
text = re.sub(r'\s+', ' ', text).strip()
# 2. Analisi con spaCy
doc = self.nlp(text)
# 3. Filtraggio e lemmatizzazione
tokens = []
for token in doc:
# Salta punteggiatura e spazi
if token.is_punct or token.is_space:
continue
# Salta stopwords se richiesto
if remove_stops and (token.is_stop or
token.text in self.custom_stops):
continue
# Lemmatizza o usa la forma originale
word = token.lemma_ if lemmatize else token.text
if len(word) > 1: # salta caratteri singoli
tokens.append(word)
return tokens
# Esempio d'uso
prep = ItalianPreprocessor()
testo = """L'intelligenza artificiale sta rivoluzionando
il modo in cui le aziende italiane gestiscono i loro
processi, cioe praticamente tutto sta cambiando."""
risultato = prep.preprocess(testo)
print("Token processati:", risultato)
# ['intelligenza', 'artificiale', 'rivoluzionare', 'modo',
# 'azienda', 'italiano', 'gestire', 'processo', 'cambiare']
10. End-to-End Příklad: Sémantické vyhledávání v italštině
Shrňme vše, co jsme se naučili, do jednoho úplného příkladu: a sémantické vyhledávání na korpus italských textů. Daná sada dokumentů a uživatelského dotazu najdeme pomocí nejrelevantnějších dokumentů vložení vět.
from sentence_transformers import SentenceTransformer, util
import torch
class SemanticSearchIT:
"""Motore di ricerca semantica per testi italiani."""
def __init__(self, model_name: str =
"paraphrase-multilingual-MiniLM-L12-v2"):
self.model = SentenceTransformer(model_name)
self.documents: list[str] = []
self.embeddings = None
def index_documents(self, documents: list[str]) -> None:
"""Indicizza i documenti calcolando gli embeddings."""
self.documents = documents
self.embeddings = self.model.encode(
documents,
convert_to_tensor=True,
show_progress_bar=True
)
print(f"Indicizzati {len(documents)} documenti")
print(f"Shape embeddings: {self.embeddings.shape}")
def search(self, query: str, top_k: int = 3) -> list[dict]:
"""Cerca i documenti più rilevanti per la query."""
query_embedding = self.model.encode(
query, convert_to_tensor=True
)
scores = util.cos_sim(query_embedding, self.embeddings)[0]
top_results = torch.topk(scores, k=min(top_k, len(self.documents)))
results = []
for score, idx in zip(top_results.values, top_results.indices):
results.append({
"documento": self.documents[idx],
"score": round(score.item(), 4),
"indice": idx.item()
})
return results
# --- Esempio d'uso ---
corpus = [
"Python e un linguaggio di programmazione versatile e facile da imparare",
"Il machine learning permette ai computer di imparare dai dati",
"Angular e un framework per costruire applicazioni web moderne",
"La pasta alla carbonara e un piatto tipico della cucina romana",
"I database relazionali usano SQL per interrogare i dati",
"Il deep learning utilizza reti neurali con molti strati nascosti",
"Roma e la capitale d'Italia e ha una storia millenaria",
"Le API REST permettono la comunicazione tra servizi web",
"Il Natural Language Processing analizza e comprende il testo",
"La pizza napoletana e patrimonio UNESCO dal 2017"
]
# Crea il motore di ricerca e indicizza
search_engine = SemanticSearchIT()
search_engine.index_documents(corpus)
# Esegui alcune ricerche
queries = [
"come analizzare il linguaggio naturale",
"framework per sviluppo frontend",
"cucina tradizionale italiana"
]
for query in queries:
print(f"\nQuery: '{query}'")
print("-" * 60)
results = search_engine.search(query, top_k=3)
for i, r in enumerate(results, 1):
print(f" {i}. [{r['score']:.4f}] {r['documento']}")
Očekávané výsledky
Sémantické vyhledávání zahrnuje význam, nejen slova. Například:
- "jak analyzovat přirozený jazyk" najde dokument NLP, i když neobsahuje přesně tato slova
- "rámec pro vývoj frontendu" najde Angular, i když se „frontend“ v dokumentu neobjeví (ale „moderní webové aplikace“ sémanticky souvisí)
- "tradiční italská kuchyně" najde carbonara i pizzu, protože model rozumí sémantickému vztahu
Plán: Odtud k LLM
V tomto článku jsme postavili základy moderního NLP, počínaje předzpracování textu až po kontextové vkládání a kompletní kanál. Shrňme si cestu, kterou jsme se vydali:
Souhrn pojmů
| Pojem | Co dělá | Vývoj |
|---|---|---|
| Předzpracování | Čistí a normalizuje nezpracovaný text | Manuální pravidla -> spaCy potrubí |
| Tokenizace | Rozdělí text na samostatné jednotky | Word -> Char -> Subword (BPE/WordPiece) |
| BoW/TF-IDF | Reprezentuje text jako řídké vektory | Jednoduché, ale bez sémantiky |
| Word Embeddings | Husté vektory, které zachycují význam | Word2Vec -> Rukavice -> FastText |
| Kontextová vložení | Kontextově závislé vektory | ELMo -> BERT -> GPT |
| Vkládání vět | Vektor pro celou větu | Sdružování médií -> Sentence-BERT |
Nel další článek uděláme skok k architektuře, která má způsobil revoluci ve všem: Transformátory. Mechanismus uvidíme podrobně z Sebepozornost, pochopíme, proč BERT změnil hru, a naučíme se používat jej pro skutečné úkoly, jako je klasifikace textu a odpovídání na otázky.
Zdroje, kde se dozvíte více
- SpaCy italské modely: Oficiální dokumentace pro modely spaCy Italian (spacy.io/models/it)
- Modely HuggingFace: Úložiště předem vycvičených italských modelů (huggingface.co/models?language=it)
- Věta-BERT: dokumentace k transformátorům vět (sbert.net)
- CÍTIT TO: Analýza sentimentu a klasifikace emocí pro italštinu (MilaNLProc)
- Papír Word2Vec: "Efektivní odhad slovních reprezentací ve vektorovém prostoru" (Mikolov et al., 2013)
- Papírové rukavice: „Globální vektory pro slovní reprezentaci“ (Pennington a kol., 2014)
- Papírový BERT: „BERT: Předtrénink hlubokých obousměrných transformátorů“ (Devlin et al., 2019)







