ก้าวต่อไปด้วยการฝัง GloVe

Nov 27 2022
คุณต้องการใช้การฝัง GloVe ในโครงการของคุณหรือไม่? คำศัพท์ต่าง ๆ ทำให้คุณมีปัญหาหรือไม่? ยินดีด้วย! คุณมาถูกที่แล้ว หมายเหตุ: บทความนี้ไม่ได้กล่าวถึงคณิตศาสตร์เบื้องหลังการฝัง GloVe
ภาพถ่ายโดย Nick Morrison บน Unsplash

คุณต้องการใช้การฝัง GloVe ในโครงการของคุณหรือไม่? คำศัพท์ต่าง ๆ ทำให้คุณมีปัญหาหรือไม่? ยินดีด้วย! คุณมาถูกที่แล้ว

หมายเหตุ:บทความนี้ไม่ได้กล่าวถึงคณิตศาสตร์เบื้องหลังการฝัง GloVe

ในบทความนี้ เราจะเรียนรู้วิธีใช้การฝัง GloVe เพื่อแปลงข้อมูลข้อความเป็นตัวเลข เราจะเรียนรู้ขั้นตอนโดยใช้คลังข้อความสั้น จากนั้นเราจะใช้ขั้นตอนเหล่านั้นเพื่อรับการฝังสำหรับชุดข้อมูลบทวิจารณ์ภาพยนตร์ IMDB เราจะใช้การฝังที่ได้รับเพื่อฝึกตัวแยกประเภทความรู้สึกแบบไบนารีในชุดข้อมูลเดียวกัน

มาเริ่มกันเลย!

บทนำ

มีการฝังคำของ GloVe ที่ได้รับการฝึกฝนไว้ล่วงหน้ามากมายให้ดาวน์โหลด สามารถดูข้อมูลเพิ่มเติมเกี่ยวกับคลังข้อมูลการฝึกซ้อมของการฝัง Glove ต่างๆ ได้ในเว็บไซต์นี้ ในบทช่วยสอนนี้ เราจะใช้การฝัง glovetwitter27b50d ซึ่งมี 50 มิติและได้รับการฝึกอบรมเกี่ยวกับทวีต 2B จาก Twitter

การฝังมีให้ในรูปแบบไฟล์ข้อความ โดยแต่ละบรรทัดมีสตริงที่มีคำและการแสดงเวกเตอร์ เราจะแปลงเนื้อหาของไฟล์ข้อความนี้เป็นพจนานุกรม

# Read the text file
glovetwitter27b50d = "pathe_to_glovetwitter27b50d.txt"
file = open(glovetwitter27b50d)
glovetwitter27b50d = file.readlines()


# Convert the text file into a dictionary
def ConvertToEmbeddingDictionary(glovetwitter27b50d):
    embedding_dictionary = {}
    for word_embedding in tqdm(glovetwitter27b50d):
        word_embedding = word_embedding.split()
        word = word_embedding[0]
        embedding = np.array([float(i) for i in word_embedding[1:]])
        embedding_dictionary[word] = embedding
    return embedding_dictionary
embedding_dictionary = ConvertToEmbeddingDictionary(glovetwitter27b50d)

# Let's look at the embedding of the word "hello."
embedding_dictionary['hello']
Output:
array([ 0.28751  ,  0.31323  , -0.29318  ,  0.17199  , -0.69232  ,
       -0.4593   ,  1.3364   ,  0.709    ,  0.12118  ,  0.11476  ,
       -0.48505  , -0.088608 , -3.0154   , -0.54024  , -1.326    ,
        0.39477  ,  0.11755  , -0.17816  , -0.32272  ,  0.21715  ,
        0.043144 , -0.43666  , -0.55857  , -0.47601  , -0.095172 ,
        0.0031934,  0.1192   , -0.23643  ,  1.3234   , -0.45093  ,
       -0.65837  , -0.13865  ,  0.22145  , -0.35806  ,  0.20988  ,
        0.054894 , -0.080322 ,  0.48942  ,  0.19206  ,  0.4556   ,
       -1.642    , -0.83323  , -0.12974  ,  0.96514  , -0.18214  ,
        0.37733  , -0.19622  , -0.12231  , -0.10496  ,  0.45388  ])

sample_corpus = ['The woods are lovely, dark and deep',
                 'But I have promises to keep',   
                 'And miles to go before I sleep', 
                 'And miles to go before I sleep']

# This is the maximum number of tokens we wish to consider from our dataset.
# When there are more tokens, the tokens with the highest frequency are chosen.
max_number_of_words = 5

# Note: Keras tokenizer selects only top n-1 tokens if the num_words is set to n
tokenizer = Tokenizer(num_words=max_number_of_words)
tokenizer.fit_on_texts(sample_corpus)
sample_corpus_tokenized = tokenizer.texts_to_sequences(sample_corpus)
print(tokenizer.word_index)
Output:
{'and': 1, 'i': 2, 'to': 3, 'miles': 4, 'go': 5, 'before': 6, 'sleep': 7, 'the': 8, 'woods': 9, 'are': 10, 'lovely': 11, 'dark': 12, 'deep': 13, 'but': 14, 'have': 15, 'promises': 16, 'keep': 17}
print("But I have promises to keep: ", sample_corpus_tokenized[1])
Output:
But I have promises to keep:  [2, 3]

ตอนนี้เราได้เลือกชุดของโทเค็นจากคลังข้อความของเราแล้ว เราต้องพัฒนาเมทริกซ์การฝังสำหรับพวกมัน เมทริกซ์การฝังจะมีคอลัมน์เท่ากับมิติของการฝังและแถวเท่ากับจำนวนโทเค็

# Create embedding matrix
total_number_of_words = min(max_number_of_words, len(tokenizer.word_index))
embedding_matrix = np.zeros((total_number_of_words,50))
for word, i in tokenizer.word_index.items():
    if i >= total_number_of_words: break
    if word in embedding_dictionary.keys():
        embedding_vector = embedding_dictionary[word]
        embedding_matrix[i] = embedding_vector

โครงข่ายประสาทเทียมและอัลกอริธึม ML ไม่สามารถจัดการกับอินพุตที่มีความยาวผันแปรได้ ดังนั้น เราจำเป็นต้องแปลงการฝังของทุกลำดับอินพุตให้มีขนาดคงที่ มีหลายวิธีในการทำเช่นนี้ แต่วิธีที่ง่ายที่สุดคือการรวมการฝังโทเค็นทุกรายการในประโยคและทำให้เวกเตอร์เป็นปกติ

def convertToSentenceVector(sentences):
    new_sentences = []
    for sentence in sentences:
        sentence_vector = []
        for word_index in sentence:
            sentence_vector.append(embedding_matrix[word_index])
        sentence_vector = np.array(sentence_vector).sum(axis=0)
        embedding_vector / np.sqrt((embedding_vector ** 2).sum())
        new_sentences.append(sentence_vecto

sample_corpus_vectorized = convertToSentenceVector(sample_corpus_tokenized)

# Print the 50-dimensional embedding of the first sentence in our text corpus.
print(sample_corpus_vectorized[0])
Output:
[-0.43196   -0.18965   -0.028294  -0.25903   -0.4481     0.53591
  0.94627   -0.07806   -0.54519   -0.72878   -0.030083  -0.28677
 -6.464     -0.31295    0.12351   -0.2463     0.029458  -0.83529
  0.19647   -0.15722   -0.5562    -0.027029  -0.23915    0.18188
 -0.15156    0.54768    0.13767    0.21828    0.61069   -0.3679
  0.023187   0.33281   -0.18062   -0.0094163  0.31861   -0.19201
  0.35759    0.50104    0.55981    0.20561   -1.1167    -0.3063
 -0.14224    0.20285    0.10245   -0.39289   -0.26724   -0.37573
  0.16076   -0.74501  ]

การจัดประเภทความรู้สึก: ชุดข้อมูลบทวิจารณ์ภาพยนตร์ IMDB

# Read the data
df = pd.read_csv("IMDB_Dataset.csv")
X = df['review']
y = df['sentiment']
# Convert labels to numbers
le = LabelEncoder()
y = le.fit_transform(y)
# Split the data into train and test sets.
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.10, random_state=0)
#Set the maximum number of tokens to 50000
max_number_of_words = 50000

# Tokenize training set
tokenizer = Tokenizer(num_words=max_number_of_words)
tokenizer.fit_on_texts(X_train)
X_train = tokenizer.texts_to_sequences(X_train)
X_test = tokenizer.texts_to_sequences(X_test)

# Create embedding matrix
total_number_of_words = min(max_number_of_words, len(tokenizer.word_index))
embedding_matrix = np.zeros((total_number_of_words+1,50))
for word, i in tokenizer.word_index.items():
    if i >= total_number_of_words: break
    if word in embedding_dictionary.keys():
        embedding_vector = embedding_dictionary[word]
        embedding_matrix[i] = embedding_vector

# Get a fixed-size embedding for every comment using the function defined earlier
X_train = convertToSentenceVector(X_train)
X_test = convertToSentenceVector(X_test)

# Define a sequential model
model = Sequential()
model.add(Dense(100, input_shape = (50,), activation = "relu"))
model.add(Dense(1000, activation = "relu"))
model.add(Dropout(0.2))
model.add(Dense(1, activation = "sigmoid"))
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
model.summary()

# Fit the model
model.fit(X_train, y_train, batch_size=32, epochs=10, validation_split=0.1)

# Get the classification report on the test set
y_pred = model.predict(X_test)
y_pred = y_pred.round()
print(classification_report(y_test, y_pred))
Output:
              precision    recall  f1-score   support

           0       0.82      0.77      0.79      2553
           1       0.77      0.82      0.80      2447

    accuracy                           0.80      5000
   macro avg       0.80      0.80      0.80      5000
weighted avg       0.80      0.80      0.80      5000

max_number_of_words = 50000
max_length = 100

tokenizer = Tokenizer(num_words=max_number_of_words)
tokenizer.fit_on_texts(X_train)
X_train = tokenizer.texts_to_sequences(X_train)
X_test = tokenizer.texts_to_sequences(X_test)

# We can use padding to make the length of every comment equal to max_length
X_train = pad_sequences(X_train, maxlen=max_length)
X_test = pad_sequences(X_test, maxlen=max_length)

# Define a sequential model
model = Sequential()
# Add an embedding layer and pass the embedding matrix as weights
model.add(Embedding(max_number_of_words+1, 50, input_shape = (100,), weights=[embedding_matrix]))
model.add(Bidirectional(LSTM(50, return_sequences=True, dropout=0.1, recurrent_dropout=0.1)))
model.add(GlobalMaxPool1D())
model.add(Dense(50, activation="relu"))
model.add(Dropout(0.1))
model.add(Dense(1, activation="sigmoid"))
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
model.summary()

# Fit the model
model.fit(X_train, y_train, batch_size=32, epochs=10, validation_split=0.1);

# Get the classification report
y_pred = model.predict(X_test)
y_pred = y_pred.round()
print(classification_report(y_test, y_pred))
Output:
              precision    recall  f1-score   support

           0       0.87      0.83      0.85      2553
           1       0.83      0.87      0.85      2447

    accuracy                           0.85      5000
   macro avg       0.85      0.85      0.85      5000
weighted avg       0.85      0.85      0.85      5000

เมื่อคุณมีความเข้าใจที่ดีขึ้นเกี่ยวกับการฝัง GloVe แล้ว คุณก็พร้อมที่จะนำไปใช้กับปัญหา NLP ต่างๆ

หมายเหตุ:คุณสามารถเข้าถึงรหัสที่สมบูรณ์ได้จากลิงค์นี้

อ้างอิง :

  1. https://www.tensorflow.org/text/guide/word_embeddings
  2. https://www.kaggle.com/code/jhoward/improved-lstm-baseline-glove-dropout
  3. https://www.kaggle.com/code/abhishek/approaching-almost-any-nlp-problem-on-kaggle