647 lines
26 KiB
Plaintext
647 lines
26 KiB
Plaintext
{
|
||
"cells": [
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"# Metin Sınıflandırma Görevi\n",
|
||
"\n",
|
||
"Bu modülde, **[AG_NEWS](http://www.di.unipi.it/~gulli/AG_corpus_of_news_articles.html)** veri setine dayalı basit bir metin sınıflandırma göreviyle başlayacağız: haber başlıklarını Dünya, Spor, İş ve Bilim/Teknoloji olmak üzere 4 kategoriden birine sınıflandıracağız.\n",
|
||
"\n",
|
||
"## Veri Seti\n",
|
||
"\n",
|
||
"Veri setini yüklemek için **[TensorFlow Datasets](https://www.tensorflow.org/datasets)** API'sini kullanacağız.\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": [
|
||
"Artık veri kümesinin eğitim ve test bölümlerine sırasıyla `dataset['train']` ve `dataset['test']` kullanarak erişebiliriz:\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": [
|
||
"Haydi veri setimizden ilk 10 yeni başlığı yazdıralım:\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": [
|
||
"## Metin Vektörleştirme\n",
|
||
"\n",
|
||
"Şimdi metni tensörler olarak temsil edilebilecek **sayılar**a dönüştürmemiz gerekiyor. Eğer kelime düzeyinde bir temsil istiyorsak, iki şey yapmamız gerekiyor:\n",
|
||
"\n",
|
||
"* Metni **token**lara ayırmak için bir **tokenizer** kullanmak.\n",
|
||
"* Bu tokenların bir **vocab**ını oluşturmak.\n",
|
||
"\n",
|
||
"### Kelime dağarcığı boyutunu sınırlama\n",
|
||
"\n",
|
||
"AG News veri seti örneğinde, kelime dağarcığı boyutu oldukça büyük, 100 binden fazla kelime içeriyor. Genel olarak konuşursak, metinde nadiren bulunan kelimelere ihtiyacımız yok — sadece birkaç cümlede yer alacaklar ve model bu kelimelerden öğrenemeyecek. Bu nedenle, vektörleştirici yapıcısına bir argüman geçirerek kelime dağarcığı boyutunu daha küçük bir sayıya sınırlamak mantıklı olacaktır:\n",
|
||
"\n",
|
||
"Bu adımların her ikisi de **TextVectorization** katmanı kullanılarak gerçekleştirilebilir. Şimdi vektörleştirici nesnesini oluşturalım ve ardından `adapt` metodunu çağırarak tüm metni gözden geçirip bir kelime dağarcığı oluşturalım:\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": [
|
||
"> **Not** yalnızca tüm veri setinin bir alt kümesini kullanarak bir kelime dağarcığı oluşturduğumuzu unutmayın. Bunu, işlem süresini hızlandırmak ve sizi bekletmemek için yapıyoruz. Ancak, tüm veri setindeki bazı kelimelerin kelime dağarcığına dahil edilmeme ve eğitim sırasında göz ardı edilme riskini alıyoruz. Bu nedenle, `adapt` sırasında tüm kelime dağarcığı boyutunu kullanmak ve tüm veri setinden geçmek nihai doğruluğu artırabilir, ancak bu artış önemli olmayacaktır.\n",
|
||
"\n",
|
||
"Şimdi gerçek kelime dağarcığına erişebiliriz:\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": [
|
||
"Vektörleştiriciyi kullanarak, herhangi bir metni kolayca bir sayı kümesine kodlayabiliriz:\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": [
|
||
"## Bag-of-words metin temsili\n",
|
||
"\n",
|
||
"Kelimeler anlamı temsil ettiği için, bazen bir metnin anlamını cümledeki sıralarına bakmaksızın sadece bireysel kelimelere bakarak anlayabiliriz. Örneğin, haberleri sınıflandırırken, *hava durumu* ve *kar* gibi kelimeler muhtemelen *hava durumu tahmini*ni işaret ederken, *hisse senetleri* ve *dolar* gibi kelimeler *finans haberleri*ne işaret edecektir.\n",
|
||
"\n",
|
||
"**Bag-of-words** (BoW) vektör temsili, anlaması en basit geleneksel vektör temsilidir. Her kelime bir vektör indeksine bağlanır ve bir vektör elemanı, belirli bir belgede her kelimenin kaç kez geçtiğini içerir.\n",
|
||
"\n",
|
||
" \n",
|
||
"\n",
|
||
"> **Not**: BoW'yu, metindeki bireysel kelimeler için tekil olarak birleştirilmiş tüm one-hot-encoded vektörlerin toplamı olarak da düşünebilirsiniz.\n",
|
||
"\n",
|
||
"Aşağıda, Scikit Learn Python kütüphanesini kullanarak bir bag-of-words temsili oluşturmanın bir örneği verilmiştir:\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": [
|
||
"Yukarıda tanımladığımız Keras vektörleştiricisini de kullanabiliriz, her kelime numarasını bir one-hot kodlamasına dönüştürerek ve tüm bu vektörleri toplayarak:\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": [
|
||
"> **Not**: Sonuçların önceki örnekten farklı olmasına şaşırabilirsiniz. Bunun nedeni, Keras örneğinde vektörün uzunluğunun, tüm AG News veri setinden oluşturulan kelime dağarcığı boyutuna karşılık gelmesidir. Ancak Scikit Learn örneğinde kelime dağarcığını örnek metinden anlık olarak oluşturduk.\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## BoW sınıflandırıcısını eğitmek\n",
|
||
"\n",
|
||
"Artık metnimizin kelime torbası (bag-of-words) temsilini nasıl oluşturacağımızı öğrendiğimize göre, bunu kullanan bir sınıflandırıcı eğitelim. Öncelikle, veri setimizi kelime torbası temsiline dönüştürmemiz gerekiyor. Bunu aşağıdaki şekilde `map` fonksiyonunu kullanarak gerçekleştirebiliriz:\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": [
|
||
"Şimdi bir doğrusal katman içeren basit bir sınıflandırıcı sinir ağı tanımlayalım. Girdi boyutu `vocab_size` ve çıktı boyutu sınıf sayısına (4) karşılık gelir. Bir sınıflandırma görevi çözdüğümüz için, son aktivasyon fonksiyonu **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": [
|
||
"Dört sınıfımız olduğu için, %80'in üzerinde bir doğruluk iyi bir sonuçtur.\n",
|
||
"\n",
|
||
"## Bir sınıfı tek bir ağ olarak eğitmek\n",
|
||
"\n",
|
||
"Vektörleştirici aynı zamanda bir Keras katmanı olduğu için, onu içeren bir ağ tanımlayabilir ve uçtan uca eğitebiliriz. Bu şekilde, veri kümesini `map` kullanarak vektörleştirmemize gerek kalmaz, sadece orijinal veri kümesini ağın girişine iletebiliriz.\n",
|
||
"\n",
|
||
"> **Not**: Yine de veri kümesindeki alanları (örneğin `title`, `description` ve `label`) sözlüklerden tuple'lara dönüştürmek için `map` uygulamamız gerekecek. Ancak, verileri diskten yüklerken, ilk etapta gerekli yapıya sahip bir veri kümesi oluşturabiliriz.\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": [
|
||
"## İkili, üçlü ve n-gramlar\n",
|
||
"\n",
|
||
"Bag-of-words yaklaşımının bir sınırlaması, bazı kelimelerin çok kelimeli ifadelerin bir parçası olmasıdır. Örneğin, 'hot dog' kelimesi, diğer bağlamlarda 'hot' ve 'dog' kelimelerinden tamamen farklı bir anlama sahiptir. Eğer 'hot' ve 'dog' kelimelerini her zaman aynı vektörlerle temsil edersek, bu modelimizi yanıltabilir.\n",
|
||
"\n",
|
||
"Bu durumu ele almak için, **n-gram temsilleri** genellikle belge sınıflandırma yöntemlerinde kullanılır. Burada, her bir kelimenin, iki kelimelik veya üç kelimelik ifadelerin sıklığı, sınıflandırıcıları eğitmek için faydalı bir özellik olarak kullanılır. Örneğin, ikili (bigram) temsillerde, orijinal kelimelere ek olarak tüm kelime çiftlerini de kelime dağarcığına ekleriz.\n",
|
||
"\n",
|
||
"Aşağıda, Scikit Learn kullanarak bir ikili bag-of-words temsili oluşturmanın bir örneği verilmiştir:\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": [
|
||
"n-gram yaklaşımının en büyük dezavantajı, kelime dağarcığının boyutunun çok hızlı bir şekilde büyümeye başlamasıdır. Pratikte, n-gram temsilini bir boyut azaltma tekniğiyle, örneğin *gömüler* ile birleştirmemiz gerekir. Bu konuyu bir sonraki birimde ele alacağız.\n",
|
||
"\n",
|
||
"**AG News** veri setimizde bir n-gram temsili kullanmak için, `ngrams` parametresini `TextVectorization` yapıcımıza geçirmemiz gerekiyor. Bir bigram kelime dağarcığının uzunluğu **önemli ölçüde daha büyüktür**, bizim durumumuzda bu sayı 1,3 milyondan fazla token! Bu nedenle, bigram tokenlerini de makul bir sayıyla sınırlamak mantıklıdır.\n",
|
||
"\n",
|
||
"Sınıflandırıcıyı eğitmek için yukarıdaki kodun aynısını kullanabiliriz, ancak bu çok bellek verimsiz olur. Bir sonraki birimde, gömüler kullanarak bigram sınıflandırıcıyı eğiteceğiz. Bu arada, bu not defterinde bigram sınıflandırıcı eğitimiyle deney yapabilir ve daha yüksek bir doğruluk elde edip edemeyeceğinizi görebilirsiniz.\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## BoW Vektörlerini Otomatik Hesaplama\n",
|
||
"\n",
|
||
"Yukarıdaki örnekte, BoW vektörlerini bireysel kelimelerin tekil kodlamalarını toplayarak elle hesapladık. Ancak, TensorFlow'un en son sürümü, vektörleştirici yapıcısına `output_mode='count` parametresini geçirerek BoW vektörlerini otomatik olarak hesaplamamıza olanak tanıyor. Bu, modelimizi tanımlamayı ve eğitmeyi önemli ölçüde kolaylaştırıyor:\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": [
|
||
"## Terim Frekansı - Ters Doküman Frekansı (TF-IDF)\n",
|
||
"\n",
|
||
"BoW (Bag-of-Words) temsilinde, kelime geçişleri, kelimenin kendisinden bağımsız olarak aynı teknikle ağırlıklandırılır. Ancak, *bir* ve *içinde* gibi sık kullanılan kelimelerin sınıflandırma için özel terimlere kıyasla çok daha az önemli olduğu açıktır. Çoğu NLP görevinde bazı kelimeler diğerlerinden daha önemlidir.\n",
|
||
"\n",
|
||
"**TF-IDF**, **terim frekansı - ters doküman frekansı** anlamına gelir. Bu, bag-of-words'un bir varyasyonudur; burada bir kelimenin bir dokümanda görünüp görünmediğini belirten ikili 0/1 değeri yerine, kelimenin korpus içindeki geçiş sıklığıyla ilişkili bir kayan nokta değeri kullanılır.\n",
|
||
"\n",
|
||
"Daha resmi olarak, bir kelimenin $i$ doküman $j$ içindeki ağırlığı $w_{ij}$ şu şekilde tanımlanır:\n",
|
||
"$$\n",
|
||
"w_{ij} = tf_{ij}\\times\\log({N\\over df_i})\n",
|
||
"$$\n",
|
||
"burada\n",
|
||
"* $tf_{ij}$, $i$ kelimesinin $j$ dokümanındaki geçiş sayısıdır, yani daha önce gördüğümüz BoW değeri\n",
|
||
"* $N$, koleksiyondaki doküman sayısıdır\n",
|
||
"* $df_i$, $i$ kelimesini içeren dokümanların tüm koleksiyondaki sayısıdır\n",
|
||
"\n",
|
||
"TF-IDF değeri $w_{ij}$, bir kelimenin bir dokümanda kaç kez geçtiğiyle orantılı olarak artar ve kelimenin korpus içindeki dokümanlarda geçiş sayısıyla dengelenir. Bu, bazı kelimelerin diğerlerinden daha sık geçtiği gerçeğini ayarlamaya yardımcı olur. Örneğin, eğer bir kelime koleksiyondaki *her* dokümanda geçiyorsa, $df_i=N$ olur ve $w_{ij}=0$ olur; bu terimler tamamen göz ardı edilir.\n",
|
||
"\n",
|
||
"Scikit Learn kullanarak metnin TF-IDF vektörleştirmesini kolayca oluşturabilirsiniz:\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": [
|
||
"Keras'ta, `TextVectorization` katmanı, `output_mode='tf-idf'` parametresini geçirerek otomatik olarak TF-IDF frekanslarını hesaplayabilir. TF-IDF kullanmanın doğruluğu artırıp artırmadığını görmek için yukarıda kullandığımız kodu tekrar edelim:\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": [
|
||
"## Sonuç\n",
|
||
"\n",
|
||
"TF-IDF temsilleri farklı kelimelere sıklık ağırlıkları verse de, anlamı veya sıralamayı temsil edemezler. Ünlü dilbilimci J. R. Firth'in 1935'te söylediği gibi, \"Bir kelimenin tam anlamı her zaman bağlamsaldır ve bağlamdan bağımsız bir anlam çalışması ciddiye alınamaz.\" Kursun ilerleyen bölümlerinde dil modelleme kullanarak metinden bağlamsal bilgiyi nasıl yakalayacağımızı öğreneceğiz.\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"\n---\n\n**Feragatname**: \nBu belge, AI çeviri hizmeti [Co-op Translator](https://github.com/Azure/co-op-translator) kullanılarak çevrilmiştir. Doğruluk için çaba göstersek de, otomatik çevirilerin hata veya yanlışlıklar içerebileceğini lütfen unutmayın. Belgenin orijinal dili, yetkili kaynak olarak kabul edilmelidir. Kritik bilgiler için profesyonel insan çevirisi önerilir. Bu çevirinin kullanımından kaynaklanan yanlış anlamalar veya yanlış yorumlamalar için sorumluluk kabul etmiyoruz.\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-28T14:37:30+00:00",
|
||
"source_file": "lessons/5-NLP/13-TextRep/TextRepresentationTF.ipynb",
|
||
"language_code": "tr"
|
||
}
|
||
},
|
||
"nbformat": 4,
|
||
"nbformat_minor": 4
|
||
} |