דף זה תורגם על ידי Cloud Translation API.
Switch to English

סיווג טקסט בסיסי

צפה ב TensorFlow.org הפעל ב- Google Colab צפה במקור ב- GitHub הורד מחברת

מדריך זה מדגים סיווג טקסט החל מקבצי טקסט רגילים המאוחסנים בדיסק. אתה מאמן מסווג בינארי לביצוע ניתוחי רגשות במערך נתונים של IMDB. בסוף המחברת, יש לך תרגיל שתנסה בו, שתאמן מסווג רב-כיתתי כדי לחזות את התג לשאלת תכנות ב- Overflow Stack.

 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 ביקורות סרטים ממאגר הסרטים באינטרנט . אלה מחולקים ל 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.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_ , המצפה למבנה ספרייה באופן הבא.

 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)
 

לאחר מכן תשתמש 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.

כפי שאתה יכול לראות לעיל, יש 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.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 כדי לפשט את מערך הנתונים. אסימון מתייחס לפיצול מחרוזות לאסימונים (למשל, פיצול משפט למילים בודדות, על ידי פיצול במרחב הלבן). וקטוריזציה מתייחסת להמרת אסימונים למספרים כך שניתן להזין אותם לרשת עצבית. ניתן לבצע את כל המשימות הללו בשכבה זו.

כפי שראית לעיל, הביקורות מכילות תגיות 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 לערכי 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() בשכבה.

 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() שומר נתונים בזיכרון לאחר .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. השכבה האחרונה מחוברת בצפיפות עם צומת פלט בודד.

פונקציית אובדן ומיטוב

מודל זקוק לפונקציית אובדן ומיטוב לאימונים. מכיוון שמדובר בבעיית סיווג בינארי והמודל מוציא הסתברות (שכבה של יחידה אחת עם הפעלה של sigmoid), תשתמש בפונקציות אובדן. losses.BinaryCrossentropy loss.

כעת, קבע את התצורה של הדגם לשימוש בכלי אופטימיזציה ופונקציית אובדן:

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

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

בעלילה זו, הנקודות מייצגות את אובדן האימונים והדיוק, והקווים היסודיים הם אובדן האימות והדיוק.

שימו לב שאובדן האימונים פוחת עם כל תקופה ודיוק האימונים גדל עם כל תקופה. זה צפוי בעת שימוש באופטימיזציה של ירידת שיפוע - עליו למזער את הכמות הרצויה בכל איטרציה.

זה לא המקרה לאובדן האימות והדיוק - נראה שהם מגיעים לשיא לפני דיוק האימונים. זו דוגמא להתאמת יתר: המודל מתפקד טוב יותר על נתוני האימונים מאשר בנתונים שמעולם לא ראה. לאחר נקודה זו, המודל מייעל יתר על המידה ולומד ייצוגים ספציפיים לנתוני האימונים שאינם כללים לבדיקת נתונים.

למקרה ספציפי זה, אתה יכול למנוע התאמה יתר על ידי עצירת ההדרכה כאשר דיוק האימות אינו עולה עוד. אחת הדרכים לעשות זאת היא להשתמש בהתקשרות חזרה של EarlyStopping .

ייצא את הדגם

בקוד שלמעלה, החלת את שכבת TextVectorization על מערך הנתונים לפני 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 בתוך הדגם שלך כשאתה מוכן להתכונן לפריסה. .

בקר במדריך זה למידע נוסף על שמירת דגמים.

תרגיל: סיווג רב-כיתתי בשאלות של הצפת ערימה

מדריך זה הראה כיצד להכשיר מסווג בינארי מאפס במערך הנתונים של IMDB. כתרגיל, באפשרותך לשנות את המחברת הזו כדי להכשיר מסווג רב-כיתתי כדי לחזות את התג של שאלה תכנות ב- Overflow Stack .

הכנו עבורך מערך נתונים לשימוש בו מכיל את המרכיב של כמה אלפי שאלות תכנות (לדוגמה, "כיצד ניתן למיין מילון לפי ערך בפיתון?") שפורסם ב- Stack Overflow. כל אחד מהם מסומן בתווית אחת בדיוק (Python, CSharp, JavaScript או Java). המשימה שלך היא לקחת שאלה כמקלט ולחזות את התג המתאים, במקרה זה, פייתון.

מערך הנתונים שאיתו תעבוד מכיל כמה אלפי שאלות שהוצאו ממערך הנתונים של 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
 

להשלמת תרגיל זה, עליכם לשנות את המחברת כך שתעבוד עם מערך הנתונים של Overflow Stack על ידי ביצוע השינויים הבאים:

  1. בחלקו העליון של המחברת, עדכנו את הקוד שמוריד את מערך ה- IMDB עם קוד כדי להוריד את מערך ה- Stack Overflow שיצא לנו להכין מראש. מכיוון שלמערכת הנתונים של Stack Overflow יש מבנה ספרייה דומה, לא תצטרך לבצע שינויים רבים.

  2. שנה את השכבה האחרונה של המודל שלך לקריאה Dense(4) , מכיוון שכעת יש ארבע כיתות פלט.

  3. כשאתה מורכב את המודל שלך, שנה את האובדן ל- SparseCategoricalCrossentropy . זוהי פונקציית ההפסד הנכונה בה משתמשים בבעיית סיווג רב-כיתתי, כאשר התוויות לכל כיתה הן מספרים שלמים (במקרה שלנו הם יכולים להיות 0, 1 , 2 או 3 ).

  4. לאחר השלמת השינויים הללו, תוכלו להכשיר מסווג רב-כיתתי.

אם אתה נתקע אתה יכול למצוא פיתרון כאן .

ללמוד עוד

מדריך זה הציג סיווג טקסט מאפס. למידע נוסף על זרימת העבודה של סיווג טקסטים באופן כללי, אנו ממליצים לקרוא מדריך זה ממפתחי Google.

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