Việc chuyển đổi một tác vụ huấn luyện từ Modal sang Nodus được thực hiện bằng cách thay đổi câu lệnh "import modal" thành "import nodus", bổ sung đường dẫn lưu điểm kiểm tra (checkpoint path) và khởi chạy bằng lệnh "nodus run app.py". Nodus duy trì cách đặt tên tương tự Modal đối với App, @app.function, Image, Volume, Secret và các chuỗi định danh GPU; do đó, một hàm huấn luyện thông thường chỉ yêu cầu chỉnh sửa một vài dòng mã nguồn. Các điểm cuối web (web endpoint), modal.Dict, modal.Queue và các lớp tham số hóa (parametrized classes) hiện chưa có thành phần tương đương trên Nodus, vì vậy các ứng dụng được xây dựng dựa trên những tính năng này nên được duy trì trên Modal hoặc phân tách độc lập.
Đây là phiên bản hướng dẫn thực hành trực tiếp. Trường hợp cần cân nhắc quyết định chuyển đổi, người dùng có thể tham khảo trước bài so sánh Nodus và Modal hoặc danh sách các phương án thay thế Modal phục vụ công tác huấn luyện mô hình.
Việc chuyển đổi tác vụ huấn luyện từ Modal sang Nodus được thực hiện bằng cách thay đổi lệnh `import modal` thành `import nodus`, bổ sung đường dẫn điểm kiểm tra (checkpoint), sau đó khởi chạy với lệnh `nodus run app.py`. Nodus giữ nguyên cách đặt tên của Modal đối với App, @app.function, Image, Volume, Secret và các chuỗi định danh GPU; do đó, một hàm huấn luyện thông thường chỉ cần chỉnh sửa một vài dòng lệnh. Các điểm cuối web (web endpoints), modal.Dict, modal.Queue và các lớp tham số hóa không có thành phần tương đương trên Nodus; vì vậy, các ứng dụng xây dựng trên các nền tảng này cần tiếp tục duy trì trên Modal hoặc phải được phân tách.
Đây là tài liệu hướng dẫn thực hành. Trường hợp còn cân nhắc việc chuyển đổi, người dùng có thể tham khảo tài liệu so sánh Nodus và Modal hoặc danh mục các giải pháp thay thế Modal trong huấn luyện mô hình. Toàn bộ lệnh Nodus dưới đây được trích xuất từ tài liệu hướng dẫn người dùng Modal và các trang liên kết tương ứng.
Các thành phần tương ứng một-một giữa Modal và Nodus
Phần lớn cấu trúc của một ứng dụng huấn luyện đều có thể chuyển đổi tương đương mà không cần thay đổi ngoài câu lệnh nạp thư viện (import). Bảng đối chiếu dưới đây được xây dựng dựa trên danh mục so sánh song song trong tài liệu hướng dẫn người dùng Modal và bảng đối số trong tài liệu hướng dẫn Functions, với các đặc tính vận hành của Modal được trích từ tài liệu chính thức của nền tảng này.
Khái niệm trên Modal
Thành phần tương đương trên Nodus
Điểm thay đổi
modal.App("x")
nodus.App("x")
Chỉ thay đổi lệnh import
@app.function(gpu="H100", timeout=3600)
@app.function(gpu="H100", timeout="1h")
Thời gian chờ (timeout) cũng hỗ trợ định dạng chuỗi theo chuẩn ngôn ngữ Go như "6h"; các giá trị số nguyên đơn thuần vẫn được tính theo giây
modal.Image.debian_slim().pip_install("torch")
nodus.Image.debian_slim().pip_install("torch")
Các lệnh from_registry, apt_install, run_commands, env, add_local_dir hoạt động tương tự
modal.Volume.from_name("v", create_if_missing=True)
Tương tự
Các phương thức vol.commit() và vol.reload() vận hành như trên Modal
modal.Secret.from_name("hf")
Tương tự
Nodus bổ sung thêm Secret.from_dotenv(".env")
gpu="H100", "H100:2", "A100-80GB", "L40S"
Giữ nguyên cú pháp định danh
Cú pháp "H100!" dùng để cố định chính xác biến thể; danh sách dạng ["H100", "H200"] chấp nhận một trong hai loại
retries (Modal)
retries, nhận giá trị số nguyên (int) hoặc nodus.Retries(...)
Cơ chế thử lại (Retries) xử lý các ngoại lệ phát sinh trong hàm
Không có thành phần tích hợp sẵn tương đương (Tài liệu hướng dẫn về thu hồi tài nguyên của Modal)
checkpoint="/nodus/state"
Các tệp tại thư mục này được lưu trữ và khôi phục khi một nút xử lý (worker) bị ngắt kết nối
Các phương thức .remote(), .map(), .spawn(), call.get(), @app.local_entrypoint() và @app.cls() cùng các điểm kích hoạt (hooks) enter và exit cũng được giữ nguyên. Hai trường thông tin cuối cùng là những yếu tố quan trọng nhất đối với quy trình huấn luyện, do quyết định mức chi phí phát sinh của một tiến trình kéo dài khi xảy ra sự cố.
Quy trình chuyển đổi tối giản đối với một hàm huấn luyện
Quy trình chuyển đổi tối giản nhất bao gồm việc thay đổi lệnh import và bổ sung một đối số checkpoint. Dưới đây là hàm huấn luyện trích từ tài liệu hướng dẫn Functions mà không thay đổi cấu trúc:
import nodus
app = nodus.App("finetune")
image = nodus.Image.debian_slim().pip_install("torch", "transformers==4.57.6")
@app.function(gpu="H100", image=image, timeout="6h", checkpoint="/nodus/state")
def train(lr: float) -> dict:
...
So với phiên bản trên Modal, có ba điểm thay đổi: định danh modal được thay bằng nodus tại ba vị trí, thời gian chờ được điều chỉnh thành "6h" (hoặc giá trị 21.600 giây), và bổ sung tham số checkpoint. Người dùng tiến hành cài đặt bộ công cụ phát triển phần mềm (SDK), đăng nhập một lần, sau đó khởi chạy tương tự như lệnh modal run:
pip install nodus-compute
nodus login # mở giao diện điều khiển, lưu khóa API cho từng tổ chức được chọn
nodus run app.py # tương tự `modal run`: ứng dụng tạm thời, bị xóa khi điểm nhập kết thúc
nodus deploy app.py # tương tự `modal deploy`: ứng dụng cố định
Trong quy trình tích hợp liên tục (CI), thiết lập biến môi trường NODUS_API_KEY thay vì chạy lệnh nodus login. Trước lượt chạy thực tế đầu tiên, người dùng có thể gọi lệnh train.estimate(3e-4) từ điểm nhập. Lệnh này sẽ trả về chi phí ước tính, thời gian bắt đầu và thời gian giữ tài nguyên cho một lệnh gọi mà không cần chạy bất kỳ tiến trình nào; đây là phương thức kiểm tra tiết kiệm nhất để xác nhận việc chuyển đổi đã thành công.
Hai bước kiểm tra giúp ngăn chặn phần lớn các trường hợp thất bại trong lần chạy đầu tiên. Phiên bản phụ (minor version) của Python trong image phải trùng khớp với phiên bản đang sử dụng, tương tự như trên Modal; hệ thống sẽ từ chối khởi chạy nếu phát hiện sự sai lệch. Trường hợp ứng dụng gọi một lớp kèm các tham số khởi tạo (constructor arguments), cần chuyển phần cấu hình đó vào hook @nodus.enter(), do cú pháp MyClass(arg=...) sẽ phát sinh lỗi nodus.errors.Unsupported.
Phương pháp duy trì tiến trình chạy khi xảy ra sự cố mất máy chủ sau khi chuyển đổi:
Tiến trình được ghi vào thư mục /nodus/state và tải lại khi khởi động; Nodus sao chép thư mục này và khôi phục trên máy chủ tiếp theo. Đây là điểm thay đổi về mặt hành vi vận hành, không đơn thuần là cú pháp. Tài liệu hướng dẫn về cơ chế ưu tiên chiếm quyền (preemption) của Modal nêu rõ: theo mặc định, toàn bộ Functions đều có thể bị chiếm quyền; tùy chọn không bị chiếm quyền không được hỗ trợ đối với GPU Functions; và một Function bị gián đoạn sẽ khởi động lại với cùng dữ liệu đầu vào. Việc tiếp tục thực thi từ điểm dừng phụ thuộc hoàn toàn vào mã nguồn của chương trình.
Trên Nodus, việc lưu trữ và khôi phục thư mục nêu trên là nhiệm vụ của nền tảng, trong khi chương trình quyết định nội dung cần ghi. Tài liệu hướng dẫn điểm kiểm tra (checkpoint) dành cho Jobs quy định một Job được tạo ít nhất 4 điểm kiểm tra trong suốt thời gian chạy dự kiến. Hệ thống cũng tự động tạo checkpoint khi có thông báo về việc tài nguyên sắp bị thu hồi. Lần chạy khôi phục sẽ thực thi lại lệnh từ đầu với thư mục nguyên trạng như trước, do đó vòng lặp cần đọc lại bước đã thực hiện.
Trường hợp huấn luyện mô hình bằng Hugging Face Trainer, quy trình dành cho Jobs tương đối ngắn gọn: thiết lập output_dir trỏ về thư mục lưu trạng thái, đồng thời cấu hình save_steps và save_total_limit; gọi lệnh trainer.train(resume_from_checkpoint=True) khi biến NODUS_RESTORED có giá trị bằng 1, và chỉ gọi trainer.train() trong lần khởi động đầu tiên. Điều kiện sau cùng mang tính bắt buộc do Trainer từ chối khôi phục từ một thư mục rỗng.
Khi các điểm kiểm tra đã sẵn sàng, có thể bổ sung tham số interruptible=True vào decorator. Theo tài liệu hướng dẫn người dùng của Modal, cơ chế này cho phép sử dụng nguồn tài nguyên có thể bị gián đoạn với chi phí thấp hơn, trong khi tiến trình vẫn được bảo toàn nhờ các checkpoint.
Cách thức áp mức trần chi tiêu cố định (hard spending cap) cho một tác vụ sau chuyển đổi:
Thực thi tập lệnh huấn luyện dưới dạng một Nodus Job đi kèm tham số --max-cost, thay vì dưới dạng Function. Đây là điểm lưu ý quan trọng được ghi nhận trong quá trình biên soạn tài liệu này. Trang thông tin người dùng của Modal hiển thị cú pháp max_cost=40 trên một Function, song tài liệu hướng dẫn Functions hiện hành lại xác định tham số max_cost chưa được hỗ trợ cho Functions và lệnh triển khai có thiết lập này sẽ bị từ chối tiếp nhận. Ngược lại, Jobs và Sandboxes đều chấp nhận tham số này.
Nếu hàm trên Modal chỉ đóng vai trò bao bọc tệp train.py, việc chuyển sang Job là phương án chuyển đổi ngắn gọn hơn. Dưới đây là các ví dụ được trích xuất từ tài liệu tham khảo lệnh nodus run:
nodus run --gpu L4 --image nodus/pytorch -- python train.py
nodus run --gpu H100:8 --max-cost 40 -d -- torchrun train.py
Lệnh đầu tiên thực thi một tập lệnh trên 1 GPU NVIDIA L4. Lệnh thứ hai chạy trên 8
Nguồn tin: Dev.to Machine Learning — Tác giả: Viswaretas Kotra. Bản dịch tiếng Việt do AI thực hiện, có thể có sai sót.