comdoleger commited on
Commit
513d887
·
verified ·
1 Parent(s): 4e36f4e

Upload notebooks/SliderTraining.ipynb with huggingface_hub

Browse files
Files changed (1) hide show
  1. notebooks/SliderTraining.ipynb +339 -0
notebooks/SliderTraining.ipynb ADDED
@@ -0,0 +1,339 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "nbformat": 4,
3
+ "nbformat_minor": 0,
4
+ "metadata": {
5
+ "colab": {
6
+ "provenance": [],
7
+ "machine_shape": "hm",
8
+ "gpuType": "V100"
9
+ },
10
+ "kernelspec": {
11
+ "name": "python3",
12
+ "display_name": "Python 3"
13
+ },
14
+ "language_info": {
15
+ "name": "python"
16
+ },
17
+ "accelerator": "GPU"
18
+ },
19
+ "cells": [
20
+ {
21
+ "cell_type": "markdown",
22
+ "source": [
23
+ "# AI Toolkit by Ostris\n",
24
+ "## Slider Training\n",
25
+ "\n",
26
+ "This is a quick colab demo for training sliders like can be found in my CivitAI profile https://civitai.com/user/Ostris/models . I will work on making it more user friendly, but for now, it will get you started."
27
+ ],
28
+ "metadata": {
29
+ "collapsed": false
30
+ }
31
+ },
32
+ {
33
+ "cell_type": "code",
34
+ "source": [
35
+ "!git clone https://github.com/ostris/ai-toolkit"
36
+ ],
37
+ "metadata": {
38
+ "id": "BvAG0GKAh59G"
39
+ },
40
+ "execution_count": null,
41
+ "outputs": []
42
+ },
43
+ {
44
+ "cell_type": "code",
45
+ "execution_count": null,
46
+ "metadata": {
47
+ "id": "XGZqVER_aQJW"
48
+ },
49
+ "outputs": [],
50
+ "source": [
51
+ "!cd ai-toolkit && git submodule update --init --recursive && pip install -r requirements.txt\n"
52
+ ]
53
+ },
54
+ {
55
+ "cell_type": "code",
56
+ "source": [
57
+ "import os\n",
58
+ "import sys\n",
59
+ "sys.path.append('/content/ai-toolkit')\n",
60
+ "from toolkit.job import run_job\n",
61
+ "from collections import OrderedDict\n",
62
+ "from PIL import Image"
63
+ ],
64
+ "metadata": {
65
+ "collapsed": false
66
+ },
67
+ "outputs": []
68
+ },
69
+ {
70
+ "cell_type": "markdown",
71
+ "source": [
72
+ "## Setup\n",
73
+ "\n",
74
+ "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."
75
+ ],
76
+ "metadata": {
77
+ "id": "N8UUFzVRigbC"
78
+ }
79
+ },
80
+ {
81
+ "cell_type": "code",
82
+ "source": [
83
+ "from collections import OrderedDict\n",
84
+ "\n",
85
+ "job_to_run = OrderedDict({\n",
86
+ " # This is the config I use on my sliders, It is solid and tested\n",
87
+ " 'job': 'train',\n",
88
+ " 'config': {\n",
89
+ " # the name will be used to create a folder in the output folder\n",
90
+ " # it will also replace any [name] token in the rest of this config\n",
91
+ " 'name': 'detail_slider_v1',\n",
92
+ " # folder will be created with name above in folder below\n",
93
+ " # it can be relative to the project root or absolute\n",
94
+ " 'training_folder': \"output/LoRA\",\n",
95
+ " 'device': 'cuda', # cpu, cuda:0, etc\n",
96
+ " # for tensorboard logging, we will make a subfolder for this job\n",
97
+ " 'log_dir': \"output/.tensorboard\",\n",
98
+ " # you can stack processes for other jobs, It is not tested with sliders though\n",
99
+ " # just use one for now\n",
100
+ " 'process': [\n",
101
+ " {\n",
102
+ " 'type': 'slider', # tells runner to run the slider process\n",
103
+ " # network is the LoRA network for a slider, I recommend to leave this be\n",
104
+ " 'network': {\n",
105
+ " 'type': \"lora\",\n",
106
+ " # rank / dim of the network. Bigger is not always better. Especially for sliders. 8 is good\n",
107
+ " 'linear': 8, # \"rank\" or \"dim\"\n",
108
+ " 'linear_alpha': 4, # Do about half of rank \"alpha\"\n",
109
+ " # 'conv': 4, # for convolutional layers \"locon\"\n",
110
+ " # 'conv_alpha': 4, # Do about half of conv \"alpha\"\n",
111
+ " },\n",
112
+ " # training config\n",
113
+ " 'train': {\n",
114
+ " # this is also used in sampling. Stick with ddpm unless you know what you are doing\n",
115
+ " 'noise_scheduler': \"ddpm\", # or \"ddpm\", \"lms\", \"euler_a\"\n",
116
+ " # how many steps to train. More is not always better. I rarely go over 1000\n",
117
+ " 'steps': 100,\n",
118
+ " # I have had good results with 4e-4 to 1e-4 at 500 steps\n",
119
+ " 'lr': 2e-4,\n",
120
+ " # enables gradient checkpoint, saves vram, leave it on\n",
121
+ " 'gradient_checkpointing': True,\n",
122
+ " # train the unet. I recommend leaving this true\n",
123
+ " 'train_unet': True,\n",
124
+ " # train the text encoder. I don't recommend this unless you have a special use case\n",
125
+ " # for sliders we are adjusting representation of the concept (unet),\n",
126
+ " # not the description of it (text encoder)\n",
127
+ " 'train_text_encoder': False,\n",
128
+ "\n",
129
+ " # just leave unless you know what you are doing\n",
130
+ " # also supports \"dadaptation\" but set lr to 1 if you use that,\n",
131
+ " # but it learns too fast and I don't recommend it\n",
132
+ " 'optimizer': \"adamw\",\n",
133
+ " # only constant for now\n",
134
+ " 'lr_scheduler': \"constant\",\n",
135
+ " # we randomly denoise random num of steps form 1 to this number\n",
136
+ " # while training. Just leave it\n",
137
+ " 'max_denoising_steps': 40,\n",
138
+ " # works great at 1. I do 1 even with my 4090.\n",
139
+ " # higher may not work right with newer single batch stacking code anyway\n",
140
+ " 'batch_size': 1,\n",
141
+ " # bf16 works best if your GPU supports it (modern)\n",
142
+ " 'dtype': 'bf16', # fp32, bf16, fp16\n",
143
+ " # I don't recommend using unless you are trying to make a darker lora. Then do 0.1 MAX\n",
144
+ " # although, the way we train sliders is comparative, so it probably won't work anyway\n",
145
+ " 'noise_offset': 0.0,\n",
146
+ " },\n",
147
+ "\n",
148
+ " # the model to train the LoRA network on\n",
149
+ " 'model': {\n",
150
+ " # name_or_path can be a hugging face name, local path or url to model\n",
151
+ " # on civit ai with or without modelVersionId. They will be cached in /model folder\n",
152
+ " # epicRealisim v5\n",
153
+ " 'name_or_path': \"https://civitai.com/models/25694?modelVersionId=134065\",\n",
154
+ " 'is_v2': False, # for v2 models\n",
155
+ " 'is_v_pred': False, # for v-prediction models (most v2 models)\n",
156
+ " # has some issues with the dual text encoder and the way we train sliders\n",
157
+ " # it works bit weights need to probably be higher to see it.\n",
158
+ " 'is_xl': False, # for SDXL models\n",
159
+ " },\n",
160
+ "\n",
161
+ " # saving config\n",
162
+ " 'save': {\n",
163
+ " 'dtype': 'float16', # precision to save. I recommend float16\n",
164
+ " 'save_every': 50, # save every this many steps\n",
165
+ " # this will remove step counts more than this number\n",
166
+ " # allows you to save more often in case of a crash without filling up your drive\n",
167
+ " 'max_step_saves_to_keep': 2,\n",
168
+ " },\n",
169
+ "\n",
170
+ " # sampling config\n",
171
+ " 'sample': {\n",
172
+ " # must match train.noise_scheduler, this is not used here\n",
173
+ " # but may be in future and in other processes\n",
174
+ " 'sampler': \"ddpm\",\n",
175
+ " # sample every this many steps\n",
176
+ " 'sample_every': 20,\n",
177
+ " # image size\n",
178
+ " 'width': 512,\n",
179
+ " 'height': 512,\n",
180
+ " # prompts to use for sampling. Do as many as you want, but it slows down training\n",
181
+ " # pick ones that will best represent the concept you are trying to adjust\n",
182
+ " # allows some flags after the prompt\n",
183
+ " # --m [number] # network multiplier. LoRA weight. -3 for the negative slide, 3 for the positive\n",
184
+ " # slide are good tests. will inherit sample.network_multiplier if not set\n",
185
+ " # --n [string] # negative prompt, will inherit sample.neg if not set\n",
186
+ " # Only 75 tokens allowed currently\n",
187
+ " # I like to do a wide positive and negative spread so I can see a good range and stop\n",
188
+ " # early if the network is braking down\n",
189
+ " 'prompts': [\n",
190
+ " \"a woman in a coffee shop, black hat, blonde hair, blue jacket --m -5\",\n",
191
+ " \"a woman in a coffee shop, black hat, blonde hair, blue jacket --m -3\",\n",
192
+ " \"a woman in a coffee shop, black hat, blonde hair, blue jacket --m 3\",\n",
193
+ " \"a woman in a coffee shop, black hat, blonde hair, blue jacket --m 5\",\n",
194
+ " \"a golden retriever sitting on a leather couch, --m -5\",\n",
195
+ " \"a golden retriever sitting on a leather couch --m -3\",\n",
196
+ " \"a golden retriever sitting on a leather couch --m 3\",\n",
197
+ " \"a golden retriever sitting on a leather couch --m 5\",\n",
198
+ " \"a man with a beard and red flannel shirt, wearing vr goggles, walking into traffic --m -5\",\n",
199
+ " \"a man with a beard and red flannel shirt, wearing vr goggles, walking into traffic --m -3\",\n",
200
+ " \"a man with a beard and red flannel shirt, wearing vr goggles, walking into traffic --m 3\",\n",
201
+ " \"a man with a beard and red flannel shirt, wearing vr goggles, walking into traffic --m 5\",\n",
202
+ " ],\n",
203
+ " # negative prompt used on all prompts above as default if they don't have one\n",
204
+ " 'neg': \"cartoon, fake, drawing, illustration, cgi, animated, anime, monochrome\",\n",
205
+ " # seed for sampling. 42 is the answer for everything\n",
206
+ " 'seed': 42,\n",
207
+ " # walks the seed so s1 is 42, s2 is 43, s3 is 44, etc\n",
208
+ " # will start over on next sample_every so s1 is always seed\n",
209
+ " # works well if you use same prompt but want different results\n",
210
+ " 'walk_seed': False,\n",
211
+ " # cfg scale (4 to 10 is good)\n",
212
+ " 'guidance_scale': 7,\n",
213
+ " # sampler steps (20 to 30 is good)\n",
214
+ " 'sample_steps': 20,\n",
215
+ " # default network multiplier for all prompts\n",
216
+ " # since we are training a slider, I recommend overriding this with --m [number]\n",
217
+ " # in the prompts above to get both sides of the slider\n",
218
+ " 'network_multiplier': 1.0,\n",
219
+ " },\n",
220
+ "\n",
221
+ " # logging information\n",
222
+ " 'logging': {\n",
223
+ " 'log_every': 10, # log every this many steps\n",
224
+ " 'use_wandb': False, # not supported yet\n",
225
+ " 'verbose': False, # probably done need unless you are debugging\n",
226
+ " },\n",
227
+ "\n",
228
+ " # slider training config, best for last\n",
229
+ " 'slider': {\n",
230
+ " # resolutions to train on. [ width, height ]. This is less important for sliders\n",
231
+ " # as we are not teaching the model anything it doesn't already know\n",
232
+ " # but must be a size it understands [ 512, 512 ] for sd_v1.5 and [ 768, 768 ] for sd_v2.1\n",
233
+ " # and [ 1024, 1024 ] for sd_xl\n",
234
+ " # you can do as many as you want here\n",
235
+ " 'resolutions': [\n",
236
+ " [512, 512],\n",
237
+ " # [ 512, 768 ]\n",
238
+ " # [ 768, 768 ]\n",
239
+ " ],\n",
240
+ " # slider training uses 4 combined steps for a single round. This will do it in one gradient\n",
241
+ " # step. It is highly optimized and shouldn't take anymore vram than doing without it,\n",
242
+ " # since we break down batches for gradient accumulation now. so just leave it on.\n",
243
+ " 'batch_full_slide': True,\n",
244
+ " # These are the concepts to train on. You can do as many as you want here,\n",
245
+ " # but they can conflict outweigh each other. Other than experimenting, I recommend\n",
246
+ " # just doing one for good results\n",
247
+ " 'targets': [\n",
248
+ " # target_class is the base concept we are adjusting the representation of\n",
249
+ " # for example, if we are adjusting the representation of a person, we would use \"person\"\n",
250
+ " # if we are adjusting the representation of a cat, we would use \"cat\" It is not\n",
251
+ " # a keyword necessarily but what the model understands the concept to represent.\n",
252
+ " # \"person\" will affect men, women, children, etc but will not affect cats, dogs, etc\n",
253
+ " # it is the models base general understanding of the concept and everything it represents\n",
254
+ " # you can leave it blank to affect everything. In this example, we are adjusting\n",
255
+ " # detail, so we will leave it blank to affect everything\n",
256
+ " {\n",
257
+ " 'target_class': \"\",\n",
258
+ " # positive is the prompt for the positive side of the slider.\n",
259
+ " # It is the concept that will be excited and amplified in the model when we slide the slider\n",
260
+ " # to the positive side and forgotten / inverted when we slide\n",
261
+ " # the slider to the negative side. It is generally best to include the target_class in\n",
262
+ " # the prompt. You want it to be the extreme of what you want to train on. For example,\n",
263
+ " # if you want to train on fat people, you would use \"an extremely fat, morbidly obese person\"\n",
264
+ " # as the prompt. Not just \"fat person\"\n",
265
+ " # max 75 tokens for now\n",
266
+ " 'positive': \"high detail, 8k, intricate, detailed, high resolution, high res, high quality\",\n",
267
+ " # negative is the prompt for the negative side of the slider and works the same as positive\n",
268
+ " # it does not necessarily work the same as a negative prompt when generating images\n",
269
+ " # these need to be polar opposites.\n",
270
+ " # max 76 tokens for now\n",
271
+ " 'negative': \"blurry, boring, fuzzy, low detail, low resolution, low res, low quality\",\n",
272
+ " # the loss for this target is multiplied by this number.\n",
273
+ " # if you are doing more than one target it may be good to set less important ones\n",
274
+ " # to a lower number like 0.1 so they don't outweigh the primary target\n",
275
+ " 'weight': 1.0,\n",
276
+ " },\n",
277
+ " ],\n",
278
+ " },\n",
279
+ " },\n",
280
+ " ]\n",
281
+ " },\n",
282
+ "\n",
283
+ " # You can put any information you want here, and it will be saved in the model.\n",
284
+ " # The below is an example, but you can put your grocery list in it if you want.\n",
285
+ " # It is saved in the model so be aware of that. The software will include this\n",
286
+ " # plus some other information for you automatically\n",
287
+ " 'meta': {\n",
288
+ " # [name] gets replaced with the name above\n",
289
+ " 'name': \"[name]\",\n",
290
+ " 'version': '1.0',\n",
291
+ " # 'creator': {\n",
292
+ " # 'name': 'your name',\n",
293
+ " # 'email': 'your@gmail.com',\n",
294
+ " # 'website': 'https://your.website'\n",
295
+ " # }\n",
296
+ " }\n",
297
+ "})\n"
298
+ ],
299
+ "metadata": {
300
+ "id": "_t28QURYjRQO"
301
+ },
302
+ "execution_count": null,
303
+ "outputs": []
304
+ },
305
+ {
306
+ "cell_type": "markdown",
307
+ "source": [
308
+ "## Run it\n",
309
+ "\n",
310
+ "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. Ill update soon."
311
+ ],
312
+ "metadata": {
313
+ "id": "h6F1FlM2Wb3l"
314
+ }
315
+ },
316
+ {
317
+ "cell_type": "code",
318
+ "source": [
319
+ "run_job(job_to_run)\n"
320
+ ],
321
+ "metadata": {
322
+ "id": "HkajwI8gteOh"
323
+ },
324
+ "execution_count": null,
325
+ "outputs": []
326
+ },
327
+ {
328
+ "cell_type": "markdown",
329
+ "source": [
330
+ "## Done\n",
331
+ "\n",
332
+ "Check your ourput dir and get your slider\n"
333
+ ],
334
+ "metadata": {
335
+ "id": "Hblgb5uwW5SD"
336
+ }
337
+ }
338
+ ]
339
+ }