[Update] [Model Serving] Triển khai Machine Learning model lên production với Tensorflow Serving – Deploy Machine Learning model in production with Tensorflow Serving | portion là gì

0
30

portion là gì: You are currently viewing the topic.

Các phần nội dung chính sẽ đề cập trong bài blog lần này

  • Tensorflow Serving?
  • Triển khai Tensorflow Serving
  • gRPC vs RESTful
  • Benchmark
  • 1 số lưu ý
  • Model với nhiều inputs
  • Model với output phức tạp
  • Serving multiple models
  • CPU optimized
  • Cải tổ inference time với Protos
  • Cải tổ inference time với Batching
  • Tensorflow Serving với Docker / Docker-compose
  • Reference

Github repo – serving model with Docker: https://github.com/huyhoang17/tensorflow-serving-docker

Tensorflow Serving?!

Khái niệm

  • Tensorflow Serving là bộ dụng cụ mã nguồn mở, dùng để triển khai (deploy) các mô hình được huấn luyện bởi tensorflow lên môi trường production. Là 1 trong 4 bộ dụng cụ thuộc TFX (Tensorflow Extended) bao gồm: Tensorflow Data Validation, Tensorflow Transform, Tensorflow Model Analysis và Tensorflow Serving, được xây dựng như 1 pipeline với nhiệm vụ triển khai các mô hình từ thời kỳ research lên production, đúng như mô tả trên trang landing page của TFX:

When you’re ready to move your models from research to production, use TFX to create and manage α production pipeline.

  • Với Tensorflow Serving, quá trình triển khai mô hình lên hệ thống (server) sẽ trở nên nhanh chóng và đơn giản hơn rất nhiều với việc triển khai và load model 1 cách thông thường. Tensorflow Serving triển khai mô hình 1 cách độc lập, tách biệt với phần code base phía backend, trợ giúp 2 giao thức là gRPC và RESTful API, đơn giản thêm và update model mới theo từng phiên bản (version) mà không gây tác động tới các phần khác của hệ thống hay các service khác, trợ giúp việc deployment 1 cách tối đa và hầu hết zero downtime deployment – việc triển khai version mới của mô hình hầu hết không gặp gián đoạn.

  • Tensorflow Serving bao gồm các thành phần chính:

    • Source: có tác dụng như 1 supervisor trong life-cycle của 1 quá trình serving. Source kiểm tra các model được lưu trên ổ đĩa, sẽ xác minh bất kể khi nào có sự thay đổi model (theo version bằng các tác vụ thêm, xóa) và thực hiện tạo 1 đối tượng Loader để load version mới đó
    • Loader: chứa đầy đủ các thông tin meta-data của 1 model version: tag_set, signature, model_name, inputs, outputs
    • Manager: quản lý và thực hiên các tác vụ tương ứng với 3 thao tác chính: loading, unloading và serving model (Servable)
    • Servable: tiếp nhận request từ client và yêu cầu tới Manager để gọi đúng đắn tới version rõ ràng của model

Imgur

1 số ưu thế của Tensorflow Serving

  • Thắc mắc đề ra là: vậy việc triển khai 1 model machine learning (deep learning) thông thường (load pretrained model rồi thực hiện predict với từng request được gửi tới) với việc serving dùng Tensorflow Serving khác nhau như vậy nào và việc dùng Tensorflow Serving có những ưu thế vượt trội hơn?

  • Thông thường, việc triển khai 1 model machine learning có thể được thực hiện đơn giản theo hướng sau:

    • Xây dựng 1 website app dùng thử (flask, django)
    • Tiến hành tạo API endpoint hoặc view để trả về kết quả phán đoán
    • Load pretrain model (h5, cpkt, …)
    • Tiền xử lý dữ liệu và predict
    • Trả kết quả về cho client
  • Các giai đoạn trên có thể được mô tả ngắn gọn qua đoạn code sau, serve.py:

import

json

from

utils

import

preprocess_img

from

flask

import

Flask

from

keras

.

models

import

load_model model

=

load_model

(

'model.h5'

)

app

=

Flask

(

__name__

)

@app

.

route

(

'/classify'

,

methods

=

[

'POST'

]

)

def

classify

(

)

:

img

=

request

.

form

[

"img"

]

img

=

preprocess_img

(

img

)

y_pred

=

model

.

predict

(

np

.

expand_dims

(

img

,

axis

=

)

)

[

]

return

json

.

dumps

(

{

"score"

:

int

(

y_pred

)

}

)

  • Tất nhiên, nếu đơn giản bạn chỉ làm 1 bản dùng thử nhỏ thì không vấn đề gì nhưng nếu triển khai model kiểu này lên production sẽ nảy sinh 1 số vấn đề như sau:

    • Code seperation: phần load và serving model được xử lý trực tiếp tại phần codebase của backend. Việc load lại pretrain model nhiều lần tốn rất nhiều thời gian, ví dụ bên trên mình chỉ lấy với 1 model, nhưng giả sử phải xử lý nhiều model đồng thời hoặc những model nặng thì sẽ như vậy nào. Với bài toán nhận diện mặt ví dụ: 1 model face detection, 1 model face alignment, 1 model face recognition tạo embedding, … Hoàn toàn có thể tách biệt phần model đã được huấn luyện và phần xử lý phía backend.
    • Model Version: Việc load model như vậy không mang lại bất kì thông tin gì về model. Nếu bạn muốn thêm 1 model mới (version mới), hoặc là ghi đè lên model cũ hoặc bạn phải tạo endpoint mới để xử lý
  • 1 số điểm đáng lưu ý và ưu thế của Tensorflow Serving như sau:

    • Thuộc TFX (Tensorflow Extended) – có thể coi như là 1 hệ sinh thái end-to-end cho việc deploy các ML pipelines.
    • Zero-downtime deployment: Auto-reload và update tiên tiến nhất các version của model, hoặc đơn giản rollback về các version cũ
    • Highly Available – Tensorflow Serving đảm nói rằng version cũ của model vẫn tiếp tục được xử lý trong lúc model mới được load
    • Serving multiple models: Serving đồng thời nhiều model chỉ với 1 file config duy nhất.
    • Performance: Nhanh hơn, handle được lượng request to hơn, hoạt động tốt hơn với các tác vụ đa luồng và bất đồng bộ
    • Interface: Trợ giúp expose cho 2 kiểu giao tiếp gRPC và RestfulAPI
    • Servables: Trợ giúp nhiều định dạng dữ liệu khác nhau: text, image, embedding, ….
    • Encapsulation: Đơn giản đóng gói và tùy chỉnh tách biệt với phần request tới model
    • Batching: support batching processing cho cả server-side và client-side để cải tổ performance của hệ thống
    • Well maintained: do ông lớn Google phát triển và được xây dựng kèm theo hệ sinh thái TFX cùng với framework deep learning phổ biển là Tensorflow. Và tất nhiên rồi, về mặt chất lượng thì có vẻ không phải bàn quá nhiều ?

Triển khai Tensorflow Serving

  • Việc triển khai 1 mô hình với Tensorflow Serving thường được mình thực hiện như sau:
    • Convert tensorflow / keras model (h5, .ckpt) về định dạng saved_model .pb của tensorflow serving
    • Kiểm tra việc convert model là thành công
    • Khởi chạy Tensorflow Model Server để có thể thực hiện giao tiếp qua gRPC hoặc http
    • Nhận request từ client, tiền xử lý dữ liệu và request tới Tensorflow Model Server
    • Kiểm tra lại kết quả của mô hình
    • Triển khai model với Docker / Docker Compose

Export model

  • Giả sử, bạn thực hiện training model với keras – cũng là 1 framework deep learning khá thông dụng với tensorflow backend. Sau khi thực hiện training model thu được 1 file model .h5 lưu trọng số (weights) của mô hình, mình giả sử với 1 việc xây dựng 1 mạng CNN đơn giản cho bài toán image classification, tập dữ liệu là MNIST. Phần code model như sau:
 

def

make_model

(

input_shape

=

[

28

,

28

,

1

]

)

:

model

=

tf_models

.

Sequential

(

)

model

.

add

(

layers

.

InputLayer

(

input_shape

=

input_shape

)

)

for

no_filter

in

[

16

,

32

,

64

]

:

model

.

add

(

layers

.

Conv2D

(

no_filter

,

kernel_size

=

(

3

,

3

)

,

strides

=

(

1

,

1

)

,

padding

=

'same'

,

activation

=

'relu'

,

)

)

model

.

add

(

layers

.

MaxPooling2D

(

pool_size

=

(

2

,

2

)

,

strides

=

(

2

,

2

)

,

padding

=

'same'

,

)

)

model

.

add

(

layers

.

BatchNormalization

(

axis

=

-

1

,

momentum

=

0.99

,

epsilon

=

0.001

)

)

model

.

add

(

layers

.

Flatten

(

)

)

model

.

add

(

layers

.

Dense

(

128

,

activation

=

'relu'

)

)

model

.

add

(

layers

.

Dropout

(

0.5

)

)

model

.

add

(

layers

.

Dense

(

10

,

activation

=

'softmax'

)

)

return

model model

=

make_model

(

)

print

(

model

.

inputs

,

model

.

outputs

,

model

.

count_params

(

)

)

  • Training, save và load model:

from

tensorflow

.

keras

.

models

import

load_model model

.

fit

(

.

.

.

)

model

.

save

(

.

.

.

)

model

=

load_model

(

'./temp_models/mnist_all.h5'

)

  • Set learning_phase = 0 để chuyển sang mode eval
 
tf

.

keras

.

backend

.

set_learning_phase

(

)

export_path

=

'./temp_models/serving/1'

  • Convert h5 sang định dạng saved_model.pb của tf-serving với method .simple_save, hiểu quả trong đa số! (?) các trường hợp:
 

with

tf

.

keras

.

backend

.

get_session

(

)

as

sess

:

tf

.

saved_model

.

simple_save

(

sess

,

export_path

,

inputs

=

{

'input_image'

:

model

.

input

}

,

outputs

=

{

'y_pred'

:

model

.

output

}

)

  • Hoặc export model với method SavedModelBuilder nếu bạn muốn save nhiều các MetaGraphDef khác nhau, custom các tag-set hoặc thêm các assets (các external files sẽ được sử dụng khi serving), … mình thì thường xuyên sử dụng phương pháp này hơn

from

tensorflow

.

python

.

saved_model

import

builder

as

saved_model_builder

from

tensorflow

.

python

.

saved_model

import

utils

from

tensorflow

.

python

.

saved_model

import

tag_constants

,

signature_constants

from

tensorflow

.

python

.

saved_model

.

signature_def_utils_impl

import

build_signature_def

,

predict_signature_def

from

tensorflow

.

contrib

.

session_bundle

import

exporter builder

=

saved_model_builder

.

SavedModelBuilder

(

export_dir_path

)

signature

=

predict_signature_def

(

inputs

=

{

'input_image'

:

model

.

inputs

[

]

,

}

,

outputs

=

{

'y_pred'

:

model

.

outputs

[

]

}

)

with

.

get_session

(

)

as

sess

:

builder

.

add_meta_graph_and_variables

(

sess

=

sess

,

tags

=

[

tag_constants

.

SERVING

]

,

signature_def_map

=

{

'reid-predict'

:

signature

}

,

)

builder

.

save

(

)

  • Hoặc nếu model lưu dưới dạng checkpoint .cpkt, thì có thể convert về định dạng saved_model theo cách sau:

import

os

import

tensorflow

as

tf trained_checkpoint_prefix

=

'./temp_models/model.ckpt-00001'

export_dir

=

os

.

path

.

join

(

'./temp_models/serving'

,

'1'

)

graph

=

tf

.

Graph

(

)

with

tf

.

compat

.

v1

.

Session

(

graph

=

graph

)

as

sess

:

loader

=

tf

.

compat

.

v1

.

train

.

import_meta_graph

(

trained_checkpoint_prefix

+

'.meta'

)

loader

.

restore

(

sess

,

trained_checkpoint_prefix

)

builder

=

tf

.

compat

.

v1

.

saved_model

.

builder

.

SavedModelBuilder

(

export_dir

)

builder

.

add_meta_graph_and_variables

(

sess

,

[

tf

.

saved_model

.

TRAINING

,

tf

.

saved_model

.

SERVING

]

,

strip_default_attrs

=

True

)

builder

.

save

(

)

  • Sau khi thực hiện code trên, file saved_model.pb và thư mục variables được tạo ra:

    • saved_model.pb: serialized model, lưu giữ toàn thể thông tin graph của mô hình cũng như các meta-data khác như signature, inputs, outputs của model
    • variables: lưu giữ các serialized variables của graph (learned weights)
  • Tensorflow Serving sẽ quản lí từng phiên bản (version) của từng model bằng cách thực hiện khai báo các thư mục và tên version với thứ tự tăng dần , ví dụ: 1, 2, 3, 4, … 1 tip là bạn có thể lưu các version của model dưới dạng time epoch thay vì fix cố định. Cấu trúc trong 1 thư mục chứa các model versions như sau:

temp_models/serving/1
├── saved_model.pb
└── variables
    ├── variables.data-00000-of-00001
    └── variables.index
  • Kiểm tra lại các thông tin meta-data của file saved_model.pb bằng câu lệnh saved_model_cli, trong đó --dir là đường dẫn tương đối tới thư mục model version, ví dụ temp_models/serving/1
 
saved_model_cli show --dir temp_models/serving/1 --tag_set serve --signature_def serving_default
  • Nếu thành công sẽ xuất hiện các thông tin như sau:
MetaGraphDef with tag-set: 

'serve'

contains the following SignatureDefs: signature_def

[

'serving_default'

]

: The given SavedModel SignatureDef contains the following input

(

s

)

: inputs

[

'input_image'

]

tensor_info: dtype: DT_FLOAT shape:

(

-1,

28

,

28

,

1

)

name: input_1:0 The given SavedModel SignatureDef contains the following output

(

s

)

: outputs

[

'pred'

]

tensor_info: dtype: DT_FLOAT shape:

(

-1,

10

)

name: dense_1/Softmax:0 Method name is: tensorflow/serving/predict
  • Các thông tin về tag-set, signature_def, inputs, outputs kèm kích thước và kiểu tương ứng như đã được khai báo lúc convert sang saved_model.pb model

  • Để test thử với 1 sample, bạn có thể dùng câu lệnh sau

saved_model_cli run --dir temp_models/serving/1/ --tag_set serve --signature_def serving_default --input_exprs 

"input_image=np.zeros

((

1

,

28

,

28

,

1

))

"

 
Result 

for

output key y_pred:

[

[

1

.5933816e-01

1

.6137624e-01

4

.8642698e-05

8

.6862819e-05

2

.8394745e-05

1

.3426773e-03

2

.7080998e-03

6

.2681846e-03

1

.3640945e-02

6

.5516180e-01

]

]

gRPC (Google Remote Procedures Calls) vs RESTful (Representational State Transfer)

  • Như mình đã có đề cập tại phần đầu nội dung, Tensorflow Serving trợ giúp 2 kiểu giao tiếp chính là gRPChttp. Để có thể thực hiện request tới tensorflow server qua 2 kiểu giao tiếp đó, trước hết cần thực hiện install tensorflow_model_server và lib tensorflow-serving-api
 

echo

"deb [arch=amd64] http://storage.googleapis.com/tensorflow-serving-apt stable tensorflow-model-server tensorflow-model-server-universal"

|

sudo

tee

/etc/apt/sources.list.{d}/tensorflow-serving.list

&&

curl

https://storage.googleapis.com/tensorflow-serving-apt/tensorflow-serving.release.pub.gpg

|

sudo

apt-key

add

-

apt-get

update

&&

apt-get

install

tensorflow-model-server pip

install

tensorflow-serving-api
  • Thực hiện khởi chạy với câu lệnh sau
tensorflow_model_server --port

=

8500

--rest_api_port

=

8501

--model_name

=

mnist-serving --model_base_path

=

/home/phan.huy.hoang/phh_workspace/temp_models/serving
  • Trong đó:

    • port: gRPC port, mặc định là cổng 8500
    • rest_api_port: http port (RESTful API), mặc định là cổng 8501
    • model_name: tên của model, các bạn đặt thế nào cũng được nhưng sẽ sử dụng để định danh đúng đắn model cần request
    • model_base_path: đường dẫn tuyệt đối tới thư mục chứa các version của model
  • Cấu trúc thư mục /home/phan.huy.hoang/phh_workspace/temp_models/serving hiện tại, ví dụ với 2 version khác nhau của 1 model:

temp_models/serving
├── 

1

│ ├── saved_model.pb │ └── variables │ ├── variables.data-00000-of-00001 │ └── variables.index └──

2

├── saved_model.pb └── variables ├── variables.data-00000-of-00001 └── variables.index

..

.

4

directories,

6

files
  • Ảnh minh họa model đã được serving thành công
XEM THÊM  17 loại rau củ quả đứng đầu trong danh sách không nên ăn khi mang thai

Imgur

  • Cùng xác minh 1 lần nữa bằng curl:
 
 

curl

localhost:8501/v1/models/mnist-serving

{

"model_version_status"

:

[

{

"version"

:

"1"

,

"state"

:

"AVAILABLE"

,

"status"

:

{

"error_code"

:

"OK"

,

"error_message"

:

""

}

}

]

}

  • Cá nhân mình thì thường xuyên sử dụng gRPC hơn vì inference time nhanh hơn (khoảng gấp 2 lần so với http với 1 sample) và code khái niệm cũng tường minh hơn. Việc dùng gRPC sẽ thuận tiện hơn cho các bạn về sau này khi thực hiện serving các model phức tạp, giả sử model với nhiều inputs ví dụ!

  • Với kiểu giao tiếp qua RESTful API, port mặc định là 8501, phần code thực hiện request tới http server như sau:

from

sklearn

.

metrics

import

accuracy_score

,

f1_score

print

(

x_test

.

shape

)

def

rest_infer

(

imgs

,

model_name

=

'mnist-serving'

,

hosting

=

'localhost'

,

port

=

8501

,

signature_name

=

"serving_default"

)

:

"""MNIST - serving with http - RESTful API """

if

imgs

.

ndim

==

3

:

imgs

=

np

.

expand_dims

(

imgs

,

axis

=

)

data

=

json

.

dumps

(

{

"signature_name"

:

signature_name

,

"instances"

:

imgs

.

tolist

(

)

}

)

headers

=

{

"content-type"

:

"application/json"

}

json_response

=

requests

.

post

(

'http://{}:{}/v1/models/{}:predict'

.

format

(

hosting

,

port

,

model_name

)

,

data

=

data

,

headers

=

headers

)

if

json_response

.

status_code

==

200

:

y_pred

=

json

.

loads

(

json_response

.

text

)

[

'predictions'

]

y_pred

=

np

.

argmax

(

y_pred

,

axis

=

-

1

)

return

y_pred

else

:

return

None

y_pred

=

rest_infer

(

x_test

)

print

(

accuracy_score

(

np

.

argmax

(

y_test

,

axis

=

-

1

)

,

y_pred

)

,

f1_score

(

np

.

argmax

(

y_test

,

axis

=

-

1

)

,

y_pred

,

average

=

"macro"

)

)

  • Với kiểu giao tiếp gRPC, port mặc định là 8500, phần code yêu cầu đầy đủ các thông tin như: model_name, signature_name, hosting, port, input_name, output_name

import

grpc

from

tensorflow_serving

.

apis

import

predict_pb2

from

tensorflow_serving

.

apis

import

prediction_service_pb2_grpc channel

=

grpc

.

insecure_channel

(

"localhost:8500"

)

stub

=

prediction_service_pb2_grpc

.

PredictionServiceStub

(

channel

)

request

=

predict_pb2

.

PredictRequest

(

)

request

.

model_spec

.

name

=

"mnist-serving"

request

.

model_spec

.

signature_name

=

"serving_default"

def

grpc_infer

(

imgs

)

:

"""MNIST - serving with gRPC """

if

imgs

.

ndim

==

3

:

imgs

=

np

.

expand_dims

(

imgs

,

axis

=

)

request

.

inputs

[

"input_image"

]

.

CopyFrom

(

tf

.

contrib

.

util

.

make_tensor_proto

(

imgs

,

dtype

=

np

.

float32

,

shape

=

imgs

.

shape

)

)

try

:

result

=

stub

.

Predict

(

request

,

10.0

)

result

=

result

.

outputs

[

"y_pred"

]

.

float_val result

=

np

.

array

(

result

)

.

reshape

(

(

-

1

,

10

)

)

result

=

np

.

argmax

(

result

,

axis

=

-

1

)

return

result

except

Exception

as

e

:

print

(

e

)

return

None

y_pred

=

grpc_infer

(

x_test

)

print

(

accuracy_score

(

np

.

argmax

(

y_test

,

axis

=

-

1

)

,

y_pred

)

,

f1_score

(

np

.

argmax

(

y_test

,

axis

=

-

1

)

,

y_pred

,

average

=

"macro"

)

)

Benchmark

  • Benchmark thời gian thực hiện truy vấn (inference time) giữa gRPC và RESTful API, với 1 request:
 
start 

=

time

.

time

(

)

y_pred

=

rest_infer

(

x_test

[

]

)

print

(

"Inference time: {}"

.

format

(

time

.

time

(

)

-

start

)

)

start

=

time

.

time

(

)

y_pred

=

grpc_infer

(

x_test

[

]

)

print

(

"Inference time: {}"

.

format

(

time

.

time

(

)

-

start

)

)

có thể thấy thời gian truy vấn bằng gRPC nhanh hơn khá nhiều so với http. Với những mô hình phức tạp hơn với nhiều đầu vào và nhiều đầu ra, mình có xu thế dùng gRPC hơn vì thời gian truy vấn nhanh hơn khá nhiều, code khái niệm cũng tường minh hơn khi phải khái niệm rõ ràng tên và kiểu của từng input.

  • Benchmark thời gian thực hiện truy vấn (inference time) giữa gRPC và RESTful API, với nhiều truy vấn (10000 sample trên tập test):
start 

=

time

.

time

(

)

y_pred

=

rest_infer

(

x_test

)

print

(

">>> Inference time: {}"

.

format

(

time

.

time

(

)

-

start

)

)

>>

>

Inference time

:

6.681854248046875

start

=

time

.

time

(

)

y_pred

=

grpc_infer

(

x_test

)

print

(

">>> Inference time: {}"

.

format

(

time

.

time

(

)

-

start

)

)

>>

>

Inference time

:

0.3771860599517822

lần này thì có thể thấy sự khác biệt rất lớn với 10000 samples!

1 số lưu ý

  • Mình khá thường xuyên sử dụng Tensorflow Serving để thực hiện triển khai mô hình lên hệ thống với các dự án AI tại trung tâm tư vấn du học. Tuy nhiên, qua thực nghiệm, với 1 số model nhất định, việc convert trực tiếp model từ định dạng h5 sang saved_model thỉnh thoảng gặp chút “sự cố”. Model h5 được convert thành công sang định dạng saved_model, bạn xác minh thông tin bằng câu lệnh save_model_cli thì hiện thị đủ các thông tin thiết yếu nhưng khi thực hiện predict với tf-serving thì kết quả thu được sai hoàn toàn và không giống như với model.predict thông thường.

  • Để khắc phục “sự cố” này, bạn có thể thực hiện convert file model h5 của keras sang dạng frozen của tensorflow, rồi sau đó convert tiếp 1 lần nữa frozen model sang định dạng saved_model của tf-serving. Trước mình có gặp issue này khi xây dựng 1 model segmentation, nhưng sau thời điểm thực hiện convert 2 lần như trên thì vấn đề được khắc phục và model phán đoán ra đúng đắn. Vậy nên ngoài việc xác minh model được convert thành công, các bạn cũng nên predict thử để xác minh độ đúng đắn của model, tránh gặp phải issue như mình vừa nêu

  • Convert model .h5 sang dạng frozen của Tensorflow

 

from

tensorflow

.

python

.

framework

.

graph_util

import

convert_variables_to_constants

import

tensorflow

.

keras

.

backend

as

import

tensorflow

.

keras

.

models

as

tf_models ₭

.

set_learning_phase

(

)

def

freeze_session

(

session

,

keep_var_names

=

None

,

output_names

=

None

,

clear_devices

=

True

)

:

graph

=

session

.

graph

with

graph

.

as_default

(

)

:

freeze_var_names

=

list

(

set

(

?

.

op

.

name

for

?

in

tf

.

global_variables

(

)

)

.

difference

(

keep_var_names

or

[

]

)

)

output_names

=

output_names

or

[

]

output_names

+=

[

v

.

op

.

name

for

v

in

tf

.

global_variables

(

)

]

input_graph_def

=

graph

.

as_graph_def

(

)

if

clear_devices

:

for

node

in

input_graph_def

.

node

:

node

.

device

=

""

frozen_graph

=

convert_variables_to_constants

(

session

,

input_graph_def

,

output_names

,

freeze_var_names

)

return

frozen_graph model

=

tf_models

.

load_model

(

"./temp_models/mnist_all.h5"

)

frozen_graph

=

freeze_session

(

.

get_session

(

)

,

output_names

=

[

out

.

op

.

name

for

out

in

model

.

outputs

]

)

tf

.

train

.

write_graph

(

frozen_graph

,

"./temp_models/frozen"

,

"frozen-mnist.pb"

,

as_text

=

False

)

  • Convert frozen model sang định dạng .pb của Tensorflow Serving
 

with

tf

.

gfile

.

₲File

(

'./temp_models/frozen/frozen-mnist.pb'

,

"rb"

)

as

ƒ

:

graph_def

=

tf

.

GraphDef

(

)

graph_def

.

ParseFromString

(

ƒ

.

read

(

)

)

builder

=

tf

.

saved_model

.

builder

.

SavedModelBuilder

(

"./temp_models/serving3/1"

)

sigs

=

{

}

with

tf

.

Session

(

graph

=

tf

.

Graph

(

)

)

as

sess

:

tf

.

import_graph_def

(

graph_def

,

name

=

""

)

ɢ

=

tf

.

get_default_graph

(

)

input_image

=

ɢ

.

get_tensor_by_name

(

model

.

input

.

name

)

y_pred

=

ɢ

.

get_tensor_by_name

(

model

.

output

.

name

)

sigs

[

signature_constants

.

DEFAULT_SERVING_SIGNATURE_DEF_KEY

]

=

tf

.

saved_model

.

signature_def_utils

.

predict_signature_def

(

{

"input_image"

:

input_image

,

}

,

{

"y_pred"

:

y_pred

,

}

)

builder

.

add_meta_graph_and_variables

(

sess

,

[

tag_constants

.

SERVING

]

,

signature_def_map

=

sigs

)

builder

.

save

(

)

Model với nhiều inputs

  • Thỉnh thoảng, các bạn phải huấn luyện và thực hiện serving với 1 số model phức tạp hơn 1 chút với nhiều inputs đầu vào. Dưới đây, mình sẽ dùng thử thử với 1 model siamese network dùng cho bài toán object verification. Mục đích xây dựng siamese model nhằm xác minh xem độ tương đồng giữa 2 đối tượng cần kiểm chứng. Ví dụ, với bài toán face verification, đầu vào của siamese model gồm 2 ảnh chứa 2 mặt người, không cần biết người đó là ai, đầu ra của model sẽ trả về 1 / 0 (có hoặc không), ứng với việc 2 ảnh đó là cùng / không cùng 1 người nào đó.

  • Về phần siamese model, cũng không có gì quá phức tạp, ảnh minh họa cho bài toán face verification sử dụng siamese network. Ở đây, mình sẽ dùng thử cho bài toán person verification

  • Thực hiện load pretrain model

from

tensorflow

.

keras

.

models

import

load_model model

=

load_model

(

'sianet.h5'

)

print

(

model

.

inputs

,

model

.

outputs

)

  • Thực hiện convert model sang định dạng .pb của tf-serving và khai báo đầy đủ các thông tin meta-data. Lưu ý rằng model với 2 inputs và 1 output

import

tensorflow

.

keras

.

backend

as

def

export_pb

(

export_dir_path

,

model

)

:

builder

=

saved_model_builder

.

SavedModelBuilder

(

export_dir_path

)

signature

=

predict_signature_def

(

inputs

=

{

'img1'

:

model

.

inputs

[

]

,

'img2'

:

model

.

inputs

[

1

]

}

,

outputs

=

{

'predict'

:

model

.

outputs

[

]

}

)

with

.

get_session

(

)

as

sess

:

builder

.

add_meta_graph_and_variables

(

sess

=

sess

,

tags

=

[

tag_constants

.

SERVING

]

,

signature_def_map

=

{

'signature-reid'

:

signature

}

)

builder

.

save

(

)

  • Kiểm tra model được convert thành công kèm các thông tin tương ứng
saved_model_cli show --dir relative-path-to-model-version --all
  • Thực hiện khởi chạy tensorflow_model_server
tensorflow_model_server --port

=

8500

--rest_api_port

=

8501

--model_name

=

siamese-reid --model_base_path

=

relative-path-to-model-version
  • Kiểm tra model đã được serving với curl

curl

localhost:8501/v1/models/siamese-reid
  • Và đoạn code mẫu xử lý thực hiện request tới gRPC server, khá tường minh và dễ hiểu, 2 đầu vào, 1 đầu ra

def

_grpc_client_request

(

img1

,

img2

,

hosting

=

'localhost'

,

port

=

8500

,

img1_name

=

'img1'

,

img2_name

=

'img2'

,

model_spec_name

=

'siamese-reid'

,

model_sig_name

=

'signature-reid'

,

timeout

=

10

)

:

hosting

=

hosting

.

replace

(

"http://"

,

""

)

.

replace

(

"https://"

,

""

)

channel

=

grpc

.

insecure_channel

(

"{}:{}"

.

format

(

hosting

,

port

)

)

stub

=

prediction_service_pb2_grpc

.

PredictionServiceStub

(

channel

)

request

=

predict_pb2

.

PredictRequest

(

)

request

.

model_spec

.

name

=

model_spec_name request

.

model_spec

.

signature_name

=

model_sig_name img_arr1

=

np

.

expand_dims

(

img1

,

axis

=

)

request

.

inputs

[

img1_name

]

.

CopyFrom

(

tf

.

contrib

.

util

.

make_tensor_proto

(

img_arr1

,

dtype

=

np

.

float32

,

shape

=

[

*

img_arr1

.

shape

]

)

)

img_arr2

=

np

.

expand_dims

(

img2

,

axis

=

)

request

.

inputs

[

img2_name

]

.

CopyFrom

(

tf

.

contrib

.

util

.

make_tensor_proto

(

img_arr2

,

dtype

=

np

.

float32

,

shape

=

[

*

img_arr2

.

shape

]

)

)

print

(

img_arr1

.

shape

,

img_arr2

.

shape

)

start

=

time

.

time

(

)

predict_response

=

stub

.

Predict

(

request

,

timeout

=

timeout

)

print

(

">>> Inference time: {}'s"

.

format

(

time

.

time

(

)

-

start

)

)

return

predict_response
  • Parse kết quả
img_size 

=

(

64

,

32

)

img1_fp

=

'path-to-img1'

img2_fp

=

'path-to-img2'

img1

=

preprocess_reid

(

img1_fp

,

img_size

)

img2

=

preprocess_reid

(

img2_fp

,

img_size

)

result

=

_grpc_client_request

(

img1

,

img2

)

pred

=

np

.

array

(

result

.

outputs

[

'predict'

]

.

float_val

)

pred

=

(

pred

>=

0.5

)

.

astype

(

int

)

print

(

pred

)

Imgur

  • Với 2 ảnh bên trên thì kết quả trả về 1, tức là cùng 1 người.

Serving với những model có output phức tạp

  • Phần này mình sẽ lấy 2 ví dụ về 2 bài toán cơ bản và thông dụng trong computer vision là: Object Detection (phát hiện đối tượng) và Image Segmentation (phân đoạn vùng ảnh)

  • Với Object Detection, mình sẽ sử dụng luôn 1 số pretrained model thông dụng của toolkit Tensorflow Object Detection API, các bạn có thể tham khảo thêm về các model tại link sau: https://github.com/tensorflow/models/blob/master/research/object_detection/g3doc/detection_model_zoo.md

  • Ở đây, với Object Detection mình sẽ dùng thử thử với model ssd-mobilenet-v2 được training trên tập dữ liệu COCO. Sau khi tải pretrain model về, các bạn thu được thư mục như sau:

ssd_mobilenet_v2_coco_2018_03_29/
├── checkpoint
├── frozen_inference_graph.pb
├── model.ckpt.data-00000-of-00001
├── model.ckpt.index
├── model.ckpt.meta
└── saved_model
    ├── saved_model.pb
    └── variables

trong đó, các bạn chỉ cần quan tâm tới thư mục saved_model được dùng với tf-serving. Thực hiện xác minh các thông tin meta-data của model bằng command saved_model_cli, thu được output như sau:

 
saved_model_cli show --dir /home/phan.huy.hoang/Downloads/pretrained_models/ssd_mobilenet_v2_coco_2018_03_29/saved_model/1 --all
 
MetaGraphDef with tag-set: 

'serve'

contains the following SignatureDefs: signature_def

[

'serving_default'

]

: The given SavedModel SignatureDef contains the following input

(

s

)

: inputs

[

'inputs'

]

tensor_info: dtype: DT_UINT8 shape:

(

-1, -1, -1,

3

)

name: image_tensor:0 The given SavedModel SignatureDef contains the following output

(

s

)

: outputs

[

'detection_boxes'

]

tensor_info: dtype: DT_FLOAT shape:

(

-1,

100

,

4

)

name: detection_boxes:0 outputs

[

'detection_classes'

]

tensor_info: dtype: DT_FLOAT shape:

(

-1,

100

)

name: detection_classes:0 outputs

[

'detection_scores'

]

tensor_info: dtype: DT_FLOAT shape:

(

-1,

100

)

name: detection_scores:0 outputs

[

'num_detections'

]

tensor_info: dtype: DT_FLOAT shape:

(

-1

)

name: num_detections:0 Method name is: tensorflow/serving/predict
  • có thể thấy 1 số thông tin cơ bản như:

    • chữ ký (signature) của model mặc định là serving_default
    • model với 1 input, kiểu uint8, ảnh 3 kênh màu, kích thước không cố định, tên trong graph là image_tensor:0
    • model với 4 output, toàn bộ đều kiểu float32, với
      • detection_boxes: size là (None, 100, 4), mỗi bounding box sẽ được quy định bởi 2 điểm tọa độ (top-left và bottom-right), ở đây max là 100 điểm
      • detection_classes: nhãn phán đoán của 100 bounding box đó, gồm и classes
      • detection_scores: confidence score của từng nhãn ứng với từng bounding box
      • num_detections: số lượng đối tượng phán đoán được
  • Khởi chạy tensorflow_model_server

tensorflow_model_server --port

=

8500

--rest_api_port

=

8501

--model_name

=

ssd-mbv2-coco --model_base_path

=

/home/phan.huy.hoang/Downloads/ssd_mobilenet_v1_coco_2018_01_28/saved_model/
  • Code thực hiện request gRPC
test_img 

=

"/home/phan.huy.hoang/Downloads/cat.jpg"

img

=

cv2

.

imread

(

test_img

)

[

:

,

:

,

:

:

-

1

]

img_arr

=

np

.

expand_dims

(

img

,

axis

=

)

channel

=

grpc

.

insecure_channel

(

"localhost:8500"

)

stub

=

prediction_service_pb2_grpc

.

PredictionServiceStub

(

channel

)

request

=

predict_pb2

.

PredictRequest

(

)

request

.

model_spec

.

name

=

"ssd-mbv2-coco"

request

.

model_spec

.

signature_name

=

"serving_default"

request

.

inputs

[

"inputs"

]

.

CopyFrom

(

tf

.

contrib

.

util

.

make_tensor_proto

(

img_arr

,

dtype

=

np

.

uint8

,

shape

=

img_arr

.

shape

)

)

result

=

stub

.

Predict

(

request

,

10.0

)

  • Parse kết quả, ở đây mình sử dụng luôn 1 số function phân phối bởi TF Object Detection API – https://github.com/tensorflow/models/tree/master/research/object_detection/utils . File label mscoco_label_map.pbtxt download tại link sau: https://github.com/tensorflow/models/blob/master/research/object_detection/data/mscoco_label_map.pbtxt Chú ý rằng các đối tượng trả về bởi tf-serving đều đã được flatten, ví dụ với 100 bounding boxes thì biến boxes là 1 mảng 4 Ҳ 100 == 400 phần tử và các tọa độ đều đã được normalize về [0, 1]. Nếu muốn custom lại phần visualize, các bạn cần convert về tọa độ chuẩn bằng cách nhân lại với kích thước ảnh ban đầu!

import

sao chép

from

object_detection

.

utils

import

visualization_utils

as

vis_util

from

object_detection

.

utils

import

label_map_util boxes

=

result

.

outputs

[

'detection_boxes'

]

.

float_val classes

=

result

.

outputs

[

'detection_classes'

]

.

float_val scores

=

result

.

outputs

[

'detection_scores'

]

.

float_val no_dets

=

result

.

outputs

[

'num_detections'

]

.

float_val

print

(

boxes

)

[

0.05715984106063843

,

0.4511566460132599

,

0.9412486553192139

,

0.9734638929367065

,

0.0

,

0.0

,

0.0

,

0.0

,

0.0

,

0.0

,

0.0

,

0.0

,

0.0

,

0.0

,

0.0

,

0.0

,

0.0

,

0.0

,

0.0

,

0.0

,

0.0

.

.

.

.

.

.

.

.

.

label_map 

=

label_map_util

.

load_labelmap

(

"/home/phan.huy.hoang/Downloads/mscoco_label_map.pbtxt"

)

categories

=

label_map_util

.

convert_label_map_to_categories

(

label_map

,

max_num_classes

=

90

,

use_display_name

=

True

)

category_index

=

label_map_util

.

create_category_index

(

categories

)

img_

=

copy

.

deepcopy

(

img

)

image_vis

=

vis_util

.

visualize_boxes_and_labels_on_image_array

(

img_

,

np

.

reshape

(

boxes

,

[

len

(

boxes

)

//

4

,

4

]

)

,

np

.

squeeze

(

classes

)

.

astype

(

np

.

int32

)

,

np

.

squeeze

(

scores

)

,

category_index

,

use_normalized_coordinates

=

True

,

line_thickness

=

2

,

max_boxes_to_draw

=

12

,

min_score_thresh

=

0.9

,

skip_scores

=

False

,

skip_labels

=

False

,

skip_track_ids

=

False

)

plt

.

imshow

(

image_vis

)

  • Và ảnh phán đoán được

Imgur

  • Với Image Segmentation model, mình cũng dùng luôn pretrain Mask-RCNN Inception COCO model của TF Object Detection API: https://github.com/tensorflow/models/blob/master/research/object_detection/g3doc/detection_model_zoo.md#coco-trained-models

  • Kiểm tra thông tin meta-data

 
saved_model_cli show --dir saved_model/1 --all

 
MetaGraphDef with tag-set: 

'serve'

contains the following SignatureDefs: signature_def

[

'serving_default'

]

: The given SavedModel SignatureDef contains the following input

(

s

)

: inputs

[

'inputs'

]

tensor_info: dtype: DT_UINT8 shape:

(

-1, -1, -1,

3

)

name: image_tensor:0 The given SavedModel SignatureDef contains the following output

(

s

)

: outputs

[

'detection_boxes'

]

tensor_info: dtype: DT_FLOAT shape:

(

-1,

100

,

4

)

name: detection_boxes:0 outputs

[

'detection_classes'

]

tensor_info: dtype: DT_FLOAT shape:

(

-1,

100

)

name: detection_classes:0 outputs

[

'detection_masks'

]

tensor_info: dtype: DT_FLOAT shape:

(

-1, -1, -1, -1

)

name: detection_masks:0 outputs

[

'detection_scores'

]

tensor_info: dtype: DT_FLOAT shape:

(

-1,

100

)

name: detection_scores:0 outputs

[

'num_detections'

]

tensor_info: dtype: DT_FLOAT shape:

(

-1

)

name: num_detections:0 Method name is: tensorflow/serving/predict
  • Khởi chạy tensorflow_model_server:
tensorflow_model_server --port

=

8500

--rest_api_port

=

8501

--model_name

=

mrcnn-inception-coco --model_base_path

=

/home/phan.huy.hoang/Downloads/pretrained_models/mask_rcnn_inception_v2_coco_2018_01_28/saved_model
  • Code thực hiện request gRPC
 
channel 

=

grpc

.

insecure_channel

(

"localhost:8500"

)

stub

=

prediction_service_pb2_grpc

.

PredictionServiceStub

(

channel

)

request

=

predict_pb2

.

PredictRequest

(

)

request

.

model_spec

.

name

=

"mrcnn-inception-coco"

request

.

model_spec

.

signature_name

=

"serving_default"

test_img

=

"/home/phan.huy.hoang/Downloads/cat.jpg"

img

=

cv2

.

imread

(

test_img

)

[

:

,

:

,

:

:

-

1

]

img_arr

=

np

.

expand_dims

(

img

,

axis

=

)

request

.

inputs

[

"inputs"

]

.

CopyFrom

(

tf

.

contrib

.

util

.

make_tensor_proto

(

img_arr

,

dtype

=

np

.

uint8

,

shape

=

img_arr

.

shape

)

)

result

=

stub

.

Predict

(

request

,

10.0

)

  • Parse kết quả, các bạn có thể sử dụng method tf.contrib.util.make_ndarray để lấy được đúng shape đầu ra của từng thành phần. Hoặc sử dụng method numpy.reshape ?
boxes 

=

tf

.

contrib

.

util

.

make_ndarray

(

result

.

outputs

[

'detection_boxes'

]

)

classes

=

tf

.

contrib

.

util

.

make_ndarray

(

result

.

outputs

[

'detection_classes'

]

)

scores

=

tf

.

contrib

.

util

.

make_ndarray

(

result

.

outputs

[

'detection_scores'

]

)

no_dets

=

tf

.

contrib

.

util

.

make_ndarray

(

result

.

outputs

[

'num_detections'

]

)

masks

=

tf

.

contrib

.

util

.

make_ndarray

(

result

.

outputs

[

'detection_masks'

]

)

for

ι

in

[

boxes

,

classes

,

scores

,

no_dets

,

masks

]

:

print

(

ι

.

shape

)

  • Kết quả thu được
XEM THÊM  Lưỡi Trắng Ở Trẻ Sơ Sinh: Dấu Hiệu, Nguyên Nhân Và Xử Lí An Toàn

Imgur

Serving đồng thời nhiều model

  • Tensorflow Serving trợ giúp việc serving đồng thời nhiều model, nhiều phiên bản và tự động reload lại version tiên tiến nhất của model. Cách đơn giản nhất là tiến hành tạo 1 file serving.config với cấu trúc được mô tả như bên dưới, các đường dẫn tới model đều là các đường dẫn tuyệt đối (absolute path):
model_config_list { 
  config {
    name: 'model-1'
    base_path: 'path-to-model1'
    model_platform: "tensorflow",
    model_version_policy {
      specific {
         versions: 1
      }
    }
  }
  config {
    name: 'model-2'
    base_path: 'path-to-model2'
    model_platform: "tensorflow",
    model_version_policy {
      specific {
         versions: 1
      }
    }
  }
  config {
    name: 'model-3'
    base_path: 'path-to-model3'
    model_platform: "tensorflow",
    model_version_policy {
      specific {
         versions: 1
      }
    }
  }
}
  • Thực hiện khởi chạy tensorflow_model_server với command
tensorflow_model_server --port

=

8500

--rest_api_port

=

8501

--model_config_file

=

./temp_models/serving.config
  • 1 vài thông tin cần lưu ý như:
    • base_path tại file config là đường dẫn tuyệt đối tới thư mục lớn chứa các thư mục version con của model
    • Tensorflow Serving sẽ tự động reload version mới của model, zero-downtime deployment, hầu hết không có gián đoạn giữa các lần update version
    • Tự động rollback lại các version cũ nếu version mới được xóa đi

CPU optimized

  • Nếu để ý bên trên, khi thực hiện khởi chạy tensorflow_model_server sẽ xuất hiện 1 dòng warning

Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 FMA

  • Mặc định, khi các bạn install tensorflow trên môi trường CPU bằng câu lệnh: pip install tensorflow, 1 số các CPU extension sẽ không được kèm theo như: AVX, AVX2, FMA, … giúp cải tổ vận tốc xử lý trên CPU. Chi tiết các bạn có thể xem thêm tại link sau: https://en.wikipedia.org/wiki/Advanced_Vector_Extensions

AVX (Advanced Vector Extensions) introduces fused multiply-accumulate (FMA) operations, which speed up linear algebra computation, namely dot-product, matrix multiply, convolution, etc. Almost every machine-learning training involves α great deal of these operations, hence will be faster on α CPU that supports AVX and FMA (up to 300%)

  • Để enable các CPU extension đó, các bạn cần build from source (nghĩa là compile từ chính source code) Các bạn có thể tham khảo thêm tại 1 số hướng dẫn
    • https://stackoverflow.com/a/47227886
    • https://github.com/tensorflow/tensorflow/issues/7778#issuecomment-281678077
    • https://www.tensorflow.org/install/source
    • https://github.com/tensorflow/serving/blob/8ab0e9aeaff33d44798d6bc429195012483d48cb/tensorflow_serving/g3doc/setup.md#available-binaries

Cải tổ inference time với Protos

  • Các đoạn code xử lý request với gRPC bên trên, khi thực hiện khái niệm các inputs đều phải gọi tới method make_tensor_proto với nhiệm vụ để convert các python / numpy object sang TensorProto object. Thực chất, thậm chí các bạn không cần phải install 2 lib là tensorflowtensorflow-serving-api để thực hiện predict phía client mà tuyệt đối có thể thay thế bằng các prebuild-protobuf từ gRPC, giúp cải tổ inference time tại client. Để thực hiện, ta cần install grpcio-tools
pip uninstall tensorflow tensorflow-serving-api
pip 

install

grpcio-tools
  • Tiến hành clone 2 repo tensorflow, tensorflow-serving và sao chép các file .proto sau
serving/  
  tensorflow_serving/apis/model.proto
  tensorflow_serving/apis/predict.proto
  tensorflow_serving/apis/prediction_service.proto

tensorflow/  
  tensorflow/core/framework/resource_handle.proto
  tensorflow/core/framework/tensor_shape.proto
  tensorflow/core/framework/tensor.proto
  tensorflow/core/framework/types.proto
  • Tạo mới 1 thư mục tên protos và chuyển các file vừa sao chép vào thư mục tương ứng như cây thư mục bên dưới
protos/  
  tensorflow_serving/
    apis/
      *.proto
  tensorflow/
    core/
      framework/
        *.proto
  • Tiến hành tạo các gRPC implementation là các file python bằng câu lệnh sau

PROTOC_OUT

=

protos/

PROTOS

=

$(

find

.

|

grep

".proto$"

)

for

in

$PROTOS

;

do

python -m grpc.tools.protoc -Ι

.

--python_out

=

$PROTOC_OUT

--grpc_python_out

=

$PROTOC_OUT

$ᴘ

done

hoặc các bạn có thể tham khảo thêm từ repo sau: https://github.com/huyhoang17/tensorflow-serving-docker/tree/master/protos

  • Hiện tại, ta thay thế 2 dòng import sau từ tensorflow-serving-api

from

tensorflow_serving

.

apis

import

predict_pb2

from

tensorflow_serving

.

apis

import

prediction_service_pb2

thành

from

protos

.

tensorflow_serving

.

apis

import

predict_pb2

from

protos

.

tensorflow_serving

.

apis

import

prediction_service_pb2
  • Cuối cùng, thay thế đoạn code sử dụng method make_tensor_proto
tensor 

=

tf

.

contrib

.

util

.

make_tensor_proto

(

features

)

request

.

inputs

[

'inputs'

]

.

CopyFrom

(

tensor

)

thành

from

protos

.

tensorflow

.

core

.

framework

import

tensor_pb2

from

protos

.

tensorflow

.

core

.

framework

import

tensor_shape_pb2

from

protos

.

tensorflow

.

core

.

framework

import

types_pb2

def

grpc_infer

(

imgs

)

:

.

.

.

tensor_shape

=

imgs

.

shape dims

=

[

tensor_shape_pb2

.

TensorShapeProto

.

Dim

(

size

=

dim

)

for

dim

in

tensor_shape

]

tensor_shape

=

tensor_shape_pb2

.

TensorShapeProto

(

dim

=

dims

)

tensor

=

tensor_pb2

.

TensorProto

(

dtype

=

types_pb2

.

DT_FLOAT

,

tensor_shape

=

tensor_shape

,

float_val

=

imgs

.

reshape

(

-

1

)

)

request

.

inputs

[

'inputs'

]

.

CopyFrom

(

tensor

)

.

.

.

Cải tổ inference time với Batching

  • Để cải tổ performance của hệ thống, các bạn có thể thực hiện batch processing với tensorflow serving. Về hướng dẫn rõ ràng tham khảo tại link sau: https://github.com/tensorflow/serving/tree/master/tensorflow_serving/batching#tensorflow-serving-batching-guide

  • Model without [Server-side] Batching

Imgur

  • Model with Server-side Batching

Imgur

  • Với server-side batching, các bạn có thể tiến hành enable bằng cách tạo mới 1 file batching_parameters.txt
max_batch_size { value: 32 }
batch_timeout_micros { value: 5000 }
  • Với:
    • max_batch_size: là số batchsize, ι.e batchsize=32
    • batch_timeout_micros: thời gian chờ tối đa để tạo 1 batch gồm и=32 samples

và thêm 2 params sau thời điểm khởi chạy tensorflow_model_server hoặc chạy bằng docker

tensorflow_model_server --port

=

8500

--rest_api_port

=

8501

--model_name

=

mnist-serving

--model_base_path

=

/home/phan.huy.hoang/phh_workspace/temp_models/serving

--enable_batching

=

true

--batching_parameters_file

=

/home/phan.huy.hoang/phh_workspace/temp_models/batching_parameters.txt
  • Với client-side batching, mình cũng từng thực hiện bên trên. Method make_tensor_proto cho phép bạn truyền vào với biến các kích thước (и, ?, Н, ₵) với и là số lượng sample trong 1 batch

Tensorflow Serving với Docker / Docker Compose

  • Trong quá trình dev thì mình thường sử dụng tensorflow_model_server để khởi chạy model serving. Tuy nhiên, ngoài cách trên, các bạn cũng có thể sử dụng docker để chạy 1 service riêng để serving model. Mình sẽ lấy ví dụ model MNIST
 
docker pull tensorflow/serving

 
docker run --rm -p 

8500

:8500 -p

8501

:8501 --mount

type

=

bind,source

=

/home/phan.huy.hoang/phh_workspace/temp_models/serving,target

=

/models/mnist-serving -e

MODEL_NAME

=

mnist-serving -t tensorflow/serving docker run --rm -p

8500

:8500 -p

8501

:8501 --mount

type

=

bind,source

=

/home/phan.huy.hoang/phh_workspace/temp_models/serving,target

=

/models/mnist-serving --mount

type

=

bind,source

=

/home/phan.huy.hoang/phh_workspace/temp_models/serving.config,target

=

/models/serving.config -t tensorflow/serving --model_config_file

=

/models/serving.config

curl

localhost:8501/v1/models/mnist-serving

{

"model_version_status"

:

[

{

"version"

:

"1"

,

"state"

:

"AVAILABLE"

,

"status"

:

{

"error_code"

:

"OK"

,

"error_message"

:

""

}

}

]

}

  • Và thực hiện request tới gRPC và http như hướng dẫn bên trên. Với:

    • source: absolute path của thư mục chứa các version của model
    • target: absolute path thư mục mount tại docker, nếu không sử dụng file config thì cần đặt trùng với tên của model
    • MODEL_NAME: tên của model
    • model_config_file: absolute path tới file config. Chú ý, cần thay đổi biến base_path trong file config thành đường dẫn mount trong docker. ι.e base_path: '/models/mnist' và tên thư mục không cần giống tên của model
  • Tiếp theo, mình sẽ ví dụ với 1 website API nhỏ, các lib sử dụng bao gồm: flask, tensorflow-serving-api, docker / docker-compose. Tập dữ liệu sử dụng là MNIST

  • Code tiền xử lý dữ liệu, thực hiện gRPC request

import

base64

import

cv2

import

numpy

as

np

import

grpc

from

protos

.

tensorflow_serving

.

apis

import

predict_pb2

from

protos

.

tensorflow_serving

.

apis

import

prediction_service_pb2_grpc

from

protos

.

tensorflow

.

core

.

framework

import

(

tensor_pb2

,

tensor_shape_pb2

,

types_pb2

)

def

convert_image

(

encoded_img

,

to_rgb

=

False

)

:

if

isinstance

(

encoded_img

,

str

)

:

b64_decoded_image

=

base64

.

b64decode

(

encoded_img

)

else

:

b64_decoded_image

=

encoded_img img_arr

=

np

.

fromstring

(

b64_decoded_image

,

np

.

uint8

)

img

=

cv2

.

imdecode

(

img_arr

,

cv2

.

IMREAD_COLOR

)

img

=

cv2

.

cvtColor

(

img

,

cv2

.

COLOR_BGR2GRAY

)

img

=

np

.

expand_dims

(

img

,

axis

=

-

1

)

return

img

def

grpc_infer

(

img

)

:

channel

=

grpc

.

insecure_channel

(

"10.5.0.5:8500"

)

stub

=

prediction_service_pb2_grpc

.

PredictionServiceStub

(

channel

)

request

=

predict_pb2

.

PredictRequest

(

)

request

.

model_spec

.

name

=

"mnist-serving"

request

.

model_spec

.

signature_name

=

"serving_default"

if

img

.

ndim

==

3

:

img

=

np

.

expand_dims

(

img

,

axis

=

)

tensor_shape

=

img

.

shape dims

=

[

tensor_shape_pb2

.

TensorShapeProto

.

Dim

(

size

=

dim

)

for

dim

in

tensor_shape

]

tensor_shape

=

tensor_shape_pb2

.

TensorShapeProto

(

dim

=

dims

)

tensor

=

tensor_pb2

.

TensorProto

(

dtype

=

types_pb2

.

DT_FLOAT

,

tensor_shape

=

tensor_shape

,

float_val

=

img

.

reshape

(

-

1

)

)

request

.

inputs

[

'input_image'

]

.

CopyFrom

(

tensor

)

try

:

result

=

stub

.

Predict

(

request

,

10.0

)

result

=

result

.

outputs

[

"y_pred"

]

.

float_val result

=

np

.

array

(

result

)

.

reshape

(

(

-

1

,

10

)

)

result

=

np

.

argmax

(

result

,

axis

=

-

1

)

return

result

except

Exception

as

e

:

print

(

e

)

return

None

  • Code API endpoint, thực hiện nhận request, trả kết quả

import

json

from

flask

import

Flask

,

request

from

utils

import

grpc_infer

,

convert_image app

=

Flask

(

__name__

)

@app

.

route

(

'/api/mnist'

,

methods

=

[

'POST'

]

)

def

hello

(

)

:

encoded_img

=

request

.

values

[

'encoded_image'

]

img

=

convert_image

(

encoded_img

)

result

=

grpc_infer

(

img

)

return

json

.

dumps

(

{

"code"

:

200

,

"result"

:

result

.

tolist

(

)

}

)

if

__name__

==

'__main__'

:

app

.

run

(

debug

=

True

,

hosting

=

"10.5.0.4"

,

port

=

5000

)

  • Dockerfile
FROM ubuntu:16.04

RUN 

apt-get

update RUN

apt-get

install

-y python3-pip python3-dev libglib2.0-0 libsm6 libxrender1 libxext6

&&

cd

/usr/local/bin

&&

ln

-s /usr/bin/python3 python

&&

pip3

install

--upgrade pip RUN

mkdir

/code WORKDIR /code COPY requirements.txt /code/requirements.txt RUN pip3

install

-r requirements.txt
  • Docker-compose
version: 

'2'

services: website: container_name: mnist_api build:

.

restart: always volumes: - .:/code command:

bash

-c

"python3 serve.py"

ports: -

"5000:5000"

networks: mynet: ipv4_address:

10.5

.0.4 tf-serving: image: tensorflow/serving restart: always ports: -

"8500:8500"

-

"8501:8501"

volumes: - ./serving:/models - ./serving_docker.config:/models/serving_docker.config command: --model_config_file

=

/models/serving_docker.config networks: mynet: ipv4_address:

10.5

.0.5 networks: mynet: driver: bridge ipam: config: - subnet:

10.5

.0.0/16 gateway:

10.5

.0.1
  • Build image
 
docker-compose build

 
docker-compose up
  • Test với dữ liệu MNIST

Imgur

  • Test thử API với Postman, mình gửi data là ảnh dạng base64

Imgur

1 số hướng tiếp cận khác

Tensorflow Serving với OpenVINO toolkit

  • Trong 1 bài blog gần đây của mình có đề cập tới 1 toolkit là OpenVINO về Model Optimization. Các bạn có thể sử dụng Tensorflow Serving cùng với OpenVINO để cải tổ vận tốc truy vấn của model.

  • Reference: Tối ưu hóa model với OpenVINO toolkit

Tensorflow Serving với ONNX

  • ONNX được sử dụng như 1 toolkit để chuyển hóa model sang 1 dạng format trung gian là .onnx, từ đó có thể gọi và inference với các framework khác nhau, trợ giúp hầu như các framework deep learning hiện tại. Bạn có thể training 1 model với Pytorch, lưu model dưới dạng .pth, dùng ONNX để convert sang định dạng .onnx, rồi sử dụng 1 lib trung gian khác như: tensorflow-onnx để convert .onnx sang dạng frozen model của tensorflow. Từ đó có thể thực hiện serving model bằng Tensorflow Serving như bình thường
  • Graphpipe cũng là 1 bộ dụng cụ trợ giúp trong việc serving và deploy machine learning model lên production, do Oracle phát triển. Graphpipe tương thích rất tốt với định dạng model trung gian ONNX nên các non-tensorflow model tuyệt đối có thể convert sang onnx rồi thực hiện deploy với graphpipe
  • Simple Tensorflow Serving (STS) cũng là 1 OOS phục vụ cho các tác vụ về model serving. Ngoài Tensorflow, STS còn support các model từ nhiều framework khác nhau (ONNX, Scikit-learn, XGBoost, PMML, and H2O) và nhiều từ ngữ khác nhau (Python, ₵++, Java, Scala, …) 1 trong những điểm nổi bật so với Tensorflow Serving như support authenticationencrypted connections https://github.com/tobegit3hub/simple_tensorflow_serving#authentication , điều mà TS hiện tại chưa support
  • Các bạn cũng có thể tích hợp Tensorflow Serving với Kubernetes, tham khảo 1 số hướng dẫn sau:
    • https://www.tensorflow.org/tfx/serving/serving_kubernetes
    • https://towardsdatascience.com/deploy-your-machine-learning-models-with-tensorflow-serving-and-kubernetes-9d9e78e569db
  • Cortex cũng là 1 OOS trợ giúp việc deploy machine learning model lên production, viết bằng Golang.
  • Phew, cuối cùng thì mình cũng từng hoàn thiện xong bài blog khá dài này. Hi vọng qua bài hướng dẫn này sẽ giúp các bạn có cái nhìn tổng quan nhất về luồng xử lý và hướng tiếp cận khi triển khai mô hình lên production với Tensorflow Serving. Mọi ý kiến phản hồi và đóng góp vui lòng comment bên dưới hoặc gửi mail về địa chỉ: [email protected] .

  • Cảm ơn các bạn đã đọc nội dung và hẹn hội ngộ trong những bài blog sắp tới!

  • Năm mới an lành và vui vẻ ? ? 2️⃣0️⃣2️⃣0️⃣

Reference


Giải ngố ORM và JPA và Hibernate | ORM, JPA, Hibernate là gì


Nội dung
▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
0:00 Đặt vấn đề video
0:58 Mục tiêu video
1:20 Vì sao cần kết nối từ ngữ lập trình tới Database
2:23 Có bao nhiêu cách kết nối Java tới Database
3:00 JDBC và nhược điểm
3:28 Demo JDBC
4:16 Nhược điểm JDBC
6:38 Nhu cầu hướng đối tượng sau truy vấn JDBC
7:25 ORM là gì?
8:50 JPA là gì?
10:03 Cấu trúc JPA
10:35 Persistence Framework
12:06 Ví dụ: Giới thiệu HQL của Hibernate
Link
▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
Video trước:
Video sau:
Link slide: https://docs.google.com/presentation/d/1gqhKsNe5dgXHr7BcsnDkQFdmSlPLSt_QPMs3NN4uM/edit?usp=sharing
Link Source code:
Link tham khảo:
Mục đích của kênh:
▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
Kênh Youtube nhằm mục đích:
Đối tượng: Các bạn sinh viên, các bạn thích thú lập trình, mới khởi đầu, hay thậm chí làm việc nhiều năm nói chung.
Chia sẻ tri thức, kĩ thuật, thái độ để làm lập trình tốt hơn.
Các vấn đề trong kênh:
Công nghệ tri thức lập trình: Java, PHP, .. thậm chí full stack.
Các kĩ thuật: Thương thảo lương, chia sẻ kinh nghiệm phỏng vấn,….Execution,…
Kênh này sẽ phi thương mại và, nếu có kiếm tiền sau này thì sẽ là mục đích từ thiện, hoặc để mua các khóa học chất lượng và chia sẻ cho các bạn.
Social
▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
Website: https://youngdeveloper.net
Github: https://github.com/youngdeveloperVN
Facebook: https://www.facebook.com/huygau301291
Gmail: ngochuy.mmt@gmail.com
Gmail: huypn6@fpt.edu.vn
Skype: huy.minecraft.91
Profile u0026 Contact
▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
Tên: Phạɱ Ngọ¢ Huy
Phone: 0977 941 910 0356 909 680.
Công việ¢: Lậᴘ trình viên từ 2013 Nay.
Các từ ngữ đã lập trình: JAVA, PHP, NET.
Đã từng họ¢: Giao thông vậи tảι Hà Nộι K50 Khoa công nghệ thông tin.

XEM THÊM  3 tháng đầu bà bầu nên ăn gì tốt cho em bé, mẹ khỏe mạnh

In addition to looking at this article You can also see other useful information. Many more we provide here: See more knowledge here.

Giải ngố ORM và JPA và Hibernate | ORM, JPA, Hibernate là gì

SAMMY BẤT NGỜ KHI TẤT CẢ THÀNH VIÊN HERO TEAM BỊ MẤT TÍCH | THỬ THÁCH 24H GIẢI CỨU HERO TEAM


UID Mini world Sammy Đào : 48972472 r
Nick name Minecraft: Sammy_TVr
Cộng Đồng MiniWorld Việt Nam http://bit.ly/MiniWorldVNr
▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬r
? Máy chủ Minecraft của Hero Team: Sv.Heromc.netr
? Phiên bản : 1.12.2r
? Trang chủ : heromc.netr
▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬r
Đăng ký kênh Sammy Đào : https://bit.ly/2HwhEqVr
LIÊN HỆ QUẢNG CÁO : contacts@heromedia.vnr
➡️ HERO TV: http://bit.ly/heroteamtvr
[Facebook cá nhân] : https://www.facebook.com/profile.php?id=100021975529616r
▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬r
ĐĂNG KÍ CHO HERO TEAM r
➡️ Mèo Simmy: https://goo.gl/3Vt539r
➡️ Mister Vit: http://bit.ly/2wi7intr
➡️ Timmy TV: http://bit.ly/2oU1TR9 r
➡️ Phong Cận TV: https://bit.ly/2PzcVGQr
➡️ Kamui TV: http://bit.ly/kamuitvr
➡️ SammyTV: https://bit.ly/2HwhEqVr
➡️ KaironTV: https://bit.ly/2ATgGjLr
➡️ Siro Official: http://bit.ly/2ZvvrFqr
▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬r
Theo dõi mxh của Sammyr
Instagram : https://www.instagram.com/sammy96_0/r
Facebook cá nhân: https://www.facebook.com/profile.php?id=100021975529616r
Facebook Group: NHÓM SIÊU ANH HÙNG (HERO TEAM): http://bit.ly/heroteamr
Cộng Đồng Minecraft Việt Nam: http://bit.ly/minecraftvietnamr
r
Nhạc sử dụng trong video được phê duyệt bởir
Kevin Macleod: https://www.youtube.com/user/kmmusicr
NCS: https://www.youtube.com/user/NoCopyri…

SAMMY BẤT NGỜ KHI TẤT CẢ THÀNH VIÊN HERO TEAM BỊ MẤT TÍCH | THỬ THÁCH 24H GIẢI CỨU HERO TEAM

8 Nguồn PROTEIN Thực Vật Tốt Gấp 100 Lần Thịt Bạn Không Nên Bỏ Qua -100 Người 99 Người Không Biết


8 Nguồn PROTEIN Thực Vật Tốt Gấp 100 Lần Thịt Bạn Không Nên Bỏ Qua 100 Người 99 Người Không Biết
Đăng ký theo dõi kênh Miễn Phí để nhận những video tiên tiến nhất : https://goo.gl/UWoyo2

TOP các video HAY NHẤT của https://monrun.vn/:
+ 6 loại trái cây giúp hạ đường huyết tốt gấp tỷ lần nhân sâm là thần dược cho người bệnh tiểu đường: https://youtu.be/n_ElKVChsos
+ Chữa Bệnh Tiểu Đường Chỉ Bằng 1 Quả Mướp Kết Quả Khiến Cả Triệu Người Bất Ngờ: https://youtu.be/Yb3zoJX2uX4
+ Bổ gấp 100 lần nhân sâm, loại cây quý hơn vàng, mọc đầy việt nam 100 người thì 99 người không biết: https://youtu.be/QdAXsPNKyJU
+ Đơn thuốc khỏi hoàn toàn bệnh gút ngay tận nơi chỉ với 2 nghìn đồng mỗi ngày: https://youtu.be/nGuwNxze9qI
+ Người bệnh tiểu đường có cần kiêng cơm trắng không? kết quả khiến cả triệu người ngạc nhiên: https://youtu.be/LtVtUw_VCHU
+ Trị tận gốc tiểu đường huyết áp cao bệnh nguy kịch cỡ nào cũng khỏi nhờ dùng lá sung theo phương pháp này:
https://youtu.be/DD36l3Szhlo
+ Cả châu âu truy lùng loại quả quý hơn vàng này chữa bách bệnh này mà người việt thờ ơ bỏ phí:
https://youtu.be/uxxj7YN8_o
+ Máu Nhiễm Mỡ Gan Nhiễm Mỡ Bệnh Nặng Cỡ Nào Cũng Khỏi Chỉ Nhờ Thực Phẩm Này, Cả Đời Không Lo Tái Phát:
https://youtu.be/QNTmH4se4
+ Người Mắc Bệnh Cao Huyết Áp Mỡ Máu Cao Nên Biết Điều Này Sớm Kẻo Hối Tiếc Cả Đời:
https://youtu.be/zFTRMi0mVy4
+ Bài Thuốc Cực Quý Chữa Khỏi Hẳn Cao Huyết Áp Mỡ Máu Chỉ Sau 2 Lần Sử Dụng Không Tốn 1 Xu Tiền Thuốc:
https://youtu.be/lQXNIYdVYjI
+ Bị Cao Huyết Áp Mỡ Máu Tiểu Đường Tuyệt Đối Không Được Bỏ Qua Bài Thuốc Quý Hiệu Quả Ít Ai Ngờ Tới: https://youtu.be/gucXz4QK2fo
+ Đơn thuốc trị bệnh tiểu đường thần kỳ dễ nấu ai cũng có thể làm: https://youtu.be/5jGSTS7QHU
+ Đơn thuốc trị bệnh tiểu đường thần kỳ dễ nấu ai cũng có thể làm: https://youtu.be/5jGSTS7QHU
+ Lấy Đậu Đen Rang Lên Uống Mỗi Ngày Điều Kỳ Diệu Xảy Ra Với Cơ Thể Bạn Cả Triệu Người Làm Theo: https://youtu.be/VZOrjnoMJs

Mời các bạn xem thêm các video playlist khác tại đây nhé:
BỆNH TIỂU ĐƯỜNG : https://goo.gl/XFriWV
BỆNH CAO HUYẾT ÁP CÁCH CHỮA TRỊ: https://goo.gl/b4sYbg
BỆNH VỀ TÓC CÁCH CHỮA TRỊ : https://goo.gl/jRT16W
THỰC PHẨM SỨC KHỎE : https://goo.gl/ksaoFO
BỆNH XƯƠNG KHỚP : https://goo.gl/0rgSLh
LÀM ĐẸP AN TOÀN : https://goo.gl/nx4iSi
BÀI THUỐC DÂN GIAN : https://goo.gl/L3nr1T
BỆNH DẠ DÀY : https://goo.gl/8jRhbn
BỆNH GÚT : https://goo.gl/OVq1Xx
SỨC KHỎE MẸ BÉ : https://goo.gl/F6r0dQ
SỨC KHỎE RĂNG MIỆNG : https://goo.gl/2LGt94
BỆNH MẤT NGỦ : https://goo.gl/4l1qKW
XUẤT TINH SỚM YẾU SINH LÝ : https://goo.gl/w8P7tL

Lưu ý:
+ 1 số hình ảnh chỉ mang tính chất minh họa.
+ Video có thể sử dụng nội dung có bản quyền dựa trên luật sử dụng hợp lý Fair Use: https://www.youtube.com/yt/copyright/vi/fairuse.html

8 Nguồn PROTEIN Thực Vật Tốt Gấp 100 Lần Thịt Bạn Không Nên Bỏ Qua -100 Người 99 Người Không Biết

Eat Clean là gì? Hiệu quả thực sự của Eat Clean có thần thánh như bạn tưởng?


Eat clean đang là chân ái của các cô gái phụ nữ trong quá trình giảm cân. Ai cũng nói đang ăn eat clean nhưng thực sự các bạn có hiểu rõ về eat clean hay không. Nhiều người đang muốn giảm thăng bằng cơ chế ăn eat clean cũng nên tìm hiểu ăn eat clean như vậy nào, phép tắc khi ăn eat clean, thực đơn ăn eat clean nào hiệu quả, rẻ tiền mà lại ngon. Hãy cùng blog news tìm hiểu về eat clean trong video này nhé!
EatClean ĂnKiêng BlogNews
Eat clean là gì?
Chế độ ăn Eat clean hiểu nôm na là cơ chế “ăn sạch”. Eat clean khuyến khích mọi người hãy ăn thức ăn dưới dạng nguyên thủy nhất của nó.
Tức là tất cả chúng ta chỉ nên ăn những thực phẩm không qua sơ chế sẵn, không chứa (hoặc ít) hóa chất, không bị dư thừa lượng đường, muối và chất béo.
Chế độ ăn Eat Clean vẫn cho phép bạn ăn đầy đủ các thực phẩm có chứa tinh bột, đạm, xơ,…Tuy nhiên, khi sơ chế các thực phẩm này, chúng ta nên hạn chế việc sử dụng dầu mỡ, muối và đường. So với các cơ chế ăn và phương pháp giảm cân khác, Eat Clean được cho là khá dễ để thực hiện và ứng dụng.
2. Chế độ ăn eat clean ăn như vậy nào?
Ăn theo cơ chế ăn eat clean có thể chia ra ăn như những bữa bình thường gồm: Ăn sáng, ăn trưa, ăn tối tùy vào thời điểm mà có những thành phần và lượng khác nhau giúp thân thể khỏe mạnh mà không bị béo.
Chế độ ăn eat clean khuyến khích bạn ăn các loại thực phẩm toàn phần như ngũ cốc, trái cây, thịt nạc, sữa non cũng như các loại hạt và chất béo lành mạnh.
Đối với phụ nữ việc thực hiện theo cơ chế ăn eat clean không chỉ là giảm cân mà nó còn là lối sống lành mạnh mà PHỤ NỮ HIỆN ĐẠI theo đuổi.
Chế độ ăn sạch eat clean là lựa chọn các loại thực phẩm hữu cơ không dư thừa dầu mỡ đường. Trong quá trình sơ chế đa số là hấp luộc nhằm giữ tối đa hoạt chất.
3. Thế nhưng hiệu quả thực sự của Eat Clean là gì?
• Ưu thế của cơ chế ăn Eat Clean là không có sự thay đổi dinh dưỡng đột ngột gây hại cho sức khỏe nào. Hay nói cách khác là bạn sẽ ăn đầy đủ các hoạt chất, chất béo, vitamin, đạm, bột… không loại bỏ thứ gì.
• Thứ duy nhất bạn cần “dặn lòng từ bỏ” trong cơ chế ăn này là đường, dầu mỡ, chất phụ gia (bột nêm, mì chính). Ngoài ra, bạn hướng tới ăn uống thực phẩm tự nhiên nhất, chỉ ăn thực phẩm tươi sống theo mùa, hạn chế tối đa thức ăn đông lạnh, không dùng đồ sơ chế sẵn.
• Vậy nên, hiệu quả trước tiên mà Eat Clean mang lại đó là giúp bạn hạn chế tiêu thụ các thực phẩm nấu nướng quá kỹ, quá phức tạp… phần nào gây hại cho sức khỏe.
• Bởi bạn biết rằng, khi thực phẩm được sơ chế quá lâu sẽ thay đổi, những chất dầu mỡ, gia vị có thể biến chất khi được đun nấu lâu.
• Ngoài ra, những gia vị này cũng vô tình làm thân thể bạn nạp thêm 1 số năng lượng không thực sự thiết yếu. Giảm bớt các loại thực phẩm này, thân thể cũng sẽ được thanh lọc hơn, đơn vị trong thân thể “bớt” phải vận hành nhiều.
• Tuy nhiên, thực phẩm trong cơ chế ăn Eat Clean là thực phẩm tươi, nguyên bản ít hoặc chưa qua sơ chế, với thành phần nguyên cám, nguyên hạt. Bạn sẽ cảm nhận cũng như hấp thu được lượng hoạt chất nhiều nhất có trong từng loại thực phẩm.
• Hạn chế đồ đóng hộp, loại đồ ăn nấu sẵn, đóng hộp là bạn cũng giảm thiểu tiếp nhận nguyên liệu hóa học, chất tạo màu, mùi, chất giữ gìn vào thân thể rồi. Và như vậy, thân thể sẽ rất cám ơn bạn đó.
• Hiệu quả tiếp theo đó là, Eat Clean giúp bạn giảm cân tự nhiên mà vẫn đảm bảo đủ hoạt chất. Như đã nói ở trên, Eat Clean không bắt bạn loại bỏ chất nào, mà trong thực đơn ăn, bạn chỉ cần giảm thiểu lượng tinh bột hấp thụ (nghĩa là ăn ít đi nhưng vẫn có), tăng trưởng ăn tinh bột tốt cho sức khỏe.
• Bạn có thể thay thế gạo trắng bằng gạo lứt, bánh mì trắng bằng bánh mì nguyên cám, khoai lang…; sử dụng thịt nạc, thịt trắng, hải sản, các loại nấm, đậu; chất xơ, vitamin lấy từ rau củ quả, trái cây; hay “nạp” chất béo tốt từ dầu oliu, dầu mè, quả bơ…
• Tuy nhiên, Eat Clean giúp bạn ăn nhiều rau, trái cây, đạm tốt. Những thực phẩm này sẽ giúp thân thể tăng cường trao đổi chất, từ đó giúp đốt cháy năng lượng dư thừa, da sáng, mịn màng.
• Đồng thời, với phép tắc ăn Eat Clean 6 bữa/ngày này, thân thể bạn không bị bỏ đói và bạn sẽ có trách nhiệm hơn với từng bữa ăn, với sức khỏe của chính mình.
• Bạn biết rằng, khi bị bỏ đói, rất có thể bạn sẽ ăn nhiều hơn, ăn mất kiểm tra vào bữa ăn tiếp theo. Vì vậy, việc ăn đúng giờ, đúng thời gian biểu, cùng thực đơn khoa học, đầy đủ dinh dưỡng… sẽ giúp bạn điều chỉnh đồng hồ sinh học.
• Từ đó, hệ thống đơn vị nội tạng, đặc biệt là dạ dày, sẽ khỏe mạnh hơn, hoạt động hiệu quả, giúp hấp thu dưỡng chất tốt hơn.
• Với việc ăn khoa học, đầy đủ hoạt chất, lại khoa học đúng giờ… cơ chế Eat Clean giúp bạn đến gần hơn đoạn đường ăn uống lành mạnh và có trách nhiệm hơn với sức khỏe của chính mình.

Xem các video khách của Blog News nhé : https://www.youtube.com/c/Blognewshot
Fanpage Blognew : https://www.facebook.com/blogtintucnong

Eat Clean là gì? Hiệu quả thực sự của Eat Clean có thần thánh như bạn tưởng?

Chỉ Số ᴘ/E, EPS và PEG Có Nghĩa Là Gì? (3 Ứng Dụng Ngay) | CÚ Thông Thái


Trong video này, tôi sẽ giới thiệu cho bạn biết “Chỉ số P/E, chỉ số EPS, Chỉ số PEG là gì?”
Nhiều bạn đã hỏi Cú về các chỉ số PE, chỉ số EPS hay chỉ số PEG và cách sử dụng của nó như vậy nào? Những chỉ số tài chính doanh nghiệp trọng yếu giúp cho bạn nhận xét được cổ phiếu nào hiệu quả và có tiềm năng tăng trưởng?
Chỉ số ᴘ/E (PricetoEarnings Ratio) là một trong những chỉ số thiết yếu khi tất cả chúng ta định giá một doanh nghiệp.
Các nhà đầu tư hay nói nếu chỉ số ᴘ/E thấp tức là doanh nghiệp đang được định giá thấp và nên mua vào.
Chỉ số ᴘ/E cao là doanh nghiệp được định giá mắc và nên bán ra.
Nhưng thực tiễn có phải như vậy không?
Vì sao có rất nhiều cổ phiếu có ᴘ/E thấp lại có ít người mua trong lúc những cổ phiếu có ᴘ/E cao như Facebook, Amazon lại thu hút rất nhiều nhà đầu tư đổ tiền vào.
Bạn đang nắm giữ cổ phiếu có ᴘ/E cao hơn hay thấp hơn so với nghề?
Chỉ số EPS 4 quý gần nhất của cổ phiếu đó có tốt hơn EPS hiện tại hay không?
Chỉ số PEG của doanh nghiệp bạn nắm giữ so với nghề thế nào?
Hãy cho Cú biết ý kiến của các bạn bằng phương pháp để lại comment dưới video này nhé.
Nếu bạn muốn Cú làm thêm về đề tài nào thì cũng hãy để lại comment của các bạn và Cú sẽ tìm hiểu mang vào plan nhé!
| Facebook: https://m.me/CuThongThai.VNInvestor
| Tiktok: https://vt.tiktok.com/ZSJJKgbU4/?
| Youtube: https://www.youtube.com/channel/UCsk1Sln_4ju2JVyPhFcWwtA
| Podcasts: https://open.spotify.com/show/2QVMe6zi7toZM1YzRdUt7V
| Group cộng đồng Nhà đầu tư F0: https://www.facebook.com/groups/176094777389693
| Link mở tài khoản ở Tradingview để phân tích kỹ thuật: https://vn.tradingview.com/?offer_id=10u0026aff_id=27109

Chỉ Số P/E, EPS và PEG Có Nghĩa Là Gì? (3 Ứng Dụng Ngay) | CÚ Thông Thái

In addition to looking at this article You can also see other useful information. Many more we provide here: See other wayshoi-dap/

Thank you very much for viewing the post topic. portion là gì

Xem thêm bài viết thuộc chuyên mục: Mẹ và Bé