Buckets:

mishig's picture
|
download
raw
24.4 kB

IP-Adapter

IP-Adapter는 텍스트 프롬프트를 유지하면서 참조 이미지를 사용하여 사전 학습된 diffusion 모델의 생성 방향을 제어합니다. 이 방법은 베이스 모델을 동결하고 작은 규모의 이미지 cross-attention 레이어를 추가하므로, fine-tuning 없이 사진의 대상이나 스타일을 일치시키는 데 실용적입니다.

text prompt                         reference image
    |                                     |
 text encoder                        image encoder
    |                                     |
    v                                     v
 text cross-attn  (frozen)          IP-Adapter cross-attn
    \                                     /
     \                                   /
      +-------->  denoiser  <-----------+
                  (frozen base)

IP-Adapter 체크포인트는 전체 모델이 아닌 어댑터 가중치만 저장하므로 일반적으로 약 100MB입니다. 먼저 기본 파이프라인을 로드한 다음 load_ip_adapter()로 어댑터를 로드합니다.

IP-Adapters는 Flux와 Stable Diffusion 3를 비롯한 다양한 모델에서 사용할 수 있습니다. 이 가이드의 예제는 Stable Diffusion과 Stable Diffusion XL를 사용합니다.

set_ip_adapter_scale()를 사용하여 IP-Adapter가 생성을 얼마나 강하게 유도하는지 제어할 수 있습니다. 1.0은 어댑터를 최대 강도로 적용하며, 0.5는 일반적으로 텍스트 프롬프트와 이미지 프롬프트의 균형을 맞춥니다.

IP-Adapter를 일반적인 작업에 적용하는 예제를 아래에 보여줍니다.

import torch
from diffusers import AutoPipelineForText2Image
from diffusers.utils import load_image

pipeline = AutoPipelineForText2Image.from_pretrained(
  "stabilityai/stable-diffusion-xl-base-1.0",
  dtype=torch.float16
).to("cuda")  # or "mps", "xpu", "cpu"
pipeline.load_ip_adapter(
  "h94/IP-Adapter",
  subfolder="sdxl_models",
  weight_name="ip-adapter_sdxl.bin"
)
pipeline.set_ip_adapter_scale(0.8)

이미지를 ip_adapter_image에 텍스트 프롬프트와 함께 전달하여 이미지를 생성합니다.

image = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/ip_adapter_diner.png")
pipeline(
    prompt="a polar bear sitting in a chair drinking a milkshake",
    ip_adapter_image=image,
    negative_prompt="deformed, ugly, wrong proportion, low res, bad anatomy, worst quality, low quality",
).images[0]
IP-Adapter 이미지



생성된 이미지
import torch
from diffusers import AutoPipelineForImage2Image
from diffusers.utils import load_image

pipeline = AutoPipelineForImage2Image.from_pretrained(
  "stabilityai/stable-diffusion-xl-base-1.0",
  dtype=torch.float16
).to("cuda")  # or "mps", "xpu", "cpu"
pipeline.load_ip_adapter(
  "h94/IP-Adapter",
  subfolder="sdxl_models",
  weight_name="ip-adapter_sdxl.bin"
)
pipeline.set_ip_adapter_scale(0.8)

image = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/ip_adapter_bear_1.png")
ip_image = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/ip_adapter_gummy.png")
pipeline(
    prompt="best quality, high quality",
    image=image,
    ip_adapter_image=ip_image,
    strength=0.5,
).images[0]
입력 이미지



IP-Adapter 이미지



생성된 이미지
import torch
from diffusers import AutoPipelineForInpainting
from diffusers.utils import load_image

pipeline = AutoPipelineForInpainting.from_pretrained(
  "stabilityai/stable-diffusion-xl-base-1.0",
  dtype=torch.float16
).to("cuda")  # or "mps", "xpu", "cpu"
pipeline.load_ip_adapter(
  "h94/IP-Adapter",
  subfolder="sdxl_models",
  weight_name="ip-adapter_sdxl.bin"
)
pipeline.set_ip_adapter_scale(0.6)

mask_image = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/ip_adapter_mask.png")
image = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/ip_adapter_bear_1.png")
ip_image = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/ip_adapter_gummy.png")
pipeline(
    prompt="a cute gummy bear waving",
    image=image,
    mask_image=mask_image,
    ip_adapter_image=ip_image,
).images[0]
입력 이미지



IP-Adapter 이미지



생성된 이미지

enable_model_cpu_offload() 메서드는 메모리를 줄이는 데 유용하며, IP-Adapter가 로드된 후에 활성화해야 합니다. 그렇지 않으면 IP-Adapter의 이미지 인코더도 CPU로 오프로드되어 오류가 반환됩니다.

import torch
from diffusers import AnimateDiffPipeline, DDIMScheduler, MotionAdapter
from diffusers.utils import export_to_gif
from diffusers.utils import load_image

adapter = MotionAdapter.from_pretrained(
  "guoyww/animatediff-motion-adapter-v1-5-2",
  dtype=torch.float16
)
pipeline = AnimateDiffPipeline.from_pretrained(
  "emilianJR/epiCRealism",
  motion_adapter=adapter,
  dtype=torch.float16
)
scheduler = DDIMScheduler.from_pretrained(
    "emilianJR/epiCRealism",
    subfolder="scheduler",
    clip_sample=False,
    timestep_spacing="linspace",
    beta_schedule="linear",
    steps_offset=1,
)
pipeline.scheduler = scheduler
pipeline.vae.enable_slicing()
pipeline.load_ip_adapter("h94/IP-Adapter", subfolder="models", weight_name="ip-adapter_sd15.bin")
pipeline.enable_model_cpu_offload()

ip_adapter_image = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/ip_adapter_inpaint.png")
pipeline(
    prompt="A cute gummy bear waving",
    negative_prompt="bad quality, worse quality, low resolution",
    ip_adapter_image=ip_adapter_image,
    num_frames=16,
    guidance_scale=7.5,
    num_inference_steps=50,
).frames[0]
IP-Adapter 이미지



생성된 비디오

Checkpoint 변형

참조 이미지의 세부 정보가 가장 중요한 경우 Load Plus를 로드하세요. CLIP 이미지 임베딩 대신 InsightFace의 ID 임베딩이 필요한 경우 Load FaceID를 로드하세요.

import torch
from transformers import CLIPVisionModelWithProjection
from diffusers import AutoPipelineForText2Image

image_encoder = CLIPVisionModelWithProjection.from_pretrained(
    "h94/IP-Adapter",
    subfolder="models/image_encoder",
    dtype=torch.float16
)

pipeline = AutoPipelineForText2Image.from_pretrained(
    "stabilityai/stable-diffusion-xl-base-1.0",
    image_encoder=image_encoder,
    dtype=torch.float16
).to("cuda")  # or "mps", "xpu", "cpu"

pipeline.load_ip_adapter(
  "h94/IP-Adapter",
  subfolder="sdxl_models",
  weight_name="ip-adapter-plus_sdxl_vit-h.safetensors"
)

FaceID 체크포인트는 CLIP 이미지 임베딩 대신 InsightFace의 얼굴 임베딩을 사용합니다. FaceID 모델에는 DDIMScheduler 또는 EulerDiscreteScheduler를 사용하세요. 얼굴 임베딩을 추출하여 ip_adapter_image_embeds에 텐서 목록으로 전달하세요.

# pip install insightface
import cv2
import numpy as np
import torch
from diffusers import StableDiffusionPipeline, DDIMScheduler
from diffusers.utils import load_image
from insightface.app import FaceAnalysis

pipeline = StableDiffusionPipeline.from_pretrained(
    "stable-diffusion-v1-5/stable-diffusion-v1-5",
    dtype=torch.float16,
).to("cuda")  # or "mps", "xpu", "cpu"
pipeline.scheduler = DDIMScheduler.from_config(pipeline.scheduler.config)
pipeline.load_ip_adapter(
  "h94/IP-Adapter-FaceID",
  subfolder=None,
  weight_name="ip-adapter-faceid_sd15.bin",
  image_encoder_folder=None
)
pipeline.set_ip_adapter_scale(0.6)

image = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/ip_mask_girl1.png")

ref_images_embeds = []
app = FaceAnalysis(name="buffalo_l", providers=['CUDAExecutionProvider', 'CPUExecutionProvider'])
app.prepare(ctx_id=0, det_size=(640, 640))
image = cv2.cvtColor(np.asarray(image), cv2.COLOR_RGB2BGR)
faces = app.get(image)
image = torch.from_numpy(faces[0].normed_embedding)
ref_images_embeds.append(image.unsqueeze(0))
ref_images_embeds = torch.stack(ref_images_embeds, dim=0).unsqueeze(0)
neg_ref_images_embeds = torch.zeros_like(ref_images_embeds)
id_embeds = torch.cat([neg_ref_images_embeds, ref_images_embeds]).to(dtype=torch.float16, device="cuda")

pipeline(
    prompt="A photo of a girl",
    ip_adapter_image_embeds=[id_embeds],
    negative_prompt="monochrome, lowres, bad anatomy, worst quality, low quality",
).images[0]

FaceID Plus의 경우, 이미지 인코더로 CLIPVisionModelWithProjection를 로드합니다.

import torch
from transformers import CLIPVisionModelWithProjection
from diffusers import AutoPipelineForText2Image

image_encoder = CLIPVisionModelWithProjection.from_pretrained(
    "laion/CLIP-ViT-H-14-laion2B-s32B-b79K",
    dtype=torch.float16,
)

pipeline = AutoPipelineForText2Image.from_pretrained(
    "stable-diffusion-v1-5/stable-diffusion-v1-5",
    image_encoder=image_encoder,
    dtype=torch.float16
).to("cuda")  # or "mps", "xpu", "cpu"

pipeline.load_ip_adapter(
  "h94/IP-Adapter-FaceID",
  subfolder=None,
  weight_name="ip-adapter-faceid-plus_sd15.bin"
)

FaceID Plus와 Plus v2는 InsightFace 임베딩 외에도 CLIP 이미지 임베딩이 필요합니다. 얼굴 임베딩을 준비한 후, 참조 이미지를 인코딩하고 CLIP 임베딩을 이미지 투영 레이어에 할당하세요.

import torch
from diffusers.utils import load_image

ip_adapter_images = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/ip_mask_girl1.png")
num_images = 1
clip_embeds = pipeline.prepare_ip_adapter_image_embeds(
    ip_adapter_image=[ip_adapter_images],
    ip_adapter_image_embeds=None,
    device=torch.device("cuda"),
    num_images_per_prompt=num_images,
    do_classifier_free_guidance=True,
)[0]

pipeline.unet.encoder_hid_proj.image_projection_layers[0].clip_embeds = clip_embeds.to(dtype=torch.float16)
# set to True if using IP-Adapter FaceID Plus v2
pipeline.unet.encoder_hid_proj.image_projection_layers[0].shortcut = False

이미지 임베딩

prepare_ip_adapter_image_embeds()은 IP-Adapter 이미지를 저장하고 재사용할 수 있는 임베딩으로 인코딩합니다. 파이프라인을 실행할 때마다 동일한 이미지를 로드하고 인코딩하는 대신, 한 번만 사전 계산해 두세요.

import torch
from diffusers import AutoPipelineForText2Image
from diffusers.utils import load_image

pipeline = AutoPipelineForText2Image.from_pretrained(
  "stabilityai/stable-diffusion-xl-base-1.0",
  dtype=torch.float16
).to("cuda")  # or "mps", "xpu", "cpu"
pipeline.load_ip_adapter(
  "h94/IP-Adapter",
  subfolder="sdxl_models",
  weight_name="ip-adapter_sdxl.bin"
)

image = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/ip_adapter_bear_1.png")
image_embeds = pipeline.prepare_ip_adapter_image_embeds(
    ip_adapter_image=image,
    ip_adapter_image_embeds=None,
    device="cuda",
    num_images_per_prompt=1,
    do_classifier_free_guidance=True,
)

torch.save(image_embeds, "image_embeds.ipadpt")

ip_adapter_image_embeds 매개변수에 이미지 임베딩을 전달하여 다시 로드합니다. 이제 이미지 임베딩을 생성하는 데 이미지 인코더가 더 이상 필요하지 않으므로 image_encoder_folder을 None으로 설정합니다.

ComfyUI와 같은 다른 소스에서 이미지 임베딩을 로드할 수도 있습니다.

pipeline = AutoPipelineForText2Image.from_pretrained(
  "stabilityai/stable-diffusion-xl-base-1.0",
  dtype=torch.float16
).to("cuda")  # or "mps", "xpu", "cpu"
pipeline.load_ip_adapter(
  "h94/IP-Adapter",
  subfolder="sdxl_models",
  image_encoder_folder=None,
  weight_name="ip-adapter_sdxl.bin"
)
pipeline.set_ip_adapter_scale(0.8)
image_embeds = torch.load("image_embeds.ipadpt")
pipeline(
    prompt="a polar bear sitting in a chair drinking a milkshake",
    ip_adapter_image_embeds=image_embeds,
    negative_prompt="deformed, ugly, wrong proportion, low res, bad anatomy, worst quality, low quality",
    num_inference_steps=100,
).images[0]

마스킹

Binary masking은 IP-Adapter 이미지를 출력 이미지의 특정 영역에 할당할 수 있게 하여, 여러 IP-Adapter 이미지를 구성하는 데 유용합니다. 각 IP-Adapter 이미지에는 바이너리 마스크가 필요합니다.

이미지 마스크를 전처리하기 위해 IPAdapterMaskProcessor를 로드합니다. 최적의 결과를 얻으려면 서로 다른 종횡비를 가진 마스크가 적절하게 크기가 조정되도록 출력 height와 width를 제공하세요. 입력 마스크가 이미 생성된 이미지의 종횡비와 일치하는 경우 height와 width를 설정할 필요가 없습니다.

import torch
from diffusers import AutoPipelineForText2Image
from diffusers.image_processor import IPAdapterMaskProcessor
from diffusers.utils import load_image

pipeline = AutoPipelineForText2Image.from_pretrained(
  "stabilityai/stable-diffusion-xl-base-1.0",
  dtype=torch.float16
).to("cuda")  # or "mps", "xpu", "cpu"

mask1 = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/ip_mask_mask1.png")
mask2 = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/ip_mask_mask2.png")

processor = IPAdapterMaskProcessor()
masks = processor.preprocess([mask1, mask2], height=1024, width=1024)
마스크 1



mask 2

IP-Adapter 이미지와 해당 스케일을 리스트로 함께 제공합니다. 전처리된 마스크를 파이프라인의 cross_attention_kwargs에 전달합니다.

face_image1 = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/ip_mask_girl1.png")
face_image2 = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/ip_mask_girl2.png")

pipeline.load_ip_adapter(
  "h94/IP-Adapter",
  subfolder="sdxl_models",
  weight_name=["ip-adapter-plus-face_sdxl_vit-h.safetensors"]
)
pipeline.set_ip_adapter_scale([[0.7, 0.7]])

ip_images = [[face_image1, face_image2]]
masks = [masks.reshape(1, masks.shape[0], masks.shape[2], masks.shape[3])]

pipeline(
  prompt="2 girls",
  ip_adapter_image=ip_images,
  negative_prompt="monochrome, lowres, bad anatomy, worst quality, low quality",
  cross_attention_kwargs={"ip_adapter_masks": masks}
).images[0]
  IP-Adapter 이미지 1


  
  IP-Adapter 이미지 2




  
  generated with mask


  
  마스크 없이 생성

레시피

IP-Adapter를 여러 어댑터, ControlNet, InstantStyle, 또는 few-step LCM와 같은 다른 어댑터나 파이프라인과 결합하여 하나의 참조 이미지가 충분하지 않은 경우를 처리합니다.

여러 IP-Adapter

여러 IP-Adapter를 조합하여 더 다양한 스타일의 이미지를 생성할 수 있습니다. 예를 들어, IP-Adapter Face를 사용하여 일관된 얼굴과 캐릭터를 생성하고, IP-Adapter Plus를 사용하여 해당 얼굴을 특정 스타일로 생성할 수 있습니다.

CLIPVisionModelWithProjection로 이미지 인코더를 로드합니다.

import torch
from diffusers import AutoPipelineForText2Image, DDIMScheduler
from transformers import CLIPVisionModelWithProjection
from diffusers.utils import load_image

image_encoder = CLIPVisionModelWithProjection.from_pretrained(
    "h94/IP-Adapter",
    subfolder="models/image_encoder",
    dtype=torch.float16,
)

base model, scheduler 및 다음 IP-Adapters를 로드합니다.

pipeline = AutoPipelineForText2Image.from_pretrained(
    "stabilityai/stable-diffusion-xl-base-1.0",
    dtype=torch.float16,
    image_encoder=image_encoder,
)
pipeline.scheduler = DDIMScheduler.from_config(pipeline.scheduler.config)
pipeline.load_ip_adapter(
  "h94/IP-Adapter",
  subfolder="sdxl_models",
  weight_name=["ip-adapter-plus_sdxl_vit-h.safetensors", "ip-adapter-plus-face_sdxl_vit-h.safetensors"]
)
pipeline.set_ip_adapter_scale([0.7, 0.3])
# enable_model_cpu_offload to reduce memory usage
pipeline.enable_model_cpu_offload()

이미지와 특정 스타일을 적용할 이미지들이 포함된 폴더를 로드합니다.

face_image = load_image("https://huggingface.co/datasets/YiYiXu/testing-images/resolve/main/women_input.png")
style_folder = "https://huggingface.co/datasets/YiYiXu/testing-images/resolve/main/style_ziggy"
style_images = [load_image(f"{style_folder}/img{i}.png") for i in range(10)]
얼굴 이미지



스타일 이미지

ip_adapter_image에 스타일 및 얼굴 이미지를 리스트로 전달합니다.

generator = torch.Generator(device="cpu").manual_seed(0)

pipeline(
    prompt="wonderwoman",
    ip_adapter_image=[style_images, face_image],
    negative_prompt="monochrome, lowres, bad anatomy, worst quality, low quality",
).images[0]
생성된 이미지

구조적 제어

구조적 제어를 위해, 깊이 맵, 엣지 맵, 자세 추정 등을 조건으로 사용하는 ControlNet과 IP-Adapter를 결합하세요.

아래 예시에서는 깊이 맵에 조건부인 ControlNetModel 체크포인트를 로드하고 IP-Adapter와 결합합니다.

import torch
from diffusers.utils import load_image
from diffusers import StableDiffusionControlNetPipeline, ControlNetModel

controlnet = ControlNetModel.from_pretrained(
  "lllyasviel/control_v11f1p_sd15_depth",
  dtype=torch.float16
)

pipeline = StableDiffusionControlNetPipeline.from_pretrained(
    "stable-diffusion-v1-5/stable-diffusion-v1-5",
    controlnet=controlnet,
    dtype=torch.float16
).to("cuda")  # or "mps", "xpu", "cpu"
pipeline.load_ip_adapter(
  "h94/IP-Adapter",
  subfolder="models",
  weight_name="ip-adapter_sd15.bin"
)

깊이 맵과 IP-Adapter 이미지를 파이프라인에 전달합니다.

depth_map = load_image("https://huggingface.co/datasets/YiYiXu/testing-images/resolve/main/depth.png")
ip_adapter_image = load_image("https://huggingface.co/datasets/YiYiXu/testing-images/resolve/main/statue.png")
pipeline(
  prompt="best quality, high quality",
  image=depth_map,
  ip_adapter_image=ip_adapter_image,
  negative_prompt="monochrome, lowres, bad anatomy, worst quality, low quality",
).images[0]
IP-Adapter 이미지



깊이 맵



생성된 이미지

스타일 및 레이아웃 제어

스타일 및 레이아웃 제어를 위해 IP-Adapter를 InstantStyle과 함께 사용하세요. InstantStyle은 스타일(색상, 질감, 전반적인 느낌)을 콘텐츠와 분리하고, 스타일 전용 블록에만 스타일을 적용하여 콘텐츠 영역이 그대로 유지되도록 합니다. 이를 통해 더 강력한 스타일 일관성과 명확한 레이아웃 제어가 가능합니다.

set_ip_adapter_scale()를 사용하여 IP-Adapter를 선택된 레이어에서만 활성화합니다. 아래 예시에서는 모델의 down block_2(layout)과 up block_0(style)에서 활성화합니다.

import torch
from diffusers import AutoPipelineForText2Image
from diffusers.utils import load_image

pipeline = AutoPipelineForText2Image.from_pretrained(
  "stabilityai/stable-diffusion-xl-base-1.0",
  dtype=torch.float16
).to("cuda")  # or "mps", "xpu", "cpu"
pipeline.load_ip_adapter(
  "h94/IP-Adapter",
  subfolder="sdxl_models",
  weight_name="ip-adapter_sdxl.bin"
)

scale = {
    "down": {"block_2": [0.0, 1.0]},
    "up": {"block_0": [0.0, 1.0, 0.0]},
}
pipeline.set_ip_adapter_scale(scale)

스타일 이미지를 로드하고 이미지를 생성합니다.

style_image = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/0052a70beed5bf71b92610a43a52df6d286cd5f3/diffusers/rabbit.jpg")

pipeline(
    prompt="a cat, masterpiece, best quality, high quality",
    ip_adapter_image=style_image,
    negative_prompt="text, watermark, lowres, low quality, worst quality, deformed, glitch, low contrast, noisy, saturation, blurry",
    guidance_scale=5,
).images[0]
스타일 이미지



생성된 이미지

아래 그림은 InstantStyle의 스타일 전용 활성화(상위 block_0)와 모든 레이어에서 IP-Adapter를 활성화한 경우를 비교합니다. 모든 레이어 방식은 일반적으로 이미지 프롬프트를 더 강하게 따르며 다양성을 낮출 수 있습니다. InstantStyle의 레이아웃 보존 동작을 원할 경우 스타일 전용 스케일을 사용하는 것이 좋습니다.

scale 사전에 모든 레이어를 지정할 필요는 없습니다. 포함되지 않은 레이어는 0으로 설정되며, 이는 IP-Adapter가 비활성화됨을 의미합니다.

scale = {
    "up": {"block_0": [0.0, 1.0, 0.0]},
}
pipeline.set_ip_adapter_scale(scale)

pipeline(
    prompt="a cat, masterpiece, best quality, high quality",
    ip_adapter_image=style_image,
    negative_prompt="text, watermark, lowres, low quality, worst quality, deformed, glitch, low contrast, noisy, saturation, blurry",
    guidance_scale=5,
).images[0]
style-only (up block_0)



모든 레이어

즉시 생성

IP-Adapter를 LCM LoRA와 결합하여 소수 스텝 생성을 수행합니다.

import torch
from diffusers import DiffusionPipeline, LCMScheduler
from diffusers.utils import load_image

pipeline = DiffusionPipeline.from_pretrained(
  "sd-dreambooth-library/herge-style",
  dtype=torch.float16
)
pipeline.load_ip_adapter(
  "h94/IP-Adapter",
  subfolder="models",
  weight_name="ip-adapter_sd15.bin"
)
pipeline.load_lora_weights("latent-consistency/lcm-lora-sdv1-5")
pipeline.scheduler = LCMScheduler.from_config(pipeline.scheduler.config)
pipeline.enable_model_cpu_offload()

pipeline.set_ip_adapter_scale(0.4)
ip_adapter_image = load_image("https://user-images.githubusercontent.com/24734142/266492875-2d50d223-8475-44f0-a7c6-08b51cb53572.png")
pipeline(
    prompt="herge_style woman in armor, best quality, high quality",
    ip_adapter_image=ip_adapter_image,
    num_inference_steps=4,
    guidance_scale=1,
).images[0]
생성된 이미지

Xet Storage Details

Size:
24.4 kB
·
Xet hash:
b4aab903355ab8781b02f4beef7cd8b57cda28bde4aa7b01294e40ce673ed811

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.