AI-For-Beginners/translations/tr/lessons/5-NLP/13-TextRep/TextRepresentationPyTorch.i...

577 lines
22 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Metin Sınıflandırma Görevi\n",
"\n",
"Daha önce belirttiğimiz gibi, **AG_NEWS** veri setine dayalı basit bir metin sınıflandırma görevi üzerinde duracağız. Bu görev, haber başlıklarını Dünya, Spor, İş ve Bilim/Teknoloji olmak üzere 4 kategoriden birine sınıflandırmaktır.\n",
"\n",
"## Veri Seti\n",
"\n",
"Bu veri seti [`torchtext`](https://github.com/pytorch/text) modülüne dahil edilmiştir, bu yüzden kolayca erişebiliriz.\n"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import torch\n",
"import torchtext\n",
"import os\n",
"import collections\n",
"os.makedirs('./data',exist_ok=True)\n",
"train_dataset, test_dataset = torchtext.datasets.AG_NEWS(root='./data')\n",
"classes = ['World', 'Sports', 'Business', 'Sci/Tech']"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Burada, `train_dataset` ve `test_dataset` sırasıyla etiket (sınıf numarası) ve metin çiftlerini döndüren koleksiyonlar içerir, örneğin:\n"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(3,\n",
" \"Wall St. Bears Claw Back Into the Black (Reuters) Reuters - Short-sellers, Wall Street's dwindling\\\\band of ultra-cynics, are seeing green again.\")"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"list(train_dataset)[0]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Öyleyse, veri setimizden ilk 10 yeni başlığı yazdıralım:\n"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"**Sci/Tech** -> Wall St. Bears Claw Back Into the Black (Reuters) Reuters - Short-sellers, Wall Street's dwindling\\band of ultra-cynics, are seeing green again.\n",
"**Sci/Tech** -> Carlyle Looks Toward Commercial Aerospace (Reuters) Reuters - Private investment firm Carlyle Group,\\which has a reputation for making well-timed and occasionally\\controversial plays in the defense industry, has quietly placed\\its bets on another part of the market.\n",
"**Sci/Tech** -> Oil and Economy Cloud Stocks' Outlook (Reuters) Reuters - Soaring crude prices plus worries\\about the economy and the outlook for earnings are expected to\\hang over the stock market next week during the depth of the\\summer doldrums.\n",
"**Sci/Tech** -> Iraq Halts Oil Exports from Main Southern Pipeline (Reuters) Reuters - Authorities have halted oil export\\flows from the main pipeline in southern Iraq after\\intelligence showed a rebel militia could strike\\infrastructure, an oil official said on Saturday.\n",
"**Sci/Tech** -> Oil prices soar to all-time record, posing new menace to US economy (AFP) AFP - Tearaway world oil prices, toppling records and straining wallets, present a new economic menace barely three months before the US presidential elections.\n"
]
}
],
"source": [
"for i,x in zip(range(5),train_dataset):\n",
" print(f\"**{classes[x[0]]}** -> {x[1]}\")\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Veri kümeleri yineleyici olduğundan, verileri birden fazla kez kullanmak istiyorsak listeye dönüştürmemiz gerekir:\n"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"train_dataset, test_dataset = torchtext.datasets.AG_NEWS(root='./data')\n",
"train_dataset = list(train_dataset)\n",
"test_dataset = list(test_dataset)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Tokenizasyon\n",
"\n",
"Şimdi metni tensörler olarak temsil edilebilecek **sayılara** dönüştürmemiz gerekiyor. Eğer kelime düzeyinde bir temsil istiyorsak, iki şey yapmamız gerekiyor:\n",
"* Metni **tokenizer** kullanarak **tokenlere** ayırmak \n",
"* Bu tokenlerin bir **vokabülerini** oluşturmak.\n"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"['he', 'said', 'hello']"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"tokenizer = torchtext.data.utils.get_tokenizer('basic_english')\n",
"tokenizer('He said: hello')"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"counter = collections.Counter()\n",
"for (label, line) in train_dataset:\n",
" counter.update(tokenizer(line))\n",
"vocab = torchtext.vocab.vocab(counter, min_freq=1)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Kelime dağarcığını kullanarak, tokenleştirilmiş dizimizi kolayca bir sayı kümesine kodlayabiliriz:\n"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Vocab size if 95810\n"
]
},
{
"data": {
"text/plain": [
"[599, 3279, 97, 1220, 329, 225, 7368]"
]
},
"execution_count": 19,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"vocab_size = len(vocab)\n",
"print(f\"Vocab size if {vocab_size}\")\n",
"\n",
"stoi = vocab.get_stoi() # dict to convert tokens to indices\n",
"\n",
"def encode(x):\n",
" return [stoi[s] for s in tokenizer(x)]\n",
"\n",
"encode('I love to play with my words')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Kelime Torbası (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*, *kar* gibi kelimeler muhtemelen *hava durumu tahmini*ni işaret ederken, *hisse senetleri*, *dolar* gibi kelimeler *finans haberleri*ne işaret edebilir.\n",
"\n",
"**Kelime Torbası** (BoW) vektör temsili, en yaygın kullanılan geleneksel vektör temsilidir. Her kelime bir vektör indeksine bağlanır ve vektör elemanı, bir belgedeki bir kelimenin kaç kez geçtiğini içerir.\n",
"\n",
"![Kelime torbası vektör temsilinin bellekte nasıl temsil edildiğini gösteren bir görsel.](../../../../../translated_images/bag-of-words-example.606fc1738f1d7ba98a9d693e3bcd706c6e83fa7bf8221e6e90d1a206d82f2ea4.tr.png) \n",
"\n",
"> **Not**: BoW'yu, metindeki bireysel kelimeler için tekil olarak bir-hot kodlanmış vektörlerin toplamı olarak da düşünebilirsiniz.\n",
"\n",
"Aşağıda, Scikit Learn Python kütüphanesi kullanılarak bir kelime torbası temsili oluşturmanın bir örneği verilmiştir:\n"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[1, 1, 0, 2, 0, 0, 0, 0, 0]], dtype=int64)"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from sklearn.feature_extraction.text import CountVectorizer\n",
"vectorizer = CountVectorizer()\n",
"corpus = [\n",
" 'I like hot dogs.',\n",
" 'The dog ran fast.',\n",
" 'Its hot outside.',\n",
" ]\n",
"vectorizer.fit_transform(corpus)\n",
"vectorizer.transform(['My dog likes hot dogs on a hot day.']).toarray()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"AG_NEWS veri setimizin vektör temsilinden bag-of-words vektörünü hesaplamak için aşağıdaki fonksiyonu kullanabiliriz:\n"
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"tensor([2., 1., 2., ..., 0., 0., 0.])\n"
]
}
],
"source": [
"vocab_size = len(vocab)\n",
"\n",
"def to_bow(text,bow_vocab_size=vocab_size):\n",
" res = torch.zeros(bow_vocab_size,dtype=torch.float32)\n",
" for i in encode(text):\n",
" if i<bow_vocab_size:\n",
" res[i] += 1\n",
" return res\n",
"\n",
"print(to_bow(train_dataset[0][1]))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"> **Not:** Burada varsayılan kelime dağarcığı boyutunu belirtmek için global `vocab_size` değişkenini kullanıyoruz. Kelime dağarcığı boyutu genellikle oldukça büyük olduğundan, kelime dağarcığı boyutunu en sık kullanılan kelimelerle sınırlayabiliriz. `vocab_size` değerini düşürmeyi deneyin ve aşağıdaki kodu çalıştırarak bunun doğruluğu nasıl etkilediğini görün. Daha yüksek performans karşılığında doğrulukta bir düşüş beklemelisiniz, ancak dramatik bir düşüş olmamalı.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## BoW sınıflandırıcısını eğitme\n",
"\n",
"Artık metnimizin Bag-of-Words (BoW) temsilini nasıl oluşturacağımızı öğrendiğimize göre, bunun üzerine bir sınıflandırıcı eğitelim. Öncelikle, veri setimizi eğitime uygun bir şekilde dönüştürmemiz gerekiyor; böylece tüm konumsal vektör temsilleri Bag-of-Words temsiline dönüştürülmüş olacak. Bu, standart torch `DataLoader`'a `collate_fn` parametresi olarak `bowify` fonksiyonunu geçirerek gerçekleştirilebilir:\n"
]
},
{
"cell_type": "code",
"execution_count": 21,
"metadata": {},
"outputs": [],
"source": [
"from torch.utils.data import DataLoader\n",
"import numpy as np \n",
"\n",
"# this collate function gets list of batch_size tuples, and needs to \n",
"# return a pair of label-feature tensors for the whole minibatch\n",
"def bowify(b):\n",
" return (\n",
" torch.LongTensor([t[0]-1 for t in b]),\n",
" torch.stack([to_bow(t[1]) for t in b])\n",
" )\n",
"\n",
"train_loader = DataLoader(train_dataset, batch_size=16, collate_fn=bowify, shuffle=True)\n",
"test_loader = DataLoader(test_dataset, batch_size=16, collate_fn=bowify, shuffle=True)"
]
},
{
"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 vektörünün boyutu `vocab_size`'a eşittir ve çıktı boyutu sınıf sayısına (4) karşılık gelir. Sınıflandırma görevini çözdüğümüz için, son aktivasyon fonksiyonu `LogSoftmax()`dır.\n"
]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {},
"outputs": [],
"source": [
"net = torch.nn.Sequential(torch.nn.Linear(vocab_size,4),torch.nn.LogSoftmax(dim=1))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Şimdi standart PyTorch eğitim döngüsünü tanımlayacağız. Veri setimiz oldukça büyük olduğu için, eğitim amacıyla yalnızca bir epoch boyunca eğitim yapacağız ve bazen bir epoch'tan daha az süreyle eğitim yapacağız (`epoch_size` parametresini belirlemek, eğitimi sınırlamamıza olanak tanır). Ayrıca, eğitim sırasında biriken eğitim doğruluğunu raporlayacağız; raporlama sıklığı `report_freq` parametresi kullanılarak belirlenir.\n"
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {},
"outputs": [],
"source": [
"def train_epoch(net,dataloader,lr=0.01,optimizer=None,loss_fn = torch.nn.NLLLoss(),epoch_size=None, report_freq=200):\n",
" optimizer = optimizer or torch.optim.Adam(net.parameters(),lr=lr)\n",
" net.train()\n",
" total_loss,acc,count,i = 0,0,0,0\n",
" for labels,features in dataloader:\n",
" optimizer.zero_grad()\n",
" out = net(features)\n",
" loss = loss_fn(out,labels) #cross_entropy(out,labels)\n",
" loss.backward()\n",
" optimizer.step()\n",
" total_loss+=loss\n",
" _,predicted = torch.max(out,1)\n",
" acc+=(predicted==labels).sum()\n",
" count+=len(labels)\n",
" i+=1\n",
" if i%report_freq==0:\n",
" print(f\"{count}: acc={acc.item()/count}\")\n",
" if epoch_size and count>epoch_size:\n",
" break\n",
" return total_loss.item()/count, acc.item()/count"
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"3200: acc=0.8028125\n",
"6400: acc=0.8371875\n",
"9600: acc=0.8534375\n",
"12800: acc=0.85765625\n"
]
},
{
"data": {
"text/plain": [
"(0.026090790722161722, 0.8620069296375267)"
]
},
"execution_count": 25,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"train_epoch(net,train_loader,epoch_size=15000)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## BiGrams, TriGrams ve N-Grams\n",
"\n",
"Bir 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",
"Bunu 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 özelliktir. Örneğin, bigram temsilde, orijinal kelimelere ek olarak tüm kelime çiftlerini de kelime dağarcığına ekleyeceğiz.\n",
"\n",
"Aşağıda, Scikit Learn kullanarak bir bigram bag of words temsili oluşturmanın bir örneği verilmiştir:\n"
]
},
{
"cell_type": "code",
"execution_count": 26,
"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": 26,
"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 çok hızlı bir şekilde büyümeye başlamasıdır. Pratikte, N-gram temsilini *gömüler* gibi bazı boyut indirgeme teknikleriyle birleştirmemiz gerekir; bu konuyu bir sonraki bölümde ele alacağız.\n",
"\n",
"**AG News** veri setimizde N-gram temsilini kullanmak için özel bir ngram kelime dağarcığı oluşturmamız gerekiyor:\n"
]
},
{
"cell_type": "code",
"execution_count": 27,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Bigram vocabulary length = 1308842\n"
]
}
],
"source": [
"counter = collections.Counter()\n",
"for (label, line) in train_dataset:\n",
" l = tokenizer(line)\n",
" counter.update(torchtext.data.utils.ngrams_iterator(l,ngrams=2))\n",
" \n",
"bi_vocab = torchtext.vocab.vocab(counter, min_freq=1)\n",
"\n",
"print(\"Bigram vocabulary length = \",len(bi_vocab))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Aynı kodu yukarıda olduğu gibi sınıflandırıcıyı eğitmek için kullanabilirdik, ancak bu çok bellek verimsiz olurdu. Bir sonraki bölümde, gömme yöntemlerini kullanarak bigram sınıflandırıcıyı eğiteceğiz.\n",
"\n",
"> **Not:** Metinde belirtilen sayının üzerinde geçen ngram'ları bırakabilirsiniz. Bu, nadir bigramların göz ardı edilmesini sağlayacak ve boyutluluğu önemli ölçüde azaltacaktır. Bunu yapmak için `min_freq` parametresini daha yüksek bir değere ayarlayın ve kelime dağarcığının uzunluğundaki değişimi gözlemleyin.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Terim Frekansı Ters Doküman Frekansı (TF-IDF)\n",
"\n",
"BoW (Bag of Words) temsili, kelime oluşumlarını kelimenin kendisinden bağımsız olarak eşit şekilde ağırlıklandırır. Ancak, *bir*, *içinde* gibi sık kullanılan kelimelerin, özel terimlere kıyasla sınıflandırma için çok daha az önemli olduğu açıktır. Aslında, ç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 yönteminin bir varyasyonudur. Burada, bir kelimenin bir dokümanda bulunup bulunmadığını gösteren ikili 0/1 değeri yerine, kelimenin korpustaki oluşum sıklığıyla ilişkili bir kayan nokta değeri kullanılır.\n",
"\n",
"Daha resmi bir şekilde, bir kelimenin $i$ doküman $j$'deki 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ında kaç kez geçtiğini, yani daha önce gördüğümüz BoW değerini ifade eder\n",
"* $N$, koleksiyondaki doküman sayısını ifade eder\n",
"* $df_i$, $i$ kelimesini içeren dokümanların tüm koleksiyondaki sayısını ifade eder\n",
"\n",
"TF-IDF değeri $w_{ij}$, bir kelimenin bir dokümanda kaç kez geçtiğiyle orantılı olarak artar ve kelimenin korpustaki dokümanlarda bulunma sayısına göre dengelenir. Bu, bazı kelimelerin diğerlerinden daha sık görünmesi gerçeğini ayarlamaya yardımcı olur. Örneğin, 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": 28,
"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": 28,
"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": [
"## Sonuç\n",
"\n",
"Ancak, TF-IDF temsilleri farklı kelimelere sıklık ağırlığı 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ık 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": "16af2a8bbb083ea23e5e41c7f5787656b2ce26968575d8763f2c4b17f9cd711f"
},
"kernelspec": {
"display_name": "Python 3.8.12 ('py38')",
"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"
},
"coopTranslator": {
"original_hash": "7b9040985e748e4e2d4c689892456ad7",
"translation_date": "2025-08-28T14:34:28+00:00",
"source_file": "lessons/5-NLP/13-TextRep/TextRepresentationPyTorch.ipynb",
"language_code": "tr"
}
},
"nbformat": 4,
"nbformat_minor": 2
}