Spaces:
Runtime error
Runtime error
| #!/usr/bin/env python | |
| """ | |
| sd api txt2img benchmark | |
| """ | |
| import os | |
| import asyncio | |
| import base64 | |
| import io | |
| import json | |
| import time | |
| import argparse | |
| from PIL import Image | |
| import sdapi | |
| from util import Map, log | |
| oom = 0 | |
| args = None | |
| options = None | |
| async def txt2img(): | |
| t0 = time.perf_counter() | |
| data = {} | |
| try: | |
| data = await sdapi.post('/sdapi/v1/txt2img', options) | |
| except Exception: | |
| return -1 | |
| if 'error' in data: | |
| return -1 | |
| if 'info' in data: | |
| info = Map(json.loads(data['info'])) | |
| else: | |
| return 0 | |
| log.debug({ 'info': info }) | |
| if options['batch_size'] != len(data['images']): | |
| log.error({ 'requested': options['batch_size'], 'received': len(data['images']) }) | |
| return 0 | |
| for i in range(len(data['images'])): | |
| data['images'][i] = Image.open(io.BytesIO(base64.b64decode(data['images'][i].split(',',1)[0]))) | |
| if args.save: | |
| fn = os.path.join(args.save, f'benchmark-{i}-{len(data["images"])}.png') | |
| data["images"][i].save(fn) | |
| log.debug({ 'save': fn }) | |
| log.debug({ "images": data["images"] }) | |
| t1 = time.perf_counter() | |
| return t1 - t0 | |
| def memstats(): | |
| mem = sdapi.getsync('/sdapi/v1/memory') | |
| cpu = mem.get('ram', 'unavailable') | |
| gpu = mem.get('cuda', 'unavailable') | |
| if 'active' in gpu: | |
| gpu['session'] = gpu.pop('active') | |
| if 'reserved' in gpu: | |
| gpu.pop('allocated') | |
| gpu.pop('reserved') | |
| gpu.pop('inactive') | |
| if 'events' in gpu: | |
| global oom # pylint: disable=global-statement | |
| oom = gpu['events']['oom'] | |
| gpu.pop('events') | |
| return cpu, gpu | |
| def gb(val: float): | |
| return round(val / 1024 / 1024 / 1024, 2) | |
| async def main(): | |
| sdapi.quiet = True | |
| await sdapi.session() | |
| await sdapi.interrupt() | |
| ver = await sdapi.get("/sdapi/v1/version") | |
| log.info({ 'version': ver}) | |
| platform = await sdapi.get("/sdapi/v1/platform") | |
| log.info({ 'platform': platform }) | |
| opts = await sdapi.get('/sdapi/v1/options') | |
| opts = Map(opts) | |
| log.info({ 'model': opts.sd_model_checkpoint }) | |
| cpu, gpu = memstats() | |
| log.info({ 'system': { 'cpu': cpu, 'gpu': gpu }}) | |
| batch = [1, 1, 2, 4, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192, 256] | |
| batch = [b for b in batch if b <= args.maxbatch] | |
| log.info({"batch-sizes": batch}) | |
| for i in range(len(batch)): | |
| if oom > 0: | |
| continue | |
| options['batch_size'] = batch[i] | |
| warmup = await txt2img() | |
| ts = await txt2img() | |
| if i == 0: | |
| ts += warmup | |
| if ts > 0.01: # cannot be faster than 10ms per run | |
| await asyncio.sleep(0) | |
| cpu, gpu = memstats() | |
| if i == 0: | |
| log.info({ 'warmup': round(ts, 2) }) | |
| else: | |
| peak = gpu['system']['used'] # gpu['session']['peak'] if 'session' in gpu else 0 | |
| log.info({ 'batch': batch[i], 'its': round(options.steps / (ts / batch[i]), 2), 'img': round(ts / batch[i], 2), 'wall': round(ts, 2), 'peak': gb(peak), 'oom': oom > 0 }) | |
| else: | |
| await asyncio.sleep(10) | |
| cpu, gpu = memstats() | |
| log.info({ 'batch': batch[i], 'result': 'error', 'gpu': gpu, 'oom': oom > 0 }) | |
| break | |
| if oom > 0: | |
| log.info({ 'benchmark': 'ended with oom so you should probably restart your automatic server now' }) | |
| await sdapi.close() | |
| if __name__ == '__main__': | |
| log.info({ 'run-benchmark' }) | |
| parser = argparse.ArgumentParser(description = 'run-benchmark') | |
| parser.add_argument("--steps", type=int, default=50, required=False, help="steps") | |
| parser.add_argument("--sampler", type=str, default='Euler a', required=False, help="Use specific sampler") | |
| parser.add_argument("--prompt", type=str, default='photo of two dice on a table', required=False, help="prompt") | |
| parser.add_argument("--negative", type=str, default='foggy, blurry', required=False, help="prompt") | |
| parser.add_argument("--maxbatch", type=int, default=16, required=False, help="max batch size") | |
| parser.add_argument("--width", type=int, default=512, required=False, help="width") | |
| parser.add_argument("--height", type=int, default=512, required=False, help="height") | |
| parser.add_argument('--debug', default = False, action='store_true', help = 'debug logging') | |
| parser.add_argument('--taesd', default = False, action='store_true', help = 'use taesd as vae') | |
| parser.add_argument("--save", type=str, default='', required=False, help="save images to folder") | |
| args = parser.parse_args() | |
| if args.debug: | |
| log.setLevel('DEBUG') | |
| options = Map( | |
| { | |
| "prompt": args.prompt, | |
| "negative_prompt": args.negative, | |
| "steps": args.steps, | |
| "sampler_name": args.sampler, | |
| "width": args.width, | |
| "height": args.height, | |
| "full_quality": not args.taesd, | |
| "cfg_scale": 0, | |
| "batch_size": 1, | |
| "n_iter": 1, | |
| "seed": -1, | |
| } | |
| ) | |
| log.info({"options": options}) | |
| try: | |
| asyncio.run(main()) | |
| except KeyboardInterrupt: | |
| log.warning({ 'interrupted': 'keyboard request' }) | |
| sdapi.interruptsync() | |