본문으로 건너뛰기

그래프 내에 모델을 포함하기

필드
범주그래프 및 파이프라인
난이도고급
예상 소요 시간20-25 minutes
레이블graph, hybrid, model, mpk

제3장에서는 단순한 입력/출력 노드를 사용하여 그래프를 구축했습니다. 제1장에서는 모델을 독립적인 객체로 실행했습니다. 이 장에서는 이 두 가지를 결합합니다. Model 자체는 그래프와 호환되는 노드이므로 다른 모든 스테이지와 마찬가지로 공개 Graph에 포함할 수 있습니다. 이것이 바로 그래프 수준 제어(다중 입력, 명명된 출력, 사용자 지정 라우팅 등)가 필요할 때, 모델 실행을 재사용 가능한 단일 조각으로 취급하면서 사용할 수 있는 브리지 패턴입니다.

핵심 아이디어는 저수준 런타임 그래프, StageModelExecutorOptions 또는 내부 노드 ID를 절대 수정하지 않는다는 것입니다. 모델을 graph.add(...)에 전달하면 NEAT가 해당 조각(필요에 따라 전처리/추론/후처리)을 빌드 시간에 올바른 내부 실행 계획으로 변환합니다. 마지막에는 모델을 공개 그래프에 포함하고, 포함된 토폴로지를 출력하고, 모델의 출력 카디널리티를 다시 읽을 수 있습니다.

둘러보기

모델 로드

구성은 컴파일된 아카이브를 로드하고 제1장과 마찬가지로 실행을 위해 준비합니다. 여기서는 옵션 객체 없이 경로만 사용합니다. 왜냐하면 이 장은 전처리보다는 구성에 관한 것이기 때문입니다. 결과 Model은 이제 그래프 레이어가 이해할 수 있는 객체입니다.

tutorials/014_embed_model_inside_graph/embed_model_inside_graph.cpp
simaai::neat::Model model(model_path);

모델을 그래프에 포함

이것이 이 장의 핵심입니다. 새 Graph에 세 개의 노드가 순서대로 추가됩니다. 명명된 입력 경계, 모델 자체, 명명된 출력 경계입니다. Model은 그래프와 호환되므로 add(model)은 전체 모델 경로를 단일 조각으로 추가합니다. 특별한 API가 없고 런타임에 직접 접근하지 않습니다. graph.describe()를 출력하면 포함된 토폴로지가 표시되므로 명명된 경계 사이에 모델이 올바르게 포함되었는지 확인할 수 있습니다.

경계는 simaai::neat::nodes::Input("image")nodes::Output("result")에서 가져옵니다. 모델은 graph.add(model)에 직접 전달됩니다.

tutorials/014_embed_model_inside_graph/embed_model_inside_graph.cpp
simaai::neat::Graph graph;
graph.add(simaai::neat::nodes::Input("image"));
graph.add(model);
graph.add(simaai::neat::nodes::Output("result"));

std::cout << graph.describe() << "\n";

모델 검사

마지막으로 모델 조각이 실제로 어떤 역할을 하는지 확인합니다. 이를 통해 모델이 올바르게 로드되었는지 확인하고 그래프가 다운스트림에서 생성할 출력 토폴로지를 확인할 수 있습니다.

model.info()는 정보 구조체를 반환합니다. model_nameoutput_topology.physical_outputslogical_outputs를 출력하여 모델의 출력 연결이 명확하게 표시되도록 합니다.

tutorials/014_embed_model_inside_graph/embed_model_inside_graph.cpp
const auto info = model.info();
std::cout << "model=" << (info.model_name.empty() ? "<unnamed>" : info.model_name)
<< " physical_outputs=" << info.output_topology.physical_outputs
<< " logical_outputs=" << info.output_topology.logical_outputs << "\n";

실행

이 장에서는 모델 아카이브(yolo_v8s)가 필요합니다. Neat 설치 루트( share/lib/가 포함된 디렉터리)에서 PythonC++(미리 빌드된 버전) 명령을 실행하고, 리포지토리 루트에서 소스에서 빌드 명령을 실행합니다.

C++ (prebuilt):

./lib/sima-neat/tutorials/tutorial_014_embed_model_inside_graph \
--model /tmp/yolo_v8s.tar.gz

C++ (build from source):

./build.sh --target tutorial_014_embed_model_inside_graph
./build/tutorials-standalone/tutorial_014_embed_model_inside_graph \
--model /tmp/yolo_v8s.tar.gz

예상 출력(C++ 빌드도 먼저 구성된 그래프 설명을 출력합니다):

model=yolo_v8s physical_outputs=1 logical_outputs=1
[OK] 014_embed_model_inside_graph

(Python 빌드는 그래프 설명을 출력한 다음 model fragment added to public Graph를 출력합니다.)

사용자 지정 CMakeLists.txt를 사용하여 이 장의 C++ 소스를 자체 프로젝트에 통합하려면(추가 폴더가 필요하지 않음) 랜딩 페이지의 튜토리얼 실행 방법을 참조하십시오.

전체 소스

전체 소스 프로그램 표시
tutorials/014_embed_model_inside_graph/embed_model_inside_graph.cpp
// Hybrid graph composition: a Model is added directly to a public Graph.
//
// Usage:
// tutorial_014_embed_model_inside_graph --model /path/to/model.tar.gz

#include "neat.h"

#include <iostream>
#include <string>

namespace {

bool get_arg(int argc, char** argv, const std::string& key, std::string& out) {
for (int i = 1; i + 1 < argc; ++i) {
if (key == argv[i]) {
out = argv[i + 1];
return true;
}
}
return false;
}

} // namespace

int main(int argc, char** argv) {
try {
std::string model_path;
if (!get_arg(argc, argv, "--model", model_path)) {
std::cerr << "Usage: tutorial_014_embed_model_inside_graph --model <path>\n";
return 1;
}

simaai::neat::Model model(model_path);

// CORE LOGIC
// Model is now a Graph-compatible object. `graph.add(model)` appends the
// model route fragment (preprocess/inference/postprocess as needed) without
// exposing the internal low-level runtime graph.
simaai::neat::Graph graph;
graph.add(simaai::neat::nodes::Input("image"));
graph.add(model);
graph.add(simaai::neat::nodes::Output("result"));

std::cout << graph.describe() << "\n";

const auto info = model.info();
std::cout << "model=" << (info.model_name.empty() ? "<unnamed>" : info.model_name)
<< " physical_outputs=" << info.output_topology.physical_outputs
<< " logical_outputs=" << info.output_topology.logical_outputs << "\n";
std::cout << "[OK] 014_embed_model_inside_graph\n";
return 0;
} catch (const std::exception& e) {
std::cerr << "[FAIL] " << e.what() << "\n";
return 1;
}
}

소스