.. _sec_sentiment_rnn: Duygu Analizi: Yinemeli Sinir Ağlarının Kullanımı ================================================= Kelime benzerliği ve benzetme görevleri gibi, biz de duygu analizine önceden eğitilmiş kelime vektörleri de uygulayabiliriz. :numref:`sec_sentiment` içindeki IMDb inceleme veri kümesi çok büyük olmadığından, büyük ölçekli külliyat üzerinde önceden eğitilmiş metin temsillerinin kullanılması modelin aşırı öğrenmesini azaltabilir. :numref:`fig_nlp-map-sa-rnn` içinde gösterilen özel bir örnek olarak, önceden eğitilmiş GloVe modelini kullanarak her belirteci temsil edeceğiz ve bu belirteç temsillerini metin dizisi gösterimini, ki duygu analizi çıktılarına dönüştürülecektir, elde etmek için çok katmanlı çift yönlü bir RNN'ye besleyeceğiz :cite:`Maas.Daly.Pham.ea.2011`. Aynı aşağı akım uygulaması için daha sonra farklı bir mimari seçimi ele alacağız. .. _fig_nlp-map-sa-rnn: .. figure:: ../img/nlp-map-sa-rnn.svg Bu bölüm, duygu analizi için önceden eğitilmiş GloVe'yi RNN tabanlı bir mimariye besler. .. raw:: html
mxnetpytorch
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python from d2l import mxnet as d2l from mxnet import gluon, init, np, npx from mxnet.gluon import nn, rnn npx.set_np() batch_size = 64 train_iter, test_iter, vocab = d2l.load_data_imdb(batch_size) .. raw:: html
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python import torch from torch import nn from d2l import torch as d2l batch_size = 64 train_iter, test_iter, vocab = d2l.load_data_imdb(batch_size) .. raw:: html
.. raw:: html
RNN'lerle Tek Metni Temsil Etme ------------------------------- Duygu analizi gibi metin sınıflandırmalarında, değişen uzunluktaki bir metin dizisi sabit uzunlukta kategorilere dönüştürülür. Aşağıdaki ``BiRNN`` sınıfında, bir metin dizisinin her belirteci, gömme katman (``self.embedding``) aracılığıyla bireysel önceden eğitilmiş GloVe temsilini alırken, tüm dizi çift yönlü RNN (``self.encoder``) ile kodlanır. Daha somut olarak, iki yönlü LSTM'nin hem ilk hem de son zaman adımlarındaki gizli durumları (son katmanda), metin dizisinin temsili olarak bitiştirilir. Bu tek metin gösterimi daha sonra iki çıktıya ("pozitif" ve "negatif") sahip tam bağlı bir katman (``self.encoder``) tarafından çıktı kategorilerine dönüştürülür. .. raw:: html
mxnetpytorch
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python class BiRNN(nn.Block): def __init__(self, vocab_size, embed_size, num_hiddens, num_layers, **kwargs): super(BiRNN, self).__init__(**kwargs) self.embedding = nn.Embedding(vocab_size, embed_size) # Çift yönlü bir RNN elde etmek için `bidirectional` (çift yönlü) # öğesini True olarak ayarlayın self.encoder = rnn.LSTM(num_hiddens, num_layers=num_layers, bidirectional=True, input_size=embed_size) self.decoder = nn.Dense(2) def forward(self, inputs): # `inputs` şekli (parti boyutu, zaman adımı sayısı)'dır. LSTM, # girdisinin ilk boyutunun zamansal boyut olmasını gerektirdiğinden, # girdi, belirteç temsilleri elde edilmeden önce değiştirilir. Çıktı # şekli (zaman adımı sayısı, iş boyutu, kelime vektör boyutu) embeddings = self.embedding(inputs.T) # Farklı zaman adımlarında son gizli katmanın gizli durumlarını # döndürür. `outputs` şekli # (zaman adımı sayısı, iş boyutu, 2 * gizli birim sayısı)'dır. outputs = self.encoder(embeddings) # Tam bağlı katmanın girdisi olarak ilk ve son zaman adımlarında gizli # durumları bitiştirin. # Şekli (parti boyutu, 4 * gizli birim sayısı)'dır encoding = np.concatenate((outputs[0], outputs[-1]), axis=1) outs = self.decoder(encoding) return outs .. raw:: html
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python class BiRNN(nn.Module): def __init__(self, vocab_size, embed_size, num_hiddens, num_layers, **kwargs): super(BiRNN, self).__init__(**kwargs) self.embedding = nn.Embedding(vocab_size, embed_size) # Çift yönlü bir RNN elde etmek için `bidirectional` (çift yönlü) # öğesini True olarak ayarlayın self.encoder = nn.LSTM(embed_size, num_hiddens, num_layers=num_layers, bidirectional=True) self.decoder = nn.Linear(4 * num_hiddens, 2) def forward(self, inputs): # `inputs` şekli (parti boyutu, zaman adımı sayısı)'dır. LSTM, # girdisinin ilk boyutunun zamansal boyut olmasını gerektirdiğinden, # girdi, belirteç temsilleri elde edilmeden önce değiştirilir. Çıktı # şekli (zaman adımı sayısı, parti boyutu, kelime vektör boyutu) embeddings = self.embedding(inputs.T) self.encoder.flatten_parameters() # Farklı zaman adımlarında son gizli katmanın gizli durumlarını # döndürür. `outputs` şekli # (zaman adımı sayısı, iş boyutu, 2 * gizli birim sayısı)'dır. outputs, _ = self.encoder(embeddings) # Tam bağlı katmanın girdisi olarak ilk ve son zaman adımlarında gizli # durumları bitiştirin. # Şekli (parti boyutu, 4 * gizli birim sayısı)'dır encoding = torch.cat((outputs[0], outputs[-1]), dim=1) outs = self.decoder(encoding) return outs .. raw:: html
.. raw:: html
Duygu analizi için tek bir metni temsil etmek üzere iki gizli katman içeren çift yönlü bir RNN oluşturalım. .. raw:: html
mxnetpytorch
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python embed_size, num_hiddens, num_layers, devices = 100, 100, 2, d2l.try_all_gpus() net = BiRNN(len(vocab), embed_size, num_hiddens, num_layers) net.initialize(init.Xavier(), ctx=devices) .. raw:: html
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python embed_size, num_hiddens, num_layers, devices = 100, 100, 2, d2l.try_all_gpus() net = BiRNN(len(vocab), embed_size, num_hiddens, num_layers) def init_weights(m): if type(m) == nn.Linear: nn.init.xavier_uniform_(m.weight) if type(m) == nn.LSTM: for param in m._flat_weights_names: if "weight" in param: nn.init.xavier_uniform_(m._parameters[param]) net.apply(init_weights); .. raw:: html
.. raw:: html
Önceden Eğitilmiş Sözcük Vektörlerini Yükleme --------------------------------------------- Aşağıda önceden eğitilmiş 100 boyutlu (``embed_size`` ile tutarlı olması gerekir) kelime dağarcığındaki belirteçler için GloVe gömmelerini yüklüyoruz. .. raw:: html
mxnetpytorch
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python glove_embedding = d2l.TokenEmbedding('glove.6b.100d') .. raw:: html
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python glove_embedding = d2l.TokenEmbedding('glove.6b.100d') .. raw:: html
.. raw:: html
Kelime dağarcığındaki tüm belirteçler için vektörlerin şeklini yazdırın. .. raw:: html
mxnetpytorch
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python embeds = glove_embedding[vocab.idx_to_token] embeds.shape .. raw:: latex \diilbookstyleoutputcell .. parsed-literal:: :class: output (49346, 100) .. raw:: html
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python embeds = glove_embedding[vocab.idx_to_token] embeds.shape .. raw:: latex \diilbookstyleoutputcell .. parsed-literal:: :class: output torch.Size([49346, 100]) .. raw:: html
.. raw:: html
Bu önceden eğitilmiş kelime vektörlerini incelemelerde belirteçleri temsil etmek için kullanıyoruz ve eğitim sırasında bu vektörleri güncellemeyeceğiz. .. raw:: html
mxnetpytorch
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python net.embedding.weight.set_data(embeds) net.embedding.collect_params().setattr('grad_req', 'null') .. raw:: html
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python net.embedding.weight.data.copy_(embeds) net.embedding.weight.requires_grad = False .. raw:: html
.. raw:: html
Model Eğitimi ve Değerlendirilmesi ---------------------------------- Şimdi çift yönlü RNN'leri duygu analizi için eğitebiliriz. .. raw:: html
mxnetpytorch
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python lr, num_epochs = 0.01, 5 trainer = gluon.Trainer(net.collect_params(), 'adam', {'learning_rate': lr}) loss = gluon.loss.SoftmaxCrossEntropyLoss() d2l.train_ch13(net, train_iter, test_iter, loss, trainer, num_epochs, devices) .. raw:: latex \diilbookstyleoutputcell .. parsed-literal:: :class: output loss 0.276, train acc 0.885, test acc 0.859 732.3 examples/sec on [gpu(0), gpu(1)] .. figure:: output_sentiment-analysis-rnn_6199ad_57_1.svg .. raw:: html
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python lr, num_epochs = 0.01, 5 trainer = torch.optim.Adam(net.parameters(), lr=lr) loss = nn.CrossEntropyLoss(reduction="none") d2l.train_ch13(net, train_iter, test_iter, loss, trainer, num_epochs, devices) .. raw:: latex \diilbookstyleoutputcell .. parsed-literal:: :class: output loss 0.293, train acc 0.881, test acc 0.854 693.3 examples/sec on [device(type='cuda', index=0), device(type='cuda', index=1)] .. figure:: output_sentiment-analysis-rnn_6199ad_60_1.svg .. raw:: html
.. raw:: html
Eğitimli modeli, ``net``, kullanarak bir metin dizisinin duygusunu tahmin etmek için aşağıdaki işlevi tanımlıyoruz. .. raw:: html
mxnetpytorch
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python #@save def predict_sentiment(net, vocab, sequence): """Bir metin dizisinin duygusunu tahmin edin.""" sequence = np.array(vocab[sequence.split()], ctx=d2l.try_gpu()) label = np.argmax(net(sequence.reshape(1, -1)), axis=1) return 'positive' if label == 1 else 'negative' .. raw:: html
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python #@save def predict_sentiment(net, vocab, sequence): """Bir metin dizisinin duygusunu tahmin edin.""" sequence = torch.tensor(vocab[sequence.split()], device=d2l.try_gpu()) label = torch.argmax(net(sequence.reshape(1, -1)), dim=1) return 'positive' if label == 1 else 'negative' .. raw:: html
.. raw:: html
Son olarak, iki basit cümlenin duygusunu tahmin etmek için eğitimli modeli kullanalım. .. raw:: html
mxnetpytorch
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python predict_sentiment(net, vocab, 'this movie is so great') .. raw:: latex \diilbookstyleoutputcell .. parsed-literal:: :class: output 'positive' .. raw:: latex \diilbookstyleinputcell .. code:: python predict_sentiment(net, vocab, 'this movie is so bad') .. raw:: latex \diilbookstyleoutputcell .. parsed-literal:: :class: output 'negative' .. raw:: html
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python predict_sentiment(net, vocab, 'this movie is so great') .. raw:: latex \diilbookstyleoutputcell .. parsed-literal:: :class: output 'positive' .. raw:: latex \diilbookstyleinputcell .. code:: python predict_sentiment(net, vocab, 'this movie is so bad') .. raw:: latex \diilbookstyleoutputcell .. parsed-literal:: :class: output 'negative' .. raw:: html
.. raw:: html
Özet ---- - Önceden eğitilmiş sözcük vektörleri, bir metin dizisinde tek tek belirteçleri temsil edebilir. - Çift yönlü RNN'ler, örneğin ilk ve son zaman adımlarında gizli durumlarının bitiştirilmesi yoluyla olduğu gibi bir metin dizisini temsil edebilir. Bu tek metin gösterimi, tam bağlı bir katman kullanılarak kategorilere dönüştürülebilir. Alıştırmalar ------------ 1. Dönem sayısını artırın. Eğitim ve test doğruluklarını iyileştirebilir misiniz? Diğer hiper parametreleri ayarlamaya ne dersiniz? 2. 300 boyutlu GloVe gömme gibi daha büyük önceden eğitilmiş sözcük vektörlerini kullanın. Sınıflandırma doğruluğunu arttırıyor mu? 3. SpaCy andıçlamasını kullanarak sınıflandırma doğruluğunu artırabilir miyiz? SpaCy (``pip install spacy``) ve İngilizce paketini (``python -m spacy download en``) yüklemeniz gerekir. Kodda, önce spaCy'i (``import spacy``) içe aktarın. Ardından, spaCy İngilizce paketini yükleyin (``spacy_en = spacy.load('en')``). Son olarak, ``def tokenizer(text): return [tok.text for tok in spacy_en.tokenizer(text)]`` işlevini tanımlayın ve orijinal ``tokenizer`` işlevini değiştirin. GloVe ve spaCy içinde ifade belirteçlerinin farklı biçimlerine dikkat edin. Örneğin, "new york" ifade belirteci GloVe'de "new-york" biçimini ve spaCy andıçlamasından sonra "new york" biçimini alır. .. raw:: html
mxnetpytorch
.. raw:: html
`Tartışmalar `__ .. raw:: html
.. raw:: html
`Tartışmalar `__ .. raw:: html
.. raw:: html