Wyjaśnienie BERT: architektura, szkolenie wstępne i dostrajanie
Rok 2018 był punktem zwrotnym w historii przetwarzania języka naturalnego. Wraz z publikacją BERT (Dwukierunkowe reprezentacje enkodera z transformatorów), ma to zrobić zespół Google AI wprowadził model, który na nowo zdefiniował stan wiedzy w 11 benchmarkach NLP jednocześnie. Dla Po raz pierwszy pojedynczy, wstępnie wytrenowany model można było dostosować do bardzo różnych zadań (klasyfikacja, odpowiadanie na pytania, NER) uzyskując wyniki przewyższające wszystkie wyspecjalizowane systemy precedensy.
Ale co czyni BERT tak rewolucyjnym? Odpowiedź kryje się w trzech podstawowych innowacjach: the głęboka dwukierunkowość, il szkolenie wstępne na dużą skalę i prostota dostrajanie do dalszych zadań. W tym artykule przeanalizujemy każdy aspekt architektury BERT, od wewnętrznych mechanizmów uwagi po wdrożenie ćwicz z HuggingFace, przeglądając wywodzące się z niego odmiany.
To drugi artykuł z tej serii Nowoczesne NLP: od BERT do LLM. Jeśli nie przeczytałeś jeszcze pierwszego artykułu o podstawach (tokenizacja, osadzanie i potoki NLP), Radzę ci to zrobić przed kontynuowaniem: wiele z omawianych tutaj koncepcji jest skonstruowanych na tych podstawach.
Czego się nauczysz
- dlaczego BERT reprezentował rewolucję w NLP i ograniczenia poprzednich modeli
- Architektura oparta wyłącznie na enkoderze Transformer, leżąca u podstaw BERT
- Jak działa wielogłowa samouważność i wzory matematyczne
- Reprezentacja wejściowa: osadzanie tokenów, segmentów i pozycji
- Dwie strategie przedtreningowe: model języka maskowanego (MLM) i przewidywanie następnego zdania (NSP)
- Tokenizacja WordPiece i tokeny specjalne [CLS], [SEP], [MASK]
- Jak dokonać dostrojenia pod kątem klasyfikacji, NER, odpowiadania na pytania
- Kompletna, praktyczna implementacja za pomocą transformatorów HuggingFace
- Warianty BERT: RoBERTa, ALBERT, DistilBERT, DeBERTa, ELECTRA
- BERT dla języka włoskiego: dostępne modele i porównanie
- Granice BERT i sposób, w jaki późniejsze modele je pokonały
Przegląd serii
| # | Przedmiot | Centrum |
|---|---|---|
| 1 | Podstawy NLP | Tokenizacja, osadzanie, potoki |
| 2 | Jesteś tutaj - BERT i Transformer | Uwaga na architekturę, szkolenie wstępne |
| 3 | Analiza sentymentów | Klasyfikacja tekstu za pomocą BERT |
| 4 | Rozpoznawanie nazwanych podmiotów | Ekstrakcja bytów z tekstu |
| 5 | Transformatory HuggingFace | Wstępnie przeszkolona biblioteka i modele |
| 6 | Dostrajanie modeli | Dostosuj BERT do swojej domeny |
| 7 | NLP dla języka włoskiego | Szablony i zasoby dla języka włoskiego |
| 8 | Od BERT do LLM | GPT, LLaMA i generowanie tekstu |
1. dlaczego BERT zrewolucjonizował NLP
Aby zrozumieć wpływ BERT, musimy wrócić do krajobrazu NLP sprzed 2018 roku i zrozumieć jakich podstawowych problemów nie rozwiązały poprzednie modele.
1.1 Ograniczenia Word2Vec i GloVe
Jak widzieliśmy w pierwszym artykule z tej serii, Word2Stary (2013) odc Rękawica (2014) były ważnym punktem zwrotnym: po raz pierwszy słowa były reprezentowane jako gęste wektory w ciągłej przestrzeni, w której zachodziły relacje semantyczne jako że „król – mężczyzna + kobieta = królowa” wyłonił się naturalnie z geometrii przestrzeni.
Modele te mają jednak podstawowe ograniczenie: produkują reprezentacje statyczne. Każde słowo ma unikalny wektor, niezależnie od kontekstu, w jakim się pojawia. Rozważmy słowo „ławka”:
Problem reprezentacji statycznych
- „Wpłaciłem pieniądze ławka" (instytucja bankowa)
- "Il ławka był za młody w szkole” (komórka)
- "A ławka mgła pokryła dolinę” (masa mgły)
- "Il ławka ryb było ogromne” (grupa ryb)
W Word2Vec słowo „bank” ma unikalny wektor, który jest średnią rozmytą wszystkich tych znaczeń. Model nie ma możliwości rozróżnienia kontekstu.
1.2 ELMo: pierwszy krok w kierunku kontekstu
W 2018 r. przed BERT ELMo (Osadzanie z modeli językowych) przez AllenAI próbował już rozwiązać problem kontekstów. ELMo korzystało z sieci biLSTM (dwukierunkowa pamięć długoterminowa) wstępnie przeszkolona do zadania modelowania języka w celu tworzenia osadzania kontekstowego.
Problem ELMo był dwojaki: po pierwsze, był dwukierunkowy powierzchowny, w tym sensie, że dwa LSTM (jeden do przodu, jeden do tyłu) zostały połączone, ale nie wchodziły w interakcję podczas przetwarzania. Po drugie, LSTM cierpią na: informacje wąskie gardło: długoterminowe zależności są stopniowo „zapominane” w miarę jak sekwencja staje się dłuższa.
1.3 Punkt zwrotny: głęboka dwukierunkowość
BERT rozwiązuje oba problemy dzięki mechanizmowi samouważność Transformatora. Każdy żeton w sekwencji może „obserwować” wszystkie pozostałe żetony jednocześnie zarówno tych po lewej, jak i tych po prawej stronie. Ta dwukierunkowość nie jest połączenie dwóch oddzielnych modeli (jak w ELMo), ale jednocześnie głęboka interakcja dzieje się w każdej warstwie architektury.
Porównanie: podejścia do dwukierunkowości
| Model | Typ | Kontekst | Ograniczenie |
|---|---|---|---|
| Word2Vec/GloVe | Statyczny | Brak kontekstu | Jeden wektor na słowo |
| GPT-1 | Jednokierunkowy (w lewo -> w prawo) | Tylko poprzedni kontekst | Nie widzi przyszłości |
| Kask | Powierzchowne dwukierunkowe | Powiązany kontekst | Brak interakcji pomiędzy kierunkami |
| BERT | Głęboki dwukierunkowy | Pełny kontekst na każdej warstwie | Tylko enkoder (bez generacji) |
Dzięki tej głębokiej dwukierunkowości BERT był w stanie założyć firmę nowe rekordy na 11 punktów odniesienia NLP w momencie jego publikacji, w tym GLUE, SQuAD 1.1, SQuAD 2.0 i MultiNLI.
2. Architektura BERT: Transformator enkodera
BERT jest modelem tylko koder, to znaczy wykorzystuje tylko część kodera oryginalnej architektury Transformer opisanej w artykule „Attention Is All You Need” (2017). Przyjrzyjmy się szczegółowo każdemu komponentowi.
2.1 Przegląd architektury
Architekturę BERT można sobie wyobrazić jako serię bloków transformatorowych ułożone pionowo. Każdy blok zawiera wielogłową warstwę samouważności po której następuje sieć ze sprzężeniem zwrotnym, z warstwą normalizacyjną i połączeniami resztkowymi.
Input: [CLS] Il gatto si siede sul tappeto [SEP]
| | | | | | |
+-----+-------+-----+----+-----+----+-------+-----+
| Token Embeddings |
| + Segment Embeddings |
| + Position Embeddings |
+-----+-------+-----+----+-----+----+-------+-----+
| | | | | | |
+---------------------------------------------------------+
| Transformer Encoder Block 1 |
| +---------------------------------------------------+ |
| | Multi-Head Self-Attention | |
| | Q = XWq K = XWk V = XWv | |
| | Attention(Q,K,V) = softmax(QK^T/sqrt(dk))V | |
| +---------------------------------------------------+ |
| | Add & Layer Norm | |
| +---------------------------------------------------+ |
| | Feed-Forward Network | |
| | FFN(x) = max(0, xW1 + b1)W2 + b2 | |
| +---------------------------------------------------+ |
| | Add & Layer Norm | |
+---------------------------------------------------------+
| | | | | | |
... ... ... ... ... ... ...
| | | | | | |
+---------------------------------------------------------+
| Transformer Encoder Block L (12 o 24) |
+---------------------------------------------------------+
| | | | | | |
[CLS]out T1 T2 T3 T4 T5 T6 [SEP]out
|
Pooling --> Classificazione / Output per task
2.2 Baza BERT kontra duży BERT
W artykule oryginalnym zaproponowano dwie konfiguracje:
Konfiguracje BERT
| Parametr | BERT-podstawowy | BERT-duży |
|---|---|---|
| Warstwy transformatora (L) | 12 | 24 |
| Ukryty rozmiar (H) | 768 | 1024 |
| Uwaga, głowy (A) | 12 | 16 |
| Całkowite parametry | 110M | 340M |
| Ciemny. dla Głowy | 768/12 = 64 | 1024/16 = 64 |
| Wym. sprzężenia do przodu | 3072 (4x768) | 4096 (4x1024) |
| Maksymalna sekwencja Długość | 512 | 512 |
| Rozmiar słownictwa | 30522 | 30522 |
2.3 Reprezentacja wejściowa: trzy osadzenia
Jedna z innowacji BERT jest Twoja reprezentacja wejścia, składa się z sumy trzech różnych osadów:
Input: [CLS] Il gatto dorme [SEP] Il cane corre [SEP]
| | | | | | | | |
Token Emb: E[CLS] E_il E_gatto E_dorme E[SEP] E_il E_cane E_corre E[SEP]
+ + + + + + + + +
Segment Emb: EA EA EA EA EA EB EB EB EB
+ + + + + + + + +
Position Emb: E0 E1 E2 E3 E4 E5 E6 E7 E8
= = = = = = = = =
Input finale: I0 I1 I2 I3 I4 I5 I6 I7 I8
Osadzanie tokenów: Każdy żeton w sekwencji jest odwzorowywany na gęsty wektor o rozmiarze H (768 dla bazy BERT) poprzez matrycę osadzającą poznaną podczas szkolenie. Słownictwo WordPiece zawiera 30 522 tokenów.
Osadzanie segmentów: BERT może otrzymać jako dane wejściowe jedno lub dwa osobne zdania token [SEP]. Osadzanie segmentów wskazuje, do którego zdania należy każdy token: wszystkie tokeny pierwszego zdania otrzymują osadzenie E_A, te drugie E_B. Ma to fundamentalne znaczenie w przypadku zadań takich jak wnioskowanie w języku naturalnym, w przypadku których BERT musi rozumować o związku między dwoma zdaniami.
Osadzenie pozycji: W przeciwieństwie do oryginalnego Transformera, który wykorzystuje funkcje sinusoidalny, BERT wykorzystuje osadzania pozycyjne Dowiedziałem się. Każda pozycja (0 do 511) ma wektor wyuczony podczas szkolenia, co oznacza, że BERT może sobie z nim poradzić sekwencje maksymalnie 512 żetonów.
from transformers import BertTokenizer, BertModel
import torch
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
model = BertModel.from_pretrained('bert-base-uncased')
# Tokenizzare un input con due frasi
text_a = "Il gatto dorme"
text_b = "Il cane corre"
encoded = tokenizer(text_a, text_b, return_tensors='pt')
print("Token IDs:", encoded['input_ids'])
print("Token Type IDs (Segments):", encoded['token_type_ids'])
print("Attention Mask:", encoded['attention_mask'])
# Decodifica per vedere i token
tokens = tokenizer.convert_ids_to_tokens(encoded['input_ids'][0])
print("Tokens:", tokens)
# Output: ['[CLS]', 'il', 'gatto', 'dor', '##me', '[SEP]', 'il', 'cane', 'cor', '##re', '[SEP]']
# Accesso agli embedding layers
token_embeddings = model.embeddings.word_embeddings
position_embeddings = model.embeddings.position_embeddings
segment_embeddings = model.embeddings.token_type_embeddings
print(f"Token embedding matrix: {token_embeddings.weight.shape}")
# Output: Token embedding matrix: torch.Size([30522, 768])
print(f"Position embedding matrix: {position_embeddings.weight.shape}")
# Output: Position embedding matrix: torch.Size([512, 768])
print(f"Segment embedding matrix: {segment_embeddings.weight.shape}")
# Output: Segment embedding matrix: torch.Size([2, 768])
2.4 Wielogłowa samouważność
Serce BERT (i każdego Transformatora) i mechanizm samouważność. Intuicyjnie samouważność pozwala każdemu tokenowi „obserwować” wszystkie inne tokeny w kolejności i zdecyduj, jak istotny jest każdy z nich dla Twojej reprezentacji.
Skalowana uwaga iloczynu punktowego
Dla każdego żetonu uwaga oblicza trzy wektory poprzez wyuczone projekcje liniowe:
- Zapytania (Q): „Czego szukam?”
- Klucz (K): „Co oferuję?”
- Wartość (V): „Jakie informacje przynoszę?”
Formuła uwagi to:
Uwaga (Q, K, V) = softmax\left(\frac{QK^T}{\sqrt{d_k}}\right)VGdzie d_k i wielkość klawiszy (64 dla podstawy BERT). Czynnik \frac{1}{\sqrt{d_k}} służy do stabilizacji gradienty: bez tego skalowania iloczyn skalarny daje bardzo duże wartości dla wysoka wymiarowość, a softmax staje się „nasycony”, tworząc dystrybucje prawie jednokrotne.
Uwaga wielogłowa
Zamiast obliczać pojedynczą funkcję uwagi, BERT używa wielogłowicowy uwaga: Obliczenia są powtarzane h razy (12 dla bazy BERT, 16 dla BERT-large), każdy z inną matrycą projekcyjną. Dzięki temu model może uchwycić jednocześnie różne typy relacji: głowa może się specjalizować w relacjach syntaktycznych, inny w koreferencjach, jeszcze inny w zależnościach semantycznych.
MultiHead(Q, K, V) = Concat(head_1, ..., head_h)W^O head_i = Uwaga(QW_i^Q, KW_i^K, VW_i^V)Gdzie W_i^Q \in \mathbb{R}^{d_{model} \times d_k}, W_i^K \in \mathbb{R}^{d_{model} \times d_k}, W_i^V \in \mathbb{R}^{d_{model} \times d_v} e W^O \in \mathbb{R}^{hd_v \times d_{model}}.
import torch
import torch.nn.functional as F
import math
def scaled_dot_product_attention(Q, K, V, mask=None):
"""Calcolo dell'attention scalata."""
d_k = Q.size(-1)
# Calcolo dei punteggi di attention
scores = torch.matmul(Q, K.transpose(-2, -1)) / math.sqrt(d_k)
# Applicazione della maschera (opzionale)
if mask is not None:
scores = scores.masked_fill(mask == 0, float('-inf'))
# Softmax per ottenere i pesi
attention_weights = F.softmax(scores, dim=-1)
# Output pesato
output = torch.matmul(attention_weights, V)
return output, attention_weights
class MultiHeadAttention(torch.nn.Module):
"""Multi-Head Attention come in BERT."""
def __init__(self, d_model=768, num_heads=12):
super().__init__()
self.d_model = d_model
self.num_heads = num_heads
self.d_k = d_model // num_heads # 64 per BERT-base
self.W_q = torch.nn.Linear(d_model, d_model)
self.W_k = torch.nn.Linear(d_model, d_model)
self.W_v = torch.nn.Linear(d_model, d_model)
self.W_o = torch.nn.Linear(d_model, d_model)
def forward(self, x, mask=None):
batch_size, seq_len, _ = x.size()
# Proiezioni lineari
Q = self.W_q(x) # (batch, seq_len, d_model)
K = self.W_k(x)
V = self.W_v(x)
# Reshape per multi-head: (batch, heads, seq_len, d_k)
Q = Q.view(batch_size, seq_len, self.num_heads, self.d_k).transpose(1, 2)
K = K.view(batch_size, seq_len, self.num_heads, self.d_k).transpose(1, 2)
V = V.view(batch_size, seq_len, self.num_heads, self.d_k).transpose(1, 2)
# Attention per ogni head
attn_output, attn_weights = scaled_dot_product_attention(Q, K, V, mask)
# Concatenazione delle head
attn_output = attn_output.transpose(1, 2).contiguous()
attn_output = attn_output.view(batch_size, seq_len, self.d_model)
# Proiezione finale
output = self.W_o(attn_output)
return output, attn_weights
# Test
mha = MultiHeadAttention(d_model=768, num_heads=12)
x = torch.randn(1, 10, 768) # batch=1, seq_len=10, dim=768
output, weights = mha(x)
print(f"Output shape: {output.shape}") # torch.Size([1, 10, 768])
print(f"Weights shape: {weights.shape}") # torch.Size([1, 12, 10, 10])
2.5 Sieć przekazująca
Po każdej warstwie uwagi BERT stosuje pozycyjną sieć wyprzedzającą, tj ta sama sieć jest stosowana niezależnie do każdej pozycji ciągu:
FFN(x) = \text{GELU}(xW_1 + b_1)W_2 + b_2Rozmiar pośredni jest zazwyczaj 4 razy ukryty wymiar (3072 dla podstawy BERT, 4096 dla dużego BERT). BERT korzysta z funkcji aktywacji ŻELU (jednostka liniowa błędu Gaussa) zamiast tradycyjnego ReLU, który zapewnia płynniejsze przejście i lepszą wydajność w praktyce.
2.6 Normalizacja warstw i połączenia resztkowe
Każda podwarstwa (uwaga i wyprzedzanie) w BERT jest owinięta a resztkowe połączenie następnie normalizacja warstw:
\text{wyjście} = \text{Norma warstwy}(x + \text{Podwarstwa}(x))Połączenia resztkowe umożliwiają przepływ gradientów bezpośrednio przez sieć podczas propagacji wstecznej, zapobiegając problemowi zanikającego gradientu w samych sieciach głęboko. Normalizacja warstw stabilizuje trening poprzez normalizację aktywacji wzdłuż wymiaru cechy.
import torch
import torch.nn as nn
class TransformerEncoderBlock(nn.Module):
"""Un singolo blocco encoder come in BERT."""
def __init__(self, d_model=768, num_heads=12, d_ff=3072, dropout=0.1):
super().__init__()
# Multi-Head Attention
self.attention = nn.MultiheadAttention(
embed_dim=d_model,
num_heads=num_heads,
dropout=dropout,
batch_first=True
)
# Feed-Forward Network
self.ffn = nn.Sequential(
nn.Linear(d_model, d_ff),
nn.GELU(),
nn.Dropout(dropout),
nn.Linear(d_ff, d_model),
nn.Dropout(dropout)
)
# Layer Normalization
self.norm1 = nn.LayerNorm(d_model)
self.norm2 = nn.LayerNorm(d_model)
self.dropout = nn.Dropout(dropout)
def forward(self, x, mask=None):
# Sub-layer 1: Multi-Head Attention + Residual + LayerNorm
attn_output, _ = self.attention(x, x, x, key_padding_mask=mask)
x = self.norm1(x + self.dropout(attn_output))
# Sub-layer 2: FFN + Residual + LayerNorm
ffn_output = self.ffn(x)
x = self.norm2(x + ffn_output)
return x
class BERTEncoder(nn.Module):
"""Stack di encoder blocks come in BERT-base."""
def __init__(self, num_layers=12, d_model=768, num_heads=12, d_ff=3072):
super().__init__()
self.layers = nn.ModuleList([
TransformerEncoderBlock(d_model, num_heads, d_ff)
for _ in range(num_layers)
])
def forward(self, x, mask=None):
for layer in self.layers:
x = layer(x, mask)
return x
# Test: simula BERT-base
encoder = BERTEncoder(num_layers=12, d_model=768, num_heads=12, d_ff=3072)
x = torch.randn(2, 128, 768) # batch=2, seq_len=128
output = encoder(x)
print(f"Output: {output.shape}") # torch.Size([2, 128, 768])
# Conta parametri
total_params = sum(p.numel() for p in encoder.parameters())
print(f"Parametri encoder: {total_params:,}")
# ~85M (solo encoder, senza embeddings)
3. Szkolenie wstępne: jak BERT uczy się języka
BERT jest wstępnie przeszkolony w zakresie używania ogromnej ilości nieoznaczonego tekstu dwa uzupełniające się cele szkoleniowe: Model języka zamaskowanego (MLM) e il Przewidywanie następnego zdania (NSP). Podstawową ideą jest model dzięki tym samonadzorowanym zadaniom uczysz się bogatych reprezentacji języka i tak dalej wiedzę tę można następnie przenieść do konkretnych zadań poprzez dostrojenie.
Dane przedtreningowe
- Korpus Książek: ~800 mln słów (11 000 niepublikowanych książek)
- Angielska Wikipedia: ~2500 mln słów (tylko tekst, bez tabel/list)
- Całkowity: ~ 3,3 miliarda słów
- Szkolenie: 4 kapsuły TPU (64 chipy TPU), 4 dni dla bazy BERT
3.1 Model języka maskowanego (MLM)
Model języka zamaskowanego jest główną innowacją BERT. Problem z językiem tradycyjne modelowanie (przewidywanie następnego słowa) i jest to samo w sobie jednokierunkowy: Model może patrzeć tylko w lewo. Zrobić w modelu dwukierunkowym BERT wprowadza elegancki trik: zamaskowanie porcji losowe żetony wejściowe i poproś model o ich przewidzenie.
Strategia 80/10/10
Dla każdej sekwencji wejściowej, 15% tokenów jest wybranych do przewidywania. Z tych wybranych tokenów:
- 80% zostaje zastąpiony specjalnym żetonem [MASKA]
- 10% zostaje zastąpiony losowym znacznikiem ze słownika
- 10% pozostaje bez zmian
Ta strategia rozwiązuje subtelny problem: podczas dostrajania token [MASK] zawodzi nigdy nie pojawia się na wejściu. Gdyby model widział [MASKĘ] tylko podczas treningu przedtreningowego, byłaby tam a rozbieżność między treningiem przedtreningowym a dostrajaniem. Zastąpienie 10% żetonami losowo i pozostawiając 10% bez zmian, model uczy się tworzyć dobre reprezentacje dla wszyscy żetony, nie tylko dla przebranych.
import random
import torch
from transformers import BertTokenizer
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
def apply_mlm_masking(tokens, tokenizer, mask_prob=0.15):
"""Applica la strategia di masking 80/10/10 di BERT."""
masked_tokens = list(tokens)
labels = [-100] * len(tokens) # -100 = ignora nella loss
for i in range(len(tokens)):
# Non mascherare token speciali
if tokens[i] in [tokenizer.cls_token_id, tokenizer.sep_token_id,
tokenizer.pad_token_id]:
continue
if random.random() < mask_prob:
labels[i] = tokens[i] # Salva il token originale come label
rand = random.random()
if rand < 0.8:
# 80%: sostituisci con [MASK]
masked_tokens[i] = tokenizer.mask_token_id
elif rand < 0.9:
# 10%: sostituisci con token casuale
masked_tokens[i] = random.randint(0, tokenizer.vocab_size - 1)
# else: 10%: lascia invariato
return masked_tokens, labels
# Esempio
text = "Il gatto si siede sul tappeto rosso"
encoded = tokenizer.encode(text)
print("Originale:", tokenizer.decode(encoded))
masked, labels = apply_mlm_masking(encoded, tokenizer)
print("Mascherato:", tokenizer.decode(masked))
print("Labels (posizioni da predire):",
[(i, tokenizer.decode([labels[i]])) for i in range(len(labels)) if labels[i] != -100])
3.2 Przewidywanie następnego zdania (NSP)
Drugim celem przedszkoleniowym jest Przewidywanie następnego zdania. Dla każdego pary zdań (A, B) na wejściu, model musi przewidzieć, czy B jest zdaniem następującym po nim właściwie A w tekście oryginalnym (Jest następny) lub jeśli jest to przypadkowa fraza (Nie następny). Zbiór danych jest skonstruowany w taki sposób, że 50% par jest dodatnich i 50% negatywnych.
Input = [CLS] Il gatto dorme [SEP] E' stanco dopo aver giocato [SEP]
Label = IsNext (frase B segue A nel testo originale)
Input = [CLS] Il gatto dorme [SEP] Roma e' la capitale d'Italia [SEP]
Label = NotNext (frase B e' casuale, non correlata ad A)
Cel NSP pomaga BERTowi uchwycić relacje między zdaniami, przydatne w zadaniach takich jak Odpowiadanie na pytania i wnioskowanie w języku naturalnym. Jednak późniejsze badania (w szczególności RoBERTa) wykazały, że NSP mogą nie być konieczne, a nawet mogą szkoda wydajność, jak zobaczymy w części dotyczącej wariantów.
3.3 Łączna strata
Całkowita utrata BERT podczas treningu przedtreningowego jest sumą dwóch strat:
\mathcal{L}_{total} = \mathcal{L}_{MLM} + \mathcal{L}_{NSP}Gdzie \mathcal{L}_{MLM} oraz strata entropii krzyżowej na tokenach zamaskowany i \mathcal{L}_{NSP} i strata entropii krzyżowej binarny w klasyfikacji IsNext/NotNext.
4. Tokenizacja WordPiece
BERT wykorzystuje tokenizację Kawałek słowa, algorytm tokenizacji podsłowo, które równoważy efektywność słownictwa i zasięg językowy. WordPiece i stan pierwotnie opracowany dla systemu tłumaczenia maszynowego Google.
4.1 Jak działa WordPiece
Idea stojąca za WordPiece jest prosta, ale potężna: zaczynając od słownictwa poszczególnych osób znaków i iteracyjnie łącz pary tokenów, które maksymalizują prawdziwość korpusu szkoleniowego. Proces trwa do momentu opanowania słownictwa wielkość docelową (30 522 dla BERT).
Rezultatem jest słownictwo zawierające:
- Całe popularne słowa (np. „the”, „of”, „i”)
- Typowe przedrostki i rdzenie (np. „un”, „re”, „pre”)
- Przyrostki i końcówki oznaczone symbolem
##(np. „##ing”, „##tion”, „##ed”) - Pojedyncze znaki do obsługi dowolnego nieznanego słowa
4.2 Żetony specjalne
Oprócz tokenów słownictwa WordPiece BERT używa kilku specjalnych tokenów:
Specjalne żetony BERT
| Żetony | ID | Zakres |
|---|---|---|
| [PODKŁADKA] | 0 | Dopełnienie w celu ujednolicenia długości sekwencji w partii |
| [UNK] | 100 | Nieznany token (nie ma go w słowniku) |
| [CLS] | 101 | Początek sekwencji, jej ostateczna reprezentacja służy do klasyfikacji |
| [wrzesień] | 102 | Separator pomiędzy dwoma zdaniami wejściowymi |
| [MASKA] | 103 | Maska dla modelu zamaskowanego języka podczas treningu wstępnego |
from transformers import BertTokenizer
# Carica il tokenizer
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
# Tokenizzazione di parole comuni e rare
examples = [
"The cat sat on the mat",
"Electroencephalography is fascinating",
"L'intelligenza artificiale rivoluzionera il mondo",
"Tokenizzazione subword con WordPiece"
]
for text in examples:
tokens = tokenizer.tokenize(text)
ids = tokenizer.encode(text)
print(f"Testo: {text}")
print(f" Tokens: {tokens}")
print(f" IDs: {ids}")
print(f" Num tokens: {len(tokens)}")
print()
# Output per "Electroencephalography is fascinating":
# Tokens: ['electro', '##ence', '##pha', '##log', '##raphy', 'is', 'fascinating']
# La parola lunga viene spezzata in subword, ma "is" e "fascinating" restano intere
# Decodifica
encoded = tokenizer("Hello world!", return_tensors="pt")
decoded = tokenizer.decode(encoded['input_ids'][0])
print(f"Encoded -> Decoded: {decoded}")
# Output: [CLS] hello world ! [SEP]
# Vocabolario
print(f"Dimensione vocabolario: {tokenizer.vocab_size}")
# Output: 30522
5. Dostosowanie BERT do zadań niższego szczebla
Paradygmat wprowadzony przez BERT brzmi: „wstępnie szkolić, a następnie dostrajać”. Faza przedszkoleniowa tworzy model z głębokim zrozumieniem języka. Faza dostrajania dostosować ten model do konkretnego zadania, dodając warstwę wyjściową i szkolenie cały model (lub jego część) na oznaczonych danych zadania.
Piękno dostrajania polega na tym, że wymaga kilka oznaczonych danych e mało czasu na szkolenie w porównaniu do trenowania modelu od zera. Zazwyczaj wystarczą 2-4 epoki o niskim współczynniku uczenia się (2e-5 do 5e-5).
5.1 Klasyfikacja tekstu
Do klasyfikacji tekstów (analiza nastrojów, klasyfikacja tematów, wykrywanie spamu), używana jest reprezentacja tokenowa [CLS] jako dane wejściowe do klasyfikatora liniowy:
Input: [CLS] Questo film e' fantastico [SEP]
|
BERT: 12 layers di Transformer Encoder
|
[CLS] output (768-dim) --> Linear(768, num_classes) --> Softmax --> Predizione
|
"Positivo" (p=0.95)
from transformers import BertForSequenceClassification, BertTokenizer
from transformers import Trainer, TrainingArguments
from datasets import load_dataset
import torch
# 1. Carica modello pre-addestrato con classification head
model = BertForSequenceClassification.from_pretrained(
'bert-base-uncased',
num_labels=2 # positivo/negativo
)
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
# 2. Prepara il dataset (esempio: IMDB reviews)
dataset = load_dataset('imdb')
def tokenize_function(examples):
return tokenizer(
examples['text'],
padding='max_length',
truncation=True,
max_length=256
)
tokenized_datasets = dataset.map(tokenize_function, batched=True)
# 3. Configura il training
training_args = TrainingArguments(
output_dir='./results',
num_train_epochs=3,
per_device_train_batch_size=16,
per_device_eval_batch_size=64,
warmup_steps=500,
weight_decay=0.01,
learning_rate=2e-5,
logging_dir='./logs',
evaluation_strategy='epoch',
save_strategy='epoch',
load_best_model_at_end=True,
)
# 4. Crea il Trainer e avvia il fine-tuning
trainer = Trainer(
model=model,
args=training_args,
train_dataset=tokenized_datasets['train'],
eval_dataset=tokenized_datasets['test'],
)
trainer.train()
# 5. Valutazione
results = trainer.evaluate()
print(f"Accuracy: {results['eval_loss']:.4f}")
5.2 Rozpoznawanie podmiotów nazwanych (NER)
W przypadku NER zamiast po prostu używać tokena [CLS], używane jest wyjście każdy żeton aby zaklasyfikować każdego do kategorii podmiotu (osoba, miejsce, organizacja itp.):
Input: [CLS] Mario Rossi vive a Roma [SEP]
| | | | | | |
BERT: 12 layers di Transformer Encoder
| | | | | | |
Output: O B-PER I-PER O O B-LOC O
Ogni token --> Linear(768, num_entity_types) --> Softmax --> Tipo entità
from transformers import BertForTokenClassification, BertTokenizer
from transformers import pipeline
# Usa un modello già fine-tuned per NER
ner_pipeline = pipeline(
"ner",
model="dbmdz/bert-large-cased-finetuned-conll03-english",
aggregation_strategy="simple"
)
text = "Mario Rossi works at Google in Mountain View, California"
entities = ner_pipeline(text)
for entity in entities:
print(f" {entity['word']}: {entity['entity_group']} "
f"(score: {entity['score']:.3f})")
# Output:
# Mario Rossi: PER (score: 0.998)
# Google: ORG (score: 0.997)
# Mountain View: LOC (score: 0.995)
# California: LOC (score: 0.999)
5.3 Odpowiadanie na pytania
Aby uzyskać wyodrębnioną odpowiedź na pytanie, BERT otrzymuje jako dane wejściowe pytanie i kontekst oddzielone [SEP]. Model musi przewidywać położenie start e koniec odpowiedzi w kontekście:
Input: [CLS] Quando e' nato Einstein? [SEP] Albert Einstein e' nato il 14 marzo 1879 [SEP]
| | | | | | | | | | | | | |
BERT: 12 layers di Transformer Encoder
| | | | | | | | | | | | | |
Start: 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.02 0.8 0.02 0.01 0.01 0.01
End: 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.85 0.01
Risposta estratta: "14 marzo 1879"
from transformers import pipeline
# Pipeline di Question Answering
qa_pipeline = pipeline(
"question-answering",
model="deepset/bert-base-cased-squad2"
)
context = """
BERT (Bidirectional Encoder Representations from Transformers)
e' un modello di linguaggio sviluppato da Google AI nel 2018.
E' stato addestrato su Wikipedia e BookCorpus, per un totale
di circa 3.3 miliardi di parole. BERT-base ha 110 milioni di
parametri e 12 layer di Transformer encoder.
"""
questions = [
"Chi ha sviluppato BERT?",
"Quanti parametri ha BERT-base?",
"Su quali dati e' stato addestrato BERT?",
"In che anno e' stato pubblicato BERT?"
]
for question in questions:
result = qa_pipeline(question=question, context=context)
print(f"D: {question}")
print(f"R: {result['answer']} (score: {result['score']:.3f})")
print()
5.4 Klasyfikacja par zdań
W przypadku zadań takich jak wnioskowanie w języku naturalnym (NLI) lub wykrywanie parafraz BERT otrzymuje dwa zdania i muszą sklasyfikować ich związek (wymóg, sprzeczność, neutralność):
from transformers import pipeline
# Natural Language Inference
nli_pipeline = pipeline(
"text-classification",
model="cross-encoder/nli-deberta-v3-small"
)
pairs = [
("Il gatto dorme sul divano", "Un animale sta riposando"),
("Il gatto dorme sul divano", "Il cane corre nel parco"),
("Tutti gli studenti hanno superato l'esame", "Nessuno studente ha fallito"),
]
for premise, hypothesis in pairs:
result = nli_pipeline(f"{premise} [SEP] {hypothesis}")
print(f"Premessa: {premise}")
print(f"Ipotesi: {hypothesis}")
print(f"Risultato: {result[0]['label']} ({result[0]['score']:.3f})")
print()
6. Wyodrębnij osady z BERT
Oprócz dostrajania do konkretnych zadań, BERT jest niezwykle przydatny jako ekstraktor funkcji. Reprezentacje utworzone przez warstwy wewnętrzne wychwytują informacje językowe na różnych poziomach abstrakcji.
from transformers import BertTokenizer, BertModel
import torch
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
model = BertModel.from_pretrained('bert-base-uncased', output_hidden_states=True)
model.eval()
text = "Il Natural Language Processing e' affascinante"
inputs = tokenizer(text, return_tensors='pt')
with torch.no_grad():
outputs = model(**inputs)
# outputs contiene:
# - last_hidden_state: output dell'ultimo layer (batch, seq_len, 768)
# - pooler_output: [CLS] passato attraverso un linear + tanh (batch, 768)
# - hidden_states: tuple di 13 tensori (embedding + 12 layers)
last_hidden = outputs.last_hidden_state
pooler = outputs.pooler_output
all_layers = outputs.hidden_states
print(f"Last hidden state: {last_hidden.shape}")
# torch.Size([1, N, 768])
print(f"Pooler output: {pooler.shape}")
# torch.Size([1, 768])
print(f"Numero di layer: {len(all_layers)}")
# 13 (embedding layer + 12 transformer layers)
# Strategie per ottenere sentence embeddings:
# 1. Usa il [CLS] token dell'ultimo layer
cls_embedding = last_hidden[:, 0, :]
print(f"[CLS] embedding: {cls_embedding.shape}")
# 2. Mean pooling sull'ultimo layer (spesso migliore)
attention_mask = inputs['attention_mask'].unsqueeze(-1)
mean_embedding = (last_hidden * attention_mask).sum(1) / attention_mask.sum(1)
print(f"Mean pooling: {mean_embedding.shape}")
# 3. Concatena gli ultimi 4 layer (cattura più informazione)
last_4_layers = torch.cat(
[all_layers[i] for i in [-1, -2, -3, -4]],
dim=-1
)
print(f"Last 4 layers concatenated: {last_4_layers.shape}")
# torch.Size([1, N, 3072])
Której warstwy użyć?
Badania wykazały, że różne warstwy przechwytują różne typy informacji:
- Warstwy 1-4 (bas): Podstawowe informacje morfologiczne i składniowe
- Warstwy 5-8 (średnie): Złożone informacje składniowe, zależności
- Warstwy 9-12 (wysokie): Informacje semantyczne wysokiego poziomu
- Ostatnia warstwa: Najlepszy do zadań semantycznych (NLI, podobieństwo)
- Warstwy średnie: Najlepszy do zadań składniowych (tagowanie POS, analizowanie)
7. Warianty BERT: Ewolucja rodziny
Od czasu publikacji BERT liczne grupy badawcze zaproponowały jego odmiany poprawić kilka aspektów. Oto przegląd najważniejszych z nich.
Tabela porównawcza wariantów BERT
| Model | Rok | Wiodąca innowacja | Parametry |
|---|---|---|---|
| BERT-podstawowy | 2018 | MLM + NSP, głęboka dwukierunkowość | 110M |
| Roberta | 2019 | Brak NSP, maskowanie dynamiczne, więcej danych, dłuższe szkolenie | 125M |
| ALBERTA | 2019 | Udostępnianie parametrów, osadzanie na czynniki | 12M-235M |
| DestylBERT | 2019 | Destylacja wiedzy, 60% szybciej | 66M |
| ELEKTRA | 2020 | Zastąpione wykrywanie tokenów (bardziej wydajne niż MLM) | 110M |
| DEBERTA | 2020 | Rozplątana uwaga (osobna treść + pozycja) | 134M-390M |
| XLNet | 2019 | Modelowanie języka permutacyjnego | 340M |
| SpanBERT | 2019 | Maskowanie sąsiadujących przęseł + SBO | 110M |
| ERNIE | 2019 | Wzmocnione wiedzą, maskowanie jednostek | 110M |
7.1 RoBERTa: Optymalizacja szkolenia BERT
RoBERTa (solidnie zoptymalizowane podejście BERT), dostarczone przez Facebook AI (obecnie Meta) udowodnił, że BERT był niedostatecznie przeszkolony. Zmiany główne z nich to:
- Usunięcie NSP: Cel NSP nie pomaga, a nawet może obniżyć wydajność
- Maskowanie dynamiczne: Zamiast maskować tylko raz podczas przetwarzania wstępnego, wzory maskujące są generowane dynamicznie w każdej epoce
- Więcej danych: 160 GB tekstu (w porównaniu do 16 GB BERT), w tym CC-News, OpenWebText, Stories
- Dłuższy trening: krok 500 tys. (w porównaniu do 100 tys. BERT), większy rozmiar partii
- Dłuższe sekwencje: Nadal 512 tokenów (BERT zaczął od 128)
7.2 ALBERT: Inteligentna kompresja
ALBERT (Lekki BERT) Google rozwiązuje problem wzrostu parametrów za pomocą dwóch eleganckich technik:
- Faktoryzowana parametryzacja osadzania: Oddzielny rozmiar słownictwa z ukrytego wymiaru. Zamiast macierzy V x H użyj V x E i E x H (przy czym E jest znacznie mniejsze niż H)
- Międzywarstwowe udostępnianie parametrów: Wszystkie warstwy Transformera są współdzielone te same parametry. To drastycznie zmniejsza liczbę parametrów bez utraty dużo jakości
ALBERT-xxlarge osiąga wyższą wydajność niż BERT-large przy parametrach zaledwie 235M (w porównaniu z 340M), chociaż czas wnioskowania nie zmniejsza się wraz ze wzrostem liczby warstw niezmienione.
7.3 DistilBERT: Destylacja wiedzy
DestylBERT autorstwa Hugging Face używa destylacja wiedzy aby stworzyć mniejszy, szybszy model. Trenowany jest model „uczniowski” (6 warstw). naśladować wyniki modelu „nauczyciela” (baza BERT, 12 warstw).
- 40% mniejszy: Parametry 66M vs 110M
- 60% szybciej: 6 warstw vs 12
- 97% wydajności: Utrzymuje prawie całą jakość bazy BERT
7.4 ELECTRA: Zupełnie inne podejście
ELEKTRA zastępuje model języka maskowanego podejściem inspirującym do sieci GAN (generatywne sieci przeciwstawne). Zamiast maskować tokeny i je przewidywać, ELECTRA:
- Mały generator (mały BERT) produkuje wiarygodne żetony zastępcze
- Dyskryminator (model główny) musi się identyfikować Który żeton zostały wymienione (wymieniono wykrywanie tokena)
Kluczowa korzyść: dyskryminator uczy się wszyscy oznaki sekwencji, a nie tylko zamaskowanych 15% jak w BERT. To sprawia, że ELECTRA jest o wiele więcej wydajne pod względem danych i obliczeń.
7.5 DeBERTa: Uwaga oddzielona
DeBERTa (BERT ze wzmocnionym dekodowaniem i rozplątaną uwagą) przez Microsoft wprowadza dwie innowacje:
- Rozkojarzona uwaga: Oddziela informacje o zawartości i lokalizacji na dwa różne wektory, co pozwala modelowi wnioskować o „co” i „gdzie” niezależnie od tego
- Ulepszony dekoder maski: Dodaje informacje o pozycji bezwzględnej w dekoderze, aby poprawić przewidywania MLM
DeBERTa v3 jest obecnie jednym z najlepiej działających modeli koderów w wielu benchmarkach, często przewyższając znacznie większe modele.
8. BERT dla języka włoskiego
Oryginalny BERT był szkolony na tekście w języku angielskim. W przypadku języka włoskiego mamy kilka opcji, każdy z zaletami i wadami.
Modele BERT dla Włochów
| Model | Podstawowy | Dane szkoleniowe | Słownictwo |
|---|---|---|---|
| MBERTA | BERT-podstawowy | Wikipedia w 104 językach | 110 tys. wielojęzycznych tokenów |
| dbmdz/bert-base-italian-xxl-cased | BERT-podstawowy | OPUS, Wikipedia IT (~13 GB) | 30 tys. tokenów włoskich |
| Alberto | BERT-podstawowy | Tweetnij po włosku | 30 tys. tokenów włoskich |
| UmBERTo | Roberta | Korpus włoski OSCAR | Tokeny 32 tys. fragmentów zdań |
| XLM-RoBERTa | Roberta | CC-100 w 100 językach | 250 tys. wielojęzycznych tokenów |
from transformers import pipeline, AutoTokenizer, AutoModelForMaskedLM
# 1. BERT Italiano (dbmdz)
fill_mask_it = pipeline(
"fill-mask",
model="dbmdz/bert-base-italian-xxl-cased"
)
results = fill_mask_it("Roma e' la [MASK] d'Italia.")
for r in results[:3]:
print(f" {r['token_str']}: {r['score']:.4f}")
# Output: capitale: 0.8234, citta: 0.0521, ...
# 2. UmBERTo (basato su RoBERTa)
fill_mask_umberto = pipeline(
"fill-mask",
model="Musixmatch/umberto-commoncrawl-cased-v1"
)
results = fill_mask_umberto("L'intelligenza artificiale <mask> il futuro.")
for r in results[:3]:
print(f" {r['token_str']}: {r['score']:.4f}")
# 3. Multilingual BERT
fill_mask_mbert = pipeline(
"fill-mask",
model="bert-base-multilingual-cased"
)
results = fill_mask_mbert("Roma e' la [MASK] d'Italia.")
for r in results[:3]:
print(f" {r['token_str']}: {r['score']:.4f}")
# mBERT funziona, ma il modello italiano dedicato e' molto più' preciso
Jaki model wybrać do języka włoskiego?
- Zadania ogólne (NER, klasyfikacja, QA):
dbmdz/bert-base-italian-xxl-casedlub UmBERTo - Analiza mediów społecznościowych: AlBERTo (szkolony na Twitterze)
- Zadania wielojęzyczne: XLM-RoBERTa (idealny do międzyjęzykowego zerowego strzału)
- Maksymalna jakość: Dostrojenie XLM-RoBERTa-large na włoskich danych
9. Granice BERT
Pomimo swojego rewolucyjnego wpływu BERT ma kilka ograniczeń strukturalnych wpływają na jego zastosowanie:
9.1 Limit tokenów 512
BERT może przetwarzać maksymalne sekwencje 512 tokenów. Do długich dokumentów (artykuły, umowy prawne, prace naukowe), jest to surowe ograniczenie. Strategie łagodzenia obejmują obcięcie, To przesuwane okno e la łączenie hierarchiczne, ale żaden nie jest optymalny.
9.2 Kwadratowa złożoność uwagi
Samouważność ma złożoność obliczeniową O(n^2) szacunek do długości sekwencji n. Oznacza to podwójną długość danych wejściowych czterokrotnie zwiększa koszt obliczeń i zużycie pamięci. Modele lubią Długotrwały, Wielki Ptak e Liinformator proponują rzadkie mechanizmy uwagi pozwalające obejść ten problem.
9.3 Tylko koder: brak możliwości generowania
BERT jest modelem tylko koder. Może tworzyć bogate reprezentacje tekstu, ale nie może spowodować nowy tekst. Do generacji potrzebny jest dekoder (jak w GPT) lub architektura koder-dekoder (jak w T5 lub BART).
9.4 Niedopasowanie przedtreningowe/dostrajające
Znacznik [MASKA] pojawia się podczas wstępnego treningu, ale nigdy podczas dostrajania lub wnioskowania. Chociaż strategia 80/10/10 częściowo łagodzi problem, to niedopasowanie pozostaje teoretyczna słabość. ELECTRA całkowicie rozwiązuje problem, nie używając [MASK].
9.5 Niezależność żetonów maskowanych
Kiedy BERT maskuje wiele tokenów, odpowiednio je przewiduje niezależny. Nie modeluje zależności pomiędzy zamaskowanymi tokenami. Na przykład, jeśli frazą jest „Nowa [MASKA] [MASKA]” a odpowiedź brzmi „Nowy Jork”, BERT przewiduje „Jork” i „Miasto” niezależnie, bez wpływać na przewidywanie jednego na drugim. XLNet rozwiązuje ten problem za pomocą modelowanie języka permutacyjnego.
Podsumowanie ograniczeń i rozwiązań
| Limit | Uderzenie | Rozwiązanie |
|---|---|---|
| Maksymalnie 512 tokenów | Żadnych długich dokumentów | Longformer, BigBird, okno przesuwne |
| Uwaga O(n^2) | Wysokie koszty obliczeniowe | Lininformer, wykonawca, uwaga Flash |
| Tylko enkodery | Brak generowania tekstu | T5, BART, GPT |
| [MASKA] niedopasowanie | Rozbieżność pociągu/wnioskowania | ELEKTRA, XLNet |
| Niezależne prognozy | Brak zależności pomiędzy tokenami maskowanymi | XLNet, modele autoregresyjne |
10. Od BERT do nowoczesnych modeli
BERT zapoczątkował erę „wstępnego szkolenia, a następnie dostrajania” w NLP, wywierając wpływ głęboko całą późniejszą architekturę. Zobaczmy, jak ewoluował krajobraz.
10.1 Modelowe drzewo genealogiczne
Transformer (2017)
|
+------ Encoder-Only ------+------ Decoder-Only ------+--- Encoder-Decoder ---+
| | | |
BERT (2018) GPT-1 (2018) T5 (2019) BART (2019)
| | |
+-- RoBERTa (2019) GPT-2 (2019) mT5 (2020)
+-- ALBERT (2019) |
+-- DistilBERT (2019) GPT-3 (2020)
+-- XLNet (2019) |
+-- ELECTRA (2020) GPT-4 (2023)
+-- DeBERTa (2020) |
+-- DeBERTa v3 (2021) LLaMA (2023)
|
LLaMA 2 (2023)
|
Mistral (2023)
|
LLaMA 3 (2024)
10.2 Kluczowa lekcja BERT
Najważniejszym dziedzictwem BERT nie jest konkretna architektura, ale: paradygmat: Trenuj model na ogromnych ilościach tekstu bez etykiety wykorzystując samodzielnie nadzorowane cele, a następnie dostosowując je do konkretnych zadań przy niewielkiej ilości danych oznakowane. Ten paradygmat jest podstawą wszystkich nowoczesnych modeli, od GPT po LLaMA.
10.3 Gdzie BERT jest nadal istotny
Pomimo pojawienia się znacznie większych modeli generatywnych, BERT i jego potomkowie Tylko koder pozostaje najlepszym wyborem w wielu scenariuszach:
- Klasyfikacja tekstu: Sentyment, temat, wykrywanie spamu
- Rozpoznawanie nazwanych podmiotów: Ekstrakcja jednostek strukturalnych
- Wyszukiwanie semantyczne: Wyszukiwanie oparte na znaczeniu (z transformatorami zdań)
- Wyszukiwanie informacji: Ranking odpowiednich dokumentów
- Generacja osadzania: Gęste reprezentacje tekstu
Modeli enkoderów takich jak BERT jest więcej wydajny, więcej szybko e tańsze w porównaniu do dużych modeli generatywnych. Do wielu zadań rozumienia języka, dostrojona DeBERTa-v3 przewyższa modele 100 razy większą parametry.
11. Wnioski i kiedy stosować BERT
W tym artykule szczegółowo przeanalizowaliśmy BERT: od architektury składającej się wyłącznie z enkodera Transformatora, po wielogłowy mechanizm samouwagi, po strategie przedtreningowe (MLM i NSP), aż po praktyczne wdrożenia z HuggingFace i jego wariantami są pochodne.
Ramy decyzyjne: kiedy stosować BERT
| Scenariusz | Polecany model | Motywacja |
|---|---|---|
| Klasyfikacja tekstu (produkcja) | DeBERTa-v3 lub RoBERTa | Maksymalna dokładność, rozsądny koszt |
| NER (włoski) | dbmdz BERT IT lub UmBERTo | Rodzime słownictwo włoskie |
| Ograniczone zasoby/przewaga | DistilBERT lub TinyBERT | Szybki, kompaktowy, jakość 97%. |
| Efektywność treningu | ELEKTRA | Ucz się na wszystkich tokenach, a nie tylko na 15% |
| Generacja tekstu | GPT/T5/LLaMA | BERT nie może generować |
| Długie dokumenty | Longformer / BigBird | BERT limitowany do 512 tokenów |
| Wielojęzyczny / zero-shot | XLM-RoBERTa | Doskonały transfer międzyjęzykowy |
BERT pozostaje ostoją współczesnego NLP. Chociaż modele wielkojęzykowe Na pierwszych stronach gazet dominują modele generatywne, a modele koderów, takie jak BERT, stanowią podstawę niezliczonych zastosowań w produkcji: wyszukiwarki, systemy rekomendacyjne, filtry spamu, asystenci prawni, analiza nastrojów i wiele więcej.
W następnym artykule z tej serii wykorzystamy tę wiedzę w praktyce, budując a system Analiza sentymentów kompletny dla tekstu włoskiego, z przygotowanie zbioru danych do wdrożenia modelu.
Zasoby, aby dowiedzieć się więcej
- Artykuł oryginalny: „BERT: Pre-training of Deep Bilateral Transformers for Language Understanding” (Devlin et al., 2018)
- Artykuł RoBERTa: „Solidnie zoptymalizowane podejście do szkolenia wstępnego BERT” (Liu i in., 2019)
- Artykuł ELECTRA: „ELECTRA: wstępne szkolenie koderów tekstu jako dyskryminatorów zamiast generatorów” (Clark i in., 2020)
- Artykuł DeBERTa: „DeBERTa: BERT ze wzmocnionym dekodowaniem i rozplątaną uwagą” (He i in., 2020)
- Dokumentacja HuggingFace BERT: huggingface.co/docs/transformers/model_doc/bert
- Ilustrowany BERT: jalammar.github.io/ilustrated-bert/







