Diffusers documentation

Triết lý

You are viewing main version, which requires installation from source. If you'd like regular pip install, checkout the latest stable version (v0.42.1).
Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

Triết lý

🧨 Diffusers cung cấp các mô hình khuếch tán được huấn luyện trước tiên tiến nhất trên nhiều phương thức khác nhau. Mục đích của nó là đóng vai trò như một hộp công cụ mô-đun cho cả suy luận và huấn luyện.

Chúng tôi hướng đến việc xây dựng một thư viện có khả năng duy trì giá trị theo thời gian và do đó rất coi trọng việc thiết kế API.

Nói ngắn gọn, Diffusers được xây dựng để trở thành một phần mở rộng tự nhiên của PyTorch. Do đó, hầu hết các lựa chọn thiết kế của chúng tôi đều dựa trên Các nguyên tắc thiết kế của PyTorch. Hãy cùng xem qua những nguyên tắc quan trọng nhất:

Dễ sử dụng hơn Hiệu suất

  • Mặc dù Diffusers có nhiều tính năng tích hợp để tăng hiệu suất (xem Bộ nhớ và Tốc độ), các mô hình luôn được nạp với độ chính xác cao nhất và mức tối ưu thấp nhất. Do đó, mặc định các pipeline khuếch tán luôn được khởi tạo trên CPU với độ chính xác float32 nếu người dùng không định nghĩa khác. Điều này đảm bảo khả năng sử dụng trên các nền tảng và bộ tăng tốc khác nhau, đồng nghĩa với việc không cần cài đặt phức tạp để chạy thư viện.
  • Diffusers hướng tới việc trở thành một gói nhẹ và do đó có rất ít phụ thuộc bắt buộc, nhưng có nhiều phụ thuộc mềm có thể cải thiện hiệu suất (chẳng hạn như accelerate, safetensors, onnx, v.v…). Chúng tôi nỗ lực giữ cho thư viện nhẹ nhất có thể để nó có thể được thêm vào như một phụ thuộc của các gói khác mà không cần quá lo ngại.
  • Diffusers ưu tiên mã đơn giản, tự giải thích được hơn là mã ngắn gọn, khó hiểu. Điều này có nghĩa là các cú pháp viết tắt như hàm lambda và các toán tử PyTorch nâng cao thường không được khuyến khích.

Đơn giản hơn cả trứng ốp la

Như PyTorch đã nêu, rõ ràng thì tốt hơn là ngầm hiểu và đơn giản thì tốt hơn là phức tạp. Triết lý thiết kế này được thể hiện ở nhiều phần của thư viện:

  • Chúng tôi tuân theo API của PyTorch với các phương thức như DiffusionPipeline.to để người dùng tự quản lý thiết bị.
  • Việc đưa ra thông báo lỗi ngắn gọn được ưu tiên hơn là tự động sửa các đầu vào sai. Diffusers hướng đến việc hướng dẫn người dùng, thay vì cố gắng làm cho thư viện dễ sử dụng nhất có thể.
  • Logic phức tạp của model so với scheduler được phơi bày thay vì được xử lý một cách “ma thuật” bên trong. Scheduler/Sampler được tách khỏi diffusion model với sự phụ thuộc tối thiểu lẫn nhau. Điều này buộc người dùng phải tự viết vòng lặp denoising đã được unroll. Tuy nhiên, sự tách biệt này cho phép gỡ lỗi dễ dàng hơn và mang lại cho người dùng nhiều quyền kiểm soát hơn trong việc điều chỉnh quá trình denoising hoặc thay thế diffusion model hoặc scheduler.
  • Các thành phần được huấn luyện riêng biệt của pipeline khuếch tán, ví dụ như text encoder, unet và variational autoencoder, mỗi thành phần đều có lớp model riêng. Điều này buộc người dùng phải xử lý tương tác giữa các thành phần model khác nhau, và định dạng serialization tách các thành phần model ra thành các tệp riêng biệt. Tuy nhiên, điều này cho phép gỡ lỗi và tùy chỉnh dễ dàng hơn. Huấn luyện DreamBooth hoặc Textual Inversion rất đơn giản nhờ khả năng tách các thành phần đơn lẻ của pipeline khuếch tán của Diffusers.

Trừu tượng có thể tùy chỉnh, thân thiện với người đóng góp

Đối với phần lớn thư viện, Diffusers áp dụng một nguyên tắc thiết kế quan trọng của thư viện Transformers, đó là ưu tiên sao chép mã hơn là các trừu tượng vội vàng. Nguyên tắc thiết kế này rất có chủ kiến và trái ngược hoàn toàn với các nguyên tắc thiết kế phổ biến như Đừng lặp lại chính mình (DRY). Nói ngắn gọn, giống như cách Transformers làm với các tệp mô hình, Diffusers ưu tiên giữ mức trừu tượng cực kỳ thấp và mã rất tự chứa cho các pipeline và scheduler. Các hàm, khối mã dài và thậm chí cả các lớp có thể được sao chép qua nhiều tệp, điều mà ban đầu có thể trông như một lựa chọn thiết kế tồi, cẩu thả khiến thư viện không thể bảo trì được. Tuy nhiên, thiết kế này đã chứng minh được sự thành công cực kỳ lớn đối với Transformers và rất hợp lý đối với các thư viện machine learning mã nguồn mở do cộng đồng thúc đẩy vì:

  • Machine Learning là một lĩnh vực phát triển cực kỳ nhanh, trong đó các hệ tư tưởng, kiến trúc mô hình và thuật toán thay đổi liên tục, do đó khiến việc định nghĩa các trừu tượng mã hóa bền vững trở nên rất khó khăn.
  • Các nhà thực hành Machine Learning thường muốn có khả năng nhanh chóng chỉnh sửa mã hiện có để hình thành ý tưởng và nghiên cứu, do đó họ ưu tiên mã tự chứa hơn là mã chứa nhiều lớp trừu tượng.
  • Các thư viện mã nguồn mở dựa vào đóng góp của cộng đồng và do đó phải xây dựng một thư viện dễ đóng góp. Mã càng trừu tượng, phụ thuộc càng nhiều, càng khó đọc và càng khó đóng góp. Người đóng góp đơn giản là ngừng đóng góp cho các thư viện quá trừu tượng vì sợ làm hỏng các chức năng quan trọng. Nếu việc đóng góp cho một thư viện không thể làm hỏng các mã cơ bản khác, không chỉ điều này hấp dẫn hơn đối với các người đóng góp mới tiềm năng, mà còn dễ dàng hơn để xem xét và đóng góp cho nhiều phần song song.

Tại Hugging Face, chúng tôi gọi thiết kế này là single-file policy, có nghĩa là hầu hết mã nguồn của một class nhất định nên được viết trong một file duy nhất, tự chứa. Để tìm hiểu thêm về triết lý này, bạn có thể xem bài đăng trên blog này.

Trong Diffusers, chúng tôi áp dụng triết lý này cho cả pipeline, scheduler và model. Một số model cũ hơn được tạo trước quy ước này và được giữ nguyên; tất cả kiến trúc model mới đều nằm trong các file tự chứa riêng biệt. Xem phần Models bên dưới để biết chi tiết.

Tuyệt, giờ bạn đã hiểu cơ bản vì sao 🧨 Diffusers được thiết kế như vậy 🤗. Chúng tôi cố gắng áp dụng nhất quán các nguyên tắc thiết kế này xuyên suốt thư viện. Tuy nhiên, vẫn có một số ngoại lệ nhỏ so với triết lý hoặc một số lựa chọn thiết kế không may mắn. Nếu bạn có phản hồi về thiết kế, chúng tôi sẽ ❤️ rất vui được lắng nghe trực tiếp trên GitHub.

Chi tiết về Triết lý Thiết kế

Bây giờ đến những chi tiết cụ thể về triết lý thiết kế. Diffusers cung cấp cho bạn hai cách để kết hợp mô hình và trình lập lịch thành một quy trình làm việc có thể chạy được: các pipeline tiêu chuẩn, vốn là đơn khối với một tác vụ cho mỗi lớp pipeline, và Modular Diffusers, vốn có thể kết hợp và dựa trên khối. Các phần bên dưới lần lượt đề cập đến pipeline, pipeline module, mô hình và trình lập lịch.

Pipelines

Pipelines, dù là chuẩn hay modular, chỉ được thiết kế cho suy luận. Chúng được tạo ra để dễ sử dụng (do đó không tuân thủ 100% nguyên tắc Simple over easy): dễ đọc, tự giải thích, dễ điều chỉnh và nên được xem như các ví dụ về cách sử dụng models và schedulers. Chúng không đầy đủ tính năng. Để xây dựng các giao diện người dùng đầy đủ tính năng trên nền Diffusers, hãy sử dụng Modular Diffusers.

Các nguyên tắc thiết kế sau được tuân theo:

  • Pipelines follow the single-file policy. All pipelines can be found in individual directories under src/diffusers/pipelines. One pipeline folder corresponds to one diffusion paper/project/release. Multiple pipeline files can be gathered in one pipeline folder, as it’s done for src/diffusers/pipelines/stable-diffusion. If pipelines share similar functionality, one can make use of the # Copied from mechanism.
  • Tất cả các Pipeline đều kế thừa từ DiffusionPipeline.
  • Mỗi pipeline bao gồm các thành phần model và scheduler khác nhau, được tài liệu hóa trong file model_index.json, có thể truy cập dưới cùng tên như các thuộc tính của pipeline và có thể được chia sẻ giữa các pipeline bằng hàm DiffusionPipeline.components.
  • Mọi pipeline đều phải có thể được nạp thông qua hàm DiffusionPipeline.from_pretrained.
  • Mỗi pipeline phải có đúng một và chỉ một cách để chạy thông qua phương thức __call__. Việc đặt tên cho các đối số của __call__ cần nhất quán trên tất cả các pipeline.
  • Pipelines nên được đặt tên theo nhiệm vụ mà chúng được thiết kế để giải quyết.

Diffusers có tính mô-đun

Modular Diffusers là giải pháp thay thế có thể ghép nối cho các pipeline chuẩn. Bạn xây dựng quy trình làm việc từ các pipeline blocks có thể tái sử dụng, cho phép kết hợp, thay thế và chia sẻ linh hoạt. Các pipeline chuẩn chỉ là những ví dụ tham khảo lỏng lẻo về cách sử dụng mô hình và trình lập lịch. Modular Diffusers là con đường được khuyến nghị để xây dựng các giao diện người dùng đầy đủ tính năng trên nền tảng Diffusers, đồng thời giúp cộng đồng xây dựng và chia sẻ các pipeline mới theo cách phi tập trung.

Các nguyên tắc thiết kế sau được tuân theo:

  • Các pipeline dạng module tuân theo chính sách một tệp. Mỗi pipeline nằm trong một thư mục riêng dưới src/diffusers/modular_pipelines/, và thư mục này chia nhỏ quy trình làm việc thành một tệp cho mỗi giai đoạn: encoders.py, before_denoise.py, denoise.py và decoders.py. Hai tệp khác hoàn thiện pipeline. modular_blocks_<model>.py lắp ráp các giai đoạn, còn modular_pipeline.py định nghĩa lớp con ModularPipeline cho từng model. Các pipeline dạng module không import chéo lẫn nhau.
  • Mỗi pipeline dạng module được định nghĩa dưới dạng một tập hợp các ModularPipelineBlocks. Các block lá nằm trong các tệp stage (encoders.py, before_denoise.py, denoise.py, decoders.py), và modular_blocks_<model>.py sẽ lắp ráp chúng thành quy trình hoàn chỉnh bằng các lớp container như SequentialPipelineBlocks và AutoPipelineBlocks. Cách này tách biệt hai khái niệm mà DiffusionPipeline combines. Một block là một định nghĩa thuần túy. Nó khai báo các đầu vào, đầu ra và sự phụ thuộc vào các thành phần, nhưng không giữ trọng số và không thể chạy. Một ModularPipeline, được tạo bằng .init_pipeline(repo_id), là phần đối ứng có thể chạy được. Việc giữ cho các block không có trạng thái và không có trọng số chính là điều khiến chúng có thể được tổ hợp, thay thế và chia sẻ tự do giữa các quy trình.
  • Để hỗ trợ một tác vụ mới, hãy viết các khối dành riêng cho tác vụ đó, kết hợp chúng với các khối hiện có, và đăng ký quy trình làm việc trong _workflow_map trên khối lắp ráp cấp cao nhất. Một ModularPipeline duy nhất có thể hỗ trợ nhiều quy trình làm việc, chẳng hạn như text-to-image, image-to-image và inpainting, trong khi một DiffusionPipeline chỉ chạy một quy trình duy nhất.

Xem tài liệu Modular Diffusers để biết hướng dẫn thiết kế và sử dụng đầy đủ.

Mô hình

Các mô hình được thiết kế như những hộp công cụ có thể cấu hình, là sự mở rộng tự nhiên của lớp Module của PyTorch. Chúng nên tuân theo chính sách một tệp. Một số mô hình cũ hơn có trước quy ước này và được giữ nguyên. Hãy coi chúng là các ngoại lệ kế thừa, không phải là các mẫu cần áp dụng cho các mô hình mới. Ví dụ, lớp UNet2DConditionModel ban đầu đã được sử dụng cho một số biến thể UNet.

Các nguyên tắc thiết kế sau được tuân theo:

  • Mỗi loại kiến trúc mô hình nằm trong một thư mục riêng dưới src/diffusers/models, ví dụ như transformers/, autoencoders/, hoặc unets/. Mỗi họ mô hình có một tệp riêng trong thư mục đó, chẳng hạn như transformer_flux.py và transformer_wan.py.
  • Các mô hình tuân theo chính sách tệp đơn. Mỗi tệp mô hình nên tự chứa, ngoại trừ một số ít module chuẩn mà mọi mô hình đều sử dụng giống nhau, chẳng hạn như nhúng bước thời gian (timestep embeddings) và các lớp chuẩn hóa. Hãy nhập chúng từ embeddings.py và normalization.py.
  • Các Model được thiết kế để phơi bày độ phức tạp, giống như lớp Module của PyTorch, và cung cấp các thông báo lỗi rõ ràng.
  • Tất cả các mô hình đều kế thừa từ ModelMixin và ConfigMixin.
  • Các mô hình có thể được tối ưu hóa cho hiệu suất khi điều đó không đòi hỏi thay đổi lớn về mã, vẫn giữ được tính tương thích ngược và mang lại lợi ích đáng kể về bộ nhớ hoặc sức mạnh tính toán.
  • Mặc định, các mô hình nên có độ chính xác cao nhất và cài đặt hiệu năng thấp nhất.
  • Để tích hợp một kiến trúc mô hình mới tương tự với một kiến trúc hiện có, hãy sao chép tệp hiện có làm điểm khởi đầu và điều chỉnh cho phù hợp. Sử dụng chú thích # Copied from cho các lớp vẫn giữ nguyên để make fix-copies đồng bộ chúng.

Trình lập lịch

Schedulers có trách nhiệm hướng dẫn quá trình khử nhiễu cho suy luận cũng như xác định lịch trình nhiễu cho huấn luyện. Chúng được thiết kế dưới dạng các lớp riêng biệt với các tệp cấu hình có thể tải được và tuân thủ chặt chẽ chính sách tệp đơn.

Các nguyên tắc thiết kế sau được tuân theo:

  • Tất cả các trình lập lịch đều nằm trong src/diffusers/schedulers.
  • Schedulers không được phép import từ các tệp utils lớn và phải được giữ ở trạng thái tự chứa rất cao.
  • Một tệp Python của scheduler tương ứng với một thuật toán scheduler (như có thể được định nghĩa trong một bài báo).
  • Nếu các trình lập lịch có các chức năng tương tự, chúng ta có thể tận dụng cơ chế # Copied from.
  • Tất cả các Scheduler đều kế thừa từ SchedulerMixin và ConfigMixin.
  • Các Scheduler có thể dễ dàng được thay thế bằng phương thức ConfigMixin.from_config như đã được giải thích chi tiết tại đây.
  • Mọi scheduler đều phải có set_num_inference_steps và một hàm step. set_num_inference_steps(...) phải được gọi trước mỗi quá trình khử nhiễu, tức là trước khi step(...) được gọi.
  • Mọi scheduler đều phơi bày các timesteps cần “lặp qua” thông qua thuộc tính timesteps, đây là một mảng các timesteps mà mô hình sẽ được gọi.
  • Hàm step(...) nhận đầu ra dự đoán của mô hình và mẫu “hiện tại” (x_t), sau đó trả về mẫu “trước đó”, ít nhiễu hơn một chút (x_t-1).
  • Do độ phức tạp của các diffusion scheduler, hàm step không hiển thị đầy đủ độ phức tạp đó và có thể hơi giống một “hộp đen”.
  • Trong hầu hết các trường hợp, các trình lập lịch mới sẽ được triển khai trong một tệp lập lịch mới.
Update on GitHub