ComfyUI를 조금 더 깊이 있게 다루면, 프롬프트 엔지니어링을 더욱 정밀하게 제어할 수 있습니다. 사용자가 작성한 프롬프트는 결국 conditioning 단계를 거쳐 U-Net으로 넘어가게 됩니다. 그럼 이 Conditioning 단계를 제어하면 조금더 프롬프트를 사용자의 입맛에 맞게 효율적으로 사용할 수 있지 않을까요? 본문에서 한 번 살펴보도록 하겠습니다.
기본 이미지 생성
먼저 테스트에 사용할 기본 이미지를 생성해보겠습니다. 기본 워크플로우(default node)를 로드한 뒤 아래와 같이 프롬프트를 작성하고 이미지를 생성했습니다.
Positive : best quality, realistic, closeup of a beautiful girl wearing a coat and a red scarf in the forest
Negative : worst quality, bad quality
프롬프트 내 red scarf를 작성했지만, 스카프의 색상이 코트까지 번진 것을 볼 수 있습니다. 꼭 코트가 아니어도, 색상이 있는 아이템을 프롬프트에 작성했을 때 해당 아이템 색상이 다른 영역까지 영향을 미치는 경우가 자주 발생하는데요, 본문에서는 이 부분을 conditioning을 제어하는 원시적인(?) 방법으로 극복해보고자 합니다.
프롬프트 엔지니어링 – Conditioning 제어
프롬프트를 작성하는 CLIP Text Encode 노드를 보면 출력단이 컨디셔닝(Conditioning)이라고 되어 있습니다. 우리는 이 컨디셔닝을 KSampler의 positive 및 negative로 연결합니다. 아래의 스테이블디퓨전 모델 아키텍쳐를 살펴보면 가장 우측의 Conditioning에 Text가 있는 것을 볼 수 있습니다.
즉, 우리가 작성한 프롬프튼는, CLIP 인코딩을 통해 컨디셔닝의 일환으로 통합되어, U-Net으로 전달되며, U-Net에서는 디노이징 작업을 반복하여 이미지를 재현해내는 방식입니다. 컨디셔닝에서 제어할 수 있는 부분 중 가장 익숙한 또다른 노드가 바로 컨트롤넷입니다. 아래는 Apply ControlNet 노드를 생성한 예시입니다.
보시다시피 해당 노드는 컨디셔닝을 받아 컨디셔닝으로 출력하며, 우리는 컨트롤넷을 사용하기 위해 컨트롤넷 모델을 로드하고, 전처리된 이미지를 Apply ControlNet 노드로 함께 전달합니다. 결국 아까 살펴본 모델 아키텍쳐의 우측, 즉, 컨디셔닝 영역에서 텍스트 프롬프트와, 컨트롤넷 정보가 모두 처리되어 이미지 생성에 관여하게 되는 것입니다. 우리는 이제 컨디셔닝을 U-Net에 전달하는 방식을 제어하여 생성 이미지에 영향을 주도록 하겠습니다.
Conditioning (Concat)
Concat은 concatenate의 약어로, 사전적 의미로 보면 사슬처럼 연쇄시킨다는 의미를 갖습니다. ComfyUI의 기본 노드 중 Conditioning(Concat)을 사용하면 인코딩된 텍스트 프롬프트(=임베드)를 연속적으로 U-Net으로 전달하게 됩니다. 먼저 노드를 구성하는 방법부터 살펴보겠습니다. 아래와 같이 conditioning(concat) 노드를 새로 추가한 뒤, CLIP Text Encode 노드를 하나 더 추가하여, red scarf를 따로 작성해줍니다. 기존의 프롬프트에서는 red scarf를 빼주도록 하겠습니다.
KSampler 설정은 동일하게 유지했습니다. 이렇게 구성한 뒤 큐 프롬프트를 눌러 이미지를 생성하자 우리가 원한대로 빨간색이 스카프에만 잘 적용되고 코트는 카멜색으로 변했습니다. 배경의 눈내린 풍경이나, 나무, 인물의 구도와 얼굴은 큰 변화가 없습니다. 어떻게 이게 가능할까요?
원리는 conditoining concat 노드에서 우리가 작성한 2개의 프롬프트 노드를 순서대로 묶어 KSampler로 전달했기 때문입니다. 이때 프롬프트 노드에 작성된 프롬프트는 각각의 77토큰 덩어리, 즉 embedding을 2개에 따로따로 토큰으로 인코딩되어 채워넣어졌으며, 77토큰을 다 사용하지 않았더라도, 하나의 새로운 임베딩을 만들어 red scarf만 따로 정보를 채워넣었기 때문에, 두번째 프롬프트 노드의 red scarf의 “red”가 첫번째 프롬프트 노드의 다른 프롬프들에게 영향을 미치지 못한 모습입니다.
Conditioning (Combine)
이번에는 Conditioning Combine 노드를 사용해보겠습니다. 아래와 같이 노드를 구성하고 이미지를 생성해봅니다.
이번에는 빨간 스카프를 잘 착용한 여성이 등장했지만, 처음 생성했던 이미지와 조금은 구도가 다른 모습입니다. 배경의 나무라든지, 여성의 코트등이 미묘하게 다른데요, 이는 Conditioning Combine 노드를 사용했을 때 아래와 같은 작업이 수행되기 때문입니다.
KSampler 안에서 벌어지는 일을 조금 더 깊이 살펴보면, Conditioning 입력단을 통해 각각의 임베딩이 모델로 전달되고 모델은 이로부터 각각의 임베딩에 해당하는 노이즈 이미지를 생성한 다음, 두 노이즈 이미지를 합해서(average) 한 장으로 반든 뒤 샘플링을 시작해 그림을 생성하게 됩니다.
그럼 만약 프롬프트를 나눠 작성했지만, 조금 더 기존 이미지 구도와 구성을 유지하려면 어떻게 해야할까요? 이럴 때는 간단히 두번째 프롬프트 노드에 기존 프롬프트를 그대로 작성하고, coat만 red scarf로 바꿔주는 것이 좋습니다.
위 예시에서 보다시피 이제 기존과 거의동일한 구도와 여성이 나타나는 것을 볼 수 있습니다.
Conditioning Average
마지막으로 Conditioning Average를 살펴보겠습니다. Average를 살펴보기 위해 이번에는 아래와같이 사람이 아닌 고릴라 이미지를 만들어봅니다.
Positive : best quality, realistic, closeup of a gorilla wearing a coat in the forest
Negative : worst quality, bad quality
코트를 입은 고릴라를 드래곤처럼 바꿔볼 예정입니다. 이번에는 Conditioning Average 노드를 생성하고 아래와 같이 두번째 프롬프트에는 고릴라 대신 드래곤을 입력해 서로 연결해 KSampler 로 넘겨줍니다.
2nd Positive : best quality, realistic, closeup of a dragon wearing a coat in the forest
두 프롬프트 노드를 반반 섞기위해 ConditioningAverage 노드의 conditioning_to_strength를 0.5로 수정하고 이미지를 생성한 모습입니다. 기존 고릴라 얼굴의 머즐이 용처럼 더 길어지고 콧잔등에 주름이 생성된 모습입니다. 체형 또한 고릴라가 아닌 드래곤의 모습이 살짝 섞인 모습인데요, conditioning_to_strength를 조금 더 강하게 조정하면 할수록 더욱 드래곤의 모습으로 변화합니다. 직접 실험해보시기 바랍니다.
Conditioning Average의 경우 2개로 각각 작성된 프롬프트 노드로부터 인코딩된 임베딩 자체가 1개의 임베딩으로 합해진(average) 뒤 KSampler로 전달되는 방식입니다. 따라서 서로다르게 작성한 두 프롬프트를 잘 섞어서 이미지를 만들 수 있습니다.
맺음말
오늘은 Conditioning을 직접 다뤄 이미지 생성에 영향을 주는 방법을 살펴봤습니다. 대략적인 원리를 파악하셨다면, 단순 1개의 프롬프트 노드가 아닌 2개 또는 2개 이상의 다수의 노드를 적절하게 사용함으로써 더욱 구체적인 제어권을 가지고 목표 이미지를 생성할 수 있습니다. 다음 글에서는 Conditioning을 다른 방식으로 제어하는 방법도 한 번 살펴보도록 하겠습니다.