Upload notebooks/FLUX_1_schnell_LoRA_Training.ipynb with huggingface_hub
Browse files
notebooks/FLUX_1_schnell_LoRA_Training.ipynb
ADDED
|
@@ -0,0 +1,296 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"cells": [
|
| 3 |
+
{
|
| 4 |
+
"cell_type": "markdown",
|
| 5 |
+
"metadata": {
|
| 6 |
+
"collapsed": false,
|
| 7 |
+
"id": "zl-S0m3pkQC5"
|
| 8 |
+
},
|
| 9 |
+
"source": [
|
| 10 |
+
"# AI Toolkit by Ostris\n",
|
| 11 |
+
"## FLUX.1-schnell Training\n"
|
| 12 |
+
]
|
| 13 |
+
},
|
| 14 |
+
{
|
| 15 |
+
"cell_type": "code",
|
| 16 |
+
"execution_count": null,
|
| 17 |
+
"metadata": {
|
| 18 |
+
"id": "3cokMT-WC6rG"
|
| 19 |
+
},
|
| 20 |
+
"outputs": [],
|
| 21 |
+
"source": [
|
| 22 |
+
"!nvidia-smi"
|
| 23 |
+
]
|
| 24 |
+
},
|
| 25 |
+
{
|
| 26 |
+
"cell_type": "code",
|
| 27 |
+
"execution_count": null,
|
| 28 |
+
"metadata": {
|
| 29 |
+
"collapsed": true,
|
| 30 |
+
"id": "BvAG0GKAh59G"
|
| 31 |
+
},
|
| 32 |
+
"outputs": [],
|
| 33 |
+
"source": [
|
| 34 |
+
"!git clone https://github.com/ostris/ai-toolkit\n",
|
| 35 |
+
"!mkdir -p /content/dataset"
|
| 36 |
+
]
|
| 37 |
+
},
|
| 38 |
+
{
|
| 39 |
+
"cell_type": "markdown",
|
| 40 |
+
"metadata": {
|
| 41 |
+
"id": "UFUW4ZMmnp1V"
|
| 42 |
+
},
|
| 43 |
+
"source": [
|
| 44 |
+
"Put your image dataset in the `/content/dataset` folder"
|
| 45 |
+
]
|
| 46 |
+
},
|
| 47 |
+
{
|
| 48 |
+
"cell_type": "code",
|
| 49 |
+
"execution_count": null,
|
| 50 |
+
"metadata": {
|
| 51 |
+
"collapsed": true,
|
| 52 |
+
"id": "XGZqVER_aQJW"
|
| 53 |
+
},
|
| 54 |
+
"outputs": [],
|
| 55 |
+
"source": [
|
| 56 |
+
"!cd ai-toolkit && git submodule update --init --recursive && pip install -r requirements.txt\n"
|
| 57 |
+
]
|
| 58 |
+
},
|
| 59 |
+
{
|
| 60 |
+
"cell_type": "markdown",
|
| 61 |
+
"metadata": {
|
| 62 |
+
"id": "OV0HnOI6o8V6"
|
| 63 |
+
},
|
| 64 |
+
"source": [
|
| 65 |
+
"## Model License\n",
|
| 66 |
+
"Training currently only works with FLUX.1-dev. Which means anything you train will inherit the non-commercial license. It is also a gated model, so you need to accept the license on HF before using it. Otherwise, this will fail. Here are the required steps to setup a license.\n",
|
| 67 |
+
"\n",
|
| 68 |
+
"Sign into HF and accept the model access here [black-forest-labs/FLUX.1-dev](https://huggingface.co/black-forest-labs/FLUX.1-dev)\n",
|
| 69 |
+
"\n",
|
| 70 |
+
"[Get a READ key from huggingface](https://huggingface.co/settings/tokens/new?) and place it in the next cell after running it."
|
| 71 |
+
]
|
| 72 |
+
},
|
| 73 |
+
{
|
| 74 |
+
"cell_type": "code",
|
| 75 |
+
"execution_count": null,
|
| 76 |
+
"metadata": {
|
| 77 |
+
"id": "3yZZdhFRoj2m"
|
| 78 |
+
},
|
| 79 |
+
"outputs": [],
|
| 80 |
+
"source": [
|
| 81 |
+
"import getpass\n",
|
| 82 |
+
"import os\n",
|
| 83 |
+
"\n",
|
| 84 |
+
"# Prompt for the token\n",
|
| 85 |
+
"hf_token = getpass.getpass('Enter your HF access token and press enter: ')\n",
|
| 86 |
+
"\n",
|
| 87 |
+
"# Set the environment variable\n",
|
| 88 |
+
"os.environ['HF_TOKEN'] = hf_token\n",
|
| 89 |
+
"\n",
|
| 90 |
+
"print(\"HF_TOKEN environment variable has been set.\")"
|
| 91 |
+
]
|
| 92 |
+
},
|
| 93 |
+
{
|
| 94 |
+
"cell_type": "code",
|
| 95 |
+
"execution_count": 5,
|
| 96 |
+
"metadata": {
|
| 97 |
+
"id": "9gO2EzQ1kQC8"
|
| 98 |
+
},
|
| 99 |
+
"outputs": [],
|
| 100 |
+
"source": [
|
| 101 |
+
"import os\n",
|
| 102 |
+
"import sys\n",
|
| 103 |
+
"sys.path.append('/content/ai-toolkit')\n",
|
| 104 |
+
"from toolkit.job import run_job\n",
|
| 105 |
+
"from collections import OrderedDict\n",
|
| 106 |
+
"from PIL import Image\n",
|
| 107 |
+
"import os\n",
|
| 108 |
+
"os.environ[\"HF_HUB_ENABLE_HF_TRANSFER\"] = \"1\""
|
| 109 |
+
]
|
| 110 |
+
},
|
| 111 |
+
{
|
| 112 |
+
"cell_type": "markdown",
|
| 113 |
+
"metadata": {
|
| 114 |
+
"id": "N8UUFzVRigbC"
|
| 115 |
+
},
|
| 116 |
+
"source": [
|
| 117 |
+
"## Setup\n",
|
| 118 |
+
"\n",
|
| 119 |
+
"This is your config. It is documented pretty well. Normally you would do this as a yaml file, but for colab, this will work. This will run as is without modification, but feel free to edit as you want."
|
| 120 |
+
]
|
| 121 |
+
},
|
| 122 |
+
{
|
| 123 |
+
"cell_type": "code",
|
| 124 |
+
"execution_count": 6,
|
| 125 |
+
"metadata": {
|
| 126 |
+
"id": "_t28QURYjRQO"
|
| 127 |
+
},
|
| 128 |
+
"outputs": [],
|
| 129 |
+
"source": [
|
| 130 |
+
"from collections import OrderedDict\n",
|
| 131 |
+
"\n",
|
| 132 |
+
"job_to_run = OrderedDict([\n",
|
| 133 |
+
" ('job', 'extension'),\n",
|
| 134 |
+
" ('config', OrderedDict([\n",
|
| 135 |
+
" # this name will be the folder and filename name\n",
|
| 136 |
+
" ('name', 'my_first_flux_lora_v1'),\n",
|
| 137 |
+
" ('process', [\n",
|
| 138 |
+
" OrderedDict([\n",
|
| 139 |
+
" ('type', 'sd_trainer'),\n",
|
| 140 |
+
" # root folder to save training sessions/samples/weights\n",
|
| 141 |
+
" ('training_folder', '/content/output'),\n",
|
| 142 |
+
" # uncomment to see performance stats in the terminal every N steps\n",
|
| 143 |
+
" #('performance_log_every', 1000),\n",
|
| 144 |
+
" ('device', 'cuda:0'),\n",
|
| 145 |
+
" # if a trigger word is specified, it will be added to captions of training data if it does not already exist\n",
|
| 146 |
+
" # alternatively, in your captions you can add [trigger] and it will be replaced with the trigger word\n",
|
| 147 |
+
" # ('trigger_word', 'image'),\n",
|
| 148 |
+
" ('network', OrderedDict([\n",
|
| 149 |
+
" ('type', 'lora'),\n",
|
| 150 |
+
" ('linear', 16),\n",
|
| 151 |
+
" ('linear_alpha', 16)\n",
|
| 152 |
+
" ])),\n",
|
| 153 |
+
" ('save', OrderedDict([\n",
|
| 154 |
+
" ('dtype', 'float16'), # precision to save\n",
|
| 155 |
+
" ('save_every', 250), # save every this many steps\n",
|
| 156 |
+
" ('max_step_saves_to_keep', 4) # how many intermittent saves to keep\n",
|
| 157 |
+
" ])),\n",
|
| 158 |
+
" ('datasets', [\n",
|
| 159 |
+
" # datasets are a folder of images. captions need to be txt files with the same name as the image\n",
|
| 160 |
+
" # for instance image2.jpg and image2.txt. Only jpg, jpeg, and png are supported currently\n",
|
| 161 |
+
" # images will automatically be resized and bucketed into the resolution specified\n",
|
| 162 |
+
" OrderedDict([\n",
|
| 163 |
+
" ('folder_path', '/content/dataset'),\n",
|
| 164 |
+
" ('caption_ext', 'txt'),\n",
|
| 165 |
+
" ('caption_dropout_rate', 0.05), # will drop out the caption 5% of time\n",
|
| 166 |
+
" ('shuffle_tokens', False), # shuffle caption order, split by commas\n",
|
| 167 |
+
" ('cache_latents_to_disk', True), # leave this true unless you know what you're doing\n",
|
| 168 |
+
" ('resolution', [512, 768, 1024]) # flux enjoys multiple resolutions\n",
|
| 169 |
+
" ])\n",
|
| 170 |
+
" ]),\n",
|
| 171 |
+
" ('train', OrderedDict([\n",
|
| 172 |
+
" ('batch_size', 1),\n",
|
| 173 |
+
" ('steps', 2000), # total number of steps to train 500 - 4000 is a good range\n",
|
| 174 |
+
" ('gradient_accumulation_steps', 1),\n",
|
| 175 |
+
" ('train_unet', True),\n",
|
| 176 |
+
" ('train_text_encoder', False), # probably won't work with flux\n",
|
| 177 |
+
" ('gradient_checkpointing', True), # need the on unless you have a ton of vram\n",
|
| 178 |
+
" ('noise_scheduler', 'flowmatch'), # for training only\n",
|
| 179 |
+
" ('optimizer', 'adamw8bit'),\n",
|
| 180 |
+
" ('lr', 1e-4),\n",
|
| 181 |
+
"\n",
|
| 182 |
+
" # uncomment this to skip the pre training sample\n",
|
| 183 |
+
" # ('skip_first_sample', True),\n",
|
| 184 |
+
"\n",
|
| 185 |
+
" # uncomment to completely disable sampling\n",
|
| 186 |
+
" # ('disable_sampling', True),\n",
|
| 187 |
+
"\n",
|
| 188 |
+
" # uncomment to use new vell curved weighting. Experimental but may produce better results\n",
|
| 189 |
+
" # ('linear_timesteps', True),\n",
|
| 190 |
+
"\n",
|
| 191 |
+
" # ema will smooth out learning, but could slow it down. Recommended to leave on.\n",
|
| 192 |
+
" ('ema_config', OrderedDict([\n",
|
| 193 |
+
" ('use_ema', True),\n",
|
| 194 |
+
" ('ema_decay', 0.99)\n",
|
| 195 |
+
" ])),\n",
|
| 196 |
+
"\n",
|
| 197 |
+
" # will probably need this if gpu supports it for flux, other dtypes may not work correctly\n",
|
| 198 |
+
" ('dtype', 'bf16')\n",
|
| 199 |
+
" ])),\n",
|
| 200 |
+
" ('model', OrderedDict([\n",
|
| 201 |
+
" # huggingface model name or path\n",
|
| 202 |
+
" ('name_or_path', 'black-forest-labs/FLUX.1-schnell'),\n",
|
| 203 |
+
" ('assistant_lora_path', 'ostris/FLUX.1-schnell-training-adapter'), # Required for flux schnell training\n",
|
| 204 |
+
" ('is_flux', True),\n",
|
| 205 |
+
" ('quantize', True), # run 8bit mixed precision\n",
|
| 206 |
+
" # low_vram is painfully slow to fuse in the adapter avoid it unless absolutely necessary\n",
|
| 207 |
+
" #('low_vram', True), # uncomment this if the GPU is connected to your monitors. It will use less vram to quantize, but is slower.\n",
|
| 208 |
+
" ])),\n",
|
| 209 |
+
" ('sample', OrderedDict([\n",
|
| 210 |
+
" ('sampler', 'flowmatch'), # must match train.noise_scheduler\n",
|
| 211 |
+
" ('sample_every', 250), # sample every this many steps\n",
|
| 212 |
+
" ('width', 1024),\n",
|
| 213 |
+
" ('height', 1024),\n",
|
| 214 |
+
" ('prompts', [\n",
|
| 215 |
+
" # you can add [trigger] to the prompts here and it will be replaced with the trigger word\n",
|
| 216 |
+
" #'[trigger] holding a sign that says \\'I LOVE PROMPTS!\\'',\n",
|
| 217 |
+
" 'woman with red hair, playing chess at the park, bomb going off in the background',\n",
|
| 218 |
+
" 'a woman holding a coffee cup, in a beanie, sitting at a cafe',\n",
|
| 219 |
+
" 'a horse is a DJ at a night club, fish eye lens, smoke machine, lazer lights, holding a martini',\n",
|
| 220 |
+
" 'a man showing off his cool new t shirt at the beach, a shark is jumping out of the water in the background',\n",
|
| 221 |
+
" 'a bear building a log cabin in the snow covered mountains',\n",
|
| 222 |
+
" 'woman playing the guitar, on stage, singing a song, laser lights, punk rocker',\n",
|
| 223 |
+
" 'hipster man with a beard, building a chair, in a wood shop',\n",
|
| 224 |
+
" 'photo of a man, white background, medium shot, modeling clothing, studio lighting, white backdrop',\n",
|
| 225 |
+
" 'a man holding a sign that says, \\'this is a sign\\'',\n",
|
| 226 |
+
" 'a bulldog, in a post apocalyptic world, with a shotgun, in a leather jacket, in a desert, with a motorcycle'\n",
|
| 227 |
+
" ]),\n",
|
| 228 |
+
" ('neg', ''), # not used on flux\n",
|
| 229 |
+
" ('seed', 42),\n",
|
| 230 |
+
" ('walk_seed', True),\n",
|
| 231 |
+
" ('guidance_scale', 1), # schnell does not do guidance\n",
|
| 232 |
+
" ('sample_steps', 4) # 1 - 4 works well\n",
|
| 233 |
+
" ]))\n",
|
| 234 |
+
" ])\n",
|
| 235 |
+
" ])\n",
|
| 236 |
+
" ])),\n",
|
| 237 |
+
" # you can add any additional meta info here. [name] is replaced with config name at top\n",
|
| 238 |
+
" ('meta', OrderedDict([\n",
|
| 239 |
+
" ('name', '[name]'),\n",
|
| 240 |
+
" ('version', '1.0')\n",
|
| 241 |
+
" ]))\n",
|
| 242 |
+
"])\n"
|
| 243 |
+
]
|
| 244 |
+
},
|
| 245 |
+
{
|
| 246 |
+
"cell_type": "markdown",
|
| 247 |
+
"metadata": {
|
| 248 |
+
"id": "h6F1FlM2Wb3l"
|
| 249 |
+
},
|
| 250 |
+
"source": [
|
| 251 |
+
"## Run it\n",
|
| 252 |
+
"\n",
|
| 253 |
+
"Below does all the magic. Check your folders to the left. Items will be in output/LoRA/your_name_v1 In the samples folder, there are preiodic sampled. This doesnt work great with colab. They will be in /content/output"
|
| 254 |
+
]
|
| 255 |
+
},
|
| 256 |
+
{
|
| 257 |
+
"cell_type": "code",
|
| 258 |
+
"execution_count": null,
|
| 259 |
+
"metadata": {
|
| 260 |
+
"id": "HkajwI8gteOh"
|
| 261 |
+
},
|
| 262 |
+
"outputs": [],
|
| 263 |
+
"source": [
|
| 264 |
+
"run_job(job_to_run)\n"
|
| 265 |
+
]
|
| 266 |
+
},
|
| 267 |
+
{
|
| 268 |
+
"cell_type": "markdown",
|
| 269 |
+
"metadata": {
|
| 270 |
+
"id": "Hblgb5uwW5SD"
|
| 271 |
+
},
|
| 272 |
+
"source": [
|
| 273 |
+
"## Done\n",
|
| 274 |
+
"\n",
|
| 275 |
+
"Check your ourput dir and get your slider\n"
|
| 276 |
+
]
|
| 277 |
+
}
|
| 278 |
+
],
|
| 279 |
+
"metadata": {
|
| 280 |
+
"accelerator": "GPU",
|
| 281 |
+
"colab": {
|
| 282 |
+
"gpuType": "A100",
|
| 283 |
+
"machine_shape": "hm",
|
| 284 |
+
"provenance": []
|
| 285 |
+
},
|
| 286 |
+
"kernelspec": {
|
| 287 |
+
"display_name": "Python 3",
|
| 288 |
+
"name": "python3"
|
| 289 |
+
},
|
| 290 |
+
"language_info": {
|
| 291 |
+
"name": "python"
|
| 292 |
+
}
|
| 293 |
+
},
|
| 294 |
+
"nbformat": 4,
|
| 295 |
+
"nbformat_minor": 0
|
| 296 |
+
}
|