AI-For-Beginners/translations/ar/lessons/5-NLP/13-TextRep/TextRepresentationTF.ipynb

647 lines
30 KiB
Plaintext

{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# مهمة تصنيف النصوص\n",
"\n",
"في هذه الوحدة، سنبدأ بمهمة بسيطة لتصنيف النصوص باستخدام مجموعة بيانات **[AG_NEWS](http://www.di.unipi.it/~gulli/AG_corpus_of_news_articles.html)**: سنقوم بتصنيف عناوين الأخبار إلى واحدة من 4 فئات: العالم، الرياضة، الأعمال، والعلوم/التكنولوجيا.\n",
"\n",
"## مجموعة البيانات\n",
"\n",
"لتحميل مجموعة البيانات، سنستخدم واجهة برمجة التطبيقات **[TensorFlow Datasets](https://www.tensorflow.org/datasets)**.\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": [
"يمكننا الآن الوصول إلى أجزاء التدريب والاختبار من مجموعة البيانات باستخدام `dataset['train']` و `dataset['test']` على التوالي:\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": [
"دعونا نطبع أول 10 عناوين جديدة من مجموعة البيانات الخاصة بنا:\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": [
"## تحويل النص إلى تمثيل عددي\n",
"\n",
"الآن نحتاج إلى تحويل النص إلى **أرقام** يمكن تمثيلها كـ tensors. إذا أردنا تمثيل النص على مستوى الكلمات، يجب علينا القيام بخطوتين:\n",
"\n",
"* استخدام **tokenizer** لتقسيم النص إلى **رموز**.\n",
"* بناء **قاموس** لهذه الرموز.\n",
"\n",
"### تحديد حجم القاموس\n",
"\n",
"في مثال مجموعة بيانات AG News، حجم القاموس كبير جدًا، حيث يتجاوز 100 ألف كلمة. بشكل عام، لا نحتاج إلى الكلمات التي نادرًا ما تظهر في النص — فقط عدد قليل من الجمل تحتوي عليها، ولن يتعلم النموذج منها. لذلك، من المنطقي تحديد حجم القاموس إلى عدد أصغر عن طريق تمرير وسيط إلى منشئ الـ vectorizer:\n",
"\n",
"يمكن التعامل مع كلا الخطوتين باستخدام طبقة **TextVectorization**. دعونا ننشئ كائن الـ vectorizer، ثم نستدعي طريقة `adapt` لاستعراض جميع النصوص وبناء القاموس:\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": [
"> **ملاحظة** نحن نستخدم فقط جزءًا من مجموعة البيانات الكاملة لبناء المفردات. نقوم بذلك لتسريع وقت التنفيذ وعدم إبقائك منتظرًا. ومع ذلك، نحن نتحمل خطر أن بعض الكلمات من مجموعة البيانات الكاملة لن يتم تضمينها في المفردات، وسيتم تجاهلها أثناء التدريب. لذلك، استخدام حجم المفردات الكامل وتشغيل العملية على مجموعة البيانات بأكملها أثناء `adapt` يجب أن يزيد من الدقة النهائية، ولكن ليس بشكل كبير.\n",
"\n",
"الآن يمكننا الوصول إلى المفردات الفعلية:\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": [
"باستخدام المُتجه، يمكننا بسهولة ترميز أي نص إلى مجموعة من الأرقام:\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": [
"## تمثيل النص باستخدام حقيبة الكلمات\n",
"\n",
"نظرًا لأن الكلمات تمثل المعاني، يمكننا أحيانًا فهم معنى نص معين بمجرد النظر إلى الكلمات الفردية فيه، بغض النظر عن ترتيبها في الجملة. على سبيل المثال، عند تصنيف الأخبار، فإن كلمات مثل *الطقس* و*الثلج* من المحتمل أن تشير إلى *توقعات الطقس*، بينما كلمات مثل *الأسهم* و*الدولار* قد تشير إلى *الأخبار المالية*.\n",
"\n",
"**حقيبة الكلمات** (Bag-of-words أو BoW) هي أبسط طريقة لفهم تمثيل النصوص باستخدام المتجهات التقليدية. يتم ربط كل كلمة بمؤشر في المتجه، ويحتوي عنصر المتجه على عدد مرات ظهور كل كلمة في مستند معين.\n",
"\n",
"![صورة توضح كيفية تمثيل حقيبة الكلمات باستخدام المتجهات في الذاكرة.](../../../../../translated_images/ar/bag-of-words-example.606fc1738f1d7ba9.webp) \n",
"\n",
"> **ملاحظة**: يمكنك أيضًا التفكير في حقيبة الكلمات على أنها مجموع جميع المتجهات المشفرة بطريقة \"واحد-ساخن\" لكل كلمة فردية في النص.\n",
"\n",
"فيما يلي مثال على كيفية إنشاء تمثيل حقيبة الكلمات باستخدام مكتبة Scikit Learn بلغة بايثون:\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": [
"يمكننا أيضًا استخدام مُوجّه Keras الذي قمنا بتعريفه أعلاه، لتحويل كل رقم كلمة إلى ترميز واحد فقط وجمع كل تلك المتجهات معًا:\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": [
"> **ملاحظة**: قد تتفاجأ بأن النتيجة تختلف عن المثال السابق. السبب هو أنه في مثال Keras، يتوافق طول المتجه مع حجم المفردات، التي تم إنشاؤها من مجموعة بيانات AG News بأكملها، بينما في مثال Scikit Learn قمنا ببناء المفردات من النص العينة مباشرة.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## تدريب المصنف BoW\n",
"\n",
"الآن بعد أن تعلمنا كيفية بناء تمثيل حقيبة الكلمات (bag-of-words) لنصوصنا، دعونا ندرب مصنفًا يستخدم هذا التمثيل. أولاً، نحتاج إلى تحويل مجموعة البيانات الخاصة بنا إلى تمثيل حقيبة الكلمات. يمكن تحقيق ذلك باستخدام دالة `map` بالطريقة التالية:\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": [
"الآن دعونا نعرّف شبكة عصبية تصنيفية بسيطة تحتوي على طبقة خطية واحدة. حجم الإدخال هو `vocab_size`، وحجم الإخراج يتوافق مع عدد الفئات (4). نظرًا لأننا نقوم بحل مهمة تصنيف، فإن وظيفة التنشيط النهائية هي **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": [
"نظرًا لأن لدينا 4 فئات، فإن دقة تتجاوز 80% تُعتبر نتيجة جيدة.\n",
"\n",
"## تدريب مصنف كشبكة واحدة\n",
"\n",
"بما أن الـ vectorizer هو أيضًا طبقة من طبقات Keras، يمكننا تعريف شبكة تتضمنه وتدريبها من البداية إلى النهاية. بهذه الطريقة، لسنا بحاجة إلى تحويل مجموعة البيانات باستخدام `map`، بل يمكننا ببساطة تمرير مجموعة البيانات الأصلية إلى مدخلات الشبكة.\n",
"\n",
"> **ملاحظة**: سنظل بحاجة إلى تطبيق عمليات map على مجموعة البيانات لتحويل الحقول من القواميس (مثل `title`، `description` و`label`) إلى أزواج. ومع ذلك، عند تحميل البيانات من القرص، يمكننا إنشاء مجموعة بيانات بالهيكل المطلوب منذ البداية.\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": [
"## ثنائيات الكلمات، ثلاثيات الكلمات و n-grams\n",
"\n",
"أحد قيود نهج حقيبة الكلمات هو أن بعض الكلمات تكون جزءًا من تعبيرات متعددة الكلمات، على سبيل المثال، الكلمة \"hot dog\" لها معنى مختلف تمامًا عن الكلمات \"hot\" و \"dog\" في سياقات أخرى. إذا قمنا بتمثيل الكلمات \"hot\" و \"dog\" دائمًا باستخدام نفس المتجهات، فقد يؤدي ذلك إلى إرباك النموذج الخاص بنا.\n",
"\n",
"لمعالجة هذا الأمر، يتم استخدام **تمثيلات n-gram** غالبًا في طرق تصنيف المستندات، حيث تكون تكرارات كل كلمة، أو ثنائية الكلمات، أو ثلاثية الكلمات ميزة مفيدة لتدريب المصنفات. في تمثيلات ثنائيات الكلمات، على سبيل المثال، سنضيف جميع أزواج الكلمات إلى المفردات، بالإضافة إلى الكلمات الأصلية.\n",
"\n",
"فيما يلي مثال على كيفية إنشاء تمثيل حقيبة كلمات ثنائية باستخدام مكتبة Scikit Learn:\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 هو أن حجم المفردات يبدأ في النمو بسرعة كبيرة جدًا. في الواقع، نحتاج إلى دمج تمثيل n-gram مع تقنية تقليل الأبعاد، مثل *التضمينات* (embeddings)، والتي سنتحدث عنها في الوحدة التالية.\n",
"\n",
"لاستخدام تمثيل n-gram في مجموعة بيانات **AG News**، نحتاج إلى تمرير المعامل `ngrams` إلى منشئ `TextVectorization`. طول مفردات الـ bigram يكون **أكبر بكثير**، وفي حالتنا يتجاوز 1.3 مليون رمز! لذلك، من المنطقي أيضًا تحديد عدد رموز الـ bigram إلى رقم معقول.\n",
"\n",
"يمكننا استخدام نفس الكود أعلاه لتدريب المصنف، ولكن ذلك سيكون غير فعال من حيث استهلاك الذاكرة. في الوحدة التالية، سنقوم بتدريب مصنف bigram باستخدام التضمينات. في هذه الأثناء، يمكنك تجربة تدريب مصنف bigram في هذا الدفتر (notebook) لترى ما إذا كان بإمكانك تحقيق دقة أعلى.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## حساب متجهات BoW تلقائيًا\n",
"\n",
"في المثال أعلاه قمنا بحساب متجهات BoW يدويًا عن طريق جمع الترميزات ذات الواحد (one-hot encodings) للكلمات الفردية. ومع ذلك، فإن الإصدار الأحدث من TensorFlow يتيح لنا حساب متجهات BoW تلقائيًا عن طريق تمرير المعامل `output_mode='count` إلى منشئ الموجه. هذا يجعل تعريف وتدريب النموذج أسهل بشكل كبير:\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": [
"## تكرار المصطلح - تكرار الوثيقة العكسي (TF-IDF)\n",
"\n",
"في تمثيل BoW، يتم وزن ظهور الكلمات باستخدام نفس التقنية بغض النظر عن الكلمة نفسها. ومع ذلك، من الواضح أن الكلمات الشائعة مثل *a* و *in* أقل أهمية بكثير للتصنيف مقارنة بالمصطلحات المتخصصة. في معظم مهام معالجة اللغة الطبيعية، تكون بعض الكلمات أكثر أهمية من غيرها.\n",
"\n",
"**TF-IDF** تعني **تكرار المصطلح - تكرار الوثيقة العكسي**. إنها نسخة معدلة من حقيبة الكلمات، حيث يتم استخدام قيمة عددية عائمة بدلاً من القيمة الثنائية 0/1 التي تشير إلى ظهور كلمة في وثيقة، وهذه القيمة ترتبط بتكرار ظهور الكلمة في المجموعة النصية.\n",
"\n",
"بشكل أكثر رسمية، يتم تعريف الوزن $w_{ij}$ لكلمة $i$ في الوثيقة $j$ على النحو التالي:\n",
"$$\n",
"w_{ij} = tf_{ij}\\times\\log({N\\over df_i})\n",
"$$\n",
"حيث:\n",
"* $tf_{ij}$ هو عدد مرات ظهور $i$ في $j$، أي قيمة BoW التي رأيناها سابقًا\n",
"* $N$ هو عدد الوثائق في المجموعة\n",
"* $df_i$ هو عدد الوثائق التي تحتوي على الكلمة $i$ في المجموعة بأكملها\n",
"\n",
"تزداد قيمة TF-IDF $w_{ij}$ بشكل متناسب مع عدد مرات ظهور الكلمة في الوثيقة ويتم تعديلها بناءً على عدد الوثائق في المجموعة التي تحتوي على الكلمة، مما يساعد على التكيف مع حقيقة أن بعض الكلمات تظهر بشكل أكثر تكرارًا من غيرها. على سبيل المثال، إذا ظهرت الكلمة في *كل* الوثائق في المجموعة، فإن $df_i=N$، و $w_{ij}=0$، وسيتم تجاهل تلك المصطلحات تمامًا.\n",
"\n",
"يمكنك بسهولة إنشاء تمثيل TF-IDF للنص باستخدام مكتبة Scikit Learn:\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": [
"في كيراس، يمكن لطبقة `TextVectorization` حساب ترددات TF-IDF تلقائيًا عن طريق تمرير المعامل `output_mode='tf-idf'`. دعونا نكرر الكود الذي استخدمناه أعلاه لنرى ما إذا كان استخدام TF-IDF يزيد من الدقة:\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": [
"## الخاتمة\n",
"\n",
"على الرغم من أن تمثيلات TF-IDF توفر أوزانًا تعتمد على التكرار للكلمات المختلفة، إلا أنها غير قادرة على تمثيل المعنى أو الترتيب. كما قال اللغوي الشهير ج. ر. فيرث في عام 1935: \"المعنى الكامل للكلمة دائمًا ما يكون سياقيًا، ولا يمكن أخذ أي دراسة للمعنى بعيدًا عن السياق على محمل الجد.\" سنتعلم لاحقًا في الدورة كيفية التقاط المعلومات السياقية من النص باستخدام نمذجة اللغة.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n---\n\n**إخلاء المسؤولية**: \nتم ترجمة هذا المستند باستخدام خدمة الترجمة بالذكاء الاصطناعي [Co-op Translator](https://github.com/Azure/co-op-translator). بينما نسعى لتحقيق الدقة، يرجى العلم أن الترجمات الآلية قد تحتوي على أخطاء أو معلومات غير دقيقة. يجب اعتبار المستند الأصلي بلغته الأصلية المصدر الرسمي. للحصول على معلومات حاسمة، يُوصى بالاستعانة بترجمة بشرية احترافية. نحن غير مسؤولين عن أي سوء فهم أو تفسيرات خاطئة ناتجة عن استخدام هذه الترجمة.\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-28T04:38:20+00:00",
"source_file": "lessons/5-NLP/13-TextRep/TextRepresentationTF.ipynb",
"language_code": "ar"
}
},
"nbformat": 4,
"nbformat_minor": 4
}