定制屬于你自己的 Stable Diffusion
我們很幸運生活在AI時代。人工智能迅速發展,現在變得更加易于獲取。大多數開源模型都經過了充分的訓練,擁有來自廣泛類別的合理數量的數據,因此我們可以生成許多不同類別的圖像。如果模型從未學習過我們想要生成的特定主題怎么辦?例如,我想要生成我今天早上剛做的蛋糕的圖像。盡管模型可以生成無數種蛋糕圖像,但模型不知道如何生成我剛剛制作的蛋糕的圖像。
盡管從頭開始訓練對個人來說幾乎是不可能的,但由于不斷發展的模型微調技術,將新主題納入模型可以輕松實現。自2022年以來,Stable Diffusion作為最新趨勢的一代模型,為圖像生成開啟了一個全新的時代。在本文中,我想分享如何使用現代技術LoRA逐步微調Stable Diffusion模型的指南。整個練習在Kaggle筆記本上進行,這樣每個人都可以在沒有適當設備的情況下完成這個練習。
在我們開始實現之前,讓我們快速了解一下Stable Diffusion的概念和微調技術LoRA。如果你已經熟悉背后的知識,請隨時跳到實施部分。
Stable Diffusion
圖1. Stable Diffusion中的反向擴散
Stable Diffusion是一種可以從文本和圖像生成逼真照片的生成性AI模型。擴散模型在潛在空間而不是圖像空間中施展魔法,這使得圖像生成對公眾來說更加可行,因為所需的計算能力更低。人們甚至可以在CPU機器上的小憩期間生成一個不存在的圖像。
有許多在線的穩定擴散平臺供公眾和開發者使用,如HuggingFace1和Stable Diffusion Online2。我們可以在沒有機器學習知識的情況下生成圖像。
LoRA(低秩適應)
圖2. Stable Diffusion網絡
LoRA是一種微調方法,它在穩定擴散網絡的交叉注意力層中添加了額外的權重。交叉注意力層在圖2中由黃色塊表示。交叉注意力層融合了圖像ZT和文本τθ的中間信息。向交叉注意力層添加權重擴展了文本提示和圖像之間的相關性。這就是LoRA如何向穩定擴散模型引入新知識。
修改后的權重被分解為更小的(低秩)矩陣。這些較小的矩陣攜帶的參數更少,并單獨存儲。這就是為什么LoRA權重文件的尺寸可控,但必須與底層的Stable Diffusion模型一起使用。
LoRA的權重大小通常在2到200 MB之間。這是共享和管理模型的優勢之一。與其以幾GB的整個模型共享,更有效的方法是以更小的尺寸共享LoRA權重。
環境
這個練習是在Kaggle筆記本中進行的,環境設置如下:
- NVIDIA Tesla P100 (RAM=16G)
- diffusers-0.30.0.dev0
- Pytorch 2.1.2
- Python 3.10
Kaggle筆記本已經安裝了Python和PyTorch。我們需要安裝的唯一庫是來自HuggingFace的Diffusers。我們可以使用以下命令從源安裝Diffusers。從源安裝確保了庫的最新版本。路徑/kaggle/working是Kaggle運行時的默認工作空間。人們可以調整路徑以適應自己的開發環境。
%cd /kaggle/working/
!pip install accelerate
!git clone https://github.com/huggingface/diffusers%cd /kaggle/working/diffusers
!pip install /kaggle/working/diffusers/. -q
%cd /kaggle/working/diffusers/examples/text_to_image
!pip install -r /kaggle/working/diffusers/examples/text_to_image/requirements.txt -q
!pip install --upgrade peft transformers xformers bitsandbytes -q
實驗在這個練習中,我想向模型介紹蠟筆小新雕像。讓我們在以下各節中經歷步驟。
第1步:數據收集
圖3. 訓練樣本
首先,我們需要收集一些主題的圖像。在這個練習中,我們收集了25張蠟筆小新雕像的照片作為我們的訓練數據。一些樣本可以在圖3中找到。以下是我遵循的數據收集推薦提示:
- 統一圖像大小:例如,512x512。
- 高圖像質量:圖片以12M分辨率拍攝。
- 保持主題在圖像中心。
此外,訓練集中盡可能多地覆蓋多樣性也很重要,以便模型學習一般特征,如角色的眼睛、發型和身材。換句話說,我們希望模型學習什么是蠟筆小新雕像,而不是特定著裝風格(例如紅襯衫和黃色短褲)和姿勢(例如站立)。
我已經在5、15、25的培訓規模上進行了實驗。盡管每一輪之間只有10張圖像的差異,但模型的泛化程度有了顯著提高。
第2步:基線評估
from diffusers import AutoPipelineForText2Image
pipeline = AutoPipelineForText2Image.from_pretrained("runwayml/stable-diffusion-v1-5", torch_dtype=torch.float16).to("cuda")
prompt = "A crayon shin-chan figurine."
image = pipeline(prompt, num_inference_steps=100).images[0]
image.save("baseline.png")
在開始訓練之前,我們想檢查一下預訓練模型是否已經知道我們想要微調的特定雕像,使用上述Python腳本。
- AutoPipelineForText2Image類用于加載Stable Diffusion預訓練模型stable-diffusion-v1–5。
- 接下來,我們將文本提示設置為“A crayon shin-chan figurine”。我保持文本提示簡潔,以便文本信息對模型來說直接了當。
- 將提示和推理次數傳遞給AutoPipelineForText2Image的實例并進行生成過程。
圖4. 基線評估結果
腳本多次運行,圖4中展示了三個生成的圖像。結果顯示,預訓練模型知道可能是一個人角色的雕像,但不知道前綴‘crayon shin-chan’具體指的是哪個角色。生成圖像中的限制驗證了我們微調工作的努力,因為我們的倡議是用一個未見過的主體來微調模型。
第3步:微調
圖5. 蠟筆
定義一個新的標識符
除了收集一些訓練圖像外,我們還需要為這個主題選擇一個新的名稱。每當新名稱出現在文本提示中時,修改后的模型就會理解它指的是新的主題,并相應地生成內容。
我們為什么需要一個新的名稱?原始名稱Crayon Shin-Chan不是更具代表性嗎?我們這樣做的想法是,我們需要一個獨特的名稱,不要與已經訓練的其他現有名稱混在一起。在我們的例子中,內部的蠟筆暗示了與我們用于繪畫的蠟筆的潛在聯系。如果關聯的文本提示包含Crayon Shin-Chan,生成的圖像可能包括與蠟筆相關的內容。
建議使用隨機名稱作為新標識符。我為這個練習選擇了aawxbc這個名字,它幾乎不會與任何現有名稱重疊。其他人也可以為新主題使用任何其他獨特的名稱。
訓練
圖6. 模型生成的類別圖像
在Kaggle筆記本中,除了工作區:/kaggle/working/,另一個常用的目錄是/kaggle/input/,我們在這里存儲工作的輸入,如檢查點和訓練圖像。以下是基于腳本train_dreambooth_lora.py的完整訓練命令。
!accelerate config default
!mkdir /kaggle/working/figurine
!accelerate launch --mixed_precision="fp16" /kaggle/working/diffusers/examples/dreambooth/train_dreambooth_lora.py
--mixed_precision="fp16"
--pretrained_model_name_or_path="runwayml/stable-diffusion-v1-5"
--instance_data_dir="/kaggle/input/aawxbc"
--instance_prompt="a photo of aawxbc figurine"
--class_data_dir="/kaggle/working/figurine"
--class_prompt="a photo of figurine"
--with_prior_preservation
--prior_loss_weight=1.0
--use_8bit_adam
--lr_scheduler="constant"
--gradient_checkpointing
--enable_xformers_memory_efficient_attention
--num_train_epochs=50
--output_dir="/kaggle/working/dreambooth-lora"
讓我們經歷一些關鍵配置:
- mixed_precision [可選]:選擇平臺支持的精度。選項有fp32、fp16和bf16。
- class_prompt [可選]:存儲類別數據的提示和文件夾。在這個實驗中,類別名稱是figurine,因為我們希望擴散模型學習一種新的雕像類型。
- class_data_dir [可選]:存儲模型生成的類別圖像的目錄。在我們的例子中,模型生成了一般的雕像圖像并將其保存在這個目錄下。
- instance_prompt [必須]:我們為新主題定義了一個文本提示。格式是{新名稱} {類別名稱},例如aawxbc figurine、uvhhhl cat等。
- instance_data_dir [必須]:存儲訓練樣本的目錄。在這個練習中,我們將前面提到的25個樣本上傳到這個目錄。
- num_train_epochs [可選]:訓練的輪數。
通過遵循上述步驟,包括數據收集、安裝庫和完成訓練,我們現在可以在由output_dir定義的目錄中找到LoRA權重pytorch_lora_weights.safetensors。權重文件的大小為3.2 MB,相當容易管理。
第4步:推理—生成新圖像
from diffusers import AutoPipelineForText2Image
pipeline = AutoPipelineForText2Image.from_pretrained("runwayml/stable-diffusion-v1-5", torch_dtype=torch.float16).to("cuda")
pipeline.load_lora_weights("/kaggle/working/dreambooth-lora", weight_name="pytorch_lora_weights.safetensors")
prompt = "A photo of aawxbc figurine."
image = pipeline(prompt, num_inference_steps=180).images[0]
image.save("aawxbc.png")
在成功導出LoRA權重后,我們可以進入最后也是最令人興奮的部分:生成新圖像。請注意,LoRA權重不能獨立工作,因此我們需要同時加載原始的穩定擴散和LoRA權重文件。
在Python腳本中,除了我們在基線評估中使用的步驟外,我們還有一個額外的步驟,使用.load_lora_weights()函數加載LoRA模型,傳入目錄和LoRA權重文件的名稱。
圖7. 使用提示生成的圖像:“沙灘上的aawxbc雕像,戴著帽子”
對于文本提示,我們在腳本中包含了標識符aawxbc和類別名稱figurine。兩組相應文本提示生成的圖像分別在圖7和圖8中展示。我們可以看到,經過微調的模型可以生成蠟筆小新雕像。
圖8. 使用提示生成的圖像:“森林里的aawxbc雕像,拿著杯子。”
我們可以通過注釋掉加載LoRA權重的行并保持文本提示不變來進一步交叉驗證新模型。我們可以看到原始的穩定擴散模型無法正確解釋標識符aawxbc,這與基線評估一致,并突出了LoRA模型的貢獻。
總結
圖9. 微調概述
工作的概述在圖9中展示。新模型結合了LoRA權重,并且可以生成帶有新實例名稱aawxbc的蠟筆小新雕像的圖像,如綠色矩形突出所示。我們所要做的就是收集足夠的圖像,并用不存在的標識符命名新主題。就這些。所有的艱苦工作都在代碼中完成了。
參考文獻:
- [1] https://huggingface.co/spaces/stabilityai/stable-diffusion
- [2] https://stablediffusionweb.com/