AI-For-Beginners/translations/pl/lessons/5-NLP/13-TextRep/TextRepresentationTF.ipynb

647 lines
26 KiB
Plaintext

{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Zadanie klasyfikacji tekstu\n",
"\n",
"W tym module rozpoczniemy od prostego zadania klasyfikacji tekstu opartego na zbiorze danych **[AG_NEWS](http://www.di.unipi.it/~gulli/AG_corpus_of_news_articles.html)**: będziemy klasyfikować nagłówki wiadomości do jednej z 4 kategorii: Świat, Sport, Biznes oraz Nauka/Technologia.\n",
"\n",
"## Zbiór danych\n",
"\n",
"Aby załadować zbiór danych, skorzystamy z API **[TensorFlow Datasets](https://www.tensorflow.org/datasets)**.\n"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import tensorflow as tf\n",
"from tensorflow import keras\n",
"import tensorflow_datasets as tfds\n",
"\n",
"# In this tutorial, we will be training a lot of models. In order to use GPU memory cautiously,\n",
"# we will set tensorflow option to grow GPU memory allocation when required.\n",
"physical_devices = tf.config.list_physical_devices('GPU') \n",
"if len(physical_devices)>0:\n",
" tf.config.experimental.set_memory_growth(physical_devices[0], True)\n",
"\n",
"dataset = tfds.load('ag_news_subset')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Możemy teraz uzyskać dostęp do części treningowej i testowej zbioru danych, używając odpowiednio `dataset['train']` i `dataset['test']:\n"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Length of train dataset = 120000\n",
"Length of test dataset = 7600\n"
]
}
],
"source": [
"ds_train = dataset['train']\n",
"ds_test = dataset['test']\n",
"\n",
"print(f\"Length of train dataset = {len(ds_train)}\")\n",
"print(f\"Length of test dataset = {len(ds_test)}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Wydrukujmy pierwsze 10 nowych nagłówków z naszego zestawu danych:\n"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"3 (Sci/Tech) -> b'AMD Debuts Dual-Core Opteron Processor' b'AMD #39;s new dual-core Opteron chip is designed mainly for corporate computing applications, including databases, Web services, and financial transactions.'\n",
"1 (Sports) -> b\"Wood's Suspension Upheld (Reuters)\" b'Reuters - Major League Baseball\\\\Monday announced a decision on the appeal filed by Chicago Cubs\\\\pitcher Kerry Wood regarding a suspension stemming from an\\\\incident earlier this season.'\n",
"2 (Business) -> b'Bush reform may have blue states seeing red' b'President Bush #39;s quot;revenue-neutral quot; tax reform needs losers to balance its winners, and people claiming the federal deduction for state and local taxes may be in administration planners #39; sights, news reports say.'\n",
"3 (Sci/Tech) -> b\"'Halt science decline in schools'\" b'Britain will run out of leading scientists unless science education is improved, says Professor Colin Pillinger.'\n",
"1 (Sports) -> b'Gerrard leaves practice' b'London, England (Sports Network) - England midfielder Steven Gerrard injured his groin late in Thursday #39;s training session, but is hopeful he will be ready for Saturday #39;s World Cup qualifier against Austria.'\n"
]
}
],
"source": [
"classes = ['World', 'Sports', 'Business', 'Sci/Tech']\n",
"\n",
"for i,x in zip(range(5),ds_train):\n",
" print(f\"{x['label']} ({classes[x['label']]}) -> {x['title']} {x['description']}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Wektoryzacja tekstu\n",
"\n",
"Teraz musimy przekształcić tekst w **liczby**, które mogą być reprezentowane jako tensory. Jeśli chcemy reprezentację na poziomie słów, musimy wykonać dwa kroki:\n",
"\n",
"* Użyć **tokenizatora**, aby podzielić tekst na **tokeny**.\n",
"* Zbudować **słownik** tych tokenów.\n",
"\n",
"### Ograniczanie rozmiaru słownika\n",
"\n",
"W przykładzie z zestawem danych AG News rozmiar słownika jest dość duży, ponad 100 tysięcy słów. Ogólnie rzecz biorąc, nie potrzebujemy słów, które rzadko występują w tekście — tylko kilka zdań będzie je zawierać, a model nie nauczy się na ich podstawie. Dlatego warto ograniczyć rozmiar słownika do mniejszej liczby, przekazując odpowiedni argument do konstruktora wektoryzatora:\n",
"\n",
"Oba te kroki można wykonać za pomocą warstwy **TextVectorization**. Zainicjujmy obiekt wektoryzatora, a następnie wywołajmy metodę `adapt`, aby przejść przez cały tekst i zbudować słownik:\n"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"vocab_size = 50000\n",
"vectorizer = keras.layers.experimental.preprocessing.TextVectorization(max_tokens=vocab_size)\n",
"vectorizer.adapt(ds_train.take(500).map(lambda x: x['title']+' '+x['description']))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"> **Uwaga** używamy jedynie podzbioru całego zbioru danych, aby zbudować słownictwo. Robimy to, aby przyspieszyć czas wykonania i nie trzymać Cię w oczekiwaniu. Jednak podejmujemy ryzyko, że niektóre słowa z całego zbioru danych nie zostaną uwzględnione w słownictwie i będą pominięte podczas treningu. Zatem użycie pełnego rozmiaru słownictwa i przejście przez cały zbiór danych podczas `adapt` powinno zwiększyć ostateczną dokładność, ale nieznacznie.\n",
"\n",
"Teraz możemy uzyskać dostęp do rzeczywistego słownictwa:\n"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"['', '[UNK]', 'the', 'to', 'a', 'in', 'of', 'and', 'on', 'for']\n",
"Length of vocabulary: 5335\n"
]
}
],
"source": [
"vocab = vectorizer.get_vocabulary()\n",
"vocab_size = len(vocab)\n",
"print(vocab[:10])\n",
"print(f\"Length of vocabulary: {vocab_size}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Korzystając z wektoryzatora, możemy łatwo zakodować dowolny tekst w zestaw liczb:\n"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"<tf.Tensor: shape=(7,), dtype=int64, numpy=array([ 112, 3695, 3, 304, 11, 1041, 1], dtype=int64)>"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"vectorizer('I love to play with my words')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Reprezentacja tekstu za pomocą modelu Bag-of-words\n",
"\n",
"Ponieważ słowa niosą znaczenie, czasami możemy zrozumieć sens fragmentu tekstu, patrząc jedynie na pojedyncze słowa, niezależnie od ich kolejności w zdaniu. Na przykład, przy klasyfikacji wiadomości, słowa takie jak *pogoda* i *śnieg* prawdopodobnie wskazują na *prognozę pogody*, podczas gdy słowa takie jak *akcje* i *dolar* będą związane z *wiadomościami finansowymi*.\n",
"\n",
"Reprezentacja wektorowa **Bag-of-words** (BoW) jest najprostszą do zrozumienia tradycyjną metodą reprezentacji wektorowej. Każde słowo jest powiązane z indeksem wektora, a element wektora zawiera liczbę wystąpień danego słowa w określonym dokumencie.\n",
"\n",
"![Obraz pokazujący, jak reprezentacja wektorowa bag-of-words jest przechowywana w pamięci.](../../../../../lessons/5-NLP/13-TextRep/images/bag-of-words-example.png) \n",
"\n",
"> **Note**: Możesz również myśleć o BoW jako o sumie wszystkich wektorów zakodowanych metodą one-hot dla poszczególnych słów w tekście.\n",
"\n",
"Poniżej znajduje się przykład generowania reprezentacji bag-of-words przy użyciu biblioteki Scikit Learn w Pythonie:\n"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[1, 1, 0, 2, 0, 0, 0, 0, 0]], dtype=int64)"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from sklearn.feature_extraction.text import CountVectorizer\n",
"sc_vectorizer = CountVectorizer()\n",
"corpus = [\n",
" 'I like hot dogs.',\n",
" 'The dog ran fast.',\n",
" 'Its hot outside.',\n",
" ]\n",
"sc_vectorizer.fit_transform(corpus)\n",
"sc_vectorizer.transform(['My dog likes hot dogs on a hot day.']).toarray()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Możemy również użyć wektoryzatora Keras, który zdefiniowaliśmy powyżej, konwertując każdy numer słowa na kodowanie one-hot i sumując wszystkie te wektory.\n"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([0., 5., 0., ..., 0., 0., 0.], dtype=float32)"
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def to_bow(text):\n",
" return tf.reduce_sum(tf.one_hot(vectorizer(text),vocab_size),axis=0)\n",
"\n",
"to_bow('My dog likes hot dogs on a hot day.').numpy()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"> **Uwaga**: Możesz być zaskoczony, że wynik różni się od poprzedniego przykładu. Powodem jest to, że w przykładzie z Keras długość wektora odpowiada rozmiarowi słownika, który został zbudowany na podstawie całego zbioru danych AG News, podczas gdy w przykładzie z Scikit Learn słownik został zbudowany dynamicznie na podstawie próbki tekstu.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Trenowanie klasyfikatora BoW\n",
"\n",
"Teraz, gdy nauczyliśmy się, jak stworzyć reprezentację tekstu w formie bag-of-words, przejdźmy do trenowania klasyfikatora, który ją wykorzystuje. Najpierw musimy przekształcić nasz zbiór danych na reprezentację bag-of-words. Można to zrobić za pomocą funkcji `map` w następujący sposób:\n"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [],
"source": [
"batch_size = 128\n",
"\n",
"ds_train_bow = ds_train.map(lambda x: (to_bow(x['title']+x['description']),x['label'])).batch(batch_size)\n",
"ds_test_bow = ds_test.map(lambda x: (to_bow(x['title']+x['description']),x['label'])).batch(batch_size)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Teraz zdefiniujmy prostą sieć neuronową klasyfikatora, która zawiera jedną warstwę liniową. Rozmiar wejścia to `vocab_size`, a rozmiar wyjścia odpowiada liczbie klas (4). Ponieważ rozwiązujemy zadanie klasyfikacji, końcową funkcją aktywacji jest **softmax**:\n"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"938/938 [==============================] - 66s 70ms/step - loss: 0.6144 - acc: 0.8427 - val_loss: 0.4416 - val_acc: 0.8697\n"
]
},
{
"data": {
"text/plain": [
"<keras.callbacks.History at 0x20c70a947f0>"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"model = keras.models.Sequential([\n",
" keras.layers.Dense(4,activation='softmax',input_shape=(vocab_size,))\n",
"])\n",
"model.compile(loss='sparse_categorical_crossentropy',optimizer='adam',metrics=['acc'])\n",
"model.fit(ds_train_bow,validation_data=ds_test_bow)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Ponieważ mamy 4 klasy, dokładność powyżej 80% jest dobrym wynikiem.\n",
"\n",
"## Trenowanie klasyfikatora jako jednej sieci\n",
"\n",
"Ponieważ wektoryzator jest również warstwą Keras, możemy zdefiniować sieć, która go zawiera, i trenować ją od początku do końca. W ten sposób nie musimy wektoryzować zbioru danych za pomocą `map`, możemy po prostu przekazać oryginalny zbiór danych na wejście sieci.\n",
"\n",
"> **Note**: Nadal musielibyśmy zastosować mapy do naszego zbioru danych, aby przekształcić pola z słowników (takich jak `title`, `description` i `label`) na krotki. Jednak podczas ładowania danych z dysku możemy od razu zbudować zbiór danych o wymaganej strukturze.\n"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Model: \"model\"\n",
"_________________________________________________________________\n",
" Layer (type) Output Shape Param # \n",
"=================================================================\n",
" input_1 (InputLayer) [(None, 1)] 0 \n",
" \n",
" text_vectorization (TextVec (None, None) 0 \n",
" torization) \n",
" \n",
" tf.one_hot (TFOpLambda) (None, None, 5335) 0 \n",
" \n",
" tf.math.reduce_sum (TFOpLam (None, 5335) 0 \n",
" bda) \n",
" \n",
" dense_2 (Dense) (None, 4) 21344 \n",
" \n",
"=================================================================\n",
"Total params: 21,344\n",
"Trainable params: 21,344\n",
"Non-trainable params: 0\n",
"_________________________________________________________________\n",
"938/938 [==============================] - 73s 77ms/step - loss: 0.6057 - acc: 0.8414 - val_loss: 0.4202 - val_acc: 0.8736\n"
]
},
{
"data": {
"text/plain": [
"<keras.callbacks.History at 0x20c721521f0>"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def extract_text(x):\n",
" return x['title']+' '+x['description']\n",
"\n",
"def tupelize(x):\n",
" return (extract_text(x),x['label'])\n",
"\n",
"inp = keras.Input(shape=(1,),dtype=tf.string)\n",
"x = vectorizer(inp)\n",
"x = tf.reduce_sum(tf.one_hot(x,vocab_size),axis=1)\n",
"out = keras.layers.Dense(4,activation='softmax')(x)\n",
"model = keras.models.Model(inp,out)\n",
"model.summary()\n",
"\n",
"model.compile(loss='sparse_categorical_crossentropy',optimizer='adam',metrics=['acc'])\n",
"model.fit(ds_train.map(tupelize).batch(batch_size),validation_data=ds_test.map(tupelize).batch(batch_size))\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Bigramy, trigramy i n-gramy\n",
"\n",
"Jednym z ograniczeń podejścia typu bag-of-words jest fakt, że niektóre słowa są częścią wyrażeń wielowyrazowych. Na przykład słowo „hot dog” ma zupełnie inne znaczenie niż słowa „hot” i „dog” w innych kontekstach. Jeśli zawsze reprezentujemy słowa „hot” i „dog” za pomocą tych samych wektorów, może to wprowadzać zamieszanie w naszym modelu.\n",
"\n",
"Aby rozwiązać ten problem, często stosuje się **reprezentacje n-gramów** w metodach klasyfikacji dokumentów, gdzie częstotliwość każdego słowa, dwuwyrazu lub trójwyrazu jest przydatną cechą do trenowania klasyfikatorów. W reprezentacjach bigramowych, na przykład, dodajemy wszystkie pary słów do słownika, oprócz oryginalnych słów.\n",
"\n",
"Poniżej znajduje się przykład, jak wygenerować reprezentację bag-of-words dla bigramów za pomocą Scikit Learn:\n"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Vocabulary:\n",
" {'i': 7, 'like': 11, 'hot': 4, 'dogs': 2, 'i like': 8, 'like hot': 12, 'hot dogs': 5, 'the': 16, 'dog': 0, 'ran': 14, 'fast': 3, 'the dog': 17, 'dog ran': 1, 'ran fast': 15, 'its': 9, 'outside': 13, 'its hot': 10, 'hot outside': 6}\n"
]
},
{
"data": {
"text/plain": [
"array([[1, 0, 1, 0, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]],\n",
" dtype=int64)"
]
},
"execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"bigram_vectorizer = CountVectorizer(ngram_range=(1, 2), token_pattern=r'\\b\\w+\\b', min_df=1)\n",
"corpus = [\n",
" 'I like hot dogs.',\n",
" 'The dog ran fast.',\n",
" 'Its hot outside.',\n",
" ]\n",
"bigram_vectorizer.fit_transform(corpus)\n",
"print(\"Vocabulary:\\n\",bigram_vectorizer.vocabulary_)\n",
"bigram_vectorizer.transform(['My dog likes hot dogs on a hot day.']).toarray()\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Główną wadą podejścia n-gramowego jest to, że rozmiar słownika zaczyna rosnąć niezwykle szybko. W praktyce musimy połączyć reprezentację n-gramową z techniką redukcji wymiarów, taką jak *embeddings*, którą omówimy w następnej jednostce.\n",
"\n",
"Aby użyć reprezentacji n-gramowej w naszym zbiorze danych **AG News**, musimy przekazać parametr `ngrams` do konstruktora `TextVectorization`. Rozmiar słownika bigramów jest **znacznie większy**, w naszym przypadku wynosi ponad 1,3 miliona tokenów! Dlatego warto ograniczyć liczbę tokenów bigramowych do jakiejś rozsądnej wartości.\n",
"\n",
"Moglibyśmy użyć tego samego kodu co powyżej, aby wytrenować klasyfikator, jednak byłoby to bardzo nieefektywne pod względem pamięci. W następnej jednostce wytrenujemy klasyfikator bigramowy, korzystając z embeddings. W międzyczasie możesz eksperymentować z treningiem klasyfikatora bigramowego w tym notebooku i sprawdzić, czy uda Ci się osiągnąć wyższą dokładność.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Automatyczne obliczanie wektorów BoW\n",
"\n",
"W powyższym przykładzie obliczyliśmy wektory BoW ręcznie, sumując jednorazowe kodowania poszczególnych słów. Jednak najnowsza wersja TensorFlow pozwala na automatyczne obliczanie wektorów BoW poprzez przekazanie parametru `output_mode='count` do konstruktora wektoryzatora. Dzięki temu definiowanie i trenowanie naszego modelu staje się znacznie łatwiejsze:\n"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Training vectorizer\n",
"938/938 [==============================] - 7s 7ms/step - loss: 0.5929 - acc: 0.8486 - val_loss: 0.4168 - val_acc: 0.8772\n"
]
},
{
"data": {
"text/plain": [
"<keras.callbacks.History at 0x20c725217c0>"
]
},
"execution_count": 15,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"model = keras.models.Sequential([\n",
" keras.layers.experimental.preprocessing.TextVectorization(max_tokens=vocab_size,output_mode='count'),\n",
" keras.layers.Dense(4,input_shape=(vocab_size,), activation='softmax')\n",
"])\n",
"print(\"Training vectorizer\")\n",
"model.layers[0].adapt(ds_train.take(500).map(extract_text))\n",
"model.compile(loss='sparse_categorical_crossentropy',optimizer='adam',metrics=['acc'])\n",
"model.fit(ds_train.map(tupelize).batch(batch_size),validation_data=ds_test.map(tupelize).batch(batch_size))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Częstotliwość terminu - odwrotna częstotliwość dokumentu (TF-IDF)\n",
"\n",
"W reprezentacji BoW wystąpienia słów są ważone w ten sam sposób, niezależnie od samego słowa. Jednak oczywiste jest, że częste słowa, takie jak *a* i *w*, są znacznie mniej istotne dla klasyfikacji niż terminy specjalistyczne. W większości zadań NLP niektóre słowa są bardziej istotne niż inne.\n",
"\n",
"**TF-IDF** oznacza **częstotliwość terminu - odwrotna częstotliwość dokumentu**. Jest to wariacja metody bag-of-words, w której zamiast binarnej wartości 0/1 wskazującej na obecność słowa w dokumencie, używana jest wartość zmiennoprzecinkowa, która jest związana z częstotliwością występowania słowa w korpusie.\n",
"\n",
"Bardziej formalnie, waga $w_{ij}$ słowa $i$ w dokumencie $j$ jest zdefiniowana jako:\n",
"$$\n",
"w_{ij} = tf_{ij}\\times\\log({N\\over df_i})\n",
"$$\n",
"gdzie\n",
"* $tf_{ij}$ to liczba wystąpień $i$ w $j$, czyli wartość BoW, którą widzieliśmy wcześniej\n",
"* $N$ to liczba dokumentów w kolekcji\n",
"* $df_i$ to liczba dokumentów zawierających słowo $i$ w całej kolekcji\n",
"\n",
"Wartość TF-IDF $w_{ij}$ rośnie proporcjonalnie do liczby wystąpień słowa w dokumencie i jest korygowana przez liczbę dokumentów w korpusie, które zawierają to słowo, co pomaga uwzględnić fakt, że niektóre słowa pojawiają się częściej niż inne. Na przykład, jeśli słowo pojawia się w *każdym* dokumencie w kolekcji, $df_i=N$, a $w_{ij}=0$, i takie terminy są całkowicie pomijane.\n",
"\n",
"Możesz łatwo stworzyć wektoryzację TF-IDF tekstu za pomocą Scikit Learn:\n"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[0.43381609, 0. , 0.43381609, 0. , 0.65985664,\n",
" 0.43381609, 0. , 0. , 0. , 0. ,\n",
" 0. , 0. , 0. , 0. , 0. ,\n",
" 0. ]])"
]
},
"execution_count": 16,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from sklearn.feature_extraction.text import TfidfVectorizer\n",
"vectorizer = TfidfVectorizer(ngram_range=(1,2))\n",
"vectorizer.fit_transform(corpus)\n",
"vectorizer.transform(['My dog likes hot dogs on a hot day.']).toarray()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"W Keras warstwa `TextVectorization` może automatycznie obliczać częstotliwości TF-IDF, przekazując parametr `output_mode='tf-idf'`. Powtórzmy kod, którego użyliśmy powyżej, aby sprawdzić, czy użycie TF-IDF zwiększa dokładność:\n"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Training vectorizer\n",
"938/938 [==============================] - 12s 12ms/step - loss: 0.4197 - acc: 0.8662 - val_loss: 0.3432 - val_acc: 0.8849\n"
]
},
{
"data": {
"text/plain": [
"<keras.callbacks.History at 0x20c729dfd30>"
]
},
"execution_count": 17,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"model = keras.models.Sequential([\n",
" keras.layers.experimental.preprocessing.TextVectorization(max_tokens=vocab_size,output_mode='tf-idf'),\n",
" keras.layers.Dense(4,input_shape=(vocab_size,), activation='softmax')\n",
"])\n",
"print(\"Training vectorizer\")\n",
"model.layers[0].adapt(ds_train.take(500).map(extract_text))\n",
"model.compile(loss='sparse_categorical_crossentropy',optimizer='adam',metrics=['acc'])\n",
"model.fit(ds_train.map(tupelize).batch(batch_size),validation_data=ds_test.map(tupelize).batch(batch_size))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Podsumowanie\n",
"\n",
"Chociaż reprezentacje TF-IDF przypisują wagi częstotliwościowe różnym słowom, nie są w stanie oddać znaczenia ani kolejności. Jak powiedział słynny językoznawca J. R. Firth w 1935 roku: \"Pełne znaczenie słowa zawsze zależy od kontekstu, a żadna analiza znaczenia oderwana od kontekstu nie może być traktowana poważnie.\" W dalszej części kursu nauczymy się, jak uchwycić informacje kontekstowe z tekstu za pomocą modelowania języka.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n---\n\n**Zastrzeżenie**: \nTen dokument został przetłumaczony za pomocą usługi tłumaczenia AI [Co-op Translator](https://github.com/Azure/co-op-translator). Chociaż staramy się zapewnić dokładność, prosimy mieć na uwadze, że automatyczne tłumaczenia mogą zawierać błędy lub nieścisłości. Oryginalny dokument w jego rodzimym języku powinien być uznawany za wiarygodne źródło. W przypadku informacji krytycznych zaleca się skorzystanie z profesjonalnego tłumaczenia wykonanego przez człowieka. Nie ponosimy odpowiedzialności za jakiekolwiek nieporozumienia lub błędne interpretacje wynikające z użycia tego tłumaczenia.\n"
]
}
],
"metadata": {
"interpreter": {
"hash": "0cb620c6d4b9f7a635928804c26cf22403d89d98d79684e4529119355ee6d5a5"
},
"kernel_info": {
"name": "conda-env-py37_tensorflow-py"
},
"kernelspec": {
"display_name": "py37_tensorflow",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.12"
},
"nteract": {
"version": "nteract-front-end@1.0.0"
},
"coopTranslator": {
"original_hash": "19b43951d55b377a76209c24c1f017e4",
"translation_date": "2025-08-31T14:13:41+00:00",
"source_file": "lessons/5-NLP/13-TextRep/TextRepresentationTF.ipynb",
"language_code": "pl"
}
},
"nbformat": 4,
"nbformat_minor": 4
}