File size: 5,303 Bytes
9e188c8
 
 
 
 
 
 
 
 
 
92e5033
9e188c8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92e5033
9e188c8
 
 
 
 
 
 
 
 
 
 
92e5033
9e188c8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92e5033
9e188c8
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
# AUTOGENERATED! DO NOT EDIT! File to edit: app.ipynb.

# %% auto 0
__all__ = ['model_name', 'revision', 'dtype', 'device', 'better_vae', 'unet_attn_slice', 'sampler_kls', 'hf_sampler',
           'model_kwargs', 'num_steps', 'height', 'width', 'k_sampler', 'use_karras_sigmas', 'NEG_PROMPT',
           'generation_kwargs', 'baseline_g', 'max_val', 'min_val', 'num_warmup_steps', 'warmup_init_val', 'num_cycles',
           'k_decay', 'DEFAULT_COS_PARAMS', 'static_sched', 'k_sched', 'inv_k_sched', 'schedules', 'iface',
           'load_model', 'cos_harness', 'compare_dynamic_guidance']

# %% app.ipynb 1
import gradio as gr
import cf_guidance
import min_diffusion
import torch
import nbdev

# %% app.ipynb 2
## MODEL SETUP
######################################
######################################
model_name = 'stabilityai/stable-diffusion-2'
revision = 'fp16'
dtype = torch.float16
device = ('cpu','cuda')[torch.cuda.is_available()]

# model parameters
better_vae = ''
unet_attn_slice = True
sampler_kls = 'dpm_multi'
hf_sampler = 'dpm_multi'

model_kwargs = {
    'better_vae': better_vae,
    'unet_attn_slice': unet_attn_slice,
    'sampler_kls': hf_sampler,
}

def load_model():
    pipeline = min_diffusion.core.MinimalDiffusion(
        model_name,
        device,
        dtype,
        revision,
        **model_kwargs,
    )
    pipeline.load()
    return pipeline
######################################
######################################

# %% app.ipynb 3
## GENERATION PARAMETERS
######################################
######################################
num_steps = 18
height, width = 768, 768
k_sampler = 'k_dpmpp_2m' #'k_dpmpp_sde'
use_karras_sigmas = True

# a good negative prompt
NEG_PROMPT = "ugly, stock photo, tiling, poorly drawn hands, poorly drawn feet, poorly drawn face, out of frame, mutation, mutated, extra limbs, extra legs, extra arms, disfigured, deformed, cross-eye, body out of frame, blurry, bad art, bad anatomy, blurred, text, watermark, grainy"

generation_kwargs = {
    'num_steps': num_steps,
    'height': height,
    'width': width,
    'k_sampler':  k_sampler,
    'negative_prompt': NEG_PROMPT,
    'use_karras_sigmas': use_karras_sigmas,
}
######################################
######################################

# %% app.ipynb 4
## dynamicCFG SETUP
######################################
######################################

# default cosine schedule parameters
baseline_g        = 9    # default, static guidance value
max_val           = 9    # the max scheduled guidance scaling value
min_val           = 6    # the minimum scheduled guidance value
num_warmup_steps  = 0    # number of warmup steps
warmup_init_val   = 0    # the intial warmup value
num_cycles        = 0.5  # number of cosine cycles
k_decay           = 1    # k-decay for cosine curve scaling 

# group the default schedule parameters
DEFAULT_COS_PARAMS = {
    'max_val':           max_val,
    'num_steps':         num_steps,
    'min_val':           min_val,
    'num_cycles':        num_cycles,
    'k_decay':           k_decay,
    'num_warmup_steps':  num_warmup_steps,
    'warmup_init_val':   warmup_init_val,
}

def cos_harness(new_params: dict) -> dict:
    '''Creates cosine schedules with updated parameters in `new_params`
    '''
    # start from the given baseline `default_params`
    cos_params = dict(DEFAULT_COS_PARAMS)
    # update the with the new, given parameters
    cos_params.update(new_params)
    
    # return the new cosine schedule
    sched = cf_guidance.schedules.get_cos_sched(**cos_params)
    return sched


# build the static schedule
static_sched = [baseline_g] * num_steps

# build the inverted kdecay schedule
k_sched = cos_harness({'k_decay': 0.2})
inv_k_sched = [max_val - g + min_val for g in k_sched]

# group the schedules 
schedules = {
    'cosine': {'g': inv_k_sched},
    'static': {'g': static_sched},
}
######################################
######################################

# %% app.ipynb 5
def compare_dynamic_guidance(prompt):
    '''
    Compares the default, static Classifier-free Guidance to a dynamic schedule.  

    Model and sampling paramters:
        Stable Diffusion 2 v-model
        Half-precision
        DPM++ 2M sampler, with Karras sigma schedule
        18 sampling steps
        (768 x 768) image
        Using a generic negative prompt

    Schedules:
        Static guidance with scale of 9
        Inverse kDecay (cosine variant) scheduled guidance
    '''
    # load the model
    pipeline = load_model()

    # stores the output images
    res = []

    # generate images with static and dynamic schedules
    for (name,sched) in schedules.items():
        # make the guidance norm
        gtfm = cf_guidance.transforms.GuidanceTfm(sched)
        # generate the image
        with torch.autocast(device), torch.no_grad():
            img = pipeline.generate(prompt, gtfm, **generation_kwargs)
        # add the generated image
        res.append(name)

    # return the generated images
    return {
        'values': res,
        'label': 'Cosine vs. Static CFG'
    }

# %% app.ipynb 6
iface = gr.Interface(
    compare_dynamic_guidance,
    inputs="text",
    outputs=gr.Gallery(),
    title="Comparison with dynamic Classifier-free Guidance Comparison",
)
iface.launch()