تکنیک Bag of Words در پردازش زبان طبیعی | آموزش کامل همراه با پروژه‌ی عملی spam detection


تکنیک Bag of Words (BOW) یکی از مهمترین و پرکاربردترین روش‌ها در استخراج ویژگی‌های متنی در حوزه‌ی پردازش زبان طبیعی (NLP) است. یکی از چالشهای اصلی در داده‌های متنی، تفاوت اندازه‌ی بردار ویژگی بین نمونه ها است که فرآیند آموزش مدل‌های یادگیری ماشین را با چالش روبرو میکند. روش BOW با تبدیل متن به یک بردار ویژگی یکسان و قابل پردازش، این مشکل را برطرف می‌کند و پایه‌ی بسیاری از مدل‌های طبقه ‌بندی متون است. برای مثال در تحلیل احساس افراد از روی کامنتها، یا تشخص موضوع یک متن، یا تشخیص پیامهای هرز میتوان از این تکنیک استفاده کرد. در این پست ابتدا با مفهوم BOW، نحوه‌ی ساخت بردار ویژگی و کاربردهای آن در sentiment analysis و طبقه بندی متون آشنا می‌شوید. سپس یک پروژه‌ی عملی تشخیص پیامکهای Spam رو به صورت گام به گام پیاده سازی خواهیم کرد. در پایان نیز یک تمرین چالشی در زمینه‌ی تحلیل احساسات افراد در مورد فیلمها ارائه شده تا بتوانید مهارتهای خود در پروژه های واقعی NLP محک بزنید.

صورت مسئله و چالش در طبقه بندی کامنت‌ها با  NLP

فرض کنید در یک شرکت تولید کننده محصولات بهداشتی به عنوان مهندس هوش مصنوعی (AI Engineer) مشغول به کار هستید. این شرکت به تازگی یک محصول جدید وارد بازار کرده و برای آن یک کمپین تبلیغاتی در شبکه های اجتماعی راه‌اندازی شده است. کاربران در زیر این پست‌ها کامنت‌های متفاوتی نوشته‌ اند.

حال از شما میخواهند سیستمی طراحی کنید که بتواند این کامنتها را طبقه بندی کند (sentiment analysis). یعنی مدل شما باید تشخیص دهد:

  • احساس کاربر مثبت است؟  (positive)
  • احساس کاربر منفی است؟  (negative)
  • یا اینکه کامنت کاملا نا مرتبط است؟  (irrelevant)

بنابراین سیستم باید کامنت‌ها را دقیقاً در سه گروه دسته‌بندی کند: positive-negative-irrelevant

نمونه کامنت‌ها

  • “I absolutely love this new hand sanitizer! It smells amazing and doesn’t dry out my skin.” (positive)
  • “Does anyone know where I can buy this in Canada?” (irrelevant)
  • “My cousin works at this company!” (irrelevant)
  • “Finally a product that keeps my hands soft even after multiple washes. Totally worth it!” (positive)
  • “The smell is way too strong. It gives me a headache.” (negative)
  • “I don’t see any difference after using it. Total waste of money.” (negative)
  • “The bottle leaks easily, very poor design.” (negative)
  • “This is the best soap I’ve used so far. The scent lasts all day!” (positive)
  • “I tried it last week and my skin feels so fresh and clean. Great job on this one!” (positive)
  • “I saw their commercial during a football game.” (irrelevant)
  • “The packaging looks premium and the quality matches it. I’m definitely buying again.” (positive)
  • “This reminds me of another product I used years ago.” (irrelevant)
  • “This product made my hands really dry after just one use. Not happy.” (negative)
  • “I expected something better for the price. It’s just like any regular soap.” (negative)
  • “It irritated my skin badly. Definitely won’t buy again.” (negative)
  • “I think the brand logo looks really cool.” (irrelevant)

چرا باید کامنت‌ها را به بردار عددی تبدیل کنیم؟

به این کامنت نگاه کنید:

“This is the best soap I’ve used so far. The scent lasts all day!” –> (positive)

این جمله از چندین کلمه تشکیل شده است. اما میدانیم که الگوریتم‌های یادگیری ماشین روی رشته کار نمی‌کنند! آن‌ها فقط اعداد را پردازش میکنند.

پس ما باید این متن را تبدیل کنیم به:

  • یک بردار ویژگی (Feature Vector) شامل مقادیر عددی
  • یا چندین بردار (اگر مدل ما از نوع دنباله‌ای باشد- مثال شبکه های بازگشتی RNNs)

اینجاست که بحث اصلی مطرح می‌شود:

برای هر کلمه در کامنت یک بردار ویژگی بسازیم یا برای کل کامنت  (برای همه کلمات) فقط یک بردار ویژگی؟

پاسخ دقیقاً وابسته است به نوع مدلی که انتخاب می‌کنید:

  1. اگر از مدل‌های کلاسیک استفاده کنیم، مثل MLP, SVM, LDA, Decision Tree, random forest و غیره. در این حالت، هر کامنت فقط باید یک بردار ویژگی داشته باشد. و تمام کامنت‌ها/نمونه ها نیز باید بردار ویژگی ای با طول یکسان داشته باشند.
  2. اگر از شبکه های بازگشتی مثل RNN / LSTM / GRU استفاده کنیم، (که در پست‌های بعدی توضیح داده خواهند شد)، در اینصورت، باید به ازای هر کلمه یک بردار ویژگی بسازیم. یعنی برای هر نمونه/کامنت چندین بردار ویژگی خواهیم داشت و این همان چیزی است که RNNها دوست دارند: داده دنباله‌ای/sequence

 

چالش اصلی در sentiment analysis: ساخت بردار ویژگی با اندازه یکسان

فرض کنید یک lookup table داریم که برای هر کلمه یک مقدار عددی یا یک بردارعددی (مثلا برای هر کلمه یک بردار ویژگی با اندازه 1*100) تعریف شده است.

رویکرد اول: ساخت lookup table و اختصاص یک مقدار برای هر کلمه

اگر بخواهید از ساده ترین روش استفاده کنید، ابتدا یک lookup table یا همان دایره لغات میسازید و برای هر کلمه، یک مقدار عددی اختصاص میدهید، و سپس برای هرکامنت که شامل تعداد کلمه هست همانند زیر بردار ویژگی میسازید.

  1. کلمات موجود در کامنت را پیدا میکنید
  2. مقدار عددی هر کلمه را از جدول ورمیدارید
  3. آنها را کنار هم می چینید و یک بردار ویژگی می سازید

اما مشکل چیه؟ کامنتها طول یکسانی نخواهند داشت!!! چرا که هر کامنت شامل تعداد کلمات متفاوتی است.پس بردار ویژگی آن‌ها نیز طول متفاوت پیدا می‌کنند و  ما عملا نمتیوانیم از مدلهایی مثل MLP  و SVM برای این مسئله استفاده کنیم!

ایده‌ی استفاده از  Padding

از طرفی اگه از Padding برای حل این مسئله استفاده کنیم، یعنی یک اندازه خاص مثلا 50000 در نظر بگیریم، هر کامنتی که بردار ویژگی اش کمتر از 50000 بود، برای جبران اون اندازه کوچک، یک تعدادی صفر به بردار بچسبانیم تا اندازه اش برابر با 50000 شود. و اونهایی که بزرگتر هستند رو کراپ کنیم. یعنی تا 50000 مقدار ورداریم و مابقی رو بریزیم بیرون!!

به عبارت ساده تر میتوان گفت:

  • یک اندازه ثابت (مثلاً 50,000) انتخاب می‌کنیم
  • اگر بردار ویژگی کامنت کوتاه تر بود، چندین صفر اضافه می‌کنیم
  • اگر طولانی تر بود، آن را کراپ میکنیم

اما این راه ‌حل خودش مشکلات جدی دارد!!

  • صفرهای اضافه شده می‌توانند مدل را دچار خطا و سوگیری کنند.
  • کراپ کردن کامنت‌های طولانی ممکن است باعث حذف کلمات مهم و احساسی شود.
  • انتخاب اندازه مناسب دشوار خواهد بود

جدا از sparse شدن بردار ویژگی (اضافه شدن صفرهای زیاد برای کامنتهای کوتاه)، بردار ویژگی بزرگ باعث افزایش تصادعدی تعداد پارامترهای شبکه عصبی و افزایش احتمال overfitting شبکه را به همراه خواهد  داشت.

بنابراین این رویکرد برای MLP  و مدل‌های کلاسیک مناسب نیست.

نتیجه‌گیری این بخش، ما برای استفاده از روشهایی مانند MLP به روشی نیاز داریم که:

  • از یک کامنت با طول متغیر، یک بردار ویژگی با اندازه ثابت بسازد، بدون اینکه اطلاعات مهم از بین برود

و این دقیقاً جایی است که تکنیک Bag of Words (BOW) وارد می‌شود. در بخش بعد، به صورت عملی توضیح خواهیم داد که چگونه BOW این مشکل را حل میکند و چگونه می‌توان از آن برای طبقه بندی احساسات و تشخیص کامنت‌های اسپم استفاده کرد. کد پایتون هم اینجا و هم در گیت هاب بارگزاری میشود.

راه‌حل اصلی: استفاده از تکنیک Bag Of Words (BOW)

پس از بررسی چالشهای طول متغیر کامنت‌ها، به یک راه‌ حل بسیار کاربردی یعنی تکنیک Bag of words میرسیم.

  • این روش با یک ترفند ساده اما هوشمندانه ثابت میکند که بدون حذف هیچ اطلاعاتی از متن میتوان برای تمام کامنت‌ها یک بردار ویژگی با اندازه ثابت ساخت.
  • از طرفی این تکنیک بردار ویژگی با حجمی بسیار کمتر نسبت به رویکردهایی مثل Paddingمیسازد که مناسب برای مدل‌های کلاسیک مثل MLP ،SVM  است
  • از همه مهمتر یک تکنیک قابل درک هست و پیاده سازی بسیار سریع و آسانی دارد.

البته BOW محدودیت‌هایی دارد که بعداً توضیح می‌دهیم و در پست‌های بعدی روشهای پیشرفته‌ تر مثل TF-IDF و Word Embedding و RNNها را معرفی خواهیم کرد.


مراحل اجرای تکنیک Bag of Words (BOW)

گام اول: ساخت vocabulary  یا همان دایره لغت/واژگان

در این مرحله تمام کامنت‌ها بررسی شده و تمام کلمات منحصر به فرد (حداقل یکبار ظاهر شده‌اند) استخراج می‌شوند.

در نهایت یک جدول یا lookup table  خواهیم داشت که هر کلمه در آن همانند تصاویر زیر یک آدرس عددی دارد.

تکنیک bag of words در پردازش زبان طبیعی

اگر فرض کنیم تعداد لغات منحصر به فرد 5000 است، با اضافه کردن کلمه unknown برای کلمات ناشناخته، طول دایره لغات ما 5001  میشود. با این حساب، هر کامنت باید تبدیل شود به یک بردار ویژگی با طول دقیقاً 5001.

گام دوم توکن کردن کامنتها (tokenization)

کامنت زیر را در نظر بگیرید:

“This is the best soap I have used so far. The scent last’s all day!”

پس ازtokenization  و تمیزسازی کامنت به شکل زیر خواهد بود.

Tokens=

[‘this’, ‘is’, ‘the’, ‘best’, ‘soap’, ‘i’, ‘have’, ‘used’, ‘so’, ‘far’, ‘the’, ‘scent’, ‘lasts’, ‘all’, ‘day’ ]

تمام کلمات:

  • کوچک‌ سازی شده‌اند
  • از علائم نگارشی جدا شده‌اند
  • به یک لیست از توکن‌ها تبدیل شده‌اند

گام سوم: ساخت بردار اولیه (تمام صفر)

برای هر کامنت، یک بردار ویژگی تمام صفر به اندازه طول vocabulary ساخته می‌شود.
مثلاً:

تکنیک bag of words در پردازش زبان طبیعی

این بردار قالب اصلی بردار ویژگی است.

گام چهارم: شمارش تکرار کلمات در کامنت

حال تعداد دفعات تکرار هر کلمه (در vocabulary) در کامنت شمارش میشود و در آدرس متناظر در بردار قرار می‌گیرد. قاعدتا هر کامنتی از تعدادی کلمه تشکیل شده است که کنار هم احساس فرد در مورد موضوع مورد نظر رو بیان میکند. از طرفی ما تعدادی کلمه در vocabulary داریم. میایییم میشماریم که هر کدام از کلمات در vocabulary چندین بار در کامنت استفاده شده اند. از طرفی اگر کلمه ای در کامنت باشد که جز لغات vocabulary نیست، اونارو جز unknownها در نظر میگیریم و تعداد اونهارو در آدرس مربوط به unknown درvocabulary قرار میدهیم.

نمونه:

Tokens=

[‘this’, ‘is’, ‘the’, ‘best’, ‘soap’, ‘i’, ‘have’, ‘used’, ‘so’, ‘far’, ‘the’, ‘scent’, ‘lasts’, ‘all’, ‘day’ ]

نتیجه‌ بردار ویژگی:

تکنیک bag of words در پردازش زبان طبیعی

  • best : یکبار
  • soap : یکبار
  • have : یکبار
  • the : دو بار
  • day : یکبار
  • unknown : سه بار. یعنی سه کلمه‌ای که در vocab نیستند.

بردار ویژگی نهایی همانند زیر خواهد بود که همان بردار ویژگی نهایی برای کامنت خواهد بود.

این همان بردار ویژگی نهایی کامنت است.



پروژه عملی: پیاده‌سازی Spam Detection با تکنیک BOW

در این پروژه با داده‌های متنی واقعی، مدل MLP را آموزش می‌دهیم تا پیام‌های spam و ham را تشخیص دهد.

پیاده سازی پروژه عملی spam detection در پایتون

دسترسی به کدهای پروژه به صورت یکجا در GitHub

مرحله 0: وارد کردن کتابخانه های مورد نیاز 

Python

import pandas as pd
from torch import nn,optim
import torch
from sklearn import metrics
from matplotlib import pyplot as plt
from sklearn import preprocessing as prep
from torch.utils.data import TensorDataset,DataLoader,Dataset
import pandas as pd
from sklearn.preprocessing import LabelEncoder
from sklearn.model_selection import train_test_split
import numpy as np
import re

مرحله 1: خواندن داده‌ها در پایتون 

  • بارگذاری فایل CSV
  • جدا کردن متن و لیبل

Python

df = pd.read_csv('spam.csv', encoding='ISO-8859-1')
df=df.drop(['Unnamed: 2', 'Unnamed: 3', 'Unnamed: 4'], axis=1)
df=df.rename(columns={"v1":'label_num',"v2":'text'})
le= LabelEncoder()
df['label_num']= le.fit_transform(df['label_num'])
df.head()

مرحله 2: Tokenize کردن متن‌ها

  • تمیزسازی
  • کوچک‌سازی
  • حذف stopwords (اختیاری)

Python

from
def tokenize(text):
    tokens=[]
    for line in text:
        line_cleaned= re.sub(r'[^A-Za-z0-9]+', ' ', line)
        tokens.append(line_cleaned.lower().split())
return tokens

doc= df['text'].astype(str).tolist()  
doc_tokens= tokenize(doc)
print(doc[1],'\n',doc_tokens[1])
output: 
Ok lar... Joking wif u oni... 
['ok', 'lar', 'joking', 'wif', 'u', 'oni']

مرحله 3: ساخت Vocabulary

  • استخراج تمام کلمات منحصر به فرد
  • اختصاص index به هر کلمه
Python
def create_vocabulary(doc_tokens,vocab_size=5000):
    word_freq = {}
    for tokens in doc_tokens:
        for token in tokens:
            if token in word_freq and token.isalpha():
                word_freq[token] += 1
            else:
                word_freq[token] = 1
    sorted_words = sorted(word_freq.items(), key=lambda x: x[1], reverse=True)
    most_frequent_words = [word for word, freq in sorted_words[:vocab_size]]
    vocab=most_frequent_words
    word2idx= {w: i+1 for i, w in enumerate(vocab)}
    word2idx['<UNK>']=0
    vocab_size+=1</pre >
    return vocab,word2idx,vocab_size</pre >
vocab,word2idx,vocab_size= create_vocabulary(doc_tokens,vocab_size=5000)
print(vocab_size)
output:
5001

مرحله 4: ساخت بردار ویژگی با تکنیک BOW

  • بردار صفر
  • شمارش تکرار
  • ساخت بردار ویژگی برای هر کامنت

Python

def vectorize_bow(tokens, vocab2idx, vocab_size):
    feature= np.zeros((len(tokens), vocab_size), dtype=np.float64)
    for i, token in enumerate(tokens):
        for j, word in enumerate(token):
            if word in vocab2idx:
               feature[i,vocab2idx[word]]+=1
            else:  
               feature[i,vocab2idx['<UNK>']]+=1
return feature

مرحله 5: تقسیم داده به سه بخش آموزش، ارزیابی و تست

Python

Xtrain, Xtest, y_train, y_test = train_test_split(doc_tokens,df["label_num"].values,test_size=0.2,random_state=42)
Xtrain, Xvalid, y_train, y_valid = train_test_split(Xtrain,y_train, test_size=0.15,random_state=42)
print(len(Xtrain), len(Xvalid), len(Xtest))
print(np.unique(y_train, return_counts=True))
output: 
3788 669 1115 (array([0, 1]), array([3274, 514], dtype=int64))

مرحله 6: ساخت Dataset اختصاصی برای لود کردن داده در پایتورچ

  • سه متد جادویی init, len , get_item را تعریف میکنیم.
  • هدف این متد این هست که هربار یک نمونه از داده به همراه لیبل از داده اصلی خوانده شده و سپس به تنسور تبدیل شوند.
  • بعدا این dataset رو به dataloader میدهیم تا یک حلقه دور آن بزند و batching را انجام دهد.

Python

class CustomDataset(Dataset):
     def __init__(self,comments, labels,vocab_size,word2idx):
         self.tokenized_comments=comments
         self.y= labels
         self.vocab_size= vocab_size
         self.word2idx= word2idx
     def __len__(self):
         return len(self.tokenized_comments)
     def __getitem__(self, idx):
         tokens= self.tokenized_comments[idx]
         x= vectorize_bow([tokens], self.word2idx, self.vocab_size)
         y= self.y[idx]
         x= torch.tensor(x, dtype=torch.float32).squeeze(0)
         y= torch.tensor(y, dtype=torch.long)
         return x,y

ds_train= CustomDataset(Xtrain, y_train,vocab_size,word2idx)
ds_valid= CustomDataset(Xvalid, y_valid,vocab_size,word2idx)
ds_test= CustomDataset(Xtest, y_test,vocab_size,word2idx)

مرحله 7: ساخت dataloader برای داده ها 

Python

train_loader = DataLoader(ds_train, batch_size=128, shuffle=True)
valid_loader = DataLoader(ds_valid, batch_size=128, shuffle=False)
test_loader = DataLoader(ds_test, batch_size=128, shuffle=False)

مرحله 8: طراحی شبکه عصبی MLP در PyTorch

  • یک hidden layer کافی است
  • ورودی مدل = طول واژگان

Python

class MLP(nn.Module):
     def __init__(self, input_size, hidden_size, num_classes):
         super(MLP, self).__init__()
         self.fc1 = nn.Linear(input_size, hidden_size)
         self.relu = nn.ReLU()
         self.fc2 = nn.Linear(hidden_size, num_classes)
     def forward(self, x):
         out = self.fc1(x)
         out = self.relu(out)
         out = self.fc2(out)
         return out

مرحله 9: تعریف Loss و Optimizer

  • CrossEntropyLoss
  • Adam optimizer

Python

model = MLP(input_size=vocab_size,hidden_size=32, num_classes=2)
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)

مرحله 10: حلقه آموزش مدل

    • batch training
  • محاسبه accuracy

Python

num_epochs = 10
train_losses = []
valid_losses = []
for epoch in range(num_epochs):
                   model.train()
                   epoch_loss = 0.0
                   num_epochs = 10
                   train_losses = []
                   valid_losses = []
               for epoch in range(num_epochs):
                   model.train()
                   epoch_loss = 0.0
                   correct_train = 0
                   total_train = 0
                   for batch_X, batch_y in train_loader:
                       optimizer.zero_grad()
                       outputs = model(batch_X)
                       loss = criterion(outputs, batch_y)
                       loss.backward()
                       optimizer.step()
                       epoch_loss += loss.item() * batch_X.size(0)
                       _, predicted = torch.max(outputs.data, 1)
                       correct_train += (predicted == batch_y).sum().item()
                       total_train += batch_y.size(0)
                   epoch_loss /= len(train_loader.dataset)
                   train_losses.append(epoch_loss)
                   train_acc = correct_train / total_train
                   # Validation
                   model.eval()
                   valid_loss = 0.0
                   correct_valid = 0
                   total_valid = 0
                   with torch.no_grad():
                       for batch_X, batch_y in valid_loader:
                           outputs = model(batch_X)
                           loss = criterion(outputs, batch_y)
                           valid_loss += loss.item() * batch_X.size(0)
                           _, predicted = torch.max(outputs.data, 1)
                           correct_valid += (predicted == batch_y).sum().item()
                           total_valid += batch_y.size(0)
                   valid_loss /= len(valid_loader.dataset)
                   valid_losses.append(valid_loss)
                   valid_acc = correct_valid / total_valid
                   print(f"Epoch [{epoch+1}/{num_epochs}], "
                         f"Train Loss: {epoch_loss:.4f}, Train Acc: {train_acc:.4f}, "
                         f"Valid Loss: {valid_loss:.4f}, Valid Acc: {valid_acc:.4f}")

مرحله 11: تست مدل آموخته‌شده

 

Python

model.eval()
y_pred=[]
y_true=[]
with torch.no_grad():
    for batch_X, batch_y in test_loader:
        outputs = model(batch_X)
        # outputs_p= torch.softmax(outputs,dim=1)
        _, predicted = torch.max(outputs.data, 1)
        
        y_pred.extend(predicted.numpy())
        y_true.extend(batch_y.numpy())
 
accuracy = metrics.accuracy_score(y_true, y_pred)*100
precision = metrics.precision_score(y_true, y_pred)*100
recall = metrics.recall_score(y_true, y_pred)*100
f1 = metrics.f1_score(y_true, y_pred)*100
print(f'Accuracy: {accuracy:.4f}%')
print(f'Percision: {precision:.4f}%')
print(f'Recall: {recall:.4f}%')
print(f'F1-score: {f1:.4f}%')
cm = metrics.confusion_matrix(y_true, y_pred, normalize='true')
# display normalized confusion matrix with %
disp = metrics.ConfusionMatrixDisplay(confusion_matrix=cm,
                                       display_labels=le.classes_)
# normalized confusion matrix
disp = metrics.ConfusionMatrixDisplay(confusion_matrix=cm,
                                       display_labels=le.classes_)
disp.plot(cmap=plt.cm.Blues, values_format='.2%')
plt.show()

Accuracy: 98.0269% 
Percision: 97.7612% 
Recall: 87.3333% 
F1-score: 92.2535%

دسترسی به کل کد و پروژه به صورت یکجا در GitHub


 پروژه: تحلیل احساسات مخاطبان فیلم (Sentiment Analysis)

در پروژه sentiment analysis ابتدا با روش Bag of words برای هر نمونه از نقدهای فیلم (review ) یک بردار ویژگی بسازید، سپس با استفاده از شبکه عصبی MLP نمونه ها را به دو گروه positive و negative دسته بندی کنید.

لینک داده برای دانلود

پیاده سازی پروژه عملی sentiment analysis در پایتون

تحلیل احساسات در نقدهای فیلمهای IMDb

تحلیل احساسات یک تکنیک پردازش زبان طبیعی هست که برای تعیین لحن احساسات در جملات استفاده می شود. در این پایگاه داده  50000 نقد بر فیلمها قرار داده شده است، که هر کدام لیبل مثبت یا منفی گرفته اند.

  • Size: 50,000 reviews
  • Label Type: Binary (positive = 1, negative = 0)

 



مشکل روش Bag of Words در پردازش زبان طبیعی

با وجود مزایایی که تکنیک BOW دارد، اما محدودیتهای اساسی نیز دارد:

  •  ترتیب کلمات را حذف میکند
  • اندازه بردار ویژگی بسیار بزرگ میشود
  • بردار ویژگی Sparse خواهد شد، در نتیجه رمزگشایی بردارهای برای شبکه های عصبی بسیار سخت خواهد بود.
  • نسبت به کلمات کم‌کاربرد بسیار حساس است
  •  معنی کلمات و ارتباط معنایی دیده نمی‌شود

بعدا سایر رویکردها برای حل این مسئله را بررسی خواهیم کرد.


چرا باید از Bag of Words به سمت RNN رفت؟

چون:

  • ترتیب کلمات مهم است
  • معنا در وابستگی زمانی قرار دارد
  • کلمات هم‌ معنی و هم‌ خانواده باید قابل تشخیص باشند
  • مدل باید مفهوم جمله را بفهمد، نه فقط بشمارد

اینجاست که شبکه‌های عصبی بازگشتی (RNN) راه‌ حل مدرن هستند.
در پست‌های آینده این مباحث را کامل پوشش می‌دهیم.



کاربرد BOW در پردازش تصویر 

Bag of Words فقط مخصوص متن نیست. در پردازش تصویر نیز زمانی که ویژگی‌ها اندازه ثابت ندارند از همین ایده استفاده می‌شود.

تکنیک bag of words لزوما فقط برای مباحث پردازش زبان طبیعی نیست. از این رویکرد در سایر حوزه، زمانی که نمونه های مشاهده، بردار ویژگی یکسانی ندارند، میتوان استفاده کرد.

برای مثال وقتی از روش SIFT در پردازش تصاویر، برای استخراج ویژگی استفاده میشود، به ازای هر تصویر این الگوریتم، بسته به محتوای تصویر، تعداد نقاط کلیدی مختلفی پیدا میکند. هر کدام از نقاط کلیدی یک بردار ویژگی (معمولا 1*128) هستند. حال اگر بخواهیم برای هر تصویر یک بردار ویژگی از روی این نقاط کلیدی بسازیم، به مشکل خواهیم خورد.

برای مثال در یک تصویر 100 نقطه کلیدی ممکن است پیدا شود، که اینها رو بخواهیم کنار هم بگذاریم میشه: 1*12800

و اگر برای یک تصویر دیگه 50 تا نقطه کلیدی پیدا شود، سایز بردار ویژگی نهایی تصویر 6400 خواهد بود.

در چنین مواردی، برای حل مشکل از تکنیک BOW استفاده میکنند تا همه تصاویر بردار ویژگی با سایز یکسانی داشته باشند.

به این طریق که یک سری نقاط کلیدی پایه از روی چندین تصویر آموزشی پیدا میکنند، مثلا 100 تا در نظر میگیریند. سپس با کمک آنها برای هر تصویر یک بردار ویژگی با سایز 1*100 میسازند.

روال هم به این شکل هست که ابتدا با کمک SIFT برای هر تصویر (چه آموزشی و چه تست) نقاط کلیدی پیدا میشود. سپس این نقاط کلیدی با 100 نقطه کلیدی پایه مقایسه میشوند تا متوجه شویم که چندتا از نقاط کلیدی تصویر، شبیه به این 100 نقطه کلیدی هستند. اینطوری یک بردار ویژگی هستوگرام ساخته میشود.

یعنی به عبارتی همانند مسئله LLM، اینجا هم میخواهیم بدانیم که هر تصویر ورودی شامل چه نوع کلمات vocabulary، هست، اما اینجا به جای کلمات، نقاط کلیدی پایه وجود دارد.


دیدگاه ها

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

code