VectorBlox vnnx_tflite.py: TFLite → VNNX 변환 파이프라인 분석
Published:
vnnx_tflite.py는 TensorFlow Lite 모델을 VectorBlox의 VNNX 형식으로 변환하는 핵심 모듈입니다.
1. 전체 플로우 개요
먼저, TFLite → JSON 서브그래프 → VNNX 로 이어지는 전체 흐름을 간단한 다이어그램으로 정리할 수 있습니다.
flowchart TD
A[TFLite 모델] --> B[lite_flow.py]
B --> C[tflite_to_vnnx 함수]
C --> D[generate_split_graphs]
D --> E[JSON 서브그래프 생성]
E --> F[vnnx_tflite.py]
F --> G[generate_vnnx_from_json_subgraphs]
G --> H[populate_nodes]
G --> I[메모리 할당]
G --> J[바이너리 생성]
J --> K[VNNX 파일]
subgraph "vnnx_tflite.py 주요 기능"
L["모델 파싱<br/>get_graph_activations"]
M["노드 변환<br/>populate_nodes"]
N["메모리 관리<br/>update_offsets"]
O["시뮬레이션 검증<br/>vbx.sim.Model"]
end
F --> L
F --> M
F --> N
F --> O
위 플로우에서 lite_flow.py는 외부 API 역할을 하고, 실제 VNNX 바이너리 생성 로직은 대부분 vnnx_tflite.py에 구현되어 있습니다.
2. 주요 역할 정리
2.1 모델 변환 엔진: generate_vnnx_from_json_subgraphs
generate_vnnx_from_json_subgraphs 함수는 JSON 형태로 표현된 TFLite 서브그래프들을 입력으로 받아, 최종 VNNX 바이너리 바이트 스트림을 생성합니다.
- JSON 서브그래프 목록과 size configuration(V250/V500/V1000 등)을 받아서,
- 각 노드를 VNNX 내부 노드 포맷으로 변환하고,
- 텐서/서브노드/그래프 메타데이터를 모두 직렬화하여 하나의 바이너리(
data)로 합칩니다.
이때, 내부적으로는 Nodes 리스트와 vnnx_graph 메타 객체를 유지하면서, 그래프 구조와 텐서 정보를 함께 관리합니다.
2.2 연산자 처리: TFLite → VNNX
vnnx_tflite.py는 다양한 TensorFlow Lite 연산자를 VNNX 내부 표현으로 매핑합니다.
- 예:
CONV_2D,DEPTHWISE_CONV_2D,MAX_POOL_2D,ADD,MUL,RELU,SOFTMAX등 - 각 연산자는
Subnode구조체에 매핑되며, 커널 크기, stride, padding, activation 등 옵션이 세부적으로 저장됩니다.
예를 들어, MAX_POOL_2D의 경우 SAME padding일 때 필요한 경우 자동으로 PAD 서브노드를 앞에 삽입하여, TFLite의 padding 동작을 정확히 재현합니다.
elif subcode == 'MAX_POOL_2D':
sn.type = BuiltinOperator.MAX_POOL_2D
sn.kernel_shape = [opts['filter_height'], opts['filter_width']]
sn.strides = [opts['stride_h'], opts['stride_w']]
...
if opts['padding'] == "SAME":
# 입력/출력 크기와 stride, kernel을 바탕으로 pad 크기 계산 후
# 필요하면 PAD 서브노드 삽입
pad_sn = Subnode()
pad_sn.type = BuiltinOperator.PAD
...
subnode_array.append(pad_sn)
subnode_array.append(sn)
이처럼, TFLite의 high-level 연산 의미를 VNNX 하드웨어 친화적인 형태로 재구성하는 것이 populate_nodes 계열 로직의 핵심입니다.
2.3 메모리 관리: update_offsets
VNNX는 하나의 큰 바이너리 안에 그래프/노드/서브노드/텐서/가중치/리플레이 버퍼를 모두 포함합니다.
update_offsets 함수는 이 모든 구조체의 메모리 오프셋을 일관되게 재계산하는 역할을 합니다.
- 각 노드/서브노드/텐서의 배열 크기를 기반으로,
node_offset,subnode_offset,tensor_offset,weights_offset를 순차적으로 할당
weights_offset는 16바이트 정렬(align) 규칙을 만족하도록 조정vnnx_graph와 각Node/Subnode/Tensor에 대해update_offsets를 호출해 내부 버퍼 주소를 갱신- 최종적으로 직렬화된
node_data,subnode_data,tensor_data와 정렬 패딩(align)을 반환합니다.
def update_offsets(vnnx_graph, Nodes, weights_offset=None, min_addr=None):
...
if weights_offset is None:
weights_offset = tensor_offset + num_tensors*tensor_size
# align weights_offset
if weights_offset % 16 != 0:
align_len = 16 - (weights_offset % 16)
align = [bytearray(align_len)]
weights_offset += align_len
vnnx_graph.update_offsets(weights_offset, min_addr)
for n in Nodes:
n.update_offsets(weights_offset, min_addr)
...
return node_data, subnode_data, tensor_data, align
이 과정 덕분에, VNNX 런타임은 고정된 오프셋 정보만으로 모든 텐서와 가중치 위치를 찾을 수 있습니다.
3. 정리 및 앞으로의 계획
vnnx_tflite.py는:- TFLite 모델을 VNNX로 변환하는 모델 컴파일러의 핵심 구현체이고,
- 연산자 매핑, 메모리 레이아웃 계산, 시뮬레이션 검증까지 모두 관장합니다.
- 현재 공개된
vnnx_tflite.py는 최신 AI 모델(예: 최신 YOLO/Segmentation/Transformer 계열)의 모든 패턴을 완전히 커버하지 못하는 한계가 있습니다. - 이를 해결하기 위해, 실제 SDK 내부 코드를 분석(“리버싱”)하여 최신 연산자 조합과 네트워크 패턴을 지원하도록 연산자 매핑 로직과 메모리 레이아웃을 개선하여, 최신 모델에서도 안정적으로 동작하도록 수정한 커스텀 버전을 작성했습니다.
Language: English
