Hiển thị các bài đăng có nhãn Machine Learning. Hiển thị tất cả bài đăng
Hiển thị các bài đăng có nhãn Machine Learning. Hiển thị tất cả bài đăng

Thứ Năm, tháng 1 19, 2017

ĐÔI NÉT VỚI TẬP LỆNH NCCL ĐA GPU (GRAPHIC PROCESSING UNIT: VI XỬ LÝ ĐỒ HỌA)


Ngày nay, nhiều máy chủ chứa 8 GPU hoặc nhiều hơn. Trên nguyên tắc đó, chạy một ứng dụng sử dụng một đến nhiều GPU đúng ra sẽ mang lại một hiệu suất gấp bội. Nhưng thực tế thì khá khó để tận dụng được lợi thế này. Có hai nguyên nhân cơ bản phía sau sự thiếu tính khả mở của hệ thống đa-GPU. Đầu tiên ứng không có đủ luồng xử lý song song để dùng hết các vi xử lý trên GPU. Lý do thứ hai gây khó khăn khi tận dụng mở rộng ở chỗ các bộ vi xử lý sẽ phải dành thời gian để trao đổi dữ liệu với nhau quá nhiều thay vì tập trung chạy thuật toán. Để giảm tình trạng nút cổ chai ấy, điều chính yếu cần thiết phải tạo được băng thông lớn nhất sẵn sàng cho các kết nối liên GPU. NCCL là một đáp án.

NCCL (phát âm là "Nickel") là một thư viện tập lệnh gốc đa-GPU có hướng cấu trúc liên kết và có thể dễ dàng tích hợp vào các ứng dụng. Khởi thủy từ một dự án nghiên cứu mã nguồn mở, NCCL được thiết kế để có dung lượng thật nhỏ dựa trên C ++ thông thường và các thư viện CUDANCCL có thể được ứng dụng vào trong các phần mềm đơn luồng hoặc đa luồng, để quản lý truyền nhận tin giữa các luồng xử lý hiệu quả. Sau nữa, NCCL đã bao gồm sẵn các API vốn rất quen thuộc với bất cứ ai có kinh nghiệm sử dụng các tập lệnh MPI.

Hình 1: Minh họa về tập lệnh All-Reduce.

Tập lệnh giao thức

Các chương trình giao thức tổ hợp là mẫu hình chung của truyền dữ liệu giữa nhiều bộ vi xử lý. Nếu đã có kinh nghiệm với MPI thì có lẽ cũng đã quen thuộc với một số phép toán tổ hợp lệnh. Ví dụ, All-Reduce (Giảm toàn phần) bắt đầu với mảng độc lập $latex V_k$ của N giá trị trên K bộ vi xử lý và kết thúc với mảng giống hệt S của N giá trị, trong đó $S[k] = V_0[k] + V_1[k] + ... + V_k[k]$, cho mỗi bộ xử lý k . Xem hình 1.
Một giao thức tổ hợp thông thường khác là All-Gather (Nhóm toàn phần), trong đó mỗi bộ xử lý trong tập hợp K bắt đầu với một mảng độc lập của N giá trị và thu thập dữ liệu từ tất cả các bộ xử lý khác để tạo thành một kết quả mảng N*K , như minh họa ở hình 2.

Hình 2: Minh họa về All-gather.
Broadcast (Tán xạ) là một ví dụ thứ ba. Dưới đây là một thành phần đệm gồm N phẩn tử trên một bộ xử lý được sao chép vào tất cả các bộ xử lý khác, như hình 3 cho thấy.
Hình 3: Minh họa về Broadcast
Tất cả các tổ hợp trên có thể được thực hiện ở vùng "ngoại vi", có bộ đệm vào và ra riêng biệt, hoặc "nội hàm" có chồng lấn vào và ra.
Hình 4: Giao thức PCIe chung cho 4 GPU gắn trong hệ thống có một CPU duy nhất. Mũi tên màu đỏ đại diện cho các kết nối băng thông PCIe x16.
Có rất nhiều phương pháp để thực hiện tổ hợp hiệu quả. Tuy nhiên, điểm then chốt khi thực hiện thì phải cân nhắc đến kiến trúc giao thức của liên kết giữa các bộ vi xử lý. Ví dụ như ở giao thức nhánh cây PCIe trong hình dưới đây về đường tán xạ dữ liệu từ GPU0 đến tất cả các GPU khác.
Thuật toán nhánh cây hai bước là một lựa chọn phổ biến ở đây. Tại bước đầu tiên, dữ liệu được gửi từ GPU0 tới một GPU khác, và trong bước thứ hai cả hai sẽ gửi dữ liệu đến các bộ vi xử lý còn lại. Dù thế thì vẫn có nhiều cách thực thi khác nhau. Dữ liệu có thể được gửi từ GPU0 đến GPU1 trong bước đầu tiên và sau đó từ GPU0 đến GPU2 và từ GPU1 đến GPU3 ở bước hai, hoặc có thể thực hiện dưới hình thức bản sao ban đầu từ GPU0 đến GPU2, kế đó ở bước hai thì từ GPU0 đến GPU1 và GPU2 đến GPU3. Kiểm tra cấu trúc liên kết, cách thứ hai tốt hơn rõ rệt, vì nếu gửi dữ liệu đồng thời từ GPU0 đến GPU2 và GPU1 đến GPU3 sẽ gây tranh chấp tài nguyên trên các liên kết PCIe, hiệu suất băng thông ở bước này bị giảm một nửa. Nói chung, để đạt được hiệu quả cao đối với tổ hợp lệnh đòi hỏi sự quan tâm cẩn trọng đến cấu trúc liên kết.
Để tối ưu hóa băng thông Broadcast, còn một cách tiếp cận tốt hơn là tạo liên kết cấu trúc vòng PCIe.
Tán xạ được thực hiện bằng việc sắp xếp các tập nhỏ dữ liệu đầu vào xung quanh vòng từ GPU0 để GPU3. Điều thú vị là, các thuật toán vòng cung cấp băng thông cận tối ưu cho hầu hết tất cả các thực thi tổ hợp lệnh tiêu chuẩn, thậm chí khi áp dụng cho cấu trúc PCIe kiểu "nhánh cây". Tất nhiên phải lưu ý rằng việc lựa chọn đúng chiều tuần hoàn của vòng vẫn rất quan trọng.

Hình 5: Vòng tuần hoàn của GPU trong cây PCIe.

Tập lệnh GPU với NCCL

Để cung cấp băng thông tối đa, NCCL áp dụng các tập lệnh tổ hợp kiểu vòng. NCCL ngầm đánh chỉ số GPU theo trật tự vòng tối ưu. Điều này cung cấp hiệu suất tuyệt vời cho ứng dụng mà nhà phát triển không còn phải lo lắng về cấu hình phần cứng cụ thể ra sao.
Nhiều tổ hợp lệnh đòi hỏi một bộ đệm chứa kết quả trung gian. Để giảm thiểu dung lượng chiếm bộ nhớ xuống còn một vài MB trên mỗi GPU, NCCL chia tách tổ hợp lệnh lớn thành nhiều phần nhỏ. Hiệu quả cực thấp nếu khởi tạo lõi xử lý và thực thi gọi hàm cudaMemcpy riêng biệt cho mỗi công đoạn hay từng phần nhỏ của cùng một thuật toán tổ hợp. Thay vào đó, mỗi tổ hợp được thực hiện trọn vẹn trên một nhân CUDANCCL tận dụng tối đa truy cập trực tiếp của giao thức GPUDirect Peer-to-Peer để truyền dữ liệu giữa các bộ xử lý. Trường hợp không lấy được truy cập trực tiếp peer-to-peer (ví dụ, khi phải truyền qua một kết nối QPI), thì các dữ liệu đã truyền đi được tổ chức thông qua một bộ đệm trong một vùng xác định trên bộ nhớ hệ thống. Tương tự như vậy, đồng bộ dũ liệu được thực hiện bằng cách kiểm tra các biến số biến đổi trong vùng nhớ của card (hoặc vùng nhớ xác định của hệ thống).
Bên trong, NCCL quy việc thực hiện mỗi tổ hợp lệnh về 3 nguyên hàm: Copy, Reduce, và ReduceAndCopy. Mỗi nguyên hàm được tối ưu hóa để truyền đi một lượng dữ liệu tinh giản (4-16KB) giữa các GPU. Các lõi xử lý cũng đã được tối ưu hóa đặc biệt để đạt được băng thông tối đa trong khi lại chiếm dụng thấp. Kết quả là, NCCL có thể sử dụng tối đa tải một kết nối PCIe 3.0 x16 mà chỉ bằng một đơn vị tổ hợp luồng xử lý CUDA. Điều này khiến giải phóng phần lớn GPU dùng vào chạy các tác vụ tính toán đồng thời với truyền tải thông tin.

NCCL hiện hỗ trợ các tập lệnh all-gather, all-reduce, broadcast, reduce, và reduce-scatter, không hạn chế số lượng GPU được sử dụng, miễn là nằm trên cùng một máy.

Sử dụng NCCL

Mã nguồn mở NCCL có sẵn trên Github . Các thư viện có thể chạy trên bất kỳ phiên bản Linux phổ biến và cũng tương thích với CUDA 7.0 hay mới hơn. Hiện giờ, CUDA chỉ hỗ trợ truy cập trực tiếp giữa các GPU cùng kiến trúc và phải nằm trên cùng một máy (PCIe root hub). GPU không phù hợp các tiêu chí này vẫn được hỗ trợ bởi NCCL, mặc dù hiệu suất sẽ được giảm do việc chuyển dữ liệu sẽ đi vòng thông qua vùng nhớ xác định trong bộ nhớ hệ thống.
Các NCCL API đều tuân thủ chặt theo MPI. Trước khi thực thi các tập lệnh, một đối tượng truyền tin phải được tạo ra trên mỗi GPU. Các đối tượng này xác định các thiết lập của các GPU tham gia vào tổ hợp và lập bản đồ các luồng thông tin liên lạc giữa chúng. Tập hợp đối tượng giao tiếp liên quan với nhau được gọi là một clique (phe). Có hai cách để khởi tạo đối tượng truyền tin trong NCCL. Phương pháp phổ thông nhất là gọi hàm ncclCommInitRank() tương ứng với mỗi GPU.

ncclResult_t ncclCommInitRank(ncclComm_t* comm,
int nGPUs, ncclUniqueId cliqueId,
int rank);
Chức năng này giả định rằng các GPU thuộc các hàng xác định đã được thiết lập thông qua cudaSetDevice()nGPUs là số lượng GPU trong một clique. cliqueId cho phép các hàng trong cùng clique nhận diện nhau. Các hàng thì sẽ có cùng một cliqueId. Để làm vậy, hàm ncclGetUniqueId() được gọi từ trong một hàng và sẽ phát tán kết quả trả về uniqueId đến các hàng khác còn lại trong clique thông qua mô hình truyền thông tùy chọn (ví dụ, MPI_Bcast).
Các biến số cuối cùng trong ncclCommInitRank() xác định các chỉ số của GPU hiện tại trong clique. Nó phải là duy nhất cho mỗi cấp trong clique và trong tập hợp [0, nGPUs]. Chỉ số này được sử dụng, ví dụ, để xác định các GPU nguồn cho lệnh broadcast, hoặc để truy xuất đến theo lệnh all-gather.
Sau khi khởi tạo thành công, ncclCommInitRank() trả về ncclSuccess và *comm được thiết lập chứa đối tượng truyền tin mới của NCCL.
Bên trong, ncclInitRank() thực hiện đồng bộ giữa tất cả các đối tượng truyền tin trong cùng một clique. Như vậy, nó phải được gọi từ các luồng khởi tạo khác nhau cho từng GPU, hoặc từ các xử lý riêng biệt (ví dụ, MPI ranks). Cụ thể, nếu gọi ncclInitRank() trong cùng một vòng lặp xử lý cho các GPUs sẽ dẫn đến tình trạng xung đột khóa chết (deadlocks)
Cách thứ hai để khởi tạo các đối tượng truyền tin là sử dụng ncclCommInitAll(). Đây thực chất là một thói quen tiện dụng để tiết kiệm việc phải sinh thêm các luồng khởi tạo mới để chạy NCCL trong trình ứng dụng đơn nhiệm.

ncclResult_t ncclCommInitAll ( ncclComm_t * comms ,
int nGPUs ,
int * devList );
Biến comms đang trỏ đến một mảng các đối tượng ncclComm_t, tương ứng cho mỗi hàng chứa nGPUs trong cùng 1 clique. devList thì quy định cụ thể thiết bị CUDA nào tương ứng với từng hàng. Khi khởi tạo các đối tượng truyền tin, ta có thể gọi các tập lệnh thông qua các hàm gốc của chúng, chẳng hạn như ncclAllReduce().
ncclResult_t ncclAllReduce ( void* sendoff ,
void* recvbuff , int count ,
ncclComm_t comm ,
ncclDataType_t type , ncclRedOp_t op ,
cudaStream_t stream);
Tài liệu chi tiết cho mỗi tập lệnh được cung cấp trong file nccl.h. Hầu hết các biến đều tương tự như trong tập lệnh API của MPI. Trường hợp ngoại lệ nổi bật là các biến dòng (stream). Tương tự như rất nhiều chương trình CUDA "Async", lệnh NCCL sẽ lên lịch thực thi trong một dòng, nhưng có thể trả lại trước khi tập lệnh được hoàn tất. Bằng cách xếp các tập lệnh vào hàng đợi còn nhân tính toán riêng khác ở các dòng độc lập, GPU có thể chồng lấn nhiều hơn công việc đòi hỏi tính toán tập trung cao vào cùng thời điểm truyền tập lệnh. Nhằm tối đa hóa sự chồng lấn này, các tập lệnh NCCL được lập lịch chạy trên dòng có độ ưu tiên cao để cho phép chúng trượt qua lại trong các lưới tính toán tập trung.
Ứng với mỗi đối tượng truyền tin trong một clique đều phải gọi đến ncclAllReduce(), mỗi lần gọi được thực hiện qua bộ đệm gửi và nhận riêng biệt, v.v. Tập lệnh NCCL sẽ giả định ngữ cảnh CUDA tương ứng là mới nhất. Và bởi vì NCCL chạy không đồng bộ, một vòng lặp đơn giản có thể được sử dụng để khởi tạo một tập lệnh từ một ứng dụng đơn luồng.

for ( int gpu = 0 ; gpu < nGPUs ; ++ gpu ) {
cudaSetDevice ( devList [ gpu ]);
}
ncclAllReduce (...);

Hiệu suất

Hình 6: Liên kết băng thông đạt được của tập thể NCCL khác nhau.
Hiệu suất mà tập lệnh NCCL đạt được phụ thuộc vào chính cấu trúc liên kết của máy tính. Trong trường hợp tốt nhất, tất cả các GPU đều chiếm phần truy cập như nhau. Đây là mô hình phổ biến nhất ở các máy trạm được trang bị vài GPU. Các máy chủ lớn hơn thường gắn với CPU kép, và một số lượng các GPU tách biệt trên các hub IO khác nhau. Hình 6 cho thấy băng thông NCCL tương ứng đối với các tập hợp lệnh khác nhau đo trên máy NVIDIA Digits DevBox trang bị 4 GPU GeForce GTX Titan X được ráp theo mô hình ở hình 4 trên đây.
Đường màu đỏ 10.4 GB/ s đại diện cho băng thông sử dụng bở một lệnh cudaMemcpy dự liệu lớn giữa hai trong số các GPU (cụ thể là GPU 0 và 2 trong hình 4). NCCL vẫn có thể duy trì tỷ lệ cao khả năng chiếm dụng băng thông cao điểm đó khi thực hiện giao tiếp giữa tất cả bốn GPU.

Hướng phát triển trong tương lai và một số điểm lưu tâm

Mục tiêu của NCCL là để cung cấp tập lệnh tổ hợp tự nhận thức được cấu trúc liên kết nhằm có thể cải thiện độ khả mở của các ứng dụng đa GPU. Sử dụng NCCL sẽ có thể giúp đạt được hiệu suất tuyệt vời mà không phải chú ý về các chi tiết phần cứng bậc thấp.
Nhữn mẩu mã nguồn ví dụ đơn giản cho cả hai loại ứng dụng trình đơn và đa luồng MPI cũng được kèm sẵn trong bộ thư viện NCCL. Xuất phát từ một dự án nghiên cứu, mọi phản hồi cuả các nhà phát triển đểu được hoanh nghênh vì dự án này vẫn còn tiếp tục. Hãy dùng thử và chia sẻ bạn nghĩ gì nhé! Để cập nhật về những thông tin mới nhất, hãy đến dự buổi nói chuyện NCCL của tôi ở GTC.

Thứ Hai, tháng 1 02, 2017

LÀM THẾ NÀO ĐỂ CHẠY SONG SONG HỌC-SÂU TRÊN GPU (PHẦN 2)


Mô hình song song


Ở phần trước, tôi đã giải thích qua khái niệm về xử lý song song trên mô hình (MP-Model Parallelism) và dữ liệu (DP-Data Parallelism) cũng như phân tích làm thế nào để sử dụng DP hiệu quả trong học-sâu (Deep Learning). Ở bài viết này, tôi sẽ tập trung vào mô hình song song (MP).

XIn nhắc lại, mô hình xử lý song song là, khi bạn chia một mô hình thành từng phần cho các GPU và sử dụng cùng một dữ liệu cho từng mô hình; vì vậy mỗi GPU hoạt động trên một phần của mô hình chứ không phải là một phần của dữ liệu. Trong học-sâu, một cách để làm việc này bằng cách phân trọng số, ví dụ một ma trận 1000 x 1000 thì trọng số sẽ được phân chia thành các ma trận 1000 × 250 nếu bạn sử dụng 4 GPU.

Sơ đồ MP. Đồng bộ hóa kết quả là cần thiết sau mỗi vòng tính tích vô hướng với ma trận trọng số cho cả hai chiều tiến và quy nạp.

Một lợi thế của phương pháp này nhận thấy ngay: Nếu chúng ta chia trọng số giữa các GPU chúng ta có thể chạy với mạng nơ-ron rất lớn dù rằng bộ nhớ của một GPU đơn lẻ không đủ dung lượng nạp trọng số vào. Ở phần trước, tôi cũng có nói rằng các mạng nơ-ron lớn như vậy là không cần thiết với đa số người. Tuy nhiên, đối với các tác vụ học-không-giám-sát (un-supervised learning) khủng hơn -trong tương lai thì sẽ khá phổ biến – mạng nơ-ron lớn lại rất cần thiết dùng để học được các đặc tả chi tiết nhất nhằm có được hành vi “thông minh”.

Làm thế nào để thuật toán chuyển tiến và quy nạp phân chia thành các ma trận như vậy được? Nếu nạp ma trận số học từng bước từng bước, ta sẽ thấy rõ ràng ngay:

Giả sử bắt đầu tìm kiếm tại A, B = C đó sẽ là tích ma trận trong trường hợp thông thường thuật toán tiến. Kích thước MP với 2 GPU, phân lô 128 và ma trận trọng số 1000 × 500 sẽ là:

Tiêu chuẩn: 128 × 1000 nhân 1000 × 500 = 128 × 500

Chia theo ma trận trọng số chiều dọc: 128 × 500 nhân 500 × 500 = 128 × 500 -> phép cộng ma trận

Chia theo ma trận trọng số chiều ngang: 128 × 1000 nhân 1000 × 250 = 128 × 250 -> phép chồng ma trận

Để tính toán sai số trong các lớp bên dưới, cần phải truyền các sai số tới được các lớp tiếp theo, hoặc nói theo cách toán học hơn, ta cần tính toán các giá trị delta bằng cách lấy tích vô hướng của các sai số ở lớp {i} trước với các trọng số kết nối lớp {j} tiếp theo , tức là :

Tiêu chuẩn: 128 × 500 nhân 500 × 1000 = 128 × 1000

Chia theo ma trận trọng số chiều dọc: 128 × 500 nhân 500 × 500 = 128 × 500 -> phép chồng ma trận

Chia theo ma trận trọng số chiều ngang: 128 × 250 nhân 250 × 1000 = 128 × 1000 -> phép cộng ma trận

Chúng ta thấy ở đây, cần phải đồng bộ hóa (cộng hoặc xếp chồng trọng số) sau mỗi kết quả tích vô hướng và bạn có thể nghĩ rằng như vậy sẽ chậm hơn so với xử lý dữ liệu song song DP ,vì DP đồng bộ hóa chỉ một lần. Nhưng có thể dễ dàng thấy rằng điều đó không phải đúng cho hầu hết các trường hợp, thử tính toán xem: Trong DP một khuynh độ của 1000 × 500 cần được truyền một lần/lớp cho 1000 × 500 lớp – tức là 500000 đơn vị; còn với MP chúng ta chỉ cần truyển một ma trận nhỏ cho tiến và quy nạp với tổng số 128000 hoặc 160000 đơn vị – dung lượng ít hơn gần 4 lần! Vì thế dù băng thông card mạng vẫn là nút cổ chai chính trong toàn bộ ứng dụng, nhưng sẽ ít bị ảnh hưởng hơn nhiều so với trong trường hợp DP.

Dĩ nhiên, tất cả chỉ là tương đối và phụ thuộc vào kiến ​​trúc mạng. DP sẽ khá nhanh cho các mạng nhỏ và rất chậm cho các mạng lớn, MP thì ngược lại. Càng nhiều thông số, MP càng có lợi. Lợi thế càng thực sự rõ ràng khi mạng nơ-ron có trọng số vượt quá dung lượng một bộ nhớ GPU đơn.MP có thể xử lý việc mà thông thường sẽ cần đến hàng ngàn bộ vi xử lý CPU.

Tuy nhiên, nếu bạn chạy các mạng nhỏ, bộ nhớ GPU dư thừa và và vẫn còn năng lực xử lý (không phải tất cả các lõi đang chạy), thì dùng MP sẽ chậm. Không giống như DP, không có thủ thuật bạn có thể sử dụng để ẩn các thời gian giao tiếp cần thiết để đồng bộ hóa, điều này là bởi vì chúng ta chỉ có một phần thông tin cho toàn bộ phân lô. Với một phần thông tin này thì không thể tính toán các hoạt động trong lớp tiếp theo và do đó phải chờ đợi để hoàn thành đồng bộ hóa mới đi tiếp bước kế tiếp được.

Làm thế nào những lợi thế và bất cập có thể kết hợp được chỉ ra rõ ràng nhất bởi Alex Krizhevsky người đã chứng minh hiệu quả của việc sử dụng DP trong các lớp tính tích chập và MP trong các lớp dày đặc của một mạng nơ-ron tích chập.

LÀM THẾ NÀO ĐỂ CHẠY SONG SONG HỌC-SÂU (DEEP LEARNING) TRÊN GPU (PHẦN 1)

Phần 1: Dữ liệu song song – Data Parallelism


Trong bài viết trước, tôi đã chỉ ra những gì cần chú ý khi bạn muốn xây dựng một cụm xử lý với nhiều GPU. Quan trọng nhất, bạn sẽ cần một kết nối mạng nhanh giữa các máy chủ và dùng thư viện MPI trong chương trình sẽ giúp đơn giản hóa vượt trội so với sử dụng các tùy chọn sẵn có của CUDA.
Ở bài viết này tôi sẽ giải thích làm thế nào để triển khai thuật toán xử lý song song cho mạng nơ-ron với một cụm GPU theo những cách khác nhau cùng với những lợi thế và bất cập của các thuật toán đó. Có hai hướng triển khai thuật toán khác nhau là xử lý dữ liệu song song (Data Parallelism- DP) hay xử lý mô hình song song (Model Parallelism -MP). Ở bài viết này tôi sẽ tập trung vào DP.
Vậy, hai hướng tiếp cận trên là gì? DP có nghĩa là bạn sử dụng cùng một mô hình giống nhau trên mỗi nhánh xử lý (thread), nhưng cấp cho các nhánh với từng phần khác nhau của cùng một bộ dữ liệu; còn MP thì sử dụng cùng một bộ dữ liệu cho mỗi nhánh, nhưng chia nhỏ mô hình thành các phần xử lý trên các nhánh khác nhau.
Đối với các mạng nơ-ron, điều trên có nghĩa DP sử dụng các trọng số giống nhau và mỗi nhánh xử lý các phân lô khác nhau; sau đó khuynh độ (gradient) cần phải được đồng bộ theo cách trung bình hóa, sau mỗi lần xử lý xong một phân lô.
MP thì chia trọng số của mạng đều ra cho các nhánh xử lý và tất cả các nhánh cùng xử lý trên cùng một phân lô; ở đây kết quả tạo được sau mỗi lớp xử lý cần phải được đồng bộ, theo cách xếp chồng lên nhau, để cung cấp đầu vào cho các lớp xử lý tiếp theo.
Mỗi phương pháp có ưu điểm và nhược điểm của nó, thay đổi theo kiến ​​trúc xử lý. Trước tiên, chúng ta cùng xem xét DP (xử lý dữ liệu song song) với những yếu điểm nghẽn cổ chai của nó, còn trong bài viết tiếp theo, tôi sẽ xét đến xử lý kiểu MP (xử lý mô hình song song).
Điểm chí tử: nút thắt cổ chai mạng trong xử lý dữ liệu song song
Ý tưởng DP khá đơn giản. Ví dụ bạn có 4 GPU, bạn chia một phân lô thành các phần nhỏ cho mỗi GPU, tỉ như, bạn chia một phân lô gồm 128 mẫu thành 32 mẫu cho mỗi GPU. Sau đó, bạn đưa các lô tương ứng qua mạng để có được khuynh độ cho từng phần đó của một lô dữ liệu. Sau đó bạn sử dụng MPI để thu thập tất cả các khuynh độ và cập nhật các thông số với giá trị trung bình tổng.





Sơ đồ xử lý dữ liệu song song DP. Không có giao tiếp bước tiến, còn trong bước lùi thì có đồng bộ hóa khuynh độ.


Vấn đề lớn nhất với phương pháp này là trong bước quy nạp cần phải chuyển toàn bộ khuynh độ sang tất cả các GPU khác. Nếu bạn có một ma trận trọng số 1000 × 1000 thì bạn cần đẩy 4 triệu byte cho mỗi hệ mạng. Nếu chúng ta dùng card mạng 40Gbit/s – cũng thuộc loại khá nhanh – thì cần ít nhất (4.000.000/40) x (1/(40x1024x1024x102)) x 1/(8×1000) = 0,75ms để chuyển dữ liệu giữa 2 nút xử lý cần phải giao tiếp đến được 5 GPU còn lại, 3 trong số đó cần phải đi qua các card mạng (3 x 0.75ms), còn 2 GPU có thể sử dụng PCIe 3.0 để truyền dữ liệu với hai GPU khác (sẽ nhanh hơn khoảng ba lần: 2×0.25ms). Do dữ liệu truyền qua cổng PCIe không liên quan tới card mạng, nên thời gian cần thiết để dữ liệu giữa 2 card mạng quyết định tốc độ chung và cũng đã là 2.25ms. Tất nhiên, chỉ một GPU có thể chuyển dữ liệu thông qua các card mạng tại một thời điểm trong bất kỳ một nút, do đó chúng ta phải nhân thời gian đó lên 3 lần, nghĩa là 7.75ms. Vậy mấu chốt là, chúng ta chỉ cần khoảng 0.2ms cho một ma trận dựng thông qua các lớp (100 × 1000 dot 1000 × 1000) và khoảng gấp đôi để quy nạp. Chúng ta có thể truyền giá trị khuynh độ trong khi chúng ta xử lý ở phân lớp kế tiếp, nhưng rồi thì về tổng thể thì tốc độ card mạng cũng sẽ giới hạn khả năng tính toán của chúng ta tương đối nhiều. Điều này càng rõ với hê thống có quy mô lớn hơn: Một hệ thống bốn nút xử lý trên cùng một bài toán cần khoảng 20.25ms để truyền thông tin khuynh độ đến được các GPU trong hệ thống. Dễ dàng nhận thấy tiếp cận DP không tăng theo được quy mô cụm nút xử lý.
Để giải quyết sự tắc nghẽn này thì phải giảm thiểu các thông số của khuynh độ bằng kỹ thuật tối đa hoá vùng chờ, tối đa số lượng đơn vị ấn định hoặc đơn giản nữa thì dùng tích chập (convolutional). Một cách nữa hướng tới để tăng tỷ lệ thời gian tính toán / thời gian kết mạng bằng các kỹ thuật khác, ví dụ như dùng tính toán tối ưu hóa chuyên sâu như RMSProp. Thời gian dành để chuyển các thông tin khuynh độ với nhau không đổi, nhưng dành được nhiều thời gian dành vào tính toán hơn, do đó tăng hiệu suất của GPU vốn có khả năng tính toán nhanh.
Một điều nữa có thể làm khi sử dụng các kỹ thuật tối ưu hóa tính toán chuyên sâu là làm ẩn đi độ trễ của mạng vào trong quá trình tính toán khuynh độ. Đại ý là cùng lúc bạn đi truyền thông tin khuynh độ đầu tiên cho tất cả các nút khác, bạn cũng đã bắt đầu một tính toán RMSProp lớn không đồng bộ cho lớp kế tiếp. Kỹ thuật này có thể giúp tăng tốc độ lên từ 0-20% tùy thuộc vào kiến ​​trúc mạng.
Nhưng đây không phải là vấn đề duy nhất với xử lý dữ liệu song song. Tồn tại nút thắt cổ chai kỹ thuật ẩn ngay trong kiến ​​trúc GPU khiến tôi mất khá nhiều thời gian để nắm bắt. Để hiểu lý do tại sao các kiến ​​trúc GPU lại thành vấn đề thì trước tiên chúng ta cần phải nhìn vào cách sử dụng và mục đích của việc phân chia dữ liệu thành các phân lô nhỏ.

Phân kỳ: Tại sao cần phân lô dữ liệu?

Nếu chúng ta bắt đầu với các thông số khởi tạo ngẫu nhiên hoặc thậm chí nếu chúng ta bắt đầu với các thông số đã tập huấn máy trước đó, chúng ta không cần phải truyền tất cả các dữ liệu để có được một bản cập nhật chính xác khuynh độ vì kiểu gì chúng cũng sẽ bị giản thiểu cục bộ. Lấy MNIST làm ví dụ, nếu chúng ta có một khuynh độ trong đó bao gồm 10 sai lầm phổ biến mà mạng lọc ra cho mỗi lớp học (kích thước phân lô khoảng 128), thì chúng ta đã đang đi theo hướng làm giảm các lỗi đáng kể vì các lớp khuynh độ lọc bỏ lỗi thô và phổ biến. Nếu chúng ta chọn một kích thước phân lô lớn hơn (512 chẳng hạn) thì chúng ta không chỉ nắm bắt được những lỗi thông thường, nhưng cũng bắt được lỗi tinh vi hơn. Tuy nhiên, lại chả có nghĩa gì khi đi tinh chỉnh một hệ thống mà biết rằng nó vẫn còn đang mắc những lỗi lớn. Vì vậy, nhìn chung chúng ta việc tăng kích cỡ phân lô đạt được hiệu quả rất ít. Chúng ta cần phải tính toán nhiều hơn mà kết quả vẫn gần tương tự và đây là luận điểm chính vì sao chúng ta sử dụng một kích thước phân lô càng nhỏ càng tốt. Tuy nhiên, nếu chúng ta chọn một kích thước phân lô quá nhỏ, thì chúng ta không nắm bắt tất cả những lỗi phổ biến mà có liên quan để toàn tập dữ liệu và do đó khuynh độ của chúng ta không thể đạt được gần mức tối ưu cục bộ, vì vậy cũng có điểm tới hạn dưới cho việc chia các phân lô nhỏ đến mức nào thì vừa.
Tại sao điều này có liên quan đến DP? Nếu chúng ta muốn có một kích thước phân lô 128 và chạy DP để phân chia ra,ví như là, 8 GPU chẳng hạn, sau đó mỗi vòng tính toán giá trị khuynh độ trên 16 mẫu rồi trung bình hóa với các dữ liệu từ GPU khác. Chính đây là trường hợp kẹt phải nút cổ chai của phần cứng.

Mảnh ghép bộ nhớ (Memory tiles): Cấp phát vùng bộ nhớ GPU nhanh để có thể tính tích vô hướng hiệu quả


Để tính tích vô hướng trên GPU, bạn cần phải sao chép vùng nhớ nhỏ, được gọi là mảnh ghép bộ nhớ, vào bộ nhớ đệm dùng chung, vốn là bộ đệm rất nhanh nhưng kích thước rất nhỏ (giới hạn trong một vài kilobyte). Vấn đề là các cuBLAS tiêu chuẩn sử dụng mảng ghép bộ nhớ kích thước 64 hay 128 và khi bạn có một kích thước phân lô dữ liệu ít hơn 64 bạn sẽ lãng phí rất nhiều bộ nhớ dùng chung quý giá ấy. Ngoài ra nếu bạn sử dụng một kích thước phân lô không phải bội số của 32 bạn cũng đang lãng phí bộ nhớ dùng chung cũng theo cách như vậy (dòng xử lý chỉ được kích hoạt theo từng khối gồm 32 dòng xử lý), vì vậy hãy cố gắng sử dụng một kích thước lô là một bội số của 32 hoặc bội số của 64 nếu có thể. Đối với DP thực ra điều này khiến tốc độ xử lý giảm đi đáng kể khi cấp một kích thước phân lô dữ liệu nhỏ hơn 64 cho mỗi GPU. Nếu bạn có nhiều GPU,sẽ thấy rất khó tối ưu và đây là một lý do tại sao các phương pháp tiếp cận DP sẽ dừng lại ở một quy mô tới hạn nhất định.
Túm lại, điều này nghe có vẻ khá nghiêm trọng đối với xử lý dữ liệu song song DP, nhưng DP vẫn có các ứng dụng phù hợp của mình. Chỉ cần hiểu rõ những chỗ thắt cổ chai, bạn có thể ứng dụng linh hoạt DP như một công cụ mạnh vào thực tế. Điều này được minh chứng bởi Alex Krishevsky trong bài báo của mình, khi ứng dụng DP trong các lớp tích chập của Alex, và do đó đạt được sự tăng tốc 3.74x lần bằng nếu chạy trên 4 GPU và 6.25x lần khi chạy trên 8 GPU. Hệ thống của Alex có 2 CPU và 8 GPU trong cùng một máy, vì vậy ông có thể sử dụng tốc độ PCIe đầy đủ cho hai bộ bốn GPU và kết nối PCIe tương đối nhanh chóng giữa các CPU để phân phối dữ liệu lên tất cả 8 GPU.
Bên cạnh mạng nơ-ron tích chập (convolutional neural networks-CNNs), DP còn được dùng trong các mạng nơ-ron tái phát (recurrent neural networks RNNs), vốn yêu cầu ít thông số nhưng cập nhật thông tin khuynh độ tính toán rất lớn – cả hai yếu tố này đều là lợi thế của xử lý dữ liệu song song.

Trong bài blog tiếp theo của tôi, tôi sẽ tập trung vào mô hình xử lý song song MP, hiệu quả cho các mạng nơ-ron lớn và cũng trên quy mô các cụm xử lý lớn hơn.

Thứ Hai, tháng 4 18, 2016

HPC(5) - chọn lựa phần cứng Motherboard và CPU

Computers  are useless. They can only give you answers. - Pablo Picasso
Như ở phần HPC 4 build trước, tôi đã giới thiệu về chọn lựa 4 card GPU GTX 780 Ti với tản nhiệt khí ACX 2.0 (2 quạt). Việc này cũng tạo rất nhiều "khoảng trống" để tôi tìm cách làm mát - xử lý nhiệt lượng -  khi GPU chạy hết tốc lực cho Deep Learning (DL). Đó là chuyện chút nữa nhé.

Giờ thì tranh thủ lý giải về 2 thành phần quan trọng khác, vốn luôn được tôn thờ và cân nhắc đầu tiên trong khi bắt tay vào dựng các dàn máy tính thông dụng: CPU - vi xử lý trung tâm -"bộ não" và motherboard - bo mạch chủ -"cơ thể". Tất nhiên, khi xây dựng đặc tả cho dàn máy chạy Deep Learning lần này, tôi đã bắt đầu với GPU trước tiên nhưng kế ngay sau đó là quyết định về 2 thành phần cần đặc biệt chú tâm tới ở trên.
Một yêu cầu phổ dụng để hỗ trợ tốc độ xử lý của GPU trong tổng thể 1 HPC là phải đáp ứng lượng dữ liệu dịch chuyển trong hệ thống ở băng thông và tốc độ đủ lớn để giúp tránh nghẽn cổ chai nhằm tận dụng năng lực của hàng nghìn nhân CUDA chạy song song hết tốc lực. Chuẩn kết nối thần thánh trong giới game thủ SLI Link của NVIDIA  chỉ đạt tốc độ tới 1GB/s, hầu như là quá chậm để tạo bộ đệm dữ liệu kịp thời cho năng lực xử lý của GPU. Thế nên, kể cho đúng ra, thì cái cầu nối 4 way-SLI tôi gắn trên HPC của mình làm màu cho vui và giữ 4 GPU thành khối gắn kết vững chắc hơn mà thôi :D. Cầu nối 4-way SLI  nguyên bản đi kèm với bo mạch chủ ASUS là bản mạch đen gắn chặt 4 đầu GPU lại với nhau như hình dưới.

image

Trong DL ở đây, việc giao tiếp và đồng bộ dữ liệu giữa các GPU sẽ chỉ còn thông qua khe PCI-e trên bo mạch chủ. Dữ liệu do CPU từ bộ nhớ RAM tới GPU cũng thông qua các cổng này. Luồng dữ liệu cơ bản dịch chuyển thực tế phức tạp hơn nhưng trong khuôn khổ bài viết này, tôi xin đơn giản hoá cho ngắn gọn như sau:
Neuron Network <--> Network card <--> [HDD/SSD<-->RAM<-->CPU<-->VRAM<-->GPU] x 4

Từ đó, có thể thấy hai yếu tố kết nối cơ bản trực tiếp liên quan và xác định năng lực hệ thống HPC chính là:

01. PCI-e trên bo mạch chủ (PCI:Peripheral Component Interconnect - Kênh liên kết các thiết bị ngoại vi) và

02. QPI trên CPU (QPI: Intel QuickPath Interconnect).

Hầu hết các bo mạch chủ ngày nay sử dụng các khe cắm mở rộng PCI Express để kết nối với card đồ hoạ. Đến giờ đang tồn tại các tiêu chuẩn PCI Express như sau:
PCIex

Chuẩn PCI-e hiện hành cao nhất là 3.0 với băng thông x16 (16 làn) Số làn chính là số "đường dây đồng" vật lý liên kết các thiết bị lại với nhau. Từ đó, ở góc độ vật lý, bạn sẽ thấy động dài của các khe cắm này. Tuy nhiên, tốc độ của 1 khe cắm cũng rất linh hoạt, chạy từ x1, x2, x4, x8 hay x16 và để ý kĩ thì trên mạch in bo mạch cũng sẽ in rõ tốc độ tối đa của từng khe cắm PCI-e (3.0 x16 chẳng hạn). Nói chung, nếu thiết bị với khe dài thì không cắm vừa khe ngắn nhưng phần lớn các thiết bị ngắn cắm được vào khe dài và bo mạch chủ sẽ tự tính toán để giảm tốc độ và làn băng thông tương ứng.  Dưới đây là một ảnh minh hoạ.

PCIExpress

Để có thể nuôi dưỡng 4 GPU 780 Ti khủng mà tôi chọn ở tốc độ cao nhất, tôi phải đi kiếm tìm bo mạch chủ có thể đáp ứng việc cấp dữ liệu x16 đồng thời trên cả 4 khe cắm. Hầu như mọi kết quả tìm kiếm và tìm hiểu với tiêu chí trên đều đưa tới kết quả một, ASUS Z10PE-D8 WS,  bo mạch dành cho máy trạm làm việc (Workstation) hàng đầu, chất lượng cực đỉnh, có thể hỗ trợ tối đa 4 card đồ hoạ chạy hết tốc lực tại PCI-e 3.0 x16. Bo mạch chủ này có đủ 4 khe PCIe-x16 bố trí cách nhau với độ rộng 2 khe, đồng thời chạy được x16 cùng lúc cả ở 4 kết nối PCI-e màu xám, cách nhau đều đặn bở 3 khe PCIe x8 đen. Tổng số là 7 khe PCI-e tất cả với đặc tả trong sách đi kèm như sau:
  • 4x PCIe 3.0/2.0 x16 (dual x16 or quad x8; light gray)

  • 2x PCIe 3.0/2.0 x16 (dual x16; dark gray)

  • 1x PCIe 3.0/2.0 x16 (dual x8; dark gray)
Chính vì với 7 khe PCI-e mà bo mạch này to hơn hẳn kích thước Full ATX thông thường mà bước sang chuẩn công nghiệp không dành cho người dùng thông thường, bo mạch server ngoại cỡ theo chuẩn SSI - EEB (Server System Infrastructure - Enterprise Electronics Bay).

6866_11_asus_z10pe_d8_ws_dual_cpu_intel_c612_workstation_motherboard_review_full

Tuy nhiên, chuẩn PCI-e với số làn như trên chỉ có thể có được trên các bo mạch Intel khi mà có số lược QPI tương ứng từ CPU để có thể cấp phát được băng thông dữ liệu tương ứng. QPI là một kiến trúc mới của Intel từ năm 2008 nhằm kết nối dịch chuyển dữ liệu vào ra I/O với các thiết bị ngoại vi. Đi vào chi tiết thì hơi loằng ngoằng nhưng mỗi CPU Intel nói chung có tối đa 40 làn dữ liệu QPI. Có nhiều thứ liên quan đến giá bán của một bộ vi xử lý CPU nhưng CPU có QPI 28 làn rẻ hơn rất nhiều so với CPU có QPI 40 làn. Nếu không tinh ý sẽ rất  dễ bị bỏ qua khi đánh giá lựa chọn mua. Ví như core I7 5820K chạy tốc độ 3.3GHz cao hơn Core I7 5960X chạy ở tốc độ 3.0GHz nhưng giá thì chưa đến một nửa đấy nhé.

1 - Processors

Với PCI-e 3.0 chạy với tốc độ cơ bản là 8GT/s. Cách tính toán băng thông QPI chi tiết khá rắc rối, phụ thuộc cả vào tốc độ xung nhịp chạy QPI trên CPU nhưng cơ bản cũng luồng dữ liẹu cũng đạt tầm 1GT/s cho mỗi làn. Vậy với QPI 40 làn, thì có thể đảm bảo dữ liệu vận chuyển tốc độ cao tới 3 thiết bị PCI-e kiểu như: 40 = 2 x16 + 1 x8. Với 4 GPU chạy x16 thì QPI cần tới 16 x4 = 64 làn. Thế là mình phải dùng bo mạch 2 CPU Xeon để có được 40 x 2 = 80 làn QPI. Ngoài ra, cứ 2 nhân CPU thì sẽ có 1 nhân "canh" chạy full load 100% cấp dữ liệu đệm cho 1 GPU và 1 nhân "cò quay", nên với hệ thống 4 GPU thì cũng cần ít nhất là 8 nhân CPU. Và theo tính toán băng thông thì CPU cũng không cần phải nhanh quá, tầm loanh quanh 2GHz trở lên cũng ổn rồi. Trên cơ sở đó, việc chọn lựa bo mạch ASUS Z10PE-D8 WS cùng với 2 CPU Xeon Haswell E5-2683 v3 14 nhân - 28 luồng là lựa chọn phù hợp (quá mức cần thiết cho DL, lợi thế cho rendering ấy chứ!!!) Dưới đây là cái cách mà bo mạch chủ trứ danh này phân tán 80 làn QPI đến các cổng PCI-e, đảm bảo cả 7 khe PCI-e này luôn có thể đạt tốc độ giao tiếp dữ liệu cao nhất. Khe 5 & 7 được thiết kế x16 trực tiếp với con CPU2, còn lại 2 khe 1 và 3 sẽ có cơ chế tự động chuyển mạch chạy với 2 x8 = x16 hay x8 tuỳ thuộc khe 2 hay khe 4 có thiết bị kết nối hay không như sơ đồ bên dưới.
6866_59_asus_z10pe_d8_ws_dual_cpu_intel_c612_workstation_motherboard_review

Kiến trúc QPI ra đời từ năm 2008 thay đế cho FSB (Front side bus) và năm bên ngoài nhân lõi kể từ đời Nehalem với cách tính lưu lượng dữ liệu khác phức tạp. Có thể hiểu mỗi QPI là một đường cao tốc gồm có 2 chiều đường, mỗi chiều có 20 làn kết nối dữ liệu từ điểm A tới điểm B và mỗi chiều đường lại có thêm 1 làn khẩn cấp nhằm đồng bộ tốc độ xung nhịp clock. QPI chạy ở xung nhịp 2.4GHz, 2.93GHz, 3.2GHz, 4.0GHz hay 4.8GHz (4.0GHz là từ dòng CPU Sandy Bridge-E/EP và 4.8GHz là từ Haswell-E/EP) . Cách tính lưu lượng dữ liệu ví như ở xung nhịp 4.8GHz của Haswell E/EP như sau:

4.8GHz x 2 bit/Hz (double data rate) x 16 (20) data bits/ QPI băng thông) x 2 (2 chiều nhận gửi cùng lúc) / 8 (bits/byte) =  38GB/s. 

Dưới đây là sơ đồ vi kiến trúc của Nalehem khi khái niệm QPI được giới thiệu lần đầu. QPI nằm cùng trên miếng silicon CPU nhưng lại là thành phần Uncore trong vi kiến trúc của bộ xử lý x86 Intel
1024px-Intel_Nehalem_arch.svgCuối cùng, ngoài việc cân nhắc tích hợp thiết kế hệ thống phù hợp về kỹ thuật để tránh nghẽn cổ chai băng thông dữ liệu cần tính toán cho GPU khi chạy các thuật toán cho Deep Learning thì việc xử lý nhiệt lượng làm mát để các GPU đang hết tốc lực như từ đầu bài viết này cũng là một yếu tố cần cân nhắc, khác hẳn với hệ thống SLI chỉ để chơi game truyền thống. GPU tự động tăng tốc lên cao nhất chỉ vài phút chạy các thuật toán DL, chạm ngưỡng giới hạn nhiệt của GPU (tầm 85 0C) dẫn đến giảm tốc độ nhân xử lý trong khi quạt rú ầm ầm để làm mát nhằm tránh nướng chín GPU. Điều chỉnh vòng tua để quạt GPU kick-in ở tốc độ cao sớm hơn tại mức nhiệt thấp là một cách phổ biến (early fan curve) của dân OC GPU trên windows, còn trên Ubuntu Linux thì sẽ là 1 trò hack khá loằng ngoằng mà tôi mất trọn 1 ngày-đêm chọc ngoáy trên 4 con GPU ở hệ thống HPC của mình trên đây. Có dịp, tôi sẽ chia sẻ thêm mình đã thành công script-hacking điều khiển quạt ở Nvidia GPU này thế nào ở một bài viết riêng khác.  Cuối cùng, để có thể làm mát 4 con GPU kẹp sandwich của mình, tôi đã phải quan sát và thử nghiệm luồng gió mát cấp vào tản nhiệt của GPU khá nhiều trước khi bố trí quạt và công suất quạt hợp lý hơn.
Mỗi GPU có 2 quạt 90mm đi kèm hút gió cửa trước thổi thẳng vào tản nhiệt, gió nóng sẽ theo các khe nhiệt chạy thẳng lên trên (80%) và 20% ra sau, phía cổng kết xuất màn hình của mỗi card. Ngoại trừ GPU(4) ngoài cùng thì các GPU(3,2,1) bên trong thì đều bị hút khi nóng ở khe hở rất nhỏ từ mặt bo mạch GPU trước đó để làm mát. Vì thế, tôi có lắp thêm 1 quạt 120mm tạo áp lực cấp gió mát từ ngoài thẳng vào dọc 3 khe hẹp giữa 4 card (chỗ chụp dẫn hướng gió DIY EVGA Enthusiast Built)  và một quạt 140mm tăng tốc hút khí nóng lên trên từ cả cụm 4 card.
Với suy nghĩ và tính toán khi động học như trên, tôi đã dựng hệ thống tản nhiệt khí hoàn toàn, đáp ứng các thuật toán DL chạy khá tốt trong một chu trình dài.


Và cuối cùng thực nghiệm lý thuyết trên cơ bản có thành công nhất định sau rất nhiều điều chỉnh:


Làm gọn gàng và tối ưu hoá dòng không khi làm mát gồm cả xoay tản CPU để CPU 1 và 2 đều có hút khi mát từ ngoài vào làm mát CPU cũng đồng thời làm mát Backplate của GPU(1) trong trường hơp GPU(1) chạy full load, hoặc hâm nóng theo CPU tý chút khi GPU(1) idle (từ 38oC lên tầm 41oC).


Khi chưa ứng dụng các sắp xếp tinh chỉnh khí động học thì hệ thống luôn ở trạng thái đun nước pha trà, luộc trứng với 4 card GPU chạy loanh quanh vùng 95 - 99oC lờ đờ giảm xung do quá nhiệt. Áp dụng vào rồi thì GPU chạy max cho đến khi hoàn thành thuật toán trong ngưỡng nhiệt cho phép <= 85oC.

image

Kết quả hiện giờ, tôi có 1 chiếc HPC đa mục đích, tạm thời phần nào thoả mãn nhu cầu tìm hiểu và học tập môn Deep Learning và cũng đủ dùng cho các tác vụ đa nhiệm, xử lý đồ hoạ, render video nặng của mấy em thiết kết đồ hoạ trong công ty. Ít ra, tôi đang mong chờ thêm đánh giá chuyên môn của các em ấy từ việc sử dụng cỗ máy HPC cho chạy Adobe After Efects làm film hoạt hoạ.

Thứ Ba, tháng 4 12, 2016

Bộ thư viện NVIDIA GPU REST Engine (GRE)

GPU thực chất cũng là một bộ vi xử lý song song cực kỳ hiệu quả có thể cung cấp dịch vụ có độ trễ thấp đáp ứng các yêu cầu gửi riêng rẽ không trùng lắp.



NVIDIA GPU REST Engine (GRE) là một cấu phần quan trọng cho các nhà phát triển xây dựng các dịch vụ web có độ trễ thấp. GRE bao gồm một máy chủ đa luồng HTTP cung cấp dịch vụ web RESTful và phân tải các yêu cầu đó một cách hiệu quả trên nhiều bộ xử lý đồ họa NVIDIA. Tổng thời gian đáp ứng cơ bản sẽ chỉ phụ thuộc vào mức độ nhu cầu tính toán của người dùng, còn bản thân GRE không làm nặng thêm mấy và còn có thể giải quyết các yêu cầu rỗng (null-request) dưới 10 micro giây.



Các dịch vụ web trên nền tảng GRE nhận yêu cầu được gửi đến, tìm nạp dữ liệu đầu vào và lập lịch lượng tử cho các đầu việc xếp trên một hàng đợi theo phương thức dịch vụ không đồng bộ. Một luồng xử lý riêng biệt dành cho quản lý công việc trên mỗi GPU và đảm bảo rằng tất cả các GPU trong hệ thống được cấp liên tục các yêu cầu từ hàng đợi không đồng bộ.

GRE sử dụng một kỹ thuật gọi là "độ trễ ẩn" cho hiệu năng thông lượng cao. Tức là, khi các dữ liệu cho một yêu cầu cụ thể đang được xử lý bởi một GPU thì cùng lúc đó, dữ liệu cho các yêu cầu tiếp theo được chuẩn bị và kết quả từ các yêu cầu trước đó nữa được trả về cho bên gửi yêu cầu. Tất cả diễn ra song song. Toàn bộ hàng đợi được sắp xếp một cách hiệu quả nhất có thể. Ở rất nhiều tình huống, GPU không bao giờ phải chờ đợi dữ liệu đầu vào.

Các nhân xử lý hình ảnh Nvidia (ICE: Nvidia Image Compute Engine) là điển hình cho thể thức vi dịch vụ cung cấp bởi GRE thông qua khả năng tăng tốc GPU trong xử lý và điểu chỉnh kích cỡ hình ảnh dành riêng cho dịch vụ web và các ứng dụng di động.

Các lập trình viên có thể tự xây dựng các dịch vụ này và tăng tốc theo cùng phương thức.  Khởi đầu với GRE, LTV có thể tập trung vào việc thực hiện các thuật toán cho các dịch vụ đang cần được tăng tốc. LTV sẽ phải xác định được các dữ liệu cần thiết gửi cho thuật toán của mình qua URL là gì. Sau đó, LTV chỉ cần tạo các hàm số chạy trên dữ liệu đó. Ví như bạn định tiến hành xử lý âm thanh nào đó, bạn có thể chỉ cần viết một hàm GPU hoặc gọi một chức năng thư viện tăng tốc GPU hiện tại từ các bộ thư viện nguyên mẫu NPP (NVIDIA Performance Primitives) để có mẫu đầu vào cùng với một vài thông số điều chỉnh rồi áp dụng các chuyển đổi.

Bản thử nghiệm bộ công cụ GRE hiện giờ đã cho phép bạn xem xét thành phần tạo lịch và chạy thử các thuật toán riêng của bạn. Bản thử nghiệm này đã gồm sẵn một máy chủ HTTP đơn giản được viết bằng ngôn ngữ Go kèm theo một dịch vụ phân loại hình ảnh cung cấp bởi thư viện học sâu cuDNN (Deep Learning). Các bản GRE thử nghiệm này nhằm đưa ra demo sớm ở góc độ khái niệm học thuật là chính.

(Theo Google Translate có hiệu đính qua qua bằng mắt người từ bản tin cộng đồng Nvidia Developers: https://developer.nvidia.com/gre)

Thứ Bảy, tháng 1 30, 2016

HPC (4) - Bonus - Nvidia GPU, tại sao lại chọn Kepler?

Như ở phần HPC build 3, tôi đã thống nhất lựa chọn dòng GTX 780Ti, tên mã vi kiến trúc Kepler (Kepler Microarchitecture GK110B) với số nhân CUDA lớn nhất vào thời điểm đầu năm 2015, 2880 CUDA cores. Mãi sau này, nó bị soán ngôi bởi Titan X với 3072 CUDA cores.
Chuyện thì dài nhưng  túm lại tại thời điểm dựng máy, tôi có thể lựa chọn 3 dòng GPU của Nvidia như sau: (Nvidia nhộn phết khi đặt mỗi tên dòng kiến trúc là tên các nhà khoa học lỗi lạc của thế giới)
Fermi: GeForce  400, 500 series, ra đời khoảng năm 2010, lúc này CUDA mới thực sự được chú ý tới vì GPU thay vì chỉ làm nhiệm vụ hiện thị hình ảnh thì giờ có thể được sử dụng trong tính toán. Khẩu hiệu lúc này là Giải pháp tính toán hình ảnh cách mạng (The Revolutionary Visual Computing Solution)  Chiếc card tôi có đại diện cho dòng này là con Quadro FX5600 1.5GB, băng thông 384-bit với 192 CUDA cores. Giá thành xuất xưởng siêu khủng $2,999. Giờ thì nó đang bị lỗi artifact, chập văn chờn, theo kinh nghiệm là phải cho vào lò nướng.
Kepler: Nvidia tuyên bố xanh rờn: Kepler là kiến trúc nhanh nhất, hiệu năng nhất thế giới cho HPC. (Kepler - The World's Fastest, Most Efficient HPC Architecture). Đến nay, ngay cả khi đã có thế hệ mới thay thế, tuyên bố này phần nào vẫn đúng trong các dòng GPU của Nvidia sản xuất. Đại diện dòng này tôi sắm 4 chiếc card siêu độ cho dân OC EVGA GTX 780 Ti Classified, 3GB, băng thông 384-bit với 2880 CUDA cores.  Giá xuất xưởng là $799. Tốn một mớ tiền x 4 vào đây. Và chúng sẽ là bạn đồng hành trải nghiệm qúa trình DL của tôi suốt thời gian ban đầu này.
Maxwell: Đây cũng là một kiến trúc được Nvidia quảng bá đổi mới nhưng thực ra, cá nhân tôi cho rằng mới mà không mới so với Kepler trước đây. Nó cũng không tạo ra cuộc cách mạng gì lớn giống như bước chuyển sang Kepler từ Fermi. Bản chất tập trung vào chỉnh sửa tối ưu tý chút đồng thời thiên về hỗ trợ kết xuất hình ảnh lớn cùng với xu thế độ phân giải siêu cao 4K hiện nay (VRAM nhiều lên hẳn). Vì thế khẩu hiệu đận này cũng đơn sơ:  GPU tân tiến nhất qủa đất (The World's Most Advance GPU). Đại diện cho dòng này tôi mua chiếc ASUS GTX 980 Strix, với 4GB, băng thông 256-bit với 2048 CUDA cores. Gía thành xuất xưởng là $599. GTX 980 được tôi lắp nâng cấp trên MacPro dành cho các tác vụ kiểm thử các vòng lặp tính toán (computing loop) đơn giản bên ngoài trong khi máy HPC kia bận rộn tính toán.
Chỉ với những thông điệp "ngầm" trên đủ thấy Kepler có vẻ mới chính là dòng kiến trúc chip chủ đạo mà Nvidia kỳ vọng tương đối lớn trong lĩnh vực điện toán HPC.
Trước khi xem xét cấu trúc phần cứng từng dòng GPU, chúng ta đều thấy trong điện toán song song của NVIDIA, CUDA là con số rất đáng quan tâm. Chúng ta hay đánh đồng CUDA  với số nhân xử lý GPU có trong một con card. Ví dụ như con GTX 780 Ti mà tôi dùng có đến 2880 CUDA cores, tức là có thể chạy 2880 nhân cùng lúc. Điều này giúp đơn giản hoá việc so sánh sức mạnh và tiên liệu năng lực tính toán của card nhưng kỳ thực không hoàn toàn chính xác. CUDA bản chất là một platform và thư viện phần mềm trên C/C++ với các API đề phục vụ các nhà phát triển có thể lập trình xử lý song song thông qua truy xuất trực tiếp tới tập lệnh và các lõi tính toán của GPU. Khả năng này còn được gọi là GPGPU (General-Purposed GPU). Các lập trình viên, thông qua thư viện CUDA để có thể điều khiển GPU nhằm và các tác vụ tính toán thông thường như serial CPU. Trong tổng thể 1 PC, luồng xử lý dùng CUDA có thể tóm tắt như trong hình dưới đây:
CUDA_processing_flow_(En)
 Với dòng Fermi, GPU thường có khoảng 3 tỷ chíp bán dẫn transistors, công nghệ 40nm là chính, tổ chức thành các tập xử lý dòng Streaming Multiprocessor gồm 32 CUDA mỗi tập. Về lý thuyết, khả năng tính toán SP của Fermi GPU (theo GFLOPS) là 2 (lệnh theo FMA mỗi chu kỳ, Fused Multiply-Add kiểu AxB+C) x số lượng nhân CUDA x tốc độ chip đổ bóng (in GHz). Còn về tính toán dấu chấm động FP64 thì khả năng giảm đi 1/2. (điều này đúng trên Tesla và Quadro chứ trên GTX, Nvidia làm thọt đi còn 1/8 thôi, quá láo).  Đặc trưng của Fermi là cơ bản nhân CUDA nào cũng có khả năng thực hiện 2 phép tính SP32 hoặc 1 phép tính FP64 trong 1 xung nhịp clock. Vì vậy, hiệu năng sẽ giảm khi không cần tính toán đến như thế trên tất cả các cores và khiến cho lượng tiêu thụ điện dòng Fermi rất khủng, đồng thời, có thể đun nước sôi pha trà với lượng nhiệt của dòng card này. :D
Fermi
Cũng với lý đó, Kepler ra đời sau đặt nặng hiệu năng tính toán và lượng năng lượng tiêu thụ hơn. Sản xuất với công nghệ 28nm, Con GK110 trong GTX 780 Ti có đến 7,1 tỷ chíp bán dẫn, gấp hơn 2 lần đời Fermi. Kepler ngoài các thế mạnh cũ thì cũng được tích hợp một loạt tính năng mới phục vụ cho điện toán song song như SMX (NeXt generation Streaming Multiprocessor), DP (Dynamic Parallelism), Hyper-Q MPI, GPUDirect... Có điều kiện tôi, sẽ đi sâu hơn về các tập kiến trúc mới này của Kepler riêng. Ở Kepler, CUDA Core vẫn có năng lực tính toán SP32 như trước, tức là 2 FMA mỗi chu kỳ nhưng không còn cõng phép tính FP64 mỗi nhân nữa mà thêm nhân tính toán FP64 riêng. Tỷ lệ tiêu chuẩn trên dòng cao cấp Titan Black, hay 780 Ti là 3:1 tức cứ 3 CUDA cores có 1 FP64(DP Unit màu cam). Ở các Kepler khác thì 24:1. Chính vì thế mà Kepler tiêu thụ điện lẫn toả nhiệt đã ít đi rất nhiều nếu so cùng năng lực tính toán ở dòng Fermi.

Con 780 Ti của tôi có 2880 CUDA Cores, tức là có 2880/3=960 DP Unit dùng cho tính toán FP64, hiệu năng FP64 của nó sẽ là 960 GFLOPS.

Kepler

Sang dòng chip hiện thời Maxwell, kiến trúc tương tự như Kepler nhưng NVIDIA  bỏ hẳn luôn nhân tính toán FP64. Toàn bộ xử lý FP64 được đẩy sang 1 core khác là Texture Mapping Unit (TMU), tỉ lệ là CUDA/TMU là 32/1  Về năng lực SP trên CUDA vẫn tương tự Kepler và Fermi nhưng FP64 thì giảm tương đối, còn lại khoảng  1/32 khả năng SP32. Chính vì thế, năng lực FP64 được xem rất tồi và kém hơn hẳn so với Kepler. Số lượng bán dẫn cũng giảm xuống còn 5.2 tỷ transistorsVí như con GTX 980 hàng đầu giờ chỉ có 128 TMU, tương đương với hiệu năng FP64 là 128 GFLOPS, chỉ bằng ~ 1/8 chú GTX 780 Ti của tôi. Được cái, thế này thì đỡ tốn điện đi nhiều đấy.

maxwell-gm-204-top-level-diagram

Với 3 dòng trên, Maxwell sẽ là kiến trúc duy nhất không có dòng siêu hi-end Tesla tăng tốc tính toán mà chỉ dùng cho dạng Tesla Grid và vGPU (Virtual GPU: card đồ hoạ ảo). Chiếc GPU Nvidia Tesla khủng nhất hành tinh đến tận giờ là chiếc K80 (K thì rõ ràng là Kepler rồi nhá), với 2 GPU GK210, 2x2496 = 4992 CUDA cores và VRAM siêu khủng 24GB.

TK80_575px

Như vậy, cho đến giờ, dòng Kepler vẫn là dòng chủ đạo số 1 trong các hệ thống HPC. Chiếc siêu máy tính Titan, xếp hạng số 2 thế giới nhưng là số 1 trong nền tảng CUDA hiện giờ cũng dùng Kepler, với 2688 CUDA (cùng nhân GTX 780). Vì thế Kepler cũng là lựa chọn hàng đầu đa mục đích cho chiếc HPC của tôi. Như ở phần HPC build 3, các bạn cũng biết tôi đã chọn lắp 4 chiếc card GPU EVGA GTX 780 Ti. Đây là một trong những dòng đỉnh cao nhất của Kepler mà Nvidia sản xuất dành cho game thủ được EVGA chế tác riêng và đã OC Ready. Những thông số cơ bản dưới đây, đặc biệt được bôi đậm là nhưng số có ảnh hưởng lớn đến việc sử dụng GPGPU trong các HPC.

  • Base Clock: 1020 MHZ (so với bản ref của Nvidia là 876 Mhz)
  • Boost Clock: 1085 MHz (so với bản ref của Nvidia là 928 Mhz)
  • Memory Clock: 7000 MHz Effective
  • CUDA Cores: 2880
  • Bus Type: PCI-E 3.0
  • Memory Detail: 3072MB GDDR5 (dư dùng cho game nhưng thật tiếc, nếu kiếm dòng Titan Black dễ dàng hơn với 6GB thì sẽ thực sự ngon dùng cho neuron networks lớn)
  • Memory Bit Width: 384 Bit
  • Memory Speed: 0.28ns
  • Memory Bandwidth: 336 GB/s
Trụ được đến đây, xin mời các bạn hãy thư giãn với một clip 20s khi tôi phải lắp lại nguồn để cấp đủ 8-pin x 2 vào mỗi con card của HPC.

Vậy trong tương lai, khi Nvidia đã hoàn toàn chú tâm và đầu tư mạnh mẽ bậc nhất vào phân hệ sức mạnh cho xử lý trí tuệ nhân tạo, AI, Deep Learning thì có gì sẽ thay đổi. Dù không phủ định, gaming đồ hoạ vi tính vẫn là thị trường bậc nhất nhưng những biến chuyển gần đây cho thấy Nvidia sẽ tiếp tục tạo được sự hợp lực cả hai hướng đi trên. NVIDIA đã công bố lộ trình trong tương lai gần năm 2016 sẽ ra mắt GPU Pascal (như một bước chuyển tiếp đến Volta 2018???) bổ sung sức mạnh cho các dòng hiện tại chủ yếu liên quan đến HPC, AI & DL.

NvidiaGPU Roadmap

Pascal là cuộc cách mạng của Nvidia hướng tới điện toán cao cấp cho trí tuệ nhân tạo và các mạng thần kinh neuron network. Pascal có thể tóm lược ở 3 điểm:
  1. Tổ hợp toán cả 16 bit và 32 bit tạo nên sức mạnh tính toán gấp 4 lần Maxwell hiện tại.
  2. Công nghệ HBM (High Bandwidth Memory- Bộ nhớ băng thông cao) sẽ thay thế cho GDDR5 (ATI đã tiên phong đưa vào sử dụng trong dòng GPU Fury X năm qua). Lượng VRAM tăng tới 32 GB và cho băng thông 6x hiện tại với HBM (bản chất là chồng các chip nhớ lên nhau, nên còn gọi là 3D VRAM).
  3. Công nghệ truyền dữ liệu NVLINK giữa các GPU với nhau cho băng thông từ 80->200 GB/s, tức là nhanh gấp từ 5 đến 12 lần băng thông PCIe x 16 gen 3 hiện tại.
Với 3 cải tiến trên, sức mạnh tổng thể của card đồ hoạ thế hệ Pascal sẽ có bước nhảy vọt, gấp 10 lần so với kiến trúc Maxwell hiện tại. Thật nóng lòng đợi nhà "bác học" Pascal nhưng nếu thế đến tay người dùng chắc phải gần hơn 1 năm nữa nhưng nếu không thật vội vàng và cấp thiết như tôi thì hãy chờ đợi một chút cũng đáng. Nếu sẵn tiền và chỉ cần để học hành tý chút thì hãy dòn tiền quất 1 con Titan X 12GB là đủ để tiếp tục chờ đợi.

PascalGPU

Thứ Hai, tháng 1 18, 2016

Siêu máy tính Titan (số 2 thế giới từ 2013 ~)

Titan vốn đang bá chủ thiên hạ cho tới năm 2013 thì bị Thiên Hà lên chiếm vị trí độc tôn. Titan có một lịch sử phát triển khá thú vị chứ không như Thiên Hà (Tienhe 2). Titan vốn được nâng cấp từ siêu máy tính Con Báo Jaguar trước đây được làm ra bởi công ty Cray. inc của Mỹ. Titan giờ đây là một sự kết hợp thú vị của quân xanh (Nvidia GPU) và quân đỏ (AMD CPU). Titan chính thức được đưa vào sử dụng 29/10/2012, đặt tại Phòng thí nghiệm quốc gia Oak Ridge.

Tài trợ chính: Bộ Năng lượng Mỹ và  and NOAA (<10%)
Tổ chức vận hành: Cray Inc.
Kiến trúc: 18,688 AMD Opteron 6274 16-core CPUs + 18,688 Nvidia Tesla K20X GPUs
Công suất tiêu thụ: 8.2 MW
Hệ điều hành: Cray Linux Environment
Diện tích đặt máy: 404 m2 (4352 ft2)
Bộ nhớ: 693.5 TiB (584 TiB CPU and 109.5 TiB GPU)
Lưu trữ ổ cứng: 40 PB, 1.4 TB/s IO Lustre filesystem
Công suất tính toán: 17.59 petaFLOPS  (công suất tính toán theo thiết kế max được 27 petaFLOPS)
Chi phí: $97 million
Xếp hạng trong TOP500: #2 từ 6/2013. Trước đó là #1 khi mới được dựng lên.
Mục đích sử dụng: nghiên cứu khoa học.



Titan_render
Nói qua chút về lịch sử kỳ vĩ của Titan. Tiền thân của Titan, Jaguar, sử dụng CPU AMD 4core 2.3 Ghz Barcelona. Bắt đầu được xây dựng vào năm 2005 với công suất tính toán thiết kế là 25 teraFlops, tức tương đương với 5 con GTX 980. Cuối năm 2008 thì cuối cùng cũng được nâng cấp lên đến 1.4 petaFlops. Đến năm 2009, Jaguar được mang ra đại tu, chuyển toàn bộ CPU sang AMD 6core 2.6 GHz Istanbul và 4core Budapest, nâng tổng số CPU trong mạng lưới lúc này là 200,000. (18,688 node thế hệ 5, mỗi node có 2 CPU Istanbul, 7830 node thế hệ 4, mỗi node sử dụng 1 cpu Budapest). Và 1 lần update cuối cùng đạt công suất 1.76 petaFlops.
Năm 2011, Jaguar được chuyển đổi dần trở thành Titan. 200 cabin (mỗi cabin chứa 96 node) thay thế từ từ thành 1 cpu 16 core AMD Opteron 6274 Interlagos và 1 GPU NVIDIA Tesla K20X (Con GPU này giá tầm 8000 USD, mỗi con chứa 2688 CUDA cores, bản chất là phiên bản cao cấp cùng chip của GTX 780). Việc chuyển đổi kéo dài đến tháng 10/2012 thì hoàn tất và chính thức đổi tên thành Titan vì Jaguar trước đây chỉ sử dụng core x86 để xử lý còn giờ phải là Titan do sử dụng cả x86 lẫn CUDA. Các lập trình sư đang sử dụng Jaguar tuy không thích quá trình nâng cấp xử lý sang CUDA, bởi vì nó không biến hóa được nhiều so với lập trình trên CPU quen thuộc trước đây, đây là một bước ngoặt "learning curve" cho đội ngũ lập trình viên về cách tiếp cận và tối ưu theo kiến trúc GPU nên có 2 trường phái sử dụng và đều được đáp ứng. Tuy nhiên, bản thân NVIDIA cũng chuyển dịch sang hướng hỗ trợ tăng tốc điện toán và thúc đẩy mạng neuron nên việc chuyển đổi sang sử dụng GPU trong điện toán song song diễn ra mạnh mẽ hơn bao giờ hết. Sức mạnh GPU giúp cho AI, Deep Learning, Machine Learning có những bước nhảy vọt. Bản thân Titan vẫn còn có kế hoạch tiếp tục nâng cấp để đến năm 2018. IBM đã trúng thầu vụ này nên Titan sẽ dần thay đổi để trở thành siêu máy tính tên mã Summit sử dụng CPU của IBM (Power PC???) và thế hệ GPU mới nhất của Nvidia Pascal. Titan cũng là siêu máy tính rất hiệu quả về mặt năng lượng và dùng tản nhiệt khí.

Thứ Ba, tháng 1 12, 2016

HPC (P3) - CUDA, đội xanh Geforce GTX cho Deep Learning giá rẻ

Như kết luận trong phần trước, CUDA là kiến trúc lựa chọn cho HPC của tôi. Và cũng chẳng phải thắc mắc nhiều, tức là chỉ có cách trung thành với các card đồ hoạ sản xuất bởi NVIDIA. Tuy nhiên, NVIDIA cũng không hổ danh là nhà sản xuất GPU số 1 thế giới nên cũng đủ để đau đầu lựa chọn sản phẩm GPU nào phù hợp nhất. Đương nhiên, nếu xuất phát điểm không phải chỉ để dành cho nghiên cứu cùng với túi tiền cực kỳ rủng rỉnh không cần quan tâm đến giá cả, cứ con mới nhất, xịn nhất mà mua.
Nhưng nếu nghĩ đến hiệu năng với giá pp (price/performance) cho một newbie trong DL thì chuyện trở lựa chọn nào trở thành một bộ môn khoa học nghiêm túc hơn nhiều. Trên thế giới, việc sử dụng GPU và cụ thể là với NVIDIA CUDA đã mang lại sức mạnh siêu máy tính đầu tiên vượt ngưỡng 10 petaFLOPS, chiếc siêu máy tính mạnh thứ 2 trên quả đất, sau Thiên Hà, với tên là Titan.
Các bạn có thể ngó thêm thông tin về siêu máy tính mạnh số 2 thế giới ở đây nhé.

Quay trở lại với quá trình dựng HPC của mình, bắt đầu với việc chọ GPU nào của NVIDIA. Trong thời gian 10 năm trở lại đây, NVIDIA có 4 dòng kiến trúc thiết kế GPU chính và có sở thích gắn tên các nhà khoa học lớn trong lịch sử với mỗi dòng đó. Kiến trúc thiết kế Fermi (GTX500-600 series), Kepler (GTX 700 series), hiện tại là Maxwell (GTX 900 series) và cuối năm nay, hy vọng sẽ xuất xưởng chip GPU dòng Pascal. Tại mỗi dòng thì sẽ có 3 cấp độ, dành riêng cho điện toán máy chủ cao cấp Tesla, máy trạm trung cấp Quadro, và game thủ thứ cấp Geforce GTX và giá tiền cũng từ rất cao xuống đến bình dân...

Vậy chọn GPU nào cho DL?

Nhiều người lầm tưởng đã làm việc thì cứ phải chọn dòng cho trạm làm việc Quadro. Để học DL thì chỉ có thừa tiền lắm mới thế. Quadro, về cơ bản là những con chip được lựa chọn kỹ càng (theo ASIC chẳng hạn) và thiết kế dùng làm đồ hoạ, đổ bóng 3D, etc chứ bản chất cũng không khác dòng Geforce rẻ tiền hơn rất nhiều (đôi khi là 1/4  ~  1/10 giá) với cùng hiệu năng.  Về phần cứng là vậy, tôi nghĩ cơ bản chip giống hệt và chỉ có Nvidia viết driver riêng thành từng dòng nên làm cho card Quadro có driver được chăm chút và test kỹ càng hơn rất nhiều khi release (sẽ ít lỗi phần mềm hơn, nhưng release tính năng mới sẽ chậm hơn). Driver cúa dòng game thủ GeForce đôi khi bị cắt bớt/ẩn tính năng của chip phần cứng đi. Nhiều cư dân mạng đôi khi hack một tý để dùng driver của Quadro cho Geforce còn được nữa là. Được cái tên đặt trong Quadro khá mạch lạc theo các kiến trúc chip GPU. Ví dụng Quadro Fx5600 là dòng Fermi, Quadro K6000 là dòng Kepler (tương đương con GTX 780 Ti của tôi, dòng GK110), Quadro M6000 là dòng Maxwell.
Tesla là một dòng card đồ hoạ cao cấp dành cho máy chủ và xử lý thuần tuý, và không có kết xuất ra màn hình (trừ một số đời ơ kìa ấm ớ, không hiểu sao lại có) Về chip thì cơ bản vẫn vậy, theo dòng nhưng các tính năng tính toán, đặc biệt là dấu phẩy động FP được kích hoạt đầy đủ và tối ưu nhiều nhất có thể (Khả năng chip có khi vẫn thế nhưng bọn Xanh nó set disable bớt đi ở các dòng rẻ đi chứ không sản xuất thành 1 con chip dòng Tesla riêng đâu??? Láo quá!) Nhưng gì thì gì, Quadro và Tesla thì có cái rất hay cho DL là bộ nhớ khủng, thường gấp 2, gấp 3 dòng phổ thông game thủ Geforce phổ thông, một trọng yếu cho các ma trận DL cỡ lớn hơn bình thường chút mà tôi sẽ đề cập đến sau này trong series về Deep Learning.

Cùng kiến trúc và chip GPU mã GK110, số nhân CUDA như nhau, GTX 780 Ti với 3GB RAM có giá tầm 600$, Quadro K6000 12GB RAM giá 4800$ và Tesla K40 giá 5800$. Mà nếu chạy mấy cái task vẽ vời dùng ma trận cỡ nhỏ, tôi nghĩ rằng sẽ chẳng khác biệt đáng kể về performance (Dòng GTX của tôi là dòng khủng, card độ, ép xung nên có khi còn nhanh hơn ấy.)

TeslaK40
Tesla K40 với FP64 ở mức vượt trội gấp 8 đến 10 các card cùng GPU ở các dòng sản phẩm còn lại, thích hợp với tính toán mô phỏng phản ứng, hóa dầu, địa chất, etc. Cái này khả năng một phần thiết kế mạch, một phần các phần mềm driver các dòng còn lại bị vô hiệu hoá chứ con chip GPU có khi như nhau thôi nhể. Siêu cuội Nvidia đa cấp với giá chát chúa $5800.

quadro-k6000-3qtr

Quadro K6000 hầu như không vượt trội gì so với GTX, ngoài bộ driver được test kỹ và VRAM khủng. Giá 4800$, tức là thêm $4K chỉ để được driver và dịch vụ support của Nvidia mức pro + + với 9GB extra VRAM. Dân đồ họa thì ưa thích dòng này vì sự bền bỉ và support tận răng cho các ứng dụng kết xuất và chỉnh sửa ảnh, video.

evga-geforce-gtx-780-classified-3gb

EVGA GTX 780 Ti Classified. Khủng của khủng trong dòng gamer đại chúng của Nvidia GTX 780 Ti. Cái gì cũng đẹp, mỗi tội VRAM 3GB là quá hẻo cho các ma trận điểm lớn một chút trong các mạng neuron lớn, còn nếu chỉ dùng video game thì đến giờ vẫn đang rất ổn áp rồi.

Nói chung muốn siết cũng phải biết điều tiết. Nhìn vào đây thì thấy cơ bản Geforce và Quadro không khác nhau mấy, còn so với Tesla thì chắc chỉ để cho mấy bố làm hoá dầu với cả mô phỏng phản ứng hạt nhân nhể. Chú ý tuyệt đối phải hiểu rõ (sâu :D) mình cần gì để chọn GPU cho phù hợp nhé.

GPU_Chart

Khả năng tính toán của 1 CPU/GPU được đo bằng đơn vị floating-point operations per second (FLOPS) – khả năng tính toán dấu chấm động trong 1 giây trong single precision(SP). SP là 1 dạng con số được định nghĩa = 32 bit.
Ở trên thì có thêm thuật ngữ double precision (DP), tức là con số được định dạng 64 bit. Tùy thuộc vào cấu tạo của Card mà 2 card chung GPU có thể giống single precision nhưng khác double precision (ví dụ K40 và 780 Ti là 2 con GPU giống nhau nhưng chỉ số DP lại khác nhau). Chắc cả CHIP và Driver ở Tesla mới được mở hết giới hạn.

Với ưu điểm tuyệt đối về giá, GeForce là lựa chọn không phải bàn cãi. Câu hỏi bây giờ là dùng 1 GPU hay nhiều GPU. Lưu ý Các trò SLI hay CrossFire là vô nghĩa trong DL và Linux vì thực ra để giao tiếp dataset giữa các card trong DL, chúng là quá chậm, chỉ có thể PCI-E  3.0 là đủ dùng. Nếu muốn mò mẫm học nhiều và tự tin về khả năng đồng bộ thì cứ mua vài con GPU (max là 4 cho đủ Quad SLI [dù chả liên quan mấy] với lại cũng gần như là max số khi PCI-e các mobo thông dụng có thể chứa được các GPU đúp này) để thử. Còn không rủng rỉnh lắm, cứ dồn tiền đập vào con mạnh nhất có thể trong dòng phổ thông (khi viết bài này là con GTX Titan X 12GB dòng Maxwell đấy)

Suy cho cùng là tính toán song song nên tổng hiệu suất mấy card rẻ thì có thể cao hơn 1 card mạnh thật. Tuy nhiên, việc đồng bộ hóa giữa 2 GPU thường không tốt và khá khó khăn cho coding (đôi chỗ là chưa thể như chia sẻ bộ nhớ video với nhau) nên sức mạnh không tăng theo phép cộng card được. Về lâu dài, thì cũng hết đường/hết khe để mà nâng cấp. Nếu chỉ nghịch ngợm tý trong Neural Network nhỏ ,thật lòng bạn nên vét túi vào con GPU mạnh nhất có thể. Nhỏ quá, việc đồng bộ là overhead quá sức tải của đầu óc, để tiếp thu cái khác có lợi hơn.
Nếu nghịch lâu dài với network khủng hơn như Convolutional Neural Network (CNN) thì có thể tối ưu hoá hiệu năng Price/Performance. Hiện tại CNN hỗ trợ tối đa lên đến 4 gpu trong 1 thùng nhưng sau này, khi mà hệ CPU Pascal của NVIDIA ra đời thì số lượng GPU trong 1 máy sẽ tăng cao hơn nhiều...

 Tạm thời xem mẩu video timelapse chiếc HPC được lắp lên thế nào cho đỡ chán mắt cái đã nhỉ? Ở phần sau tôi sẽ nói kĩ hơn về các vi kiến trúc cơ bản của Nvidia và lựa chọn của mình.

HPC (P2) - Lựa chọn kiến trúc GPU nào cho Deep Learning

Như trong phần trước, tôi đã giới thiệu sơ qua về khái niệm Deep Learning và khả năng to lớn của việc sử dụng kiến trúc của GPU trong xử lý song song phục vụ tăng tốc cho quá trình học tập và rèn luyện trí tuệ nhân tạo của máy tính, đặc biệt với Deep Learning và Neuron Networks. Trong phần tiếp theo này, tôi sẽ giới thiệu qua về các nền tảng phần cứng hiện thời cho việc xử lý các thuật toán song song cùng với lựa chọn của mình.
Với mấy ông chỉ coding phần mềm thương mại và mobile, có lẽ việc khó khăn nhất khi bắt đầu làm về Deep learning nói riêng và Machine Learning nói chung là chọn được đúng nền tảng đi kèm phần cứng hỗ trợ tính toán song song mạnh. Đương nhiên, ai cũng nghĩ thế. Có vài hướng đi cơ bản với mục đích tăng thật nhiều core xử lý cùng lúc như sau:

01.Intel Xeon Phi
Với khẩu hiệu: Thêm nhân, thêm sức mạnh (More Cores, More Performance)xeonphi
Xeon Phi ra đời là mở rộng của bo mạch chủ chạy Chip Intel, nhằm đưa thêm nhiều nhân xử lý co-processor vào hệ thống thông qua khe cắm mở PCI -Express. Intel đặt tên mỹ miều cho kiến trúc này là Intel MIC (Intel Many Integrated Core Architecture) nhưng bản chất là gắn thêm nhiều con CPU Xeon vào bản mạch rồi cắm vào khe PCI-E mà thôi 

intel.web.480.270
Hồi đầu chúng nó được đặt tên mã là hiệp sỹ (Knights) này nọ kiểu Knights Ferry, Knights Corner, Knights Land và Knights Hill. Sau này thì dồn lại về theo kiểu đánh số xe BMW có series 3, 5 và 7 tương ứng là 3100 series, 5100 series và 7100 series. Do bản chất vẫn là dây chuyền sản xuất Intel CPU nên số nhân cũng tương đối hạn chế, ví dụ như con mạnh nhất hiện giờ 7120D có 61 nhân, 512 SIMD units (Single Instruction, Multiple Dataset), 16GB RAM thừa kế kiến trúc cổ xưa Pentium (thời CPU cắm mobo kiểu cartridge???). Giá con Xeon Phi này đắt, tầm 4300 USD và đặc biệt là không có bán đại chúng cho người dùng thông thường. Tuy thế, nói gì thì nói, bản chất vẫn là intel x86 nên ace lập trình cũng chả phải học hành lại gì mấy, dùng luôn kỹ năng coding hiện tại thôi. Sở dĩ tôi đề cập đến Xeon Phi đầu tiên dù chưa được sờ vào so với 2 cái sau đây vì nó chính là các bộ xử lý trong chiếc siêu máy tính mạnh nhất hành tinh của chúng ta hiện giờ từ suốt  2013 đến giờ, chiếc Thiên Hà 2 (Tienhe 2) của Trung Quốc.

Thông tin thêm: Thiên Hà 2 bản chất là kết nối sâu của 16000 node tính toán, mỗi node là một con HPC với 2 Xeon CPU e5-2692 v2(đời Ivy Bridge), 3 card Xeon Phi loại serie 3, chỉ có 8GB RAM on-card và 64GB RAM hệ thống.  Nhẩm nhanh cũng tầm 12000 USD cho mỗi node nếu cá nhân đi mua roài. Thiên Hà 2 có sức mạnh tính toán lý thuyết max là 54.9 PetaFLOPS còn thực tế thì chạy ở tầm 60% khoảng 34 PetaFLOPS.


Vị trí: Trung tâm siêu điện toán quốc gia, Quảng Đông, Trung Quốc.
Kiến trúc: 32,000 Intel Xeon E5-2692 12C tốc độ 2.200 GHz + 48,000 Xeon Phi 31S1P
Tiêu thụ điện: 17.6 MW (24 MW bao gồm cả làm mát)
Hệ điều hành:  Kỳ Lân OS (Kylin Linux)
Bộ nhớ: 1,375 TiB (1,000 TiB CPU and 375 TiB coprocessor)[1]
Ổ cứng: 12.4 PB
Khả năng tính toán: 33.86 PFLOPS
Trị giá: 2.4 tỷ Nhân Dân Tệ (US$390 triệu)
Mục đích sử dụng: Mô phỏng, phân tích, và ứng dụng an ninh quốc phòng.

Túm lại là con Thiên hà 2 tốn điện vãi lúa.

02. OpenCL (Khronos Group)

Với khẩu hiệu kết nối phần mềm tới silicon (Connecting Software to Silicon, hơi phiêu tý he he)

Open Computing Language với ưu điểm chạy được đa nền tảng phần cứng CPU, GPU, DSP, FPGAs, cung cấp một giao diện API tiêu chuẩn cho việc xử lý đa nhiệm song song theo cả hai kiểu tác vụ hay dữ liệu (task-based or data-based). OpenCL được duy trì và phát triển bởi Khronos Group. Nguyên thuỷ xuất phát từ Apple nên được Apple cam kết và hỗ trợ tận răng với các thế hệ máy tính và hệ điều hành Mac OS X. Nền tảng phần cứng, phần mềm đứng đầu là AMD/ATI, là nhà sản xuất cả CPU lẫn GPU, đối tác chính của Apple . Tuy nhiên, OpenCL ra đời tương đối chậm, cùng với thư viện phần mềm tuy mở open source nhưng ì ạch, driver không ổn định, lib thì ít và thiếu vắng các cộng đồng lớn, OpenCL không phù hợp với newbie như tôi và tôi cũng võ đoán rằng cũng rất ít nhà nghiên cứu đi sâu được ngay dùng cho DL. Sau này, nếu có tham vọng đi sâu hơn thì OpenCL thực sự rất có tương lai.

Thông tin thêm: Khronos Group một tổ chức phi lợi nhuận của Mỹ thành lập năm 2000 ban đầu bởi khoảng 7-8 công ty gồm cả ATI, Intel, NVIDIA, SGI (Silicon Graphics) và Sun Microsystems. Đến giờ thì đã có tới xấp xỉ tầm 120 công ty tham gia thành viên, và khoảng hơn 50 thành viên "dự bị" theo chuẩn OpenCL.
khronos-group-logo

03. CUDA (NVIDIA)

Với khẩu hiệu Nvidia Tăng tốc điện toán (Nvidia Accelerated Computing)
NV_CUDA_2D_Color_large
Thực ra môn CUDA này chỉ có 1 tay chơi và duy nhất là Nvidia, nhà sản xuất card màn hình và vi xử lý đồ hoạ (GPU) hàng đầu thế giới. Sự phổ biến của phần cứng, hỗ trợ mạnh về thư viện và phần mềm cùng với nhiều cộng đồng nghiên cứu và phát triển tiếng tăm trên thế giới như ở các đại học Standford , MIT, etc khiến cho hầu như không còn ai đứng làm đối thủ cạnh tranh phân khúc này. Một mình Nvidia thao túng, trong khi vẫn nhúng tay vào Khronos Group ở trên. Đó là lý do các card đồ hoạ GPU của NVIDIA luôn hỗ trợ cả OpenCL lẫn CUDA còn AMD/ATI chỉ có OpenCL mà thôi. CUDA cũng là nền tảng mà tôi lựa chọn. Bản thân Nvidia cam kết cao ngất cho việc này và các ông lớn đều thế cả mà.

Nvidia AI Engine

Giá cả để trang bị NVIDIA GPU (đội xanh) không hề rẻ và có sức mạnh xử lý "cứng" như đội đỏ nhưng cũng rất sẵn có với đại chúng và nhiều mức độ chi tiền. Nvidia có nhiều dòng sản phẩm, từ rất cao cấp như Tesla với giá khủng hơn cả Xeon Phi ($5,000-$10,000), trung cấp Quadro từ vài trăm $ cho đến $5,000 và dòng phổ thông rẻ nhất GTX cho game thủ ở ngưỡng $100 - $1,000.  Cho Deep Learning thông thường, độ chính xác FP không cần quá chính xác nên nếu tận dụng cho học tập và xử lý cơ bản, một hệ thống với card GTX mà hiệu năng cũng có thể cực khủng không thua kém gì các hệ thống lớn đắt tiền cả. Về cân nhắc lựa chọn hiệu năng PP (Price/Performance) cho hệ thống của mình, tôi sẽ chia sẻ với các bạn trong phần sau. Đây cũng là lý do mà nhiều researcher hay data scientist trên thế giới tự xây dựng HPC của mình với lựa chọn CUDA Nvidia GTX.