![1O42bkBP6MVGw1LPeUXZ4-A.jpeg](https://quantinsightsnetwork.com/wp-content/uploads/2023/11/1O42bkBP6MVGw1LPeUXZ4-A.jpeg)
一般而言,如果你的程式會需要 TensorFlow model來推論時,普遍的作法會使用TensorFlow Serving API來解決,serving在你給他有哪些模型後,它會自己管理資源,我的程式再透過grpc去溝通。但有些時候,在做一些簡單的應用時,你想要直接把讀取模型的部份直接寫在程式內時,通常就必須額外花心力去查找你所使用的語言該如何使用,而以下就是我在使用Golang時整理的方法。
在使用之前,我發現TensorFlow官方已經不再支援Golang,目前專案轉由社群來支持。
The TensorFlow team is not currently maintaning the Documentation for installing the Go bindings for TensorFlow.
而實際我們使用的 Golang TensorFlow 底層實際是C語言,所以需要先在自己的電腦環境中安裝 libtensorflow。以我目前寫這篇文章所用的版本是libtensorflow-cpu-linux-x86_64–2.14.0.tar.gz。
官方libtensorflow安裝文件(不建議閱讀中文版,因為很久沒更新)
照文件安裝後,用gcc編譯執行測試後,應該能看到下面這行
Hello from TensorFlow C library version 2.14.0
TensorFlow for C 安裝後,就可以安裝社群版的 Golang TensorFlow wrapper。
go get github.com/wamuir/graft/tensorflow@v0.6.0
這邊的0.6.0對應的是 TensorFlow C 2.14.0,請自行注意版本相依性!
這樣就完成了TensorFlow的準備。
GoCV 其實也是一個wrapper,透過Golang呼叫系統的OpenCV,因此同樣地,我們一樣也要在系統內先安裝OpenCV,以目前寫文章的這個時間點,我們安裝的是v4.8.1。
安裝完畢後,印出下面訊息代表安裝完成。
gocv version: 0.35.0
opencv lib version: 4.8.1
在Python時務操作上,我們通常會有下面幾個步驟:
- 讀取Model、讀取Image。
- Image Resize到適當的比例、確保RGB再像素中的0~255正規化到[-1.0, 1.0]當輸入。
- 推論結果。
import cv2
import numpy as np
import tensorflow as tfdef main():
# 1. read image and pb model
img = cv2.imread("images/test.jpg")
model = tf.keras.models.load_model("models/face_detection/")
# 2. preprocess image
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
img = cv2.resize(img, (300, 300))
img = img - 127.5
img = img * 0.007843
img = np.expand_dims(img, axis=0)
# 3. inference
output = model.predict(img)
print(f"output: {output}")
if __name__ == "__main__":
main()
所以同樣的,換到Golang也一樣需要上面三個步驟,中間最麻煩的是GoCV讀取圖片後的type是Mat格式,但TensorFlow要模型推論需要Tensor格式,第二步需要有個型態轉換。
完整的Golang程式碼如下
package mainimport (
"fmt"
"image"
tf "github.com/wamuir/graft/tensorflow"
"gocv.io/x/gocv"
)
func main() {
// 1. Load the image and model
img := gocv.IMRead("images/test.jpg", gocv.IMReadColor)
if img.Empty() {
fmt.Println("Error reading image")
return
}
defer img.Close()
model, err := tf.LoadSavedModel("models/face_detection", []string{"serve"}, nil)
if err != nil {
fmt.Printf("error loading saved model: %v\n", err)
return
}
defer model.Session.Close()
// 2. preprocess the image
gocv.Resize(img, &img, image.Pt(300, 300), 0, 0, gocv.InterpolationArea)
gocv.CvtColor(img, &img, gocv.ColorBGRToRGB)
img.ConvertTo(&img, gocv.MatTypeCV32F)
gocv.Normalize(img, &img, -1.0, 1.0, gocv.NormMinMax)
const size = 300 * 300 * 3
floatData, err := img.DataPtrFloat32()
if err != nil {
fmt.Printf("error getting float data pointer: %v\n", err)
return
}
tensor, err := tf.NewTensor([][]float32{floatData[:size]})
if err != nil {
fmt.Printf("error creating tensor: %v\n", err)
return
}
tensor.Reshape([]int64{1, 300, 300, 3})
// 3. inference
results, err := model.Session.Run(
map[tf.Output]*tf.Tensor{
model.Graph.Operation("serving_default_input_1").Output(0): tensor,
},
[]tf.Output{
model.Graph.Operation("StatefulPartitionedCall").Output(0),
},
nil,
)
if err != nil {
fmt.Printf("error running session: %v\n", err)
return
}
output, ok := results[0].Value().([][][]float32)
if !ok {
fmt.Printf("error getting output: %v\n", err)
return
}
fmt.Printf("Output: %v\n", output[0])
}
- 我們個別用了 gocv 和 gotf 讀取了圖片和模型
- 這邊我們可以盡情的使用OpenCV原有的功能去對圖片做處理,只需要在最後用 GoCV 提供的 DataPtrFloat32 方法和 gotf 的 NewTensor 方法,從Mat格式轉換成Tensor格式
- 在tfgo推論模型時,必須要知道 input 和 output的 Operation Name,如果要印出所有Operation Name也可以透過下面的 script 找出來。
for _, op := range model.Graph.Operations() {
fmt.Printf("Operation: %v\n", op.Name())
}
這樣就可以在 Golang 中實現和 Python 幾乎一樣的功能,整個流程比較麻煩的地方大概就是環境安裝,還有中間Data Type的轉換在第一次遇到時會摸不著頭緒。
本次研究大量透過 ChatGPT 4.0 程式輔助,偉哉OpenAI!
Be the first to comment