1. 安裝Go版TensorFlow
TensorFlow 提供了一個 Go API,該 API 特別適合加載用 Python 創建的模型並在 Go 應用中運行這些模型。
安裝TensorFlow C庫
下載地址
解壓 :
tar -C $dir -xzf tar_file
添加到動態庫:
export LIBRARY_PATH=$LIBRARY_PATH:$dir/lib
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$dir/lib
如果你已經解壓到了/usr/local下,則不需要配置LIBRARY_PATH和LD_LIBRARY_PATH,只需要執行sudo ldconfig即可
安裝 TensorFlow Go
go get github.com/tensorflow/tensorflow/tensorflow/go
2. 用Python訓練tensor flow模型並保存
注意:python的tensor flow版本不能高於go的tensor flow版本,否則go加載模型文件時會報錯。
import tensorflow as tf from keras import backend as K sess = tf.Session() K.set_session(sess) def build_deep_cross(): inputs = [] for i, feature_name in enumerate(feature_names): cate_in = Input((1,), name=feature_name) inputs.append(cate_in) # 此處略去很多代碼 cross_net = build_cross_net(f_dim_vectors) # CrossNet deep_out = build_dnn(f_dim_vectors, continuous_input) # 深層網絡 # 結合CrossNet和深層網絡 concat_cross_deep = Concatenate()([cross_net, deep_out]) outputs = Dense(1, activation="sigmoid", name="output_layer")(concat_cross_deep) # 留意模型的inputs和outputs,寫Golang時要用 model = Model(inputs=inputs, outputs=outputs) solver = Adam(lr=0.01, decay=0.1) model.compile(optimizer=solver, loss='binary_crossentropy', metrics=['acc']) return model model=build_deep_cross() model.fit(X_train, Y_train, batch_size=256, epochs=10) # 專門為Golang保存一個模型 builder = tf.compat.v1.saved_model.builder.SavedModelBuilder("dcnModel") # 必須為模型打個Tag,否則golang無法加載 builder.add_meta_graph_and_variables(sess, ["myTag"]) # 保存 builder.save()
3. Golang加載tensor flow模型
package main import ( tf "github.com/tensorflow/tensorflow/tensorflow/go" "strconv" "strings" "sync" "fmt" ) type DCN struct { model *tf.SavedModel featureNames []string } var ( dcn *DCN dcnOnce sync.Once ) func GetDCNInstance(modelFile string, tags []string) *DCN { if dcn != nil { return dcn } dcnOnce.Do(func() { dcn = &DCN{} //LoadSavedModel時使用的go tensorflow版本不能低於tf.saved_model.builder.SavedModelBuilder時使用的tensorflow版本 if model, err := tf.LoadSavedModel(modelFile, tags, nil); err == nil { dcn.model = model dcn.featureNames = []string{"age", "work_year", "gender"} //第一次執行model.Session.Run很耗時,所以初始化后先預熱一下 X := []float32{0.31,0.09,1.0} input := [][]float32{X} dcn.Predict(input) } else { fmt.Printf("read dcn model file %s failed: %v", modelFile, err) return } }) return dcn } //Predict 預測點擊率。X的連續特征需要事先做好歸一化,離散特征要轉成index func (self DCN) Predict(X [][]float32) []float32 { if len(X[0]) != len(self.featureNames) { fmt.Printf("feature number of x is %d, but should be %d", len(X[0]), len(self.featureNames)) return nil } input_layer := make(map[tf.Output]*tf.Tensor) for i := 0; i < len(X[0]); i++ { //第i列 input := [][]float32{} for j := 0; j < len(X); j++ { //第j行 input = append(input, []float32{X[j][i]}) } tensor, _ := tf.NewTensor(input) // python版tensorflow/keras中定義的輸入層input_layer out := self.model.Graph.Operation(self.featureNames[i]).Output(0) input_layer[out] = tensor } output_layer := []tf.Output{ //python版tensorflow/keras中定義的輸出層output_layer self.model.Graph.Operation("output_layer/Sigmoid").Output(0), } if result, err := self.model.Session.Run(input_layer, output_layer, nil); err == nil { //不論是1條數據還是300條數據,執行該行代碼只需要2毫秒 scores := result[0].Value().([][]float32) rect := make([]float32, len(scores)) for i, arr := range scores { rect[i] = arr[0] } return rect } else { fmt.Printf("predict failed: %v", err) return nil } } func main(){ dcn := rank.GetDCNInstance("dcnModel", []string{"myTag"}) X := []float32{0.31,0.09,1.0} input := [][]float32{X} scores := dcn.Predict(input) }