2011-09-30 19 views
5

Xin chào Tôi có vòng lặp này trong C + và tôi đang cố chuyển đổi nó thành lực đẩy nhưng không nhận được kết quả tương tự ... Bất kỳ ý tưởng nào? cảm ơn bạnChuyển đổi phức tạp lực đẩy của 3 vectơ kích thước khác nhau

C++ Mã

for (i=0;i<n;i++) 
    for (j=0;j<n;j++) 
     values[i]=values[i]+(binv[i*n+j]*d[j]); 

Thrust Mã

thrust::fill(values.begin(), values.end(), 0); 
thrust::transform(make_zip_iterator(make_tuple(
       thrust::make_permutation_iterator(values.begin(), thrust::make_transform_iterator(thrust::make_counting_iterator(0), IndexDivFunctor(n))), 
       binv.begin(), 
       thrust::make_permutation_iterator(d.begin(), thrust::make_transform_iterator(thrust::make_counting_iterator(0), IndexModFunctor(n))))), 
       make_zip_iterator(make_tuple(
       thrust::make_permutation_iterator(values.begin(), thrust::make_transform_iterator(thrust::make_counting_iterator(0), IndexDivFunctor(n))) + n, 
       binv.end(), 
       thrust::make_permutation_iterator(d.begin(), thrust::make_transform_iterator(thrust::make_counting_iterator(0), IndexModFunctor(n))) + n)), 
       thrust::make_permutation_iterator(values.begin(), thrust::make_transform_iterator(thrust::make_counting_iterator(0), IndexDivFunctor(n))), 
       function1() 
       ); 

Thrust Chức năng

struct IndexDivFunctor: thrust::unary_function<int, int> 
{ 
    int n; 

    IndexDivFunctor(int n_) : n(n_) {} 

    __host__ __device__ 
    int operator()(int idx) 
    { 
    return idx/n; 
    } 
}; 

struct IndexModFunctor: thrust::unary_function<int, int> 
{ 
    int n; 

    IndexModFunctor(int n_) : n(n_) {} 

    __host__ __device__ 
    int operator()(int idx) 
    { 
    return idx % n; 
    } 
}; 


struct function1 
{ 
    template <typename Tuple> 
    __host__ __device__ 
    double operator()(Tuple v) 
    { 
    return thrust::get<0>(v) + thrust::get<1>(v) * thrust::get<2>(v); 
    } 
}; 

Trả lời

4

Để bắt đầu, một số ý kiến ​​chung. vòng lặp của bạn

for (i=0;i<n;i++) 
    for (j=0;j<n;j++) 
     v[i]=v[i]+(B[i*n+j]*d[j]); 

là tương đương với tiêu chuẩn BLAS gemv hoạt động

enter image description here

nơi ma trận được lưu trữ trong hàng thứ tự lớn. Cách tối ưu để làm điều này trên thiết bị sẽ sử dụng CUBLAS, không phải thứ gì đó được xây dựng từ các nguyên thủy đẩy.

Có nói rằng, hoàn toàn không có cách nào mã lực đẩy bạn đăng sẽ bao giờ làm những gì mã nối tiếp của bạn thực hiện. Các lỗi bạn đang nhìn thấy không phải là kết quả của sự liên kết dấu chấm động. Về cơ bản, thrust::transform áp dụng hàm functor được cung cấp cho mọi phần tử của trình lặp đầu vào và lưu trữ kết quả trên trình vòng lặp đầu ra. Để mang lại kết quả tương tự như vòng kết nối bạn đã đăng, cuộc gọi thrust::transform sẽ cần thực hiện các thao tác (n * n) của hàm fmad functor mà bạn đã đăng. Rõ ràng là không. Hơn nữa, không có gì đảm bảo rằng thrust::transform sẽ thực hiện thao tác tổng hợp/giảm theo kiểu thời trang sẽ an toàn khỏi các cuộc đua bộ nhớ.

Các giải pháp đúng có lẽ sẽ trở thành một cái gì đó như:

  1. Sử dụng lực đẩy :: transform để tính toán (n * n) Các sản phẩm của các yếu tố của Bd
  2. Sử dụng lực đẩy :: reduce_by_key để giảm các sản phẩm thành một phần tiền, năng suất Bd
  3. Sử dụng lực đẩy :: chuyển đổi để thêm kết quả ma trận-vector sản phẩm để v để mang lại kết quả cuối cùng.

Trong mã, trước hết xác định một functor như thế này:

struct functor 
{ 
    template <typename Tuple> 
    __host__ __device__ 
    double operator()(Tuple v) 
    { 
    return thrust::get<0>(v) * thrust::get<1>(v); 
    } 
}; 

Sau đó làm như sau để tính toán các phép nhân ma trận vector

typedef thrust::device_vector<int> iVec; 
    typedef thrust::device_vector<double> dVec; 

    typedef thrust::counting_iterator<int> countIt; 
    typedef thrust::transform_iterator<IndexDivFunctor, countIt> columnIt; 
    typedef thrust::transform_iterator<IndexModFunctor, countIt> rowIt; 

    // Assuming the following allocations on the device 
    dVec B(n*n), v(n), d(n); 

    // transformation iterators mapping to vector rows and columns 
    columnIt cv_begin = thrust::make_transform_iterator(thrust::make_counting_iterator(0), IndexDivFunctor(n)); 
    columnIt cv_end = cv_begin + (n*n); 

    rowIt rv_begin = thrust::make_transform_iterator(thrust::make_counting_iterator(0), IndexModFunctor(n)); 
    rowIt rv_end = rv_begin + (n*n); 

    dVec temp(n*n); 
    thrust::transform(make_zip_iterator(
         make_tuple(
         B.begin(), 
         thrust::make_permutation_iterator(d.begin(),rv_begin))), 
        make_zip_iterator(
         make_tuple(
         B.end(), 
         thrust::make_permutation_iterator(d.end(),rv_end))), 
        temp.begin(), 
        functor()); 

    iVec outkey(n); 
    dVec Bd(n); 
    thrust::reduce_by_key(cv_begin, cv_end, temp.begin(), outkey.begin(), Bd.begin()); 
    thrust::transform(v.begin(), v.end(), Bd.begin(), v.begin(), thrust::plus<double>()); 

Tất nhiên, đây là một cách khủng khiếp không hiệu quả để thực hiện tính toán so với việc sử dụng mã nhân ma trận vector được thiết kế mục đích như dgemv từ CUBLAS.

0

Kết quả của bạn khác nhau bao nhiêu? Nó có phải là một câu trả lời hoàn toàn khác, hay chỉ khác với các chữ số cuối cùng? Vòng lặp có được thực hiện một lần hay là một loại quá trình lặp?

Hoạt động điểm nổi, đặc biệt là các hoạt động bổ sung hoặc nhân lên một số giá trị nhất định, là không phải là liên kết, do các vấn đề về độ chính xác. Hơn nữa, nếu bạn sử dụng tối ưu hóa toán học nhanh, các hoạt động có thể không phải là bộ biên dịch IEEE.

Đối với người mới bắt đầu, hãy kiểm tra phần wikipedia này trên các số dấu chấm động: http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems

+0

Cảm ơn câu trả lời của bạn. Nhưng vấn đề không phải là với các điểm nổi của nó hoàn toàn khác nhau mặc dù tôi chỉ chạy nó một lần. Tại sao bạn nghĩ quyền của nó? –

+0

Tôi đổ lỗi cho sự chính xác, bởi vì - theo kinh nghiệm của tôi - đây là nguồn khác biệt phổ biến nhất. Tất nhiên, trừ khi có một số lỗi đơn giản, mà tôi không thấy trong mã của bạn. Làm thế nào để bạn biết chắc chắn, vấn đề là không có? Sự khác biệt lớn đến mức nào? Loại GPU bạn đang chạy trên đó? – CygnusX1

+0

Tôi đang chạy trên một gtx 460 với vòm 20 và các vectơ được nhân đôi. nó có thể là các vector giá trị viết cho chính nó? –

Các vấn đề liên quan