构建深度学习框架运行平台
構(gòu)建深度學(xué)習(xí)框架運(yùn)行平臺
將為TensorFlow、PyTorch和TorchScript之外的元素構(gòu)建一個(gè)簡單的深度學(xué)習(xí)框架運(yùn)行平臺模型。將展示如何從Python和C++運(yùn)行推理。
打包和推斷接口還具有全面的文檔字符串,并提供了API的更詳細(xì)用法。
打包一個(gè)模型
包裝模型的第一步是定義一個(gè)“問題”(例如,2d對象檢測)。
“問題”由四個(gè)部分組成: 輸入規(guī)格
指定輸入張量的名稱、數(shù)據(jù)類型和形狀的dict列表
輸出規(guī)格
指定輸出張量的名稱、數(shù)據(jù)類型和形狀的dict列表
測試輸入數(shù)據(jù)(可選)
如果提供了,將在打包后立即運(yùn)行推斷,以驗(yàn)證模型打包是否正確。如果提供了測試輸出數(shù)據(jù),則必須提供
測試輸出數(shù)據(jù)(可選)
如果提供,將用測試輸入數(shù)據(jù)測試推理輸出是否與測試輸出數(shù)據(jù)匹配。
張量的形狀可以不包含任何值,在這種情況下,任何值都是可接受的。也可以在這些形狀定義中使用“符號”。該符號的每個(gè)實(shí)例必須在運(yùn)行時(shí)解析為相同的值。例如,加法模型的問題定義:
INPUT_SPEC = [
# A one dimensional tensor of any size with dtype float32{"name": "x", "dtype": "float32", "shape": ("num_inputs",)},# A one dimensional tensor of the same size with dtype float32{"name": "y", "dtype": "float32", "shape": ("num_inputs",)},
]
OUTPUT_SPEC = [
# The sum of the two tensors{
"name": "out", "dtype": "float32", "shape": (None,)},
]
TEST_INPUT_DATA = {
"x": np.arange(5, dtype=np.float32),"y": np.arange(5, dtype=np.float32),
}
TEST_EXPECTED_OUT = {
"out": np.arange(5) + np.arange(5)
}
x和y形狀的符號num_inputs在運(yùn)行時(shí)必須解析為相同的值。
現(xiàn)在已經(jīng)定義了一個(gè)問題,將看到如何在每個(gè)當(dāng)前支持的DL框架中打包一個(gè)模型。 TensorFlow
有兩種方法可以打包TensorFlow模型。一個(gè)是帶GraphDef的,另一個(gè)是帶到凍結(jié)圖的路徑的。這兩種方法都需要一個(gè)node_name_mapping,該映射將問題定義(見上文)中的張量名稱映射到張量流圖中的節(jié)點(diǎn)。
圖表
如果有一個(gè)返回GraphDef的函數(shù):
import tensorflow as tf
def create_tf_addition_model():
"""A simple addition model"""g = tf.Graph()with g.as_default():with tf.name_scope("some_namespace"):x = tf.placeholder(tf.float32, name="in_x")y = tf.placeholder(tf.float32, name="in_y")out = tf.add(x, y, name="out")
return g.as_graph_def()
可以將模型打包如下:
from neuropod.packagers import create_tensorflow_neuropod
create_tensorflow_neuropod(
neuropod_path=neuropod_path,model_name="addition_model",graph_def=create_tf_addition_model(),node_name_mapping={"x": "some_namespace/in_x:0","y": "some_namespace/in_y:0","out": "some_namespace/out:0",},input_spec=addition_problem_definition.INPUT_SPEC,output_spec=addition_problem_definition.OUTPUT_SPEC,test_input_data=addition_problem_definition.TEST_INPUT_DATA,test_expected_out=addition_problem_definition.TEST_EXPECTED_OUT,
)
提示
create_tensorflow_neuropod在創(chuàng)建之后立即使用測試數(shù)據(jù)運(yùn)行推斷。如果模型輸出與預(yù)期輸出不匹配,則引發(fā)ValueError。
凍結(jié)圖表的路徑
已經(jīng)有一個(gè)凍結(jié)的圖形,則可以將模型打包如下:
from neuropod.packagers import create_tensorflow_neuropod
create_tensorflow_neuropod(
neuropod_path=neuropod_path,model_name="addition_model",frozen_graph_path="/path/to/my/frozen.graph",node_name_mapping={"x": "some_namespace/in_x:0","y": "some_namespace/in_y:0","out": "some_namespace/out:0",},input_spec=addition_problem_definition.INPUT_SPEC,output_spec=addition_problem_definition.OUTPUT_SPEC,test_input_data=addition_problem_definition.TEST_INPUT_DATA,test_expected_out=addition_problem_definition.TEST_EXPECTED_OUT,
)
提示
create_tensorflow_neuropod在創(chuàng)建之后立即使用測試數(shù)據(jù)運(yùn)行推斷。如果模型輸出與預(yù)期輸出不匹配,則引發(fā)ValueError。
PyTorch
提示
打包PyTorch模型有點(diǎn)復(fù)雜,因?yàn)檫\(yùn)行網(wǎng)絡(luò)需要python代碼和權(quán)重。
如果可能,建議將模型轉(zhuǎn)換為TorchScript。
為了創(chuàng)建Pythorch 包,需要遵循以下幾條準(zhǔn)則:
只要運(yùn)行時(shí)環(huán)境安裝了包,絕對導(dǎo)入(例如導(dǎo)入torch)就可以。
對于Python 3,包中的所有其他導(dǎo)入都必須是相對的 與TensorFlow/TorchScript/Keras包相比,這種類型的包的靈活性稍低,因?yàn)榻^對導(dǎo)入引入了對運(yùn)行時(shí)環(huán)境的依賴。這將在將來的版本中得到改進(jìn)。
假設(shè)的加法模型是這樣的(存儲在/my/model/code/dir/main.py):
import torch
import torch.nn as nn
class AdditionModel(nn.Module):
def forward(self, x, y):
return {"out": x + y}
def get_model(data_root):
return AdditionModel()
為了打包,需要4樣?xùn)|西:
要存儲的任何數(shù)據(jù)的路徑(例如,模型權(quán)重)
代碼的python_root的路徑以及要打包的python_root中任何dir的相對路徑
返回給定打包數(shù)據(jù)路徑的模型的入口點(diǎn)函數(shù)。
模型的依賴關(guān)系。這些應(yīng)該是python包。
提示
有關(guān)每個(gè)參數(shù)的詳細(xì)說明,請參閱create_pytorch_eminod的API文檔
對于模型:
不需要存儲任何數(shù)據(jù)(因?yàn)槲覀兊哪P蜎]有權(quán)重)
python根目錄是/my/model/code/dir,希望將所有代碼存儲在其中
entrypoint函數(shù)是get_模型,entrypoint_包是main(因?yàn)榇a在主.py在python根目錄中) 這意味著:
from neuropod.packagers import create_pytorch_neuropod
create_pytorch_neuropod(
neuropod_path=neuropod_path,model_name="addition_model",data_paths=[],code_path_spec=[{"python_root": '/my/model/code/dir',"dirs_to_package": ["" # Package
everything in the python_root
],}],entrypoint_package="main",entrypoint="get_model",input_spec=addition_problem_definition.INPUT_SPEC,output_spec=addition_problem_definition.OUTPUT_SPEC,test_input_data=addition_problem_definition.TEST_INPUT_DATA,test_expected_out=addition_problem_definition.TEST_EXPECTED_OUT,
)
提示
create_pytorch_neuropod創(chuàng)建后立即使用測試數(shù)據(jù)運(yùn)行推斷。如果模型輸出與預(yù)期輸出不匹配,則引發(fā)ValueError。
TorchScript
TorchScript比PyTorch更容易打包(因?yàn)椴恍枰鎯θ魏蝡ython代碼)。
如果有一個(gè)附加模型,它看起來像:
import torch
class AdditionModel(torch.jit.ScriptModule):
"""A simple addition model"""@torch.jit.script_methoddef forward(self, x, y):return {"out": x + y}
可以通過運(yùn)行以下命令對其進(jìn)行打包:
from neuropod.packagers import create_torchscript_neuropod
create_torchscript_neuropod(
neuropod_path=neuropod_path,model_name="addition_model",module=AdditionModel(),input_spec=addition_problem_definition.INPUT_SPEC,output_spec=addition_problem_definition.OUTPUT_SPEC,test_input_data=addition_problem_definition.TEST_INPUT_DATA,
test_expected_out=addition_problem_definition.TEST_EXPECTED_OUT,
提示
create_torchscript_neuropod在創(chuàng)建后立即使用測試數(shù)據(jù)運(yùn)行推斷。如果模型輸出與預(yù)期輸出不匹配,則引發(fā)ValueError。
Keras
如果有一個(gè)Keras附加模型,它看起來像:
def create_keras_addition_model():
"""A simple addition model"""x = Input(batch_shape=(None,), name="x")y = Input(batch_shape=(None,), name="y")out = Add(name="out")([x, y])model = Model(inputs=[x, y], outputs=[out])return model
可以通過運(yùn)行:
from neuropod.packagers import create_keras_neuropod
create_keras_neuropod(
neuropod_path=neuropod_path,model_name="addition_model",sess=tf.keras.backend.get_session(),model=create_keras_addition_model(),input_spec=addition_problem_definition.INPUT_SPEC,output_spec=addition_problem_definition.OUTPUT_SPEC,test_input_data=addition_problem_definition.TEST_INPUT_DATA,test_expected_out=addition_problem_definition.TEST_EXPECTED_OUT,
)
提示
create_keras_neurood在創(chuàng)建之后立即使用測試數(shù)據(jù)運(yùn)行推斷。如果模型輸出與預(yù)期輸出不匹配,則引發(fā)ValueError。
Python
打包aribtrary Python代碼具有與上面打包PyTorch相同的接口。
例如,請參見上面的PyTorch部分,并使用create_python_neurood而不是create_PyTorch_neurood
運(yùn)行推理
不管底層的DL框架是什么,推理都是完全相同的
來自Python
x = np.array([1, 2, 3, 4])
y = np.array([5, 6, 7, 8])
with load_neuropod(ADDITION_MODEL_PATH) as neuropod:
results = neuropod.infer({“x”: x, “y”: y})
array([6, 8, 10, 12])
print results[“out”]
From C++
#include “neuropod/neuropod.hh”
int main()
{
const std::vector<int64_t> shape = {4};// To show two different ways of adding data, one of our inputs is an
array
// and the other is a vector.const float[]
x_data = {1, 2, 3, 4};
const std::vector<float> y_data = {5, 6, 7, 8};// Load the neuropodNeuropod neuropod(ADDITION_MODEL_PATH);// Add the input data using two different signatures of `copy_from`// (one with a pointer and size, one with a vector)auto x_tensor = neuropod.allocate_tensor<float>(shape);x_tensor->copy_from(x_data, 4);auto y_tensor = neuropod.allocate_tensor<float>(shape);y_tensor->copy_from(y_data);// Run inferenceconst auto output_data = neuropod.infer({{"x", x_tensor},{"y", y_tensor}});const auto out_tensor = output_data->at("out");// {6, 8, 10, 12}const auto out_vector = out_tensor->as_typed_tensor<float>()->get_data_as_vector();// {4}const auto out_shape = out_tensor->get_dims();
}
提示
這顯示了C++ API的基本用法。為了更靈活和高效地使用內(nèi)存,請參閱C++ API文檔。
附錄
問題定義示例
二維目標(biāo)檢測的問題定義可能如下所示:
INPUT_SPEC = [
# BGR image{"name": "image", "dtype": "uint8", "shape": (1200, 1920, 3)},
]
OUTPUT_SPEC = [
# shape: (num_detections, 4): (xmin, ymin, xmax, ymax)# These values are in units of pixels. The origin is the top left corner# with positive X to the right and positive Y towards the bottom of the
image
{"name": "boxes", "dtype": "float32", "shape": ("num_detections", 4)},# The list of classes that the network can output# This must be some subset of ['vehicle', 'person', 'motorcycle',
‘bicycle’]
{"name": "supported_object_classes", "dtype": "string", "shape": ("num_classes",)},# The probability of each class for each detection# These should all be floats between 0 and 1{"name": "object_class_probability", "dtype": "float32", "shape": ("num_detections", "num_classes")},
]
總結(jié)
以上是生活随笔為你收集整理的构建深度学习框架运行平台的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: GitHub上YOLOv5开源代码的训练
- 下一篇: 国内操作系统OS分析(上)