建立 iOS 應用程式來預測價值

建立 iOS 應用程式來預測價值

程式碼研究室簡介

subject上次更新時間:4月 8, 2022
account_circle作者:Wei Wei

1. 事前準備

在本程式碼研究室中,您將瞭解如何使用包含搭配 REST 和 gRPC 的 TensorFlow Serving,在 iOS 應用程式中執行迴歸推論。

必要條件

  • 與 Swift 進行 iOS 開發作業的基本知識
  • TensorFlow 機器學習基本知識,例如訓練和部署
  • Colaboratory 基本知識
  • 終端機、Python 和 Docker 的基本知識

課程內容

  • 如何使用 TensorFlow 訓練迴歸模型。
  • 如何透過 TensorFlow Serving (REST 和 gRPC) 使用經過訓練的模型建構簡單的 iOS 應用程式及進行預測。
  • 如何在使用者介面中顯示結果。

軟硬體需求

2. 做好準備

若要下載此程式碼研究室的程式碼:

  1. 前往這項程式碼研究室的 GitHub 存放區
  2. 按一下 [程式碼 >下載 zip],即可下載這個程式碼研究室的所有程式碼。

a72f2bb4caa9a96.png

  1. 將下載的 ZIP 檔案解壓縮,解壓縮您需要的所有 codelabs 根資料夾。

在這個程式碼研究室中,您只需要存放區的 TFServing/RegressioniOS 子目錄中的檔案,其中包含兩個資料夾:

  • starter 資料夾包含您為這個程式碼研究室建立的範例程式碼。
  • finished 資料夾包含已完成範例應用程式的範例程式碼。

3. 下載專案的依附元件

下載必要的 pod

  • starter/iOS 資料夾中執行下列指令:
pod install

Cocoapods 會安裝所有必要的資料庫,並產生新的 regression.xcworkspace 檔案。

4. 執行啟動應用程式

  • 按兩下 regression.xcworkspace 檔案即可開啟 Xcode。

執行並探索應用程式

  1. 將裝置目標變更為任何 iPhone,例如 iPhone 13。

a57198a4f21f970.png

  1. 按一下 cacc15c5638260ed.png [執行],然後等待 Xcode 編譯專案,並在模擬工具中開啟啟動應用程式。

使用者介面相當簡單,這裡有一個文字方塊,您可以輸入數值。系統會將這個數字傳送到包含 REST 或 gRPC 的 TensorFlow Serving 後端。後端會對輸入值執行迴歸,並將預測值傳回用戶端應用程式,讓應用程式重新顯示在使用者介面中。

d2976072474ce0b1.png

如果您輸入數字並點選 [推測],應用程式就不會與後端通訊,因此不會發生任何狀況。

5. 使用 TensorFlow 訓練簡單的迴歸模型

迴歸是最常見的機器學習工作之一。目的是根據輸入內容預測單一的連續數量。例如,根據今天的天氣狀況,預測明天最高溫度。

訓練迴歸模型

  1. 在瀏覽器中開啟這個連結

Colab 會載入 Python 筆記本。

  1. 在 Python 筆記本中,匯入 TensorFlowNumPy 程式庫,然後建立六組訓練資料,其中 xs 為輸入資料,ys 為標籤。

如果您把這些資料點放到圖表上,其實實際上是直線,因為這些項目是由 y = 2x -1 方程式所產生。

56d05252cfc9df9d.png

  1. 使用 Keras API 建立一個簡單的雙層類神經網路,根據 x 輸入內容預測 y 值,然後編譯並調整模型。
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]))

模型訓練需要幾秒鐘的時間,因此 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. 將匯出的 SavedModel 壓縮成單一 regression.zip 檔案:
!zip -r regression.zip ./regression
  1. 按一下導覽選單中的 [Run &&t; Run all] (執行時間> Run all) 以執行筆記本,然後等待執行作業完成。
  2. 按一下 [c55600d42359f901.png 檔案],然後下載 regression.zip 檔案。

武士 15d86571583.png

6. 使用 TensorFlow Serving 部署迴歸模型

  • 如要使用 TensorFlow Serving 部署模型,請使用壓縮工具 (例如 7-Zip) 將下載的 regression.zip 檔案解壓縮。

資料夾結構應如下列所示:

7faeb4f03af39646.png

regression 資料夾可視為 SavedModel 資料夾。123 是範例版本號碼。如有需要,您可以挑選其他號碼。

啟動 TensorFlow Serving

  • 在終端機中,以 Docker 啟動 TensorFlow Serving,但將 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 Serving 映像檔,這可能需要一分鐘的時間。之後,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. 透過 REST 將 iOS 應用程式與 TensorFlow Serving 連結

後端已就緒,您可以傳送用戶端要求至 TensorFlow Serving 進行預測。向 TensorFlow Serving 傳送要求的方法有兩種:

  • REST
  • gRPC

透過 REST 傳送要求及接收回應

這裡有三個簡單的步驟:

  1. 建立 REST 要求。
  2. 將 REST 要求傳送至 TensorFlow Serving。
  3. 從 REST 回應中擷取預測結果並顯示 UI。

您可以在 iOS/regression/ViewController.swift 檔案中完成這些步驟。

建立 REST 要求

  1. doInference() 函式目前無法向 REST Serving 傳送 REST 要求。您必須導入這個 REST 分支來建立 REST 要求:
if (connectionMode[picker.selectedRow(inComponent: 0)] == "REST") {
   
print("Using REST")
   
// TODO: Add code to send a REST request to TensorFlow Serving.
   
}

TensorFlow Serving 的 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 Serving

  • 將下列程式碼加入 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()

處理 TensorFlow Serving 中的 REST 回應

  • 請將這段程式碼加進 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])
}

現在,後續處理函式會從回應中擷取預測值,並在使用者介面中顯示結果。

執行

  1. 按一下 cacc15c5638260ed.png [執行],然後等待 Xcode 在模擬工具中啟動應用程式。
  2. 在文字方塊中輸入數字,然後按一下 [推測]

現在,您會在使用者介面中看到預測值。

df9bcb9aa21bb30e.png

8. 透過 gRPC 將 iOS 應用程式與 TensorFlow Serving 連結

除了 REST 以外,TensorFlow Serving 也支援 gRPC

b6f4449c2c850b0e.png

gRPC 是現代化、開放原始碼的高效能遠端程序呼叫 (RPC) 架構,可在任何環境中執行。這項服務具備可連接的負載平衡、追蹤、健康狀態檢查和驗證等功能,可透過高效率的方式連結資料中心內外的服務。發現在實驗中,gRPC 的成效比 REST 更好。

使用 gRPC 傳送要求及接收回應

這裡有四個簡單的步驟:

  1. 選用:產生 gRPC 用戶端 stub 程式碼。
  2. 建立 gRPC 要求。
  3. 將 gRPC 要求傳送至 TensorFlow Serving。
  4. 從 gRPC 回應中擷取預測結果,然後顯示 UI。

您可以在 iOS/regression/ViewController.swift 檔案中完成這些步驟。

選用:產生 gRPC 用戶端 stub 程式碼

如要搭配 TensorFlow Serving 使用 gRPC,您需要遵守 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 用戶端 stub 程式碼:

  1. 在終端機中,前往 starter/src/proto/ 資料夾並產生 stub:
bash generate_grpc_stub_swift.sh

starter/src/proto/generated/import 資料夾中會產生多個 .swift 檔案。

  1. 如果他們尚未複製到您的專案中,請將所有產生的 .swift 檔案拖曳至 Xcode 的專案。

9e65705cf6be7aac.png

建立 gRPC 要求

與 REST 要求類似,您會在 gRPC 分支中建立 gRPC 要求。

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 Serving

  • 將下列程式碼加入前一個程式碼片段中緊接在 gRPC 分支的後方:
// Send the gRPC request.
let call
= stub.predict(request, callOptions: callOptions)

處理 TensorFlow Serving 中的 gRPC 回應

  • 加入以下程式碼,緊接在前一個程式碼片段中的程式碼後面:
// 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)")
}

現在,後續處理函式會從回應中擷取預測值,並在使用者介面中顯示結果。

執行

  1. 在導覽選單中按一下 cacc15c5638260ed.png [執行],然後等待 Xcode 在模擬工具中啟動應用程式。
  2. 在文字方塊中輸入數字,然後按一下 [推測]

現在,您會在使用者介面中看到預測值。

9. 恭喜

您使用 TensorFlow Serving 為應用程式增添迴歸功能!

瞭解詳情