微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何使用 GPU.js 运行此函数?

如何解决如何使用 GPU.js 运行此函数?

我想在 GPU 上运行这个排列函数

function* permute(permutation) {
  var length = permutation.length;
  var c = Array(length).fill(0);
  var i = 1;
  var k;
  var p;

  yield permutation.slice();
  while (i < length) {
    if (c[i] < i) {
      k = i % 2 && c[i];
      p = permutation[i];
      permutation[i] = permutation[k];
      permutation[k] = p;
      ++c[i];
      i = 1;
      yield permutation.slice();
    } else {
      c[i] = 0;
      ++i;
    }
  }
}

为了在 GPU 上运行它,我尝试使用 https://gpu.rocks/,但我不明白他们关于如何设置线程的示例。我应该如何编写这个排列函数,以便我可以在 GPU 上的浏览​​器中运行它?

解决方法

GPU.js 只支持少数操作,因为它被转换为着色器。在此处的测试中,您不能使用它来生成超过 100k 个元素的输出。

operations supported 非常有限,例如不能分配给数组元素,这是由于底层计算单元的性质。您还必须注意 branch divergence

需要两个步骤才能以可在内核中使用的方式实现您的函数。

  1. 使其并行:您的实现是迭代的,每次迭代都会根据前一次迭代的结果构建一个新结果。我创建的是一个函数,它给定迭代次数 J 可以产生一个排列。
  2. 使其成为标量且不修改数组:计算排列的函数交换数组上的元素,因此需要分配给数组元素。为了防止我创建的是一个循环,我在其中跟踪每个元素的位置。如果给定元素在位置 I 结束,则返回该元素。请注意,必须为每个排列中的每个元素调用一次此函数。

const gpu = new GPU();
// For reference
// This is the function to compute the J'th permutation
// of N elements. Rewrited to create the kernel.
function permutation(J,N) {
  const arr = []
  for(let i = 0; i < N; ++i)arr[i] = i;
  let j = J;
  for(let i = 2; i <= N; ++i){
    let e1 = j % i;
    const t = arr[e1];
    arr[e1] = arr[i-1];
    arr[i-1] = t;
    j = (j - e1) / i;
  }
  return arr;
}

function permuteAt() {
  const N = this.constants.length;
  let I = N - this.thread.x - 1;
  let J = this.thread.y;
  
  for(let d = 0; d < N; ++d){
    // check if the I'th element of the J'th permutation is d
    let dPos = d;
    let j = J;
    let i = 0;
    for(let i = 2; i <= N; ++i){
      let e1 = j % i;
      let e2 = i - 1;
      // track the movements element d
      if(e1 == dPos){
        dPos = e2;
      }else if(e2 == dPos){
        dPos = e1;
      }
      j = (j - e1) / i;
    }
    // element d ended at position i
    // console.log(JSON.stringify({dPos,I,J,N,t: this.thread}))
    if(dPos == I){
      return d;
    }
  }
  return -1;
}

// Run it in javascript
let result;
const t0Js = Date.now()
for(let i = 0; i < 1000; ++i){
  result = [0,1,2,3,4,5,6,7,8,9].map(v => permuteAt.apply({
  thread: {x: i,y: v},constants: {length: 10}
  }))
}
const tfJs = Date.now();
console.log('time spend in javascript: ',(tfJs - t0Js)/10000);

const generatePermutations = gpu.createKernel(permuteAt).setOutput([10,10000]).setConstants({length: 10});

const t0GPU = Date.now()
for(let i = 0; i < 100; ++i){
  const c = generatePermutations();
}
const tfGPU = Date.now();
console.log('time spend in gpu: ',(tfGPU - t0GPU)/10000/100);
<script src="https://unpkg.com/gpu.js@latest/dist/gpu-browser.min.js"></script>

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。