.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
#@save
def _pad_bert_inputs(examples, max_len, vocab):
max_num_mlm_preds = round(max_len * 0.15)
all_token_ids, all_segments, valid_lens, = [], [], []
all_pred_positions, all_mlm_weights, all_mlm_labels = [], [], []
nsp_labels = []
for (token_ids, pred_positions, mlm_pred_label_ids, segments,
is_next) in examples:
all_token_ids.append(np.array(token_ids + [vocab['
']] * (
max_len - len(token_ids)), dtype='int32'))
all_segments.append(np.array(segments + [0] * (
max_len - len(segments)), dtype='int32'))
# `valid_lens`, '' belirteçlerinin sayısını hariç tutar
valid_lens.append(np.array(len(token_ids), dtype='float32'))
all_pred_positions.append(np.array(pred_positions + [0] * (
max_num_mlm_preds - len(pred_positions)), dtype='int32'))
# Dolgulu belirteçlerin tahminleri, 0 ağırlıklar çarpımı
# yoluyla kayıpta filtrelenecektir.
all_mlm_weights.append(
np.array([1.0] * len(mlm_pred_label_ids) + [0.0] * (
max_num_mlm_preds - len(pred_positions)), dtype='float32'))
all_mlm_labels.append(np.array(mlm_pred_label_ids + [0] * (
max_num_mlm_preds - len(mlm_pred_label_ids)), dtype='int32'))
nsp_labels.append(np.array(is_next))
return (all_token_ids, all_segments, valid_lens, all_pred_positions,
all_mlm_weights, all_mlm_labels, nsp_labels)
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
#@save
def _pad_bert_inputs(examples, max_len, vocab):
max_num_mlm_preds = round(max_len * 0.15)
all_token_ids, all_segments, valid_lens, = [], [], []
all_pred_positions, all_mlm_weights, all_mlm_labels = [], [], []
nsp_labels = []
for (token_ids, pred_positions, mlm_pred_label_ids, segments,
is_next) in examples:
all_token_ids.append(torch.tensor(token_ids + [vocab['
']] * (
max_len - len(token_ids)), dtype=torch.long))
all_segments.append(torch.tensor(segments + [0] * (
max_len - len(segments)), dtype=torch.long))
# `valid_lens`, '' belirteçlerinin sayısını hariç tutar
valid_lens.append(torch.tensor(len(token_ids), dtype=torch.float32))
all_pred_positions.append(torch.tensor(pred_positions + [0] * (
max_num_mlm_preds - len(pred_positions)), dtype=torch.long))
# Dolgulu belirteçlerin tahminleri, 0 ağırlıklar çarpımı
# yoluyla kayıpta filtrelenecektir.
all_mlm_weights.append(
torch.tensor([1.0] * len(mlm_pred_label_ids) + [0.0] * (
max_num_mlm_preds - len(pred_positions)),
dtype=torch.float32))
all_mlm_labels.append(torch.tensor(mlm_pred_label_ids + [0] * (
max_num_mlm_preds - len(mlm_pred_label_ids)), dtype=torch.long))
nsp_labels.append(torch.tensor(is_next, dtype=torch.long))
return (all_token_ids, all_segments, valid_lens, all_pred_positions,
all_mlm_weights, all_mlm_labels, nsp_labels)
.. raw:: html
.. raw:: html
İki ön eğitim görevinin eğitim örneklerini üretmek için yardımcı
fonksiyonları ve girdi dolgulama için yardımcı işlevini bir araya
getirerek, BERT ön eğitimi için WikiText-2 veri kümesi olarak aşağıdaki
``_WikiTextDataset`` sınıfını özelleştiriyoruz. ``__getitem__`` işlevini
uygulayarak, WikiText-2 külliyatından bir çift cümleden oluşturulan ön
eğitim (maskeli dil modelleme ve sonraki cümle tahmini) örneklerine
keyfi olarak erişebiliriz.
Orijinal BERT modeli kelime boyutu 30000
:cite:`Wu.Schuster.Chen.ea.2016` olan WordPiece gömmeleri kullanır.
WordPiece'nin belirteçlere ayırma yöntemi,
:numref:`subsec_Byte_Pair_Encoding` içinde orijinal sekizli çifti
kodlama algoritmasının hafif bir değişiğidir. Basitlik için,
belirteçlere ayırmak için ``d2l.tokenize`` işlevini kullanıyoruz. Beş
kereden az görünen seyrek belirteçler filtrelenir.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
#@save
class _WikiTextDataset(gluon.data.Dataset):
def __init__(self, paragraphs, max_len):
# Girdi `paragraphs[i]`, bir paragrafı temsil eden cümle dizilerinin
# bir listesidir; çıktı `paragraphs[i]` bir paragrafı temsil eden
# cümlelerin bir listesidir, burada her cümle bir belirteç listesidir
paragraphs = [d2l.tokenize(
paragraph, token='word') for paragraph in paragraphs]
sentences = [sentence for paragraph in paragraphs
for sentence in paragraph]
self.vocab = d2l.Vocab(sentences, min_freq=5, reserved_tokens=[
'
', '', '', ''])
# Bir sonraki cümle tahmini görevi için veri alın
examples = []
for paragraph in paragraphs:
examples.extend(_get_nsp_data_from_paragraph(
paragraph, paragraphs, self.vocab, max_len))
# Maskeli dil modeli görevi için veri alın
examples = [(_get_mlm_data_from_tokens(tokens, self.vocab)
+ (segments, is_next))
for tokens, segments, is_next in examples]
# Girdiyi dolgula
(self.all_token_ids, self.all_segments, self.valid_lens,
self.all_pred_positions, self.all_mlm_weights,
self.all_mlm_labels, self.nsp_labels) = _pad_bert_inputs(
examples, max_len, self.vocab)
def __getitem__(self, idx):
return (self.all_token_ids[idx], self.all_segments[idx],
self.valid_lens[idx], self.all_pred_positions[idx],
self.all_mlm_weights[idx], self.all_mlm_labels[idx],
self.nsp_labels[idx])
def __len__(self):
return len(self.all_token_ids)
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
#@save
class _WikiTextDataset(torch.utils.data.Dataset):
def __init__(self, paragraphs, max_len):
# Girdi `paragraphs[i]`, bir paragrafı temsil eden cümle dizilerinin
# bir listesidir; çıktı `paragraphs[i]` bir paragrafı temsil eden
# cümlelerin bir listesidir, burada her cümle bir belirteç listesidir
paragraphs = [d2l.tokenize(
paragraph, token='word') for paragraph in paragraphs]
sentences = [sentence for paragraph in paragraphs
for sentence in paragraph]
self.vocab = d2l.Vocab(sentences, min_freq=5, reserved_tokens=[
'
', '', '', ''])
# Bir sonraki cümle tahmini görevi için veri alın
examples = []
for paragraph in paragraphs:
examples.extend(_get_nsp_data_from_paragraph(
paragraph, paragraphs, self.vocab, max_len))
# Maskeli dil modeli görevi için veri alın
examples = [(_get_mlm_data_from_tokens(tokens, self.vocab)
+ (segments, is_next))
for tokens, segments, is_next in examples]
# Girdiyi dolgula
(self.all_token_ids, self.all_segments, self.valid_lens,
self.all_pred_positions, self.all_mlm_weights,
self.all_mlm_labels, self.nsp_labels) = _pad_bert_inputs(
examples, max_len, self.vocab)
def __getitem__(self, idx):
return (self.all_token_ids[idx], self.all_segments[idx],
self.valid_lens[idx], self.all_pred_positions[idx],
self.all_mlm_weights[idx], self.all_mlm_labels[idx],
self.nsp_labels[idx])
def __len__(self):
return len(self.all_token_ids)
.. raw:: html
.. raw:: html
``_read_wiki`` işlevini ve ``_WikiTextDataset`` sınıfını kullanarak,
WikiText-2 veri kümesini indirmek ve ondan ön eğitim örnekleri
oluşturmak için aşağıdaki ``load_data_wiki``'yı tanımlıyoruz.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
#@save
def load_data_wiki(batch_size, max_len):
"""WikiText-2 veri kümesini yükleyin."""
num_workers = d2l.get_dataloader_workers()
data_dir = d2l.download_extract('wikitext-2', 'wikitext-2')
paragraphs = _read_wiki(data_dir)
train_set = _WikiTextDataset(paragraphs, max_len)
train_iter = gluon.data.DataLoader(train_set, batch_size, shuffle=True,
num_workers=num_workers)
return train_iter, train_set.vocab
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
#@save
def load_data_wiki(batch_size, max_len):
"""WikiText-2 veri kümesini yükleyin."""
num_workers = d2l.get_dataloader_workers()
data_dir = d2l.download_extract('wikitext-2', 'wikitext-2')
paragraphs = _read_wiki(data_dir)
train_set = _WikiTextDataset(paragraphs, max_len)
train_iter = torch.utils.data.DataLoader(train_set, batch_size,
shuffle=True, num_workers=num_workers)
return train_iter, train_set.vocab
.. raw:: html
.. raw:: html
Toplu iş boyutunu 512 olarak ve BERT girdi dizisinin maksimum uzunluğunu
64 olarak ayarlayarak, BERT ön eğitim örneklerinden oluşan bir
minigrubun şekillerini yazdırıyoruz. Her BERT girdi dizisinde,
maskelenmiş dil modelleme görevi için :math:`10`
(:math:`64 \times 0.15`) konumun tahmin edildiğini unutmayın.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
batch_size, max_len = 512, 64
train_iter, vocab = load_data_wiki(batch_size, max_len)
for (tokens_X, segments_X, valid_lens_x, pred_positions_X, mlm_weights_X,
mlm_Y, nsp_y) in train_iter:
print(tokens_X.shape, segments_X.shape, valid_lens_x.shape,
pred_positions_X.shape, mlm_weights_X.shape, mlm_Y.shape,
nsp_y.shape)
break
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
(512, 64) (512, 64) (512,) (512, 10) (512, 10) (512, 10) (512,)
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
batch_size, max_len = 512, 64
train_iter, vocab = load_data_wiki(batch_size, max_len)
for (tokens_X, segments_X, valid_lens_x, pred_positions_X, mlm_weights_X,
mlm_Y, nsp_y) in train_iter:
print(tokens_X.shape, segments_X.shape, valid_lens_x.shape,
pred_positions_X.shape, mlm_weights_X.shape, mlm_Y.shape,
nsp_y.shape)
break
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
torch.Size([512, 64]) torch.Size([512, 64]) torch.Size([512]) torch.Size([512, 10]) torch.Size([512, 10]) torch.Size([512, 10]) torch.Size([512])
.. raw:: html
.. raw:: html
Sonunda, kelime dağarcığına bir göz atalım. Sık görülen belirteçleri
filtreledikten sonra bile, PTB veri kümesinden iki kat daha büyüktür.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
len(vocab)
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
20256
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
len(vocab)
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
20256
.. raw:: html
.. raw:: html
Özet
----
- PTB veri kümesiyle karşılaştırıldığında, WikiText-2 veri kümesi
orijinal noktalama işaretlerini, büyük/küçük harf ve sayıları korur
ve iki kat daha büyüktür.
- WikiText-2 külliyatındaki bir çift cümleden oluşturulan ön eğitim
(maskeli dil modellemesi ve sonraki cümle tahmini) örneklerine keyfi
olarak erişebiliriz.
Alıştırmalar
------------
1. Basitlik açısından, nokta cümleleri bölmede tek sınırlayıcı olarak
kullanılır. SpaCy ve NLTK gibi diğer cümle ayırma tekniklerini
deneyin. Örnek olarak NLTK'yi ele alalım. Önce NLTK'yi kurmanız
gerekiyor: ``pip install nltk``. Kodda, ilk ``import nltk`` çağırın.
Daha sonra Punkt cümle belirteci ayıklayıcıyı indirin:
``nltk.download('punkt')``.
``sentences = 'This is great ! Why not ?'`` gibi cümleleri ayırmak
için ``nltk.tokenize.sent_tokenize(sentences)`` çağırmak iki cümlelik
bir liste döndürür: ``['This is great !', 'Why not ?']``
2. Seyrek belirteçleri filtrelemezsek kelime dağarcığı boyutu ne olur?
.. raw:: html