나노바나나(NanoBanana) 정밀 제어: ControlNet과 Adapter 활용
들어가는 글
이번 글에서는 나노바나나를 위한 경량화된 제어 모듈인 ‘Banana-Adapter’를 사용하여, 스케치나 포즈 데이터를 기반으로 이미지를 생성하는 방법을 다룬다.
Banana-Adapter의 원리
기존 Stable Diffusion의 ControlNet은 모델의 인코더 전체를 복제하여 학습시키기 때문에 용량이 크고(수 GB 단위), 연산량이 두 배 가까이 늘어나는 단점이 있었다.
반면, 나노바나나는 T2I-Adapter 방식을 차용하여 독자적인 ‘Banana-Adapter’ 구조를 사용한다. 이는 전체 모델을 건드리지 않고, 약 50MB 내외의 아주 작은 경량 네트워크가 이미지의 특징(Feature)만을 추출하여 나노바나나의 트랜스포머 블록에 주입(Injection)하는 방식이다.
덕분에 추론 속도 저하가 거의 없이(약 5~10% 지연) 강력한 구조 제어가 가능하다.
준비물: OpenCV와 ControlNet 모델
이미지 전처리를 위해 OpenCV 라이브러리가 필요하다.
1
pip install opencv-python numpy
또한, 나노바나나 커뮤니티에서 사전 학습된 Adapter 가중치를 다운로드해야 한다. 대표적으로 canny(선화), openpose(자세), depth(깊이) 등이 있다.
실전 예제 1: Canny Edge (스케치를 실사로)
가장 많이 쓰이는 기법이다. 대충 그린 스케치나 기존 이미지의 외곽선을 따서, 그 구도 그대로 새로운 이미지를 만든다.
전처리 함수 (Canny Map 생성)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import cv2
import numpy as np
from PIL import Image
def get_canny_image(image_path):
image = cv2.imread(image_path)
image = np.array(image)
low_threshold = 100
high_threshold = 200
image = cv2.Canny(image, low_threshold, high_threshold)
image = image[:, :, None]
image = np.concatenate([image, image, image], axis=2)
return Image.fromarray(image)
canny_image = get_canny_image("my_sketch.png")
# canny_image.show() # 검은 배경에 흰 선으로 된 이미지가 보여야 한다.
Banana-Adapter를 이용한 추론
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import torch
from nano_banana import BananaControlPipeline, BananaAdapter
# 1. 어댑터 로드 (Canny용)
adapter = BananaAdapter.from_pretrained(
"banana-ai/adapter-v1-canny",
torch_dtype=torch.float16
)
# 2. 파이프라인 설정
pipe = BananaControlPipeline.from_pretrained(
"banana-ai/nano-banana-v1-base",
adapter=adapter,
torch_dtype=torch.float16
).to("cuda")
# 3. 이미지 생성
prompt = "A futuristic sci-fi building, hyperrealistic, 8k, unreal engine 5"
image = pipe(
prompt=prompt,
image=canny_image, # 전처리된 Canny 이미지 입력
controlnet_conditioning_scale=0.7, # 제어 강도 (0.5 ~ 1.0 권장)
num_inference_steps=25
).images[0]
image.save("output_canny.png")
위 코드를 실행하면 my_sketch.png의 선 구성을 완벽하게 따르면서, 프롬프트에서 묘사한 ‘SF 건물’의 질감을 입힌 결과물이 나온다. conditioning_scale을 높일수록 선을 더 엄격하게 지킨다.
실전 예제 2: Multi-Control (여러 조건 동시 적용)
나노바나나는 구조가 가볍기 때문에, 여러 개의 어댑터를 동시에 사용해도 VRAM 부담이 적다. 예를 들어, 인물의 자세(Pose)와 배경의 깊이감(Depth)을 동시에 제어하고 싶을 때 유용하다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 다중 어댑터 로드
adapter_pose = BananaAdapter.from_pretrained("banana-ai/adapter-v1-openpose")
adapter_depth = BananaAdapter.from_pretrained("banana-ai/adapter-v1-depth")
pipe = BananaControlPipeline.from_pretrained(
"banana-ai/nano-banana-v1-base",
adapter=[adapter_pose, adapter_depth], # 리스트로 전달
torch_dtype=torch.float16
).to("cuda")
# 각각의 제어 이미지와 스케일 전달
image = pipe(
prompt="A soldier running in a jungle",
image=[pose_image, depth_image],
controlnet_conditioning_scale=[1.0, 0.5], # 포즈는 강력하게, 깊이는 약하게
num_inference_steps=30
).images[0]
이 기능은 웹툰 작가나 콘티 작업을 하는 크리에이터들에게 매우 강력한 도구가 된다. 3D 툴로 잡은 구도를 그대로 2D 일러스트로 렌더링할 수 있기 때문이다.
성능 고려사항 (Performance Note)
- VRAM 사용량: 어댑터 하나당 약 100MB의 VRAM만 추가로 소모한다. 4GB VRAM에서도 Canny 어댑터 하나 정도는 충분히 구동 가능하다.
- 추론 시간: Adapter 연산은 전체 추론 과정에서 극히 일부만 차지한다. 베이스 모델만 돌릴 때와 체감 속도 차이는 거의 없다.