สร้างแอป iOS เพื่อคาดการณ์ค่า

สร้างแอป iOS เพื่อคาดการณ์ค่า

เกี่ยวกับ Codelab นี้

subjectอัปเดตล่าสุดเมื่อ เม.ย. 8, 2022
account_circleเขียนโดย Wei Wei

1 ข้อควรทราบก่อนที่จะเริ่มต้น

ใน Codelab นี้ คุณดูวิธีเรียกใช้การถดถอยจากแอป iOS โดยใช้ TensorFlow Serving ที่มี REST และ gRPC

สิ่งที่ต้องมีก่อน

  • ความรู้เบื้องต้นเกี่ยวกับการพัฒนาบน iOS ด้วย Swift
  • ความรู้เบื้องต้นเกี่ยวกับแมชชีนเลิร์นนิงด้วย TensorFlow เช่น การฝึกอบรมและการทําให้ใช้งานได้
  • ความรู้พื้นฐานเกี่ยวกับ Colaboratory
  • ความรู้เบื้องต้นเกี่ยวกับเทอร์มินัล, Python และ Docker

สิ่งที่คุณจะได้เรียนรู้

  • วิธีฝึกโมเดลการถดถอยด้วย TensorFlow
  • วิธีสร้างแอป iOS แบบง่ายๆ และสร้างการคาดการณ์ด้วยโมเดลที่ฝึกผ่าน TensorFlow Serving (REST และ gRPC)
  • วิธีแสดงผลลัพธ์ใน UI

สิ่งที่ต้องมี

2 ตั้งค่า

วิธีดาวน์โหลดโค้ดสําหรับ Codelab นี้

  1. ไปที่ที่เก็บ GitHub สําหรับ Codelab นี้
  2. คลิก Code > Download ZIP เพื่อดาวน์โหลดโค้ดทั้งหมดสําหรับ Codelab นี้

a72f2bb4caa9a96.png

  1. แตกไฟล์ ZIP ที่ดาวน์โหลดเพื่อคลายโฟลเดอร์ราก codelabs ที่มีทรัพยากรทั้งหมดที่คุณต้องการ

Codelab นี้ต้องการเฉพาะไฟล์ในไดเรกทอรีย่อย TFServing/RegressioniOS ในที่เก็บ ซึ่งมี 2 โฟลเดอร์ดังนี้

  • โฟลเดอร์ starter มีโค้ดเริ่มต้นที่คุณสร้างสําหรับ Codelab นี้
  • โฟลเดอร์ finished มีโค้ดที่สมบูรณ์สําหรับแอปตัวอย่างที่สมบูรณ์

3 ดาวน์โหลดทรัพยากร Dependency สําหรับโปรเจ็กต์

ดาวน์โหลดพ็อดที่จําเป็น

  • ในโฟลเดอร์ starter/iOS ให้เรียกใช้
pod install

Cocoapods จะติดตั้งไลบรารีที่จําเป็นทั้งหมดและสร้างไฟล์ regression.xcworkspace ใหม่

4 เรียกใช้แอปเริ่มต้น

  • ดับเบิลคลิกไฟล์ regression.xcworkspace เพื่อเปิด Xcode

เรียกใช้และสํารวจแอป

  1. เปลี่ยนเป้าหมายของอุปกรณ์เป็น iPhone เช่น iPhone 13

a57198a4f21f970.png

  1. คลิก cacc15c5638260ed.png "Run' แล้วรอให้ Xcode คอมไพล์โปรเจ็กต์และเริ่มแอปเริ่มต้นในเครื่องจําลอง

UI มีความตรงไปตรงมา จะมีกล่องข้อความสําหรับพิมพ์ตัวเลขซึ่งจะส่งไปที่แบ็กเอนด์ TensorFlow Serving ที่มี REST หรือ gRPC แบ็กเอนด์จะดําเนินการรีเซ็ตค่าที่ป้อน และจะส่งคืนค่าที่คาดการณ์ไว้ไปยังแอปไคลเอ็นต์ซึ่งจะแสดงผลใน UI อีกครั้ง

D2976072474ce0b1.png

หากคุณป้อนตัวเลขแล้วคลิกอนุมาน ไม่มีอะไรเกิดขึ้นเนื่องจากแอปยังสื่อสารกับแบ็กเอนด์ไม่ได้

5 ฝึกโมเดลการถดถอยแบบง่ายด้วย TensorFlow

การถดถอยเป็นหนึ่งในงาน ML ที่พบบ่อยที่สุด โดยมีเป้าหมายเพื่อคาดการณ์ปริมาณอย่างต่อเนื่องรายการเดียวโดยพิจารณาจากอินพุต ตัวอย่างเช่น โดยอิงตามสภาพอากาศวันนี้ คาดการณ์ว่าอุณหภูมิสูงสุดในวันพรุ่งนี้

ฝึกโมเดลการถดถอย

  1. เปิดลิงก์นี้ในเบราว์เซอร์

Colab โหลดสมุดบันทึก Python

  1. นําเข้าไลบรารี TensorFlow และ NumPy ในสมุดบันทึก Python แล้วสร้างข้อมูลการฝึก 6 คู่ที่มี xs เป็นอินพุต และ ys เป็นป้ายกํากับ

หากคุณพล็อตจุดข้อมูลเหล่านี้บนกราฟ จริงๆ แล้วข้อมูลเหล่านั้นจะอยู่ในเส้นตรง เนื่องจากข้อมูลเหล่านี้สร้างขึ้นจากสมการ y = 2x -1

56d05252cfc9df9d.png

  1. ใช้ Keras API เพื่อสร้างเครือข่ายโครงข่ายระบบประสาทเทียมแบบ 2 ชั้นเพื่อคาดการณ์ค่า y โดยอิงตามอินพุต x จากนั้นคอมไพล์และจําลองโมเดล
xs = np.array([-1.0,  0.0, 1.0, 2.0, 3.0, 4.0], dtype=float)
ys
= np.array([-3.0, -1.0, 1.0, 3.0, 5.0, 7.0], dtype=float)

model
= tf.keras.Sequential([
   tf
.keras.layers.Dense(units=10, input_shape=[1]),
   tf
.keras.layers.Dense(units=1),
   
])

model
.compile(optimizer='sgd',
             loss
='mean_squared_error')

history
= model.fit(xs, ys, epochs=500, verbose=0)

print("Finished training the model")

print(model.predict([10.0]))

โมเดลนี้ใช้เวลาเพียง 2-3 วินาทีในการฝึก และคุณจะเห็นค่าที่คาดการณ์ของอินพุต 10 คือ 18.999996 ซึ่งเป็นการคาดการณ์ที่ค่อนข้างดีมากเนื่องจากข้อเท็จจริงพื้นฐานคือ 2 * 10 -1 = 19

  1. ส่งออกโมเดล:
model_dir = './regression/'
version
= 123
export_path
= os.path.join(model_dir, str(version))
model
.save(export_path, save_format="tf")
print('\nexport_path = {}'.format(export_path))
!ls -l {export_path}
  1. บีบอัด ระบบจะบันทึก Model Model ที่ส่งออกเป็นไฟล์ regression.zip ไฟล์เดียว ดังนี้
!zip -r regression.zip ./regression
  1. คลิก Runtime > Run all ในเมนูการนําทางเพื่อเรียกใช้สมุดบันทึกและรอให้การเรียกใช้เสร็จสิ้น
  2. คลิก c55600d42359f901.png Files แล้วดาวน์โหลดไฟล์ regression.zip

bcaa15d86571583.png

6 ทําให้โมเดลการเกิดปัญหาซ้ําใช้งานได้ด้วยการแสดงผล TensorFlow

  • หากต้องการทําให้โมเดลใช้งานได้ด้วยการแสดงผล TensorFlow ให้ยกเลิกการบีบอัดไฟล์ regression.zip ที่ดาวน์โหลดด้วยเครื่องมือขยายข้อมูลที่บีบอัดไว้ เช่น 7-Zip

โครงสร้างโฟลเดอร์ควรมีลักษณะเช่นนี้

7faeb4f03af39646.png

คุณจะอ้างอิงโฟลเดอร์ regression ว่าเป็นโฟลเดอร์ SavedModel ก็ได้ 123 เป็นหมายเลขเวอร์ชันตัวอย่าง คุณเลือกหมายเลขอื่นได้หากต้องการ

เริ่มแสดงโฆษณา TensorFlow

  • ในเทอร์มินัล ให้เริ่มแสดงโฆษณา TensorFlow ด้วย Docker แต่แทนที่ตัวยึดตําแหน่ง PATH/TO/SAVEDMODEL ด้วยเส้นทางสัมบูรณ์ของโฟลเดอร์ regression ในคอมพิวเตอร์
docker pull tensorflow/serving

docker run -it --rm -p 8500:8500 -p 8501:8501 -v "PATH/TO/SAVEDMODEL:/models/regression" -e MODEL_NAME=regression tensorflow/serving

Docker จะดาวน์โหลดอิมเมจการแสดงผล TensorFlow โดยอัตโนมัติก่อน ซึ่งจะใช้เวลา 1 นาที หลังจากนั้น TensorFlow Serving ควรจะเริ่มแสดง บันทึกควรมีลักษณะเหมือนข้อมูลโค้ดนี้

2022-02-25 06:01:12.513231: I external/org_tensorflow/tensorflow/cc/saved_model/loader.cc:206] Restoring SavedModel bundle.
2022-02-25 06:01:12.585012: I external/org_tensorflow/tensorflow/core/platform/profile_utils/cpu_utils.cc:114] CPU Frequency: 3000000000 Hz
2022-02-25 06:01:13.395083: I external/org_tensorflow/tensorflow/cc/saved_model/loader.cc:190] Running initialization op on SavedModel bundle at path: /models/ssd_mobilenet_v2_2/123
2022-02-25 06:01:13.837562: I external/org_tensorflow/tensorflow/cc/saved_model/loader.cc:277] SavedModel load for tags { serve }; Status: success: OK. Took 1928700 microseconds.
2022-02-25 06:01:13.877848: I tensorflow_serving/servables/tensorflow/saved_model_warmup_util.cc:59] No warmup data file found at /models/ssd_mobilenet_v2_2/123/assets.extra/tf_serving_warmup_requests
2022-02-25 06:01:13.929844: I tensorflow_serving/core/loader_harness.cc:87] Successfully loaded servable version {name: regression version: 123}
2022-02-25 06:01:13.985848: I tensorflow_serving/model_servers/server_core.cc:486] Finished adding/updating models
2022-02-25 06:01:13.985987: I tensorflow_serving/model_servers/server.cc:367] Profiler service is enabled
2022-02-25 06:01:13.988994: I tensorflow_serving/model_servers/server.cc:393] Running gRPC ModelServer at 0.0.0.0:8500 ...
[warn] getaddrinfo: address family for nodename not supported
2022-02-25 06:01:14.033872: I tensorflow_serving/model_servers/server.cc:414] Exporting HTTP/REST API at:localhost:8501 ...
[evhttp_server.cc : 245] NET_LOG: Entering the event loop ...

7 เชื่อมต่อแอป iOS กับ TensorFlow Serving ผ่าน REST

แบ็กเอนด์พร้อมให้บริการแล้ว คุณจึงส่งคําขอไคลเอ็นต์ไปยังบริการ TensorFlow เพื่อทําการคาดการณ์ได้ คุณส่งคําขอไปยังการแสดง TensorFlow ได้ 2 วิธีดังนี้

  • REST
  • gRPC

ส่งคําขอและรับการตอบกลับด้วย REST

มี 3 ขั้นตอนง่ายๆ ดังนี้

  1. สร้างคําขอ REST
  2. ส่งคําขอ REST ไปยังการแสดงผล TensorFlow
  3. ดึงผลลัพธ์ที่คาดการณ์ไว้จากการตอบกลับของ REST และแสดง UI

คุณจะทําขั้นตอนเหล่านี้ได้ในไฟล์ iOS/regression/ViewController.swift

สร้างคําขอ REST

  1. ขณะนี้ฟังก์ชัน doInference() ไม่ได้ส่งคําขอ REST ไปยังการแสดงผล TensorFlow คุณต้องใช้สาขา REST นี้เพื่อสร้างคําขอ REST ดังนี้
if (connectionMode[picker.selectedRow(inComponent: 0)] == "REST") {
   
print("Using REST")
   
// TODO: Add code to send a REST request to TensorFlow Serving.
   
}

การแสดงผล TensorFlow ต้องการคําขอ POST ที่มีค่าเดียว คุณจึงต้องฝังค่าอินพุตใน JSON ซึ่งเป็นเพย์โหลดของคําขอ

  1. เพิ่มโค้ดนี้ลงในสาขา REST
//Create the REST request.
let json
: [String: Any] = ["signature_name" : "serving_default", "instances" : [[value]]]

let jsonData
= try? JSONSerialization.data(withJSONObject: json)

let url
= URL(string: "http://localhost:8501/v1/models/regression:predict")!
var request = URLRequest(url: url)
request
.httpMethod = "POST"

// Insert JSON data into the request.
request
.httpBody = jsonData

ส่งคําขอ REST ไปยังการแสดงโฆษณา TensorFlow

  • เพิ่มรหัสนี้ทันทีหลังจากรหัสในสาขา REST
// Send the REST request.
let task
= URLSession.shared.dataTask(with: request) { data, response, error in
    guard let data
= data, error == nil else {
       
print(error?.localizedDescription ?? "No data")
       
return
   
}
   
   
// TODO: Add code to process the response.
}

task
.resume()

ประมวลผลการตอบกลับ REST จาก TensorFlow Serving

  • เพิ่มโค้ดนี้ในข้อมูลโค้ดก่อนหน้าหลังความคิดเห็น TODO: Add code to process the response.
// Process the REST response.
let results
: RESTResults = try! JSONDecoder().decode(RESTResults.self, from: data)
DispatchQueue.main.async{
   
self.txtOutput.text = String(results.predictions[0][0])
}

ตอนนี้ฟังก์ชันหลังการประมวลผลจะแยกค่าที่คาดการณ์ไว้ออกจากการตอบกลับ และแสดงผลลัพธ์ใน UI

เรียกใช้

  1. คลิก cacc15c5638260ed.png "Run' แล้วรอให้ Xcode เปิดแอปในเครื่องจําลอง
  2. ป้อนตัวเลขในกล่องข้อความ แล้วคลิกอนุมาน

ตอนนี้คุณจะเห็นค่าที่คาดการณ์ใน UI

df9bcb9aa21bb30e.png

8 เชื่อมต่อแอป iOS กับ TensorFlow Serving ผ่าน gRPC

นอกจาก REST แล้ว TensorFlow Serving ยังรองรับ gRPC อีกด้วย

b6f4449c2c850b0e.png

gRPC เป็นเฟรมเวิร์ก Call Procedure Call (RPC) แบบโอเพนซอร์สที่มีประสิทธิภาพสูงและใช้งานได้กับทุกสภาพแวดล้อม เครื่องมือนี้จะเชื่อมบริการอย่างมีประสิทธิภาพทั่วทั้งศูนย์ข้อมูลต่างๆ ที่รองรับความสามารถในการจัดสรรภาระงาน การติดตาม การตรวจสอบประสิทธิภาพการทํางาน และการตรวจสอบสิทธิ์แบบเสียบปลั๊กได้ พบว่า gRPC มีประสิทธิภาพมากกว่า REST ในทางปฏิบัติ

ส่งคําขอและรับการตอบกลับด้วย gRPC

มี 4 ขั้นตอนง่ายๆ ดังนี้

  1. ไม่บังคับ: สร้างโค้ดไคลเอ็นต์ gRPC
  2. สร้างคําขอ gRPC
  3. ส่งคําขอ gRPC ไปยัง TensorFlow Serving
  4. ดึงผลลัพธ์ที่คาดการณ์ไว้จากการตอบกลับของ gRPC และแสดง UI

คุณจะทําขั้นตอนเหล่านี้ได้ในไฟล์ iOS/regression/ViewController.swift

ไม่บังคับ: สร้างโค้ดไคลเอ็นต์ gRPC

หากต้องการใช้ gRPC กับการให้บริการ TensorFlow คุณต้องทําตามเวิร์กโฟลว์ gRPC ดูข้อมูลเพิ่มเติมเกี่ยวกับรายละเอียดได้ที่เอกสารประกอบ gRPC

a9d0e5cb543467b4.png

TensorFlow Serving และ TensorFlow จะกําหนดไฟล์ .proto ให้คุณ เมื่อคํานึงถึง TensorFlow และ TensorFlow Serving 2.8 จึงต้องมีไฟล์ .proto รายการต่อไปนี้

tensorflow/core/example/example.proto
tensorflow
/core/example/feature.proto
tensorflow
/core/protobuf/struct.proto
tensorflow
/core/protobuf/saved_object_graph.proto
tensorflow
/core/protobuf/saver.proto
tensorflow
/core/protobuf/trackable_object_graph.proto
tensorflow
/core/protobuf/meta_graph.proto
tensorflow
/core/framework/node_def.proto
tensorflow
/core/framework/attr_value.proto
tensorflow
/core/framework/function.proto
tensorflow
/core/framework/types.proto
tensorflow
/core/framework/tensor_shape.proto
tensorflow
/core/framework/full_type.proto
tensorflow
/core/framework/versions.proto
tensorflow
/core/framework/op_def.proto
tensorflow
/core/framework/graph.proto
tensorflow
/core/framework/tensor.proto
tensorflow
/core/framework/resource_handle.proto
tensorflow
/core/framework/variable.proto

tensorflow_serving
/apis/inference.proto
tensorflow_serving
/apis/classification.proto
tensorflow_serving
/apis/predict.proto
tensorflow_serving
/apis/regression.proto
tensorflow_serving
/apis/get_model_metadata.proto
tensorflow_serving
/apis/input.proto
tensorflow_serving
/apis/prediction_service.proto
tensorflow_serving
/apis/model.proto

วิธีสร้างโค้ดไคลเอ็นต์ gRPC

  1. จากนั้นไปที่โฟลเดอร์ starter/src/proto/ ในเทอร์มินัลแล้วสร้างหลอดไฟ
bash generate_grpc_stub_swift.sh

ไฟล์ .swift จํานวนหนึ่งอยู่ในโฟลเดอร์ starter/src/proto/generated/import

  1. หากยังไม่มีการคัดลอกไปยังโปรเจ็กต์ ให้ลากไฟล์ .swift ที่สร้างขึ้นทั้งหมดไปยังโปรเจ็กต์ใน Xcode

9e65705cf6be7aac.png

สร้างคําขอ gRPC

คุณสร้างคําขอ gRPC ใน gRPC ได้เช่นเดียวกับคําขอ REST

if (connectionMode[picker.selectedRow(inComponent: 0)] == "REST") {
   
}
else {
   
print("Using gRPC")
   
// TODO: add code to send a gRPC request to TF Serving
   
}
  • ในการสร้างคําขอ gRPC ให้เพิ่มโค้ดนี้ลงในสาขา gRPC
//Create the gRPC request.
let
group = MultiThreadedEventLoopGroup(numberOfThreads: 1)
let channel
= ClientConnection.insecure(group: group).connect(host: "localhost", port: 8500)
let stub
= Tensorflow_Serving_PredictionServiceClient(channel: channel)

var modelSpec = Tensorflow_Serving_ModelSpec()
modelSpec
.name = "regression"
modelSpec
.signatureName = "serving_default"

// Prepare the input tensor.
var batchDim = Tensorflow_TensorShapeProto.Dim()
batchDim
.size = 1
var inputDim = Tensorflow_TensorShapeProto.Dim()
inputDim
.size = 1
var inputTensorShape = Tensorflow_TensorShapeProto()
inputTensorShape
.dim = [batchDim, inputDim]
var inputTensor = Tensorflow_TensorProto()
inputTensor
.dtype = Tensorflow_DataType.dtFloat
inputTensor
.tensorShape = inputTensorShape
inputTensor
.floatVal = [Float(value)]

var request = Tensorflow_Serving_PredictRequest()
request
.modelSpec = modelSpec
request
.inputs = ["dense_input" : inputTensor]

let callOptions
= CallOptions(timeLimit: .timeout(.seconds(15)))

ส่งคําขอ gRPC ไปยังการแสดงผล TensorFlow

  • เพิ่มโค้ดนี้ลงในสาขา gRPC ทันทีหลังจากโค้ดในข้อมูลโค้ดก่อนหน้า
// Send the gRPC request.
let call
= stub.predict(request, callOptions: callOptions)

ประมวลผลการตอบสนอง gRPC จาก TensorFlow Serving

  • เพิ่มโค้ดนี้หลังโค้ดในข้อมูลโค้ดก่อนหน้านี้
// Process the response.
call
.response.whenSuccess { response in
    let result
= response.outputs["dense_1"]?.floatVal[0]
   
DispatchQueue.main.async{
       
self.txtOutput.text = String(describing: result!)
   
}
}
call
.response.whenFailure { error in
   
print("Call failed with error\n\(error)")
}

ตอนนี้ฟังก์ชันหลังการประมวลผลจะแยกค่าที่คาดการณ์ไว้ออกจากการตอบกลับ และแสดงผลลัพธ์ใน UI

เรียกใช้

  1. คลิกcacc15c5638260ed.png "เรียกใช้' ในเมนูการนําทาง แล้วรอให้ Xcode เปิดแอปในเครื่องจําลอง
  2. ป้อนตัวเลขในกล่องข้อความ แล้วคลิกอนุมาน

ตอนนี้คุณจะเห็นค่าที่คาดการณ์ใน UI

9 ยินดีด้วย

คุณใช้ TensorFlow Serving เพื่อเพิ่มความสามารถในการถดถอยลงในแอปแล้ว

ดูข้อมูลเพิ่มเติม