분산·연합학습 개발도구 통합

신경망 하단 일부를 임베디드 단말로 분리해 학습·추론하는 구조를 오픈소스 개발 프레임워크에 통합하고, 분산 연산 성능을 측정했습니다.

연표로 돌아가기
문제
발주 측이 먼저 만들어 둔 흉부 영상 진단 데모(첫 입력층을 분리한 구조)를 출발점으로 ONNX 변환·분할, 시험 앱, 통신 모듈, 프레임워크 통합까지 넓혀야 했습니다. 제공받은 학습 모델 파일에는 일부 층의 합성곱 가중치가 빠져 있었습니다.
담당
단말 연산량 측정 응용(명령줄·그래픽 두 구현)과 중간 텐서 송수신 모듈, 프레임워크의 분류기 학습 모듈 통합, 시험 절차서 작성을 맡았습니다.
설계 판단
분할 지점은 '첫 합성곱과 풀링까지'와 '첫 밀집 블록과 전이층까지' 두 안을 견줬고, 두 안의 중간 텐서 크기가 4배 차이여서 앞쪽 안으로 진행했습니다. 전송 값은 16비트 부동소수점으로 줄여 전송량을 절반으로 했습니다.
검증 기준
분할한 모델을 원래 모델과 같은 시험 이미지로 돌려 분류 결과와 점수가 일치하는지 비교했고, 검증 서버가 단말이 보낸 중간 텐서와 서버가 직접 계산한 텐서를 대조하도록 만들었습니다. 측정은 GPU 예열 구간을 나눠 첫 구간을 뺀 평균으로 냈습니다. 수치는 싣지 않습니다.
결과 범위
단말 연산량 측정과 분산 실행 시험평가까지 수행했고, 이후 다른 엣지 장치로 같은 측정 체계를 옮겨 재수행했습니다. 제공받은 모델의 가중치 일부가 빠져 있어 시험은 구조와 연산량 확인에 한정해 썼습니다.

신경망의 아래쪽 일부 층만 임베디드 단말에서 계산하고 나머지는 서버가 맡는 구조를, 오픈소스 통합개발 프레임워크에 모듈로 붙였습니다.

모델 분할은 학습·추론에 쓰는 신경망을 앞부분과 뒷부분으로 자르는 것입니다. 단말은 앞부분까지만 계산해 그 결과인 중간 텐서를 보내고, 서버가 나머지 층과 분류기를 이어서 돌립니다. 어디서 자르느냐로 단말이 감당하는 연산량과 오가는 자료량이 함께 정해집니다.

이 구조의 이점은 원본이 단말을 벗어나지 않는다는 데 있습니다. 선 위로 나가는 값은 여러 층의 비선형 변환을 거친 중간 텐서뿐이라, 받은 쪽이 원본 영상으로 되돌리는 역변환이 정의되지 않습니다. 열쇠를 주고받고 푸는 절차가 없는데도 필요한 정보만 건너가는 셈이라, 암호화 통신과 성격이 비슷하면서 복호화 비용은 들지 않습니다.

다만 앞부분 가중치를 가진 쪽이라면 근사 복원을 시도할 수 있으므로, 분할 지점을 깊게 둘수록 되돌리기 어려워진다는 점을 함께 봅니다. 실제로는 개인정보가 실린 영상을 서버로 모으지 않아도 되는 점, 단말 성능에 맞춰 분할 지점을 옮겨 연산량과 대역폭을 조절할 수 있는 점이 도입 이유였습니다.

단말과 PC, 서버 사이에 중간 텐서를 주고받는 통신과 제어 경로를 만들고, 배포는 컨테이너 오브젝트 기술로 자동화했습니다.

시험평가에서는 자동 생성된 신경망을 분산 실행하며 단말이 감당하는 연산량을 측정했고, 이후 다른 엣지 장치로 같은 측정 체계를 옮겨 재수행했습니다.

분할 지점 후보를 견줄 때는 단말 입력단 후보로 DenseNet 계열과 ResNet 계열의 첫 합성곱도 비교해, DenseNet 쪽이 출력 값 수는 4배, 입력단 연산량은 약 5배 크다는 점을 확인했습니다. 분할한 모델은 원래 모델과 같은 시험 이미지로 돌려 분류 결과와 점수가 일치하는지 비교했고, ResNet 계열도 전체 모델과 분할 모델의 출력이 시험 데이터에서 모두 일치함을 확인했습니다. PC 쪽 검증 서버는 단말이 보낸 중간 텐서와, 같은 이미지를 서버에서 직접 앞부분 모델로 계산한 텐서를 비교하고 NaN 유무를 검사하며, 불일치가 나오면 채널 단위로 기록하도록 만들었습니다.

중간 텐서는 32바이트 헤더와 1024바이트 단위 패킷으로 나눠 보내고 패킷마다 순번을 붙여, 수신 쪽이 한 패킷씩 확인 응답하는 방식으로 순서 어긋남을 잡았습니다. 값 형식은 7월 초안의 32비트에서 16비트 부동소수점으로 줄였습니다. PC 쪽 서버는 단말 접속마다 스레드를 열어 여러 단말의 요청을 함께 받고, 단말이 5초마다 접속 확인 패킷을 보내 응답이 없으면 재시도한 뒤 연결을 닫도록 했습니다.

연산량 측정 응용은 TensorRT 엔진을 직렬화해 한 장씩 돌리는 C++ 명령줄 구현과 PyTorch 로 묶음 단위 처리량을 재는 PyQt5 그래픽 구현의 두 가지로 만들었고, 시험평가는 그래픽 구현으로 진행했으며 단말에서 부팅과 함께 전체 화면으로 자동 실행되도록 서비스로 등록했습니다. 측정은 GPU 예열 구간(약 10초)과 본 측정(약 1분)으로 나누고 1초 단위 평균 처리량을 그래프로 쌓아, 첫 구간을 뺀 평균을 최종값으로 표시합니다. 지원 환경은 JetPack 과 CUDA 버전이 다른 두 스택으로 문서화했습니다.

프레임워크에는 ResNet 분류기 학습 모듈을 시작·중지·상태 조회 HTTP 인터페이스를 가진 컨테이너로 추가했습니다. 학습은 별도 프로세스로 돌려 완료와 실패를 프로젝트 관리자 서비스에 보고하고 산출물(신경망 정보 YAML, 추론 코드, 가중치)을 배포 단계가 가져가게 했으며, 미리 받아 둔 가중치가 있으면 훈련 결과 대신 그것을 배포 산출물로 씁니다. 제공받은 학습 모델 파일은 일부 층의 합성곱 가중치가 빠져 있어, 시험에서는 그 층을 임의 값으로 채우거나 해당 항목을 제외하고 불러와 구조와 연산량 확인에 한정해 썼습니다.

시험 절차서는 2023년 10월 하순에 작성했고, 단말 세 대를 공유기로 묶어 원격 화면과 터미널로 시험 앱을 구동하는 시험 구성도를 11월에 작성했습니다. 2025년에 재구축한 측정 도구는 묶음 크기·분석 시간·예열 횟수를 설정 파일로 빼고, 입력 읽기 시간을 측정에서 빼려고 데이터를 메모리에 미리 올렸습니다.

그림

왼쪽 단말이 원본 프레임에서 앞부분 층까지 계산해 중간 텐서만 오른쪽 서버로 보내고, 원본을 되돌리는 경로는 없다고 표시한 구조 그림왼쪽 단말이 원본 프레임에서 앞부분 층까지 계산해 중간 텐서만 오른쪽 서버로 보내고, 원본을 되돌리는 경로는 없다고 표시한 구조 그림
분할 지점 앞뒤로 나뉜 계산과, 선 위로 나가는 값. 아래는 같은 프레임이 단말 안에서와 전송 구간에서 어떻게 다른지 견준 것입니다.

화면

단말의 초당 연산량을 실시간 선 그래프로 보여 주고 아래에 층별 표가 있는 측정 응용 화면단말의 초당 연산량을 실시간 선 그래프로 보여 주고 아래에 층별 표가 있는 측정 응용 화면
단말 연산량 측정 응용. 분할 지점을 바꿔 가며 단말이 감당하는 연산량을 기록합니다.

더미 데이터로 채운 그림입니다. 실제 화면과 배치·문구가 다를 수 있습니다.

구조와 흐름

분할 추론 구조

임베디드 단말 (Jetson)추론 PC오픈소스 개발 프레임워크중간 텐서자체 TCP 규약회신배포입력 텐서1×256×256신경망 앞부분첫 풀링까지나머지 층 + 분류기진단 결과 · 점수분류기 학습 모듈Kubernetes 배포
단말은 첫 풀링까지만 계산하고 중간 텐서를 보냅니다. 고정 헤더와 부동소수점 버퍼로 된 자체 규약입니다.
PyTorchKubernetesDockerJetson분산 학습