<jupyter_start><jupyter_text><jupyter_code>import tensorflow as tf

tf.__version__
# টেক্সট করপাস ডিফাইন করি । আমাদের এই করপাসে দুইটা বাক্য আছে 
texts = [
    "আমি বাংলায় কথা কই",
    "আমি বাংলার কথা কই"
]
# ডিফল্ট সেটআপ
tokenizer1 = tf.keras.preprocessing.text.Tokenizer(filters=',')

# এই বার আমরা টোকেনাইজার ডিফাইন করার সময় বলে দিচ্ছি `num_wors=3`
# এর ফলে `texts` এ যতগুলোই ওয়ার্ড থাকুক না কেন সে ২ টা 
# (সেটা সেট করে দিব টার থেকে ১ টা কম দিবে) ওয়ার্ড রিটার্ন করবে 
tokenizer2 = tf.keras.preprocessing.text.Tokenizer(filters=',', num_words=3)

tokenizer1.fit_on_texts(texts)
tokenizer2.fit_on_texts(texts)

print("Word to index map of `tokenizer1`:", tokenizer1.word_index)
print("Word to index map of `tokenizer2`:", tokenizer2.word_index)<jupyter_output>Word to index map of `tokenizer1`: {'আমি': 1, 'কথা': 2, 'কই': 3, 'বাংলায়': 4, 'বাংলার': 5}
Word to index map of `tokenizer2`: {'আমি': 1, 'কথা': 2, 'কই': 3, 'বাংলায়': 4, 'বাংলার': 5}<jupyter_text>আমরা দেখে পাচ্ছি দুইটা টোকেনাইজার এর জন্যই `word_index` একই । তার মানে কি আমাদের `num_words=3` কাজ করে নি ? এটা আসলে কাজ করেছে । আমরা যদি `texts_to_sequences` মেথড দেখি তাহলেই বুঝতে পারব ।<jupyter_code># টেক্সট কে সংখ্যায় কনভার্ট করি । টেক্সট কে এইভাবে সংখ্যায় প্রকাশ করার করা কে সিকুয়েন্স বলে 
sequence1 = tokenizer1.texts_to_sequences(texts)
sequence2 = tokenizer2.texts_to_sequences(texts)

print('Using 1st tokenizer:', sequence1)
print('Using 2nd tokenizer:', sequence2)<jupyter_output>Using 1st tokenizer: [[1, 4, 2, 3], [1, 5, 2, 3]]
Using 2nd tokenizer: [[1, 2], [1, 2]]<jupyter_text>আমরা দেখতে পাচ্ছি যে প্রথম টোকেনাইজার সবগুলো নিয়েছে কিন্তু ২য় টোকেনাইজার শুধু ২ টা শব্দ নিয়েছে । এখন প্রশ্ন থাকতে পারে `word_index` জন্য কাজ `num_words=3` করল না কেন ? এটা কাজ করে নি কারণ যখন `fit_on_texts` কল করা হয় তখন টোকেনাইজার `word_index, index_word, word_counts, word_docs` এই ভেরিয়েবলগুলকে আপডেট করবে পুরা টেক্সট ডাটার উপর । `num_words=3` এর প্রভাব পরবে `sequences_to_texts, texts_to_sequences, sequences_to_matrix, texts_to_matrix` এই ধরনের মেথড গুলতে । এখন আমরা বুঝতে পারলাম আমরা চাইলে আমাদের ইচ্ছা মত ওয়ার্ড (`num_words`) সেট করে দিয়ে লোড করতে পারি ।  কিন্তু টোকেনাইজার কিভবে `num_words` এর বেশি ওয়ার্ড কে বাদ দেয় ? আমরা আগের মত একটা উদাহরণ টা আবার দেখি<jupyter_code>texts_small = [
    "আমি বাংলায় কথা কই",
    "আমি বাংলার কথা কই"]

texts_large = [
    "আমি বাংলায় কথা কই",
    "আমি বাংলার কথা কই",
    "আমি বাংলায় ভাসি, বাংলায় হাসি, বাংলায় জেগে রই",
    "আমি বাংলায় ভাসি, বাংলায় হাসি, বাংলায় জেগে রই"]
tokenizer_small = tf.keras.preprocessing.text.Tokenizer(filters=',')
tokenizer_large = tf.keras.preprocessing.text.Tokenizer(filters=',')

tokenizer_small.fit_on_texts(texts_small)
tokenizer_large.fit_on_texts(texts_large)

print("Tokenizer small:", tokenizer_small.word_index)
print("Tokenizer lerge:", tokenizer_large.word_index)<jupyter_output>Tokenizer small: {'আমি': 1, 'কথা': 2, 'কই': 3, 'বাংলায়': 4, 'বাংলার': 5}
Tokenizer lerge: {'বাংলায়': 1, 'আমি': 2, 'কথা': 3, 'কই': 4, 'ভাসি': 5, 'হাসি': 6, 'জেগে': 7, 'রই': 8, 'বাংলার': 9}<jupyter_text>উপরে আমরা দেখতে পাচ্ছি `tokenizer_small` এ `আমি` শব্দ প্রথমে চলে আসছে । `tokenizer_large` এ দেখতে পাচ্ছি `বাংলায়` কথা প্রথমে আসছে এটা এই রকম কেন হওয়ার পেছনে কারণ কি ? টোকেনাইজার যেটা করে সেটা হল পুরা ডাটাসেট এ যে শব্দের frequency বেশি সটা সবার প্রথমে রাখবে ২য় বেশি frequency র শব্দ ২য় পজিশনে রাখবে এবং যেটা frequency সবচেয়ে কম সেটা সেটা সবার শেষে রাখবে । আমরা `word_counts` দেখলেই বুঝতে পারব ।<jupyter_code>print("Tokenizer small:", tokenizer_small.word_counts)
print("Tokenizer large:", tokenizer_large.word_counts)<jupyter_output>Tokenizer small: OrderedDict([('আমি', 2), ('বাংলায়', 1), ('কথা', 2), ('কই', 2), ('বাংলার', 1)])
Tokenizer large: OrderedDict([('আমি', 4), ('বাংলায়', 7), ('কথা', 2), ('কই', 2), ('বাংলার', 1), ('ভাসি', 2), ('হাসি', 2), ('জেগে', 2), ('রই', 2)])<jupyter_text>যখন আমরা `Tokenizer(filters=',', num_words=3)` করি তখন উপরের frequency ধরে টপ ২ টা নিবে ।   OOV টকেন কি ?<jupyter_code>train_texts = ["আমি বাংলায় কথা কই"]
test_texts = ["আমি বাংলায় কথা কই", "আমি বাংলার কথা কই"]
tokenizer = tf.keras.preprocessing.text.Tokenizer(filters=',')
tokenizer.fit_on_texts(train_texts)
# "আমি বাংলার কথা কই" এর জন্য ৪ টা সংখ্যা না এসে ৩ আসবে কারণ 
# `বাংলার` টোকেন আমাদের `tokenizer` আগে দেখে নি । 
# যে সকল টোকেন টোকেনাইজার আগে দেখেনি সেই সকল টকেন কে বলে OOV (Out Of Vocabulary)
tokenizer.texts_to_sequences(test_texts)<jupyter_output><empty_output><jupyter_text>আপনি NLP তে যে মডেলই বানান না কেন, ট্রেনিং করার সময় যে টোকেনাইজার ব্যাবহার করবেন, মডেল টেস্ট করার সময় একই টোকেনাইজার ব্যবহার করতে হবে । এর ফলে এটা হওয়ার সম্ভবনা খুব বেশি যে আপনার টেস্ট ডটাতে oov কিছু টোকেন থাকবে । এই সমস্যা হ্যান্ডলে করার জন্য আমাদের টোকেনাইজার এ নতুন একটা প্যারামিটার এড করব ।<jupyter_code># oov_token="<OOV>" দিয়ে আমরা বলে দিলাম যদি এমন কোন টোকেন/শব্দ আশে 
# সেটা আমাদের টোকেনাইজার দেখে নি তাহলে সে সেই টোকেন কে <OOV> দিয়ে রিপ্লেস করবে 
tokenizer = tf.keras.preprocessing.text.Tokenizer(filters=',', oov_token="<OOV>")
tokenizer.fit_on_texts(train_texts)

# oov আগের সমস্যা শলভ
tokenizer.texts_to_sequences(test_texts)
# আমরা word_index এ দেখতে পাচ্ছি '<OOV>': 1 সেট করেছে 
tokenizer.word_index<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.23981282901150322, 'fraction_numerical': 0.01676740105283681, 'mean_word_length': 5.688396349413298, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '6', 'dir': 'jupyter-structured-clean-dedup', 'id': '287786', 'license': 'Apache-2.0', 'n_tokens_mistral': 3777, 'n_tokens_neox': 4268, 'n_words': 639, 'path': 'nlp/drive_into_tokenizer_part_2.ipynb', 'repo_name': 'menon92/DL-Sneak-Peak', 'size': '5129'}