NLP の基礎: トークン化、埋め込み、最新のパイプライン
音声アシスタントに何かを尋ねるたびに、Google 翻訳でテキストを翻訳し、 電子メールの受信トレイでスパムをフィルターしたり、ビデオの自動字幕を読んだりできます。 を使用していますか 自然言語処理 (NLP)。この規律は、 言語学、コンピューターサイエンス、人工知能の交差点で、次のことを扱います。 機械に人間の言語を理解し、解釈し、生成するように教えることです。
近年、NLP の分野は急激な変化を遂げています。私たちは通り過ぎました ニュアンスを理解できるニューラルモデルへの手書きのルールと静的辞書、 文脈や皮肉さえも。 バート, GPT, ラマ そして次世代モデルは、これから探求する基礎がなければ不可能です。 この記事では: トークン化, gli 埋め込み そして 最新の NLP パイプライン.
これはシリーズの最初の記事です 最新の NLP: BERT から LLM へ。 絶対的な基礎から始めて、必要な直感を段階的に構築していきます より高度な言語モデルを理解するために。特に注意を払います 英語圏のリソースでは見落とされがちな、イタリア語の特殊性について説明します。
何を学ぶか
- NLP とは何ですか、なぜそれがほぼすべての最新の AI アプリケーションの基礎になっているのか
- テキストの前処理方法: 小文字化、ストップワード、ステミング、見出し語化
- トークン化へのさまざまなアプローチ: 単語レベル、文字レベル、サブワード (BPE、WordPiece、SentencePiece)
- 古典的なテキスト表現: Bag of Words と TF-IDF
- 単語の埋め込み: Word2Vec、GloVe、および幾何学的な意味の直観
- コンテキスト埋め込み: 静的表現から BERT まで
- 文の埋め込みとその実際の応用
- 最新の NLP パイプライン: 生のテキストから予測まで
- イタリア語の前処理の特異性
- Python コードを使用した完全なエンドツーエンドの例
シリーズ概要
| # | アイテム | 集中 |
|---|---|---|
| 1 | 現在位置 - NLP の基礎 | トークン化、埋め込み、パイプライン |
| 2 | BERTとトランスフォーマー | アテンションアーキテクチャ、事前トレーニング |
| 3 | 感情分析 | BERT によるテキスト分類 |
| 4 | 固有表現の認識 | テキストからのエンティティの抽出 |
| 5 | ハグフェイストランスフォーマー | 事前トレーニングされたライブラリとモデル |
| 6 | モデルの微調整 | BERT をドメインに適応させる |
| 7 | イタリア語のNLP | イタリア語のテンプレートとリソース |
| 8 | BERT から LLM へ | GPT、LLaMA、テキスト生成 |
1. テキストの前処理: データの準備
NLP モデルがテキストを処理できるようにするには、事前にこれを行う必要があります。 クリーンで正常化された。ラフでノイズの多いテキスト: 句読点、 大文字、略語、絵文字、HTML、URL。前処理はこの混乱を 構造化された一貫した形式。
1.1 小文字化と正規化
最初のステップは、すべてのテキストを小文字に変換することです。コンピュータの場合は、「ホーム」、「自宅」、 「HOME」は 3 つのまったく異なる文字列です。小文字にすると統一されます。
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"
イタリア語のアクセントに注意
多くの英語圏の NLP パイプラインでは、アクセントの削除が標準的な手順です。イタリア語では、 ただし、アクセントによって単語の意味が変わります。 "しかし" (接続詞) 対 "しかし" (木)、 "そして" (接続詞) vs "そして" (動詞であること)。 アクセントを決して削除しないでください イタリア語のテキストを扱う場合。
1.2 ストップワード: 情報内容のない単語
Le ストップワード これらは非常に頻繁に使用される単語ですが、意味的な意味はほとんどありません。 冠詞、前置詞、接続詞。それらを削除すると、データの次元が削減されます。 モデルが意味のある単語に集中できるようにします。
イタリア語と英語のストップワード
| Lingua | ストップワードの例 | 一般的な数 |
|---|---|---|
| 英語 | その、である、で、どの、上、a、an、および、または | ~180単語 |
| イタリア語 | その、その、その、の、に、から、で、で、に、のために、それ、そして、ではない、 | ~300単語 |
イタリア語は冠詞が豊富であるため、英語よりもストップワードが多い (il、lo、la、i、gli、le)、分節前置詞 (del、dello、della、nei、nei、nelle) そして助動詞の形。
# 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 ステミングと見出し語化
どちらのテクニックも単語を基本的な形式に変換しますが、その方法は大きく異なります。
ステミングと見出し語化 - 比較
| 待ってます | ステミング | 見出し語化 |
|---|---|---|
| 方法 | ヒューリスティックルールによるサフィックスのカット | 辞書と形態素解析を使用する |
| 結果 | 語幹 (必ずしも実際の単語であるとは限りません) | Lemma (辞書からの実際の単語) |
| ITの例 | 「食べる」→「食べる」 | 「食べる」→「食べる」 |
| スピード | 非常に速い | 遅い(辞書が必要) |
| 精度 | 低 (一般的なオーバーステミング) | 高(正しいフォーム) |
| イタリア人向け | スノーボール ステマー (イタリアン ポーター) | 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)
イタリア語の場合、 spaCy による見出し語化 そしてほとんどの場合好ましい
ステミングに。モデル it_core_news_lg 500,000 個の単語ベクトルが含まれています
トークン化、POS タグ付け、依存関係解析、NER、および見出し語化をサポートします。
2. トークン化: 機械がテキストを読み取る方法
La トークン化 テキストを個別の単位に分割するプロセス 電話 トークン。 NLP パイプラインの最初で最も重要なステップは次のとおりです。 トークン化の品質は、後続の各モデルのパフォーマンスに直接影響します。
基本的なアプローチは 3 つあり、それぞれに異なる利点とトレードオフがあります。
2.1 単語レベルのトークン化
最も直感的なアプローチ: 各単語がトークンになります。
# 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
単語レベルのトークン化の制限
- 膨大な語彙: それぞれの固有の単語には語彙エントリが必要です。イタリア語には何十万もの活用形がある
- 語彙外の単語 (OOV): トレーニング中に一度も見たことのない単語は <UNK> (不明) になります。
- 形態学的共有なし: 「eat」、「eating」、「ate」は 3 つの完全に別個の無関係なトークンです。
2.2 文字レベルのトークン化
対極では、各文字がトークンになります。語彙が少ない (26 文字 + 数字 + 句読点) ただし、シーケンスは非常に長くなります。
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!)
文字のトークン化により、未知の単語 (あらゆる単語) の問題が解決されます。 表現できます)が、非常に長いシーケンスによりモデルが困難になります。 遠距離関係をテキストで捉えます。
2.3 サブワードのトークン化: 最適な妥協策
La サブワードのトークン化 そしてすべての最新モデルで使用されている方法 (BERT、GPT、LLaMA、T5)。このアイデアは素晴らしいです。一般的な単語はそのまま残りますが、単語はそのまま残ります。 rare は、モデルがすでに認識しているサブユニット (サブワード) に分割されます。
サブワードトークン化アルゴリズム
| アルゴリズム | 使用者 | 戦略 | 方向 |
|---|---|---|---|
| BPE (バイトペアエンコーディング) | GPT-2、GPT-3、GPT-4、LLaMA、RoBERTa | 最も頻繁に使用されるペアの反復マージ | ボトムアップ |
| ワードピース | BERT、DistilBERT、ELECTRA | 可能性を最大化するマージ | ボトムアップ |
| センテンスピース | T5、アルバート、XLNet、mBART | テキストを文字の生のストリームとして扱う | 言語に依存しない |
| ユニグラム | SentencePiece (オプション)、アルバート | 大量の語彙から開始し、あまり有用でないトークンを削除します | トップダウン |
BPE (バイト ペア エンコーディング) の仕組み
BPE は単一の文字から開始し、最も頻繁に使用されるペアを繰り返しマージします。 希望の語彙サイズに達するまで。
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 と BPE の比較
WordPiece は BPE と同様のアプローチを使用しますが、プラス ペアを選択する代わりに
頻繁を最大化するものを選択してください。 可能性 コーパスの
トレーニングの。実際には、WordPiece はより有用なトークンを生成するマージを優先します。
単に最も一般的なものではなく、言語モデルについてです。起動しないトークン
単語に接頭辞が付く ##.
SentencePiece: 言語の独立性
SentencePiece の主な違いは次のとおりです。 事前のトークン化は必要ありません。 BPE と WordPiece は、テキストがすでに単語 (通常はスペースによって) に分割されていることを前提としています。 英語とイタリア語ではうまく機能しますが、中国語、日本語、タイ語などの言語では失敗します。 彼らは単語の間にスペースを使用しません。 SentencePiece はテキストをバイトの生のストリームとして扱います。 真に言語に依存しないようにします。
3. 実践例: HuggingFace によるトークン化
BERT と GPT-2 が同じイタリア語テキストをどのようにトークン化するかを具体的に見てみましょう。
図書館を利用します transformers ハギングフェイスによる。
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")
主な所見
- バート イタリア語 (
dbmdz/bert-base-italian-cased) 語彙はイタリア語のテキストで訓練されているため、「Intelligence」と「rivoluzionando」を整数トークンとして認識します。 - GPT-2 イタリア語の単語をさらに多くのサブワードに分割します。その語彙は主に英語のテキストで訓練されているためです。
- ターゲット言語でトレーニングされたトークナイザーは生成するトークンが少なくなります。つまり、 アテンションウィンドウの詳細なコンテキスト e トークンあたりのコストが低い
- BERT は特別なトークンを追加します。
[CLS]初めにそして[SEP]最後に。 GPT-2はそうではありません
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 と TF-IDF: 古典的な表現
単語が埋め込まれる前は、テキストは次のように表現されていました。 スパースベクトル 単語の頻度に基づいて。これらの方法は今でも多くの状況で使用されています そしてその限界を理解することは、なぜ埋め込みが革命であったのかを理解するのに役立ちます。
4.1 バッグ・オブ・ワード (BoW)
モデル 言葉の袋 ドキュメントをベクトルとして表します。 各位置は語彙とその値と数に対応します。 文書内でその単語が出現する箇所。
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 (用語頻度 - 逆文書頻度)
TF-IDF は単語自体に重み付けをすることで BoW を改善します 相対的な重要性。 文書内で頻繁に使用されるが、コーパス全体ではまれな単語は、より大きな重みを受け取ります。 どこでもよく使われる単語 (「the」、「the」など) の重みは低くなります。
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)
BoW と TF-IDF の制限
- セマンティクスなし: 「犬」と「犬」は全く違います。 「bank」(川)と「bank」(機関)は同じです
- 注文なし: 「猫がネズミを食べる」と「ネズミが猫を食べる」は同じ表現です
- 高次元性: 100,000 語の語彙は、ほぼすべてがゼロである 100,000 次元のベクトル (疎ベクトル) を生成します。
- 一般化はできません: 単語間の関係を捉えていません (「キング」と「クイーン」には親密性がありません)。
5. 単語の埋め込み: 幾何学としての意味
I 単語の埋め込み 彼らは単語を変換することで NLP に革命をもたらしました 高密度の低次元ベクトル (通常は 100 ~ 300 次元) でキャプチャ 単語間の意味上の関係。似た意味を持つ 2 つの単語は次のようになります。 ベクトル 隣人 ベクトル空間で。
5.1 Word2Vec: すべてを変えた発明
Tomas Mikolov らによって導入されました (Google、2013)。 Word2古い 単語が出現するコンテキストから単語のベクトルを学習します。直感 基本仮説と分布仮説: 「単語は次のような特徴を持っています。 彼は会社を続けています」(JR. R. ファース、1957)。
2 つの Word2Vec アーキテクチャ
| 建築 | 入力 | 出力 | 直感 |
|---|---|---|---|
| CBOW (連続した言葉の袋) | コンテキスト(周囲の単語) | 対象単語 | 「__ は食べる」というコンテキストを考慮して、「猫」を予測します |
| スキップグラム | 対象単語 | コンテキスト(周囲の単語) | 「猫」という単語が与えられた場合、「その」、「食べる」などを予測します。 |
実際には、 スキップグラム 小規模なデータセットとキャプチャで最適に機能します 珍しい言葉の方が良いです。 CBOW より高速で、頻繁に使用される単語に適しています。
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 言葉の算術
単語埋め込みの最も驚くべき特性は、 意味的な関係 それらは代数演算になります キャリア上で。有名なたとえ:
王 - 男性 + 女性 = 女王
それは偶然ではありません。「男」から「女」に向かうベクトルは、「男」から「女」に向かうベクトルと同じです。 「王様」から「女王様」へ。これは、国と首都、動詞と過去形など、多くの関係で機能します。 最上級の形容詞。
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 GloVe: 単語表現のためのグローバル ベクトル
グローブ (スタンフォード、2014) は、予測する代わりに、異なるアプローチを採用しています。 Word2Vec のような単語ごとのコンテキスト、GloVe が最初のコンテキストを構築 グローバル共起行列 コーパス全体の因数分解 この行列を使用してベクトルを取得します。に基づいた方法の利点を組み合わせます。 グローバル統計と Word2Vec ローカル学習の統計。
Word2Vec 対 GloVe
| 待ってます | Word2古い | グローブ |
|---|---|---|
| 方法 | 予測 (ニューラル ネットワーク) | カウントベース (行列因数分解) |
| コンテクスト | ローカルウィンドウ | グローバルコーパス統計 |
| トレーニング | オンライン(テキストスクロール) | バッチ (完全な配列) |
| 一般的なサイズ | 100、200、300 | 50、100、200、300 |
| パフォーマンス | 類推に最適 | 類似性に優れています |
6. コンテキスト埋め込み: 同じ単語でも異なる意味
Word2Vec と GloVe には基本的な制限があります。 単一のベクトル すべての言葉でコンテキストに関係なく。でも言語はいっぱいある 曖昧さ: 「銀行」という言葉は、世界ではまったく異なる意味を持っています。 「スクールデスク」と「ナポリデスク」。
Gli コンテキストに応じた埋め込み この問題を解決します: ベクトル 単語の内容は、その単語が出現する文全体によって決まります。これは、次の方法で使用されるアプローチです。 BERT、GPT、およびすべての Transformer ベースのモデル。
静的埋め込みとコンテキスト埋め込み
| 待ってます | 静的 (Word2Vec、GloVe) | コンテキスト (BERT、GPT) |
|---|---|---|
| 単語のベクトル | 固定されたもの、常に同じもの | 文脈に応じて異なる |
| 多義性 | 非管理 (「銀行」には 1 つの通信会社しかありません) | マネージド (「取引」には意味ごとにベクトルが異なります) |
| モデル | ルックアップテーブル | ディープ ニューラル ネットワーク (トランスフォーマー) |
| モデルサイズ | 数MB | 数百MBまたはGB |
| スピード | インスタント | フォワードパスが必要です |
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!
これは根本的な概念の飛躍です。BERT では、「銀行」という言葉はもう存在しません。 固定された意味。まるで周囲の環境に応じてベクトルが変化します。 人間の言語理解の中で起こります。
7. 文の埋め込み: 文全体に対する 1 つのベクトル
多くの場合、単一の単語の埋め込みは必要ありませんが、文全体または 段落。ザ 文の埋め込み 彼らは意味を圧縮する 単一の固定サイズのベクトル内の任意の長さのテキスト。
参照モデル e 文-BERT(SBERT)、変化します
比較に最適化された文埋め込みを生成する BERT アーキテクチャ
類似性の。イタリア人の場合、モデルは paraphrase-multilingual-MiniLM-L12-v2
384 次元ベクトルで 50 以上の言語をサポートします。
文埋め込みの応用
| 応用 | 説明 | 仕組み |
|---|---|---|
| セマンティック検索 | キーワードではなく意味で検索する | クエリを埋め込み、最も近いドキュメントを検索します |
| クラスタリング | 類似したテキストを自動的にグループ化する | 埋め込みに対する K 平均法または HDBSCAN |
| 重複の検出 | 重複または重複に近いものを見つける | コサイン類似度のしきい値 > 0.9 |
| ゼロショット分類 | トレーニングデータなしのランキング | テキストの埋め込みとラベルの埋め込みを比較する |
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. 最新の NLP パイプライン
個々のコンポーネントを見てきました。では、それがどのように機能するかを理解するためにそれらをまとめてみましょう 1つ 最新のエンドツーエンド NLP パイプライン、BERT、GPT、および すべてのモデルはトランスフォーマーに基づいています。
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
トークンの役割 [CLS]
BERT では、特別なトークン [CLS] 各入力の先頭に挿入されます。
Transformer のすべての層を通過した後、その埋め込みは次のことを表します。
シーケンス全体。分類タスクの入力として使用されます
(感情分析、スパム検出など)。
9. イタリア語の NLP: 特殊性とツール
イタリア語には、英語とは異なる NLP 特有の課題があります。 そして他の言語からも。システムを構築するには、これらの特性を知ることが不可欠です イタリア語のための効果的なNLP。
9.1 イタリア語の言語的課題
NLP のためのイタリア語の特徴
| チャレンジ | 説明 | Esempio |
|---|---|---|
| 豊富な形態 | 各動詞には数十の活用形があります | 「食べる」には 50 以上の形式があります (私は食べる、私は食べる、私は食べる、私たちは食べる...) |
| 省略とアポストロフィ | 冠詞と前置詞が結合する | 「その人」、「芸術の」、「友人」、「今年」 |
| 分節前置詞 | 単語の前置詞 + 冠詞 | 「デル」(ディ+イル)、「ネロ」(イン+ロ)、「スラ」(ス+ラ) |
| 重要なアクセント | 彼らは意味を変える | 「e」(そして)対「e」(ある)、「だ」(から)対「だ」(与える) |
| 批判語の代名詞 | 彼らは動詞に固執します | 「それを私にください」(Give+me+it)、「それを彼に持ってきてください」 |
| 無料注文 | SVOは必須ではありません | 「マルコはケーキを食べる」 = 「マルコはケーキを食べる」 |
9.2 イタリア語用の事前トレーニング済みモデル
主なイタリアモデル
| モデル | 基本 | タスク | リポジトリ |
|---|---|---|---|
| dbmdz/bert-base-イタリア語ケース | バート | 汎用イタリア語 NLP | ハグ顔 |
| アルベルト | バート | イタリアのソーシャル メディア (Twitter) | ハグ顔 |
| イタリアの感情を感じる | ウンバート | イタリア人の感情分析 | ミラNLProc |
| イタリアの感情を感じてください | ウンバート | 感情検知(喜び、怒り、恐怖、悲しみ) | ミラNLProc |
| イタリア法-BERT | バート | イタリアの法律書 | ドリカリ |
| ディープマウント00/イタリアン_NER_XXL | バート | イタリア語の固有表現の認識 | ハグ顔 |
| it_core_news_lg | スペイシーCNN | トークン化、POS、NER、補題、解析 | スペイシー |
9.3 イタリア語に特有の前処理
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. エンドツーエンドの例: イタリア語のセマンティック検索
これまで学んだすべてを 1 つの完全な例にまとめてみましょう。 セマンティック検索 イタリア語テキストのコーパス。セットが与えられると ドキュメントとユーザーのクエリから、最も関連性の高いドキュメントを見つけます。 文の埋め込み。
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']}")
期待される結果
セマンティック検索には、 意味、言葉だけではありません。例えば:
- 「自然言語を解析する方法」 それらの単語が正確に含まれていない場合でも、NLP ドキュメントを検索します。
- 「フロントエンド開発のフレームワーク」 「フロントエンド」がドキュメントに現れない場合でも、Angular が検索されます (ただし、「最新の Web アプリケーション」は意味的に関連しています)。
- 「伝統的なイタリア料理」 モデルは意味的な関係を理解しているため、カルボナーラとピザの両方が見つかります。
ロードマップ: ここから LLM へ
この記事では、以下から始めて最新の NLP の基礎を構築しました。 コンテキスト埋め込みと完全なパイプラインに至るまでのテキストの前処理。 私たちがたどった道を要約しましょう。
概念の概要
| コンセプト | 彼がやっていること | 進化 |
|---|---|---|
| 前処理 | 生のテキストをクリーンアップして正規化します | 手動ルール -> spaCy パイプライン |
| トークン化 | テキストを個別の単位に分割します | 単語 -> 文字 -> サブワード (BPE/WordPiece) |
| バウ/TF-IDF | テキストをスパースベクトルとして表現します | シンプルだがセマンティクスがない |
| 単語の埋め込み | 意味を捉える高密度のベクトル | Word2Vec -> GloVe -> FastText |
| コンテキスト埋め込み | コンテキスト依存ベクトル | ELMo -> BERT -> GPT |
| 文の埋め込み | 文全体のベクトル | メディアプーリング -> 文-BERT |
Nel 次の記事 を備えたアーキテクチャへ飛躍します。 すべてに革命を起こした: トランスフォーマー。仕組みを詳しく見ていきます の 自己注意、なぜ BERT がゲームチェンジャーであったのかを理解し、学びます テキスト分類や質問応答などの実際のタスクに使用します。
詳細を学ぶためのリソース
- スペイシーなイタリア人モデル: spaCy イタリアモデルの公式ドキュメント (spacy.io/models/it)
- ハグフェイスモデル: 事前トレーニングされたイタリア語モデルのリポジトリ (huggingface.co/models? language=it)
- 文-BERT: 文変換ドキュメント (sbert.net)
- フィールイット: イタリア語の感情分析と感情分類 (MilaNLProc)
- 紙のWord2Vec: 「ベクトル空間における単語表現の効率的な推定」 (Mikolov et al.、2013)
- 紙手袋: 「単語表現のためのグローバル ベクトル」 (Pennington et al.、2014)
- 紙のBERT: 「BERT: ディープ双方向トランスフォーマーの事前トレーニング」 (Devlin et al.、2019)







