שימוש ב-word embedding שאומן מראש במודל Keras לסיווג טקסטים

מחבר:
בתאריך:

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

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

אתה יכול לקרוא על טכנולוגית word embedding במדריך מבוא לעיבוד שפה באמצעות Gensim ו-Word2Vec.

במדריך זה נשתמש ב-word embedding שעשו בשבילנו באמצעות אלגוריתם GloVe שאומן מראש על וויקיפדיה האנגלית.

את הקוד המלא של המדריך כדאי להוריד מהקישור: keras_glove_embedding.py בגלל שלא פרטתי במדריך את כל השלבים.

 

שיטות

מסד הנתונים במדריך הוא 20 news group שייבאתי לפי הפרוטוקול שתארתי במדריך למידת מכונה - סיווג טקסטים באמצעות sklearn.

בהכנת מסד הנתונים ושכבת ה-embedding השתמשתי בגישה המתוארת ב-Using pre-trained word embeddings in a Keras model עם התאמות קלות.

 

הכנת מסד הנתונים

מסד הנתונים 20 news group שהורדנו בשלב קודם מורכב מקבצים שבכל אחד מהם נמצא אחד הטקסטים. הקבצים מסודרים בתיקיות. לצורך המדריך, לקחתי 4 קטגוריות מתוך ה-20.

 

# second, prepare text samples and their labels
print('Processing text dataset')
 
dir_list = os.listdir(TEXT_DATA_DIR)
 
texts = []  # list of text samples
labels_index = {}  # dictionary mapping label name to numeric id
labels = []  # list of label ids
categories = ['rec.autos','sci.med','comp.os.ms-windows.misc','comp.windows.x']
 
for name in sorted(dir_list):
    path = os.path.join(TEXT_DATA_DIR, name)
    # print(path)
    if os.path.isdir(path) and name in categories:
        label_id = len(labels_index)
        labels_index[name] = label_id
        for fname in sorted(os.listdir(path)):
            if fname.isdigit():
                fpath = os.path.join(path, fname)
                args = {}
                with open(fpath, encoding='latin-1') as f:
                    t = f.read()
                    i = t.find('\n\n')  # skip header
                    if 0 < i:
                        t = t[i:]
                    texts.append(t)
                labels.append(label_id)
 
print('Found %s texts.' % len(texts))

הפיכת הטקסטים לווקטורים:

# vectorize the text samples into a 2D integer tensor
tokenizer = Tokenizer(num_words=MAX_NUM_WORDS)
tokenizer.fit_on_texts(texts)
sequences = tokenizer.texts_to_sequences(texts)
 
word_index = tokenizer.word_index
print('Found %s unique tokens.' % len(word_index))
 
data = pad_sequences(sequences, maxlen=MAX_SEQUENCE_LENGTH)
 
labels = to_categorical(np.asarray(labels))
print('Shape of data tensor:', data.shape)
print('Shape of label tensor:', labels.shape)

נחלק את הדוגמאות בין קבוצת אימון ובקרה:

VALIDATION_SPLIT = 0.2

# split the data into a training set and a validation set
indices = np.arange(data.shape[0])
np.random.shuffle(indices)
data = data[indices]
labels = labels[indices]
num_validation_samples = int(VALIDATION_SPLIT * data.shape[0])
 
x_train = data[:-num_validation_samples]
y_train = labels[:-num_validation_samples]
x_val = data[-num_validation_samples:]
y_val = labels[-num_validation_samples:]

 

הכנת שכבת ה-embedding

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

# first, build index mapping words in the embeddings set
# to their embedding vector
 
print('Indexing word vectors.')
 
embeddings_index = {}
with open(os.path.join(GLOVE_DIR,'glove.6B.100d.txt')) as f:
    for line in f:
        word, coefs = line.split(maxsplit=1)
        coefs = np.fromstring(coefs, 'f', sep=' ')
        embeddings_index[word] = coefs
 
print('Found %s word vectors.' % len(embeddings_index))

בשלב זה נתרגם את הטקסטים שלנו לוקטורים שמספק GloVe. התוצאה של השלב הזה היא embedding matrix שאותו נזין לרשת הנוירונית.

# prepare embedding matrix
num_words = min(MAX_NUM_WORDS, len(word_index) + 1)
embedding_matrix = np.zeros((num_words, EMBEDDING_DIM))
for word, i in word_index.items():
    if i >= MAX_NUM_WORDS:
        continue
    embedding_vector = embeddings_index.get(word)
    if embedding_vector is not None:
        # words not found in embedding index will be all-zeros.
        embedding_matrix[i] = embedding_vector

 

הרשת הנוירונית

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

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

  • הורדתי את מספר שכבות ה-RNN מ-3 ל-2
  • הוספתי רגולריזציה מסוג l2
  • הוספתי dropout 

שלוש השיטות מיועדות למנוע overfitting כפי שהסברתי במדריך כיצד להתגבר על overfitting במודלים מבוססי Keras?

בניית המודל:

EPOCHS = 22
BATCH_SIZE = 32
NUM_CLASSES = 4

model = Sequential()
model.add(Embedding(MAX_NUM_WORDS, 
                    128, 
                    embeddings_initializer=Constant(embedding_matrix),
                    input_length=MAX_SEQUENCE_LENGTH,
                    trainable=False))
model.add(Bidirectional(GRU(units=64, dropout=0.2, recurrent_dropout=0.2, activation='sigmoid', return_sequences=True)))
model.add(Bidirectional(GRU(units=4, dropout=0.2, recurrent_dropout=0.2, activation='sigmoid', return_sequences=False)))
model.add(Dense(NUM_CLASSES, activation='softmax'))
model.compile(loss='categorical_crossentropy',
              optimizer='adam',
              metrics=['accuracy'])

אימון המודל:

# set the conditions for early stopping
from tensorflow.keras.callbacks import EarlyStopping
es = EarlyStopping(patience = 2, monitor='val_loss')
 
 
model.fit(x_train, y_train,
          batch_size=BATCH_SIZE,
          epochs=EPOCHS,
          validation_data=(x_val, y_val), 
          callbacks=[es])

 

הערכת המודל

loss, accuracy = model.evaluate(x_val, y_val, verbose=1)
print('Accuracy: %0.2f' % (accuracy*100))

דיוק של 78.78% בסיווג דוגמאות קבוצת הבקרה.

 

השוואה לביצועי מודל sklearn

במדריך למידת מכונה - סיווג טקסטים באמצעות sklearn הגעתי למידת דיוק של 99% בדוגמאות הבקרה כשהשתמשתי לסיווג במודל MultinomialNB. תוצאה שהיא גבוהה משמעותית מ-79% שאליו הגיע המודל מבוסס ה-Keras. לא זו בלבד, גם זמן האימון היה ארוך משמעותית יותר כשהשתמשתי ב-Keras. בתחילה, חשבתי שמודל אחר של Keras עשוי להשתוות לתוצאות של sklearn. בהתאם, ניסיתי מודל מבוסס קונבולציה, שאפרסם את תוצאותיו בעתיד. רק שגם הוא לא הצליח להתקרב לתוצאות של sklearn. נראה שהמודלים שאני בונה עם Keras הם לא מספיק מוצלחים, וייתכן שמה שתורם לכך הוא מספר הדוגמאות היחסית קטן שבו השתמשתי לאימון כי רשתות נוירוניות דורשות מספר גדול מאוד של דוגמאות. בכל מקרה, הניסיון שלי מלמד אותי שכדאי להעדיף את sklearn לצורך סיווג טקסט לקטגוריות בפרט כשמספר הדוגמאות והטוקנים אינו גדול מספיק.

 

מקורות מידע

  1. מבוא לעיבוד שפה באמצעות Gensim ו-Word2Vec
  2. למידת מכונה - סיווג טקסטים באמצעות sklearn
  3. Using pre-trained embedding model in Keras
  4. פיתוח מודל לאנליזת סנטימנט באמצעות למידת מכונה ו-keras
  5. כיצד להתגבר על overfitting במודלים מבוססי Keras

 

לכל המדריכים בנושא של למידת מכונה

 

אהבתם? לא אהבתם? דרגו!

0 הצבעות, ממוצע 0 מתוך 5 כוכבים

 

 

הוסף תגובה חדשה

 

= 6 + 4