moj-2024-ns-cw/04_zadania_helpful_codebloc...

5.8 KiB

Wczytanie zbioru danych do postaci DataFrame

from datasets import load_dataset
import pandas as pd
import torch
from torch.nn.utils.rnn import pad_sequence

hf_dataset = load_dataset("mteb/tweet_sentiment_extraction")
df = pd.DataFrame(hf_dataset["train"])
test_df = pd.DataFrame(hf_dataset["test"])
c:\Users\ryssta\AppData\Local\anaconda3\envs\python39\lib\site-packages\tqdm\auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html
  from .autonotebook import tqdm as notebook_tqdm

Przykładowa modyfikacja tekstu (analogiczne operacje należy wykonać dla podzbioru test)

df = pd.DataFrame(hf_dataset["train"])
print(df["text"].head(3))
df["text"] = df["text"].apply(lambda text_row: text_row.upper())
print(df["text"].head(3))
0               I`d have responded, if I were going
1     Sooo SAD I will miss you here in San Diego!!!
2                         my boss is bullying me...
Name: text, dtype: object
0               I`D HAVE RESPONDED, IF I WERE GOING
1     SOOO SAD I WILL MISS YOU HERE IN SAN DIEGO!!!
2                         MY BOSS IS BULLYING ME...
Name: text, dtype: object

Dodanie warstwy embedding z tokenem pad (czyli "zapychaczem" służącym do wypełniania macierzy)

padding_idx = 9
embedding = torch.nn.Embedding(10, 5, padding_idx=padding_idx)

pad_embedding = embedding(torch.LongTensor([9]))
print(pad_embedding)
tensor([[0., 0., 0., 0., 0.]], grad_fn=<EmbeddingBackward0>)

Padowanie sekwencji przy pomocy funkcji

input_token_ids = [[4,7,2], [7,3,2,7,5,3,2], [1,7,4,2,5]]

max_length = max(len(seq) for seq in input_token_ids)
padded_input = pad_sequence([torch.tensor(seq) for seq in input_token_ids], batch_first=True, padding_value=padding_idx)
lengths = [len(seq) for seq in input_token_ids]

print(padded_input)
print("Długości inputów")
print(lengths)
tensor([[4, 7, 2, 9, 9, 9, 9],
        [7, 3, 2, 7, 5, 3, 2],
        [1, 7, 4, 2, 5, 9, 9]])
Długości inputów
[3, 7, 5]

Przepuszczanie embeddingów przez warstwę LSTM (przy pomocy funkcji padujących)

lstm_layer = torch.nn.LSTM(5, 5, 30, batch_first=True, bidirectional=True)

embedded_inputs = embedding(padded_input)
x = torch.nn.utils.rnn.pack_padded_sequence(embedded_inputs, lengths, batch_first=True, enforce_sorted=False)
output, (hidden, cell) = lstm_layer(x)
output, _ = torch.nn.utils.rnn.pad_packed_sequence(output, batch_first=True)

Zmienna hidden zawiera wszystkie ukryte stany na przestrzeni wszystkich warstw, natomiast zmienna output zawiera jedynie stany w ostatniej warstwie

Wartościami, które należy wykorzystać do klasyfikacji to (jedna z dwóch opcji):

  • konkatenacja ostatniego i przedostatniego elementu ze zmiennej hidden (sieć jest dwukierunkowa, więc chcemy się dostać do stanów z ostatniej warstwy jednego oraz drugiego kierunku)
  • pierwszy element dla każdego przykładu ze zmiennej out (tam jest automatycznie skonkatenowany output dla obu kierunków, dlatego mamy na końcu rozmiar 10)
print(hidden.shape)
print(output.shape)
torch.Size([60, 3, 5])
torch.Size([3, 7, 10])

torch.Size([6, 3, 5]) torch.Size([3, 7, 10])