Phần phụ trợ của Accelerator

Việc mô tả phép tính Tensor khá đơn giản, nhưng thời điểm và cách thực hiện phép tính đó sẽ phụ thuộc vào chương trình phụ trợ nào được sử dụng cho Tensor và khi nào cần có kết quả trên CPU chủ.

Phía sau, các hoạt động trên Tensor được gửi đến các bộ tăng tốc như GPU hoặc TPU hoặc chạy trên CPU khi không có bộ tăng tốc. Điều này xảy ra tự động cho bạn và giúp bạn dễ dàng thực hiện các phép tính song song phức tạp bằng giao diện cấp cao. Tuy nhiên, sẽ rất hữu ích nếu hiểu cách thức gửi thư này và có thể tùy chỉnh nó để có hiệu suất tối ưu.

Swift dành cho TensorFlow có hai phần phụ trợ để thực hiện tính toán tăng tốc: chế độ háo hức TensorFlow và X10. Phần phụ trợ mặc định là chế độ háo hức TensorFlow, nhưng chế độ đó có thể bị ghi đè. Hướng dẫn tương tác có sẵn để hướng dẫn bạn cách sử dụng các chương trình phụ trợ khác nhau này.

Chế độ háo hức TensorFlow

Chương trình phụ trợ của chế độ háo hức TensorFlow tận dụng API TensorFlow C để gửi từng thao tác Tensor tới GPU hoặc CPU khi gặp phải. Kết quả của thao tác đó sau đó được truy xuất và chuyển sang thao tác tiếp theo.

Công văn theo từng hoạt động này rất dễ hiểu và không yêu cầu cấu hình rõ ràng trong mã của bạn. Tuy nhiên, trong nhiều trường hợp, nó không mang lại hiệu suất tối ưu do chi phí thực hiện nhiều hoạt động nhỏ, kết hợp với việc thiếu sự hợp nhất và tối ưu hóa hoạt động có thể xảy ra khi có biểu đồ hoạt động. Cuối cùng, chế độ háo hức của TensorFlow không tương thích với TPU và chỉ có thể được sử dụng với CPU và GPU.

X10 (theo dõi dựa trên XLA)

X10 là tên của phần phụ trợ Swift dành cho TensorFlow sử dụng tính năng theo dõi tensor lười biếng và trình biên dịch tối ưu hóa XLA để trong nhiều trường hợp cải thiện đáng kể hiệu suất so với việc gửi từng thao tác một. Ngoài ra, nó còn bổ sung khả năng tương thích cho TPU , bộ tăng tốc được tối ưu hóa đặc biệt cho các loại tính toán có trong các mô hình học máy.

Việc sử dụng X10 để tính toán Tensor không phải là mặc định, vì vậy bạn cần chọn tham gia chương trình phụ trợ này. Điều đó được thực hiện bằng cách chỉ định rằng Tensor được đặt trên thiết bị XLA:

let tensor1 = Tensor<Float>([0.0, 1.0, 2.0], on: Device.defaultXLA)
let tensor2 = Tensor<Float>([1.5, 2.5, 3.5], on: Device.defaultXLA)

Sau thời điểm đó, việc mô tả một phép tính hoàn toàn giống với chế độ háo hức của TensorFlow:

let tensor3 = tensor1 + tensor2

Thông tin chi tiết hơn có thể được cung cấp khi tạo Tensor , chẳng hạn như loại máy gia tốc nào sẽ sử dụng và thậm chí cả loại máy gia tốc nào, nếu có sẵn. Ví dụ: một Tensor có thể được tạo trên thiết bị TPU thứ hai (giả sử nó hiển thị với máy chủ mà chương trình đang chạy) bằng cách sử dụng như sau:

let tpuTensor = Tensor<Float>([0.0, 1.0, 2.0], on: Device(kind: .TPU, ordinal: 1, backend: .XLA))

Không có chuyển động ngầm nào của Tensor giữa các thiết bị được thực hiện, vì vậy nếu hai Tensor trên các thiết bị khác nhau được sử dụng cùng nhau trong một thao tác thì sẽ xảy ra lỗi thời gian chạy. Để sao chép thủ công nội dung của Tensor sang thiết bị mới, bạn có thể sử dụng trình khởi tạo Tensor(copying:to:) . Một số cấu trúc quy mô lớn hơn có chứa Tensor bên trong chúng, như mô hình và trình tối ưu hóa, có chức năng trợ giúp để di chuyển tất cả Tensor bên trong của chúng sang một thiết bị mới trong một bước.

Không giống như chế độ háo hức của TensorFlow, các hoạt động sử dụng phần phụ trợ X10 không được gửi đi riêng lẻ khi gặp phải. Thay vào đó, việc gửi tới máy gia tốc chỉ được kích hoạt bằng cách đọc các giá trị được tính toán trở lại máy chủ hoặc bằng cách đặt một rào cản rõ ràng. Cách thức hoạt động là thời gian chạy bắt đầu từ giá trị được đọc đến máy chủ (hoặc phép tính cuối cùng trước rào cản thủ công) và theo dõi biểu đồ tính toán dẫn đến giá trị đó.

Sau đó, biểu đồ được theo dõi này được chuyển đổi thành biểu diễn trung gian XLA HLO và được chuyển đến trình biên dịch XLA để được tối ưu hóa và biên dịch để thực thi trên bộ tăng tốc. Từ đó, toàn bộ phép tính được gửi đến máy gia tốc và thu được kết quả cuối cùng.

Tính toán là một quá trình tốn nhiều thời gian, vì vậy X10 được sử dụng tốt nhất với các phép tính song song lớn được thể hiện qua biểu đồ và được thực hiện nhiều lần. Giá trị băm và bộ nhớ đệm được sử dụng để các biểu đồ giống hệt nhau chỉ được biên dịch một lần cho mỗi cấu hình duy nhất.

Đối với các mô hình học máy, quá trình đào tạo thường bao gồm một vòng lặp trong đó mô hình phải thực hiện cùng một chuỗi tính toán lặp đi lặp lại. Bạn sẽ muốn mỗi đường chuyền này được xem như một sự lặp lại của cùng một dấu vết, thay vì một biểu đồ dài với các đơn vị lặp lại bên trong nó. Tính năng này được kích hoạt bằng cách chèn thủ công lệnh gọi đến LazyTensorBarrier() tại các vị trí trong mã mà bạn muốn kết thúc dấu vết.

Hỗ trợ độ chính xác hỗn hợp trong X10

Hỗ trợ đào tạo với độ chính xác hỗn hợp thông qua X10 và cả API cấp thấp và cấp cao đều được cung cấp để kiểm soát nó. API cấp thấp cung cấp hai thuộc tính được tính toán: toReducedPrecisiontoFullPrecision chuyển đổi giữa độ chính xác đầy đủ và độ chính xác giảm, cùng với isReducedPrecision để truy vấn độ chính xác. Ngoài Tensor s, các mô hình và trình tối ưu hóa có thể được chuyển đổi giữa độ chính xác hoàn toàn và độ chính xác giảm bằng cách sử dụng API này.

Lưu ý rằng việc chuyển đổi sang độ chính xác giảm không làm thay đổi loại logic của Tensor . Nếu tTensor<Float> , t.toReducedPrecision cũng là Tensor<Float> với biểu diễn cơ bản có độ chính xác giảm.

Giống như các thiết bị, không được phép thực hiện các thao tác giữa các tensor có độ chính xác khác nhau. Điều này tránh việc quảng bá thầm lặng và không mong muốn lên các float 32 bit, điều mà người dùng khó phát hiện.