תחי ישראל - אין לנו ארץ אחרת

תחי ישראל -אין לנו ארץ אחרת

ensemble learning לשיפור ביצועי מודלים של למידת מכונה

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

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

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

כל מודל המשתתף ensemble learning תורם את חלקו להבנת הבעיה אותה למידת המכונה מיועדת לפתור בדומה למשל העיוורים והפיל
source: commons.wikimedia

במדריך זה נשלב את 4 המודלים אותם פיתחנו כדי לפתור את הבעיה של איתור SMS ספאמי בגישה של למידה בצוותא ensemble learning.

את פיתוח המודלים עליהם מבוסס המדריך תיארתי בפירוט במדריכים:

המדריך מניח שעשיתם לפחות שניים מהמדריכים הקודמים ועל כן יש ברשותכם מספר מודלים מאומנים בהם תוכלו להשתמש בשביל למידה בצוותא ensemble learning.

גם אם אין לכם מודלים מאומנים ואתם לא רוצים לקרוא את המדריכים הקודמים עדיין אתם יכולים ללמוד את העיקרון של ensemble learning כי מה שהוא עושה בסך הכל הוא לשלב בין הניבויים של המודלים.

דרך אחת היא לתת משקל שווה לכל מודל, לדוגמה, מקרה של 3 מודלים:

w = 0.33
preds = w * y_pred_model_0 + w * y_pred_model_1 + w * y_pred_model_2

דרך שנייה היא לתת למודלים משקלים שונים. את המשקלים ניתן למצוא באמצעות אלגוריתמים שעושים אופטימיזציה דוגמת Bayesian optimization, ואם מרחב החיפוש מצומצם מספיק grid search תמיד ייתן את התוצאה האופטימלית ביותר.

 

להורדת הקוד אותו נפתח במדריך

 

נייבא את הספריות הדרושות ללמידת מכונה:

import os

import numpy as np
import pandas as pd

import tensorflow as tf
from tensorflow import keras
  • מודול os של פייתון לעבודה עם מערכת הקבצים.
  • Numpy פונקציות מתמטיות ועבודה עם מערכים.
  • Pandas לסידור ולסינון המידע בדומה לגיליון אקסל.
  • ספריית TensorFlow בשביל למידת מכונה. נעבוד עם הספרייה באמצעות ממשק Keras.
  • בהמשך נייבא ספריות נוספות כאשר נצטרך.

 

מסד הנתונים

את הנתונים הדרושים למדריך אחסנתי בדרייב של גוגל Google Drive הפתוח לכל מי שיש לו חשבון גוגל :

BASE_DIR = '/content/gdrive/MyDrive/projects/nlp_sms/'
DATA_DIR = os.path.join(BASE_DIR, 'data')
  • את התיקיות צריך ליצור בתוך הדרייב. בתוכם נשים את המידע הדרוש ללמידת מכונה.

את מסד הנתונים מצאתי באתר התחרויות Kaggle SMS Spam Collection Dataset משם הורדתי אותו למחשב האישי וחילקתי לשלוש תיקיות באמצעות סקריפט (לחץ להורדת הסקריפט) על פי החלוקה המקובלת של הקצאת נתונים לאימון, הערכה ובחינה. שמות התיקיות הם בהתאם: train, val, test. אחרי החלוקה לתיקיות כיווצתי את התיקייה שהכילה את 3 התיקיות ויצרתי קובץ data.zip אותו העלתי לדרייב, שם חילצתי את המידע לתוך התיקייה /content/gdrive/MyDrive/projects/nlp_sms/ באמצעות פקודת unzip:

# when uploading to gdrive the zip file you need
# to specify the destination folder for unzip
!install unzip
!unzip /content/gdrive/MyDrive/projects/nlp_sms/data.zip -d /content/gdrive/MyDrive/projects/nlp_sms/

מבנה התיקיות בתוך הדרייב צריך להיות:

projects/
  nlp_sms/
    data/
      datasets/
        test/
          ham/
          spam/
        train/
          ham/
          spam/
        val/
          ham/
          spam/

נחזיק את הנתיבים לתיקיות בתוך קבועים:

# folder structure
BASE_DIR = '/content/gdrive/MyDrive/projects/nlp_sms/'
DATA_DIR = os.path.join(BASE_DIR, 'data')
 
DATASETS_DIR = os.path.join(DATA_DIR, "datasets")
TRAIN_DIR = os.path.join(DATASETS_DIR, "train")
VAL_DIR = os.path.join(DATASETS_DIR, "val")
TEST_DIR = os.path.join(DATASETS_DIR, "test")

נוודא את מספר הקבצים בתיקיות המשנה:

# validate the folder structure
for category in categories:
   path = os.path.join(TRAIN_DIR, category)
   print(f"TRAIN path {path}")
   file_count = len(os.listdir(path))
   print(f"TRAIN {category} has {file_count} files")
   path = os.path.join(TEST_DIR, category)
   print(f"TEST path {path}")
   file_count = len(os.listdir(path))
   print(f"TEST {category} has {file_count} files")

התוצאה:

TRAIN path /content/gdrive/MyDrive/projects/nlp_sms/data/datasets/train/ham
TRAIN ham has 3378 files
TEST path /content/gdrive/MyDrive/projects/nlp_sms/data/datasets/test/ham
TEST ham has 477 files
TRAIN path /content/gdrive/MyDrive/projects/nlp_sms/data/datasets/train/spam
TRAIN spam has 523 files
TEST path /content/gdrive/MyDrive/projects/nlp_sms/data/datasets/test/spam
TEST spam has 73 files

נגדיר את 2 הקטגוריות של הודעות - תקינות או ספאמיות:

categories = ['ham', 'spam']
NUM_CLASSES = 2

 

עיבוד הנתונים בשביל למידת מכונה pre-processing

נייבא את התיקיות על פי המבנה הדרוש ל- Keras הכולל אצוות batches ומתחשב בקטגוריות:

BATCH_SIZE = 32
train_ds = keras.utils.text_dataset_from_directory(
  TRAIN_DIR,
  label_mode="categorical",
  batch_size=BATCH_SIZE
)
test_ds = keras.utils.text_dataset_from_directory(
  TEST_DIR,
  label_mode="categorical",
  shuffle=False,
  batch_size=BATCH_SIZE
)
Found 3901 files belonging to 2 classes.
Found 550 files belonging to 2 classes.

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

 

וקטוריזציה של הנתונים בשביל מודל bag of words

train_ds = keras.utils.text_dataset_from_directory(
  TRAIN_DIR,
  label_mode="categorical",
  batch_size=BATCH_SIZE
)
test_ds = keras.utils.text_dataset_from_directory(
  TEST_DIR,
  label_mode="categorical",
  shuffle=False,
  batch_size=BATCH_SIZE
)
# prepare a text only dataset
text_only_train_ds_0 = train_ds.map(lambda x, y: x)
 
# use the adapt method to let the adapt method
# learn from the train dataset
text_vectorization_0.adapt(text_only_train_ds_0)
# vectorize the test dataset
vectorized_test_ds_0 = test_ds.map(
  lambda x, y: (text_vectorization_0(x), y))

 

וקטוריזציה של הנתונים בשביל מודל RNN

# vectorization layer
MAX_SEQUENCE_LEN = 38
MAX_TOKENS = 20000
 
text_vectorization_1 = keras.layers.TextVectorization(
  max_tokens=MAX_TOKENS,
  output_mode="int",
  output_sequence_length=MAX_SEQUENCE_LEN,
)
# prepare a text only dataset
text_only_train_ds_1 = train_ds.map(lambda x, y: x)
# the adapt method needs to learn
# to vectorize only on the train dataset
text_vectorization_1.adapt(text_only_train_ds_1)
# vectorize the test dataset
vectorized_test_ds_1 = test_ds.map(
  lambda x, y: (text_vectorization_1(x), y))

 

וקטוריזציה של הנתונים בשביל מודל RNN הנסמך על מרחב הטמעה שהוכן מראש pre-trained word embeddings

כדי להשתמש במרחב הטמעה מסוג Glove כחלק ממודל Keras ראשית נוריד את מסד הנתונים לתיקייה בתוך הדרייב:

GLOVE_DIR = os.path.join(BASE_DIR, "glove")
# download pre-trained GloVe embeddings
!wget -O /content/gdrive/MyDrive/projects/nlp_sms/glove/ https://nlp.stanford.edu/data/glove.6B.zip
!unzip -q glove.6B.zip

נפרוש את הקובץ המכווץ שהורדנו:

!unzip /content/gdrive/MyDrive/projects/nlp_sms/glove/glove.6B.zip -d /content/gdrive/MyDrive/projects/nlp_sms/glove/

ניצור מילון הממפה טוקנים על הוקטורים המייצגים אותם:

# the download contains encoded vectors
# of sizes: 50-dim, 100, 200, 300
# here we use the 100-dim version
# to make a dictionary mapping words to their vector
# representation
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(f"Number of word vectors: {len(embeddings_index)}")
Number of word vectors: 400000

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

MAX_SEQUENCE_LEN = 38
MAX_TOKENS = 20000
 
# vectorization layer
text_vectorization_2 = keras.layers.TextVectorization(
  max_tokens=MAX_TOKENS,
  output_mode="int",
  output_sequence_length=MAX_SEQUENCE_LEN,
)
# prepare a text only dataset
text_only_train_ds_2 = train_ds.map(lambda x, y: x)
# the adapt method needs to learn
# to vectorize only on the train dataset
text_vectorization_2.adapt(text_only_train_ds_2)
# vectorize the test dataset
vectorized_test_ds_2 = test_ds.map(
  lambda x, y: (text_vectorization_2(x), y))
embedding_dim = 100
max_tokens = 7884
 
# get the vocabulary from the TextVectorization method as a dictionary
vocabulary = text_vectorization_2.get_vocabulary()
# reverse the order of the dictionary: mapping from words to indexes
word_index = dict(zip(vocabulary, range(len(vocabulary))))
 
# prepare a matrix to fill the GloVe vectors
embedding_matrix = np.zeros((max_tokens, embedding_dim))
# fill each entry with the corresponding embedding vector, if exists
for word, i in word_index.items():
  if i < max_tokens:
      embedding_vector = embeddings_index.get(word)
  if embedding_vector is not None:
      embedding_matrix[i] = embedding_vector

 

וקטוריזציה של הנתונים בשביל מודל Transformer

נעזר בספריית Transformers בשביל לעבוד עם מודל טרנספורמר מסוג BERT:

!pip install transformers -q
!pip install datasets -q

נתאים את מסד הנתונים לדרישות הספרייה. ראשית על ידי כך שנייבא את הקבצים מהדרייב ונהפוך אותם ל- DataFrame של Pandas:

# make a Pandas dataframe
ls = []
for batch in test_ds:
   msgs = batch[0].numpy()
   ints = batch[1].numpy()
   for idx, item in enumerate(msgs):
       ls.append({'Message': msgs[idx], 'cat_int': ints[idx][1]})
 
df = pd.DataFrame(ls)
 
# decode byte strings into ordinary strings
df["Message"] = df["Message"].str.decode("utf-8")
 
# remove non ascii
df["Message"] = df["Message"].str.encode('ascii', 'ignore').str.decode('ascii')
 
test_dataset = df

נסתמך על ה-DataFrame כדי ליצור מסד נתונים המתאים לדרישות של ספריית Transformers:

# make a dataset matching the Hugging face library requirements
import datasets
from datasets import Dataset, DatasetDict
 
test_ds_3 = Dataset.from_pandas(test_dataset)
dataset = DatasetDict()
 
dataset['test'] = test_ds_3

נבחר במודל "bert-base-uncased":

MODEL_NAME = "bert-base-uncased"

ונעשה טוקניזציה המותאמת למודל שבחרנו:

MAX_SEQ_LEN = 100
 
# tokenize
from transformers import AutoTokenizer
 
tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)
 
# tokenize inside a function
def preprocess_function(examples):
   return tokenizer(examples["Message"], max_length=MAX_SEQ_LEN, truncation=True, padding='max_length')
 
 
# Use the Datasets map function to apply the preprocessing function over the entire dataset
# batched=True to process multiple elements of the dataset at once
tokenized_dataset = dataset.map(preprocess_function, batched=True)
 
 
# Use DataCollatorWithPadding to create a batch of examples. It will also dynamically pad your text to the length
# of the longest element in its batch, so they are a uniform length.
from transformers import DataCollatorWithPadding
 
data_collator = DataCollatorWithPadding(tokenizer=tokenizer, return_tensors="tf")
 
# To fine-tune a model in TensorFlow, start by converting your datasets
# to the tf.data.Dataset format with to_tf_dataset.
 
 
tf_test_dataset = tokenized_dataset["test"].to_tf_dataset(
   columns=["attention_mask", "input_ids"],
   label_cols=["cat_int"],
   shuffle=False,
   batch_size=BATCH_SIZE,
   collate_fn=data_collator,
)

 

המודלים המאומנים

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

TRAINED_MODELS_DIR = os.path.join(BASE_DIR, "trained_models")

שם הקבצים בהם נמצאים המודלים המאומנים:

model_file_names = ["binary_2gram.keras", "nlp_rnn.keras", "nlp_embeddings.keras"]

במודל הרביעי מסוג Transformer נטפל בנפרד.

נטען את המודלים:

# 0. Bag of words
model_0 = keras.models.load_model(os.path.join(TRAINED_MODELS_DIR, model_file_names[0]))
 
# 1. RNN
model_1 = keras.models.load_model(os.path.join(TRAINED_MODELS_DIR, model_file_names[1]))
 
# 2. Word embeddings
model_2 = keras.models.load_model(os.path.join(TRAINED_MODELS_DIR, model_file_names[2]))

נטען ונקמפל את מודל Transformer אותו אמנו במדריך איתור SMS ספאמי באמצעות טכנולוגית Transformer:

# 3. Transformer
 
from transformers import TFAutoModelForSequenceClassification
 
model_3 = TFAutoModelForSequenceClassification.from_pretrained(MODEL_NAME, num_labels=2)
 
# get trained model from drive
MODEL_FILE_NAME = "bert_ckpt"
TRAINED_MODELS_DIR = os.path.join(BASE_DIR, "trained_models")
model_3.load_weights(os.path.join(TRAINED_MODELS_DIR, MODEL_FILE_NAME))
 
 
optimizer = tf.keras.optimizers.Adam(learning_rate=3e-5, epsilon=1e-08, clipnorm=1.0)
loss = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)
metric = tf.keras.metrics.SparseCategoricalAccuracy('accuracy')
model_3.compile(optimizer=optimizer, loss=loss, metrics=[metric])

 

הערכה של כל אחד מהמודלים בנפרד

להערכת המודלים אני משתמש במדד של דיוק accuracy ובודק את מספר הזיהויים השגויים. בדגש על False Positive זיהוי של הודעה לגיטימית כאילו היתה ספאם. כי שגיאה כזו עלולה לגרום להודעות לגיטימיות להגיע להיזרק לפח מה שמשתמשי מערכת המבוססת על המודל לא יאהבו.

from sklearn.metrics import confusion_matrix, accuracy_score, classification_report, f1_score

נעריך את ביצועי המודל Bag of words:

loss, acc = model_0.evaluate(vectorized_test_ds_0)
18/18 [==============================] - 1s 44ms/step - loss: 0.1018 - accuracy: 0.9745

היכן שגה המודל?

y_pred_logits_0 = model_0.predict(vectorized_test_ds_0)
y_pred_0 = np.argmax(y_pred_logits_0, axis=1)
y_actual = []
for bx in test_ds:
   mx = np.argmax(bx[1].numpy(), axis=1)
   y_actual.extend(mx)
 
print(confusion_matrix(y_actual, y_pred_0))
[[477   0]
 [ 14  59]]

 

נעריך את ביצועי המודל RNN:

loss, acc = model_1.evaluate(vectorized_test_ds_1)
18/18 [==============================] - 7s 42ms/step - loss: 0.0894 - accuracy: 0.9709

היכן שגה המודל?

y_pred_logits_0 = model_0.predict(vectorized_test_ds_0)
y_pred_0 = np.argmax(y_pred_logits_0, axis=1)
y_actual = []
for bx in test_ds:
   mx = np.argmax(bx[1].numpy(), axis=1)
   y_actual.extend(mx)
 
print(confusion_matrix(y_actual, y_pred_0))
[[476   1]
 [ 15  58]]

 

נעריך את ביצועי המודל Word embeddings:

loss, acc = model_2.evaluate(vectorized_test_ds_2)
18/18 [==============================] - 5s 48ms/step - loss: 0.0747 - accuracy: 0.9782

היכן שגה המודל?

y_pred_logits_2 = model_2.predict(vectorized_test_ds_2)
y_pred_2 = np.argmax(y_pred_logits_2, axis=1)
y_actual = []
for bx in test_ds:
  mx = np.argmax(bx[1].numpy(), axis=1)
  y_actual.extend(mx)
 
print(confusion_matrix(y_actual, y_pred_2))
[[471   6]
 [  6  67]]

 

נעריך את ביצועי המודל מסוג Transformer:

loss, acc = model_3.evaluate(tf_test_dataset)
18/18 [==============================] - 16s 220ms/step - loss: 0.0394 - accuracy: 0.9927

היכן שגה המודל?

y_pred_logits_3 = model_3.predict(tf_test_dataset)
y_pred_logits_3 = y_pred_logits_3[0]
y_pred_3 = np.argmax(y_pred_logits_3, axis=1)
 
y_actual = []
for bx in tf_test_dataset:
   ax = bx[1].numpy()
   y_actual.extend(ax)
 
print(confusion_matrix(y_actual, y_pred_3))
[[477   0]
 [  4  69]]

 

הטבלה הבאה מסכמת את התוצאות:

False Negative

Accuracy

False Positive

model

19.18%

97.45%

0

Bag of words

20.55%

97.09%

0.21%

RNN

8.22%

97.82%

1.26%

Word embeddings

5.48%

99.27%

0

Transformer

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

רמת הדיוק ושיעור הזיהוי השגוי הנמוך יחסית לא משאירים מקום רב לשיפור. מעניין אם שילוב בין המודלים בגישה של ensemble learning ישפר את התוצאות.

 

למידה בצוותא ensemble learning

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

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

avg_pred_logits = [x + y + z + t for x, y, z, t in zip(y_pred_logits_0, y_pred_logits_1, y_pred_logits_2, y_pred_logits_3)]

נעריך את ביצועי הלמידה בצוותא ensemble learning:

avg_pred = np.argmax(avg_pred_logits, axis=1)
accuracy_score(y_actual, avg_pred)
0.9927272727272727
print(confusion_matrix(y_actual, avg_pred))
[[477   0]
 [  4  69]]
  • ביצועי הלמידה בצוותא ensemble learning טובים כמו המודל הטוב ביותר transformer, למרות שנתנו משקל שווה לכל 4 המודלים בשקלול התוצאות.

 

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

# weights according to estimated successfulness of the models
w0 = 0.05
w1 = 0.15
w2 = 0.2
w3 = 0.6
 
weighted_avg_pred_logits = [w0*x + w1*y + w2*z + w3*t for x, y, z, t in zip(y_pred_logits_0, y_pred_logits_1, y_pred_logits_2, y_pred_logits_3)]

נעריך את ביצועי המודל המשוקלל:

weighted_avg_pred = np.argmax(weighted_avg_pred_logits, axis=1)
accuracy_score(y_actual, weighted_avg_pred)
0.9927272727272727
confusion_matrix(y_actual, weighted_avg_pred)
[[477,   0],
       [  4,  69]]
  • גם במקרה שבו בחרתי את המשקלים משיקולים סובייקטיביים לא ראיתי שיפור בתוצאות.

 

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

from bayes_opt import BayesianOptimization
import time
 
# Bounded region of parameter space
pbounds = {
   'w0': (0.01, 0.99),
   'w1': (0.01, 0.99),
   'w2': (0.01, 0.99),
   'w3': (0.01, 0.99),
}
 
def objective(w0, w1, w2, w3):
   weighted_avg_pred_logits = [w0*x + w1*y + w2*z + w3*t for x, y, z, t in zip(y_pred_logits_0, y_pred_logits_1, y_pred_logits_2, y_pred_logits_3)]
   weighted_avg_pred = np.argmax(weighted_avg_pred_logits, axis=1)
   return accuracy_score(y_actual, weighted_avg_pred)
 
optimizer = BayesianOptimization(
   f=objective,
   pbounds=pbounds,
   verbose=2,
   random_state=42
)
 
start_time = time.time()
optimizer.maximize(init_points=10, n_iter=100)
delta_time = time.time() - start_time
print(optimizer.max)

אחרי 110 איטרציות קבלתי את התוצאה:

{'target': 0.9927272727272727, 'params': {'w0': 0.37704931647041523, 'w1': 0.9417000202817178, 'w2': 0.727354062975177, 'w3': 0.5966853145130959}}
  • דיוק של 99.27% עבור משקלי המודלים המצוינים בפלט.

שימוש בפונקציה optimizer() לא מאפשרת לי לעשות אופטימיזציה ליותר מפרמטר אחד ולכן עשיתי אופטימיזציה רק לרמת הדיוק. אם הייתי רוצה להפחית את רמת ה- False Positive הייתי יכול לקחת כמה עשרות או מאות קומבינציות משקלים הנותנות את התוצאה הטובה ביותר ולבחון איזו קומבינציה גם מצטיינת בשיעור Error Type 1 נמוך ביותר.

 

בשלב זה, פניתי לחיפוש רשת Grid search של המשקלים הטובים ביותר. ראשית, יצרתי 256 קומבינציות של משקלים ועבור כל קומבינציה מצאתי את רמת הדיוק ושיעור הטעות מסוג 1.

def getWeightedRes(w0, w1, w2, w3):
   weighted_avg_pred_logits = [w0*x + w1*y + w2*z + w3*t for x, y, z, t in zip(y_pred_logits_0, y_pred_logits_1, y_pred_logits_2, y_pred_logits_3)]
   weighted_avg_pred = np.argmax(weighted_avg_pred_logits, axis=1)
   acc = accuracy_score(y_actual, weighted_avg_pred)
   fp = confusion_matrix(y_actual, weighted_avg_pred)[0][1]
   fn = confusion_matrix(y_actual, weighted_avg_pred)[1][0]
   return {'w0': w0, 'w1': w1, 'w2': w2, 'w3': w3, 'acc': acc, 'fp': fp, 'fn': fn}
 
results = []
weights = np.array([0, 1, 10, 89])/100
for w0 in weights:
 for w1 in weights:
   for w2 in weights:
     for w3 in weights:
         results.append(getWeightedRes(w0, w1, w2, w3))
 
df = pd.DataFrame(results)
 
print(df)

בתהליך נוצרו 256 קומבינציות של משקלים בתוך DataFrame.

סידרתי את התוצאות לפי שיעור ה-False Positive והדיוק, והרכב המשקלים המוביל שקיבלתי היה:

df.sort_values(['fp','acc','fn'], ascending=[True,False,True])
# weights
w0 = 0.01
w1 = 0
w2 = 0.89
w3 = 0.10

נעריך את התוצאה:

0.9945454545454545
[[477   0]
 [  3  70]]
  • אכן אחד השילובים שיפר את מידת הדיוק והפחית את מספר ה-Type 1 error תוך השארת ה-Type 2 error על 0.

 

להורדת הקוד אותו פיתחנו במדריך

סיכום

הראנו שהשיטה של למידה בצוותא ensemble learning עובדת. למרות ששילבנו מודל מוצלח מאוד (99.27% אחוזי דיוק) עם שלושה מודלים פחות מוצלחים ממנו עדיין קיבלנו תוצאות מוצלחות אפילו יותר (99.45% אחוזי דיוק) .

 

אולי גם זה יעניין אותך

איתור SMS ספאמי באמצעות טכנולוגית Transformer

זיהוי SMS ספאמי בעזרת RNN ומרחב הטמעה שאומן מראש

זיהוי SMS ספאמי באמצעות מודל RNN

זיהוי SMS ספאמי באמצעות מודל RNN

 

מדריך למידת מכונה

 

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

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

 

 

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

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

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

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

השימוש שלך באתר מהווה ראייה להסכמתך עם הכללים והתקנות שנוסחו בהסכם תנאי השימוש.

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

 

 

ענה על השאלה הפשוטה הבאה כתנאי להוספת תגובה:

דג למים הוא כמו ציפור ל...?