txt2img.py 8.83 KB
Newer Older
1
2
3
4
import argparse
import os
from itertools import islice

5
6
import cv2
import numpy as np
7
8
import torch
from einops import rearrange
9
10
11
from omegaconf import OmegaConf
from PIL import Image
from torchvision.utils import make_grid
12
13
from tqdm import tqdm, trange

Fazzie's avatar
Fazzie committed
14
15
16
17
try:
    from lightning.pytorch import seed_everything
except:
    from pytorch_lightning import seed_everything
18

Fazzie's avatar
Fazzie committed
19
from contextlib import nullcontext
20

21
from imwatermark import WatermarkEncoder
22
from ldm.models.diffusion.ddim import DDIMSampler
Fazzie's avatar
Fazzie committed
23
from ldm.models.diffusion.dpm_solver import DPMSolverSampler
24
25
26
27
from ldm.models.diffusion.plms import PLMSSampler
from ldm.util import instantiate_from_config
from torch import autocast
from utils import replace_module
28

Fazzie's avatar
Fazzie committed
29
torch.set_grad_enabled(False)
30

31

32
33
34
35
36
37
38
39
40
41
42
def chunk(it, size):
    it = iter(it)
    return iter(lambda: tuple(islice(it, size)), ())


def load_model_from_config(config, ckpt, verbose=False):
    print(f"Loading model from {ckpt}")
    pl_sd = torch.load(ckpt, map_location="cpu")
    if "global_step" in pl_sd:
        print(f"Global Step: {pl_sd['global_step']}")
    sd = pl_sd["state_dict"]
43
    model = instantiate_from_config(config.model)
44
45
46
47
48
49
50
51
52
53
54
55
    m, u = model.load_state_dict(sd, strict=False)
    if len(m) > 0 and verbose:
        print("missing keys:")
        print(m)
    if len(u) > 0 and verbose:
        print("unexpected keys:")
        print(u)

    model.eval()
    return model


Fazzie's avatar
Fazzie committed
56
def parse_args():
57
58
59
60
61
    parser = argparse.ArgumentParser()
    parser.add_argument(
        "--prompt",
        type=str,
        nargs="?",
Fazzie's avatar
Fazzie committed
62
        default="a professional photograph of an astronaut riding a triceratops",
63
        help="the prompt to render",
64
65
    )
    parser.add_argument(
66
        "--outdir", type=str, nargs="?", help="dir to write results to", default="outputs/txt2img-samples"
67
68
    )
    parser.add_argument(
Fazzie's avatar
Fazzie committed
69
        "--steps",
70
71
72
73
74
75
        type=int,
        default=50,
        help="number of ddim sampling steps",
    )
    parser.add_argument(
        "--plms",
76
        action="store_true",
77
78
79
        help="use plms sampling",
    )
    parser.add_argument(
Fazzie's avatar
Fazzie committed
80
        "--dpm",
81
        action="store_true",
Fazzie's avatar
Fazzie committed
82
        help="use DPM (2) sampler",
83
84
85
    )
    parser.add_argument(
        "--fixed_code",
86
        action="store_true",
Fazzie's avatar
Fazzie committed
87
        help="if enabled, uses the same starting code across all samples ",
88
89
90
91
92
93
94
95
96
97
    )
    parser.add_argument(
        "--ddim_eta",
        type=float,
        default=0.0,
        help="ddim eta (eta=0.0 corresponds to deterministic sampling",
    )
    parser.add_argument(
        "--n_iter",
        type=int,
Fazzie's avatar
Fazzie committed
98
        default=3,
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
        help="sample this often",
    )
    parser.add_argument(
        "--H",
        type=int,
        default=512,
        help="image height, in pixel space",
    )
    parser.add_argument(
        "--W",
        type=int,
        default=512,
        help="image width, in pixel space",
    )
    parser.add_argument(
        "--C",
        type=int,
        default=4,
        help="latent channels",
    )
    parser.add_argument(
        "--f",
        type=int,
        default=8,
Fazzie's avatar
Fazzie committed
123
        help="downsampling factor, most often 8 or 16",
124
125
126
127
128
    )
    parser.add_argument(
        "--n_samples",
        type=int,
        default=3,
Fazzie's avatar
Fazzie committed
129
        help="how many samples to produce for each given prompt. A.k.a batch size",
130
131
132
133
134
135
136
137
138
139
    )
    parser.add_argument(
        "--n_rows",
        type=int,
        default=0,
        help="rows in the grid (default: n_samples)",
    )
    parser.add_argument(
        "--scale",
        type=float,
Fazzie's avatar
Fazzie committed
140
        default=9.0,
141
142
143
144
145
        help="unconditional guidance scale: eps = eps(x, empty) + scale * (eps(x, cond) - eps(x, empty))",
    )
    parser.add_argument(
        "--from-file",
        type=str,
Fazzie's avatar
Fazzie committed
146
        help="if specified, load prompts from this file, separated by newlines",
147
148
149
150
    )
    parser.add_argument(
        "--config",
        type=str,
Fazzie's avatar
Fazzie committed
151
        default="configs/stable-diffusion/v2-inference.yaml",
152
153
154
155
156
157
158
159
160
161
162
163
164
165
        help="path to config which constructs model",
    )
    parser.add_argument(
        "--ckpt",
        type=str,
        help="path to checkpoint of model",
    )
    parser.add_argument(
        "--seed",
        type=int,
        default=42,
        help="the seed (for reproducible sampling)",
    )
    parser.add_argument(
166
        "--precision", type=str, help="evaluate at this precision", choices=["full", "autocast"], default="autocast"
167
    )
Fazzie's avatar
Fazzie committed
168
169
170
171
172
173
    parser.add_argument(
        "--repeat",
        type=int,
        default=1,
        help="repeat each prompt in file this often",
    )
174
175
176
177
178
179
    parser.add_argument(
        "--use_int8",
        type=bool,
        default=False,
        help="use int8 for inference",
    )
180
    opt = parser.parse_args()
Fazzie's avatar
Fazzie committed
181
    return opt
182
183


Fazzie's avatar
Fazzie committed
184
185
186
def put_watermark(img, wm_encoder=None):
    if wm_encoder is not None:
        img = cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR)
187
        img = wm_encoder.encode(img, "dwtDct")
Fazzie's avatar
Fazzie committed
188
189
190
191
192
        img = Image.fromarray(img[:, :, ::-1])
    return img


def main(opt):
193
194
195
196
    seed_everything(opt.seed)

    config = OmegaConf.load(f"{opt.config}")
    model = load_model_from_config(config, f"{opt.ckpt}")
197

198
199
    device = torch.device("cuda") if torch.cuda.is_available() else torch.device("cpu")

200
    model = model.to(device)
201

202
203
204
205
206
    # quantize model
    if opt.use_int8:
        model = replace_module(model)
        # # to compute the model size
        # getModelSize(model)
207

208
209
    if opt.plms:
        sampler = PLMSSampler(model)
Fazzie's avatar
Fazzie committed
210
211
    elif opt.dpm:
        sampler = DPMSolverSampler(model)
212
213
214
215
216
217
218
    else:
        sampler = DDIMSampler(model)

    os.makedirs(opt.outdir, exist_ok=True)
    outpath = opt.outdir

    print("Creating invisible watermark encoder (see https://github.com/ShieldMnt/invisible-watermark)...")
Fazzie's avatar
Fazzie committed
219
    wm = "SDV2"
220
    wm_encoder = WatermarkEncoder()
221
    wm_encoder.set_watermark("bytes", wm.encode("utf-8"))
222
223
224
225
226
227
228
229
230
231
232
233

    batch_size = opt.n_samples
    n_rows = opt.n_rows if opt.n_rows > 0 else batch_size
    if not opt.from_file:
        prompt = opt.prompt
        assert prompt is not None
        data = [batch_size * [prompt]]

    else:
        print(f"reading prompts from {opt.from_file}")
        with open(opt.from_file, "r") as f:
            data = f.read().splitlines()
Fazzie's avatar
Fazzie committed
234
            data = [p for p in data for i in range(opt.repeat)]
235
236
237
238
            data = list(chunk(data, batch_size))

    sample_path = os.path.join(outpath, "samples")
    os.makedirs(sample_path, exist_ok=True)
Fazzie's avatar
Fazzie committed
239
    sample_count = 0
240
241
242
243
244
245
246
    base_count = len(os.listdir(sample_path))
    grid_count = len(os.listdir(outpath)) - 1

    start_code = None
    if opt.fixed_code:
        start_code = torch.randn([opt.n_samples, opt.C, opt.H // opt.f, opt.W // opt.f], device=device)

Fazzie's avatar
Fazzie committed
247
    precision_scope = autocast if opt.precision == "autocast" else nullcontext
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
    with torch.no_grad(), precision_scope("cuda"), model.ema_scope():
        all_samples = list()
        for n in trange(opt.n_iter, desc="Sampling"):
            for prompts in tqdm(data, desc="data"):
                uc = None
                if opt.scale != 1.0:
                    uc = model.get_learned_conditioning(batch_size * [""])
                if isinstance(prompts, tuple):
                    prompts = list(prompts)
                c = model.get_learned_conditioning(prompts)
                shape = [opt.C, opt.H // opt.f, opt.W // opt.f]
                samples, _ = sampler.sample(
                    S=opt.steps,
                    conditioning=c,
                    batch_size=opt.n_samples,
                    shape=shape,
                    verbose=False,
                    unconditional_guidance_scale=opt.scale,
                    unconditional_conditioning=uc,
                    eta=opt.ddim_eta,
                    x_T=start_code,
                )

                x_samples = model.decode_first_stage(samples)
                x_samples = torch.clamp((x_samples + 1.0) / 2.0, min=0.0, max=1.0)

                for x_sample in x_samples:
                    x_sample = 255.0 * rearrange(x_sample.cpu().numpy(), "c h w -> h w c")
                    img = Image.fromarray(x_sample.astype(np.uint8))
                    img = put_watermark(img, wm_encoder)
                    img.save(os.path.join(sample_path, f"{base_count:05}.png"))
                    base_count += 1
                    sample_count += 1

                all_samples.append(x_samples)

        # additionally, save as grid
        grid = torch.stack(all_samples, 0)
        grid = rearrange(grid, "n b c h w -> (n b) c h w")
        grid = make_grid(grid, nrow=n_rows)

        # to image
        grid = 255.0 * rearrange(grid, "c h w -> h w c").cpu().numpy()
        grid = Image.fromarray(grid.astype(np.uint8))
        grid = put_watermark(grid, wm_encoder)
        grid.save(os.path.join(outpath, f"grid-{grid_count:04}.png"))
        grid_count += 1

    print(f"Your samples are ready and waiting for you here: \n{outpath} \n" f" \nEnjoy.")
297
298
299


if __name__ == "__main__":
Fazzie's avatar
Fazzie committed
300
301
    opt = parse_args()
    main(opt)
302
303
    # # to compute the mem allocated
    # print(torch.cuda.max_memory_allocated() / 1024 / 1024)