ترجمت واجهة Cloud Translation API‏ هذه الصفحة.
Switch to English

تصنيف النص الأساسي

عرض على TensorFlow.org تشغيل في Google Colab عرض المصدر على جيثب تنزيل دفتر الملاحظات

يوضح هذا البرنامج التعليمي تصنيف النص بدءًا من ملفات النص العادي المخزنة على القرص. سوف تقوم بتدريب المصنف الثنائي لإجراء تحليل المشاعر على مجموعة بيانات IMDB. في نهاية دفتر الملاحظات ، هناك تمرين يمكنك تجربته ، حيث ستقوم بتدريب مصنف متعدد الفئات للتنبؤ بالعلامة لسؤال برمجة على Stack Overflow.

 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
from tensorflow.keras import preprocessing
from tensorflow.keras.layers.experimental.preprocessing import TextVectorization
 
 print(tf.__version__)
 
2.3.0

تحليل المشاعر

يدرب هذا الكمبيوتر الدفتري نموذج تحليل المشاعر لتصنيف مراجعات الأفلام بأنها إيجابية أو سلبية ، بناءً على نص المراجعة. هذا مثال لتصنيف ثنائي — أو فئتين — وهو نوع مهم من مشكلات التعلم الآلي قابل للتطبيق على نطاق واسع.

ستستخدم مجموعة بيانات مراجعة الأفلام الكبيرة التي تحتوي على نص 50،000 مراجعة فيلم من قاعدة بيانات أفلام الإنترنت . تنقسم هذه إلى 25000 مراجعة للتدريب و 25000 مراجعة للاختبار. مجموعات التدريب والاختبار متوازنة ، مما يعني أنها تحتوي على عدد متساو من المراجعات الإيجابية والسلبية.

قم بتنزيل مجموعة بيانات IMDB واستكشافها

لنقم بتنزيل مجموعة البيانات واستخراجها ، ثم استكشاف بنية الدليل.

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

dataset = tf.keras.utils.get_file("aclImdb_v1.tar.gz", 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 [==============================] - 7s 0us/step

 os.listdir(dataset_dir)
 
['imdb.vocab', 'train', 'test', 'README', 'imdbEr.txt']
 train_dir = os.path.join(dataset_dir, 'train')
os.listdir(train_dir)
 
['urls_pos.txt',
 'neg',
 'labeledBow.feat',
 'pos',
 'urls_neg.txt',
 'unsup',
 'unsupBow.feat',
 'urls_unsup.txt']

تحتوي 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 و class_b . ستكون هذه مراجعات الفيلم الإيجابية والسلبية ، والتي يمكن العثور عليها في aclImdb/train/pos و aclImdb/train/neg . نظرًا لأن مجموعة بيانات IMDB تحتوي على مجلدات إضافية ، فستقوم بإزالتها قبل استخدام هذه الأداة المساعدة.

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

بعد ذلك ، text_dataset_from_directory أداة text_dataset_from_directory لإنشاء tf.data.Dataset . tf.data عبارة عن مجموعة قوية من الأدوات للعمل مع البيانات.

عند تشغيل تجربة تعلُّم الآلة ، من الأفضل تقسيم مجموعة البيانات إلى ثلاثة أقسام: التدريب والتحقق والاختبار .

تم تقسيم مجموعة بيانات IMDB بالفعل إلى قطار واختبار ، لكنها تفتقر إلى مجموعة التحقق من الصحة. لنقم بإنشاء مجموعة التحقق باستخدام تقسيم 80:20 من بيانات التدريب باستخدام الوسيطة validation_split أدناه.

 batch_size = 32
seed = 42

raw_train_ds = tf.keras.preprocessing.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.

كما ترى أعلاه ، هناك 25000 مثال في مجلد التدريب ، ستستخدم 80٪ (أو 20000) للتدريب. كما سترى في لحظة ، يمكنك تدريب نموذج بتمرير مجموعة بيانات مباشرة إلى 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

بعد ذلك ، ستنشئ مجموعة بيانات للتحقق والاختبار. ستستخدم 5000 مراجعة المتبقية من مجموعة التدريب للتحقق من الصحة.

 raw_val_ds = tf.keras.preprocessing.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.preprocessing.text_dataset_from_directory(
    'aclImdb/test', 
    batch_size=batch_size)
 
Found 25000 files belonging to 2 classes.

قم بإعداد مجموعة البيانات للتدريب

بعد ذلك ، ستقوم بتوحيد البيانات وترميزها وتوجيهها باستخدام طبقة preprocessing.TextVectorization المفيدة.

يشير التوحيد إلى المعالجة المسبقة للنص ، عادةً لإزالة علامات الترقيم أو عناصر HTML لتبسيط مجموعة البيانات. يشير الرمز المميز إلى تقسيم السلاسل إلى رموز مميزة (على سبيل المثال ، تقسيم جملة إلى كلمات فردية ، عن طريق التقسيم على مسافة بيضاء). يشير Vectorization إلى تحويل الرموز إلى أرقام حتى يمكن تغذيتها في شبكة عصبية. يمكن تحقيق كل هذه المهام بهذه الطبقة.

كما رأيت أعلاه ، تحتوي المراجعات على علامات HTML مختلفة مثل <br /> . لن تتم إزالة هذه العلامات من قبل المعياري الافتراضي في طبقة TextVectorization (التي تحول النص إلى أحرف صغيرة وعلامات الترقيم بشكل افتراضي ، ولكن لا تجرد HTML). سوف تكتب وظيفة التوحيد القياسي لإزالة 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 . ستستخدم هذه الطبقة لتوحيد بياناتنا وترميزها وتوجيهها. يمكنك ضبط output_mode على int لإنشاء مؤشرات عددية فريدة لكل رمز مميز.

لاحظ أنك تستخدم وظيفة التقسيم الافتراضية ، ووظيفة التقييس المخصصة التي حددتها أعلاه. عليك أيضا تحديد بعض الثوابت لنموذج، مثل الحد الأقصى صريحة sequence_length ، والذي يؤدي إلى طبقة سادة أو اقتطاع تسلسل بالضبط sequence_length القيم.

 max_features = 10000
sequence_length = 250

vectorize_layer = 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'Silent Night, Deadly Night 5 is the very last of the series, and like part 4, it\'s unrelated to the first three except by title and the fact that it\'s a Christmas-themed horror flick.<br /><br />Except to the oblivious, there\'s some obvious things going on here...Mickey Rooney plays a toymaker named Joe Petto and his creepy son\'s name is Pino. Ring a bell, anyone? Now, a little boy named Derek heard a knock at the door one evening, and opened it to find a present on the doorstep for him. Even though it said "don\'t open till Christmas", he begins to open it anyway but is stopped by his dad, who scolds him and sends him to bed, and opens the gift himself. Inside is a little red ball that sprouts Santa arms and a head, and proceeds to kill dad. Oops, maybe he should have left well-enough alone. Of course Derek is then traumatized by the incident since he watched it from the stairs, but he doesn\'t grow up to be some killer Santa, he just stops talking.<br /><br />There\'s a mysterious stranger lurking around, who seems very interested in the toys that Joe Petto makes. We even see him buying a bunch when Derek\'s mom takes him to the store to find a gift for him to bring him out of his trauma. And what exactly is this guy doing? Well, we\'re not sure but he does seem to be taking these toys apart to see what makes them tick. He does keep his landlord from evicting him by promising him to pay him in cash the next day and presents him with a "Larry the Larvae" toy for his kid, but of course "Larry" is not a good toy and gets out of the box in the car and of course, well, things aren\'t pretty.<br /><br />Anyway, eventually what\'s going on with Joe Petto and Pino is of course revealed, and as with the old story, Pino is not a "real boy". Pino is probably even more agitated and naughty because he suffers from "Kenitalia" (a smooth plastic crotch) so that could account for his evil ways. And the identity of the lurking stranger is revealed too, and there\'s even kind of a happy ending of sorts. Whee.<br /><br />A step up from part 4, but not much of one. Again, Brian Yuzna is involved, and Screaming Mad George, so some decent special effects, but not enough to make this great. A few leftovers from part 4 are hanging around too, like Clint Howard and Neith Hunter, but that doesn\'t really make any difference. Anyway, I now have seeing the whole series out of my system. Now if I could get some of it out of my brain. 4 out of 5.', shape=(), dtype=string)
Label neg
Vectorized review (<tf.Tensor: shape=(1, 250), dtype=int64, numpy=
array([[1287,  313, 2380,  313,  661,    7,    2,   52,  229,    5,    2,
         200,    3,   38,  170,  669,   29, 5492,    6,    2,   83,  297,
         549,   32,  410,    3,    2,  186,   12,   29,    4,    1,  191,
         510,  549,    6,    2, 8229,  212,   46,  576,  175,  168,   20,
           1, 5361,  290,    4,    1,  761,  969,    1,    3,   24,  935,
        2271,  393,    7,    1, 1675,    4, 3747,  250,  148,    4,  112,
         436,  761, 3529,  548,    4, 3633,   31,    2, 1331,   28, 2096,
           3, 2912,    9,    6,  163,    4, 1006,   20,    2,    1,   15,
          85,   53,  147,    9,  292,   89,  959, 2314,  984,   27,  762,
           6,  959,    9,  564,   18,    7, 2140,   32,   24, 1254,   36,
           1,   85,    3, 3298,   85,    6, 1410,    3, 1936,    2, 3408,
         301,  965,    7,    4,  112,  740, 1977,   12,    1, 2014, 2772,
           3,    4,  428,    3, 5177,    6,  512, 1254,    1,  278,   27,
         139,   25,  308,    1,  579,    5,  259, 3529,    7,   92, 8981,
          32,    2, 3842,  230,   27,  289,    9,   35,    2, 5712,   18,
          27,  144, 2166,   56,    6,   26,   46,  466, 2014,   27,   40,
        2745,  657,  212,    4, 1376, 3002, 7080,  183,   36,  180,   52,
         920,    8,    2, 4028,   12,  969,    1,  158,   71,   53,   67,
          85, 2754,    4,  734,   51,    1, 1611,  294,   85,    6,    2,
        1164,    6,  163,    4, 3408,   15,   85,    6,  717,   85,   44,
           5,   24, 7158,    3,   48,  604,    7,   11,  225,  384,   73,
          65,   21,  242,   18,   27,  120,  295,    6,   26,  667,  129,
        4028,  948,    6,   67,   48,  158,   93,    1]])>, <tf.Tensor: shape=(), dtype=int32, numpy=0>)

كما ترى أعلاه ، تم استبدال كل رمز مميز بعدد صحيح. يمكنك البحث عن الرمز المميز (سلسلة) التي يتوافق .get_vocabulary() كل عدد صحيح عن طريق استدعاء .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)
 

تكوين مجموعة البيانات للأداء

هذان طريقتان مهمتان يجب عليك استخدامهما عند تحميل البيانات للتأكد من أن الإدخال / الإخراج لا يصبح حظرًا.

.cache() يحتفظ بالبيانات في الذاكرة بعد تحميلها من القرص. سيضمن ذلك عدم تحول مجموعة البيانات إلى عنق الزجاجة أثناء تدريب النموذج الخاص بك. إذا كانت مجموعة البيانات الخاصة بك كبيرة جدًا بحيث لا تتناسب مع الذاكرة ، يمكنك أيضًا استخدام هذه الطريقة لإنشاء ذاكرة تخزين مؤقت على القرص ، والتي تعد أكثر فعالية في القراءة من العديد من الملفات الصغيرة.

.prefetch() يتداخل مع معالجة البيانات وتنفيذ النموذج أثناء التدريب.

يمكنك معرفة المزيد حول كلتا الطريقتين ، بالإضافة إلى كيفية تخزين البيانات في ذاكرة التخزين المؤقت على القرص في دليل أداء البيانات .

 AUTOTUNE = tf.data.experimental.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 (Gl (None, 16)                0         
_________________________________________________________________
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. يتم توجيه ناقلات الإخراج ذات الطول الثابت عبر طبقة ( Dense ) متصلة بالكامل مع 16 وحدة مخفية.
  4. ترتبط الطبقة الأخيرة بكثافة عقدة إخراج واحدة.

وظيفة الخسارة والمحسن

يحتاج النموذج إلى وظيفة فقدان ومحسن للتدريب. نظرًا لأن هذه مشكلة تصنيف ثنائية losses.BinaryCrossentropy النموذج احتمالية (طبقة وحدة واحدة مع تنشيط سيني) ، 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 [==============================] - 3s 5ms/step - loss: 0.6632 - binary_accuracy: 0.6931 - val_loss: 0.6135 - val_binary_accuracy: 0.7752
Epoch 2/10
625/625 [==============================] - 3s 4ms/step - loss: 0.5472 - binary_accuracy: 0.8003 - val_loss: 0.4968 - val_binary_accuracy: 0.8220
Epoch 3/10
625/625 [==============================] - 3s 4ms/step - loss: 0.4434 - binary_accuracy: 0.8459 - val_loss: 0.4187 - val_binary_accuracy: 0.8486
Epoch 4/10
625/625 [==============================] - 3s 4ms/step - loss: 0.3770 - binary_accuracy: 0.8660 - val_loss: 0.3726 - val_binary_accuracy: 0.8622
Epoch 5/10
625/625 [==============================] - 2s 4ms/step - loss: 0.3349 - binary_accuracy: 0.8786 - val_loss: 0.3442 - val_binary_accuracy: 0.8678
Epoch 6/10
625/625 [==============================] - 2s 4ms/step - loss: 0.3046 - binary_accuracy: 0.8889 - val_loss: 0.3253 - val_binary_accuracy: 0.8722
Epoch 7/10
625/625 [==============================] - 2s 4ms/step - loss: 0.2807 - binary_accuracy: 0.8977 - val_loss: 0.3118 - val_binary_accuracy: 0.8726
Epoch 8/10
625/625 [==============================] - 2s 4ms/step - loss: 0.2609 - binary_accuracy: 0.9046 - val_loss: 0.3026 - val_binary_accuracy: 0.8762
Epoch 9/10
625/625 [==============================] - 2s 4ms/step - loss: 0.2443 - binary_accuracy: 0.9123 - val_loss: 0.2961 - val_binary_accuracy: 0.8774
Epoch 10/10
625/625 [==============================] - 2s 4ms/step - loss: 0.2309 - binary_accuracy: 0.9163 - val_loss: 0.2915 - val_binary_accuracy: 0.8804

قم بتقييم النموذج

دعونا نرى كيف يعمل النموذج. سيتم إرجاع قيمتين. الخسارة (رقم يمثل خطأنا ، والقيم الأقل أفضل) ، والدقة.

 loss, accuracy = model.evaluate(test_ds)

print("Loss: ", loss)
print("Accuracy: ", accuracy)
 
782/782 [==============================] - 2s 3ms/step - loss: 0.3097 - binary_accuracy: 0.8740
Loss:  0.30967268347740173
Accuracy:  0.8740400075912476

يحقق هذا النهج الساذج إلى حد ما دقة تبلغ حوالي 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()
 

بي إن جي

 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()
 

بي إن جي

في هذه المؤامرة ، تمثل النقاط فقدان التدريب ودقته ، والخطوط الصلبة هي فقدان التحقق والدقة.

لاحظ أن فقدان التدريب ينخفض مع كل حقبة وتزيد دقة التدريب مع كل حقبة. هذا أمر متوقع عند استخدام تحسين نزول التدرج - يجب أن يقلل الكمية المطلوبة في كل تكرار.

هذا ليس هو الحال بالنسبة لفقدان الدقة والدقة - يبدو أنها تصل إلى الذروة قبل دقة التدريب. هذا مثال على الإفراط في التجهيز: يعمل النموذج بشكل أفضل على بيانات التدريب مما يفعله على البيانات التي لم يسبق له مثيل. بعد هذه النقطة ، يعمل النموذج على الإفراط في التحسين ويتعلم العروض الخاصة ببيانات التدريب التي لا يتم تعميمها لاختبار البيانات.

في هذه الحالة بالذات ، يمكنك منع الإفراط في التجهيز عن طريق إيقاف التدريب ببساطة عندما لا تزداد دقة التحقق. إحدى الطرق للقيام بذلك هي استخدام رد الاتصال 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.3097 - accuracy: 0.8740
0.8740400075912476

يمكّنك تضمين منطق المعالجة المسبقة للنص داخل النموذج الخاص بك من تصدير نموذج للإنتاج يبسط النشر ويقلل من إمكانيات تدريب / اختبار الانحراف .

هناك اختلاف في الأداء يجب أخذه في الاعتبار عند اختيار مكان تطبيق طبقة TextVectorization. يتيح لك استخدامه خارج النموذج الخاص بك القيام بمعالجة غير متزامنة لوحدة المعالجة المركزية وتخزين البيانات مؤقتًا عند التدريب على GPU. لذا ، إذا كنت تقوم بتدريب نموذجك على GPU ، فربما ترغب في استخدام هذا الخيار للحصول على أفضل أداء أثناء تطوير النموذج الخاص بك ، ثم التبديل إلى تضمين طبقة TextVectorization داخل نموذجك عندما تكون مستعدًا للتحضير للنشر .

قم بزيارة هذا البرنامج التعليمي لمعرفة المزيد حول حفظ النماذج.

تمرين: تصنيف متعدد الفئات على أسئلة Stack Overflow

أظهر هذا البرنامج التعليمي كيفية تدريب المصنف الثنائي من الصفر على مجموعة بيانات IMDB. كتمرين ، يمكنك تعديل هذا الكمبيوتر المحمول لتدريب مصنف متعدد الفئات للتنبؤ بعلامة سؤال البرمجة على Stack Overflow .

لقد أعددنا مجموعة بيانات لتستخدمها تحتوي على نص عدة آلاف من أسئلة البرمجة (على سبيل المثال ، "كيف يمكنك فرز القاموس حسب القيمة في Python؟") المنشورة في Stack Overflow. يتم تمييز كل علامة من هذه العلامات بعلامة واحدة بالضبط (إما Python أو CSharp أو JavaScript أو Java). مهمتك هي أخذ سؤال كمدخل ، والتنبؤ بالعلامة المناسبة ، في هذه الحالة ، Python.

تحتوي مجموعة البيانات التي ستعمل عليها على عدة آلاف من الأسئلة المستخرجة من مجموعة بيانات Stack Overflow العامة الأكبر حجمًا على BigQuery ، والتي تحتوي على أكثر من 17 مليون مشاركة.

بعد تنزيل مجموعة البيانات ، ستجد أن لها بنية دليل مشابهة لمجموعة بيانات IMDB التي عملت معها سابقًا:

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

لإكمال هذا التمرين ، يجب تعديل هذا الكمبيوتر الدفتري للعمل مع مجموعة بيانات Stack Overflow عن طريق إجراء التعديلات التالية:

  1. في الجزء العلوي من دفتر الملاحظات الخاص بك ، قم بتحديث التعليمات البرمجية التي تقوم بتنزيل مجموعة بيانات IMDB برمز لتنزيل مجموعة بيانات Stack Overflow التي قمنا بإعدادها مسبقًا. نظرًا لأن مجموعة بيانات Stack Overflow لها بنية دليل مشابهة ، فلن تحتاج إلى إجراء العديد من التعديلات.

  2. قم بتعديل الطبقة الأخيرة من نموذجك لقراءة Dense(4) ، حيث يوجد الآن أربع فئات إخراج.

  3. عند تجميع النموذج الخاص بك ، قم بتغيير الخسارة إلى SparseCategoricalCrossentropy . هذه هي وظيفة الخسارة الصحيحة لاستخدامها في مشكلة تصنيف متعددة الفئات ، عندما تكون التسميات لكل فئة أعدادًا صحيحة (في حالتنا ، يمكن أن تكون 0 أو 1 أو 2 أو 3 ).

  4. بمجرد اكتمال هذه التغييرات ، ستتمكن من تدريب مصنف متعدد الفئات.

إذا واجهتك مشكلة ، يمكنك العثور على حل هنا .

تعلم المزيد

قدم هذا البرنامج التعليمي تصنيف النص من الصفر. لمعرفة المزيد حول سير عمل تصنيف النص بشكل عام ، نوصي بقراءة هذا الدليل من Google Developers.

 
#
# 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.