Gluon代码在GPU上的速度不比在CPU上快多少

时间:2019-04-04 12:44:14

标签: mxnet

我们正在三胞胎上训练推荐系统的网络。 fit方法的核心代码如下:

for e in range(epochs):
    start = time.time()

    cumulative_loss = 0

    for i, batch in enumerate(train_iterator):
        # Forward + backward.
        with autograd.record():
            output = self.model(batch.data[0])
            loss = loss_fn(output, batch.label[0])

        # Calculate gradients
        loss.backward()
        # Update parameters of the network.
        trainer_fn.step(batch_size)
        # Calculate training metrics. Sum losses of every batch.
        cumulative_loss += nd.mean(loss).asscalar()
    train_iterator.reset()

其中train_iterator是自mx.io.DataIter继承的自定义迭代器类,并在适当的上下文中已返回数据(三元组),如下所示:

        data = [mx.nd.array(data[:, :-1], self.ctx, dtype=np.int)]
        labels = [mx.nd.array(data[:, -1], self.ctx)]
        return mx.io.DataBatch(data, labels)
在运行self.model.initialize(ctx=mx.gpu(0))方法之前还调用了

fitloss_fn = gluon.loss.L1Loss()

问题在于nvidia-smi报告该进程已正确分配到GPU中。但是,在GPU中运行fit的速度并不比在CPU中运行速度快多少。此外,将batch_size从50000增加到500000,每批处理时间增加了10倍(考虑到GPU并行化,这不是我所期望的)。

具体来说,对于50k批次: * output = self.model(batch.data[0])在GPU上花费0.03秒,在CPU上花费0.08秒。 * loss.backward()耗时0.11秒,在CPU上耗时0.39。

都用nd.waitall()进行了评估,以避免异步调用导致错误的测量结果。

此外,在普通MXNet上运行的非常相似的代码所用的相应部分用时不到0.03秒,这导致完整的时期从MXNet稍稍超过一分钟到Gluon长达15分钟。

关于这里可能发生什么的任何想法?

谢谢!

1 个答案:

答案 0 :(得分:1)

问题在以下几行:

cumulative_loss += nd.mean(loss).asscalar()

调用asscalar()时,MXNet必须隐式进行同步调用才能将结果从GPU复制到CPU:本质上与调用nd.waitall()相同。由于您是在每次迭代中都这样做,因此它将在每次迭代中进行同步,从而大大降低了挂钟时间。

您可以做的是将cumulative_loss保存在GPU中并进行更新,仅在实际需要显示时才将其复制到CPU中-可以是每N次迭代或在实际完成之后,具体取决于如何每次迭代都需要很长时间。