52.4_函数的相应修改

52.4 函数的相应修改

关于DeZero的“GPU化”,剩下的主要任务是修改DeZero的函数。这些具体的函数实际上是在forward方法中进行计算的,比如Sin类,其代码如下所示。

dezero/functions.py

class Sin(Function): def forward(self, x): y = np.sin(x) return y def backward(self, gy): x, = self.inputs gx = gy * cos(x) return gx

代码中def forward(self, x):的参数x应为NumPy的ndarray实例。因此,我们可以对其使用np.sin(x)等NumPy的函数进行计算。如果想在

GPU上运行,参数x应为CuPy的ndarray实例。此时用cp.sin(x)来代替np.sin(x)。换言之,当x是NumPy时必须使用np.sin;当x是CuPy时必须使用cp.sin。基于以上内容,我们将Sin类修改如下。

dezero/functions.py

fromdezeroimport CUDA   
class Sin(Functions): defforward(self,x): xp  $=$  CUDA.get_array_module(x)  $\mathbf{y} = \mathbf{x}\mathbf{p}.\sin (\mathbf{x})$  return y defbackward(self,gy): x,  $=$  selfinputs gx  $=$  gy\*cos(x) returngx

上面的代码通过xp =uda.get_array_module(x)提取x对应的模块。代码中的xp可以是cp,也可以是np。之后使用xp进行计算。现在的Sin类在CPU/GPU(NumPy/CuPy)上都能正确运行。

这里只展示了 Sin 类的代码,但上面的修改需要应用于dezero/functions.py 中所有对应的地方。对应的地方指的是 np.xxX() 这种以 np. 开头的代码。我们要对这些地方执行与上面相同的修改。此外,还要对dezero/optimizers.py 和dezero/layers.py 执行同样的修改。

最后修改DeZero的四则运算的代码。具体来说,就是对dezero/core.py按如下内容进行修改。

dezero/core.py

def as_array(x, array_module=np):
    if np.iscalar(x):
        return array_module.array(x)
    return x
def add(x0, x1):
    x1 = as_array(x1,dezero.cuda.get_array_module(x0.data))
    return Add()(x0, x1)
def mul(x0, x1):
    x1 = as_array(x1,dezero.cuda.get_array_module(x0.data))
    return Mul()(x0, x1)
# 对sub、rsub、div、rdiv进行同样的修改

首先向as_array函数添加新的参数array_module。这个array_module的值为numpy或copy,函数将数据转换为array_module指定的模块的ndarray。然后使用这个新的as_array函数修改add和mul等四则运算函数。在add函数中使用as_array函数,是为了能够运行 x+1x + 1 这样的代码(x是Variable实例)。即使x.data是CuPy数据, x+1x + 1 这样的代码也能正确运行。