মৌলিক পাঠ্য শ্রেণিবিন্যাস

TensorFlow.org এ দেখুন Google Colab-এ চালান GitHub-এ উৎস দেখুন নোটবুক ডাউনলোড করুন

এই টিউটোরিয়ালটি ডিস্কে সংরক্ষিত প্লেইন টেক্সট ফাইল থেকে শুরু করে পাঠ্য শ্রেণিবিন্যাস প্রদর্শন করে। আপনি একটি আইএমডিবি ডেটাসেটে অনুভূতি বিশ্লেষণ করার জন্য একটি বাইনারি ক্লাসিফায়ারকে প্রশিক্ষণ দেবেন। নোটবুকের শেষে, আপনার জন্য চেষ্টা করার জন্য একটি অনুশীলন রয়েছে, যেখানে আপনি স্ট্যাক ওভারফ্লোতে একটি প্রোগ্রামিং প্রশ্নের জন্য ট্যাগের পূর্বাভাস দেওয়ার জন্য একটি মাল্টি-ক্লাস ক্লাসিফায়ারকে প্রশিক্ষণ দেবেন।

import matplotlib.pyplot as plt
import os
import re
import shutil
import string
import tensorflow as tf

from tensorflow.keras import layers
from tensorflow.keras import losses
print(tf.__version__)
2.8.0-rc1

অনুভূতির বিশ্লেষণ

এই নোটবুকটি পর্যালোচনার পাঠ্যের উপর ভিত্তি করে চলচ্চিত্র পর্যালোচনাগুলিকে ইতিবাচক বা নেতিবাচক হিসাবে শ্রেণীবদ্ধ করার জন্য একটি অনুভূতি বিশ্লেষণ মডেল প্রশিক্ষণ দেয়। এটি বাইনারি —বা দ্বি-শ্রেণী—শ্রেণীবিভাগের একটি উদাহরণ, একটি গুরুত্বপূর্ণ এবং ব্যাপকভাবে প্রযোজ্য ধরনের মেশিন লার্নিং সমস্যা।

আপনি বড় মুভি রিভিউ ডেটাসেট ব্যবহার করবেন যাতে ইন্টারনেট মুভি ডেটাবেস থেকে 50,000 মুভি পর্যালোচনার পাঠ্য থাকে৷ এগুলি প্রশিক্ষণের জন্য 25,000টি পর্যালোচনা এবং পরীক্ষার জন্য 25,000টি পর্যালোচনাতে বিভক্ত। প্রশিক্ষণ এবং পরীক্ষার সেটগুলি ভারসাম্যপূর্ণ , যার অর্থ তাদের সমান সংখ্যক ইতিবাচক এবং নেতিবাচক পর্যালোচনা রয়েছে৷

ডাউনলোড করুন এবং IMDB ডেটাসেট অন্বেষণ করুন

আসুন ডেটাসেট ডাউনলোড করে এক্সট্র্যাক্ট করি, তারপর ডিরেক্টরির কাঠামোটি অন্বেষণ করি।

url = "https://ai.stanford.edu/~amaas/data/sentiment/aclImdb_v1.tar.gz"

dataset = tf.keras.utils.get_file("aclImdb_v1", url,
                                    untar=True, cache_dir='.',
                                    cache_subdir='')

dataset_dir = os.path.join(os.path.dirname(dataset), 'aclImdb')
Downloading data from https://ai.stanford.edu/~amaas/data/sentiment/aclImdb_v1.tar.gz
84131840/84125825 [==============================] - 6s 0us/step
84140032/84125825 [==============================] - 6s 0us/step
os.listdir(dataset_dir)
['test', 'README', 'imdbEr.txt', 'imdb.vocab', 'train']
train_dir = os.path.join(dataset_dir, 'train')
os.listdir(train_dir)
['neg',
 'urls_neg.txt',
 'unsup',
 'unsupBow.feat',
 'urls_unsup.txt',
 'urls_pos.txt',
 'labeledBow.feat',
 'pos']

aclImdb/train/pos এবং aclImdb/train/neg ডিরেক্টরিতে অনেক টেক্সট ফাইল রয়েছে, যার প্রতিটি একটি একক মুভি পর্যালোচনা। আসুন তাদের একটি কটাক্ষপাত করা যাক.

sample_file = os.path.join(train_dir, 'pos/1181_9.txt')
with open(sample_file) as f:
  print(f.read())
Rachel Griffiths writes and directs this award winning short film. A heartwarming story about coping with grief and cherishing the memory of those we've loved and lost. Although, only 15 minutes long, Griffiths manages to capture so much emotion and truth onto film in the short space of time. Bud Tingwell gives a touching performance as Will, a widower struggling to cope with his wife's death. Will is confronted by the harsh reality of loneliness and helplessness as he proceeds to take care of Ruth's pet cow, Tulip. The film displays the grief and responsibility one feels for those they have loved and lost. Good cinematography, great direction, and superbly acted. It will bring tears to all those who have lost a loved one, and survived.

ডেটাসেট লোড করুন

এর পরে, আপনি ডিস্ক থেকে ডেটা লোড করবেন এবং প্রশিক্ষণের জন্য উপযুক্ত একটি বিন্যাসে প্রস্তুত করবেন। এটি করার জন্য, আপনি সহায়ক text_dataset_from_directory ইউটিলিটি ব্যবহার করবেন, যা নিম্নরূপ একটি ডিরেক্টরি কাঠামো আশা করে।

main_directory/
...class_a/
......a_text_1.txt
......a_text_2.txt
...class_b/
......b_text_1.txt
......b_text_2.txt

বাইনারি শ্রেণীবিভাগের জন্য একটি ডেটাসেট প্রস্তুত করতে, আপনার ডিস্কে দুটি ফোল্ডারের প্রয়োজন হবে, class_a এবং class_b সাথে সম্পর্কিত। এগুলি হবে ইতিবাচক এবং নেতিবাচক মুভি রিভিউ, যা aclImdb/train/pos এবং aclImdb/train/neg এ পাওয়া যাবে। যেহেতু IMDB ডেটাসেটে অতিরিক্ত ফোল্ডার রয়েছে, আপনি এই ইউটিলিটি ব্যবহার করার আগে সেগুলি সরিয়ে ফেলবেন।

remove_dir = os.path.join(train_dir, 'unsup')
shutil.rmtree(remove_dir)

এরপর, আপনি লেবেলযুক্ত tf.data.Dataset তৈরি করতে text_dataset_from_directory ইউটিলিটি ব্যবহার করবেন। tf.data হল ডেটা নিয়ে কাজ করার জন্য টুলগুলির একটি শক্তিশালী সংগ্রহ।

একটি মেশিন লার্নিং পরীক্ষা চালানোর সময়, আপনার ডেটাসেটকে তিনটি ভাগে ভাগ করা একটি সর্বোত্তম অনুশীলন: ট্রেন , বৈধতা এবং পরীক্ষা

আইএমডিবি ডেটাসেট ইতিমধ্যেই ট্রেন এবং পরীক্ষায় ভাগ করা হয়েছে, তবে এটির একটি বৈধতা সেটের অভাব রয়েছে। আসুন নীচের validation_split আর্গুমেন্ট ব্যবহার করে প্রশিক্ষণের ডেটার 80:20 স্প্লিট ব্যবহার করে একটি বৈধতা সেট তৈরি করি।

batch_size = 32
seed = 42

raw_train_ds = tf.keras.utils.text_dataset_from_directory(
    'aclImdb/train', 
    batch_size=batch_size, 
    validation_split=0.2, 
    subset='training', 
    seed=seed)
Found 25000 files belonging to 2 classes.
Using 20000 files for training.

আপনি উপরে দেখতে পাচ্ছেন, প্রশিক্ষণ ফোল্ডারে 25,000টি উদাহরণ রয়েছে, যার মধ্যে আপনি প্রশিক্ষণের জন্য 80% (বা 20,000) ব্যবহার করবেন। আপনি কিছুক্ষণের মধ্যে দেখতে পাবেন, আপনি সরাসরি model.fit একটি ডেটাসেট পাস করে একটি মডেলকে প্রশিক্ষণ দিতে পারেন। আপনি যদি tf.data নতুন হয়ে থাকেন, তাহলে আপনি ডেটাসেটের উপরেও পুনরাবৃত্তি করতে পারেন এবং নিম্নরূপ কয়েকটি উদাহরণ প্রিন্ট করতে পারেন।

for text_batch, label_batch in raw_train_ds.take(1):
  for i in range(3):
    print("Review", text_batch.numpy()[i])
    print("Label", label_batch.numpy()[i])
Review b'"Pandemonium" is a horror movie spoof that comes off more stupid than funny. Believe me when I tell you, I love comedies. Especially comedy spoofs. "Airplane", "The Naked Gun" trilogy, "Blazing Saddles", "High Anxiety", and "Spaceballs" are some of my favorite comedies that spoof a particular genre. "Pandemonium" is not up there with those films. Most of the scenes in this movie had me sitting there in stunned silence because the movie wasn\'t all that funny. There are a few laughs in the film, but when you watch a comedy, you expect to laugh a lot more than a few times and that\'s all this film has going for it. Geez, "Scream" had more laughs than this film and that was more of a horror film. How bizarre is that?<br /><br />*1/2 (out of four)'
Label 0
Review b"David Mamet is a very interesting and a very un-equal director. His first movie 'House of Games' was the one I liked best, and it set a series of films with characters whose perspective of life changes as they get into complicated situations, and so does the perspective of the viewer.<br /><br />So is 'Homicide' which from the title tries to set the mind of the viewer to the usual crime drama. The principal characters are two cops, one Jewish and one Irish who deal with a racially charged area. The murder of an old Jewish shop owner who proves to be an ancient veteran of the Israeli Independence war triggers the Jewish identity in the mind and heart of the Jewish detective.<br /><br />This is were the flaws of the film are the more obvious. The process of awakening is theatrical and hard to believe, the group of Jewish militants is operatic, and the way the detective eventually walks to the final violent confrontation is pathetic. The end of the film itself is Mamet-like smart, but disappoints from a human emotional perspective.<br /><br />Joe Mantegna and William Macy give strong performances, but the flaws of the story are too evident to be easily compensated."
Label 0
Review b'Great documentary about the lives of NY firefighters during the worst terrorist attack of all time.. That reason alone is why this should be a must see collectors item.. What shocked me was not only the attacks, but the"High Fat Diet" and physical appearance of some of these firefighters. I think a lot of Doctors would agree with me that,in the physical shape they were in, some of these firefighters would NOT of made it to the 79th floor carrying over 60 lbs of gear. Having said that i now have a greater respect for firefighters and i realize becoming a firefighter is a life altering job. The French have a history of making great documentary\'s and that is what this is, a Great Documentary.....'
Label 1

লক্ষ্য করুন পর্যালোচনাগুলিতে কাঁচা পাঠ রয়েছে (বিরাম চিহ্ন এবং মাঝে মাঝে HTML ট্যাগ সহ যেমন <br/> )। আপনি নিম্নলিখিত বিভাগে এগুলি কীভাবে পরিচালনা করবেন তা দেখাবেন।

লেবেলগুলি হল 0 বা 1৷ এইগুলির মধ্যে কোনটি ইতিবাচক এবং নেতিবাচক মুভি পর্যালোচনাগুলির সাথে মিলে যায় তা দেখতে, আপনি ডেটাসেটে class_names বৈশিষ্ট্যটি পরীক্ষা করতে পারেন৷

print("Label 0 corresponds to", raw_train_ds.class_names[0])
print("Label 1 corresponds to", raw_train_ds.class_names[1])
Label 0 corresponds to neg
Label 1 corresponds to pos

এর পরে, আপনি একটি বৈধতা এবং পরীক্ষা ডেটাসেট তৈরি করবেন। আপনি বৈধতার জন্য প্রশিক্ষণ সেট থেকে অবশিষ্ট 5,000 পর্যালোচনা ব্যবহার করবেন।

raw_val_ds = tf.keras.utils.text_dataset_from_directory(
    'aclImdb/train', 
    batch_size=batch_size, 
    validation_split=0.2, 
    subset='validation', 
    seed=seed)
Found 25000 files belonging to 2 classes.
Using 5000 files for validation.
raw_test_ds = tf.keras.utils.text_dataset_from_directory(
    'aclImdb/test', 
    batch_size=batch_size)
Found 25000 files belonging to 2 classes.

প্রশিক্ষণের জন্য ডেটাসেট প্রস্তুত করুন

এর পরে, আপনি সহায়ক tf.keras.layers.TextVectorization লেয়ার ব্যবহার করে ডেটা মানক, টোকেনাইজ এবং ভেক্টরাইজ করবেন।

স্ট্যান্ডার্ডাইজেশন বলতে টেক্সট প্রিপ্রসেসিং বোঝায়, সাধারণত ডেটাসেট সহজ করার জন্য বিরাম চিহ্ন বা এইচটিএমএল উপাদান অপসারণ করা। টোকেনাইজেশন বলতে বোঝায় স্ট্রিংকে টোকেনে বিভক্ত করা (উদাহরণস্বরূপ, একটি বাক্যকে পৃথক শব্দে বিভক্ত করা, হোয়াইটস্পেসে বিভক্ত করে)। ভেক্টরাইজেশন বলতে টোকেনকে সংখ্যায় রূপান্তর করা বোঝায় যাতে সেগুলিকে একটি নিউরাল নেটওয়ার্কে খাওয়ানো যায়। এই সব কাজ এই স্তর দিয়ে সম্পন্ন করা যেতে পারে.

আপনি উপরে যেমন দেখেছেন, পর্যালোচনাগুলিতে <br /> এর মত বিভিন্ন HTML ট্যাগ রয়েছে। এই ট্যাগগুলি TextVectorization লেয়ারে ডিফল্ট স্ট্যান্ডার্ডাইজার দ্বারা সরানো হবে না (যা পাঠ্যকে ছোট হাতের অক্ষরে রূপান্তরিত করে এবং ডিফল্টরূপে বিরামচিহ্ন স্ট্রিপ করে, কিন্তু HTML ছিনতাই করে না)। আপনি এইচটিএমএল অপসারণের জন্য একটি কাস্টম স্ট্যান্ডার্ডাইজেশন ফাংশন লিখবেন।

def custom_standardization(input_data):
  lowercase = tf.strings.lower(input_data)
  stripped_html = tf.strings.regex_replace(lowercase, '<br />', ' ')
  return tf.strings.regex_replace(stripped_html,
                                  '[%s]' % re.escape(string.punctuation),
                                  '')

এর পরে, আপনি একটি TextVectorization স্তর তৈরি করবেন। আপনি এই স্তরটি ব্যবহার করবেন আমাদের ডেটা মানসম্মত, টোকেনাইজ এবং ভেক্টরাইজ করতে। আপনি প্রতিটি টোকেনের জন্য অনন্য পূর্ণসংখ্যা সূচক তৈরি করতে intoutput_mode সেট করেছেন।

মনে রাখবেন যে আপনি ডিফল্ট বিভক্ত ফাংশন ব্যবহার করছেন, এবং আপনার উপরে সংজ্ঞায়িত কাস্টম স্ট্যান্ডার্ডাইজেশন ফাংশন। আপনি মডেলের জন্য কিছু ধ্রুবকও সংজ্ঞায়িত করবেন, যেমন একটি সুস্পষ্ট সর্বাধিক sequence_length , যা লেয়ারটিকে প্যাড করতে বা সিকোয়েন্সগুলিকে হুবহু sequence_length মানগুলিতে ছেঁটে দেবে৷

max_features = 10000
sequence_length = 250

vectorize_layer = layers.TextVectorization(
    standardize=custom_standardization,
    max_tokens=max_features,
    output_mode='int',
    output_sequence_length=sequence_length)

এর পরে, আপনি ডেটাসেটে প্রিপ্রসেসিং লেয়ারের অবস্থার adapt করতে অ্যাডাপ্ট কল করবেন। এটি মডেলটিকে পূর্ণসংখ্যার স্ট্রিংগুলির একটি সূচক তৈরি করবে।

# Make a text-only dataset (without labels), then call adapt
train_text = raw_train_ds.map(lambda x, y: x)
vectorize_layer.adapt(train_text)

কিছু ডেটা প্রিপ্রসেস করার জন্য এই স্তরটি ব্যবহার করার ফলাফল দেখতে একটি ফাংশন তৈরি করা যাক।

def vectorize_text(text, label):
  text = tf.expand_dims(text, -1)
  return vectorize_layer(text), label
# retrieve a batch (of 32 reviews and labels) from the dataset
text_batch, label_batch = next(iter(raw_train_ds))
first_review, first_label = text_batch[0], label_batch[0]
print("Review", first_review)
print("Label", raw_train_ds.class_names[first_label])
print("Vectorized review", vectorize_text(first_review, first_label))
Review tf.Tensor(b'Great movie - especially the music - Etta James - "At Last". This speaks volumes when you have finally found that special someone.', shape=(), dtype=string)
Label neg
Vectorized review (<tf.Tensor: shape=(1, 250), dtype=int64, numpy=
array([[  86,   17,  260,    2,  222,    1,  571,   31,  229,   11, 2418,
           1,   51,   22,   25,  404,  251,   12,  306,  282,    0,    0,
           0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
           0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
           0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
           0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
           0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
           0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
           0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
           0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
           0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
           0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
           0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
           0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
           0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
           0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
           0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
           0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
           0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
           0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
           0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
           0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
           0,    0,    0,    0,    0,    0,    0,    0]])>, <tf.Tensor: shape=(), dtype=int32, numpy=0>)

আপনি উপরে দেখতে পাচ্ছেন, প্রতিটি টোকেন একটি পূর্ণসংখ্যা দ্বারা প্রতিস্থাপিত হয়েছে। আপনি স্তরে .get_vocabulary() কল করে প্রতিটি পূর্ণসংখ্যার সাথে সঙ্গতিপূর্ণ টোকেন (স্ট্রিং) সন্ধান করতে পারেন।

print("1287 ---> ",vectorize_layer.get_vocabulary()[1287])
print(" 313 ---> ",vectorize_layer.get_vocabulary()[313])
print('Vocabulary size: {}'.format(len(vectorize_layer.get_vocabulary())))
1287 --->  silent
 313 --->  night
Vocabulary size: 10000

আপনি আপনার মডেল প্রশিক্ষণের জন্য প্রায় প্রস্তুত. একটি চূড়ান্ত প্রিপ্রসেসিং ধাপ হিসেবে, আপনি আগে তৈরি করা TextVectorization লেয়ারটি ট্রেন, ভ্যালিডেশন এবং টেস্ট ডেটাসেটে প্রয়োগ করবেন।

train_ds = raw_train_ds.map(vectorize_text)
val_ds = raw_val_ds.map(vectorize_text)
test_ds = raw_test_ds.map(vectorize_text)

কর্মক্ষমতা জন্য ডেটাসেট কনফিগার করুন

I/O যাতে ব্লক হয়ে না যায় তা নিশ্চিত করতে ডেটা লোড করার সময় এই দুটি গুরুত্বপূর্ণ পদ্ধতি ব্যবহার করা উচিত।

.cache() ডিস্ক লোড হওয়ার পরে মেমরিতে ডেটা রাখে। এটি নিশ্চিত করবে যে ডেটাসেটটি আপনার মডেলকে প্রশিক্ষণ দেওয়ার সময় বাধা হয়ে দাঁড়ায় না। যদি আপনার ডেটাসেটটি মেমরিতে মাপসই করার জন্য খুব বড় হয়, তবে আপনি একটি পারফরম্যান্ট অন-ডিস্ক ক্যাশে তৈরি করতে এই পদ্ধতিটি ব্যবহার করতে পারেন, যা অনেকগুলি ছোট ফাইলের চেয়ে পড়ার জন্য আরও দক্ষ।

প্রশিক্ষণের সময় .prefetch() ডেটা প্রিপ্রসেসিং এবং মডেল এক্সিকিউশনকে ওভারল্যাপ করে।

আপনি উভয় পদ্ধতি সম্পর্কে আরও শিখতে পারেন, সেইসাথে ডেটা পারফরম্যান্স গাইডে কীভাবে ডিস্কে ডেটা ক্যাশে করতে হয়।

AUTOTUNE = tf.data.AUTOTUNE

train_ds = train_ds.cache().prefetch(buffer_size=AUTOTUNE)
val_ds = val_ds.cache().prefetch(buffer_size=AUTOTUNE)
test_ds = test_ds.cache().prefetch(buffer_size=AUTOTUNE)

মডেল তৈরি করুন

আপনার নিউরাল নেটওয়ার্ক তৈরি করার সময় এসেছে:

embedding_dim = 16
model = tf.keras.Sequential([
  layers.Embedding(max_features + 1, embedding_dim),
  layers.Dropout(0.2),
  layers.GlobalAveragePooling1D(),
  layers.Dropout(0.2),
  layers.Dense(1)])

model.summary()
Model: "sequential"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 embedding (Embedding)       (None, None, 16)          160016    
                                                                 
 dropout (Dropout)           (None, None, 16)          0         
                                                                 
 global_average_pooling1d (G  (None, 16)               0         
 lobalAveragePooling1D)                                          
                                                                 
 dropout_1 (Dropout)         (None, 16)                0         
                                                                 
 dense (Dense)               (None, 1)                 17        
                                                                 
=================================================================
Total params: 160,033
Trainable params: 160,033
Non-trainable params: 0
_________________________________________________________________

শ্রেণিবিন্যাসকারী তৈরি করতে স্তরগুলি ক্রমানুসারে স্ট্যাক করা হয়:

  1. প্রথম স্তরটি একটি Embedding স্তর। এই স্তরটি পূর্ণসংখ্যা-এনকোড করা পর্যালোচনাগুলি নেয় এবং প্রতিটি শব্দ-সূচকের জন্য একটি এমবেডিং ভেক্টর সন্ধান করে। এই ভেক্টর মডেল ট্রেন হিসাবে শেখা হয়. ভেক্টর আউটপুট অ্যারেতে একটি মাত্রা যোগ করে। ফলস্বরূপ মাত্রাগুলি হল: (batch, sequence, embedding) । এমবেডিং সম্পর্কে আরও জানতে, শব্দ এমবেডিং টিউটোরিয়াল দেখুন।
  2. এর পরে, একটি GlobalAveragePooling1D স্তর প্রতিটি উদাহরণের জন্য ক্রম মাত্রার গড় করে একটি নির্দিষ্ট দৈর্ঘ্যের আউটপুট ভেক্টর প্রদান করে। এটি মডেলটিকে পরিবর্তনশীল দৈর্ঘ্যের ইনপুট পরিচালনা করতে দেয়, সহজতম উপায়ে।
  3. এই স্থির-দৈর্ঘ্যের আউটপুট ভেক্টরটি 16টি লুকানো ইউনিট সহ একটি সম্পূর্ণ-সংযুক্ত ( Dense ) স্তরের মাধ্যমে পাইপ করা হয়।
  4. শেষ স্তরটি একটি একক আউটপুট নোডের সাথে ঘনভাবে সংযুক্ত।

ক্ষতি ফাংশন এবং অপ্টিমাইজার

একটি মডেল একটি ক্ষতি ফাংশন এবং প্রশিক্ষণের জন্য একটি অপ্টিমাইজার প্রয়োজন. যেহেতু এটি একটি বাইনারি শ্রেণিবিন্যাস সমস্যা এবং মডেলটি একটি সম্ভাব্যতা (সিগময়েড অ্যাক্টিভেশন সহ একটি একক-ইউনিট স্তর) আউটপুট করে, আপনি ক্ষতি ব্যবহার করবেন। losses.BinaryCrossentropy লস ফাংশন।

এখন, একটি অপ্টিমাইজার এবং একটি ক্ষতি ফাংশন ব্যবহার করার জন্য মডেলটি কনফিগার করুন:

model.compile(loss=losses.BinaryCrossentropy(from_logits=True),
              optimizer='adam',
              metrics=tf.metrics.BinaryAccuracy(threshold=0.0))

মডেলকে প্রশিক্ষণ দিন

আপনি ফিট পদ্ধতিতে dataset অবজেক্ট পাস করে মডেলটিকে প্রশিক্ষণ দেবেন।

epochs = 10
history = model.fit(
    train_ds,
    validation_data=val_ds,
    epochs=epochs)
Epoch 1/10
625/625 [==============================] - 4s 4ms/step - loss: 0.6644 - binary_accuracy: 0.6894 - val_loss: 0.6159 - val_binary_accuracy: 0.7696
Epoch 2/10
625/625 [==============================] - 2s 4ms/step - loss: 0.5494 - binary_accuracy: 0.8020 - val_loss: 0.4993 - val_binary_accuracy: 0.8226
Epoch 3/10
625/625 [==============================] - 2s 3ms/step - loss: 0.4450 - binary_accuracy: 0.8447 - val_loss: 0.4205 - val_binary_accuracy: 0.8466
Epoch 4/10
625/625 [==============================] - 2s 3ms/step - loss: 0.3778 - binary_accuracy: 0.8659 - val_loss: 0.3740 - val_binary_accuracy: 0.8618
Epoch 5/10
625/625 [==============================] - 2s 3ms/step - loss: 0.3357 - binary_accuracy: 0.8785 - val_loss: 0.3451 - val_binary_accuracy: 0.8678
Epoch 6/10
625/625 [==============================] - 2s 3ms/step - loss: 0.3055 - binary_accuracy: 0.8885 - val_loss: 0.3260 - val_binary_accuracy: 0.8700
Epoch 7/10
625/625 [==============================] - 2s 3ms/step - loss: 0.2817 - binary_accuracy: 0.8971 - val_loss: 0.3126 - val_binary_accuracy: 0.8730
Epoch 8/10
625/625 [==============================] - 2s 4ms/step - loss: 0.2616 - binary_accuracy: 0.9034 - val_loss: 0.3037 - val_binary_accuracy: 0.8754
Epoch 9/10
625/625 [==============================] - 2s 4ms/step - loss: 0.2458 - binary_accuracy: 0.9110 - val_loss: 0.2965 - val_binary_accuracy: 0.8788
Epoch 10/10
625/625 [==============================] - 2s 4ms/step - loss: 0.2319 - binary_accuracy: 0.9158 - val_loss: 0.2920 - val_binary_accuracy: 0.8792

মডেল মূল্যায়ন

আসুন দেখি মডেলটি কেমন করে। দুটি মান ফেরত দেওয়া হবে। ক্ষতি (একটি সংখ্যা যা আমাদের ত্রুটির প্রতিনিধিত্ব করে, নিম্ন মানগুলি ভাল), এবং নির্ভুলতা।

loss, accuracy = model.evaluate(test_ds)

print("Loss: ", loss)
print("Accuracy: ", accuracy)
782/782 [==============================] - 2s 2ms/step - loss: 0.3104 - binary_accuracy: 0.8735
Loss:  0.3104138672351837
Accuracy:  0.873520016670227

এই মোটামুটি নিষ্পাপ পদ্ধতির প্রায় 86% এর নির্ভুলতা অর্জন করে।

সময়ের সাথে সাথে সঠিকতা এবং ক্ষতির একটি প্লট তৈরি করুন

model.fit() একটি History অবজেক্ট ফেরত দেয় যাতে প্রশিক্ষণের সময় যা ঘটেছিল তার সাথে একটি অভিধান রয়েছে:

history_dict = history.history
history_dict.keys()
dict_keys(['loss', 'binary_accuracy', 'val_loss', 'val_binary_accuracy'])

চারটি এন্ট্রি রয়েছে: প্রশিক্ষণ এবং বৈধতার সময় প্রতিটি পর্যবেক্ষণ করা মেট্রিকের জন্য একটি। তুলনা করার জন্য প্রশিক্ষণ এবং বৈধতা হারানোর পাশাপাশি প্রশিক্ষণ এবং বৈধতা নির্ভুলতার জন্য আপনি এগুলি ব্যবহার করতে পারেন:

acc = history_dict['binary_accuracy']
val_acc = history_dict['val_binary_accuracy']
loss = history_dict['loss']
val_loss = history_dict['val_loss']

epochs = range(1, len(acc) + 1)

# "bo" is for "blue dot"
plt.plot(epochs, loss, 'bo', label='Training loss')
# b is for "solid blue line"
plt.plot(epochs, val_loss, 'b', label='Validation loss')
plt.title('Training and validation loss')
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.legend()

plt.show()

png

plt.plot(epochs, acc, 'bo', label='Training acc')
plt.plot(epochs, val_acc, 'b', label='Validation acc')
plt.title('Training and validation accuracy')
plt.xlabel('Epochs')
plt.ylabel('Accuracy')
plt.legend(loc='lower right')

plt.show()

png

এই প্লটে, বিন্দুগুলি প্রশিক্ষণের ক্ষতি এবং নির্ভুলতার প্রতিনিধিত্ব করে এবং কঠিন রেখাগুলি হল বৈধতা ক্ষতি এবং নির্ভুলতা।

লক্ষ্য করুন প্রতিটি যুগের সাথে প্রশিক্ষণের ক্ষতি হ্রাস পায় এবং প্রতিটি যুগের সাথে প্রশিক্ষণের সঠিকতা বৃদ্ধি পায় । গ্রেডিয়েন্ট ডিসেন্ট অপ্টিমাইজেশান ব্যবহার করার সময় এটি প্রত্যাশিত - এটি প্রতিটি পুনরাবৃত্তিতে পছন্দসই পরিমাণ কমিয়ে আনতে হবে।

এটি বৈধতা হারানো এবং নির্ভুলতার ক্ষেত্রে নয়—এগুলি প্রশিক্ষণের নির্ভুলতার আগে শীর্ষ বলে মনে হয়। এটি ওভারফিটিং-এর একটি উদাহরণ: মডেলটি প্রশিক্ষণের ডেটাতে আরও ভাল পারফর্ম করে যা এটি আগে কখনও দেখেনি এমন ডেটার তুলনায়। এই পয়েন্টের পরে, মডেলটি অতিরিক্ত-অপ্টিমাইজ করে এবং প্রশিক্ষণের ডেটার জন্য নির্দিষ্ট উপস্থাপনা শিখে যা ডেটা পরীক্ষা করার জন্য সাধারণীকরণ করে না।

এই বিশেষ ক্ষেত্রে, আপনি শুধুমাত্র প্রশিক্ষণ বন্ধ করে ওভারফিটিং প্রতিরোধ করতে পারেন যখন বৈধতার নির্ভুলতা আর বাড়ছে না। এটি করার একটি উপায় হল tf.keras.callbacks.EarlyStopping কলব্যাক ব্যবহার করা।

মডেল রপ্তানি করুন

উপরের কোডে, আপনি মডেলে টেক্সট খাওয়ানোর আগে ডেটাসেটে TextVectorization লেয়ার প্রয়োগ করেছেন। আপনি যদি আপনার মডেলটিকে কাঁচা স্ট্রিং প্রক্রিয়াকরণের জন্য সক্ষম করতে চান (উদাহরণস্বরূপ, এটি স্থাপন করা সহজ করার জন্য), আপনি আপনার মডেলের ভিতরে TextVectorization স্তর অন্তর্ভুক্ত করতে পারেন। এটি করার জন্য, আপনি এইমাত্র প্রশিক্ষিত ওজন ব্যবহার করে একটি নতুন মডেল তৈরি করতে পারেন।

export_model = tf.keras.Sequential([
  vectorize_layer,
  model,
  layers.Activation('sigmoid')
])

export_model.compile(
    loss=losses.BinaryCrossentropy(from_logits=False), optimizer="adam", metrics=['accuracy']
)

# Test it with `raw_test_ds`, which yields raw strings
loss, accuracy = export_model.evaluate(raw_test_ds)
print(accuracy)
782/782 [==============================] - 3s 4ms/step - loss: 0.3104 - accuracy: 0.8735
0.873520016670227

নতুন তথ্যের উপর অনুমান

নতুন উদাহরণের জন্য ভবিষ্যদ্বাণী পেতে, আপনি কেবল কল করতে পারেন model.predict()

examples = [
  "The movie was great!",
  "The movie was okay.",
  "The movie was terrible..."
]

export_model.predict(examples)
array([[0.60320234],
       [0.4262717 ],
       [0.34439093]], dtype=float32)

আপনার মডেলের ভিতরে টেক্সট প্রিপ্রসেসিং লজিক অন্তর্ভুক্ত করা আপনাকে উত্পাদনের জন্য একটি মডেল রপ্তানি করতে সক্ষম করে যা স্থাপনাকে সহজ করে এবং ট্রেন/পরীক্ষার স্ক্যুর সম্ভাবনা হ্রাস করে।

আপনার TextVectorization স্তরটি কোথায় প্রয়োগ করবেন তা বেছে নেওয়ার সময় মনে রাখতে পারফরম্যান্সের পার্থক্য রয়েছে। আপনার মডেলের বাইরে এটি ব্যবহার করা আপনাকে GPU-তে প্রশিক্ষণের সময় অ্যাসিঙ্ক্রোনাস CPU প্রক্রিয়াকরণ এবং আপনার ডেটার বাফারিং করতে সক্ষম করে। সুতরাং, আপনি যদি আপনার মডেলটিকে GPU-তে প্রশিক্ষণ দিচ্ছেন, আপনি সম্ভবত আপনার মডেলটি তৈরি করার সময় সেরা পারফরম্যান্স পেতে এই বিকল্পটি ব্যবহার করতে চান, তারপর আপনি যখন স্থাপনার জন্য প্রস্তুত হন তখন আপনার মডেলের ভিতরে TextVectorization লেয়ারটি অন্তর্ভুক্ত করতে স্যুইচ করুন। .

মডেল সংরক্ষণ সম্পর্কে আরও জানতে এই টিউটোরিয়াল দেখুন।

অনুশীলন: স্ট্যাক ওভারফ্লো প্রশ্নে বহু-শ্রেণীর শ্রেণীবিভাগ

এই টিউটোরিয়ালটি দেখিয়েছে কিভাবে IMDB ডেটাসেটে স্ক্র্যাচ থেকে একটি বাইনারি ক্লাসিফায়ারকে প্রশিক্ষণ দেওয়া যায়। একটি অনুশীলন হিসাবে, আপনি স্ট্যাক ওভারফ্লোতে একটি প্রোগ্রামিং প্রশ্নের ট্যাগের পূর্বাভাস দেওয়ার জন্য একটি বহু-শ্রেণীর শ্রেণীবদ্ধকারীকে প্রশিক্ষণ দিতে এই নোটবুকটি পরিবর্তন করতে পারেন।

স্ট্যাক ওভারফ্লোতে পোস্ট করা কয়েক হাজার প্রোগ্রামিং প্রশ্নের মূল অংশ (উদাহরণস্বরূপ, "কিভাবে আমি পাইথনে মান অনুসারে একটি অভিধান সাজাতে পারি?") ব্যবহার করার জন্য একটি ডেটাসেট প্রস্তুত করা হয়েছে। এগুলির প্রত্যেকটিকে ঠিক একটি ট্যাগ দিয়ে লেবেল করা হয়েছে (হয় পাইথন, CSharp, JavaScript, বা Java)। আপনার কাজ হল একটি প্রশ্ন ইনপুট হিসাবে নেওয়া এবং উপযুক্ত ট্যাগের পূর্বাভাস দেওয়া, এই ক্ষেত্রে, পাইথন।

আপনি যে ডেটাসেটের সাথে কাজ করবেন তাতে BigQuery- এর অনেক বড় পাবলিক স্ট্যাক ওভারফ্লো ডেটাসেট থেকে বের করা কয়েক হাজার প্রশ্ন রয়েছে, যেটিতে 17 মিলিয়নেরও বেশি পোস্ট রয়েছে।

ডেটাসেট ডাউনলোড করার পরে, আপনি দেখতে পাবেন যে এটিতে আপনি পূর্বে যে আইএমডিবি ডেটাসেটের সাথে কাজ করেছেন তার অনুরূপ ডিরেক্টরি কাঠামো রয়েছে:

train/
...python/
......0.txt
......1.txt
...javascript/
......0.txt
......1.txt
...csharp/
......0.txt
......1.txt
...java/
......0.txt
......1.txt

এই অনুশীলনটি সম্পূর্ণ করতে, আপনাকে নিম্নলিখিত পরিবর্তনগুলি করে স্ট্যাক ওভারফ্লো ডেটাসেটের সাথে কাজ করার জন্য এই নোটবুকটি পরিবর্তন করতে হবে:

  1. আপনার নোটবুকের শীর্ষে, ইতিমধ্যে প্রস্তুত করা স্ট্যাক ওভারফ্লো ডেটাসেট ডাউনলোড করতে কোড সহ IMDB ডেটাসেট ডাউনলোড করে এমন কোড আপডেট করুন৷ যেহেতু স্ট্যাক ওভারফ্লো ডেটাসেটের একটি অনুরূপ ডিরেক্টরি কাঠামো রয়েছে, তাই আপনাকে অনেক পরিবর্তন করতে হবে না।

  2. আপনার মডেলের শেষ স্তরটিকে Dense(4) এ পরিবর্তন করুন, কারণ এখন চারটি আউটপুট ক্লাস রয়েছে।

  3. মডেল কম্পাইল করার সময়, ক্ষতিকে tf.keras.losses.SparseCategoricalCrossentropy এ পরিবর্তন করুন। এটি একটি মাল্টি-ক্লাস শ্রেণীবিভাগ সমস্যার জন্য ব্যবহার করার জন্য সঠিক ক্ষতি ফাংশন, যখন প্রতিটি শ্রেণীর লেবেল পূর্ণসংখ্যা হয় (এই ক্ষেত্রে, তারা 0, 1 , 2 বা 3 হতে পারে)। উপরন্তু, মেট্রিক্সকে metrics=['accuracy'] এ পরিবর্তন করুন, যেহেতু এটি একটি বহু-শ্রেণীর শ্রেণিবিন্যাস সমস্যা ( tf.metrics.BinaryAccuracy শুধুমাত্র বাইনারি শ্রেণীবিভাগের জন্য ব্যবহৃত হয়)।

  4. সময়ের সাথে নির্ভুলতা প্লট করার সময়, যথাক্রমে binary_accuracy এবং val_binary_accuracy যথাক্রমে accuracy এবং val_accuracy এ পরিবর্তন করুন।

  5. একবার এই পরিবর্তনগুলি সম্পূর্ণ হলে, আপনি একটি বহু-শ্রেণীর শ্রেণিবিন্যাসকারীকে প্রশিক্ষণ দিতে সক্ষম হবেন৷

আরো শেখা

এই টিউটোরিয়ালটি স্ক্র্যাচ থেকে পাঠ্য শ্রেণীবিভাগ চালু করেছে। সাধারণভাবে টেক্সট ক্লাসিফিকেশন ওয়ার্কফ্লো সম্পর্কে আরও জানতে, Google Developers থেকে টেক্সট ক্লাসিফিকেশন গাইড দেখুন।

# MIT License
#
# Copyright (c) 2017 François Chollet
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.