.. _sec_natural-language-inference-and-dataset:
Doğal Dil Çıkarımı ve Veri Kümesi
=================================
:numref:`sec_sentiment` içinde, duygu analizi sorununu tartıştık. Bu
görev, tek bir metin dizisini, duygu kutupları kümesi gibi önceden
tanımlanmış kategorilere sınıflandırmayı amaçlamaktadır. Bununla
birlikte, bir cümlenin diğerinden çıkarılıp çıkarılamayacağına karar
vermek veya anlamsal olarak eşdeğer cümleleri tanımlayarak fazlalıkları
ortadan kaldırmak gerektiğinde, bir metin dizisini nasıl
sınıflandıracağını bilmek yetersizdir. Bunun yerine, metin dizileri
çiftleri üzerinde akıl yürütebilmemiz gerekir.
Doğal Dil Çıkarımı
------------------
*Doğal dil çıkarımı*, her ikisinin de bir metin dizisi olduğu bir
*öncülden* bir *hipotezin* çıkarılıp çıkarılamayacağını inceler. Başka
bir deyişle, doğal dil çıkarımı, bir çift metin dizisi arasındaki
mantıksal ilişkiyi belirler. Bu tür ilişkiler genellikle üç tipe
ayrılır:
- *Gerekçe*: Hipotez, öncülden çıkarılabilir.
- *Çelişki*: Hipotezin olumsuzlanması öncülden çıkarılabilir.
- *Tarafsızlık*: Diğer tüm durumlar.
Doğal dil çıkarımı aynı zamanda metinsel gerekçe görevi olarak da
bilinir. Örneğin, aşağıdaki çift, *gerekçe* olarak etiketlenecektir,
çünkü hipotezdeki “sevgi göstermek” öncülünden “birbirine sarılmak”
çıkarılabilir.
Öncül: İki kadın birbirlerine sarılıyor.
Hipotez: İki kadın sevgi gösteriyor.
"Kodlama örneğini çalıştırmak", "uyku" yerine "uyumamayı"
gösterdiğinden, aşağıda bir *çelişki* örneği verilmiştir.
Öncül: Bir adam Derin Öğrenmeye Dalış'tan kodlama örneğini
çalıştırıyor.
Hipotez: Adam uyuyor.
Üçüncü örnek bir *tarafsızlık* ilişkisini gösterir, çünkü ne "ünlü" ne
de "ünlü değil" "bizim için performans gösteriyor" gerçeğinden
çıkarılamaz.
Öncül: Müzisyenler bizim için performans gösteriyorlar.
Hipotez: Müzisyenler ünlüdür.
Doğal dil çıkarımı doğal dili anlamak için merkezi bir konu olmuştur.
Bilgi getiriminden açık alan sorularını yanıtlamaya kadar geniş
uygulamalara sahiptir. Bu sorunu incelemek için popüler bir doğal dil
çıkarım kıyaslama veri kümesini araştırarak başlayacağız.
Stanford Doğal Dil Çıkarımı (SNLI) Veri Kümesi
----------------------------------------------
Stanford Doğal Dil Çıkarımı (Stanford Natural Language Inference - SNLI)
Külliyatı 500000'in üzerinde etiketli İngilizce cümle çiftleri içeren
bir koleksiyondur :cite:`Bowman.Angeli.Potts.ea.2015`. Ayıklanan SNLI
veri kümesini ``../data/snli_1.0`` yoluna indirip saklıyoruz.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
import os
import re
from d2l import mxnet as d2l
from mxnet import gluon, np, npx
npx.set_np()
#@save
d2l.DATA_HUB['SNLI'] = (
'https://nlp.stanford.edu/projects/snli/snli_1.0.zip',
'9fcde07509c7e87ec61c640c1b2753d9041758e4')
data_dir = d2l.download_extract('SNLI')
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
import os
import re
import torch
from torch import nn
from d2l import torch as d2l
#@save
d2l.DATA_HUB['SNLI'] = (
'https://nlp.stanford.edu/projects/snli/snli_1.0.zip',
'9fcde07509c7e87ec61c640c1b2753d9041758e4')
data_dir = d2l.download_extract('SNLI')
.. raw:: html
.. raw:: html
Veri Kümesini Okuma
~~~~~~~~~~~~~~~~~~~
Orijinal SNLI veri kümesi, deneylerimizde gerçekten ihtiyacımız olandan
çok daha zengin bilgi içeriyor. Bu nedenle, veri kümesinin yalnızca bir
kısmını çıkarmak için bir ``read_snli`` işlevi tanımlarız, ardından
öncüllerin, hipotezlerin ve bunların etiketlerinin listesini döndürürüz.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
#@save
def read_snli(data_dir, is_train):
"""SNLI veri kümesini öncüller, hipotezler ve etiketler halinde okuyun."""
def extract_text(s):
# Bizim tarafımızdan kullanılmayacak bilgileri kaldırın
s = re.sub('\\(', '', s)
s = re.sub('\\)', '', s)
# Ardışık iki veya daha fazla boşluğu boşlukla değiştirin
s = re.sub('\\s{2,}', ' ', s)
return s.strip()
label_set = {'entailment': 0, 'contradiction': 1, 'neutral': 2}
file_name = os.path.join(data_dir, 'snli_1.0_train.txt'
if is_train else 'snli_1.0_test.txt')
with open(file_name, 'r') as f:
rows = [row.split('\t') for row in f.readlines()[1:]]
premises = [extract_text(row[1]) for row in rows if row[0] in label_set]
hypotheses = [extract_text(row[2]) for row in rows if row[0] in label_set]
labels = [label_set[row[0]] for row in rows if row[0] in label_set]
return premises, hypotheses, labels
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
#@save
def read_snli(data_dir, is_train):
"""SNLI veri kümesini öncüller, hipotezler ve etiketler halinde okuyun."""
def extract_text(s):
# Bizim tarafımızdan kullanılmayacak bilgileri kaldırın
s = re.sub('\\(', '', s)
s = re.sub('\\)', '', s)
# Ardışık iki veya daha fazla boşluğu boşlukla değiştirin
s = re.sub('\\s{2,}', ' ', s)
return s.strip()
label_set = {'entailment': 0, 'contradiction': 1, 'neutral': 2}
file_name = os.path.join(data_dir, 'snli_1.0_train.txt'
if is_train else 'snli_1.0_test.txt')
with open(file_name, 'r') as f:
rows = [row.split('\t') for row in f.readlines()[1:]]
premises = [extract_text(row[1]) for row in rows if row[0] in label_set]
hypotheses = [extract_text(row[2]) for row in rows if row[0] in label_set]
labels = [label_set[row[0]] for row in rows if row[0] in label_set]
return premises, hypotheses, labels
.. raw:: html
.. raw:: html
Şimdi ilk 3 çift öncül ve hipotezin yanı sıra onların etiketlerini
yazdıralım ("0", "1" ve "2" sırasıyla "gerekçe", "çelişki" ve
"tarafsızlık"'a karşılık gelir).
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
train_data = read_snli(data_dir, is_train=True)
for x0, x1, y in zip(train_data[0][:3], train_data[1][:3], train_data[2][:3]):
print('premise:', x0)
print('hypothesis:', x1)
print('label:', y)
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
premise: A person on a horse jumps over a broken down airplane .
hypothesis: A person is training his horse for a competition .
label: 2
premise: A person on a horse jumps over a broken down airplane .
hypothesis: A person is at a diner , ordering an omelette .
label: 1
premise: A person on a horse jumps over a broken down airplane .
hypothesis: A person is outdoors , on a horse .
label: 0
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
train_data = read_snli(data_dir, is_train=True)
for x0, x1, y in zip(train_data[0][:3], train_data[1][:3], train_data[2][:3]):
print('premise:', x0)
print('hypothesis:', x1)
print('label:', y)
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
premise: A person on a horse jumps over a broken down airplane .
hypothesis: A person is training his horse for a competition .
label: 2
premise: A person on a horse jumps over a broken down airplane .
hypothesis: A person is at a diner , ordering an omelette .
label: 1
premise: A person on a horse jumps over a broken down airplane .
hypothesis: A person is outdoors , on a horse .
label: 0
.. raw:: html
.. raw:: html
Eğitim kümesinin yaklaşık 550000 çifti vardır ve test kümesi yaklaşık
10000 çifte sahiptir. Aşağıdakiler, hem eğitim kümesindeki hem de test
kümesindeki üç etiketin, "gerekçe", "çelişki" ve "tarafsızlık",
dengelendiğini göstermektedir.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
test_data = read_snli(data_dir, is_train=False)
for data in [train_data, test_data]:
print([[row for row in data[2]].count(i) for i in range(3)])
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
[183416, 183187, 182764]
[3368, 3237, 3219]
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
test_data = read_snli(data_dir, is_train=False)
for data in [train_data, test_data]:
print([[row for row in data[2]].count(i) for i in range(3)])
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
[183416, 183187, 182764]
[3368, 3237, 3219]
.. raw:: html
.. raw:: html
Veri kümesini Yüklemek İçin Bir Sınıf Tanımlama
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Aşağıda, Gluon'daki ``Dataset`` sınıfından türetilmiş SNLI veri kümesini
yüklemek için bir sınıf tanımlıyoruz. Sınıf kurucusundaki ``num_steps``
bağımsız değişkeni, bir metin dizisinin uzunluğunu belirtir, böylece
dizilerin her minigrup işlemi aynı şekle sahip olur. Başka bir deyişle,
daha uzun dizideki ilk ``num_steps`` olanlardan sonraki belirteçler
kırpılırken, "" özel belirteçleri uzunlukları ``num_steps`` olana
kadar daha kısa dizilere eklenecektir. ``__getitem__`` işlevini
uygulayarak, ``idx`` endeksi ile öncüle, hipoteze ve etikete keyfi
olarak erişebiliriz.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
#@save
class SNLIDataset(gluon.data.Dataset):
"""SNLI veri kümesini yüklemek için özelleştirilmiş bir veri kümesi."""
def __init__(self, dataset, num_steps, vocab=None):
self.num_steps = num_steps
all_premise_tokens = d2l.tokenize(dataset[0])
all_hypothesis_tokens = d2l.tokenize(dataset[1])
if vocab is None:
self.vocab = d2l.Vocab(all_premise_tokens + all_hypothesis_tokens,
min_freq=5, reserved_tokens=['
'])
else:
self.vocab = vocab
self.premises = self._pad(all_premise_tokens)
self.hypotheses = self._pad(all_hypothesis_tokens)
self.labels = np.array(dataset[2])
print('read ' + str(len(self.premises)) + ' examples')
def _pad(self, lines):
return np.array([d2l.truncate_pad(
self.vocab[line], self.num_steps, self.vocab[''])
for line in lines])
def __getitem__(self, idx):
return (self.premises[idx], self.hypotheses[idx]), self.labels[idx]
def __len__(self):
return len(self.premises)
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
#@save
class SNLIDataset(torch.utils.data.Dataset):
"""SNLI veri kümesini yüklemek için özelleştirilmiş bir veri kümesi."""
def __init__(self, dataset, num_steps, vocab=None):
self.num_steps = num_steps
all_premise_tokens = d2l.tokenize(dataset[0])
all_hypothesis_tokens = d2l.tokenize(dataset[1])
if vocab is None:
self.vocab = d2l.Vocab(all_premise_tokens + all_hypothesis_tokens,
min_freq=5, reserved_tokens=['
'])
else:
self.vocab = vocab
self.premises = self._pad(all_premise_tokens)
self.hypotheses = self._pad(all_hypothesis_tokens)
self.labels = torch.tensor(dataset[2])
print('read ' + str(len(self.premises)) + ' examples')
def _pad(self, lines):
return torch.tensor([d2l.truncate_pad(
self.vocab[line], self.num_steps, self.vocab[''])
for line in lines])
def __getitem__(self, idx):
return (self.premises[idx], self.hypotheses[idx]), self.labels[idx]
def __len__(self):
return len(self.premises)
.. raw:: html
.. raw:: html
Her Şeyi Bir Araya Koymak
~~~~~~~~~~~~~~~~~~~~~~~~~
Artık ``read_snli`` işlevini ve ``SNLIDataset`` sınıfını SNLI veri
kümesini indirmek ve eğitim kümesinin kelime dağarcığıyla birlikte hem
eğitim hem de test kümeleri için ``DataLoader`` örneklerini döndürmek
için çalıştırabiliriz. Eğitim kümesinden inşa edilen kelime dağarcığını
test kümesininki gibi kullanmamız dikkat çekicidir. Sonuç olarak, test
kümesindeki herhangi bir yeni belirteç, eğitim kümesinde eğitilen
modelce bilinmeyecektir.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
#@save
def load_data_snli(batch_size, num_steps=50):
"""SNLI veri kümesini indirin ve veri yineleyicilerini ve kelime dağarcığını döndürün."""
num_workers = d2l.get_dataloader_workers()
data_dir = d2l.download_extract('SNLI')
train_data = read_snli(data_dir, True)
test_data = read_snli(data_dir, False)
train_set = SNLIDataset(train_data, num_steps)
test_set = SNLIDataset(test_data, num_steps, train_set.vocab)
train_iter = gluon.data.DataLoader(train_set, batch_size, shuffle=True,
num_workers=num_workers)
test_iter = gluon.data.DataLoader(test_set, batch_size, shuffle=False,
num_workers=num_workers)
return train_iter, test_iter, train_set.vocab
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
#@save
def load_data_snli(batch_size, num_steps=50):
"""SNLI veri kümesini indirin ve veri yineleyicilerini ve kelime dağarcığını döndürün."""
num_workers = d2l.get_dataloader_workers()
data_dir = d2l.download_extract('SNLI')
train_data = read_snli(data_dir, True)
test_data = read_snli(data_dir, False)
train_set = SNLIDataset(train_data, num_steps)
test_set = SNLIDataset(test_data, num_steps, train_set.vocab)
train_iter = torch.utils.data.DataLoader(train_set, batch_size,
shuffle=True,
num_workers=num_workers)
test_iter = torch.utils.data.DataLoader(test_set, batch_size,
shuffle=False,
num_workers=num_workers)
return train_iter, test_iter, train_set.vocab
.. raw:: html
.. raw:: html
Burada toplu iş boyutunu 128'e ve dizi uzunluğunu 50'ye ayarlıyoruz ve
veri yineleyicilerini ve kelime dağarcığını elde etmek için
``load_data_snli`` işlevini çağırıyoruz. Sonra kelime dağarcığı boyutunu
yazdırıyoruz.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
train_iter, test_iter, vocab = load_data_snli(128, 50)
len(vocab)
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
read 549367 examples
read 9824 examples
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
18678
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
train_iter, test_iter, vocab = load_data_snli(128, 50)
len(vocab)
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
read 549367 examples
read 9824 examples
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
18678
.. raw:: html
.. raw:: html
Şimdi ilk minigrubun şeklini yazdırıyoruz. Duygu analizinin aksine, iki
girdi, ``X[0]`` ve ``X[1]``, öncül ve hipotez çiftlerini temsil ediyor.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
for X, Y in train_iter:
print(X[0].shape)
print(X[1].shape)
print(Y.shape)
break
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
(128, 50)
(128, 50)
(128,)
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
for X, Y in train_iter:
print(X[0].shape)
print(X[1].shape)
print(Y.shape)
break
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
torch.Size([128, 50])
torch.Size([128, 50])
torch.Size([128])
.. raw:: html
.. raw:: html
Özet
----
- Doğal dil çıkarımı, her ikisinin de bir metin dizisi olduğu, bir
öncülden bir hipotezin çıkarılıp çıkarılamayacağını inceler.
- Doğal dil çıkarımlarında, öncüller ve hipotezler arasındaki
ilişkiler, gerekçe, çelişki ve tarafsızlık olarak sayılabilir.
- Stanford Doğal Dil Çıkarımı (Stanford Natural Language Inference -
SNLI) Külliyatı, doğal dil çıkarımında popüler bir kıyaslama veri
kümesidir.
Alıştırmalar
------------
1. Makine çevirisi uzun zamandır bir çıktı çevirisi ile bir gerçek
referans değer çeviri arasındaki yüzeysel :math:`n`-gramlar
eşleşmesine dayalı olarak değerlendirilmektedir. Doğal dil çıkarımını
kullanarak makine çevirisi sonuçlarını değerlendirmek için bir ölçü
tasarlayabilir misiniz?
2. Kelime dağarcığı boyutunu azaltmak için hiper parametreleri nasıl
değiştirebiliriz?
.. raw:: html
.. raw:: html
`Tartışmalar `__
.. raw:: html
.. raw:: html
`Tartışmalar `__
.. raw:: html
.. raw:: html