1. 程式人生 > >從DNNClassifier到tensorflow Serving部署

從DNNClassifier到tensorflow Serving部署

利用Tensorflow高階庫DNNClassifier進行分類訓練,並部署到serving上, 關於高階庫部署到serving上網上資料太少了,自己費盡九牛二虎之力才搞定,在此分享下,能幫助一些童鞋最好了。

import pandas as pd
  import tensorflow as tf
  import numpy as np
  from tensorflow.contrib.learn import DNNClassifier


  CATEGORICAL_COLUMNS = []
  CONTINUOUS_COLUMNS = ['MEAN_INTERVAL_CALL', 'SD_INTERVAL_CALL',
                        'NUM_CALL', 'MEAN_DURATION',
                        'MOST_DURATION', 'MOST_DURATION_NUM',
                        'SD_DURATION', 'TOTAL_DURATION',
                        'TRK_NUM',
]
LABEL_COLUMN = 'TAG'


  def input_fn(df):
      continuous_cols = {k: tf.constant(df[k].values, shape=[df[k].size, 1]) for k in CONTINUOUS_COLUMNS}

      feature_cols = dict(continuous_cols)

      if CATEGORICAL_COLUMNS:
          categorical_cols = {
              k: tf.SparseTensor(
                  indices=[[i, 0] for i in range(df[k].size)],
                  values=df[k].values,
                  dense_shape=[df[k].size, 1])
              for k in CATEGORICAL_COLUMNS}

      feature_cols.update(categorical_cols)
      label = tf.constant(df[LABEL_COLUMN].values, shape=[df[LABEL_COLUMN].size, 1])

      return feature_cols, label


  def create_columns(continuous_columns):
      deep_columns = []
      for column in continuous_columns:
          column = tf.contrib.layers.real_valued_column(column)
          deep_columns.append(column)
      return deep_columns


  def main():
      training_data = pd.read_csv('./data/20180105_label.csv',
                                  skipinitialspace=True,
                                  engine='python',
                                  dtype=np.float64,
                                  iterator=True,
                                  )

      test_data = pd.read_csv('./data/20180107_label.csv',
                              skipinitialspace=True,
                              engine='python',
                              dtype=np.float64,
                              iterator=True,
                          )
      deep_columns = create_columns(CONTINUOUS_COLUMNS)

      model = DNNClassifier(feature_columns=deep_columns,
                     model_dir='./model',
                     hidden_units=[10, 10],
                     n_classes=2,
                     input_layer_min_slice_size=10000)

      tf.logging.set_verbosity(tf.logging.INFO)
      training_data_chunk = training_data.get_chunk(1000000000)
      model.fit(input_fn=lambda: input_fn(training_data_chunk),
         steps=100)

      tf.logging.info("end fit model")

      test_data_chunk = test_data.get_chunk(10000)

      accuracy = model.evaluate(input_fn=lambda: input_fn(test_data_chunk),
                          steps=100)['accuracy']
      print(accuracy * 100)

if __name__ == '__main__':
      main()

定義serving儲存模型,不然沒法利用serving部署。 激動人心的時刻到了,你是不是在想程式碼會很多,結果出乎意料: 首先定義一個名為 _serving_input_receiver_fn的函式用來返回特定格式的input_fn。

  1. def _serving_input_receiver_fn():
  2. feature_placeholders = {k: tf.placeholder(tf.float64, [None]) for k in CONTINUOUS_COLUMNS}
  3. features = { key: tf.expand_dims(tensor, -1) for key, tensor in feature_placeholders.items()
  4. }
  5. return tf.contrib.learn.utils.input_fn_utils.InputFnOps(
  6. features,
  7. None,
  8. feature_placeholders
  9. )

然後在main函式裡定義一個匯出函式就行啦,一條語句搞定。是不是很驚喜。

  1. model.export_savedmodel(export_dir_base="./serving_model",serving_input_fn=_serving_input_receiver_fn,)

儲存完成,你就會在你剛剛定義的路徑下看到類似這種結構 

到此,你的模型訓練和到處serving格式就完成啦,接下來就部署到serving上吧。 3. serving部署 什麼?serving安裝很煩?不存在的,docker簡單搞定。what?不會用docker,那我只能說你out了,趕緊去學吧。 首先下載映象:

  1. docker pull bitnami/tensorflow-serving

然後就可以運行了,將剛剛的模型儲存路徑掛載到容器的/bitnami/model-data中就可以了。

  1. docker run -d --name tensorflow-serving -e TENSORFLOW_SERVING_MODEL_NAME=dnn -p 9000:9000 -v /chenxf/python_project/dnn_classifier/serving_model/:/bitnami/model-data docker.io/bitnami/tensorflow-serving

檢視下日誌

  1. docker logs -f tensorflow-serving

看到這種輸出就成功了

  1. 8077573}
  2. 2018-03-30 02:47:18.090297: I tensorflow_serving/core/loader_harness.cc:66] Approving load for servable version {name: dnn version: 1518077573}
  3. 2018-03-30 02:47:18.090316: I tensorflow_serving/core/loader_harness.cc:74] Loading servable version {name: dnn version: 1518077573}
  4. 2018-03-30 02:47:18.090349: I external/org_tensorflow/tensorflow/contrib/session_bundle/bundle_shim.cc:360] Attempting to load native SavedModelBundle in bundle-shim from: /bitnami/model-data/1518077573
  5. 2018-03-30 02:47:18.090374: I external/org_tensorflow/tensorflow/cc/saved_model/loader.cc:236] Loading SavedModel from: /bitnami/model-data/1518077573
  6. 2018-03-30 02:47:18.108009: I external/org_tensorflow/tensorflow/core/platform/cpu_feature_guard.cc:137] Your CPU supports instructions that this TensorFlow binary was not compiled to use: SSE4.1 SSE4.2
  7. 2018-03-30 02:47:18.135780: I external/org_tensorflow/tensorflow/cc/saved_model/loader.cc:155] Restoring SavedModel bundle.
  8. 2018-03-30 02:47:18.152961: I external/org_tensorflow/tensorflow/cc/saved_model/loader.cc:190] Running LegacyInitOp on SavedModel bundle.
  9. 2018-03-30 02:47:18.155245: I external/org_tensorflow/tensorflow/cc/saved_model/loader.cc:284] Loading SavedModel: success. Took 64855 microseconds.
  10. 2018-03-30 02:47:18.155578: I tensorflow_serving/core/loader_harness.cc:86] Successfully loaded servable version {name: dnn version: 1518077573}
  11. E0330 02:47:18.160940286 55 ev_epoll1_linux.c:1051] grpc epoll fd: 3
  12. 2018-03-30 02:47:18.162335: I tensorflow_serving/model_servers/main.cc:288] Running ModelServer at 0.0.0.0:9000 ...

至此serving已經成功執行啦,是不是很簡單,你以後迭代訓練的時候serving會自動檢測並部署最新的model(模型儲存路徑不變更)是不是很智慧! 那麼接下來該結束了?no,no部署上去了得用啊!怎麼使用呢?

serving使用 首先你的裝個serving client。目前只支援python2,python3得費點力氣。 可以參考官網serving安裝

pip install tensorflow-serving-api

輸入下面語句驗證下

python -c “import tensorflow_serving”

接下里就編寫serving client端了,不多說了看註釋吧,很詳細了

  1. from grpc.beta import implementations
  2. import numpy as np
  3. import tensorflow as tf
  4. from tensorflow_serving.apis import predict_pb2
  5. from tensorflow_serving.apis import prediction_service_pb2
  6. import pandas as pd
  7. # 定義serving server端
  8. tf.app.flags.DEFINE_string('server', 'localhost:9000',
  9. 'PredictionService host:port')
  10. FLAGS = tf.app.flags.FLAGS
  11. #和訓練時的引數一樣定義連續性欄位
  12. CONTINUOUS_COLUMNS = ['MEAN_INTERVAL_CALL', 'SD_INTERVAL_CALL',
  13. 'NUM_CALL', 'MEAN_DURATION',
  14. 'MOST_DURATION', 'MOST_DURATION_NUM',
  15. 'SD_DURATION', 'TOTAL_DURATION',
  16. 'TRK_NUM',
  17. ]
  18. # 讀取測試的檔案,這裡只取了前10行
  19. data = pd.read_csv('../dnn_classifier/data/20180107_label.csv')
  20. data = data[0:10]
  21. n_samples = 100
  22. # 獲取server的host和port
  23. host, port = FLAGS.server.split(':')
  24. #連線serving server
  25. channel = implementations.insecure_channel(host, int(port))
  26. stub = prediction_service_pb2.beta_create_PredictionService_stub(channel)
  27. # Send request
  28. request = predict_pb2.PredictRequest()
  29. request.model_spec.name = 'dnn'
  30. request.model_spec.signature_name = tf.saved_model.signature_constants.DEFAULT_SERVING_SIGNATURE_DEF_KEY
  31. for column in CONTINUOUS_COLUMNS:
  32. request.inputs[column].CopyFrom(
  33. tf.contrib.util.make_tensor_proto(data[column].values,
  34. shape=[data[column].size],
  35. dtype=tf.double))
  36. result = stub.Predict(request, 10.0, ) # 10 means timeout
  37. print(result.outputs['classes'])

看看輸出結果:0,1就是分類的結果。至此完成一個訓練到部署到預測的完整過程了!!