Droidcon Ph 2018 မှာ codelabs အဖြစ်နဲ့ပြောခဲ့ပေမဲ့ ပွဲမှာလူလာနည်းတာကတစ်ကြောင်း၊ ကျောင်းသားတွေများလို့ အခြေခံတွေပါပြန်ရှင်းပြရတော့ မှန်းထားတဲ့အချိန်ထက်ပိုသွားလို့ နောက်ပိုင်းတွေမြန်မြန်လုပ်လိုက်လာတစ်ကြောင်း။ ပြောရရင် အားမရဘူးပေါ့။ ဒါနဲ့ပဲ blog post အဖြစ်ပြောင်းရေးမလားလို့ စိတ်ကူးရသွားတယ်။
အရင်ဆုံး Not Hotdog ဆိုတာဘာလဲမသိတဲ့သူတွေအတွက် အောက်က clip လေးကို ကြည့်စေချင်တယ်။ (သတိပေးချက်။ ဆဲဆိုတာလေးတွေပါလို့ အနည်းငယ် NSFW ဖြစ်ပါတယ်)
ဆိုတော့ ကျွန်တော်တို့ရေးတဲ့ App လေးက Hotdog ဟုတ်လား မဟုတ်လား ဆုံးဖြတ်ပေးမဲ့ app လေးဖြစ်တယ်။ ဒါကိုစမရေးခင် အောက်ကအချက်တွေ ပြည့်စုံရမယ်။
- Android Studio ရှိရမယ်
- Firebase console သုံးတတ်ရမယ်
- Linux အခြေခံတဲ့ OS ဖြစ်ရမယ် (တစ်ချို့ command တွေက Windows မှာအလုပ်မလုပ်ဘူး)
- Python 3.+ သွင်းထားရမယ်
Python ဘယ်လိုသွင်းရတယ်၊ Android Studio ဘယ်လိုသွင်းရလဲ အစရှိတဲ့ အခြေခံတွေကို ကျွန်တော် ဒီမှာတော့ မပြောတော့ဘူး။ Google-fu ပဲသုံးပြီးရှာကြည့်စေချင်ပါတယ်။
Dataset
Dataset ကို ကျွန်တော် ဒီ link ကနေယူထားပါတယ်။ Kaggle account ဖွင့်ပြီးမှတော့ ဒေါင်းလို့ရမယ်။ zip ဖြည်လိုက်တာနဲ့ test/train နှစ်ခုတွေ့လိမ့်မယ်။ ကျွန်တော်တို့ကတော့ train ကိုပဲသုံးမယ်။ ပြီးမှ model ကို ပြန်စမ်းချင်ရင် test ကိုသုံးမယ်ပေါ့။ train ထဲမှာ hotdog အတွက် folder တစ်ခုပါမယ်၊ not hotdog အတွက် folder တစ်ခုပါမယ်။ folder နာမည်တွေကပုံရဲ့ “label” လို့ပြောရင်လည်း မမှားပါဘူး။
Setting up project
ဘာမှစမလုပ်ခင်မှာ virtual environment တစ်ခုစလုပ်မယ်။ Python အသုံးပြုဖူးတဲ့သူဆိုရင်သိပါတယ်။ Project တစ်ခုနဲ့တစ်ခု dependency တူမှာမဟုတ်သလို environment variable တွေလည်းတူချင်မှတူမယ်။ ဒီတော့ ကျွန်တော်တို့က project တစ်ခုစီအတွက် virual enviornment တစ်ခုစီခွဲထားလေ့ရှိတယ်။ Terminal မှာအောက်က command ကို ရိုက်ထည့်လိုက်ပါ။
~ python3 -m venv env
~ source env/bin/activate
ဒါဆိုရင် ကျွန်တော်တို့ “env” ဆိုတဲ့နာမည်နဲ့ folder တစ်ခုရလာမယ်၊ ပြီးတဲ့နောက်မှာ env folder ထဲက environment ကို အသုံးပြုပါမယ်ဆိုပြီး system ကိုပြောလိုက်မယ်။
TensorFlow Dependencies
သက်ဆိုင်တဲ့ Depdencies တွေစသွင်းမယ်။ Python မှာ package management အတွက် “pip” ဆိုတဲ့ tool ကိုအသုံးပြုတယ်။ ကျွန်တော်တို့က tensorflow ကိုသွင်းမှာဖြစ်လို့ အောက်က command ကိုအသုံးပြုရမယ်။
~ pip3 install tensorflow
~ pip3 install tensorflow-hub
Retraining model
ကျွန်တော်တို့ ဒီမှာတော့ အစအဆုံး model တစ်ခုဆောက်စရာမလိုသေးဘူး။ ရှိပြီးသား Image Classfication Model တစ်ခုကိုပြန် train ကြမယ်။ ကျွန်တော်ကတော့ mobile net ကိုအသုံးပြုသွားမယ်။ တစ်ခြား တစ်ခုသုံးချင်လည်း ပြောင်းသုံးကြည့်လို့ရပါတယ်။ Retrain script ကလည်း ကျွန်တော်တို့ ရေးစရာမလိုပဲ Tensorflow Github မှာ တစ်ခါတည်း အသင့်ရှိပြီးသားပါ။ ဆိုတော့ အဲ့ script လေးကို အရင်ဆုံး ယူလိုက်ကြမယ်။
~ wget https://raw.githubusercontent.com/tensorflow/hub/master/examples/image_retraining/retrain.py
ပြီးရင်ကျွန်တော်တို့သုံးမဲ့ mobile net version ကိုရွေးရမယ်။ ကျွန်တော်ကတော့ 1.0 depth, 224 width 224 height ကိုသုံးပါမယ်။ Depth ရယ် Image Size ရယ်က Model file size နဲ့ accuracy ကို တိုက်ရိုက်အချိုးကျမယ်။ ပြောချင်တာက Depth/Image Size များလေလေ၊ model file size ပိုကြီးလေလေ၊ accuracy ပိုများလေလေဖြစ်မယ်။ ဒီတော့ ကိုယ် apk size ရယ်၊ လိုချင်တဲ့ တိကျမှုရယ်ကို ချိန်ပြီးလိုသလိုရွေးချယ်လို့ရပါတယ်။ အောက်က command နဲ့ model ကိုထပ်ဒေါင်းလိုက်မယ်
~ wget https://tfhub.dev/google/imagenet/mobilenet_v2_100_224/classification/2\?tf-hub-format\=compressed -O mobilenet_v2_1_224_224.gz
ပြီးရင် zipped file ကိုဖြည်လိုက်မယ်။ ဒါဆိုရင် ကျွန်တော်တို့ အတွက်လိုအပ်တဲ့ resources တွေအကုန်ရပြီ။ ဒီမှာတော့ ကျွန်တော်ခုနက ဒေါင်းခဲ့တဲ့ image dataset ထဲက train အောက်က folder နှစ်ခုကို images ဆိုတဲ့ folder ထဲပြောင်းထည့်ထားတယ်။ ဒါကတော့ အဆင်ပြေသလို နာမည်ပေးလို့ရပါတယ်။ retrain အတွက် command က
~ python3 retrain.py \
--image_dir ./images \
--bottleneck_dir=tf_files/bottlenecks \
--how_many_training_steps=500 \
--output_graph=tf_files/retrained_graph.pb \
--output_label=tf_files/retrained_labels.txt \
--tfhub_module ./mobilenet_v2_1_224_224/
image_dir
က ကျွန်တော်တို့ ဘယ် folder မှာကျွန်တော်တို့ retrain လုပ်စေချင်တဲ့ ပုံတွေရှိတယ်ဆိုတာကို သတ်မှတ်ပေးတာပါ။ သူကအထဲမှာရှိတဲ့ folder တွေရဲ့ နာမည်ကို label အဖြစ်ယူဆပြီး folder အောက်ကပုံတွေကိုတော့ ဒီ label နဲ့သက်ဆိုင်တယ်ဆိုပြီး သတ်မှတ်ပါတယ်။ ဆိုတော့ ကိုယ့်မှာ တစ်ခြား data set ရှိရင် folder ကိုအလိုက်သင့်ဆောက်ပြီး တစ်ခြား label နဲ့စမ်းလို့ရပါတယ်။ ဉပမာ မု့န်ဟင်းခါးဟုတ်လား မဟုတ်လားစစ်မယ်ဆိုပါတော့။
bottleneck_dir
က မထည့်လည်းရတယ်။ သူကတော့ bottleneck file တွေကိုဘယ်လမ်းကြောင်းမှာ output ထုတ်ပေးရမလဲ သတ်မှတ်ပေးတယ်။ ဒီမှာတော့ ဘာလို့သုံးတာလဲမရှင်းပြတော့ပါဘူး။ စိတ်ဝင်စားတော့ ဒီမှာ ဝင်ဖတ်လို့ရပါတယ်။
how_many_training_steps
ကတော့ ဖတ်လိုက်တာနဲ့နားလည်မှာပါ။ ဘယ်နခါလောက် iterate လုပ်ချင်လဲသတ်မှတ်ပေးတယ်။ များရင်များသလောက်ပိုကြာမယ်။ အရမ်းများသွားရင်လည်း accuracy ပိုကျသွားနိုင်တယ်။ ကျွန်တော်တော့ ၅၀၀ နဲ့စမ်းပြထားတယ်။
output_graph
ကတော့ ဒီ retrain လုပ်ထားပြီးသား model graph ကိုဘယ်မှာထားချင်လယ်ဆိုတာကိုသတ်မှတ်ပါတယ်။ ပြီးရင် ဒီ file ကိုပဲသုံးပြီး ကျွန်တော်တို့ tflite format ကိုပြောင်းပါမယ်။
output_label
ကတော့ ဖြစ်နိုင်တဲ့ label output ကိုဘယ်မှာသိမ်းမလဲသတ်မှတ်ပေးပါတယ်။ ကျွန်တော်တို့ကတော့ label က hot_dog နဲ့ not_hot_dog ပဲဖြစ်နိုင်ချေရှိပါတယ်။
tfhub_module
ကတော့ ကျွန်တော်တို့ tensorflow hub (tfhub) ကဘယ် model ကိုအသုံးချပြီး ပြန် retrain လုပ်မယ်ဆိုတာကို သတ်မှတ်ပေးတယ်။ tfhub link ကဘယ် link မဆိုရတယ်။ ဒေါင်းပြီးသား file ကိုထည့်ပေးလည်းအဆင်ပြေတယ်။ ကျွန်တော်ကတော့ ခုနကဒေါင်းခဲ့တဲ့ model ကိုပဲသုံးပါမယ်။
Coverting to TFLite
ကျွန်တော်တို့လိုချင်တဲ့ HotDog ဟုတ်လားမဟုတ်လားပဲသိတဲ့ model တော့ရလာပြီ။ဒါပေမဲ့ mobile မှာအဆင်ပြေစေဖို့ TensorFlow Lite (TFLite) format ကိုကျွန်တော်တို့ပြောင်းရဦးမယ်။ ဒီအတွက် TensorFlow Lite Optimizing Converter (TOCO) ဆိုတဲ့ tool လေးတစ်ခုကိုသုံးမယ်။ ဒီအတွက် command ကတော့
~ toco \
--graph_def_file=tf_files/retrained_graph.pb \
--output_file=tf_files/nothotdog.tflite \
--input_format=TENSORFLOW_GRAPHDEF \
--output_format=TFLITE \
--input_shape=1,224,224,3 \
--input_array=Placeholder \
--output_array=final_result \
--inference_type=FLOAT \
--input_data_type=FLOAT
graph_def_file
က ကျွန်တော်တို့ခုနက output_graph အဖြစ်ထားခဲ့တဲ့ retrained_graph.pb ကိုကျွန်တော်တို့ ဒီမှာ input အဖြစ်ပြန်သုံးမယ်။
output_file
ကတော့ tflite format နဲ့ဖြစ်မယ်။ ရှေ့ကတော့ကြိုက်တာသုံးလို့ရပါတယ်။
input_format
ကတော့ TensorFlow graph definition ဖြစ်မယ်။
output_format
က TFLite နဲ့လိုချင်တယ်။
Input_shape က ဒီမှာ input array ပုံစံကိုသတ်မှတ်ပေးထားတာဖြစ်တယ်။ ကျွန်တော်တို့က 4-D array တစ်ခုကိုသုံးမယ်။
- တစ်ကြိမ်ကို ပုံတစ်ခုပဲစမ်းခွင့်ရှိမယ်။
- ပုံရဲ့ အလျားက 224 pixels ရှိမယ်။
- ပုံရဲ့အနံက 224 pixels ရှိမယ်။ (ကိုယ်သုံးထားတဲ့ mobile net အမျိုအးစားပေါ်မူတည်ပြီးပြောင်းနိုင်မယ်)
- Pixel တစ်ခုဆီမှာ Red,Green,Blue (RGB) ဆိုပြီး သုံးမျိုးရှိတယ်။
ဒါကြောင့် input shape က 1x224x224x3 array တစ်ခုဖြစ်မယ်။
input_array/output_array ကတော့ ကြိုက်တဲ့နာမည်ပေးလို့ရတယ်။
ကျွန်တော်တို့သုံးမဲ့ Pixel တစ်ခုချင်းစီရဲ့ RGB တွေရဲ့ Data type က float ဖြစ်လို့ FLOAT type ကိုပဲ သုံးသွားမယ်။
Run လိုက်မယ်ဆိုရင် ကျွန်တော်တို့ လိုချင်တဲ့ TfLite Model တော့ရလာပြီ။ ဒါဆို python အပိုင်းပြီးသွားပါပြီ။ Android အပိုင်းကိုဆက်ရေးကြမယ်။
Add Firebase to Project
အရင်ဆုံး ကျွန်တော်တို့ Play Service အရင်ထည့်ရမယ်။ ဒါကိုတော့ ကျွန်တော်အသေးစိတ်မပြောတော့ဘူး။ Play Services ထည့်ပြီးပြီဆိုရင် app ရဲ့ gradle မှာ ဒီ dependencies တွေထည့်ပေးရမယ်။
implementation 'com.google.firebase:firebase-core:16.0.0'
implementation 'com.google.firebase:firebase-ml-model-interpreter:16.2.0'
ပြီးရင်တော့ပြန် build လိုက်ပါ။
Constants
အရင်ဆုံးကျွန်တော်တို့ Input Constants တွေသတ်မှတ်ကြမယ်။ Input ကတော့သိပြီ။Output က ပုံတစ်ပုံကို ရလဒ်တစ်ခု။ ရလဒ်က hotdog သော်လည်းကောင်း၊ not hotdog သော်လည်းကောင်းဖြစ်နိုင်လို့ output array က 1x2 ဖြစ်မယ်။
//224x224 as defined by model
val IMAGE_HEIGHT = 224
val IMAGE_WIDTH = 224
//Batch size
val BATCH_SIZE = 1
//RGB
val PIXEL_SIZE = 3
//Output Label Count
val LABEL_COUNT = 2
တကယ်လို့ ကိုယ်က သူများပြင်ပေးထားတဲ့ TFLite ကိုသုံးမယ်ဆိုရင် ဒီ website မှာ tflite လေးပစ်ထည့်ပြီး format ဘာညာ ကာလာ အနေအထားတွေကိုဝင်ကြည့်လို့ရတယ်။
Setting up TFLite Model
ကျွန်တော်တို့ ခုနကထုတ်ခဲ့တဲ့ TFLite file ကို ကျွန်တော်တို့ App လေးရဲ့ asset အောက်ထဲထည့်ပေးရမယ်။ Firebase Console မှာပါတဲ့ MLKit မှာ တင်ထားလည်းရတယ်။ ဒါဆိုရင်တော့ file ကို ဒေါင်းဖို့ အရင်အချိန်ပေးရလိမ့်မယ်။ တစ်ခုကောင်းတာကတော့ App update စရာမလိုပဲ model version ကိုတင်သွားလို့ရတယ်။ ဒီမှာတော့ ကျွန်တော် offline ပဲစမ်းပြထားမယ်။ ပြန်သွားရရင် Asset ထဲထည့်ပြီးရင် ကျွန်တော်တို့ source သတ်မှတ်ပေးမယ်။
//Setup with asset
//You can also add FirebaseCloudModelSource here
val firebaseModelSource = FirebaseLocalModelSource.Builder("NotHotDog")
.setAssetFilePath("nothotdog.tflite")
.build()
ပြီးရင် ကျွန်တော်တို့သတ်မှတ်ထားတဲ့ source ကို register လုပ်ပေးရမယ်။
//Register the module to FirebaseManager
FirebaseModelManager.getInstance().registerLocalModelSource(firebaseModelSource)
ပြီးရင် Options ကိုထတ်သတ်မှတ်ပေးရတယ် (နည်းနည်းတော့ အလုပ်ရှုပ်တယ် 😆)
//Create Options class
//Name has to the same as the one we defined for firebaseModelSource
val modelOptions = FirebaseModelOptions.Builder()
.setLocalModelName("NotHotDog")
.build()
နောက်ဆုံးမှာတော့ model file ကိုဖတ်နိုင်တဲ့ interpreter တစ်ခုရပါပြီ။
val firebaseInterpreter = FirebaseModelInterpreter.getInstance(modelOptions)!!
ဒါနဲ့ မပြီးသေးဘူး ကျွန်တော်တို့ input ouput format ကိုပါထပ်ပြောပေးရမယ်။ အောက်ရောက်ရင် ဒါကိုပြန်သုံးရမယ်။ Builder မှာ Parameter ကသုံးမျိုးရှိမယ်။
- ပထမ parameter က index ကိုပြောချင်တာဖြစ်တယ်။ ပုံတစ်ပုံတည်းမဟုတ်ပဲ ပုံသုံးမျိုးလောက်ကို input သတ်မှတ်မယ်ဆိုရင် သူတို့ format တွေကတူချင်မှ တူမယ်ဆိုပါဆို့။ ဒါဆိုရင် index နဲ့တစ်ခုချင်းစီရဲ့ formart တွေခွဲပေးလို့ရတယ်။ ကျွန်တော်တို့ကတော့ input/ouput တစ်ခုပဲရှိလို့ index 0 ကိုပဲစိတ်ဝင်စားတယ်။
- ဒုတိယက Data type ပါ။ ကျွန်တော်တို့က Input ကော output ကော Float နဲ့ပဲလာမှာဖြစ်လို့ FLOAT32 ကိုသုံးထားတယ်။
- တတိယက array size ကိုသတ်မှတ်ပေးရတယ်။ ကျွန်တော်တို့ကတော့ input က အပေါ်မှာပြောခဲ့သလို 1x224x224x3။ output က 1x2 ဖြစ်မယ်။
val inputOutputOptions = FirebaseModelInputOutputOptions.Builder()
.setInputFormat(0, FirebaseModelDataType.FLOAT32, intArrayOf(BATCH_SIZE, IMAGE_HEIGHT, IMAGE_WIDTH, PIXEL_SIZE))
.setOutputFormat(0, FirebaseModelDataType.FLOAT32, intArrayOf(BATCH_SIZE, LABEL_COUNT))
.build()
Converting Bitmap to Float
Tensorflow ဘက်ကတော့ အဆင်သင့်ဖြစ်နေပြီ။ ခက်တာက Android မှာ ပုံတွေက Android ရဲ့ကိုယ်ပိုင် Bitmap class အနေနဲ့သိမ်းထားတယ်။ ကျွန်တော်တို့ input type က Float ဆိုတော့ ကျွန်တော်တို့ Bitmap ထဲက Pixel တွေကို Float array နဲ့သိမ်းမှရမယ်။ အရင်ဆုံးကျွန်တော်တို့ Pixel တွေဆွဲထုတ်လိုက်မယ်။ ဒါပေမဲ့ lower level မှာ စက်နားလည်တာက byte တွေဆိုတော့ ကျွန်တော်တို့တွေ byte array တစ်ခုအဖြစ်သိမ်းမယ်။
//FB requires direct byte buffer with native byte order
val imageByteBuffer =ByteBuffer.allocateDirect(
4 *
BATCH_SIZE *
PIXEL_SIZE *
IMAGE_HEIGHT *
IMAGE_WIDTH
)
imageByteBuffer.order(ByteOrder.nativeOrder())
Firebase interpreter က Direct byte buffer ကိုပဲနားလည်လို့ ကျွန်တော်တို့တွေ အရင်ဆုံး လိုအပ်သလောက် direct byte buffer တစ်ခုယူထားမယ်။ ဘယ်လောက်ယူမှာလဲဆိုတော့ 4x1x3x224x224 ဖြစ်တယ်။ အပေါ်က input/output options မှာသုံးခဲ့တာ FLOAT32 ဆိုတဲ့အတိုင်း 32 bit ဖြစ်လို့ bit ကို byte ပြောင်းရင် 1 byte မှာ 8 bit ဆိုတော့ 32/8=4 ရမယ်။ ဒါ့ကြောင့်မလို့ 4 နဲ့မြှောက်ထားတယ်။ Phone ပေါ်မူတည်ပြီး Phone ရဲ့ Default byte order ကိုပဲယူချင်လို့ nativeOrder သုံးထားတယ်။ ByteOrder အကြောင်း စိတ်ဝင်စားရင် ဒီမှာဖတ်ကြည့်လို့ရပါတယ်။
ရလာတဲ့ Bitmap (Gallery ကပဲဖြစ်ဖြစ်၊ camera ကပဲဖြစ်ဖြစ်။ ဒါတော့ရေးမပြတော့ဘူး။) ကို လိုချင်တဲ့ format ဖြစ်အောင် ချုံ့/ခြဲ့ လုပ်မယ်။ ဒီမှာတော့ 224x224 ဖြစ်မှာပေါ့။ နောက်ဆုံးက false ကတော့ ဘာ color mask မှမသုံးဘူး။ အရှိတိုင်းပဲထားမယ်လို့ ပြောလိုက်တာဖြစ်တယ်။
val scaledBitmap = Bitmap
.createScaledBitmap(bitmap,
IMAGE_WIDTH,
IMAGE_HEIGHT,
false)
ပြီးရင် ကျွန်တော်တို့ Bitmap က Pixel တွေကို 224x224 ရှိတဲ့ array တစ်ခုထဲမှာ သိမ်းလိုက်မယ်။
val intValues = IntArray(IMAGE_HEIGHT * IMAGE_WIDTH)
scaledBitmap.getPixels(
intValues,
0,
bitmap.width,
0,
0,
bitmap.width,
bitmap.height
)
- Image size က 224 x 224 ဖြစ်ရမယ်၊။ ဒီတော့ 224x224 array တစ်ခုဆောက်ပြီး ဒီ array ထဲထည့်ပါမယ်လို့ပြောထားတယ်။
- Offset က 0 ဖြစ်မယ်။ ဟိုးအစကနေ စ write မှာဖြစ်လို့ 0 offset ဖြစ်နေရမယ်။
- တတိယ parameter ဖြစ်တဲ့ Stride က row တစ်ခုနဲ့တစ်ခုကြား pixel ဘယ်နှစ်ခုကျော်ရမယ်ဆိုတာကိုသတ်မှတ်ပေးတယ်။ ကျွန်တော်တို့ကတော့ ဘာမှမကျော်ခွဘူးဆိုတော့ တစ်လိုင်းဆင်းသွားတိုင်း bitmap ရဲ့ ရှိသလောက် width ကိုကျော်ပြီး ပြန်စမယ်။ ဉပမာ 2nd row ဆိုရင် pixel index 224 ကပြန်စမယ်ဆိုပါတော့။
- စဖတ်ရမဲ့ x-position က 0 ဖြစ်တယ်။
- အဲလိုပဲ y-position ကလည်း 0 ဖြစ်မယ်။
- ဘယ်လောက်ထိ width ရှိတာလဲဆိုတော့ bitmap ရဲ့ width ရှိသလောက်ဖြစ်မယ်။
- height ကလည်း bitmap height ရှိသလောက်ယူမယ်။
ပြီးရင်ကျွန်တော်တို့ Pixel တွေကို ခုနက ယူထားခဲတဲ့ byte buffer array ထဲပြောင်းရမယ်။
//Mean and standard deviation
val IMAGE_MEAN = 128
val IMAGE_STD = 128.0f// Convert the image to floating point.
var pixel = 0
for (i in 0 until IMAGE_HEIGHT) {
for (j in 0 until IMAGE_WIDTH) {
val currPixel = intValues[pixel++]
imageByteBuffer.putFloat(((currPixel shr 16 and 0xFF) - IMAGE_MEAN) / IMAGE_STD)
imageByteBuffer.putFloat(((currPixel shr 8 and 0xFF) - IMAGE_MEAN) / IMAGE_STD)
imageByteBuffer.putFloat(((currPixel and 0xFF) - IMAGE_MEAN) / IMAGE_STD)
}
}
ဒါကတော့ ရှင်းရင်တော်တော်ရှည်သွားမယ်။ အဓိကကတော့ RGB value တွေရအောင် Bitwise operator သုံးပြီးယူထားတာပါ။ ပြီးတော့မှ float အဖြစ်ပြန်ပြောင်းထားတယ်။ ဒီ stackoverflow answer လေးကတော့ ရှင်းပြထားတာ တော်တော်ပြည့်စုံပါတယ်။
Running the model
ဒါဆိုရင်တော့ ကျွန်တော်တို့တွေ ပြင်ဆင်စရာတွေပြင်ဆင်ပြီးပြီ။ Model နဲ့ ချိတ်ကြမယ်။အရင်ဆုံး ခုနကယူခဲ့တဲ့ bytebuffer ကို input အဖြစ်သတ်မှတ်မယ်။
val inputs = FirebaseModelInputs.Builder()
.add(imageByteBuffer)
.build()
ဒါတွေအားလုံးပြီးရင်အပေါ်က သတ်မှတ်ထားခဲ့တဲ့ interpreter ကို စ run လို့ရမယ်။ ဒီမှာ input နဲ့ လိုချင်တဲ့ input/output format options တွေကိုထည့်ပေးရမယ်။
firebaseInterpreter.run(inputs, inputOutputOptions)
?.addOnSuccessListener { modelOutput ->
//TODO Add Success code
}
Output ထဲက result ကိုကြည့်ဖို့ကတော့..
val result = modelOutput.getOutput<Array<FloatArray>>(0)[0]
Output index 0 မှာပါလာမှာက သတ်မှတ်ထားခဲ့တဲ့ 1x2 array ဖြစ်တယ်။ ဒီထဲကမှာမှထပ်ပြီး 0 index ကိုထပ်ယူမယ်။ ဒါဆိုရင် ကျွန်တော်တို့မှာ size 2 ရှိတဲ့ array ပဲကျန်မယ်။
result အခန်း 0 က hot dog ဖြစ်တန်စွမ်း၊ 1 က not hot dog ဖြစ်တန်စွမ်း။
//Index 0 is hot dog and index 1 is not hot dog
val hotDogProbability = result[0]
val notHotDogProbability = result[1]Log.d("Result", "hot dog probability : $hotDogProbability")
Log.d("Result", "Not hot dog probability : $notHotDogProbability")
ကိုယ်သတ်မှတ်ထားတဲ့ အနည်းဆုံးဖြစ်တန်းစွမ်းထက်များရင် ဒါ hot dog ပဲ ဆိုပြီးသတ်မှတ်မယ်။ ကျွန်တော်ကတော့ 0.8 လောက်ပေးတယ်။
//If greater than minimum probability, then it's hot dog
val minimumProbability = 0.8f
val isHotDog = hotDogProbability > minimumProbability
//TODO Show result
ဒါဆိုရင်တော့ ကျွန်တော်တို့ရဲ့ NotHodg App လေးပြီးဆုံးသွားပါပြီ။ User ကို ပြန်ပြဖို့ကတော့ ဆက်ရေးရမှာပေါ့။ တစ်ခုရှိတာက ကျွန်တော်တို့က full resolution ပုံတွေကို 224x224 ဖြစ်အောင် လျှော့ရတောဆိုတော့ ကြားထဲမှာ loss တွေတအားများတယ်။ ဒါကြောင့်မလို့ accuracy ကိုတော့ အမြင့်ကြီးဖြစ်မယ်လို့ မမျှော်လင့်ထားပါနဲ့။ ကျွန်တော်စမ်းတာတော့ ပေါင်မုန့်မှန်သမျှကို hot dog ကြီးပဲပြောနေတယ် 😅။ ကျွန်တော့ Code ကိုကြည့်ချင်ရင် ဒီ Repo မှာကြည့်လို့ရပါတယ်။
ဒီလောက်ဆိုရင်တော့ TFLite အသုံးပြုပုံကို အခြေခံလောက်တော့သိသွားပြီ။ ဒါကိုလေ့လာဖို့ Reference အနေနဲ့ မှီဝဲခဲ့တာကတော့
- https://www.tensorflow.org/hub/tutorials/image_retraining
- https://github.com/tensorflow/hub/tree/master/examples/image_retraining
- https://codelabs.developers.google.com/codelabs/tensorflow-for-poets (Codelab က ကျွန်တော်လုပ်တုန်းက out-of-date ဖြစ်နေတယ် 😛)
- https://heartbeat.fritz.ai/building-pok%C3%A9dex-in-android-using-tensorflow-lite-and-firebase-cc780848395
စာကြွင်း။ Tensorflow Expert မဟုတ်လို့ မှားတာပါရင်လည်း ပြင်ပေးကြပါဦီး။