العرض على ai.google.dev | تجربة ورقة ملاحظات Colab | الاطّلاع على ورقة الملاحظات على GitHub |
نظرة عامة
ستتعرّف في هذا الدفتر على كيفية استخدام التضمينات التي أنشأتها واجهة برمجة التطبيقات Gemini API لتدريب نموذج يمكنه تصنيف أنواع مختلفة من مشاركات مجموعات الأخبار استنادًا إلى الموضوع.
سوف تدرِّب أحد المصنِّفات في هذا البرنامج التعليمي على التنبؤ بالفئة التي تنتمي إليها المشاركة في مجموعة أخبار.
المتطلبات الأساسية
يمكنك تشغيل دليل البدء السريع هذا في Google Colab.
لإكمال هذه البدء السريع في بيئة التطوير الخاصة بك، تأكد من أن بيئتك تفي بالمتطلبات التالية:
- Python 3.9+
- يجب تثبيت
jupyter
لتشغيل ورقة الملاحظات.
ضبط إعدادات الجهاز
أولاً، عليك تنزيل مكتبة Gemini API Python وتثبيتها.
pip install -U -q google.generativeai
import re
import tqdm
import keras
import numpy as np
import pandas as pd
import google.generativeai as genai
# Used to securely store your API key
from google.colab import userdata
import seaborn as sns
import matplotlib.pyplot as plt
from keras import layers
from matplotlib.ticker import MaxNLocator
from sklearn.datasets import fetch_20newsgroups
import sklearn.metrics as skmetrics
الحصول على مفتاح واجهة برمجة التطبيقات
لكي تتمكّن من استخدام Gemini API، يجب أولاً الحصول على مفتاح واجهة برمجة تطبيقات. إذا لم يكن لديك مفتاح، يمكنك إنشاء مفتاح بنقرة واحدة في Google AI Studio.
الحصول على مفتاح واجهة برمجة التطبيقات
في Colab، أضِف المفتاح إلى مدير المفاتيح السرّية ضمن "🔑". في اللوحة اليمنى. أدخِل الاسم API_KEY
.
بعد حصولك على مفتاح واجهة برمجة التطبيقات، أرسِله إلى حزمة تطوير البرامج (SDK). هناك طريقتان لإجراء ذلك:
- ضَع المفتاح في متغيّر البيئة
GOOGLE_API_KEY
(ستتولى حزمة تطوير البرامج (SDK) استلامه تلقائيًا من هناك). - تمرير المفتاح إلى
genai.configure(api_key=...)
genai.configure(api_key=GOOGLE_API_KEY)
for m in genai.list_models():
if 'embedContent' in m.supported_generation_methods:
print(m.name)
models/embedding-001 models/embedding-001
مجموعة البيانات
تضم مجموعة البيانات النصية لـ 20 مجموعة إخبارية 18,000 مجموعة إخبارية حول 20 موضوعًا مقسّمًا إلى مجموعات تدريب واختبار. يعتمد التقسيم بين مجموعات بيانات التدريب والاختبار على الرسائل المنشورة قبل وبعد تاريخ محدد. في هذا البرنامج التعليمي، ستستخدم المجموعات الفرعية من مجموعات بيانات التدريب والاختبار. ستقوم بمعالجة البيانات مسبقًا وتنظيمها في إطارات بيانات Pandas.
newsgroups_train = fetch_20newsgroups(subset='train')
newsgroups_test = fetch_20newsgroups(subset='test')
# View list of class names for dataset
newsgroups_train.target_names
['alt.atheism', 'comp.graphics', 'comp.os.ms-windows.misc', 'comp.sys.ibm.pc.hardware', 'comp.sys.mac.hardware', 'comp.windows.x', 'misc.forsale', 'rec.autos', 'rec.motorcycles', 'rec.sport.baseball', 'rec.sport.hockey', 'sci.crypt', 'sci.electronics', 'sci.med', 'sci.space', 'soc.religion.christian', 'talk.politics.guns', 'talk.politics.mideast', 'talk.politics.misc', 'talk.religion.misc']
في ما يلي مثال على ما تبدو عليه نقطة البيانات من مجموعة التطبيق.
idx = newsgroups_train.data[0].index('Lines')
print(newsgroups_train.data[0][idx:])
Lines: 15 I was wondering if anyone out there could enlighten me on this car I saw the other day. It was a 2-door sports car, looked to be from the late 60s/ early 70s. It was called a Bricklin. The doors were really small. In addition, the front bumper was separate from the rest of the body. This is all I know. If anyone can tellme a model name, engine specs, years of production, where this car is made, history, or whatever info you have on this funky looking car, please e-mail. Thanks, - IL ---- brought to you by your neighborhood Lerxst ----
ستبدأ الآن في معالجة البيانات مسبقًا لهذا البرنامج التعليمي. أزِل أي معلومات حسّاسة مثل الأسماء أو عناوين البريد الإلكتروني أو الأجزاء المكرّرة من النص، مثل "From: "
و"\nSubject: "
. نظّم المعلومات في إطار بيانات Pandas بحيث تكون أكثر قابلية للقراءة.
def preprocess_newsgroup_data(newsgroup_dataset):
# Apply functions to remove names, emails, and extraneous words from data points in newsgroups.data
newsgroup_dataset.data = [re.sub(r'[\w\.-]+@[\w\.-]+', '', d) for d in newsgroup_dataset.data] # Remove email
newsgroup_dataset.data = [re.sub(r"\([^()]*\)", "", d) for d in newsgroup_dataset.data] # Remove names
newsgroup_dataset.data = [d.replace("From: ", "") for d in newsgroup_dataset.data] # Remove "From: "
newsgroup_dataset.data = [d.replace("\nSubject: ", "") for d in newsgroup_dataset.data] # Remove "\nSubject: "
# Cut off each text entry after 5,000 characters
newsgroup_dataset.data = [d[0:5000] if len(d) > 5000 else d for d in newsgroup_dataset.data]
# Put data points into dataframe
df_processed = pd.DataFrame(newsgroup_dataset.data, columns=['Text'])
df_processed['Label'] = newsgroup_dataset.target
# Match label to target name index
df_processed['Class Name'] = ''
for idx, row in df_processed.iterrows():
df_processed.at[idx, 'Class Name'] = newsgroup_dataset.target_names[row['Label']]
return df_processed
# Apply preprocessing function to training and test datasets
df_train = preprocess_newsgroup_data(newsgroups_train)
df_test = preprocess_newsgroup_data(newsgroups_test)
df_train.head()
بعد ذلك، ستقوم بعمل عينة من بعض البيانات عن طريق أخذ 100 نقطة بيانات في مجموعة بيانات التدريب، وإسقاط بعض الفئات لتشغيلها من خلال هذا البرنامج التعليمي. اختيار فئات العلوم التي تريد مقارنتها.
def sample_data(df, num_samples, classes_to_keep):
df = df.groupby('Label', as_index = False).apply(lambda x: x.sample(num_samples)).reset_index(drop=True)
df = df[df['Class Name'].str.contains(classes_to_keep)]
# Reset the encoding of the labels after sampling and dropping certain categories
df['Class Name'] = df['Class Name'].astype('category')
df['Encoded Label'] = df['Class Name'].cat.codes
return df
TRAIN_NUM_SAMPLES = 100
TEST_NUM_SAMPLES = 25
CLASSES_TO_KEEP = 'sci' # Class name should contain 'sci' in it to keep science categories
df_train = sample_data(df_train, TRAIN_NUM_SAMPLES, CLASSES_TO_KEEP)
df_test = sample_data(df_test, TEST_NUM_SAMPLES, CLASSES_TO_KEEP)
df_train.value_counts('Class Name')
Class Name sci.crypt 100 sci.electronics 100 sci.med 100 sci.space 100 dtype: int64
df_test.value_counts('Class Name')
Class Name sci.crypt 25 sci.electronics 25 sci.med 25 sci.space 25 dtype: int64
إنشاء التضمينات
ستتعرّف في هذا القسم على كيفية إنشاء تضمينات لجزء من النص باستخدام التضمينات من Gemini API. لمزيد من المعلومات حول التضمينات، يُرجى زيارة دليل التضمين.
تغييرات واجهة برمجة التطبيقات على عمليات التضمين -001
في نموذج التضمينات الجديد، هناك مَعلمة جديدة لنوع المهمة وعنوان اختياري (صالحان فقط مع نوع المهمة=RETRIEVAL_DOCUMENT
).
تنطبق هذه المعلمات الجديدة فقط على أحدث نماذج التضمينات.وأنواع المهام هي:
نوع المهمّة | الوصف |
---|---|
RETRIEVAL_QUERY | لتحديد أن النص المقدم هو طلب بحث في إعداد البحث/الاسترجاع. |
RETRIEVAL_DOCUMENT | لتحديد أن النص المحدّد هو مستند في إعداد البحث/الاسترجاع. |
SEMANTIC_SIMILARITY | لتحديد أنه سيتم استخدام النص المحدّد في التشابه النصي الدلالي (STS). |
التصنيف | لتحديد أن التضمينات سيتم استخدامها للتصنيف. |
التصنيف | لتحديد أن التضمينات سيتم استخدامها للتجميع العنقودي. |
from tqdm.auto import tqdm
tqdm.pandas()
from google.api_core import retry
def make_embed_text_fn(model):
@retry.Retry(timeout=300.0)
def embed_fn(text: str) -> list[float]:
# Set the task_type to CLASSIFICATION.
embedding = genai.embed_content(model=model,
content=text,
task_type="classification")
return embedding['embedding']
return embed_fn
def create_embeddings(model, df):
df['Embeddings'] = df['Text'].progress_apply(make_embed_text_fn(model))
return df
model = 'models/embedding-001'
df_train = create_embeddings(model, df_train)
df_test = create_embeddings(model, df_test)
0%| | 0/400 [00:00<?, ?it/s] 0%| | 0/100 [00:00<?, ?it/s]
df_train.head()
إنشاء نموذج تصنيف بسيط
ستقوم هنا بتعريف نموذج بسيط بطبقة واحدة مخفية وناتج احتمالية من فئة واحدة. يتجاوب التوقع مع احتمالية كون جزء من النص فئة معينة من الأخبار. عند إنشاء نموذجك، سيعمل Keras تلقائيًا على ترتيب نقاط البيانات عشوائيًا.
def build_classification_model(input_size: int, num_classes: int) -> keras.Model:
inputs = x = keras.Input(input_size)
x = layers.Dense(input_size, activation='relu')(x)
x = layers.Dense(num_classes, activation='sigmoid')(x)
return keras.Model(inputs=[inputs], outputs=x)
# Derive the embedding size from the first training element.
embedding_size = len(df_train['Embeddings'].iloc[0])
# Give your model a different name, as you have already used the variable name 'model'
classifier = build_classification_model(embedding_size, len(df_train['Class Name'].unique()))
classifier.summary()
classifier.compile(loss = keras.losses.SparseCategoricalCrossentropy(from_logits=True),
optimizer = keras.optimizers.Adam(learning_rate=0.001),
metrics=['accuracy'])
Model: "model" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= input_1 (InputLayer) [(None, 768)] 0 dense (Dense) (None, 768) 590592 dense_1 (Dense) (None, 4) 3076 ================================================================= Total params: 593668 (2.26 MB) Trainable params: 593668 (2.26 MB) Non-trainable params: 0 (0.00 Byte) _________________________________________________________________
embedding_size
768
تدريب النموذج لتصنيف المجموعات الإخبارية
وأخيرًا، يمكنك تدريب نموذج بسيط. استخدام عدد صغير من الحقبات لتجنب الإفراط في التوافق. وتستغرق الحقبة الأولى وقتًا أطول بكثير من غيرها، لأنّه يجب احتساب التضمينات مرّة واحدة فقط.
NUM_EPOCHS = 20
BATCH_SIZE = 32
# Split the x and y components of the train and validation subsets.
y_train = df_train['Encoded Label']
x_train = np.stack(df_train['Embeddings'])
y_val = df_test['Encoded Label']
x_val = np.stack(df_test['Embeddings'])
# Train the model for the desired number of epochs.
callback = keras.callbacks.EarlyStopping(monitor='accuracy', patience=3)
history = classifier.fit(x=x_train,
y=y_train,
validation_data=(x_val, y_val),
callbacks=[callback],
batch_size=BATCH_SIZE,
epochs=NUM_EPOCHS,)
Epoch 1/20 /usr/local/lib/python3.10/dist-packages/keras/src/backend.py:5729: UserWarning: "`sparse_categorical_crossentropy` received `from_logits=True`, but the `output` argument was produced by a Softmax activation and thus does not represent logits. Was this intended? output, from_logits = _get_logits( 13/13 [==============================] - 1s 30ms/step - loss: 1.2141 - accuracy: 0.6675 - val_loss: 0.9801 - val_accuracy: 0.8800 Epoch 2/20 13/13 [==============================] - 0s 12ms/step - loss: 0.7580 - accuracy: 0.9400 - val_loss: 0.6061 - val_accuracy: 0.9300 Epoch 3/20 13/13 [==============================] - 0s 13ms/step - loss: 0.4249 - accuracy: 0.9525 - val_loss: 0.3902 - val_accuracy: 0.9200 Epoch 4/20 13/13 [==============================] - 0s 13ms/step - loss: 0.2561 - accuracy: 0.9625 - val_loss: 0.2597 - val_accuracy: 0.9400 Epoch 5/20 13/13 [==============================] - 0s 13ms/step - loss: 0.1693 - accuracy: 0.9700 - val_loss: 0.2145 - val_accuracy: 0.9300 Epoch 6/20 13/13 [==============================] - 0s 13ms/step - loss: 0.1240 - accuracy: 0.9850 - val_loss: 0.1801 - val_accuracy: 0.9600 Epoch 7/20 13/13 [==============================] - 0s 21ms/step - loss: 0.0931 - accuracy: 0.9875 - val_loss: 0.1623 - val_accuracy: 0.9400 Epoch 8/20 13/13 [==============================] - 0s 16ms/step - loss: 0.0736 - accuracy: 0.9925 - val_loss: 0.1418 - val_accuracy: 0.9600 Epoch 9/20 13/13 [==============================] - 0s 20ms/step - loss: 0.0613 - accuracy: 0.9925 - val_loss: 0.1315 - val_accuracy: 0.9700 Epoch 10/20 13/13 [==============================] - 0s 20ms/step - loss: 0.0479 - accuracy: 0.9975 - val_loss: 0.1235 - val_accuracy: 0.9600 Epoch 11/20 13/13 [==============================] - 0s 19ms/step - loss: 0.0399 - accuracy: 0.9975 - val_loss: 0.1219 - val_accuracy: 0.9700 Epoch 12/20 13/13 [==============================] - 0s 21ms/step - loss: 0.0326 - accuracy: 0.9975 - val_loss: 0.1158 - val_accuracy: 0.9700 Epoch 13/20 13/13 [==============================] - 0s 19ms/step - loss: 0.0263 - accuracy: 1.0000 - val_loss: 0.1127 - val_accuracy: 0.9700 Epoch 14/20 13/13 [==============================] - 0s 17ms/step - loss: 0.0229 - accuracy: 1.0000 - val_loss: 0.1123 - val_accuracy: 0.9700 Epoch 15/20 13/13 [==============================] - 0s 20ms/step - loss: 0.0195 - accuracy: 1.0000 - val_loss: 0.1063 - val_accuracy: 0.9700 Epoch 16/20 13/13 [==============================] - 0s 17ms/step - loss: 0.0172 - accuracy: 1.0000 - val_loss: 0.1070 - val_accuracy: 0.9700
تقييم أداء النموذج
استخدام Keras
Model.evaluate
لمعرفة فقدان مجموعة بيانات الاختبار ودقتها.
classifier.evaluate(x=x_val, y=y_val, return_dict=True)
4/4 [==============================] - 0s 4ms/step - loss: 0.1070 - accuracy: 0.9700 {'loss': 0.10700511932373047, 'accuracy': 0.9700000286102295}
تتمثل إحدى طرق تقييم أداء النموذج في تصور أداء المصنِّف. استخدِم plot_history
للاطّلاع على مؤشرات الخسارة والدقة على مدار العصور.
def plot_history(history):
"""
Plotting training and validation learning curves.
Args:
history: model history with all the metric measures
"""
fig, (ax1, ax2) = plt.subplots(1,2)
fig.set_size_inches(20, 8)
# Plot loss
ax1.set_title('Loss')
ax1.plot(history.history['loss'], label = 'train')
ax1.plot(history.history['val_loss'], label = 'test')
ax1.set_ylabel('Loss')
ax1.set_xlabel('Epoch')
ax1.legend(['Train', 'Validation'])
# Plot accuracy
ax2.set_title('Accuracy')
ax2.plot(history.history['accuracy'], label = 'train')
ax2.plot(history.history['val_accuracy'], label = 'test')
ax2.set_ylabel('Accuracy')
ax2.set_xlabel('Epoch')
ax2.legend(['Train', 'Validation'])
plt.show()
plot_history(history)
هناك طريقة أخرى لعرض أداء النموذج تتجاوز مجرد قياس الخسارة والدقة وذلك باستخدام مصفوفة التشويش. وتتيح لك مصفوفة التشويش تقييم أداء نموذج التصنيف بطريقة تتجاوز الدقة. يمكنك الاطّلاع على النقاط التي تم تصنيفها عن طريق الخطأ. ولإنشاء مصفوفة التشويش لمشكلة التصنيف متعدد الفئات هذه، احصل على القيم الفعلية في مجموعة الاختبار والقيم المتنبأ بها.
ابدأ بإنشاء الفئة المتوقعة لكل مثال في مجموعة التحقق من الصحة باستخدام Model.predict()
.
y_hat = classifier.predict(x=x_val)
y_hat = np.argmax(y_hat, axis=1)
4/4 [==============================] - 0s 4ms/step
labels_dict = dict(zip(df_test['Class Name'], df_test['Encoded Label']))
labels_dict
{'sci.crypt': 0, 'sci.electronics': 1, 'sci.med': 2, 'sci.space': 3}
cm = skmetrics.confusion_matrix(y_val, y_hat)
disp = skmetrics.ConfusionMatrixDisplay(confusion_matrix=cm,
display_labels=labels_dict.keys())
disp.plot(xticks_rotation='vertical')
plt.title('Confusion matrix for newsgroup test dataset');
plt.grid(False)
الخطوات التالية
لمزيد من المعلومات حول كيفية استخدام التضمينات، اطّلِع على هذه الفيديوهات التعليمية الأخرى: