LSTM على مجموعة بيانات 20 Newsgroups باستخدام Keras
يوضّح هذا الدفتر (Notebook) كيفية بناء نموذج LSTM قياسي ونموذج LSTM ثنائي الاتجاه (Bidirectional) ومقارنتهما باستخدام مجموعة بيانات 20 Newsgroups. نستخدم 10 فئات وننفّذ تصنيفًا متعدد الفئات (Multi-Class Classification).
مجموعة بيانات 20 Newsgroups هي مسألة تصنيف معروفة جيدًا. الهدف هو تصنيف أي مجموعة إخبارية (Newsgroup) جاءت منها منشورة معيّنة. المجموعات العشرون المحتملة هي:
comp.graphics comp.os.ms-windows.misc comp.sys.ibm.pc.hardware comp.sys.mac.hardware comp.windows.x rec.autos rec.motorcycles rec.sport.baseball rec.sport.hockey sci.crypt sci.electronics sci.med sci.space misc.forsale talk.politics.misc talk.politics.guns talk.politics.mideast talk.religion.misc alt.atheism soc.religion.christian
هنا نختار 10 فئات للعمل عليها.
from sklearn.datasets import fetch_20newsgroups
from tensorflow.keras.preprocessing.text import Tokenizer
from tensorflow.keras.preprocessing.sequence import pad_sequences
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Embedding, LSTM, Dense, Bidirectional
import numpy as np
from sklearn.preprocessing import LabelBinarizer# Load dataset
categories = [
'sci.space', 'comp.graphics', 'rec.sport.baseball', 'talk.politics.misc',
'sci.electronics', 'soc.religion.christian', 'rec.autos',
'talk.politics.mideast', 'comp.sys.mac.hardware', 'misc.forsale'
]
newsgroups = fetch_20newsgroups(subset='train', categories=categories)
texts = newsgroups.data
labels = newsgroups.target
len(texts)5750# ✅ Display a sample
print("Sample text:")
print(texts[1][:1000])
print("\nLabel:", labels[1])
print("Actual Category:", newsgroups.target_names[labels[1]])Sample text:
From: [email protected] (Wolfgang Pest)
Subject: Speedstar 24 - how to program the TrueColor mode ?
Distribution: world
Organization: Kontron Elektronik GmbH Eching, Germany
Lines: 17
Hello,
I purchased my new 486 with a NoName graphics card installed which is obviously
Speedstar 24 compatible. Its name is "VGA 4000 TrueColor".
It is accompanied with some drivers and the utilities VMODE, XMODE and
at least one more MODE, as well as some drivers for Lotus, Windows, etc.
Only one of the drivers is told to provide the TrueColor mode, namely
the Windows 3.1 driver.
Nowhere else, except in the ad, is any pointer to the TrueColor mode.
Some articles in this group about the Speedstar 24 and some other facts
made me believe that my card is compatible to that one.
Does anybody out there know how this mode can be adjusted? How can I write
a driver which allows me to have 16.7 millions of colors with a resolution
of 640 x 480 with 45 Hz interlaced ?
Greetings,
Wolfgang
Label: 0
Actual Category: comp.graphicsfor i, name in enumerate(newsgroups.target_names):
print(f"Label {i}: {name}")Label 0: comp.graphics
Label 1: comp.sys.mac.hardware
Label 2: misc.forsale
Label 3: rec.autos
Label 4: rec.sport.baseball
Label 5: sci.electronics
Label 6: sci.space
Label 7: soc.religion.christian
Label 8: talk.politics.mideast
Label 9: talk.politics.misc🔹 شرح Tokenizer
يُستخدَم الـTokenizer لتحويل مجموعة نصوص (Corpus) إلى متجهات (Vectorize) عن طريق:
- إنشاء فهرس للكلمات (Word Index) (ربط الكلمات بأعداد صحيحة)
- تحويل كل مستند إلى قائمة من فهارس الكلمات
Tokenizer: يحوّل الكلمات إلى أعداد صحيحة (مثلًا "space" ← 345).
يقصر الـTokenizer استخدامه على أعلى vocab_size كلمة فقط (مثلًا 10,000 كلمة). يُتجاهَل أي كلمة خارج أعلى 10,000 كلمة الأكثر تكرارًا أثناء تحويل النص إلى تسلسل (Sequence).
fit_on_texts: يبني قاموس الكلمات.
texts_to_sequences: يحوّل كل نص إلى قائمة من الأرقام.
pad_sequences: يبطّن (Pads) جميع التسلسلات لتصبح بنفس الطول (200 كلمة).
# Tokenization
vocab_size = 10000
maxlen = 200
tokenizer = Tokenizer(num_words=vocab_size)
# Learns the word -> number mapping
tokenizer.fit_on_texts(texts)
# Converts each article into a sequence of word indices
sequences = tokenizer.texts_to_sequences(texts)
padded_sequences = pad_sequences(sequences, maxlen=maxlen, padding='post')
# Encode labels to one-hot
encoder = LabelBinarizer()
one_hot_labels = encoder.fit_transform(labels)# ✅ Display a sample
print("Sample text:")
print(padded_sequences[500])
print("\nLabel:", labels[500])Sample text:
[ 13 4108 1631 14 1822 8471 28 209 10 411 1317 31 548 487
3 372 2498 30 343 85 74 81 1631 14 388 1317 411 146
56 36 6 20 4 2581 209 24 119 13 38 249 2974 3020
1317 27 12 47 310 66 2 504 11 169 3 12 1 231
232 8 22 4 467 503 146 73 3 55 94 9770 1108 24
80 31 9 40 1620 1317 184 4 4010 4108 1631 14 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]
Label: 5🔹 شرح الطبقات
طبقة Embedding
- تحوّل كل فهرس كلمة إلى متجه كثيف (Dense Vector).
input_dim: حجم المفردات (Vocabulary Size).output_dim: أبعاد متجهات التضمين (Embedding Vectors).input_length: الطول الثابت لتسلسلات الإدخال.
طبقة LSTM
units: عدد الوحدات المخفية (Hidden Units) أو خلايا الذاكرة.return_sequences: القيمةTrueتُعيد التسلسل الكامل؛ استخدمها عند رصّ عدة طبقات LSTM فوق بعضها.dropout: معدل الإسقاط (Dropout) لاتصالات الإدخال.recurrent_dropout: معدل الإسقاط لاتصالات حالة الذاكرة بين الخطوات الزمنية
model_lstm = Sequential()
model_lstm.add(Embedding(input_dim=vocab_size, output_dim=128, input_length=maxlen))
model_lstm.add(LSTM(units=64, return_sequences=True))
model_lstm.add(LSTM(units=32, dropout=0.2, recurrent_dropout=0.2))
model_lstm.add(Dense(10, activation='softmax'))
model_lstm.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
model_lstm.fit(padded_sequences, one_hot_labels, epochs=10, batch_size=32, validation_split=0.2)Epoch 1/10
/usr/local/lib/python3.11/dist-packages/keras/src/layers/core/embedding.py:90: UserWarning: Argument `input_length` is deprecated. Just remove it.
warnings.warn(
[1m144/144[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m64s[0m 355ms/step - accuracy: 0.1436 - loss: 2.2707 - val_accuracy: 0.2157 - val_loss: 2.1740
Epoch 2/10
[1m144/144[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m52s[0m 361ms/step - accuracy: 0.2254 - loss: 2.1460 - val_accuracy: 0.2365 - val_loss: 2.1035
Epoch 3/10
[1m144/144[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m80s[0m 343ms/step - accuracy: 0.2947 - loss: 1.9751 - val_accuracy: 0.2365 - val_loss: 2.0300
Epoch 4/10
[1m144/144[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m51s[0m 353ms/step - accuracy: 0.3294 - loss: 1.8010 - val_accuracy: 0.3339 - val_loss: 1.7684
Epoch 5/10
[1m144/144[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m82s[0m 357ms/step - accuracy: 0.3438 - loss: 1.7629 - val_accuracy: 0.2504 - val_loss: 2.0128
Epoch 6/10
[1m144/144[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m81s[0m 352ms/step - accuracy: 0.3253 - loss: 1.7569 - val_accuracy: 0.3365 - val_loss: 1.8139
Epoch 7/10
[1m144/144[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m83s[0m 363ms/step - accuracy: 0.4165 - loss: 1.5375 - val_accuracy: 0.3530 - val_loss: 1.7347
Epoch 8/10
[1m144/144[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m81s[0m 355ms/step - accuracy: 0.4726 - loss: 1.3878 - val_accuracy: 0.4209 - val_loss: 1.6340
Epoch 9/10
[1m144/144[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m82s[0m 352ms/step - accuracy: 0.5262 - loss: 1.2354 - val_accuracy: 0.4609 - val_loss: 1.5254
Epoch 10/10
[1m144/144[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m51s[0m 350ms/step - accuracy: 0.5796 - loss: 1.0998 - val_accuracy: 0.5191 - val_loss: 1.4216
<keras.src.callbacks.history.History at 0x7fa0e2224190>طبقة Bidirectional
- تعالج تسلسل الإدخال في كلا الاتجاهين، الأمامي والخلفي.
- غالبًا ما تحسّن الأداء في مهام معالجة اللغة الطبيعية (NLP) حيث يكون السياق من الجهتين مفيدًا.
model_bi = Sequential()
model_bi.add(Embedding(input_dim=vocab_size, output_dim=128, input_length=maxlen))
model_bi.add(Bidirectional(LSTM(units=64, dropout=0.2, recurrent_dropout=0.2)))
model_bi.add(Dense(10, activation='softmax'))
model_bi.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
model_bi.fit(padded_sequences, one_hot_labels, epochs=10, batch_size=32, validation_split=0.2)Epoch 1/10
[1m144/144[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m92s[0m 581ms/step - accuracy: 0.1717 - loss: 2.2183 - val_accuracy: 0.3843 - val_loss: 1.8057
Epoch 2/10
[1m144/144[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m81s[0m 566ms/step - accuracy: 0.4948 - loss: 1.5136 - val_accuracy: 0.6157 - val_loss: 1.1395
Epoch 3/10
[1m144/144[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m82s[0m 568ms/step - accuracy: 0.7449 - loss: 0.8354 - val_accuracy: 0.7070 - val_loss: 0.8469
Epoch 4/10
[1m144/144[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m82s[0m 565ms/step - accuracy: 0.8816 - loss: 0.4428 - val_accuracy: 0.7530 - val_loss: 0.7618
Epoch 5/10
[1m144/144[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m82s[0m 565ms/step - accuracy: 0.9387 - loss: 0.2518 - val_accuracy: 0.7783 - val_loss: 0.7177
Epoch 6/10
[1m144/144[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m82s[0m 564ms/step - accuracy: 0.9585 - loss: 0.1622 - val_accuracy: 0.8026 - val_loss: 0.6888
Epoch 7/10
[1m144/144[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m82s[0m 563ms/step - accuracy: 0.9787 - loss: 0.0978 - val_accuracy: 0.8096 - val_loss: 0.6960
Epoch 8/10
[1m144/144[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m82s[0m 569ms/step - accuracy: 0.9895 - loss: 0.0547 - val_accuracy: 0.8113 - val_loss: 0.7218
Epoch 9/10
[1m144/144[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m80s[0m 553ms/step - accuracy: 0.9871 - loss: 0.0556 - val_accuracy: 0.8061 - val_loss: 0.7460
Epoch 10/10
[1m144/144[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m86s[0m 579ms/step - accuracy: 0.9971 - loss: 0.0288 - val_accuracy: 0.8070 - val_loss: 0.7524
<keras.src.callbacks.history.History at 0x7fa0f4273cd0>sample_text = ["NASA is planning a mission to Jupiter"]
seq = tokenizer.texts_to_sequences(sample_text)
pad = pad_sequences(seq, maxlen=maxlen, padding='post')
prediction = model_bi.predict(pad)
predicted_class_index = np.argmax(prediction)
print("Predicted class index:", predicted_class_index)
print("Actual Category:", newsgroups.target_names[predicted_class_index])[1m1/1[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m0s[0m 74ms/step
Predicted class index: 6
Actual Category: sci.space🔚 ملخص المقارنة
- LSTM القياسي: يعالج التسلسلات من الماضي إلى المستقبل.
- LSTM ثنائي الاتجاه (Bidirectional): يعالج التسلسلات من كلا الاتجاهين.
- يمكن للنماذج ثنائية الاتجاه تعلّم سياق أغنى، وغالبًا ما تُعطي نتائج أفضل في مهام معالجة اللغة الطبيعية.
في النموذج السابق، حاول رصّ طبقة LSTM أخرى وإضافة طبقة Dropout بعد طبقة LSTM
تمرين: درّب نموذج GRU
- استبدل LSTM الخاص بك بـGRU.
- نزّل مجموعة بيانات 20 newsgroups الكاملة؛ توجد بالفعل مجموعتا "تدريب" و"اختبار" محدَّدتان، واستخدم مجموعة الاختبار لتقييم نموذجك
- جرّب أطوال تسلسل (Sequence Lengths) مختلفة، وأبعادًا مختلفة للحالة المخفية (Hidden State) في LSTM. هل يمكنك تحسين النموذج؟