在不同的 GPU 上初始化结构

Initialize struct on different GPUs

我有一个看起来像这样的结构

struct LstmLayer {
  int deviceId;
  thrust::device_vector <real_t> W;
  thrust::device_vector <real_t> gradW;

  LstmLayer() : deviceId(0) {}

  LstmLayer(int __deviceId__) : deviceId(__deviceId__) {}

  void setDevice(int __deviceId__) { deviceId = __deviceId__; }

  void init(bool initParams) {
    W.resize(4*lstmSize * 2*lstmSize);
    gradW.resize(4*lstmSize * 2*lstmSize);

    if (initParams) GPU_Random_Vector(W);
  }
}

现在我想初始化一个 LstmLayer 的数组,每个元素都在不同的 GPU 设备上。我是这样做的

  struct LstmLayer lstmLayers[MAX_NUM_LSTM_LAYERS];

  for (int i = 0; i < numLstmLayers; ++i) {
    CUDA_SAFE_CALL(cudaSetDevice(i));
    lstmLayers[i].setDevice(i);
    lstmLayers[i].init(true);
  }

运行这个程序报错如下

terminate called after throwing an instance of 'thrust::system::system_error'
  what():  driver shutting down

请告诉我我的代码有什么问题以及如何正确处理?先谢谢你了。

问题是您在同一个 CUDA GPU 上下文中实例化所有向量,然后尝试在不同的上下文中使用它们。发生这种情况是因为当您定义结构数组时,每个 device_vector 的默认构造函数都会被调用。注释您的代码:

struct LstmLayer lstmLayers[MAX_NUM_LSTM_LAYERS]; // default constructor for each device vector called here in one GPU context.

for (int i = 0; i < numLstmLayers; ++i) {
    CUDA_SAFE_CALL(cudaSetDevice(i));
    lstmLayers[i].setDevice(i);
    lstmLayers[i].init(true); // Error here, you changed to a different device and called resize
}

解决方案可能是将设备向量重新定义为指针,并在您的 init 方法中显式调用它们的构造函数。有很多不同的方法可以做到这一点,例如:

 struct LstmLayer {
  int deviceId;
  thrust::device_vector <real_t>  * W;
  thrust::device_vector <real_t> * gradW;

  LstmLayer() : deviceId(0) {}

  LstmLayer(int __deviceId__) : deviceId(__deviceId__) {}

  void setDevice(int __deviceId__) { deviceId = __deviceId__; }

  void init(bool initParams) {
    W = new thrust::device_vector<real_t>(4*lstmSize * 2*lstmSize);
    gradW = new thrust::device_vector<real_t>(4*lstmSize * 2*lstmSize);

    if (initParams) GPU_Random_Vector(W);
  }
}

[免责声明:用浏览器编写,从未编译,使用风险自负]

显然你需要定义一个析构函数来防止内存泄漏。还有其他可能性,我将把它留给 reader 作为练习。