fos-blog/study
01 / 홈02 / 카테고리03 / 시리즈
01 / 홈02 / 카테고리03 / 시리즈

카테고리

  • AI 페이지로 이동
    • RAG 페이지로 이동
    • langgraph 페이지로 이동
    • agents.md
    • BMAD Method — AI 에이전트로 애자일 개발하는 방법론
    • Claude Code의 Skill 시스템 - 개발자를 위한 AI 자동화의 새로운 차원
    • Claude Code를 5주 더 쓴 결과 — 스킬·CLAUDE.md를 키워가는 방식
    • Claude Code를 11일 동안 쓴 결과 — 데이터로 본 나의 사용 패턴
    • Claude Code 멀티 에이전트 — Teams
    • AI 에이전트와 디자인의 새 컨벤션 — DESIGN.md, Google Stitch, Claude Design
    • Docling — IBM Research 의 문서 파싱 toolkit 상세 정리
    • 하네스 엔지니어링 실전 — 4인 에이전트 팀으로 코딩 파이프라인 구축하기
    • 하네스 엔지니어링 — 오래 실행되는 AI 에이전트를 위한 설계
    • 멀티모달 LLM (Multimodal Large Language Model)
    • AI 에이전트와 함께 MVP 만들기 — dooray-cli 사례
  • ai 페이지로 이동
    • agent 페이지로 이동
  • algorithm 페이지로 이동
    • live-coding 페이지로 이동
    • 분산 계산을 위한 알고리즘
  • apartment 페이지로 이동
    • 구리 럭키아파트 24평 인테리어 레퍼런스 모음
  • architecture 페이지로 이동
    • [초안] 시니어 백엔드를 위한 API 설계 실전 스터디 팩 — REST · 멱등성 · 페이지네이션 · 버전 전략
    • [초안] API Versioning과 Backward Compatibility: 시니어 백엔드 관점 정리
    • 캐시 설계 전략 총정리
    • [초안] CJ푸드빌 디지털 채널 면접: 슬롯 도메인 경험을 커머스 도메인 설계 능력으로 번역하기
    • [초안] 커머스 Spring 서비스에 Clean/Hexagonal Architecture를 실용적으로 적용하기
    • [초안] 커머스 도메인 모델링: 주문·재고·노출의 세 축을 분리해서 설계하기
    • 커머스 주문 상태와 데이터 정합성 기본기 — CJ푸드빌 면접 대비
    • [초안] 쿠폰/프로모션 동시성과 정합성 기본기 — 선착순·중복 사용 방지·발급/사용/복구
    • [초안] DDD와 도메인 모델링: 시니어 백엔드 관점의 전술/전략 패턴 실전 가이드
    • [초안] Decorator & Chain of Responsibility — 행동을 체인으로 조립하는 두 가지 방식
    • 디자인 패턴
    • [초안] 분산 아키텍처 완전 정복: Java 백엔드 시니어 인터뷰 대비 실전 가이드
    • [초안] 분산 트랜잭션과 Outbox 패턴 — 왜 2PC를 피하고 어떻게 대신할 것인가
    • 분산 트랜잭션
    • [초안] e-Commerce 주문·결제 도메인 모델링: 상태머신, 멱등성, Outbox/Saga 실전 정리
    • [초안] F&B 쿠폰·프로모션·멤버십·포인트 설계
    • [초안] F&B · e-Commerce 디지털 채널 도메인 한 장 정리 — CJ푸드빌 디지털 채널 백엔드 면접 대비
    • [초안] F&B 주문/매장/픽업 상태머신 설계 — CJ푸드빌 디지털 채널 백엔드 관점
    • [초안] F&B 이커머스 결제·환불·정산 운영 가이드
    • [초안] Hexagonal / Clean Architecture를 Spring 백엔드에 적용하기
    • [초안] 대규모 커머스 트래픽 처리 패턴 — 1,600만 고객과 올영세일을 버티는 설계
    • [초안] 레거시 JSP/jQuery 화면과 신규 API가 공존하는 백엔드 운영 전략
    • [초안] MSA 서비스 간 통신: Redis [Cache-Aside](../database/redis/cache-aside.md) × Kafka 이벤트 하이브리드 설계
    • [초안] Observability 입문: 시니어 백엔드가 장애를 탐지하고 대응하는 방식
    • [초안] Outbox / Inbox Pattern 심화 — 분산 메시징의 정합성 문제를 DB 트랜잭션으로 풀어내기
    • [초안] 결제 도메인 멱등성과 트랜잭션 재시도 기본기
    • [초안] 시니어 백엔드를 위한 Resilience 패턴 실전 가이드 — Timeout, Retry, Circuit Breaker, Bulkhead, Backpressure
    • [초안] REST API 버저닝과 모바일 앱 하위 호환성 — CJ푸드빌 디지털 채널 백엔드 관점
    • [초안] Spring Batch vs Event-Driven — 같은 비동기처럼 보이지만 전혀 다른 두 패러다임
    • [초안] Strategy Pattern — 분기문을 없애는 설계, 시니어 백엔드 인터뷰 핵심 패턴
    • [초안] 시니어 백엔드를 위한 시스템 설계 입문 스터디 팩
    • [초안] 템플릿 메서드 패턴 - 백엔드 처리 골격을 강제하는 가장 오래되고 가장 위험한 패턴
    • [초안] 대규모 트래픽 중 무중단 마이그레이션 — Feature Flag + Shadow Mode 실전
  • database 페이지로 이동
    • mysql 페이지로 이동
    • opensearch 페이지로 이동
    • redis 페이지로 이동
    • 김영한의-실전-데이터베이스-설계 페이지로 이동
    • [초안] DB Connection Pool Saturation과 Thread Pool 격리
    • 커넥션 풀 크기는 얼마나 조정해야 할까?
    • 인덱스 - DB 성능 최적화의 핵심
    • [초안] JPA N+1과 커머스 조회 모델: 주문/메뉴/쿠폰 도메인에서 살아남기
    • [초안] MyBatis 기본기 — XML Mapper, resultMap, 동적 SQL, 운영 패턴 정리
    • [초안] MyBatis와 JPA/Hibernate 트레이드오프 — 레거시 백엔드를 다루는 시니어 관점
    • 역정규화 (Denormalization)
    • 데이터 베이스 정규화
  • devops 페이지로 이동
    • docker 페이지로 이동
    • k8s 페이지로 이동
    • k8s-in-action 페이지로 이동
    • observability 페이지로 이동
    • [초안] 커머스/F&B 채널 장애 첫 5분과 관측성 기본기
    • Envoy Proxy
    • [초안] F&B / e-Commerce 운영 장애 대응과 모니터링 — 백엔드 관점 정리
    • Graceful Shutdown
    • [초안] 시니어 백엔드를 위한 SLO와 Error Budget 기반 장애 대응
  • finance 페이지로 이동
    • industry-cycle 페이지로 이동
    • investing 페이지로 이동
  • http 페이지로 이동
    • HTTP Connection Pool
  • interview 페이지로 이동
    • [초안] AI 서비스 팀 경험 기반 시니어 백엔드 면접 질문 뱅크 — Spring Batch RAG / gRPC graceful shutdown / 전략 패턴 / 12일 AI 웹툰 MVP
    • [초안] 커머스/F&B 면접 답변집 — 슬롯 도메인 경험을 주문·결제·쿠폰·매장 설계로 매핑하기
    • [초안] F&B / e-Commerce 운영 모니터링과 장애 대응 인터뷰 정리
    • Observability — 면접 답변 프레임
    • [초안] 시니어 Java 백엔드 면접 마스터 플레이북 — 김병태
    • [초안] NSC 슬롯팀 경험 기반 질문 은행 — 도메인 모델링·동시성·성능·AI 협업
  • java 페이지로 이동
    • concurrency 페이지로 이동
    • jdbc 페이지로 이동
    • opentelemetry 페이지로 이동
    • spring 페이지로 이동
    • spring-batch 페이지로 이동
    • 더_자바_코드를_조작하는_다양한_방법 페이지로 이동
    • [초안] Java 동시성 락 정리 — 커머스 메뉴/프로모션 정책 캐시 갱신 관점
    • [초안] JVM 튜닝 실전: 메모리 구조부터 Virtual Threads, GC 튜닝, 프로파일링까지
    • Java의 로깅 환경
    • MDC (Mapped Diagnostic Context)
    • Java StampedLock — 읽기 폭주에도 쓰기가 밀리지 않는 락
    • Virtual Thread와 Project Loom
  • javascript 페이지로 이동
    • typescript 페이지로 이동
    • AbortController
    • Async Iterator와 제너레이터
    • CommonJS와 ECMAScript Modules
    • 제너레이터(Generator)
    • Http Client
    • Node 백엔드 운영 패턴 — Streams 백프레셔, pipe/pipeline, 멱등성 vs 분산 락
    • Node.js
    • npm vs pnpm — 어떤 기준으로 선택했나
    • `setImmediate()`
  • kafka 페이지로 이동
    • [초안] Kafka 기본 개념 — 토픽, 파티션, 오프셋, 복제
    • Kafka를 사용하여 **데이터 정합성**은 어떻게 유지해야 할까?
    • [초안] Kafka 실전 설계: 파티션 전략, 컨슈머 그룹, 전달 보장, 재시도, 순서 보장 트레이드오프
    • 메시지 전송 신뢰성
  • linux 페이지로 이동
    • fsync — 리눅스 파일 동기화 시스템 콜
    • tmux — Terminal Multiplexer
  • network 페이지로 이동
    • L2(스위치)와 L3(라우터)의 역할 차이
    • L4와 VIP(Virtual IP Address)
    • IP Subnet
  • python 페이지로 이동
    • Python async/await — CompletableFuture·Reactor 와 다른 점, 그리고 blocking I/O 함정
    • Python 의존성 관리 — Java Maven/Gradle 사용자가 만나는 첫 충격
    • FastAPI 기초 — Spring Boot 사용자가 빠르게 익히는 법
    • GPU·CUDA·MPS 기초 — 자바 백엔드 개발자가 처음 만나는 그림
    • Multi-process GPU 워크로드 — 자바 ThreadPool 사용자가 만나는 모델 차이
    • Java 개발자를 위한 Python 심화 — OOP·데코레이터·컨텍스트 매니저
    • PyTorch 기초 — 텐서, 디바이스, 그리고 모델 로딩이 무거운 이유
    • Java 개발자를 위한 Python 문법 핵심
    • ML 서비스 성능 분석 워크플로 — 자바 백엔드 트러블슈팅과 다른 점
    • OCR 동작 원리 — Layout · Text · Post-process 3단계
    • Python 서버의 RSS 가 안 줄어드는 이유 — gc.collect 의 한계와 malloc_trim
  • rabbitmq 페이지로 이동
    • [초안] RabbitMQ Basics — 실전 백엔드 관점에서 정리하는 메시지 브로커 기본기
    • [초안] RabbitMQ vs Kafka — 백엔드 메시징 선택 기준과 실전 운영 관점
  • security 페이지로 이동
    • [초안] 시니어 백엔드를 위한 보안 / 인증 스터디 팩 — Spring Security, JWT, OAuth2, OWASP Top 10
    • [초안] Spring Security 6.x OAuth2 + JWT 상용 인증 설계 — Grant 선택, Resource Server, Refresh Rotation, 로그아웃
  • task 페이지로 이동
    • ai-service-team 페이지로 이동
    • nsc-slot 페이지로 이동
    • sb-dev-team 페이지로 이동
    • the-future-company 페이지로 이동
  • testing 페이지로 이동
    • [초안] 시니어 Java 백엔드를 위한 테스트 전략 완전 정리 — 피라미드부터 TestContainers, 마이크로벤치, Contract까지
  • travel 페이지로 이동
    • 오사카 3박 4일 일정표: 우메다 쇼핑, USJ, 난바·도톤보리, 오사카성
  • web 페이지로 이동
    • [초안] HTTP / Cookie / Session / Token 인증 기본기 — 레거시 JSP와 모바일 API가 공존하는 백엔드 관점
FOS-BLOG · FOOTERall systems normal·v0.1 · 2026.04.27·seoul, kr
Ffos-blog/study

개발 학습 기록을 정리하는 블로그입니다. 공부하면서 기록하고, 기록하면서 다시 배웁니다.

visitors
01site
  • Home↗
  • Posts↗
  • Categories↗
  • About↗
02policy
  • 소개/about
  • 개인정보처리방침/privacy
  • 연락처/contact
03categories
  • AI↗
  • Algorithm↗
  • DB↗
  • DevOps↗
  • Java/Spring↗
  • JS/TS↗
  • React↗
  • Next.js↗
  • System↗
04connect
  • GitHub@jon890↗
  • Source repositoryjon890/fos-study↗
  • RSS feed/rss.xml↗
  • Newsletter매주 1 회 · 한 편의 글→
© 2026 FOS Study. All posts MIT-licensed.
built with·Next.js·Tailwind v4·Geist·Pretendard·oklch
fos-blog/python/PyTorch 기초 — 텐서, 디바이스, 그…
system

PyTorch 기초 — 텐서, 디바이스, 그리고 모델 로딩이 무거운 이유

자바 백엔드에서 Spring Boot 가 부팅하는 시간이 5-30초 걸리는 게 일반적이다. 클래스 로딩, 컴포넌트 스캔, 의존성 주입, EntityManagerFactory 초기화 등이 누적된다. 한 번 부팅하면 그 뒤로는 요청 처리에 거의 영향이 없다. PyTorch 기반 ML 서비스는 비슷하지만 한 단계 더 무겁다. 우리 프로젝트의 KR Worker 가...

2026.05.19·7 min read·16 views

자바 백엔드에서 Spring Boot 가 부팅하는 시간이 5-30초 걸리는 게 일반적이다. 클래스 로딩, 컴포넌트 스캔, 의존성 주입, EntityManagerFactory 초기화 등이 누적된다. 한 번 부팅하면 그 뒤로는 요청 처리에 거의 영향이 없다.

PyTorch 기반 ML 서비스는 비슷하지만 한 단계 더 무겁다. 우리 프로젝트의 KR Worker 가 실측으로 워커 한 번 spawn 마다 5.74초 (1,565회 측정, p95 5.94s) 의 워밍업 비용을 지불한다. 자바 시각으로는 "Spring Boot 가 매번 부팅하는 비용을 요청 몇 건마다 다시 내는 셈". 이 글은 PyTorch 의 모델 로딩이 왜 그렇게 무거운지, 자바 백엔드 비교로 정리한다.

텐서 — numpy array + GPU + autograd

PyTorch 의 모든 데이터는 torch.Tensor 다. 겉모습은 numpy ndarray 와 비슷하지만 세 가지가 더 있다.

  1. GPU 에서 동작 가능 — .to("cuda") 로 VRAM 으로 이동, 같은 연산을 GPU 가 수행
  2. 자동 미분 — requires_grad=True 시 모든 연산이 계산 그래프로 기록, 학습 가능
  3. dtype 가 정수·소수·복소수·bool 까지 폭넓음 — float32, float16, bfloat16, int8 등 (양자화 시 중요)
python
import torch
 
x = torch.tensor([[1.0, 2.0], [3.0, 4.0]])      # CPU 텐서, float32 기본
print(x.shape, x.dtype, x.device)
# torch.Size([2, 2]) torch.float32 cpu
 
y = x.to("cuda")                                  # GPU 로 복사
z = y @ y.T                                       # GPU 에서 행렬 곱
print(z.device)
# cuda:0

자바로 비유하면 Tensor 는 double[] + Stream API + GPU 위에서 도는 SIMD 까지 묶은 객체. Spring 의 Mono<T> 처럼 lazy 한 것은 아니지만, autograd 모드에서는 계산 그래프가 차곡차곡 쌓인다는 점에서 비슷한 결.

추론 (학습 아님) 서비스에서는 보통 autograd 를 끈다. torch.no_grad() 또는 torch.inference_mode() 컨텍스트 매니저 안에서 연산. 자바의 final 처럼 "수정 안 함" 을 컴파일러가 아니라 런타임에 PyTorch 에 알려주는 셈.

python
with torch.inference_mode():
    output = model(input_tensor)

device — 자바의 Executor 자리

자바에서 ExecutorService 가 작업을 어디서 실행할지 결정하듯, PyTorch 에서는 텐서·모델의 device 가 어디서 연산이 일어날지 결정한다.

python
device = "cuda" if torch.cuda.is_available() else \
         "mps"  if torch.backends.mps.is_available() else \
         "cpu"
 
model = model.to(device)
input = input.to(device)
output = model(input)        # 같은 device 에서만 연산 가능

같은 device 끼리만 연산이 된다. CPU 텐서와 GPU 텐서를 곱하려 하면 RuntimeError: Expected all tensors to be on the same device 가 난다. 자바 멀티스레드에서 ThreadLocal 자원을 다른 스레드가 만지면 NPE 가 나는 것과 비슷한 위치.

device 가 여러 개 (multi-GPU) 인 환경에서는 cuda:0, cuda:1 처럼 인덱스를 지정한다. 우리 운영 환경은 T4 한 장이라 항상 cuda:0.

nn.Module — Spring @Service 같은 비유

PyTorch 모델의 단위는 torch.nn.Module 서브클래스다. 자바에서 @Service 클래스가 비즈니스 로직을 담듯, nn.Module 은 forward 연산을 담는다.

python
import torch.nn as nn
 
class Classifier(nn.Module):
    def __init__(self):
        super().__init__()
        self.layer1 = nn.Linear(768, 256)
        self.layer2 = nn.Linear(256, 10)
 
    def forward(self, x):
        x = torch.relu(self.layer1(x))
        return self.layer2(x)
 
model = Classifier().to("cuda")
output = model(input_tensor)         # 사실은 model.forward(input_tensor)

자바 차이점:

  • 모델의 상태 = parameter 들(텐서) 이 객체 안에 보유된다. model.parameters() 로 순회 가능.
  • 모델 호출 시 forward 가 아니라 객체 자체를 함수처럼 부른다 (model(x)). Python 데코레이터 글 의 __call__ dunder 가 동작.
  • .to("cuda") 한 번 부르면 모든 parameter 텐서가 GPU 로 일괄 이동. 자바의 @Transactional 처럼 모듈 전체에 적용되는 동작.

모델 로딩이 무거운 이유 — 다섯 단계 누적

자바 Spring 부팅이 한 번 끝나면 그 뒤로는 코드 로딩이 끝나지만, PyTorch 모델 로딩은 다음 다섯 단계가 모두 끝나야 첫 추론이 가능하다.

1단계: heavy import (3-8s)

import torch, import paddle, import docling, import transformers 자체가 비싸다. 각 라이브러리가 수십 MB 짜리 native 바이너리 (CUDA kernels, BLAS 라이브러리) 를 로딩하고 ABI 호환성 체크를 한다.

자바 Class.forName(...) 의 lazy 클래스 로딩과 달리 Python 은 import 즉시 모듈 본문이 전부 실행된다. ML 라이브러리들은 import 시점에 GPU device 스캔, CUDA 버전 확인 등을 한다.

2단계: 모델 파일 디스크 읽기 (수 100MB)

torch.load("model.pt") 또는 HuggingFace from_pretrained(...) 는 사실상 큰 binary file 을 디스크에서 읽어 파이썬 객체로 deserialize 한다. 모델 크기가 BERT-base 라면 ~440MB, 더 큰 모델은 수 GB.

자바의 ObjectInputStream deserialization 과 같은 결인데 데이터 크기 자체가 큼.

3단계: weights 를 GPU 로 복사 (PCIe 전송)

파일에서 읽은 weight 텐서를 시스템 RAM 에서 VRAM 으로 옮긴다. model.to("cuda"). PCIe 버스를 통한 단방향 전송. 약 10GB/s 대역폭 기준 400MB 모델은 약 40ms 지만 실제로는 작은 청크 여러 개라 시간이 좀 더 든다.

4단계: CUDA context 초기화 (300-600MB VRAM + 1-2s)

각 프로세스가 GPU 에 처음 접근할 때 CUDA Runtime 이 컨텍스트를 만든다. 자바의 첫 Thread.start() 가 OS 스레드를 만드는 비용과 비슷한 위치인데 훨씬 무겁다. 300-600MB 의 VRAM 도 소비. NVIDIA MPS 가 이 비용을 공유로 줄이려는 시도.

5단계: JIT warmup — 첫 추론 캐싱 (3-10s)

PyTorch / cuDNN 은 첫 번째 추론 시점에 최적 알고리즘을 선택하고 GPU kernel 을 컴파일해 캐싱한다. 같은 입력 shape 라면 두 번째 호출부터 매우 빠르다.

자바의 JIT (HotSpot) 가 자주 호출되는 메서드를 컴파일하는 것과 같은 개념인데, ML 라이브러리는 첫 호출 자체에 더 큰 비용을 모은다. 그래서 서비스 부팅 시 "warmup" 단계를 의도적으로 수행한다.

python
# warmup — 서비스가 받을 입력과 같은 shape 로 한 번 돌려준다
dummy = torch.randn(1, 3, 224, 224, device="cuda")
with torch.inference_mode():
    _ = model(dummy)
torch.cuda.synchronize()

우리 프로젝트의 warm_up_all_converters 함수가 정확히 이 일을 한다. Docling converter 를 만들고 sample/warmup.pdf 를 한 번 변환해 JIT 캐시를 채운다. 운영 로그에서 Finished converting document warmup.pdf in 4.67 sec 로 보이는 게 이 단계.

우리 환경의 5.74초 분해

운영 측정 결과 KR Worker 워밍업 시간 mean 5.74s, p50 5.48s. 위 다섯 단계로 분해하면 다음과 같다.

단계추정 시간비고
heavy import~1-2s두 번째 worker spawn 부터는 OS 페이지 캐시 덕에 빠름
PaddleOCR 모델 로드~1sdet+rec+cls 세 모델
Docling converter 생성~0.5-1slayout, table, OCR pipeline 옵션 결합
GPU 로 transfer + CUDA context~0.5-1s모델이 GPU 모드일 때
warmup convert + MarkItDown sample~2-3swarmup.pdf 4.67s + warmup.docx 0.55s 합산

부팅 시점에는 모델 파일 다운로드 (HuggingFace) 까지 포함되어 16.5s 가 걸린다. 그 이후 respawn 은 디스크 캐시 덕에 5.7s 수준. 우리 분석에서 "모델 다시 로딩하는 비용이 워밍업 시간 차이를 만든다" 가 핵심 결론.

HuggingFace 캐시 — 자바 Maven local repo 자리

transformers, docling-ibm-models 같은 라이브러리는 모델을 처음 요청할 때 HuggingFace Hub 에서 자동 다운로드한 뒤 ~/.cache/huggingface/ 에 저장한다. 자바의 ~/.m2/repository 와 같은 자리.

Docker 환경에서는 이 캐시가 컨테이너 안에 있으면 컨테이너 재시작 시 사라진다. 그래서 우리 Dockerfile 은 빌드 시점에 huggingface-cli download 로 모델을 미리 받아 이미지에 박는다. 자바에서 mvn dependency:go-offline 으로 의존성을 박는 것과 같은 패턴.

모델 캐시 — 자바 싱글톤 빈

PyTorch 모델 자체는 한 번 로드하면 메모리에 떠 있다. 매 요청마다 다시 로드하면 위 다섯 단계를 매번 반복해 처리가 안 된다.

우리 프로젝트는 worker 안에 _converter_cache (document_parser.py:161) 라는 dict 로 옵션 조합별 Docling converter 를 캐싱한다. 자바 Spring 의 싱글톤 빈과 같은 패턴.

python
_converter_cache = {}
 
def get_converter(do_ocr, do_table, ja_doc):
    cache_key = f"ocr_{do_ocr}_table_{do_table}_ja_{ja_doc}"
    if cache_key not in _converter_cache:
        _converter_cache[cache_key] = build_converter(do_ocr, do_table, ja_doc)
    return _converter_cache[cache_key]

cache key 가 빠뜨려진 인자 (예: ocr_model) 가 있으면 stale cache 버그가 생긴다. 우리 분석에서 이슈로 잡힌 부분.

정리

자바 백엔드에서 ML 서비스로 넘어올 때 두 줄로 외우면 좋다.

PyTorch 모델 로딩은 import + 디스크 읽기 + GPU 전송 + CUDA context + JIT warmup 다섯 단계의 합이다. 한 번 끝나면 캐시 객체로 재사용한다.

Worker 가 죽고 다시 spawn 될 때마다 이 다섯 단계가 반복된다. MAX_TASKS_PER_WORKER 가 작으면 누적 비용이 폭증한다.

다음 글은 이 워밍업 비용을 multi-process worker pool 패턴으로 다루는 방법, 자바 ThreadPool 과의 결정적 차이를 정리한다.

참고

  • PyTorch — Tensors
  • PyTorch — nn.Module
  • PyTorch — Inference Mode
  • HuggingFace — Caching
  • PyTorch CUDA Semantics — Caching allocator
on this page
  • 01텐서 — numpy array + GPU + autograd
  • 02device — 자바의 Executor 자리
  • 03nn.Module — Spring `@Service` 같은 비유
  • 04모델 로딩이 무거운 이유 — 다섯 단계 누적
  • 1단계: heavy import (3-8s)
  • 2단계: 모델 파일 디스크 읽기 (수 100MB)
  • 3단계: weights 를 GPU 로 복사 (PCIe 전송)
  • 4단계: CUDA context 초기화 (300-600MB VRAM + 1-2s)
  • 5단계: JIT warmup — 첫 추론 캐싱 (3-10s)
  • 05우리 환경의 5.74초 분해
  • 06HuggingFace 캐시 — 자바 Maven local repo 자리
  • 07모델 캐시 — 자바 싱글톤 빈
  • 08정리
  • 09참고

이런 글도

  • Python 서버의 RSS 가 안 줄어드는 이유 — gc.collect 의 한계와 malloc_trim
    Python 으로 long-running 서버 (FastAPI / Flask / Celery / uWSGI 등) 를 운영하다 보면 한 번쯤 마주치는 증상이 있다. - 워커 프로세스의 RSS 가 시간이 지날수록 단조 증가한다 - 큰 객체를 del 하고 gc.collect() 를 불러도 RSS 가 줄지 않는다 - 결국 max-requests / workerma...
    📁 system
    system
    2026.05.22
  • ML 서비스 성능 분석 워크플로 — 자바 백엔드 트러블슈팅과 다른 점
    이 시리즈의 마무리 글이다. 앞선 글들에서 다음 주제를 자바 백엔드 비교 관점으로 정리했다. - Python 문법 - 의존성 관리 - FastAPI - async/await - GPU·CUDA·MPS - PyTorch - multi-process worker pool - OCR 파이프라인 마지막은 이 모든 개념을 적용해 실제 ML 서비스의 성능을 분석하는...
    📁 system
    system
    2026.05.19
  • OCR 동작 원리 — Layout · Text · Post-process 3단계
    자바 백엔드만 다뤄오다가 OCR (Optical Character Recognition) 서비스를 분석할 일이 생겼다. "이미지에서 글자를 뽑는다" 라는 한 줄 요약은 알았지만, 실제 코드를 열어보면 모델이 둘이상이고, 여러 단계가 직렬·병렬로 엮여 있고, "왜 이 단계가 따로 있지" 같은 의문이 계속 생긴다. 이 글은 OCR 파이프라인의 표준 구조를 정리...
    📁 system
    system
    2026.05.19
  • Multi-process GPU 워크로드 — 자바 ThreadPool 사용자가 만나는 모델 차이
    자바 백엔드에서 ThreadPoolExecutor 는 거의 만능이었다. CPU bound 든 I/O bound 든 스레드 풀 크기만 잘 잡으면 동시성을 챙길 수 있었다. JVM 안에서 메모리를 공유하니 작업 간 데이터 전달도 가볍다. Python ML 서비스는 그림이 다르다. ThreadPoolExecutor 가 있지만 CPU/GPU 작업에서는 거의 안 쓰...
    📁 system
    system
    2026.05.19

댓글 (0)