InvokeAI/invokeai/backend/util/devices.py

76 lines
2.5 KiB
Python
Raw Normal View History

from __future__ import annotations
2023-08-18 15:13:28 +00:00
from contextlib import nullcontext
from typing import Union, Optional
import torch
Refactoring simplet2i (#387) * start refactoring -not yet functional * first phase of refactor done - not sure weighted prompts working * Second phase of refactoring. Everything mostly working. * The refactoring has moved all the hard-core inference work into ldm.dream.generator.*, where there are submodules for txt2img and img2img. inpaint will go in there as well. * Some additional refactoring will be done soon, but relatively minor work. * fix -save_orig flag to actually work * add @neonsecret attention.py memory optimization * remove unneeded imports * move token logging into conditioning.py * add placeholder version of inpaint; porting in progress * fix crash in img2img * inpainting working; not tested on variations * fix crashes in img2img * ported attention.py memory optimization #117 from basujindal branch * added @torch_no_grad() decorators to img2img, txt2img, inpaint closures * Final commit prior to PR against development * fixup crash when generating intermediate images in web UI * rename ldm.simplet2i to ldm.generate * add backward-compatibility simplet2i shell with deprecation warning * add back in mps exception, addresses @vargol comment in #354 * replaced Conditioning class with exported functions * fix wrong type of with_variations attribute during intialization * changed "image_iterator()" to "get_make_image()" * raise NotImplementedError for calling get_make_image() in parent class * Update ldm/generate.py better error message Co-authored-by: Kevin Gibbons <bakkot@gmail.com> * minor stylistic fixes and assertion checks from code review * moved get_noise() method into img2img class * break get_noise() into two methods, one for txt2img and the other for img2img * inpainting works on non-square images now * make get_noise() an abstract method in base class * much improved inpainting Co-authored-by: Kevin Gibbons <bakkot@gmail.com>
2022-09-06 00:40:10 +00:00
from torch import autocast
2023-08-18 15:13:28 +00:00
from invokeai.app.services.config import InvokeAIAppConfig
CPU_DEVICE = torch.device("cpu")
2023-03-03 05:02:15 +00:00
CUDA_DEVICE = torch.device("cuda")
MPS_DEVICE = torch.device("mps")
config = InvokeAIAppConfig.get_config()
2023-03-03 06:02:00 +00:00
2023-07-27 14:54:01 +00:00
def choose_torch_device() -> torch.device:
2023-03-03 06:02:00 +00:00
"""Convenience routine for guessing which GPU device to run model on"""
2023-08-17 17:47:26 +00:00
if config.use_cpu: # legacy setting - force CPU
return CPU_DEVICE
2023-08-17 17:47:26 +00:00
elif config.device == "auto":
if torch.cuda.is_available():
return torch.device("cuda")
if hasattr(torch.backends, "mps") and torch.backends.mps.is_available():
return torch.device("mps")
else:
return CPU_DEVICE
else:
return torch.device(config.device)
2023-03-03 06:02:00 +00:00
def choose_precision(device: torch.device) -> str:
2023-03-03 06:02:00 +00:00
"""Returns an appropriate precision for the given torch device"""
if device.type == "cuda":
device_name = torch.cuda.get_device_name(device)
2023-03-03 06:02:00 +00:00
if not ("GeForce GTX 1660" in device_name or "GeForce GTX 1650" in device_name):
if config.precision == "bfloat16":
return "bfloat16"
else:
return "float16"
elif device.type == "mps":
return "float16"
2023-03-03 06:02:00 +00:00
return "float32"
def torch_dtype(device: Optional[torch.device] = None) -> torch.dtype:
device = device or choose_torch_device()
precision = choose_precision(device)
if precision == "float16":
return torch.float16
if precision == "bfloat16":
return torch.bfloat16
else:
# "auto", "autocast", "float32"
return torch.float32
2023-03-03 06:02:00 +00:00
def choose_autocast(precision):
2023-03-03 06:02:00 +00:00
"""Returns an autocast context or nullcontext for the given precision string"""
# float16 currently requires autocast to avoid errors like:
# 'expected scalar type Half but found Float'
2023-03-03 06:02:00 +00:00
if precision == "autocast" or precision == "float16":
return autocast
return nullcontext
2023-03-03 06:02:00 +00:00
def normalize_device(device: Union[str, torch.device]) -> torch.device:
"""Ensure device has a device index defined, if appropriate."""
device = torch.device(device)
if device.index is None:
# cuda might be the only torch backend that currently uses the device index?
# I don't see anything like `current_device` for cpu or mps.
2023-03-03 06:02:00 +00:00
if device.type == "cuda":
device = torch.device(device.type, torch.cuda.current_device())
return device