Skip to content

Commit

Permalink
[Local loading] Correct bug with local files only (#4318)
Browse files Browse the repository at this point in the history
* [Local loading] Correct bug with local files only

* file not found error

* fix

* finish
  • Loading branch information
patrickvonplaten committed Jul 27, 2023
1 parent a982916 commit 0709650
Show file tree
Hide file tree
Showing 8 changed files with 66 additions and 16 deletions.
18 changes: 16 additions & 2 deletions src/diffusers/pipelines/pipeline_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -1474,11 +1474,25 @@ def download(cls, pretrained_model_name, **kwargs) -> Union[str, os.PathLike]:
user_agent=user_agent,
)

if pipeline_class._load_connected_pipes:
# retrieve pipeline class from local file
cls_name = cls.load_config(os.path.join(cached_folder, "model_index.json")).get("_class_name", None)
pipeline_class = getattr(diffusers, cls_name, None)

if pipeline_class is not None and pipeline_class._load_connected_pipes:
modelcard = ModelCard.load(os.path.join(cached_folder, "README.md"))
connected_pipes = sum([getattr(modelcard.data, k, []) for k in CONNECTED_PIPES_KEYS], [])
for connected_pipe_repo_id in connected_pipes:
DiffusionPipeline.download(connected_pipe_repo_id)
download_kwargs = {
"cache_dir": cache_dir,
"resume_download": resume_download,
"force_download": force_download,
"proxies": proxies,
"local_files_only": local_files_only,
"use_auth_token": use_auth_token,
"variant": variant,
"use_safetensors": use_safetensors,
}
DiffusionPipeline.download(connected_pipe_repo_id, **download_kwargs)

return cached_folder

Expand Down
4 changes: 2 additions & 2 deletions tests/models/test_lora_layers.py
Original file line number Diff line number Diff line change
Expand Up @@ -563,10 +563,10 @@ def get_dummy_components(self):
projection_dim=32,
)
text_encoder = CLIPTextModel(text_encoder_config)
tokenizer = CLIPTokenizer.from_pretrained("hf-internal-testing/tiny-random-clip", local_files_only=True)
tokenizer = CLIPTokenizer.from_pretrained("hf-internal-testing/tiny-random-clip")

text_encoder_2 = CLIPTextModelWithProjection(text_encoder_config)
tokenizer_2 = CLIPTokenizer.from_pretrained("hf-internal-testing/tiny-random-clip", local_files_only=True)
tokenizer_2 = CLIPTokenizer.from_pretrained("hf-internal-testing/tiny-random-clip")

unet_lora_attn_procs, unet_lora_layers = create_unet_lora_layers(unet)
text_encoder_one_lora_layers = create_text_encoder_lora_layers(text_encoder)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,10 @@ def get_dummy_components(self):
projection_dim=32,
)
text_encoder = CLIPTextModel(text_encoder_config)
tokenizer = CLIPTokenizer.from_pretrained("hf-internal-testing/tiny-random-clip", local_files_only=True)
tokenizer = CLIPTokenizer.from_pretrained("hf-internal-testing/tiny-random-clip")

text_encoder_2 = CLIPTextModelWithProjection(text_encoder_config)
tokenizer_2 = CLIPTokenizer.from_pretrained("hf-internal-testing/tiny-random-clip", local_files_only=True)
tokenizer_2 = CLIPTokenizer.from_pretrained("hf-internal-testing/tiny-random-clip")

components = {
"unet": unet,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,10 @@ def get_dummy_components(self, skip_first_text_encoder=False):
projection_dim=32,
)
text_encoder = CLIPTextModel(text_encoder_config)
tokenizer = CLIPTokenizer.from_pretrained("hf-internal-testing/tiny-random-clip", local_files_only=True)
tokenizer = CLIPTokenizer.from_pretrained("hf-internal-testing/tiny-random-clip")

text_encoder_2 = CLIPTextModelWithProjection(text_encoder_config)
tokenizer_2 = CLIPTokenizer.from_pretrained("hf-internal-testing/tiny-random-clip", local_files_only=True)
tokenizer_2 = CLIPTokenizer.from_pretrained("hf-internal-testing/tiny-random-clip")

components = {
"unet": unet,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,10 @@ def get_dummy_components(self, skip_first_text_encoder=False):
projection_dim=32,
)
text_encoder = CLIPTextModel(text_encoder_config)
tokenizer = CLIPTokenizer.from_pretrained("hf-internal-testing/tiny-random-clip", local_files_only=True)
tokenizer = CLIPTokenizer.from_pretrained("hf-internal-testing/tiny-random-clip")

text_encoder_2 = CLIPTextModelWithProjection(text_encoder_config)
tokenizer_2 = CLIPTokenizer.from_pretrained("hf-internal-testing/tiny-random-clip", local_files_only=True)
tokenizer_2 = CLIPTokenizer.from_pretrained("hf-internal-testing/tiny-random-clip")

components = {
"unet": unet,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,10 @@ def get_dummy_components(self):
projection_dim=32,
)
text_encoder = CLIPTextModel(text_encoder_config)
tokenizer = CLIPTokenizer.from_pretrained("hf-internal-testing/tiny-random-clip", local_files_only=True)
tokenizer = CLIPTokenizer.from_pretrained("hf-internal-testing/tiny-random-clip")

text_encoder_2 = CLIPTextModelWithProjection(text_encoder_config)
tokenizer_2 = CLIPTokenizer.from_pretrained("hf-internal-testing/tiny-random-clip", local_files_only=True)
tokenizer_2 = CLIPTokenizer.from_pretrained("hf-internal-testing/tiny-random-clip")

components = {
"unet": unet,
Expand Down
40 changes: 38 additions & 2 deletions tests/pipelines/test_pipelines.py
Original file line number Diff line number Diff line change
Expand Up @@ -374,15 +374,15 @@ def test_cached_files_are_used_when_no_internet(self):
response_mock.json.return_value = {}

# Download this model to make sure it's in the cache.
orig_pipe = StableDiffusionPipeline.from_pretrained(
orig_pipe = DiffusionPipeline.from_pretrained(
"hf-internal-testing/tiny-stable-diffusion-torch", safety_checker=None
)
orig_comps = {k: v for k, v in orig_pipe.components.items() if hasattr(v, "parameters")}

# Under the mock environment we get a 500 error when trying to reach the model.
with mock.patch("requests.request", return_value=response_mock):
# Download this model to make sure it's in the cache.
pipe = StableDiffusionPipeline.from_pretrained(
pipe = DiffusionPipeline.from_pretrained(
"hf-internal-testing/tiny-stable-diffusion-torch", safety_checker=None
)
comps = {k: v for k, v in pipe.components.items() if hasattr(v, "parameters")}
Expand All @@ -392,6 +392,42 @@ def test_cached_files_are_used_when_no_internet(self):
if p1.data.ne(p2.data).sum() > 0:
assert False, "Parameters not the same!"

def test_local_files_only_are_used_when_no_internet(self):
# A mock response for an HTTP head request to emulate server down
response_mock = mock.Mock()
response_mock.status_code = 500
response_mock.headers = {}
response_mock.raise_for_status.side_effect = HTTPError
response_mock.json.return_value = {}

# first check that with local files only the pipeline can only be used if cached
with self.assertRaises(FileNotFoundError):
with tempfile.TemporaryDirectory() as tmpdirname:
orig_pipe = DiffusionPipeline.from_pretrained(
"hf-internal-testing/tiny-stable-diffusion-torch", local_files_only=True, cache_dir=tmpdirname
)

# now download
orig_pipe = DiffusionPipeline.download("hf-internal-testing/tiny-stable-diffusion-torch")

# make sure it can be loaded with local_files_only
orig_pipe = DiffusionPipeline.from_pretrained(
"hf-internal-testing/tiny-stable-diffusion-torch", local_files_only=True
)
orig_comps = {k: v for k, v in orig_pipe.components.items() if hasattr(v, "parameters")}

# Under the mock environment we get a 500 error when trying to connect to the internet.
# Make sure it works local_files_only only works here!
with mock.patch("requests.request", return_value=response_mock):
# Download this model to make sure it's in the cache.
pipe = DiffusionPipeline.from_pretrained("hf-internal-testing/tiny-stable-diffusion-torch")
comps = {k: v for k, v in pipe.components.items() if hasattr(v, "parameters")}

for m1, m2 in zip(orig_comps.values(), comps.values()):
for p1, p2 in zip(m1.parameters(), m2.parameters()):
if p1.data.ne(p2.data).sum() > 0:
assert False, "Parameters not the same!"

def test_download_from_variant_folder(self):
for safe_avail in [False, True]:
import diffusers
Expand Down
4 changes: 2 additions & 2 deletions tests/pipelines/test_pipelines_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,7 @@ def _test_inference_batch_consistent(
batched_inputs[name] = [value[: len_prompt // i] for i in range(1, batch_size + 1)]

# make last batch super long
batched_inputs[name][-1] = 2000 * "very long"
batched_inputs[name][-1] = 100 * "very long"
# or else we have images
else:
batched_inputs[name] = batch_size * [value]
Expand Down Expand Up @@ -462,7 +462,7 @@ def _test_inference_batch_single_identical(
batched_inputs[name] = [value[: len_prompt // i] for i in range(1, batch_size + 1)]

# make last batch super long
batched_inputs[name][-1] = 2000 * "very long"
batched_inputs[name][-1] = 100 * "very long"
# or else we have images
else:
batched_inputs[name] = batch_size * [value]
Expand Down

0 comments on commit 0709650

Please sign in to comment.