১. শুরু করার আগে
এই কোডল্যাবে, আপনি আগের 'গেট স্টার্টেড উইথ মোবাইল টেক্সট ক্লাসিফিকেশন' কোডল্যাবগুলোতে তৈরি করা অ্যাপটি আপডেট করবেন।
পূর্বশর্ত
- এই কোডল্যাবটি মেশিন লার্নিং-এ নতুন কিন্তু অভিজ্ঞ ডেভেলপারদের জন্য ডিজাইন করা হয়েছে।
- কোডল্যাবটি একটি ধারাবাহিক পাঠ্যক্রমের অংশ। আপনি যদি এখনও 'Build a basic messaging style app' অথবা 'Build a comment spam machine learning model' সম্পন্ন না করে থাকেন, তবে অনুগ্রহ করে থামুন এবং এখনই তা করুন।
আপনি যা তৈরি করবেন বা শিখবেন
- পূর্ববর্তী ধাপগুলোতে তৈরি করা আপনার অ্যাপে কীভাবে আপনার নিজস্ব মডেলটি সংহত করবেন, তা আপনি শিখবেন।
আপনার যা যা লাগবে
- অ্যান্ড্রয়েড স্টুডিও, অথবা আইওএস-এর জন্য কোকোয়া পডস
২. বিদ্যমান অ্যান্ড্রয়েড অ্যাপটি খুলুন
আপনি কোডল্যাব ১ অনুসরণ করে, অথবা এই রিপোটি ক্লোন করে এবং TextClassificationStep1 থেকে অ্যাপটি লোড করে এর কোডটি পেতে পারেন।
git clone https://github.com/googlecodelabs/odml-pathways
আপনি এটি TextClassificationOnMobile->Android পাথে খুঁজে পাবেন।
সম্পূর্ণ কোডটি TextClassificationStep2 হিসেবেও আপনার জন্য উপলব্ধ আছে।
একবার এটি খুলে গেলে, আপনি দ্বিতীয় ধাপে যাওয়ার জন্য প্রস্তুত।
৩. মডেল ফাইল এবং মেটাডেটা ইম্পোর্ট করুন
"Build a comment spam machine learning model" কোডল্যাবে, আপনি একটি .TFLITE মডেল তৈরি করেছেন।
আপনার মডেল ফাইলটি ডাউনলোড করা থাকার কথা। যদি আপনার কাছে এটি না থাকে, তবে আপনি এই কোডল্যাবের রিপো থেকে এটি পেতে পারেন, এবং মডেলটি এখানে পাওয়া যাবে।
একটি অ্যাসেটস ডিরেক্টরি তৈরি করে এটিকে আপনার প্রজেক্টে যুক্ত করুন।
- প্রজেক্ট নেভিগেটর ব্যবহার করে নিশ্চিত করুন যে শীর্ষে অ্যান্ড্রয়েড নির্বাচিত আছে।
- অ্যাপ ফোল্ডারটিতে রাইট-ক্লিক করুন। New > Directory নির্বাচন করুন।

- নতুন ডিরেক্টরি ডায়ালগে, src/main/assets নির্বাচন করুন।

আপনি দেখবেন, অ্যাপটিতে এখন একটি নতুন অ্যাসেটস ফোল্ডার উপলব্ধ হয়েছে।

- অ্যাসেটগুলিতে ডান ক্লিক করুন।
- যে মেনুটি খুলবে, সেখানে আপনি (ম্যাকে) ‘Reveal in Finder’ দেখতে পাবেন। সেটি নির্বাচন করুন। (উইন্ডোজে এটিতে ‘Show in Explorer’ লেখা থাকবে, উবুন্টুতে এটিতে ‘Show in Files’ লেখা থাকবে।)

ফাইলগুলির অবস্থান দেখানোর জন্য ফাইন্ডার চালু হবে (উইন্ডোজে ফাইল এক্সপ্লোরার , লিনাক্সে ফাইলস )।
-
labels.txt,model.tfliteএবংvocabফাইলগুলো এই ডিরেক্টরিতে কপি করুন।

- অ্যান্ড্রয়েড স্টুডিওতে ফিরে যান, এবং আপনি সেগুলোকে আপনার অ্যাসেটস ফোল্ডারে দেখতে পাবেন।

৪. TensorFlow Lite ব্যবহার করার জন্য আপনার build.gradle আপডেট করুন।
TensorFlow Lite এবং এটিকে সমর্থনকারী TensorFlow Lite টাস্ক লাইব্রেরিগুলো ব্যবহার করার জন্য, আপনাকে আপনার build.gradle ফাইলটি আপডেট করতে হবে।
অ্যান্ড্রয়েড প্রজেক্টে প্রায়শই একাধিক থাকে, তাই অ্যাপ লেভেলেরটি খুঁজে বের করা নিশ্চিত করুন। অ্যান্ড্রয়েড ভিউতে প্রজেক্ট এক্সপ্লোরারে, আপনার গ্রেডল স্ক্রিপ্টস (Gradle Scripts) বিভাগে এটি খুঁজুন। সঠিকটিতে .app লেবেল থাকবে, যেমনটি এখানে দেখানো হয়েছে:

আপনাকে এই ফাইলটিতে দুটি পরিবর্তন করতে হবে। প্রথমটি হলো একদম নিচের dependencies সেকশনে। TensorFlow Lite টাস্ক লাইব্রেরির জন্য একটি টেক্সট implementation যোগ করুন, ঠিক এইভাবে:
implementation 'org.tensorflow:tensorflow-lite-task-text:0.1.0'
এই লেখাটির পর ভার্সন নম্বর পরিবর্তিত হয়ে থাকতে পারে, তাই সর্বশেষ ভার্সনের জন্য https://www.tensorflow.org/lite/inference_with_metadata/task_library/nl_classifier দেখে নিতে ভুলবেন না।
টাস্ক লাইব্রেরিগুলোর জন্যও ন্যূনতম এসডিকে ভার্সন ২১ প্রয়োজন। android > default config এ এই সেটিংটি খুঁজুন এবং এটিকে ২১-এ পরিবর্তন করুন:

আপনার কাছে এখন প্রয়োজনীয় সব উপাদান রয়েছে, তাই কোডিং শুরু করার সময় হয়েছে!
৫. একটি হেল্পার ক্লাস যোগ করুন
ইউজার ইন্টারফেস থেকে ইনফারেন্স লজিক (যেখানে আপনার অ্যাপ মডেল ব্যবহার করে) আলাদা করতে, মডেল ইনফারেন্স পরিচালনা করার জন্য আরেকটি ক্লাস তৈরি করুন। এটিকে একটি 'হেল্পার' ক্লাস বলুন।
- আপনার
MainActivityকোডটি যে প্যাকেজ নামের মধ্যে রয়েছে, সেটির উপর রাইট ক্লিক করুন। - নতুন > প্যাকেজ নির্বাচন করুন।

- স্ক্রিনের মাঝখানে আপনি একটি ডায়ালগ বক্স দেখতে পাবেন, যেখানে আপনাকে প্যাকেজের নাম লিখতে বলা হবে। বর্তমান প্যাকেজের নামের শেষে এটি যোগ করুন। (এখানে, এটিকে হেল্পার বলা হয়।)

- এটি হয়ে গেলে, প্রজেক্ট এক্সপ্লোরারে থাকা হেল্পার্স ফোল্ডারটির উপর রাইট ক্লিক করুন।
- 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 টাইপটি `text tasks` লাইব্রেরির একটি অংশ, এবং এটি সঠিক সিকোয়েন্স লেংথ ব্যবহার করে আপনার স্ট্রিংকে টোকেনে রূপান্তর করে, সেটিকে মডেলে পাঠায় এবং ফলাফল পার্স করে আপনাকে সাহায্য করে।
(এগুলো সম্পর্কে আরও বিস্তারিত জানতে, 'একটি মন্তব্য স্প্যাম মেশিন লার্নিং মডেল তৈরি করুন' অংশটি পুনরায় দেখুন।)
ক্লাসিফিকেশনটি `classify` মেথডে করা হয়, যেখানে আপনি একটি স্ট্রিং পাস করলে এটি একটি List রিটার্ন করে। যখন কোনো কন্টেন্ট ক্লাসিফাই করার জন্য মেশিন লার্নিং মডেল ব্যবহার করা হয় এবং কোনো স্ট্রিং স্প্যাম কি না তা নির্ধারণ করতে চাওয়া হয়, তখন সাধারণত সব উত্তরই নির্ধারিত সম্ভাবনাসহ রিটার্ন করা হয়। উদাহরণস্বরূপ, যদি আপনি স্প্যামের মতো দেখতে একটি মেসেজ পাস করেন, তাহলে আপনি ২টি উত্তরের একটি লিস্ট পাবেন; একটিতে থাকবে মেসেজটি স্প্যাম হওয়ার সম্ভাবনা, এবং অন্যটিতে থাকবে এটি স্প্যাম নয় হওয়ার সম্ভাবনা। স্প্যাম/নট স্প্যাম হলো দুটি ক্যাটাগরি, তাই রিটার্ন করা ` List এই সম্ভাবনাগুলো থাকবে। আপনি পরে এটি পার্স করে বের করে নেবেন।
এখন যেহেতু আপনার কাছে হেল্পার ক্লাসটি আছে, আপনার MainActivity তে ফিরে যান এবং আপনার টেক্সটকে শ্রেণীবদ্ধ করতে এটি ব্যবহার করার জন্য আপডেট করুন। আপনি তা পরবর্তী ধাপে দেখতে পাবেন!
৬. পাঠ্যটিকে শ্রেণীবদ্ধ করুন
আপনার 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 হবে ০ নম্বর আইটেম এবং 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()
}
- এখানে মডেলটির কার্যকারিতা দেখুন। "জিনিসপত্র কিনতে আমার ব্লগ দেখুন!" বার্তাটিকে স্প্যাম হওয়ার উচ্চ সম্ভাবনা হিসেবে চিহ্নিত করা হয়েছে:

এবং এর বিপরীতে, "আরে, মজার টিউটোরিয়াল, ধন্যবাদ!"-এর মতো বার্তা স্প্যাম হওয়ার সম্ভাবনা খুবই কম বলে মনে করা হয়েছিল:

৭. TensorFlow Lite মডেল ব্যবহার করার জন্য আপনার iOS অ্যাপটি আপডেট করুন।
আপনি কোডল্যাব ১ অনুসরণ করে, অথবা এই রিপোটি ক্লোন করে এবং TextClassificationStep1 থেকে অ্যাপটি লোড করে এর কোডটি পেতে পারেন। এটি আপনি TextClassificationOnMobile->iOS পাথে খুঁজে পাবেন।
সম্পূর্ণ কোডটি TextClassificationStep2 হিসেবেও আপনার জন্য উপলব্ধ আছে।
"Build a comment spam machine learning model" কোডল্যাবে, আপনি একটি খুব সাধারণ অ্যাপ তৈরি করেছিলেন যা ব্যবহারকারীকে একটি UITextView তে বার্তা টাইপ করার এবং কোনো ফিল্টারিং ছাড়াই তা আউটপুটে পাঠানোর সুযোগ দিত।
এখন আপনি অ্যাপটিকে একটি TensorFlow Lite মডেল ব্যবহার করার জন্য আপডেট করবেন, যাতে পাঠানোর আগে টেক্সটের মধ্যে থাকা কমেন্ট স্প্যাম শনাক্ত করা যায়। এই অ্যাপে একটি আউটপুট লেবেলে টেক্সটটি রেন্ডার করে পাঠানোর প্রক্রিয়াটি সিমুলেট করুন (কিন্তু একটি আসল অ্যাপে বুলেটিন বোর্ড, চ্যাট বা এই ধরনের কিছু থাকতে পারে)।
শুরু করার জন্য, আপনার ধাপ ১-এর অ্যাপটি প্রয়োজন হবে, যেটি আপনি রিপো থেকে ক্লোন করতে পারবেন।
TensorFlow Lite অন্তর্ভুক্ত করতে, আপনাকে CocoaPods ব্যবহার করতে হবে। যদি আপনার সিস্টেমে এটি আগে থেকে ইনস্টল করা না থাকে, তবে আপনি https://cocoapods.org/ -এর নির্দেশাবলী অনুসরণ করে তা করতে পারেন।
- CocoaPods ইনস্টল হয়ে গেলে, TextClassification অ্যাপের
.xcprojectফাইলের ডিরেক্টরিতে Podfile নামে একটি ফাইল তৈরি করুন। এই ফাইলের বিষয়বস্তু দেখতে এইরকম হবে:
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.txt হিসেবে) আউটপুট করতে পেরেছিলেন।
- ফাইন্ডার থেকে সেগুলোকে টেনে এনে আপনার প্রজেক্ট উইন্ডোতে ছেড়ে দিয়ে প্রজেক্টে যুক্ত করুন। নিশ্চিত করুন যে ‘add to targets’ অপশনটি চেক করা আছে:

কাজ শেষ হলে, আপনি আপনার প্রজেক্টে এগুলো দেখতে পাবেন:

- আপনার প্রজেক্টটি সিলেক্ট করে (উপরের স্ক্রিনশটে, এটি নীল আইকন TextClassificationStep2 ) এবং Build Phases ট্যাবটি দেখে নিশ্চিত হয়ে নিন যে সেগুলি বান্ডেলে যোগ করা হয়েছে (যাতে সেগুলি ডিভাইসে ডেপ্লয় করা যায়):

৯. শব্দভান্ডার লোড করুন
এনএলপি ক্লাসিফিকেশন করার সময়, মডেলটিকে ভেক্টরে এনকোড করা শব্দ দিয়ে প্রশিক্ষণ দেওয়া হয়। মডেলটি নির্দিষ্ট কিছু নাম এবং মান দিয়ে শব্দগুলোকে এনকোড করে, যা মডেলটি প্রশিক্ষণের সময় শিখে নেওয়া হয়। অনুগ্রহ করে মনে রাখবেন যে, বেশিরভাগ মডেলের শব্দভান্ডার ভিন্ন ভিন্ন হয়ে থাকে, এবং আপনার মডেলের জন্য প্রশিক্ষণের সময় তৈরি হওয়া শব্দভান্ডারটি ব্যবহার করা গুরুত্বপূর্ণ। এটিই হলো vocab.txt ফাইল, যা আপনি এইমাত্র আপনার অ্যাপে যুক্ত করেছেন।
এনকোডিংগুলো দেখতে আপনি ফাইলটি এক্সকোডে খুলতে পারেন। '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()
}
১০. একটি স্ট্রিংকে টোকেনের অনুক্রমে পরিণত করুন
আপনার ব্যবহারকারীরা বাক্য আকারে শব্দ টাইপ করবেন, যা একটি স্ট্রিং-এ পরিণত হবে। বাক্যটির প্রতিটি শব্দ, যদি অভিধানে উপস্থিত থাকে, তবে তা ভোকাব-এ সংজ্ঞায়িত শব্দটির কী ভ্যালু হিসেবে এনকোড করা হবে।
একটি এনএলপি মডেল সাধারণত একটি নির্দিষ্ট সিকোয়েন্স দৈর্ঘ্য গ্রহণ করে। ragged tensors ব্যবহার করে তৈরি মডেলের ক্ষেত্রে এর ব্যতিক্রম আছে, কিন্তু বেশিরভাগ ক্ষেত্রেই আপনি দেখবেন যে এটি নির্দিষ্ট থাকে। আপনার মডেল তৈরি করার সময় আপনি এই দৈর্ঘ্যটি নির্দিষ্ট করে দিয়েছিলেন। আপনার আইওএস অ্যাপেও যেন একই দৈর্ঘ্য ব্যবহার করা হয়, তা নিশ্চিত করুন।
আপনি আগে যে Colab for TensorFlow Lite Model Maker ব্যবহার করেছিলেন, সেটির ডিফল্ট মান ছিল ২০, তাই এখানেও সেটি সেট করে দিন:
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 পড এবং ইন্টারপ্রেটার ইমপ্লিমেন্ট করার সময়, আপনি একটি Tensor Type ব্যবহারের সুযোগ পান।
কোডটি এইভাবে শুরু করুন (এখনও 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()
আহ্বানটি সম্পন্ন হয়ে গেলে, ফলাফল দেখার জন্য আপনি ইন্টারপ্রেটারের আউটপুট দেখতে পারেন।
এগুলো হবে র ভ্যালু (প্রতি নিউরনে ৪ বাইট), যা আপনাকে পরে পড়ে নিয়ে রূপান্তর করতে হবে। যেহেতু এই নির্দিষ্ট মডেলটিতে ২টি আউটপুট নিউরন আছে, তাই আপনাকে ৮ বাইট পড়তে হবে যা পার্সিংয়ের জন্য 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)")
}
}
১২. সুইফট এক্সটেনশনগুলো যোগ করুন
উপরের কোডটিতে Data টাইপের একটি এক্সটেনশন ব্যবহার করা হয়েছে, যা আপনাকে একটি 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 অ্যাপটি চালান
অ্যাপটি চালান এবং পরীক্ষা করুন।
সবকিছু ঠিকঠাক থাকলে, আপনি আপনার ডিভাইসে অ্যাপটি এইভাবে দেখতে পাবেন:

যেখানে "অনলাইন ট্রেডিং শিখতে আমার বই কিনুন!" বার্তাটি পাঠানো হয়েছিল, সেখানে অ্যাপটি .৯৯% সম্ভাবনায় একটি স্প্যাম শনাক্ত হওয়ার সতর্কতা পাঠায়!
১৪. অভিনন্দন!
আপনি এখন একটি খুব সাধারণ অ্যাপ তৈরি করেছেন যা ব্লগ স্প্যাম করতে ব্যবহৃত ডেটার উপর প্রশিক্ষিত একটি মডেল ব্যবহার করে মন্তব্য স্প্যামের জন্য টেক্সট ফিল্টার করে।
একজন সাধারণ ডেভেলপারের কাজের পরবর্তী ধাপ হলো, নিজের কমিউনিটিতে প্রাপ্ত তথ্যের ভিত্তিতে মডেলটিকে কাস্টমাইজ করতে কী কী প্রয়োজন হবে, তা খতিয়ে দেখা। পরবর্তী পাথওয়ে অ্যাক্টিভিটিতে আপনি দেখতে পাবেন কীভাবে তা করতে হয়।