۱. قبل از شروع
در این آزمایشگاه کد، برنامهای را که در آزمایشگاههای کد قبلی «شروع کار با آزمایشگاههای کد طبقهبندی متن موبایل» ساختید، بهروزرسانی خواهید کرد.
پیشنیازها
- این آزمایشگاه کد برای توسعهدهندگان باتجربه و تازهکار در یادگیری ماشین طراحی شده است.
- آزمایشگاه کد بخشی از یک مسیر متوالی است. اگر قبلاً «ساخت یک برنامه پیامرسان ساده» یا «ساخت یک مدل یادگیری ماشینی برای اسپم کردن نظرات» را تکمیل نکردهاید، لطفاً همین حالا دست نگه دارید و این کار را انجام دهید.
آنچه [خواهید ساخت یا یاد خواهید گرفت]
- شما یاد خواهید گرفت که چگونه مدل سفارشی خود را که در مراحل قبلی ساخته شده است، در برنامه خود ادغام کنید.
آنچه نیاز دارید
- اندروید استودیو یا CocoaPods برای iOS
۲. برنامه اندروید موجود را باز کنید
میتوانید کد مربوط به این کار را با دنبال کردن Codelab 1 یا با کلون کردن این مخزن و بارگذاری برنامه از TextClassificationStep1 دریافت کنید.
git clone https://github.com/googlecodelabs/odml-pathways
این مورد را میتوانید در مسیر TextClassificationOnMobile->Android پیدا کنید.
کد نهایی نیز با عنوان TextClassificationStep2 در دسترس شماست.
وقتی باز شد، آمادهاید تا به مرحله ۲ بروید.
۳. فایل مدل و متادیتا را وارد کنید
در بخش «ساخت مدل یادگیری ماشینی برای هرزنامههای کامنت» در codelab، شما یک مدل .TFLITE ایجاد کردید.
شما باید فایل مدل را دانلود کرده باشید. اگر آن را ندارید، میتوانید آن را از مخزن این codelab دریافت کنید و مدل اینجا موجود است.
با ایجاد یک دایرکتوری assets، آن را به پروژه خود اضافه کنید.
- با استفاده از ناوبری پروژه، مطمئن شوید که اندروید در بالا انتخاب شده است.
- روی پوشه برنامه کلیک راست کنید. گزینه New > Directory را انتخاب کنید.

- در پنجرهی «دایرکتوری جدید» ، src/main/assets را انتخاب کنید.

خواهید دید که یک پوشه جدید به نام assets اکنون در برنامه موجود است.

- کلیک راست روی داراییها.
- در منویی که باز میشود، (در مک) عبارت Reveal in Finder را خواهید دید. آن را انتخاب کنید. (در ویندوز عبارت Show in Explorer و در اوبونتو عبارت Show in Files را خواهید دید.)

فایندر (Finder) اجرا میشود تا محل فایلها را نشان دهد ( فایل اکسپلورر در ویندوز، فایلها در لینوکس).
- فایلهای
labels.txt،model.tfliteوvocabرا در این پوشه کپی کنید.

- به اندروید استودیو برگردید، خواهید دید که آنها در پوشه assets شما موجود هستند.

۴. build.gradle خود را برای استفاده از TensorFlow Lite بهروزرسانی کنید.
برای استفاده از TensorFlow Lite و کتابخانههای وظیفه TensorFlow Lite که از آن پشتیبانی میکنند، باید فایل build.gradle خود را بهروزرسانی کنید.
پروژههای اندروید اغلب بیش از یک سطح برنامه دارند، بنابراین حتماً سطح برنامه یک را پیدا کنید. در پنجره کاوشگر پروژه در نمای اندروید، آن را در بخش Gradle Scripts خود پیدا کنید. سطح صحیح با .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 مراجعه کنید.
کتابخانههای وظیفه همچنین به حداقل نسخه SDK 21 نیاز دارند. این تنظیم را در android > default config پیدا کنید و آن را به 21 تغییر دهید:

حالا شما تمام وابستگیهای خود را دارید، پس وقت آن است که شروع به کدنویسی کنید!
۵. یک کلاس کمکی اضافه کنید
برای جدا کردن منطق استنتاج ، جایی که برنامه شما از مدل استفاده میکند، از رابط کاربری، کلاس دیگری برای مدیریت استنتاج مدل ایجاد کنید. این را یک کلاس "کمکی" بنامید.
- روی نام بستهای که کد
MainActivityشما در آن قرار دارد، کلیک راست کنید. - جدید > بسته را انتخاب کنید.

- در مرکز صفحه، پنجرهای خواهید دید که از شما میخواهد نام بسته را وارد کنید. آن را به انتهای نام بسته فعلی اضافه کنید. (در اینجا، helpers نامیده میشود.)

- پس از انجام این کار، روی پوشه helpers در project explorer کلیک راست کنید.
- از منوی New گزینه Java Class را انتخاب کنید و نام آن را
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 بخشی از کتابخانههای وظایف متنی است و با تبدیل رشته به توکنها، استفاده از طول توالی صحیح، ارسال آن به مدل و تجزیه نتایج به شما کمک میکند.
(برای جزئیات بیشتر در مورد این موارد، دوباره به بخش «ساخت یک مدل یادگیری ماشینی برای اسپم کردن کامنت» مراجعه کنید.)
طبقهبندی در متد classes انجام میشود، جایی که شما یک رشته را به آن ارسال میکنید و این متد یک List را برمیگرداند. هنگام استفاده از مدلهای یادگیری ماشین برای طبقهبندی محتوا که میخواهید مشخص کنید یک رشته هرزنامه است یا خیر، معمولاً همه پاسخها با احتمالات اختصاص داده شده بازگردانده میشوند. به عنوان مثال، اگر پیامی را که شبیه هرزنامه است به آن ارسال کنید، لیستی از 2 پاسخ دریافت خواهید کرد؛ یکی با احتمال هرزنامه بودن و دیگری با احتمال غیر هرزنامه بودن. هرزنامه/غیر هرزنامه دسته بندی هستند، بنابراین List برگردانده شده شامل این احتمالات خواهد بود. بعداً آن را تجزیه و تحلیل خواهید کرد.
حالا که کلاس کمکی را دارید، به MainActivity خود برگردید و آن را بهروزرسانی کنید تا از این برای طبقهبندی متن خود استفاده کنید. این را در مرحله بعدی خواهید دید!
۶. متن را طبقهبندی کنید
در MainActivity خود، ابتدا باید helperهایی را که ایجاد کردهاید، وارد (import) کنید!
- در بالای
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 آیتم ۰ و True آیتم ۱ خواهد بود.)
- برای بدست آوردن امتیاز احتمال
Trueبودن مقدار، میتوانید به results[1].score به این صورت نگاه کنید:
val score = results[1].score
- یک مقدار آستانه (در این مورد ۰.۸) انتخاب شده است، که در آن شما میگویید اگر امتیاز دستهی «درست» (True) بالاتر از مقدار آستانه (۰.۸) باشد، پیام هرزنامه است. در غیر این صورت، هرزنامه نیست و ارسال پیام ایمن است:
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()
}
- مدل را در عمل اینجا ببینید. پیام «برای خرید به وبلاگ من سر بزنید!» به عنوان یک پیام با احتمال بالای اسپم علامتگذاری شد:

و برعکس، احتمال اسپم بودن عبارت «هی، آموزش جالبی بود، ممنون!» بسیار کم بود:

۷. اپلیکیشن iOS خود را برای استفاده از مدل TensorFlow Lite بهروزرسانی کنید.
میتوانید کد مربوط به این کار را با دنبال کردن Codelab 1 یا با شبیهسازی این مخزن و بارگذاری برنامه از TextClassificationStep1 دریافت کنید. میتوانید این کد را در مسیر TextClassificationOnMobile->iOS پیدا کنید.
کد نهایی نیز با عنوان TextClassificationStep2 در دسترس شماست.
در آزمایشگاه کد مدل یادگیری ماشینی «ساخت کامنت اسپم»، شما یک برنامه بسیار ساده ایجاد کردید که به کاربر اجازه میداد پیامی را در یک UITextView تایپ کند و آن را بدون هیچ فیلتری به یک خروجی ارسال کند.
حالا آن برنامه را بهروزرسانی میکنید تا از یک مدل TensorFlow Lite برای تشخیص هرزنامههای کامنت در متن قبل از ارسال استفاده کند. فقط ارسال را در این برنامه با رندر کردن متن در یک برچسب خروجی شبیهسازی کنید (اما یک برنامه واقعی ممکن است یک تابلوی اعلانات، یک چت یا چیزی شبیه به آن داشته باشد).
برای شروع، به برنامهای که در مرحله ۱ ارائه شد نیاز دارید که میتوانید آن را از مخزن (repo) کپی کنید.
برای ادغام 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 در دایرکتوری اشتباه یا نام هدف اشتباه، معمولاً مقصر اصلی هستند!
۸. فایلهای مدل و واژگان را اضافه کنید
وقتی مدل را با TensorFlow Lite Model maker ایجاد کردید، توانستید مدل (به صورت model.tflite ) و فایل vocab (به صورت vocab.txt ) را خروجی بگیرید.
- با کشیدن و رها کردن آنها از Finder به پنجره پروژه، آنها را به پروژه خود اضافه کنید. مطمئن شوید که گزینه add to targets تیک خورده باشد:

وقتی کارتان تمام شد، باید آنها را در پروژه خود ببینید:

- با انتخاب پروژه خود (در تصویر بالا، آیکون آبی TextClassificationStep2 است) و نگاه کردن به تب Build Phases ، دوباره بررسی کنید که آنها به بسته نرمافزاری اضافه شدهاند (تا روی یک دستگاه مستقر شوند):

۹. واژگان را بارگیری کنید
هنگام انجام طبقهبندی NLP، مدل با کلماتی که در بردارها کدگذاری شدهاند، آموزش داده میشود. مدل، کلمات را با مجموعهای خاص از نامها و مقادیر کدگذاری میکند که هنگام آموزش مدل، آموخته میشوند. لطفاً توجه داشته باشید که اکثر مدلها واژگان متفاوتی خواهند داشت و استفاده از واژگانی که در زمان آموزش برای مدل شما تولید شده است، برای شما مهم است. این فایل vocab.txt است که شما به برنامه خود اضافه کردهاید.
میتوانید فایل را در Xcode باز کنید تا کدگذاریها را ببینید. کلماتی مانند "song" با عدد ۶ و "love" با عدد ۱۲ کدگذاری شدهاند. این ترتیب در واقع به ترتیب فراوانی است، بنابراین "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()
}
۱۰. تبدیل یک رشته به دنبالهای از توکنها
کاربران شما کلمات را به صورت جمله تایپ میکنند که به یک رشته تبدیل میشود. هر کلمه در جمله، اگر در فرهنگ لغت وجود داشته باشد، به مقدار کلیدی کلمه، همانطور که در واژگان تعریف شده است، کدگذاری میشود.
یک مدل NLP معمولاً طول توالی ثابتی را میپذیرد. استثنائاتی در مورد مدلهای ساخته شده با استفاده از ragged tensors وجود دارد، اما در بیشتر موارد خواهید دید که این طول ثابت است. هنگام ایجاد مدل خود، این طول را مشخص کردهاید. مطمئن شوید که در برنامه iOS خود نیز از همان طول استفاده میکنید.
مقدار پیشفرض در Colab for 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 با اعداد صحیح در یک دنباله رشتهای به عنوان اعداد صحیح ۳۲ بیتی رفتار میکند. این کار، کار شما را هنگام ارسال رشتهها به مدل (کمی) آسانتر میکند.
۱۱. طبقهبندی را انجام دهید
برای طبقهبندی یک جمله، ابتدا باید آن را به دنبالهای از توکنها بر اساس کلمات موجود در جمله تبدیل کرد. این کار در مرحله ۹ انجام خواهد شد.
اکنون جمله را میگیرید و آن را به مدل منتقل میکنید، از مدل میخواهید که روی جمله استنتاج انجام دهد و نتایج را تجزیه کند.
این از مفسر 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 و همچنین مفسر، به یک نوع تنسور دسترسی پیدا کردید.
کد را به این صورت شروع کنید (هنوز در func classification است):
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()
پس از اتمام فراخوانی، میتوانید خروجی مفسر را برای مشاهده نتایج مشاهده کنید.
اینها مقادیر خام (۴ بایت برای هر نورون) خواهند بود که سپس باید آنها را بخوانید و تبدیل کنید. از آنجایی که این مدل خاص ۲ نورون خروجی دارد، باید ۸ بایت را بخوانید که برای تجزیه به 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)")
}
}
۱۲. افزونههای 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)
}
}
۱۳. برنامه iOS را اجرا کنید
اپ را اجرا و تست کنید.
اگر همه چیز خوب پیش رفته باشد، باید برنامه را روی دستگاه خود به این شکل ببینید:

در جایی که پیام «کتاب من را بخرید تا تجارت آنلاین را یاد بگیرید!» ارسال شده است، برنامه با احتمال 0.99٪ هشدار شناسایی هرزنامه را ارسال میکند!
۱۴. تبریک میگویم!
شما اکنون یک برنامه بسیار ساده ایجاد کردهاید که با استفاده از مدلی که بر اساس دادههای مورد استفاده برای وبلاگهای اسپم آموزش دیده است، متن را برای هرزنامههای کامنت فیلتر میکند.
گام بعدی در چرخه حیات معمول توسعهدهنده، بررسی این است که برای سفارشیسازی مدل بر اساس دادههای موجود در جامعه خودتان، چه چیزهایی لازم است. در فعالیت بعدی مسیر، نحوه انجام این کار را خواهید دید.