11 KiB
11 KiB
Funkcja build_vocab_from_iterator automatycznie tworzy słownik na podstawie najczęściej występujących słów, jednocześnie traktując pozostałe słowa jako <unk>
from torchtext.vocab import build_vocab_from_iterator
import io
import zipfile
import torch
with zipfile.ZipFile("challenging_america_50k_texts.zip") as zf:
with io.TextIOWrapper(zf.open("challenging_america_50k_texts.txt"), encoding="utf-8") as f:
data = f.readlines()
def get_words_from_line(line):
line = line.rstrip()
for t in line.split():
yield t
def get_word_lines_from_list(data):
for line in data:
yield get_words_from_line(line)
vocab_size = 3000
vocab = build_vocab_from_iterator(
get_word_lines_from_list(data),
max_tokens = vocab_size,
specials = ['<unk>'])
vocab.set_default_index(vocab['<unk>'])
c:\Users\ryssta\AppData\Local\anaconda3\envs\python39\lib\site-packages\torchtext\vocab\__init__.py:4: UserWarning: /!\ IMPORTANT WARNING ABOUT TORCHTEXT STATUS /!\ Torchtext is deprecated and the last released version will be 0.18 (this one). You can silence this warning by calling the following at the beginnign of your scripts: `import torchtext; torchtext.disable_torchtext_deprecation_warning()` warnings.warn(torchtext._TORCHTEXT_DEPRECATION_MSG) c:\Users\ryssta\AppData\Local\anaconda3\envs\python39\lib\site-packages\torchtext\utils.py:4: UserWarning: /!\ IMPORTANT WARNING ABOUT TORCHTEXT STATUS /!\ Torchtext is deprecated and the last released version will be 0.18 (this one). You can silence this warning by calling the following at the beginnign of your scripts: `import torchtext; torchtext.disable_torchtext_deprecation_warning()` warnings.warn(torchtext._TORCHTEXT_DEPRECATION_MSG)
Dostęp do par słowo, indeks ze słownika
vocab_dict = vocab.get_stoi()
for x, key in enumerate(vocab_dict):
print(key, vocab_dict[key])
if x == 10:
break
<unk> 0 witness 1755 Supreme 2520 seems 577 her 51 ! 503 were 40 Messrs. 1911 small 282 council 2064 but 35
Słownik dla podanego słowa w postaci stringa zwraca indeks w słowniku, który będzie wykorzystywany przez sieć neuronową (słowa nie znajdujące się w słowniku mapowane są na token unk, który posiada indeks 0 - zostało to zdefiniowane poprzez metodę vocab.set_default_index(vocab['<unk>']))
print(vocab["a"])
print(vocab["the"])
print(vocab["John"])
print(vocab["awnifnawonf"])
print(vocab["Poznań"])
print("Dla listy słów:")
print(vocab.lookup_indices(["a", "the"]))
5 1 208 0 0 Dla listy słów: [5, 1]
Operacja odwrota (czyli odczytanie słowa na podstawie indeksu)
print(vocab.lookup_token(1))
print(vocab.lookup_token(1000))
print("Dla listy indeksów:")
print(vocab.lookup_tokens([0, 1, 1000, 2000]))
the attempt Dla listy indeksów: ['<unk>', 'the', 'attempt', 'drew']
Aby przekazać dane słowo (lub słowa) do sieci neuronowej, należy utworzyć na podstawie indeksu danego słowa Tensor
input_to_neural_network = torch.tensor(vocab["the"])
print(input_to_neural_network)
input_to_neural_network = torch.tensor(vocab.lookup_indices(["the", "current"]))
print(input_to_neural_network)
tensor(1) tensor([ 1, 2020])
Zanurzenia słów uzyskujemy poprzez wykorzystanie warstwy torch.nn.Embedding
vocab_size = 10
embedding_size = 3
embedding_layer = torch.nn.Embedding(vocab_size, embedding_size)
input_to_embedding_layer = torch.IntTensor([1, 5])
print("Uzyskanie wartości embeddingów dla tokenu o indeksie 1 oraz tokenu o indeksie 5")
print(embedding_layer((input_to_embedding_layer)))
batched_input_to_embedding_layer = torch.IntTensor([[1, 4],
[2, 9],
[3, 1]])
print("##########################################################")
print("Uzyskanie wartości embeddingów dla batcha z tokenami")
print(embedding_layer((batched_input_to_embedding_layer)))
Uzyskanie wartości embeddingów dla tokenu o indeksie 1 oraz tokenu o indeksie 5 tensor([[-1.0945, -0.1461, 1.2927], [-0.0303, 0.5213, 1.1486]], grad_fn=<EmbeddingBackward0>) ########################################################## Uzyskanie wartości embeddingów dla batcha z tokenami tensor([[[-1.0945, -0.1461, 1.2927], [ 0.2963, 0.1083, 0.0797]], [[-0.9783, 1.1639, 0.3828], [ 1.1856, 1.1943, -0.5562]], [[-0.3472, 0.5670, -1.2830], [-1.0945, -0.1461, 1.2927]]], grad_fn=<EmbeddingBackward0>)
Aby połączyć ze sobą zanurzenia kilku słów (podczas trenowania modelu ngramowego innego niż unigramowy/bigramowy), należy użyć konkatenacji. W torchu do tego wykorzystujemy funkcję torch.cat
first_embedding = torch.Tensor([0.5, 0.2, 0.2])
second_embedding = torch.Tensor([0.91, 0.92, 0.93])
concatenated_embeddings = torch.cat([first_embedding, second_embedding])
print(concatenated_embeddings)
tensor([0.5000, 0.2000, 0.2000, 0.9100, 0.9200, 0.9300])
W przypadku korzystania z batchy musimy zwrócić uwagę na właściwą oś (axis) po której będziemy dokonywać konkatenacji
first_batched_embedding = torch.Tensor([[0.5, 0.2, 0.2],
[0.51, 0.21, 0.21]])
second_batched_embedding = torch.Tensor([[0.91, 0.92, 0.93],
[0.911, 0.922, 0.933]])
concatenated_embeddings = torch.cat([first_batched_embedding, second_batched_embedding])
print("Nieprawidłowa konkatenacja embeddingów (stworzenie 4 tensorów o wymiarze 3, zamiast 2 tensorów o wymiarze 6)")
print(concatenated_embeddings)
properly_concatenated_embeddings = torch.cat([first_batched_embedding, second_batched_embedding], axis=1)
print("#########################################################################")
print("Prawidłowa konkatenacja embeddingów dzięki właściwej wartości parametru axis")
print("Wtedy pierwsze 3 wartości (czyli dla pierwszego Tensora są to wartości 0.5000, 0.2000, 0.2000) reprezentują embedding pierwszego słowa")
print("a kolejne 3 wartości reprezentują embedding drugiego słowa (czyli 0.9100, 0.9200, 0.9300)")
print(properly_concatenated_embeddings)
Nieprawidłowa konkatenacja embeddingów (stworzenie 4 tensorów o wymiarze 3, zamiast 2 tensorów o wymiarze 6) tensor([[0.5000, 0.2000, 0.2000], [0.5100, 0.2100, 0.2100], [0.9100, 0.9200, 0.9300], [0.9110, 0.9220, 0.9330]]) ######################################################################### Prawidłowa konkatenacja embeddingów dzięki właściwej wartości parametru axis Wtedy pierwsze 3 wartości (czyli dla pierwszego Tensora są to wartości 0.5000, 0.2000, 0.2000) reprezentują embedding pierwszego słowa a kolejne 3 wartości reprezentują embedding drugiego słowa (czyli 0.9100, 0.9200, 0.9300) tensor([[0.5000, 0.2000, 0.2000, 0.9100, 0.9200, 0.9300], [0.5100, 0.2100, 0.2100, 0.9110, 0.9220, 0.9330]])