Skip to content

Commit 18f89ed

Browse files
fix: Make DepthAnything work with Invoke's Model Management
1 parent f170697 commit 18f89ed

File tree

4 files changed

+47
-5
lines changed

4 files changed

+47
-5
lines changed

invokeai/app/invocations/controlnet_image_processors.py

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
# initial implementation by Gregg Helt, 2023
33
# heavily leverages controlnet_aux package: https://github.com/patrickvonplaten/controlnet_aux
44
from builtins import bool, float
5+
from pathlib import Path
56
from typing import Dict, List, Literal, Union
67

78
import cv2
@@ -21,6 +22,7 @@
2122
from PIL import Image
2223
from pydantic import BaseModel, Field, field_validator, model_validator
2324
from transformers import pipeline
25+
from transformers.pipelines import DepthEstimationPipeline
2426

2527
from invokeai.app.invocations.baseinvocation import (
2628
BaseInvocation,
@@ -44,6 +46,7 @@
4446
from invokeai.app.services.shared.invocation_context import InvocationContext
4547
from invokeai.app.util.controlnet_utils import CONTROLNET_MODE_VALUES, CONTROLNET_RESIZE_VALUES, heuristic_resize
4648
from invokeai.backend.image_util.canny import get_canny_edges
49+
from invokeai.backend.image_util.depth_anything.depth_anything_pipeline import DepthAnythingPipeline
4750
from invokeai.backend.image_util.dw_openpose import DWPOSE_MODELS, DWOpenposeDetector
4851
from invokeai.backend.image_util.hed import HEDProcessor
4952
from invokeai.backend.image_util.lineart import LineartProcessor
@@ -614,9 +617,16 @@ class DepthAnythingImageProcessorInvocation(ImageProcessorInvocation):
614617
resolution: int = InputField(default=512, ge=1, description=FieldDescriptions.image_res)
615618

616619
def run_processor(self, image: Image.Image) -> Image.Image:
617-
depth_anything_pipeline = pipeline(task="depth-estimation", model=DEPTH_ANYTHING_MODELS[self.model_size])
618-
depth_map = depth_anything_pipeline(image)["depth"]
619-
return depth_map
620+
def load_depth_anything(model_path: Path):
621+
depth_anything_pipeline = pipeline(model=str(model_path), task="depth-estimation", local_files_only=True)
622+
assert isinstance(depth_anything_pipeline, DepthEstimationPipeline)
623+
return DepthAnythingPipeline(depth_anything_pipeline)
624+
625+
with self._context.models.load_remote_model(
626+
source=DEPTH_ANYTHING_MODELS[self.model_size], loader=load_depth_anything
627+
) as depth_anything_detector:
628+
assert isinstance(depth_anything_detector, DepthAnythingPipeline)
629+
return depth_anything_detector.generate_depth(image, self.resolution)
620630

621631

622632
@invocation(
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
from typing import cast
2+
3+
from PIL import Image
4+
from transformers.pipelines import DepthEstimationPipeline
5+
6+
7+
class DepthAnythingPipeline:
8+
"""Custom wrapper for the Depth Estimation pipeline from transformers adding compatibility
9+
for Invoke's Model Management System"""
10+
11+
def __init__(self, pipeline: DepthEstimationPipeline) -> None:
12+
self.pipeline = pipeline
13+
14+
def generate_depth(self, image: Image.Image, resolution: int = 512):
15+
image_width, image_height = image.size
16+
depth_map = self.pipeline(image)["depth"]
17+
depth_map = cast(Image.Image, depth_map)
18+
19+
new_height = int(image_height * (resolution / image_width))
20+
depth_map = depth_map.resize((resolution, new_height))
21+
return depth_map
22+
23+
def calc_size(self) -> int:
24+
from invokeai.backend.model_manager.load.model_util import calc_module_size
25+
26+
return calc_module_size(self.pipeline.model)

invokeai/backend/model_manager/config.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,16 @@
3131
from typing_extensions import Annotated, Any, Dict
3232

3333
from invokeai.app.util.misc import uuid_string
34+
from invokeai.backend.image_util.depth_anything.depth_anything_pipeline import DepthAnythingPipeline
3435
from invokeai.backend.model_hash.hash_validator import validate_hash
3536
from invokeai.backend.raw_model import RawModel
3637
from invokeai.backend.stable_diffusion.schedulers.schedulers import SCHEDULER_NAME_VALUES
3738

3839
# ModelMixin is the base class for all diffusers and transformers models
3940
# RawModel is the InvokeAI wrapper class for ip_adapters, loras, textual_inversion and onnx runtime
40-
AnyModel = Union[ModelMixin, RawModel, torch.nn.Module, Dict[str, torch.Tensor], diffusers.DiffusionPipeline]
41+
AnyModel = Union[
42+
ModelMixin, RawModel, torch.nn.Module, Dict[str, torch.Tensor], diffusers.DiffusionPipeline, DepthAnythingPipeline
43+
]
4144

4245

4346
class InvalidModelConfigException(Exception):

invokeai/backend/model_manager/load/model_util.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from diffusers.schedulers.scheduling_utils import SchedulerMixin
1212
from transformers import CLIPTokenizer
1313

14+
from invokeai.backend.image_util.depth_anything.depth_anything_pipeline import DepthAnythingPipeline
1415
from invokeai.backend.ip_adapter.ip_adapter import IPAdapter
1516
from invokeai.backend.lora import LoRAModelRaw
1617
from invokeai.backend.model_manager.config import AnyModel
@@ -34,7 +35,9 @@ def calc_model_size_by_data(logger: logging.Logger, model: AnyModel) -> int:
3435
elif isinstance(model, CLIPTokenizer):
3536
# TODO(ryand): Accurately calculate the tokenizer's size. It's small enough that it shouldn't matter for now.
3637
return 0
37-
elif isinstance(model, (TextualInversionModelRaw, IPAdapter, LoRAModelRaw, SpandrelImageToImageModel)):
38+
elif isinstance(
39+
model, (TextualInversionModelRaw, IPAdapter, LoRAModelRaw, SpandrelImageToImageModel, DepthAnythingPipeline)
40+
):
3841
return model.calc_size()
3942
else:
4043
# TODO(ryand): Promote this from a log to an exception once we are confident that we are handling all of the

0 commit comments

Comments
 (0)