Anime Denser ✨ Wan2.1-T2V-14B
세부 정보
파일 다운로드
모델 설명
ℹ️ 참고: 색상 포스트의 비디오들은 이 LoRA가 하는 모든 것을 완전히 나타내지 않으므로, 갤러리의 그리드를 주의 깊게 확인하세요.
설명
이 LoRA는 환경의 구성 밀도를 제어하기 위해 설계된 강화(슬라이더) LoRA입니다. SD1.5 시절부터 디테일러와 트위커가 제가 가장 좋아하는 LoRA 유형이었기 때문에, 비디오 모델을 위한 유사한 기능을 만들고 싶었습니다.
이것은 제가 계획한 첫 번째(그리고 마지막은 아닐) 강화 LoRA입니다. 이 LoRA는 ComfyTinker가 이 LoRA에 대해 설명한 방법론을 기반으로 한 _차등 LoRA(differential LoRA)라는 학습 개념을 사용합니다. 저는 이 접근 방식에 흥미를 느꼈고, (음, 이상한 예시이긴 하지만) 다른 도메인에서 이를 재현하기로 결정했습니다. 두 개의 참고 자료에 의존했습니다: 하나, 둘.
이 개념 자체는 단순하지만 강력한 아이디어를 기반으로 합니다: 단 하나의 특정 특징만 다르게 된 두 개의 LoRA를 학습한 후, 하나의 LoRA를 다른 LoRA에서 빼서 결합하면, 독립된 LoRA에 명확한 개념을 "정제"할 수 있습니다. 이렇게 파생된 LoRA는 추론 시 강도를 조정함으로써 해당 특징의 존재 여부와 강도를 제어할 수 있습니다. 단일 개념을 효과적으로 분리하면, 비분리된 데이터셋에서 일반적인 개념 LoRA를 학습할 때 불가피하게 발생하는 부수적인 노이즈 특징의 침투를 방지할 수 있습니다(이론적으로). 그러나 두 개의 기준 LoRA를 위한 데이터셋은 학습하려는 목표 특징을 제외하고는 모든 측면에서 매우 유사해야 합니다. 그렇지 않으면, 목표 개념 LoRA를 신중하게 추출한 후에도 여전히 특징 침투가 발생할 수 있습니다.
이 방법 자체가 완전히 새로운 것은 아님을 언급할 가치가 있습니다. 이 방법은 이전의 LECO, 슬라이더 LoRA( Ostris 및 AI Toolkit에 의해 대중화됨), "Concept sliders" 프로젝트, FlexWaifu, SD 웹 UI용 sd-webui-traintrain 확장기, 그리고 NLP의 일부 기법(임베딩을 위한 벡터 산술 등)과 많은 공통점을 가집니다. kohya-ss의 유명한 svd_merge_lora.py 스크립트도 마찬가지입니다. 그러나 이는 비디오 모델 LoRA 학습에 이 개념을 적용한 첫 번째 사례입니다(비록 DiT의 주의 메커니즘이 "전통적인" 트랜스포머와 그렇게 다르지 않을 수 있지만요).
(물론 이 개념은 ML에만 고유한 것이 아니며, 오디오 노이즈 감소를 위한 위상 상쇄와 같은 고전적인 신호 처리 기법들과도 유사합니다.)
사용법
이 LoRA는 자체적으로 애니메이션 스타일을 적용하지 않음을 기억하세요. 그러나 저는 사실적인 비디오에 대한 관심이 제로 이하이기 때문에, 이 LoRA를 2D 애니메이션 LoRA와 함께 사용하기 위해 특별히 설계했고, 그 맥락에서만 테스트했습니다. 따라서 이를 "Anime Denser"라고 이름지었습니다. 저는 다른 것에는 테스트하지 않았고, 테스트할 계획도 없습니다.
(그러나 이 LoRA는 2D 애니메이션 전용으로 학습 및 테스트되었지만, 제가 제대로 구현했다면 사실적인 비디오에서도 작동할 것입니다. 개념 분리의 아이디어는 스타일 차이를 우회하는 것을 목표로 하기 때문입니다. 그러나 이는 제 추측일 뿐입니다.)
공개한 모든 클립은 이 LoRA와 "기본"(베이스) Wan2.1-T2V-14B 모델 및 Studio Ghibli LoRA를 결합하여 생성했습니다. (Ghibli LoRA가 너무 강력해서 자체적으로 강화 효과를 발휘하고, 이 LoRA의 증폭 효과를 가리키는 경우가 많기 때문에 최선의 선택은 아닐 수 있습니다.) 또한, self-forcing lightx2v LoRA도 적용했는데, 그렇지 않으면 이 LoRA의 데모 영상을 만들기 위해 두 달 이상이 걸렸을 것입니다.
이 LoRA를 사용하는 워크플로우는 WanVideoWrapper를 사용하지만, LoRA 로더가 포함된 어떤 네이티브 워크플로우도 작동합니다. 샘플 워크플로우는 색상 포스트의 비디오 중 하나를 ComfyUI에 드래그하거나 여기서 다운로드할 수 있습니다: JSON.
(수직 그리드 비디오는 내장된 워크플로우가 없습니다.)
이 LoRA의 안전한 강도 범위는 -3(환경 밀도를 낮춤)에서 +3(높은 밀도, 더 복잡한 구성적 "혼잡")입니다. 길고 복잡한 프롬프트의 경우 텍스트 인코더의 영향을 보완하기 위해 +4 또는 -4까지 올릴 수 있지만, 그 이상으로 올리면 대부분 노이즈가 심한 출력이 생성됩니다.
(광범위한 테스트 결과, 높은 강도에서 이 LoRA는 가끔(항상은 아님) 실내 환경에서 녹색 계열의 색조를 약간 증폭하는 현상이 관찰되었습니다. 원인은 불명확합니다. 분명히 뺄셈 과정 중 일부 특징 맵이 불균형하게 빠졌을 수도 있고, 또는 조명을 어떻게든 "밀도 높게" 만들려는 시도일 수도 있습니다.)
데이터셋
차등 LoRA의 경우 데이터셋이 핵심적입니다. 제가 선택한 개념(구성 밀도)을 위해 두 개의 데이터셋이 필요했습니다: 하나는 매우 상세한("밀집된") 장면, 다른 하나는 저밀도("희박한") 장면입니다. 이러한 장면들이 공통점을 더 많이 가질수록 뺄셈 과정에서 노이즈 제거 효과가 더 높아집니다. 이상적으로는 동일한 장면을 다른 세부 수준으로 촬영한 것을 수집해야 했습니다. 처음에는 애니메이션 영화에서 잘 세부화된 장면들을 수집하고, VACE나 낮은 노이즈 설정을 가진 간단한 V2V 파이프라인을 통해 실행하려 했습니다.
💡 그러나 두 가지 일이 발생했습니다:
구성 밀도와 같은 개념을 학습하려면 이미지만 사용해도 충분하고, 오히려 시간적 노이즈의 가능성을 완전히 배제할 수 있기 때문에 더 나을 수 있다는 것을 깨달았습니다. 이로 인해 LoRA 학습 요구사항이 크게 낮아져 다양한 설정을 실험할 수 있는 여지가 늘었습니다. (이 LoRA를 결정하기 전에 최소 20개의 LoRA를 학습했습니다...)
FLUX.1 Kontext [dev]가 출시되었고, 이는 제 작업을 위한 이상적인 데이터셋을 생성하는 매우 편리하고 쉬운 방법을 제공했습니다.
따라서 마코토 신카이 감독의 영화에서 채취한 100개 이상의 프레임을 사용했습니다(그는 터무니없이 "밀집되고" 세밀한 환경을 만드는 것으로 유명합니다). 그런 다음 이 프레임들을 Flux Kontext 기반의 배치 워크플로우에 입력했고, 다음과 같은 프롬프트를 사용했습니다:
이 장면의 세부 정보를 줄이기 위해 음식, 주방용품, 책, 포스터, 장식품과 같은 모든 작은 객체와 혼잡한 요소를 제거하세요. 복장 요소와 캐릭터 액세서리의 정교한 패턴, 작은 아이템 또는 과도한 세부사항도 단순화하세요. 캐릭터와 전체 아트 스타일은 유지하되, 전체 장면을 매우 단순하고 세부가 적으며 미니멀리스트처럼 보이게 하세요.
이 작업은 완벽하게 작동했습니다. 결과적으로, 저는 126개의 이미지 쌍(이 데이터는 학습 데이터에 포함되어 있습니다)을 얻었고, 이는 차등 LoRA의 두 구성 요소(밀집 LoRA 및 희박 LoRA)의 데이터셋을 구성했습니다. 아래는 데이터셋 이미지 쌍의 예시입니다:
1️⃣ 세부화된, "밀집된" 버전(원본 프레임)

2️⃣ 단순화된, "희박한" 버전(Kontext로 생성)

캡션 생성에 대해서는 여러 접근 방식을 시도했습니다:
- 각 데이터셋마다 다른 짧은 캡션
- 두 데이터셋 모두 동일한 짧은 캡션
- 각 데이터셋마다 다른 상세한 캡션
- 동일한 캡션에 "상세한"이라는 단어만 밀집 데이터셋 캡션에 추가
- 밀집 데이터셋에는 "상세한 이미지", 희박 데이터셋에는 단순히 "이미지"라고 캡션
- 각 쌍에 고유 ID를 할당 - 예: 희박 이미지는 "anime_image_165656"로 캡션하고, 그에 대응하는 밀집 이미지는 "anime_image_165656, detailed"로 캡션 (이 아이디어는 장면의 콘텐츠를 텍스트 레이블로 캡슐화하여 "세부성" 개념의 뺄셈을 용이하게 하려는 것이었지만, 작동하지 않았습니다)
- 빈 캡션 사용 🥳
그리고 (분명히) 빈 캡션이 가장 효과적이었습니다.
이것은 어느 정도 합리적입니다. 다음 이미지의 오른쪽 부분을 살펴보세요. Wan 트랜스포머에서는 MMDiT과 달리, self-attention과 cross-attention이 교차하지 않습니다.
(이 이미지는 Kijai 가 Banodoco 에 게시한 것인데, 출처는 여기 입니다)

텍스트 캡션은 텍스트 인코더 정렬 메커니즘을 통해 LoRA 가중치에 cross-attention 노이즈를 도입할 수 있으므로, 빈 캡션을 통해 이를 완전히 무시하는 것이 최소한의 노이즈를 무조건적으로 도입하는 방법일 수 있습니다. 그리고 Wan에서는 cross-attention이 "핵심" self-attention과 분리되어 있기 때문에, 빈 캡션을 사용하면 다른 블록을 방해하지 않고 텍스트 컨디셔닝을 효과적으로 "비활성화"할 수 있습니다.
(그러나 이것이 의미가 없어 보인다면 죄송합니다. 저는 설명을 찾으려 노력했고, 이는 제 최선의 추측이며, 경험적 관찰과 Gemini Pro의 도움을 기반으로 합니다.)
학습
학습에는 일반적으로 Musubi Tuner를 사용했습니다. (Windows 11, RTX 3090, 64 GB RAM.)
이미지를 기반으로 학습할 수 있었기 때문에, 차등 LoRA의 한 구성 요소를 학습하는 것이 매우 빠르게 이루어졌습니다. 또한, 제가 실제로 세부사항 자체를 가르치려는 것이 아니라 "밀집"과 "희박" 사이의 차이를 포착하기만 하면 되었기 때문에, 192p 해상도로 학습할 수 있었습니다. 사실, 구체적인 세부사항을 배우는 것을 피하려 했고, 목표는 내용의 차이가 아니라 추상적인 대비를 분리하는 것이었습니다.
그 결과, 저는 일반적으로 2~3시간 만에 두 개의 복합 LoRA를 학습할 수 있었고, 다양한 설정을 실험할 여유가 많았습니다. 여러 학습 구성 방식을 시도한 후, 최종적으로 Lion 옵티마이저, lr=2e-5, 50 warmup_step을 가진 constant_with_warmup 스케줄러, LoRA 랭크 16, 5000 스텝, 배치 크기 1을 선택했습니다. (모든 구성 파일을 학습 데이터에 포함시켰으므로 여기서는 자세히 설명하지 않겠습니다.)
솔직히, 이 설정들이 그렇게 큰 차이를 만들지 않았다고 생각합니다. 다양한 옵티마이저, 스텝 수, 학습률, 스케줄러 파라미터를 실험했지만, 어떤 선택도 큰 차이를 만들지 않았습니다. 또한 "혼잡함"과 같은 추상적 개념에 앞서, 단순한 낮/밤 LoRA를 만들어 연습했습니다: 낮 시간 장면 20장과 Kontext로 생성한 그에 대응하는 밤 장면. 다양한 설정으로 여러 번 학습했습니다. 공유 데이터셋에 단 40장의 이미지만 사용했지만, 한 시간도 넘지 않았습니다. 이 실험에서 가장 효과적이었던 설정이 바로 후에 Anime Denser 학습에 사용한 설정입니다.
따라서 제 의견으로는, 데이터셋의 "순도"와 차등 스크립트에 전달된 매개변수(아래 참고 👇)가 가장 중요합니다.
두 구성 요소 LoRA 학습 중에 얻은 샘플 이미지들은 상당히 나빴습니다. 하지만 이는 좋았습니다. 왜냐하면 제가 기대했던 것이 바로 그것이었기 때문입니다(192x192 해상도의 정적 이미지로 학습하면서 깨끗한 결과를 기대할 수 있나요?). 하지만 가장 놀라운 점은 두 세트의 샘플 모두 유사하게 나빴지만, 중요한 차이점이 있었습니다: 밀집 LoRA는 구성을 혼잡하게 만드는 방법을 명확히 기억했고, 희박 LoRA는 공허하고 무미건조한 환경을 재현하는 방법을 배웠습니다. 따라서, 뺄셈 과정에서 모든 "컨텍스트 인식" 특성이 효과적으로 상쇄되어 최종 LoRA에 환경 밀도와 세부성 개념만 남을 것이라고 기대할 수 있었습니다. 그때, 저는 조리할 준비가 되었다고 느꼈습니다 👨🍳.
차등 LoRA
두 LoRA를 얻은 후, 하나의 LoRA를 다른 LoRA에서 빼야 했습니다. 다행히 ComfyTinker가 이를 수행하는 방법에 대한 자세한 지침을 공유해 주셨습니다(이미 앞서 링크했습니다). 하지만 실제 코드는 제공하지 않았습니다. 그러나 13년 이상의 소프트웨어 개발 경험을 가진 저로서는 두려움이 없었고, 무엇을 해야 할지 알고 있었습니다. Cursor를 열고 지침을 붙여넣은 후, 이를 기반으로 스크립트를 생성하라고 지시했습니다.
이후 저는 초기 스크립트의 다양한 개선 사항을 실험했습니다(여기서는 설명하지 않겠습니다. 아직 작업 중이기 때문입니다). 예: 이름 패턴 및/또는 숫자 인덱스로 특정 블록을 타겟팅, 대상 정규화를 기반으로 alpha 값 자동 계산, 병합에 참여할 레이어 필터링(크기 임계값 사용), 백분위 기반 필터링을 통한 자동 임계값 계산, 차이 크기를 계산하여 가장 구별적인 레이어 찾기, 빠른 무작위 SVD를 추가하여 빠른 프로토타이핑, 디버깅을 위한 블록 구조 분석, 비타겟 레이어를 출력에서 nullify하거나 완전히 제외하는 옵션 등. 이 스크립트는 향후 차등 LoRA 프로젝트를 위해 계속 수정하고 개선할 예정입니다. 하지만 현재 버전만으로도 충분히 기능을 수행합니다. (차등 LoRA 생성 스크립트도 학습 데이터 아카이브에 포함시켰습니다.)
이 텍스트의 크기를 사용 방법에 대한 자세한 지침으로 늘리지 않겠습니다(댓글에서 요청하지 않는 한). 하지만 기본적으로 이 도구는 두 입력 LoRA 간의 차이를 계산하여 새로운 LoRA를 생성합니다. 아래는 제가 차이 LoRA를 생성할 때 사용한 정확한 명령어입니다:
python differential_lora.py ^
--lora_a animedenser_pos_wan14b.safetensors ^
--lora_b animedenser_neg_wan14b.safetensors ^
--target_blocks attn ^
--output animedenser_v01rc.safetensors ^
--rank 4 ^
--dtype float32 ^
--alpha 1.0 ^
--device cuda ^
--analyze_blocks ^
--exclude_non_targeted
(저는 이 매개변수들이 프로세스에 어떤 영향을 미치는지 명확히 이해하지 못한 채 많은 파라미터를 시도해봤습니다. 더 효과적인 방식으로 병합 LoRA를 생성할 수 있는 방법이 있을 수도 있습니다.)
병합 시, 저는 어텐션 레이어만 대상으로 지정했습니다(--target_blocks attn). 따라서 결과 LoRA는 모델의 어텐션 메커니즘에만 영향을 주며, 모든 다른 블록은 대상 LoRA에서 제외됩니다(제로화되지 않고 단순히 제외됨; _--exclude_non_targeted_를 생략하면 이 블록들이 제로화되어 기본 모델의 가중치와 간섭이 더 심해집니다). 그 외 모든 레이어(피드포워드, 정규화 등)는 기본 모델의 가중치를 그대로 사용합니다. 저는 어텐션(특히 크로스 어텐션) 블록이 구성적 밀도를 담는 데 가장 적합하다고 판단했습니다. 그리고 그 결과는 성공적이었던 것 같습니다🤷♂️
선택한 알파 값은 경험적으로 결정한 것이며, 반드시 최적은 아닙니다. (저는 "최적" 알파를 자동으로 계산하는 기능을 구현해 보았지만, 예상대로 작동하지 않았고 오히려 출력 LoRA의 효과를 감소시켰습니다.)
이 스크립트를 사용하려는 경우, SVD는 매우 비싼 연산이라는 점을 인지하세요. RTX 3090에서도 랭크 16의 두 LoRA를 랭크 4의 차이 LoRA로 병합하는 데 약 1시간이 걸렸습니다. 더 빠른 테스트를 위해 --fast_svd 플래그와 함께 스크립트를 사용할 수 있습니다. 이 옵션은 특이값 분해의 손실 근사 방법을 사용하여 약 5~10초 내에 병합 LoRA를 생성해 효과를 추정할 수 있게 해줍니다. 결과가 유망해 보이면, 이후에 전체 SVD 분해를 실행해 최적의 병합을 얻을 수 있습니다.
결론
이 LoRA는 모든 생산 환경에서 실용적이지는 않을 수 있습니다( WanVideo와 같은 강력한 모델의 경우, 프롬프트에 “혼잡함” 또는 “공허함”을 직접 요청하는 것이 더 효과적일 수 있습니다). 하지만 저는 얻은 결과가 마음에 들었고, 이 LoRA가 실용성 때문에 중요하다고 말하진 않지만, '혼잡함'과 같은 추상적이고 '분산된' 개념에도 이 개념과 방법이 작동함을 입증했다고 생각합니다.
누군가 이 결과를 유용하게 활용하고 이 방법을 발전시키길 바라며 공유합니다. 더 많은 사람들이 이 방법론을 채택하고 더 발전시켜주기를 바랍니다. 이는 비디오 모델용 슬라이더를 비교적 저렴하고 안정적으로 구축하는 방법이며, 잠재력이 매우 크다고 생각합니다. (저는 개인적으로 모션 강화기, 블러 제거기, 실제 디테일러, 그리고 몇 가지 더 진기한 아이디어를 훈련하는 데 관심이 있습니다.)
💾 이 LoRA를 재현하는 데 필요한 모든 학습 자료(데이터셋, 설정, 스크립트)를 포함했습니다. 이 분야에는 여전히 탐구할 것이 많이 있으며, 제 스크립트와 방법은 아직 완벽하거나 정밀한 수준에 도달하지 못했습니다. 예를 들어, 특정 블록에 대해서만 LoRA를 훈련하거나 병합 시 특정 블록을 건너뛰는 것이 유익할 수 있습니다. 저는 초기 블록(0–10)만, 중간 블록만, 또는 둘 다 병합해 효과를 개선해보려 했지만 명확한 이점은 찾지 못했습니다. 또한 어떤 블록이 어떤 기능을 담당하는지 이해하기 위해 Wan DiT 블록을 켜고 끄는 간단한 노드를 만들기도 했습니다. (HV 학습에서, 제가 기억하기로는 이미지에 대해 LoRA를 학습할 때 더블 블록을 건너뛰는 것이 보편적이었습니다.) 불행히도 이 시도는 가장 효과적인 전략을 규명하는 데 도움이 되지 않았습니다. 제가 사용한 병합 명령어에서 볼 수 있듯이, 어텐션 블록만 집중했고, 이들이 장면의 무조건적(프롬프트 독립적) '형성'을 담당한다고 가정했습니다. 이 접근법이 모든 블록을 병합하는 것보다 더 나은 결과를 낳았습니다.
🤔 또한, 정지 이미지로 학습하는 것이(적어도 계산적 측면에서는) 효과가 있음을 입증했지만, 모델의 움직임 능력을 감소시킬 수 있는 잠재적 노이즈를 도입할 수도 있다고 생각합니다(이 문제를 곧 해결하고 다음 차이 LoRA를 비디오로 학습하려고 계획 중입니다).
🚀 또한, Flux Kontext는 제게 생명선이 되었습니다. 이미 모두가 알고 있듯이, Kontext는 생성할 수 없는 소스 이미지를 입력하여 그 이미지를 이해할 수 있는 형태로 쉽게 효과적으로 변환할 수 있게 해줍니다. 저는 이것이 이미지 학습을 넘어서 더 많은 용도를 가질 수 있다고 생각합니다. 아마도 그 힘을 활용하는 새로운 혁신적 방법들이 곧 등장할지도 모릅니다.
감사의 말씀
🏆 처음에 언급했듯이, 이 방법은 ComfyTinker가 처음으로 설명했습니다. 그분이 이 방법을 커뮤니티와 공유해 주지 않았다면, 저에게는 이 방법을 재현하는 것이 불가능했거나, 적어도 훨씬 더 많은 시간이 걸렸을 것입니다.
🏆 self forcing training method의 저자들에게도 큰 감사를 드립니다. 이 방법 덕분에 LightX2V 프로젝트가 가능했고, 그들의 Wan distilled 모델에서 blyss가 Wan Accelerator LoRA를 추출해냈으며, comfyanonymous가 ComfyUI를 만들었고, 마지막으로 Kijai가 WanVideoWrapper에서 뛰어난 작업을 해주었습니다.
🏆 마지막으로, 매일 Wan 관련(그리고 기타) 채널에서 귀중한 정보를 공유해주는 모든 banodocians에게 환호의 박수를 보냅니다. 그분들의 통찰과 아이디어는 이 LoRA를 만드는 데 큰 도움이 되었고 크게 기여했습니다.
