Buckets:

mishig's picture
|
download
raw
33.5 kB

深度から画像へ

Stable Diffusion モデルは、MiDaS を使用して画像から深度を推定することもできます。これにより、新しい画像の生成を条件付けするためのテキストプロンプトと初期画像に加えて、画像の構造を保持するための depth_map を渡すことが可能になります。

スケジューラーの速度と品質のトレードオフをどのように探索するか、またパイプラインのコンポーネントを効率的に再利用する方法を学ぶために、Stable DiffusionのTipsセクションをぜひご確認ください。

タスクに公式チェックポイントのいずれかを使用する場合は、CompVis と Stability AI の Hub 組織を探索してください!

StableDiffusionDepth2ImgPipeline[[diffusers.StableDiffusionDepth2ImgPipeline]]

diffusers.StableDiffusionDepth2ImgPipeline[[diffusers.StableDiffusionDepth2ImgPipeline]]

diffusers.StableDiffusionDepth2ImgPipeline(vae: AutoencoderKL, text_encoder: CLIPTextModel, tokenizer: CLIPTokenizer, unet: UNet2DConditionModel, scheduler: KarrasDiffusionSchedulers, depth_estimator: DPTForDepthEstimation, feature_extractor: DPTImageProcessorPil)

ソース

パラメータ:

vae (AutoencoderKL) : 画像を潜在表現にエンコードし、潜在表現からデコードするための変分オートエンコーダ(VAE)モデル。

text_encoder (CLIPTextModel) : 凍結されたテキストエンコーダー (clip-vit-large-patch14)。

tokenizer (CLIPTokenizer) : テキストをトークン化するためのCLIPTokenizer。

unet (UNet2DConditionModel) : エンコードされた画像の潜在変数をノイズ除去するための UNet2DConditionModel。

scheduler (SchedulerMixin) : unet と組み合わせて、エンコードされた画像の潜在変数をデノイズするために使用するスケジューラ。DDIMScheduler、LMSDiscreteScheduler、または PNDMScheduler のいずれかです。

Stable Diffusion を使用した、テキストガイドによる深度ベースの画像から画像への生成を行う Pipeline です。

このモデルは DiffusionPipeline を継承しています。すべてのパイプラインに実装されている汎用的なメソッド(ダウンロード、保存、特定のデバイスでの実行など)については、スーパークラスのドキュメントを参照してください。

パイプラインは、以下の読み込みメソッドも継承します:

call[[diffusers.StableDiffusionDepth2ImgPipeline.call]]

__call__(prompt: str | list[str] = None, image: typing.Union[PIL.Image.Image, numpy.ndarray, torch.Tensor, list[PIL.Image.Image], list[numpy.ndarray], list[torch.Tensor]] = None, depth_map: typing.Optional[torch.Tensor] = None, strength: float = 0.8, num_inference_steps: int | None = 50, guidance_scale: float | None = 7.5, negative_prompt: str | list[str] | None = None, num_images_per_prompt: int | None = 1, eta: float | None = 0.0, generator: typing.Union[torch.Generator, list[torch.Generator], NoneType] = None, prompt_embeds: typing.Optional[torch.Tensor] = None, negative_prompt_embeds: typing.Optional[torch.Tensor] = None, output_type: str | None = 'pil', return_dict: bool = True, cross_attention_kwargs: dict[str, typing.Any] | None = None, clip_skip: int | None = None, callback_on_step_end: typing.Optional[typing.Callable[[int, int], NoneType]] = None, callback_on_step_end_tensor_inputs: list[str] = ['latents'], **kwargs)

ソース

パラメータ:

prompt (str または list[str]、省略可能) : 画像生成をガイドするためのプロンプトです。定義されていない場合は、prompt_embeds を渡す必要があります。

image (torch.Tensor、PIL.Image.Image、np.ndarray、list[torch.Tensor]、list[PIL.Image.Image]、または list[np.ndarray]) : 開始点として使用される画像バッチを表す Image またはテンソル。depth_map が None でない場合のみ、image として画像潜在変数を受け取れます。

depth_map (torch.Tensor, 任意) : 画像生成プロセスの追加条件として使用する深度予測。未定義の場合、self.depth_estimator を用いて自動的に深度を予測します。

strength (float、任意、デフォルト値は 0.8) : 参照となるimageの変換の程度を示します。0 から 1 の間の値である必要があります。imageは開始点として使用され、strengthが大きいほど多くのノイズが追加されます。デノイジングのステップ数は、最初に追加されるノイズの量に依存します。strengthが 1 の場合、追加されるノイズは最大となり、デノイジングプロセスはnum_inference_stepsで指定された全イテレーション数分実行されます。値が 1 である場合、imageは実質的に無視されます。

num_inference_steps (int、任意、デフォルト値は 50) : デノイジングのステップ数です。デノイジングのステップ数を増やすと、推論速度が遅くなる代わりに、通常はより高品質な画像が得られます。このパラメータは strength によって調整されます。

guidance_scale (float、任意、デフォルト値は 7.5) : 高い guidance scale の値は、画像の品質が低下する代わりに、テキストの prompt と密接に関連した画像を生成するようモデルを促します。guidance_scale > 1 の場合、guidance scale が有効になります。

negative_prompt (str または list[str]、省略可能) : 画像生成に含めるべきでない内容を指示するためのプロンプトまたはプロンプトのリストです。定義されていない場合、代わりに negative_prompt_embeds を渡す必要があります。ガイダンスを使用していない場合(guidance_scale < 1)は無視されます。

num_images_per_prompt (int、任意、デフォルトは 1) : プロンプトごとに生成する画像の数。

eta (float、任意、デフォルト値は 0.0) : DDIM論文のパラメータ eta (η) に対応します。DDIMSchedulerでのみ適用され、他のスケジューラーでは無視されます。

generator (torch.Generator または list[torch.Generator]、任意) : 生成を決定論的にするための torch.Generator。

prompt_embeds (torch.Tensor, 任意) : 事前に生成されたテキスト埋め込み。テキスト入力(プロンプトの重み付け)を簡単に調整するために使用できます。指定されない場合、prompt 入力引数からテキスト埋め込みが生成されます。

negative_prompt_embeds (torch.Tensor, 任意) : 事前に生成されたネガティブなテキスト埋め込み。テキスト入力(プロンプトの重み付け)を簡単に調整するために使用できます。指定されない場合、negative_prompt_embeds は negative_prompt 入力引数から生成されます。

output_type (str、任意、デフォルトは"pil") : 生成された画像の出力形式。PIL.Imageまたはnp.arrayから選択します。

return_dict (bool、任意、デフォルトはTrue) : プレーンなタプルではなく、StableDiffusionPipelineOutputを返すかどうか。

cross_attention_kwargs (dict, 任意) : 指定された場合、self.processor で定義されている AttentionProcessor に渡される kwargs の辞書です。

clip_skip (int, optional) : プロンプト埋め込みを計算する際に、CLIPからスキップするレイヤー数。値が1の場合、プロンプト埋め込みの計算に最終レイヤーの直前のレイヤーの出力が使用されます。

callback_on_step_end (Callable、任意) : 推論中の各デノイジングステップの終了時に呼び出される関数です。この関数は、以下の引数とともに呼び出されます: callback_on_step_end(self: DiffusionPipeline, step: int, timestep: int, callback_kwargs: Dict)。 callback_kwargs には、callback_on_step_end_tensor_inputs で指定されたすべてのテンソルのリストが含まれます。

callback_on_step_end_tensor_inputs (list, 任意) : callback_on_step_end 関数へのテンソル入力のリストです。リストで指定されたテンソルは、callback_kwargs 引数として渡されます。パイプラインクラスの ._callback_tensor_inputs 属性に列挙された変数のみを、リストに含めることができます。

戻り値: StableDiffusionPipelineOutput または tuple

return_dict が True の場合、StableDiffusionPipelineOutput が返され、それ以外の場合は、最初の要素が生成された画像のリストである tuple が返されます。

生成用の pipeline への呼び出し関数。

例:

>>> import torch
>>> import requests
>>> from PIL import Image

>>> from diffusers import StableDiffusionDepth2ImgPipeline

>>> pipe = StableDiffusionDepth2ImgPipeline.from_pretrained(
...     "stabilityai/stable-diffusion-2-depth",
...     torch_dtype=torch.float16,
... )
>>> pipe.to("cuda")

>>> url = "http://images.cocodataset.org/val2017/000000039769.jpg"
>>> init_image = Image.open(requests.get(url, stream=True).raw)
>>> prompt = "two tigers"
>>> n_prompt = "bad, deformed, ugly, bad anotomy"
>>> image = pipe(prompt=prompt, image=init_image, negative_prompt=n_prompt, strength=0.7).images[0]

enable_attention_slicing[[diffusers.StableDiffusionDepth2ImgPipeline.enable_attention_slicing]]

enable_attention_slicing(slice_size: str | int = 'auto')

ソース

パラメータ:

slice_size (str または int、任意、デフォルトは "auto") : "auto" の場合、アテンションヘッドへの入力を半分にし、アテンションを2段階で計算します。"max" の場合、一度に1つのスライスのみを実行することで、最大限のメモリを節約します。数値が指定された場合、attention_head_dim // slice_size 個のスライスを 사용합니다。この場合、attention_head_dim は slice_size の倍数である必要があります。

スライスされたアテンション計算を有効にします。このオプションを有効にすると、アテンションモジュールは入力テンソルをスライスに分割し、複数ステップでアテンションを計算します。アテンションヘッドが1つを超える場合、各ヘッドに対して計算が順次実行されます。これは、わずかな速度低下を代償にメモリを節約するために有用です。

> ⚠️ scaled_dot_product_attention(SDPA)をすでに使用している場合は、attention slicing を有効にしないでください PyTorch > 2.0 または xFormers から。これらのアテンション計算はすでに非常にメモリ効率が高いため、この機能を有効にする必要はありません。SDPA または xFormers でアテンションスライシングを有効にすると、重大なスローダウンを引き起こす可能性があります!

例:

>>> import torch
>>> from diffusers import StableDiffusionPipeline

>>> pipe = StableDiffusionPipeline.from_pretrained(
...     "stable-diffusion-v1-5/stable-diffusion-v1-5",
...     dtype=torch.float16,
...     use_safetensors=True,
... )

>>> prompt = "a photo of an astronaut riding a horse on mars"
>>> pipe.enable_attention_slicing()
>>> image = pipe(prompt).images[0]

disable_attention_slicing[[diffusers.StableDiffusionDepth2ImgPipeline.disable_attention_slicing]]

disable_attention_slicing()

ソース

スライスされたアテンションの計算を無効にします。enable_attention_slicingが以前に呼び出されていた場合、アテンションは1ステップで計算されます。

enable_xformers_memory_efficient_attention[[diffusers.StableDiffusionDepth2ImgPipeline.enable_xformers_memory_efficient_attention]]

enable_xformers_memory_efficient_attention(attention_op: typing.Optional[typing.Callable] = None)

ソース

パラメータ:

attention_op (Callable、任意) : xFormers の memory_efficient_attention() 関数の op 引数として使用するために、デフォルトの None オペレーターをオーバーライドします。

xFormersからメモリ効率の高いアテンションを有効にします。このオプションを有効にすると、GPUメモリ使用量の低下と、推論時の処理速度の向上が期待できます。ただし、学習時の処理速度向上は保証されません。

> ⚠️ メモリ効率の良いアテンションとスライスされたアテンションの両方が有効な場合、メモリ効率 attention は > に優先します。

例:

>>> import torch
>>> from diffusers import DiffusionPipeline
>>> from xformers.ops import MemoryEfficientAttentionFlashAttentionOp

>>> pipe = DiffusionPipeline.from_pretrained("stabilityai/stable-diffusion-2-1", dtype=torch.float16)
>>> pipe = pipe.to("cuda")
>>> pipe.enable_xformers_memory_efficient_attention(attention_op=MemoryEfficientAttentionFlashAttentionOp)
>>> # Workaround for not accepting attention shape using VAE for Flash Attention
>>> pipe.vae.enable_xformers_memory_efficient_attention(attention_op=None)

disable_xformers_memory_efficient_attention[[diffusers.StableDiffusionDepth2ImgPipeline.disable_xformers_memory_efficient_attention]]

disable_xformers_memory_efficient_attention()

ソース

xFormersからのメモリ効率の高いアテンションを無効にします。

load_textual_inversion[[diffusers.StableDiffusionDepth2ImgPipeline.load_textual_inversion]]

load_textual_inversion(pretrained_model_name_or_path: str | list[str] | dict[str, torch.Tensor] | list[dict[str, torch.Tensor]], token: str | list[str] | None = None, tokenizer: 'PreTrainedTokenizer' | None = None, text_encoder: 'PreTrainedModel' | None = None, **kwargs)

ソース

パラメータ:

pretrained_model_name_or_path (str または os.PathLike または list[str or os.PathLike] または Dict または list[Dict]) : 以下のいずれか、またはそれらのリストを指定できます。 - Hub にホストされている事前学習済みモデルの model id(例: sd-concepts-library/low-poly-hd-logos-icons)を表す文字列。 - テキストインバージョンの重みを含む ディレクトリ へのパス(例: ./my_text_inversion_directory/)。 - テキストインバージョンの重みを含む ファイル へのパス(例: ./my_text_inversions.pt)。 - torch state dict。

token (str または list[str]、省略可能) : テキスト反転の重みに使用するトークンを上書きします。pretrained_model_name_or_path がリストの場合、token も同じ長さのリストである必要があります。

text_encoder (CLIPTextModel、任意) : 凍結されたテキストエンコーダー (clip-vit-large-patch14)。指定しない場合、関数は self.tokenizer を使用します。

tokenizer (CLIPTokenizer、任意) : テキストをトークン化するためのCLIPTokenizer。指定しない場合、関数はself.tokenizerを使用します。

weight_name (str, 任意) : カスタム重みファイルの名前。次の場合に使用します。 - 保存されたテキストインバージョンファイルが🤗 Diffusers形式であるが、text_inv.binのような特定の重み名で保存されている場合。 - 保存されたテキストインバージョンファイルがAutomatic1111形式である場合。

cache_dir (str | os.PathLike、任意) : 標準のキャッシュを使用しない場合、ダウンロードした事前学習済みモデルの構成がキャッシュされるディレクトリのパス。

force_download (bool, 任意, デフォルトは False) : モデルの重みと設定ファイルの(再)ダウンロードを強制するかどうか。キャッシュされたバージョンが存在する場合でも、それを上書きします。

proxies (dict[str, str]、省略可) : プロトコルまたはエンドポイントごとに使用するプロキシサーバーの辞書です。例えば、{'http': 'foo.bar:3128', 'http://hostname': 'foo.bar:4012'} のように指定します。これらのプロキシは、各リクエストで使用されます。

local_files_only (bool、任意、デフォルトはFalse) : ローカルのモデルの重みと設定ファイルのみを読み込むかどうかを指定します。Trueに設定すると、モデルは Hub からダウンロードされません。

hf_token (str または bool、省略可能) : リモートファイルの HTTP ベアラ認証に使用するトークン。True の場合、diffusers-cli login で生成されたトークン(~/.huggingface に保存)が使用されます。

revision (str、任意、デフォルトは"main") : 使用する特定のモデルバージョンです。ブランチ名、タグ名、コミット ID、または Git で許可されている任意の識別子を使用できます。

subfolder (str、任意、デフォルトは "") : Hub またはローカル上のより大きなモデルリポジトリ内での、モデルファイルのサブフォルダの場所。

mirror (str, 任意) : 中国でモデルをダウンロードする場合、アクセシビリティの問題を解決するためのミラーソースを指定します。ソースの鮮度や安全性を保証するものではなく、詳細についてはミラーサイトをご参照ください。

StableDiffusionPipelineのテキストエンコーダーにTextual Inversionの埋め込みを読み込みます(🤗 Diffusers形式とAutomatic1111形式の両方をサポートしています)。

例:

🤗 Diffusers形式でTextual Inversion埋め込みベクトルを読み込むには:

from diffusers import StableDiffusionPipeline
import torch

model_id = "stable-diffusion-v1-5/stable-diffusion-v1-5"
pipe = StableDiffusionPipeline.from_pretrained(model_id, torch_dtype=torch.float16).to("cuda")

pipe.load_textual_inversion("sd-concepts-library/cat-toy")

prompt = "A <cat-toy> backpack"

image = pipe(prompt, num_inference_steps=50).images[0]
image.save("cat-backpack.png")

Automatic1111形式のTextual Inversion埋め込みベクトルを読み込むには、まずベクトルをダウンロードしてください(civitAIなどから)。その後、ベクトルを読み込みます。

ローカルで:

from diffusers import StableDiffusionPipeline
import torch

model_id = "stable-diffusion-v1-5/stable-diffusion-v1-5"
pipe = StableDiffusionPipeline.from_pretrained(model_id, torch_dtype=torch.float16).to("cuda")

pipe.load_textual_inversion("./charturnerv2.pt", token="charturnerv2")

prompt = "charturnerv2, multiple views of the same character in the same outfit, a character turnaround of a woman wearing a black jacket and red shirt, best quality, intricate details."

image = pipe(prompt, num_inference_steps=50).images[0]
image.save("character.png")

load_lora_weights[[diffusers.StableDiffusionDepth2ImgPipeline.load_lora_weights]]

load_lora_weights(pretrained_model_name_or_path_or_dict: str | dict[str, torch.Tensor], adapter_name: str | None = None, hotswap: bool = False, **kwargs)

ソース

パラメータ:

pretrained_model_name_or_path_or_dict (str または os.PathLike または dict) : lora_state_dict() を参照してください。

adapter_name (str, 省略可) : 読み込まれたアダプターモデルを参照するために使用するアダプター名。指定しない場合、読み込まれるアダプターの総数を i として default_{i} が使用されます。

low_cpu_mem_usage (bool, 省略可) : ランダムな重みの初期化を行わず、事前学習済み LoRA 重みのみを読み込むことで、モデルの読み込みを高速化します。

hotswap (bool, 任意) : デフォルトは False です。既存の (LoRA) アダプターを、新しく読み込まれたアダプターでその場で置き換えるかどうかを指定します。つまり、追加のアダプターを読み込むのではなく、既存のアダプターの重みを新しいアダプターの重みで置き換えます。これにより、より高速かつメモリ効率の高い処理が可能になります。ただし、ホットスワップの主な利点は、モデルが torch.compile でコンパイルされている場合、新しいアダプターを読み込んでもモデルの再コンパイルが不要になる点です。ホットスワップを使用する場合は、渡す adapter_name は、すでに読み込まれているアダプターの名前である必要があります。 新しいアダプターと古いアダプターでランクと/または LoRA alpha (すなわちスケーリング) が異なる場合、アダプターを読み込む前に追加のメソッドを呼び出す必要があります: py pipeline = ... # load diffusers pipeline max_rank = ... # the highest rank among all LoRAs that you want to load # call *before* compiling and loading the LoRA adapter pipeline.enable_lora_hotswap(target_rank=max_rank) pipeline.load_lora_weights(file_name) # optionally compile the model now テキストエンコーダーのアダプターのホットスワップは、まだサポートされていません。この技術にはいくつかの制限があり、以下にドキュメント化されています: https://huggingface.co/docs/peft/main/en/package_reference/hotswap

kwargs (dict、任意) : lora_state_dict()を参照してください。

pretrained_model_name_or_path_or_dict で指定された LoRA の重みを self.unet および self.text_encoder に読み込みます。

すべてのkwargsはself.lora_state_dictに転送されます。

ステートディクトの読み込み方法の詳細については、lora_state_dict()を参照してください。

self.unet にステートディクトがどのように読み込まれるかについては、load_lora_into_unet() を参照してください。

self.text_encoder に state dict がどのように読み込まれるかについては、load_lora_into_text_encoder() を参照してください。

save_lora_weights[[diffusers.StableDiffusionDepth2ImgPipeline.save_lora_weights]]

save_lora_weights(save_directory: str | os.PathLike, unet_lora_layers: dict[str, typing.Union[torch.nn.Module, torch.Tensor]] = None, text_encoder_lora_layers: dict[str, torch.nn.Module] = None, is_main_process: bool = True, weight_name: str = None, save_function: typing.Callable = None, safe_serialization: bool = True, unet_lora_adapter_metadata = None, text_encoder_lora_adapter_metadata = None)

ソース

パラメータ:

save_directory (str または os.PathLike) : LoRA パラメータを保存するディレクトリ。存在しない場合は作成されます。

unet_lora_layers (dict[str, torch.nn.Module] または dict[str, torch.Tensor]) : unet に対応する LoRA レイヤーの state dict。

text_encoder_lora_layers (dict[str, torch.nn.Module] または dict[str, torch.Tensor]) : text_encoder に対応する LoRA レイヤーの state dict。🤗 Transformers から取得されるため、テキストエンコーダーの LoRA state dict を明示的に渡す必要があります。

is_main_process (bool、任意、デフォルトはTrue) : この関数を呼び出したプロセスがメインプロセスかどうかを示します。分散学習時に、すべてのプロセスでこの関数を呼び出す必要がある場合に便利です。この場合、競合状態を避けるために、メインプロセスでのみis_main_process=Trueを設定してください。

save_function (Callable) : 状態辞書を保存するために使用する関数です。分散学習時に torch.save を別のメソッドに置き換える必要がある場合に便利です。環境変数 DIFFUSERS_SAVE_MODE で設定できます。

safe_serialization (bool、任意、デフォルトはTrue) : モデルをsafetensorsで保存するか、pickleを用いた従来の PyTorch の方法で保存するかどうかを指定します。

unet_lora_adapter_metadata : state dict と一緒にシリアライズされる unet に関連付けられた LoRA アダプターのメタデータ。

text_encoder_lora_adapter_metadata : state dict と一緒にシリアライズされる、テキストエンコーダーに関連付けられた LoRA アダプターのメタデータ。

UNetおよびテキストエンコーダーに対応するLoRAパラメータを保存します。

encode_prompt[[diffusers.StableDiffusionDepth2ImgPipeline.encode_prompt]]

encode_prompt(prompt, device, num_images_per_prompt, do_classifier_free_guidance, negative_prompt = None, prompt_embeds: typing.Optional[torch.Tensor] = None, negative_prompt_embeds: typing.Optional[torch.Tensor] = None, lora_scale: float | None = None, clip_skip: int | None = None)

ソース

パラメータ:

prompt (str または list[str]、省略可能) : エンコードするプロンプト

device : (torch.device): torch デバイス

num_images_per_prompt (int) : プロンプトごとに生成すべき画像の数

do_classifier_free_guidance (bool) : classifier free guidance を使用するかどうか

negative_prompt (str または list[str]、省略可能) : 画像生成をガイドしないプロンプトです。定義されていない場合、代わりに negative_prompt_embeds を渡す必要があります。ガイドを使用していない場合は無視されます(guidance_scale が 1 未満の場合は無視されます)。

prompt_embeds (torch.Tensor, 任意) : 事前生成されたテキスト埋め込み。テキスト入力の調整、例えばプロンプトの重み付けなどを容易に行うために使用できます。指定されない場合、prompt 入力引数からテキスト埋め込みが生成されます。

negative_prompt_embeds (torch.Tensor, 任意) : 事前に生成されたネガティブなテキスト埋め込み。テキスト入力の調整、例えばプロンプトの重み付けなどを容易に行うために使用できます。指定されない場合、negative_prompt 入力引数から negative_prompt_embeds が生成されます。

lora_scale (float、任意) : LoRAレイヤーが読み込まれている場合、テキストエンコーダーのすべてのLoRAレイヤーに適用されるLoRAスケールです。

clip_skip (int, optional) : プロンプト埋め込みを計算する際に、CLIPからスキップするレイヤー数。値が1の場合、プロンプト埋め込みの計算に最終レイヤーの直前のレイヤーの出力が使用されます。

プロンプトをテキストエンコーダーの隠れ状態にエンコードします。

StableDiffusionPipelineOutput[[diffusers.pipelines.stable_diffusion.StableDiffusionPipelineOutput]]

diffusers.pipelines.stable_diffusion.StableDiffusionPipelineOutput[[diffusers.pipelines.stable_diffusion.StableDiffusionPipelineOutput]]

diffusers.pipelines.stable_diffusion.StableDiffusionPipelineOutput(images: list[PIL.Image.Image] | numpy.ndarray, nsfw_content_detected: list[bool] | None)

ソース

パラメータ:

images (list[PIL.Image.Image] または np.ndarray) : 長さ batch_size のノイズ除去済み PIL 画像のリスト、または形状 (batch_size, height, width, num_channels) の NumPy 配列。

nsfw_content_detected (list[bool]) : 対応する生成画像に「not-safe-for-work」(nsfw)コンテンツが含まれるかどうかを示すリスト。安全性チェックを実行できなかった場合はNone。

Stable Diffusion パイプライン用の出力クラスです。

Xet Storage Details

Size:
33.5 kB
·
Xet hash:
ec0a08bf481ede6800d9a2f373a6e16429b29f55caf5578738dc892c64141eb6

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