这与前一个问题有关:How to partition a single batch into many invocations to save memory,也与How to train a big model with relatively large batch size on a single GPU using Tensorflow?有关;但是,我还是找不到确切的答案 . 例如,另一个相关问题的回答没有被接受,并且没有其他评论 .
我想尝试模拟更大的批量大小,但只使用一个GPU . 因此,我需要为每个较小的批次计算渐变,在几个这样的较小批次中聚合/平均它们,然后才应用 .
(基本上,它就像同步分布式SGD,但在单个设备/ GPU上,串行执行 . 当然,分布式SGD的加速优势会丢失,但更大的批量大小本身可能会使收敛更大的精度和更大的步长,如图所示最近几篇论文 . )
为了保持低内存要求,我应该使用小批量标准SGD,在每次迭代后更新渐变,然后调用 optimizer.apply_gradients()
(其中 optimizer
是已实现的优化器之一) .
所以,一切看起来都很简单但是当我去实现它时,它实际上并非如此微不足道 .
例如,我想使用一个 Graph
,计算每次迭代的渐变,然后,当处理多个批次时,将渐变相加并将它们传递给我的模型 . 但是列表本身无法输入 sess.run
的 feed_dict
参数 . 另外,直接传递渐变并不完全正常,我得到 TypeError: unhashable type: 'numpy.ndarray'
(我认为原因是我无法传递 numpy.ndarray
,只有张量流变量) . 我可以为渐变定义一个占位符,但为此我需要首先构建模型(指定可训练的变量等) .
总而言之,请告诉我有一种更简单的方法来实现它 .
2 回答
您需要将渐变作为传递给
apply_gradients
的值 . 它可以是占位符,但使用通常的compute_gradients
/apply_gradients
组合可能更容易:如果你想在TensorFlow中计算渐变的平均值,那还需要一些专门针对它的额外代码,可能是这样的:
没有比你已经被告知过的更简单的方法了 . 这种方式起初可能看起来很复杂,但它实际上非常简单 . 您只需使用低级API手动计算每个批次的渐变,平均值,然后手动将平均渐变量提供给优化器以应用它们 .
我将尝试提供一些如何执行此操作的精简代码 . 我将使用点作为实际代码的占位符,这取决于问题 . 你通常会做的是这样的事情:
你现在想做什么,将多个批次平均到保存内存将是这样的:
如果你填补空白,这应该是可以运行的 . 但是,我可能在将它剥离并粘贴在这里时犯了一个错误 . 对于一个可运行的例子,你可以看看project我目前正在自己工作 .
我还想明确指出,这与一次评估所有批次数据的损失不同,因为您对梯度进行平均 . 当您的损失不适用于低统计数据时,这一点尤为重要 . 以直方图的卡方为例,计算具有低仓数的直方图的平方梯度将不如仅在一个直方图上计算梯度,并且所有仓一次填满 .