1. قبل البدء
في هذا الدرس التطبيقي حول الترميز، ستعدّل التطبيق الذي أنشأته في الدروس التطبيقية السابقة حول الترميز بعنوان "البدء في تصنيف النصوص على الأجهزة الجوّالة".
المتطلبات الأساسية
- تم تصميم هذا الدرس التطبيقي حول الترميز للمطوّرين ذوي الخبرة الذين لا يملكون خبرة في تعلُّم الآلة.
- هذا الدرس التطبيقي حول الترميز هو جزء من مسار تعليمي متسلسل. إذا لم تكن قد أكملت بعد إحدى ورشتَي العمل "إنشاء تطبيق أساسي لأسلوب المراسلة" أو "إنشاء نموذج تعلُّم آلي للتعرّف على التعليقات غير المرغوب فيها"، يُرجى التوقّف وإكمالها الآن.
ما [ستنشئه أو ستتعلمه]
- ستتعرّف على كيفية دمج النموذج المخصّص في تطبيقك الذي تم إنشاؤه في الخطوات السابقة.
المتطلبات
- استوديو Android أو CocoaPods لأجهزة iOS
2. فتح تطبيق Android الحالي
يمكنك الحصول على الرمز البرمجي لذلك باتّباع الدرس التطبيقي حول الترميز 1، أو عن طريق استنساخ مستودع هذا وتحميل التطبيق من TextClassificationStep1.
git clone https://github.com/googlecodelabs/odml-pathways
يمكنك العثور على هذا المسار في TextClassificationOnMobile->Android.
يتوفّر لك أيضًا الرمز تمت باسم TextClassificationStep2.
بعد فتحها، يمكنك الانتقال إلى الخطوة 2.
3- استيراد ملف النموذج والبيانات الوصفية
في برنامج Build a comment spam machine learning model التدريبي، أنشأت نموذج .TFLITE.
يجب أن تكون قد نزّلت ملف النموذج. إذا لم يكن لديك، يمكنك الحصول عليه من مستودع هذا الدرس العملي، ويتوفّر النموذج هنا.
أضِفها إلى مشروعك من خلال إنشاء مجلّد الموارد.
- باستخدام "مستكشف المشروع"، تأكَّد من اختيار Android في أعلى الصفحة.
- انقر بزر الماوس الأيمن على مجلد التطبيق. انقر على جديد > دليل.

- في مربّع الحوار دليل جديد، اختَر src/main/assets.

سيظهر لك الآن مجلد مواد العرض جديد في التطبيق.

- انقر بزر الماوس الأيمن على مواد العرض.
- في القائمة التي تفتح، سيظهر لك (على جهاز Mac) العرض في الباحث (Finder). اختَرها. (في نظام التشغيل Windows، سيظهر الخيار عرض في المستكشف، وفي نظام التشغيل Ubuntu، سيظهر الخيار عرض في الملفات).

سيتم تشغيل الباحث (Finder) لعرض موقع الملفات (مستكشف الملفات (File Explorer) على نظام التشغيل Windows، والملفات (Files) على نظام التشغيل Linux).
- انسخ الملفات
labels.txtوmodel.tfliteوvocabإلى هذا الدليل.

- ارجع إلى استوديو Android، وستظهر لك هذه الملفات في مجلد مواد العرض.

4. تعديل ملف build.gradle لاستخدام TensorFlow Lite
لاستخدام TensorFlow Lite ومكتبات مهام TensorFlow Lite المتوافقة معه، عليك تعديل ملف build.gradle.
تحتوي مشاريع Android غالبًا على أكثر من ملف واحد، لذا احرص على العثور على الملف على مستوى التطبيق. في "مستكشف المشاريع" في "طريقة عرض Android"، ابحث عنه في قسم برامج Gradle النصية. سيتم تصنيف التطبيق الصحيح باستخدام .app كما هو موضّح هنا:

عليك إجراء تغييرَين على هذا الملف. يظهر الأول في قسم التبعيات في أسفل الصفحة. أضِف نصًا implementation لمكتبة مهام TensorFlow Lite، على النحو التالي:
implementation 'org.tensorflow:tensorflow-lite-task-text:0.1.0'
قد يكون رقم الإصدار قد تغيّر منذ كتابة هذا المستند، لذا احرص على مراجعة https://www.tensorflow.org/lite/inference_with_metadata/task_library/nl_classifier للحصول على أحدث المعلومات.
تتطلّب مكتبات المهام أيضًا توفُّر الإصدار 21 من حزمة تطوير البرامج (SDK) كحد أدنى. يمكنك العثور على هذا الإعداد في android > default config، وتغييره إلى 21:

أصبحت لديك الآن جميع التبعيات، لذا حان وقت البدء في كتابة الرمز.
5- إضافة فئة مساعدة
لفصل منطق الاستنتاج، حيث يستخدم تطبيقك النموذج، عن واجهة المستخدم، أنشئ فئة أخرى للتعامل مع استنتاج النموذج. يمكنك تسمية هذا النوع من الفئات "فئة مساعدة".
- انقر بزر الماوس الأيمن على اسم الحزمة التي يتضمّنها رمز
MainActivity. - انقر على جديد > حزمة.

- سيظهر مربّع حوار في وسط الشاشة يطلب منك إدخال اسم الحزمة. أضِفها في نهاية اسم الحزمة الحالي. (يُطلق عليها هنا اسم المساعدون).

- بعد الانتهاء من ذلك، انقر بزر الماوس الأيمن على مجلد helpers في "مستكشف المشروع".
- انقر على جديد > فئة Java، وأطلِق عليها اسم
TextClassificationClient. ستعدّل الملف في الخطوة التالية.
ستبدو فئة TextClassificationClient المساعدة على النحو التالي (مع العلم أنّ اسم الحزمة قد يكون مختلفًا).
package com.google.devrel.textclassificationstep1.helpers;
public class TextClassificationClient {
}
- عدِّل الملف باستخدام الرمز التالي:
package com.google.devrel.textclassificationstep2.helpers;
import android.content.Context;
import android.util.Log;
import java.io.IOException;
import java.util.List;
import org.tensorflow.lite.support.label.Category;
import org.tensorflow.lite.task.text.nlclassifier.NLClassifier;
public class TextClassificationClient {
private static final String MODEL_PATH = "model.tflite";
private static final String TAG = "CommentSpam";
private final Context context;
NLClassifier classifier;
public TextClassificationClient(Context context) {
this.context = context;
}
public void load() {
try {
classifier = NLClassifier.createFromFile(context, MODEL_PATH);
} catch (IOException e) {
Log.e(TAG, e.getMessage());
}
}
public void unload() {
classifier.close();
classifier = null;
}
public List<Category> classify(String text) {
List<Category> apiResults = classifier.classify(text);
return apiResults;
}
}
سيوفر هذا الصف برنامج تضمين لمترجم TensorFlow Lite، مع تحميل النموذج وتجريد تعقيد إدارة تبادل البيانات بين تطبيقك والنموذج.
في طريقة load()، سيتم إنشاء نوع NLClassifier جديد من مسار النموذج. مسار النموذج هو ببساطة اسم النموذج، model.tflite. يشكّل النوع NLClassifier جزءًا من مكتبات مهام النصوص، ويساعدك من خلال تحويل السلسلة إلى رموز مميزة، واستخدام طول التسلسل الصحيح، وتمريرها إلى النموذج، وتحليل النتائج.
(لمزيد من التفاصيل حول هذه الخطوات، يُرجى الرجوع إلى مقالة إنشاء نموذج تعلُّم آلي للتعليقات غير المرغوب فيها).
يتم إجراء التصنيف في طريقة التصنيف، حيث يتم تمرير سلسلة إليها، وستعرض List. عند استخدام نماذج تعلُّم الآلة لتصنيف المحتوى الذي تريد تحديد ما إذا كانت السلسلة غير مرغوب فيها أم لا، من الشائع عرض جميع الإجابات مع الاحتمالات المحدّدة. على سبيل المثال، إذا أرسلت إليها رسالة تبدو كرسالة غير مرغوب فيها، ستتلقّى قائمة تتضمّن إجابتَين، إحداهما تتضمّن احتمال أن تكون الرسالة غير مرغوب فيها، والأخرى تتضمّن احتمال ألا تكون كذلك. المحتوى غير المرغوب فيه/المحتوى غير غير المرغوب فيه هما فئتان، لذا سيتضمّن الرمز List الذي يتم عرضه هذه الاحتمالات. ستحلّل ذلك لاحقًا.
بعد الحصول على فئة المساعد، ارجع إلى MainActivity وعدِّله لاستخدامها في تصنيف النص. ستظهر لك في الخطوة التالية.
6. تصنيف النص
في ملف MainActivity، عليك أولاً استيراد الدوال المساعدة التي أنشأتها للتو.
- في أعلى
MainActivity.kt، أضِف ما يلي مع عمليات الاستيراد الأخرى:
import com.google.devrel.textclassificationstep2.helpers.TextClassificationClient
import org.tensorflow.lite.support.label.Category
- بعد ذلك، عليك تحميل الدوال المساعدة. في
onCreate، أضِف الأسطر التالية لإنشاء مثيل لفئة المساعد وتحميلها، وذلك مباشرةً بعد السطرsetContentView:
val client = TextClassificationClient(applicationContext)
client.load()
في الوقت الحالي، من المفترض أن يبدو onClickListener الزر على النحو التالي:
btnSendText.setOnClickListener {
var toSend:String = txtInput.text.toString()
txtOutput.text = toSend
}
- عدِّله ليصبح على النحو التالي:
btnSendText.setOnClickListener {
var toSend:String = txtInput.text.toString()
var results:List<Category> = client.classify(toSend)
val score = results[1].score
if(score>0.8){
txtOutput.text = "Your message was detected as spam with a score of " + score.toString() + " and not sent!"
} else {
txtOutput.text = "Message sent! \nSpam score was:" + score.toString()
}
txtInput.text.clear()
}
يؤدي ذلك إلى تغيير الوظيفة من مجرد إخراج ما أدخله المستخدم إلى تصنيفه أولاً.
- باستخدام هذا السطر، ستأخذ السلسلة التي أدخلها المستخدم وتمرّرها إلى النموذج، وستحصل على النتائج:
var results:List<Category> = client.classify(toSend)
هناك فئتان فقط، False وTrue
. (يرتّب TensorFlow القيم أبجديًا، لذا ستكون القيمة False هي العنصر 0، والقيمة True هي العنصر 1).
- للحصول على نتيجة احتمال أن تكون القيمة
True، يمكنك الاطّلاع على results[1].score على النحو التالي:
val score = results[1].score
- اختيار قيمة الحدّ (0.8 في هذه الحالة)، حيث تحدّد أنّه إذا كانت نتيجة الفئة "صحيح" أعلى من قيمة الحدّ (0.8)، تكون الرسالة غير مرغوب فيها. بخلاف ذلك، لن تكون الرسالة غير مرغوب فيها ويمكن إرسالها بأمان:
if(score>0.8){
txtOutput.text = "Your message was detected as spam with a score of " + score.toString() + " and not sent!"
} else {
txtOutput.text = "Message sent! \nSpam score was:" + score.toString()
}
- يمكنك الاطّلاع على النموذج عمليًا هنا. تم وضع علامة على الرسالة "يمكنك شراء منتجات من مدونتي" باعتبارها غير مرغوب فيها:

في المقابل، كانت الرسالة "مرحبًا، برنامج تعليمي ممتع، شكرًا" منخفضة الاحتمالية جدًا لأن تكون رسالة غير مرغوب فيها:

7. تحديث تطبيق iOS لاستخدام نموذج TensorFlow Lite
يمكنك الحصول على الرمز البرمجي لذلك باتّباع الدرس التطبيقي حول الترميز 1، أو عن طريق استنساخ مستودع هذا وتحميل التطبيق من TextClassificationStep1. يمكنك العثور على هذا المسار في TextClassificationOnMobile->iOS.
يتوفّر لك أيضًا الرمز تمت باسم TextClassificationStep2.
في درس تطبيقي حول الترميز Build a comment spam machine learning model، أنشأت تطبيقًا بسيطًا جدًا يتيح للمستخدم كتابة رسالة في UITextView ثم تمريرها إلى الناتج بدون أي فلترة.
سنعدّل هذا التطبيق الآن لاستخدام نموذج TensorFlow Lite لرصد التعليقات غير المرغوب فيها في النص قبل إرساله. ما عليك سوى محاكاة عملية الإرسال في هذا التطبيق من خلال عرض النص في تصنيف الإخراج (ولكن قد يحتوي تطبيق حقيقي على لوحة إعلانات أو محادثة أو شيء مشابه).
للبدء، ستحتاج إلى التطبيق من الخطوة 1، والذي يمكنك استنساخه من مستودع الرموز.
لاستخدام TensorFlow Lite، عليك استخدام CocoaPods. إذا لم تكن هذه الأدوات مثبّتة من قبل، يمكنك تثبيتها باتّباع التعليمات الواردة في https://cocoapods.org/.
- بعد تثبيت CocoaPods، أنشئ ملفًا باسم Podfile في الدليل نفسه الذي يحتوي على
.xcprojectلتطبيق TextClassification. يجب أن يبدو محتوى هذا الملف على النحو التالي:
target 'TextClassificationStep2' do
use_frameworks!
# Pods for NLPClassifier
pod 'TensorFlowLiteSwift'
end
يجب أن يكون اسم تطبيقك في السطر الأول بدلاً من "TextClassificationStep2".
باستخدام "الوحدة الطرفية"، انتقِل إلى هذا الدليل وشغِّل pod install. في حال نجاح العملية، سيتم إنشاء دليل جديد باسم Pods، وملف جديد باسم .xcworkspace. ستستخدِم هذا الرمز في المستقبل بدلاً من .xcproject.
إذا تعذّر ذلك، يُرجى التأكّد من توفّر ملف Podfile في الدليل نفسه الذي كان يتضمّن .xcproject. عادةً ما يكون السبب الرئيسي هو ملف podfile في الدليل الخاطئ أو اسم الهدف الخاطئ.
8. إضافة ملفات النموذج والمفردات
عند إنشاء النموذج باستخدام أداة TensorFlow Lite Model Maker، كان بإمكانك إخراج النموذج (بتنسيق model.tflite) والمفردات (بتنسيق vocab.txt).
- أضِفها إلى مشروعك عن طريق سحبها وإفلاتها من Finder في نافذة مشروعك. تأكَّد من وضع علامة في المربّع بجانب الإضافة إلى الاستهدافات:

عند الانتهاء، من المفترض أن تظهر لك في مشروعك:

- تأكَّد من إضافتها إلى الحزمة (كي يتم نشرها على أحد الأجهزة) من خلال اختيار مشروعك (في لقطة الشاشة أعلاه، الرمز الأزرق TextClassificationStep2)، والاطّلاع على علامة التبويب مراحل الإنشاء:

9- تحميل المفردات
عند إجراء تصنيف باستخدام معالجة اللغة الطبيعية، يتم تدريب النموذج باستخدام كلمات مشفّرة في متّجهات. يشفّر النموذج الكلمات باستخدام مجموعة معيّنة من الأسماء والقيم التي يتم تعلّمها أثناء تدريب النموذج. يُرجى العِلم أنّ معظم النماذج ستتضمّن مفردات مختلفة، ومن المهم استخدام المفردات الخاصة بنموذجك والتي تم إنشاؤها في وقت التدريب. هذا هو ملف vocab.txt الذي أضفته للتو إلى تطبيقك.
يمكنك فتح الملف في Xcode للاطّلاع على عمليات الترميز. يتم ترميز كلمات مثل "أغنية" إلى 6 و "حب" إلى 12. الترتيب هو في الواقع ترتيب التكرار، لذا كانت الكلمة "I" هي الأكثر شيوعًا في مجموعة البيانات، تليها الكلمة "check".
عندما يكتب المستخدم كلمات، عليك ترميزها باستخدام هذه المفردات قبل إرسالها إلى النموذج لتصنيفها.
لنستكشف هذا الرمز. ابدأ بتحميل المفردات.
- حدِّد متغيّرًا على مستوى الفئة لتخزين القاموس:
var words_dictionary = [String : Int]()
- بعد ذلك، أنشئ
funcفي الصف لتحميل المفردات إلى هذا القاموس:
func loadVocab(){
// This func will take the file at vocab.txt and load it into a has table
// called words_dictionary. This will be used to tokenize the words before passing them
// to the model trained by TensorFlow Lite Model Maker
if let filePath = Bundle.main.path(forResource: "vocab", ofType: "txt") {
do {
let dictionary_contents = try String(contentsOfFile: filePath)
let lines = dictionary_contents.split(whereSeparator: \.isNewline)
for line in lines{
let tokens = line.components(separatedBy: " ")
let key = String(tokens[0])
let value = Int(tokens[1])
words_dictionary[key] = value
}
} catch {
print("Error vocab could not be loaded")
}
} else {
print("Error -- vocab file not found")
}
}
- يمكنك تنفيذ هذا الإجراء من خلال استدعائه من داخل
viewDidLoad:
override func viewDidLoad() {
super.viewDidLoad()
txtInput.delegate = self
loadVocab()
}
10. تحويل سلسلة إلى تسلسل من الرموز المميزة
سيكتب المستخدمون كلمات في شكل جملة ستصبح سلسلة. سيتم ترميز كل كلمة في الجملة، إذا كانت متوفرة في القاموس، إلى قيمة المفتاح الخاصة بالكلمة كما هو محدّد في المفردات.
يقبل نموذج معالجة اللغة الطبيعية عادةً تسلسلاً ثابتًا من الأحرف. هناك استثناءات مع النماذج التي تم إنشاؤها باستخدام ragged tensors، ولكن في معظم الحالات، ستلاحظ أنّها ثابتة. لقد حدّدت هذه المدة عند إنشاء النموذج. احرص على استخدام الطول نفسه في تطبيق iOS.
كانت القيمة التلقائية في Colab لأداة TensorFlow Lite Model Maker التي استخدمتها سابقًا هي 20، لذا عليك ضبطها هنا أيضًا:
let SEQUENCE_LENGTH = 20
أضِف func الذي سيأخذ السلسلة ويحوّلها إلى أحرف صغيرة ويزيل أي علامات ترقيم:
func convert_sentence(sentence: String) -> [Int32]{
// This func will split a sentence into individual words, while stripping punctuation
// If the word is present in the dictionary it's value from the dictionary will be added to
// the sequence. Otherwise we'll continue
// Initialize the sequence to be all 0s, and the length to be determined
// by the const SEQUENCE_LENGTH. This should be the same length as the
// sequences that the model was trained for
var sequence = [Int32](repeating: 0, count: SEQUENCE_LENGTH)
var words : [String] = []
sentence.enumerateSubstrings(
in: sentence.startIndex..<sentence.endIndex,options: .byWords) {
(substring, _, _, _) -> () in words.append(substring!) }
var thisWord = 0
for word in words{
if (thisWord>=SEQUENCE_LENGTH){
break
}
let seekword = word.lowercased()
if let val = words_dictionary[seekword]{
sequence[thisWord]=Int32(val)
thisWord = thisWord + 1
}
}
return sequence
}
يُرجى العِلم أنّ التسلسل سيكون من النوع Int32. تم اختيار هذا النوع عمدًا لأنّه عند تمرير القيم إلى TensorFlow Lite، ستتعامل مع الذاكرة ذات المستوى المنخفض، ويتعامل TensorFlow Lite مع الأعداد الصحيحة في تسلسل السلسلة على أنّها أعداد صحيحة 32 بت. سيؤدي ذلك إلى تسهيل عملية تمرير السلاسل إلى النموذج (قليلاً).
11. إجراء التصنيف
لتصنيف جملة، يجب أولاً تحويلها إلى تسلسل من الرموز المميزة استنادًا إلى الكلمات في الجملة. تم إجراء ذلك في الخطوة 9.
ستأخذ الآن الجملة وتمرّرها إلى النموذج، وتطلب من النموذج استنتاج المعنى من الجملة، ثم تحلّل النتائج.
سيتم استخدام مفسّر TensorFlow Lite الذي عليك استيراده:
import TensorFlowLite
ابدأ بـ func الذي يتضمّن تسلسلك، والذي كان عبارة عن مجموعة من أنواع Int32:
func classify(sequence: [Int32]){
// Model Path is the location of the model in the bundle
let modelPath = Bundle.main.path(forResource: "model", ofType: "tflite")
var interpreter: Interpreter
do{
interpreter = try Interpreter(modelPath: modelPath!)
} catch _{
print("Error loading model!")
return
}
سيؤدي ذلك إلى تحميل ملف النموذج من الحزمة واستدعاء مترجم باستخدام هذا الملف.
الخطوة التالية هي نسخ الذاكرة الأساسية المخزَّنة في التسلسل إلى مخزن مؤقت يُسمى myData, حتى يمكن تمريرها إلى موتر. عند تنفيذ وحدة TensorFlow Lite، بالإضافة إلى المترجم، يمكنك الوصول إلى نوع الموتر.
ابدأ الرمز على النحو التالي (لا يزال في classify func.):
let tSequence = Array(sequence)
let myData = Data(copyingBufferOf: tSequence.map { Int32($0) })
let outputTensor: Tensor
لا تقلق إذا ظهرت لك رسالة خطأ على copyingBufferOf. سيتم تنفيذ ذلك كإضافة لاحقًا.
حان الوقت الآن لتخصيص موترات في المترجم، ونسخ مخزن البيانات المؤقت الذي أنشأته للتو إلى موتر الإدخال، ثم استدعاء المترجم لإجراء الاستدلال:
do {
// Allocate memory for the model's input `Tensor`s.
try interpreter.allocateTensors()
// Copy the data to the input `Tensor`.
try interpreter.copy(myData, toInputAt: 0)
// Run inference by invoking the `Interpreter`.
try interpreter.invoke()
بعد اكتمال عملية الاستدعاء، يمكنك الاطّلاع على ناتج المترجم لمعرفة النتائج.
ستكون هذه القيم قيمًا أولية (4 بايت لكل عصبون) عليك قراءتها وتحويلها بعد ذلك. بما أنّ هذا النموذج المحدّد يحتوي على خليتَي إخراج عصبية، عليك قراءة 8 بايت سيتم تحويلها إلى Float32 لتحليلها. أنت تتعامل مع ذاكرة منخفضة المستوى، ومن هنا جاءت unsafeData.
// Get the output `Tensor` to process the inference results.
outputTensor = try interpreter.output(at: 0)
// Turn the output tensor into an array. This will have 2 values
// Value at index 0 is the probability of negative sentiment
// Value at index 1 is the probability of positive sentiment
let resultsArray = outputTensor.data
let results: [Float32] = [Float32](unsafeData: resultsArray) ?? []
أصبح من السهل نسبيًا تحليل البيانات لتحديد جودة المحتوى غير المرغوب فيه. يتضمّن النموذج نتيجتَين، الأولى تتضمّن احتمال ألا تكون الرسالة غير مرغوب فيها، والثانية تتضمّن احتمال أن تكون كذلك. وبالتالي، يمكنك الاطّلاع على results[1] للعثور على قيمة الرسالة غير المرغوب فيها:
let positiveSpamValue = results[1]
var outputString = ""
if(positiveSpamValue>0.8){
outputString = "Message not sent. Spam detected with probability: " + String(positiveSpamValue)
} else {
outputString = "Message sent!"
}
txtOutput.text = outputString
لتسهيل الأمر عليك، إليك الطريقة الكاملة:
func classify(sequence: [Int32]){
// Model Path is the location of the model in the bundle
let modelPath = Bundle.main.path(forResource: "model", ofType: "tflite")
var interpreter: Interpreter
do{
interpreter = try Interpreter(modelPath: modelPath!)
} catch _{
print("Error loading model!")
Return
}
let tSequence = Array(sequence)
let myData = Data(copyingBufferOf: tSequence.map { Int32($0) })
let outputTensor: Tensor
do {
// Allocate memory for the model's input `Tensor`s.
try interpreter.allocateTensors()
// Copy the data to the input `Tensor`.
try interpreter.copy(myData, toInputAt: 0)
// Run inference by invoking the `Interpreter`.
try interpreter.invoke()
// Get the output `Tensor` to process the inference results.
outputTensor = try interpreter.output(at: 0)
// Turn the output tensor into an array. This will have 2 values
// Value at index 0 is the probability of negative sentiment
// Value at index 1 is the probability of positive sentiment
let resultsArray = outputTensor.data
let results: [Float32] = [Float32](unsafeData: resultsArray) ?? []
let positiveSpamValue = results[1]
var outputString = ""
if(positiveSpamValue>0.8){
outputString = "Message not sent. Spam detected with probability: " +
String(positiveSpamValue)
} else {
outputString = "Message sent!"
}
txtOutput.text = outputString
} catch let error {
print("Failed to invoke the interpreter with error: \(error.localizedDescription)")
}
}
12. إضافة إضافات Swift
استخدم الرمز البرمجي أعلاه إضافة إلى نوع البيانات للسماح لك بنسخ وحدات البت الأولية لمصفوفة Int32 إلى Data. في ما يلي رمز هذه الإضافة:
extension Data {
/// Creates a new buffer by copying the buffer pointer of the given array.
///
/// - Warning: The given array's element type `T` must be trivial in that it can be copied bit
/// for bit with no indirection or reference-counting operations; otherwise, reinterpreting
/// data from the resulting buffer has undefined behavior.
/// - Parameter array: An array with elements of type `T`.
init<T>(copyingBufferOf array: [T]) {
self = array.withUnsafeBufferPointer(Data.init)
}
}
عند التعامل مع الذاكرة ذات المستوى المنخفض، يمكنك استخدام بيانات "غير آمنة"، ويتطلّب الرمز البرمجي أعلاه تهيئة مصفوفة من البيانات غير الآمنة. تتيح لك هذه الإضافة إجراء ما يلي:
extension Array {
/// Creates a new array from the bytes of the given unsafe data.
///
/// - Warning: The array's `Element` type must be trivial in that it can be copied bit for bit
/// with no indirection or reference-counting operations; otherwise, copying the raw bytes in
/// the `unsafeData`'s buffer to a new array returns an unsafe copy.
/// - Note: Returns `nil` if `unsafeData.count` is not a multiple of
/// `MemoryLayout<Element>.stride`.
/// - Parameter unsafeData: The data containing the bytes to turn into an array.
init?(unsafeData: Data) {
guard unsafeData.count % MemoryLayout<Element>.stride == 0 else { return nil }
#if swift(>=5.0)
self = unsafeData.withUnsafeBytes { .init($0.bindMemory(to: Element.self)) }
#else
self = unsafeData.withUnsafeBytes {
.init(UnsafeBufferPointer<Element>(
start: $0,
count: unsafeData.count / MemoryLayout<Element>.stride
))
}
#endif // swift(>=5.0)
}
}
13. تشغيل تطبيق iOS
تشغيل التطبيق واختباره
إذا سارت الأمور على ما يرام، من المفترض أن يظهر التطبيق على جهازك على النحو التالي:

في المكان الذي تم فيه إرسال الرسالة "اشترِ كتابي لتعلُّم التداول على الإنترنت"، يرسل التطبيق تنبيهًا بشأن رصد رسالة غير مرغوب فيها باحتمالية %99.
14. تهانينا!
لقد أنشأت الآن تطبيقًا بسيطًا جدًا يفلتر النص بحثًا عن التعليقات غير المرغوب فيها باستخدام نموذج تم تدريبه على بيانات مستخدَمة لإرسال محتوى غير مرغوب فيه إلى المدونات.
تتمثّل الخطوة التالية في دورة حياة المطوّر النموذجية في استكشاف ما يلزم لتخصيص النموذج استنادًا إلى البيانات المتوفّرة في المنتدى الخاص بك. ستتعرّف على كيفية إجراء ذلك في نشاط المسار التالي.