Làm thế nào tôi có thể gieo một bộ tạo số giả ngẫu nhiên tuyến tính song song trong khoảng thời gian tối đa?


8

Thông thường khi tôi tạo một bộ tạo số ngẫu nhiên liên tiếp trong C, tôi sử dụng cuộc gọi

srand(time(NULL))

sau đó sử dụng

rand() mod N

để có được một số nguyên ngẫu nhiên trong khoảng từ 0 đến N-1. Tuy nhiên, khi tôi thực hiện việc này song song, các lệnh gọi thời gian (NULL) rất gần nhau và cuối cùng chúng có cùng một số.

Tôi đã thử sử dụng một trình tạo số ngẫu nhiên đồng quy tuyến tính:

xn+1:=axn+c(modm) cho một số số nguyên a,c,m .

Tôi biết rằng việc chọn m=2k cho một số nguyên lớn k tạo ra kết quả nhanh vì toán tử mô đun có thể được tính bằng cách cắt các chữ số. Tuy nhiên, tôi thấy khó khăn khi thiết lập các hạt tạo ra các chuỗi ngẫu nhiên với một khoảng thời gian lớn song song. Tôi biết rằng một khoảng thời gian là tối đa nếu

  1. c và m là các số nguyên tố liên quan đến nhau
  2. a - 1 chia hết cho tất cả các thừa số nguyên tố của m
  3. nếu m là bội của 4 thì a - 1 cũng phải là bội của 4.

(nguồn: wikipedia )

Nhưng làm thế nào để tôi đảm bảo rằng tất cả các luồng số ngẫu nhiên có thuộc tính tối đa này? Về khía cạnh MPI, làm cách nào để kết hợp ranksizetạo ra các khoảng thời gian tối đa bằng cách sử dụng phương pháp cộng hưởng tuyến tính? Sẽ dễ dàng hơn khi sử dụng Fibros Lagled hoặc Mersenne Twister để tạo ra các luồng ngẫu nhiên song song dài hơn?


3
Cũng như một lưu ý phụ, bạn gần như chắc chắn không muốn sử dụng PRNG đồng dạng tuyến tính cho tính toán khoa học. Họ không thể lấy mẫu đúng không gian có kích thước cao hơn 1. Điều đó có nghĩa là: họ thậm chí không thể vẽ một mẫu điểm thích hợp trong mặt phẳng.
dmckee --- ex-moderator mèo con

1
@dmckee: Định lý của Marsaglia chắc chắn có liên quan đến một số tính toán khoa học, nhưng sẽ không công bằng khi nói rằng nó không đủ tiêu chuẩn của LCG cho tất cả các tính toán khoa học. Đôi khi có PRNG nhanh cũng quan trọng không kém và số lượng vectơ kéo dài (thông qua gốc) thường quan trọng hơn số lượng siêu phẳng bao trùm không gian mẫu.
Jack Poulson

2
@dmckee: bạn có thể đúng về LCG, nhưng với rất nhiều ứng dụng, 1D là đủ.
Paul

1
@JackPerinois Tôi thiên vị bởi tính chất công việc của mình và tôi nhận thức được đó là lý do tại sao tôi chỉ định bản chất của khuyết điểm. Paul: Có rất nhiều PRNG được nghiên cứu kỹ lưỡng và rất nhiều sự đánh đổi (tốc độ, thời gian, an toàn mật mã và khả năng rút ra các bộ dữ liệu có chiều hướng cao). Tôi sử dụng Mersenne Twister cả trong những thứ tôi viết mã bằng tay và làm PRNG mặc định trong ROOT . Đây không phải là cách nhanh nhất để đi, nhưng sau đó vẽ số thường là một đóng góp khiêm tốn cho thời gian hoạt động của tôi.
dmckee --- ex-moderator mèo con

1
Một lưu ý phụ khác, nếu bạn cần sử dụng LC PRNG (có lẽ vì lý do tốc độ), bạn chắc chắn không muốn sử dụng modđể lấy các bit thứ tự thấp - như Jonathan Dursi đề xuất, chúng ít ngẫu nhiên hơn nhiều. Thay vào đó hãy chia số ngẫu nhiên (int) của bạn cho maxint / phạm vi để có được phạm vi bạn cần. Bạn phải trả một khoản tiền chia, nhưng có lẽ đó là một lựa chọn rẻ hơn để cải thiện chất lượng của luồng số ngẫu nhiên của bạn so với chuyển sang PRNG khác.
Đánh dấu gian hàng

Câu trả lời:


9

Mẹo nhỏ là xen kẽ luồng LCG của mỗi tiến trình: đối với các tiến trình , chúng tôi sửa đổi LCGp

xn+1:=axn+c(modm),

được

xn+p:=Apxn+Cp(modm),

trong đó và có hiệu quả bước tiếp các bước . Chúng tôi có thể nhanh chóng lấy được chúng bằng cách mở rộng bước LCG ban đầu:C p pApCpp

xn+2=a(axn+c)+c(modm)=a2xn+(a+1)c(modm),

và mô hình là và là kết quả của, bắt đầu từ số , liên tiếp nhân với và thêm lần, sau đó nhân với , tất cả .C p 0 a 1 p c mod mApapmodm,Cp0a1 pcmodm

Bước cuối cùng là đảm bảo rằng LCG -stride của mỗi quá trình không trùng nhau: chỉ cần khởi tạo quy trình với thứ hạng với và LCG song song với các giai đoạn riêng lẻ đã sẵn sàng, trong đó là giai đoạn ban đầu và là giai đoạn ban đầu số lượng quá trình. Nếu LCG được sửa đổi của mỗi quá trình được sử dụng như nhau, toàn bộ thời gian được phục hồi song song.r x r N / p N pprxrN/pNp

Tôi đã thực hiện điều này khoảng sáu tháng trước (có lẽ là ngây thơ), và bạn có thể tìm thấy mã ở đây .


Đó là một cách tiếp cận thú vị. Nó thực sự lấy N tuples từ một luồng LC PRNG theo cách phân tán. Nó vẫn chịu các vấn đề tương quan được đề cập trên wikipedia nhưng không yêu cầu chi phí đồng bộ hóa của nguồn PRNG tập trung. Tôi sẽ quan tâm để xem chất lượng của các luồng này so với tương quan giữa các luồng được tạo bởi nhiều LC PRNG với các hằng số khác nhau.
Đánh dấu gian hàng

Ý kiến ​​hay; điều này dường như cầu xin được viết cho GPU.
Chinasaur

Là thực hiện của bạn điều chỉnh cho sự gắn kết bộ nhớ? Tôi tưởng tượng việc cố gắng cung cấp cho mỗi luồng một khối tiếp giáp lớn hơn và để chúng nhảy qua nhau trong các bước lớn hơn sẽ hoạt động trơn tru hơn? Mặt khác, GPU là phiên bản hoàn chỉnh.
Chinasaur

6

Có một bài viết tổng quan rất hay của Katzgrabber, Số ngẫu nhiên trong tính toán khoa học: Giới thiệu , tôi chỉ cho mọi người muốn trở thành người sử dụng PRNG cho tính toán khoa học. Máy phát điện tuyến tính nhanh, nhưng đó là tất cả những gì họ có cho chúng; họ có thời gian ngắn, và họ có thể rất dễ đi sai; kết hợp tìm kiếm hoàn toàn hợp lý của a, c và m có thể kết thúc với đầu ra tương quan khủng khiếp, ngay cả khi bạn đáp ứng các yêu cầu thông thường giữa a, c và m.

Tồi tệ hơn, trong một trường hợp phổ biến trong đó m là lũy thừa của hai (vì vậy thao tác mod nhanh), các bit bậc thấp hơn có chu kỳ ngắn hơn nhiều so với toàn bộ chuỗi, vì vậy nếu bạn đang thực hiện rand ()% N, bạn có một khoảng thời gian thậm chí ngắn hơn bạn mong đợi.

Theo nguyên tắc chung, máy phát điện lagged-fftimeacci, MT và WELL có các đặc tính tốt hơn nhiều và chúng vẫn còn khá nhanh.

Về mặt gieo hạt song song, phương pháp của Jack Poulson rất hay vì nó đưa ra một chuỗi các số được xác định rõ ràng chia đều giữa các bộ xử lý. Nếu điều đó không quan trọng, bạn có thể làm bất cứ điều gì hợp lý để gieo các PRNG khác nhau; cùng một bài báo cho thấy một số thứ mà nhiều người đã nghĩ ra một cách độc lập, băm số nhiệm vụ của PID hoặc MPI cùng với thời gian. Công thức cụ thể được đề xuất là

long seedgen(void)  {
    long s, seed, pid;

    pid = getpid();
    s = time ( &seconds );

    seed = abs(((s*181)*((pid-83)*359))%104729); 
    return seed;
}

Tôi không có ý kiến ​​cụ thể về việc thực hiện cụ thể đó, nhưng cách tiếp cận chung chắc chắn là hợp lý.


Tôi thích bài viết tổng quan, cảm ơn! Tôi cho rằng tôi nên bảo vệ LCG bằng cách lập luận rằng bây giờ người ta có thể chỉ cần chọn các giá trị tốt cho từ Thuật toán chuyên đề của Wikipedia hoặc Knuth, và ví dụ trong bài báo Katzgrabber là không công bằng vì đó là LCG mà không có sự thay đổi ( ). c = 0(a,c,m)c=0
Jack Poulson

Có cái đó, nhưng ngay cả cái có a = 106, c = 1283, m = 6075 (hình 2) là cả một đống thất bại. Nhưng có, có ba bộ ba tốt có sẵn.

@JackPoulson: Tôi luôn cảm thấy rất bực mình khi phải chọn một, c và m khỏi đỉnh đầu ... khi tôi làm theo cách này, nó dường như luôn dẫn đến những giai đoạn rất nhỏ. Cảm ơn đã trích dẫn! Tôi sẽ tìm kiếm các thuật toán chuyên ngành của Knuth.
Paul

2

Một ý tưởng đơn giản để truyền bá một RNG tuần tự điển hình trên một số lượng lớn các luồng là để một luồng duy nhất tiến hạt giống nhanh nhất có thể và chỉ gửi mỗi nghìn hạt giống vào bộ nhớ. Sau đó, mỗi luồng khác của bạn lấy một trong số các hạt tham chiếu cách nhau này và xử lý 1000 giá trị trong khối đó, tức là tái tạo lại 1000 hạt trong khối, tạo ra các bản vẽ psuedorandom của chúng, và sau đó thực hiện bất kỳ việc xử lý nào khác cho nhiệm vụ của bạn.

Điều này hoạt động vì đối với các RNG không tính toán được nhiều như vậy (LCG chắc chắn là một, nhưng nhiều người khác nên nằm trong danh mục này), nút cổ chai thực sự đang gửi các hạt giống ra bộ nhớ (và có thể xử lý tiếp theo). Nếu bạn chạy LCG mà không gửi bất cứ thứ gì vào bộ nhớ, toàn bộ điều phải ở trong các thanh ghi CPU và cực kỳ nhanh. Ngay cả đối với một RNG phức tạp hơn, bạn nên ở trong bộ đệm L1 và rất nhanh.

Tôi đã sử dụng phương pháp rất đơn giản này với LCG mà vì lý do di sản mà chúng tôi phải giữ. Về cơ bản, chúng tôi có được tăng tốc tuyến tính lên đến 4-8 luồng trong một máy trạm đa lõi điển hình. Nhưng bây giờ tôi sẽ thử phương pháp từ câu trả lời của Jack Poulson và hy vọng sẽ nhanh hơn nữa :).

OTOH, tôi tin rằng thủ thuật đơn giản này sẽ hiệu quả với các RNG tuần tự vốn có khác.


2

Câu trả lời này là muộn, nhưng bạn nên xem qua XUÂN . Nó được thiết kế đặc biệt cho khả năng mở rộng song song và hỗ trợ một số loại PRNG.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.