如何防止 TensorFlow 分配全部 GPU 内存?
- 2024-12-04 08:56:00
- admin 原创
- 178
问题描述:
我在一个计算资源共享的环境中工作,即我们有几台服务器,每台都配备了几个 Nvidia Titan X GPU。
对于中小型模型,Titan X 的 12 GB 通常足以让 2-3 人在同一 GPU 上同时进行训练。如果模型足够小,以至于单个模型无法充分利用 GPU 的所有计算单元,那么与逐个运行训练过程相比,这实际上可以加快速度。即使在并发访问 GPU 确实减慢了单个训练时间的情况下,让多个用户同时在 GPU 上训练的灵活性仍然很好。
TensorFlow 的问题在于,默认情况下,它在启动时会分配全部可用的 GPU 内存。即使是一个小型的两层神经网络,我也发现 12 GB 的 GPU 内存全部用完了。
如果知道这对于给定的模型来说已经足够了,有没有办法让 TensorFlow 仅分配 4 GB 的 GPU 内存?
解决方案 1:
tf.Session
您可以通过将 atf.GPUOptions
作为可选参数的一部分传递来设置在构造 a 时要分配的 GPU 内存比例config
:
# Assume that you have 12GB of GPU memory and want to allocate ~4GB:
gpu_options = tf.GPUOptions(per_process_gpu_memory_fraction=0.333)
sess = tf.Session(config=tf.ConfigProto(gpu_options=gpu_options))
充当per_process_gpu_memory_fraction
同一台机器上每个 GPU 上进程将使用的 GPU 内存量的硬性上限。目前,此分数统一应用于同一台机器上的所有 GPU;无法针对每个 GPU 设置此分数。
解决方案 2:
config = tf.ConfigProto()
config.gpu_options.allow_growth=True
sess = tf.Session(config=config)
https://github.com/tensorflow/tensorflow/issues/1578
解决方案 3:
对于 TensorFlow 2.0 和 2.1(文档):
import tensorflow as tf
tf.config.gpu.set_per_process_memory_growth(True)
对于 TensorFlow 2.2+(文档):
import tensorflow as tf
gpus = tf.config.experimental.list_physical_devices('GPU')
for gpu in gpus:
tf.config.experimental.set_memory_growth(gpu, True)
文档还列出了更多方法:
将环境变量设置
TF_FORCE_GPU_ALLOW_GROWTH
为true
。用于
tf.config.experimental.set_virtual_device_configuration
设置虚拟 GPU 设备的硬限制。
解决方案 4:
以下是本书的摘录Deep Learning with TensorFlow
在某些情况下,进程最好只分配可用内存的子集,或者只在进程需要时增加内存使用量。TensorFlow在会话上提供了两个配置
allow_growth
选项来控制这一点。第一个选项是尝试仅根据运行时分配分配尽可能多的 GPU 内存的选项,它一开始分配很少的内存,随着会话的运行和需要更多的 GPU 内存,我们会扩展 TensorFlow 进程所需的 GPU 内存区域。
1)允许增长:(更灵活)
config = tf.ConfigProto()
config.gpu_options.allow_growth = True
session = tf.Session(config=config, ...)
第二种方法是选项,它决定了可见 GPU 应分配per_process_gpu_memory_fraction
的内存总量的百分比。注意:无需释放内存,否则释放后甚至会加剧内存碎片化。each
2)分配固定内存:
仅通过以下方式分配40%
每个 GPU 的总内存:
config = tf.ConfigProto()
config.gpu_options.per_process_gpu_memory_fraction = 0.4
session = tf.Session(config=config, ...)
注意:
这仅当您真正想要绑定 TensorFlow 进程上可用的 GPU 内存量时才有用。
解决方案 5:
对于 Tensorflow 版本 2.0 和 2.1,请使用以下代码片段:
import tensorflow as tf
gpu_devices = tf.config.experimental.list_physical_devices('GPU')
tf.config.experimental.set_memory_growth(gpu_devices[0], True)
对于以前的版本,以下代码片段对我有用:
import tensorflow as tf
tf_config=tf.ConfigProto()
tf_config.gpu_options.allow_growth=True
sess = tf.Session(config=tf_config)
解决方案 6:
以上所有答案都假设通过调用执行sess.run()
,这在 TensorFlow 的最新版本中正在成为例外而不是规则。
使用tf.Estimator
框架(TensorFlow 1.4 及更高版本)时,将分数传递给隐式创建的方法MonitoredTrainingSession
是,
opts = tf.GPUOptions(per_process_gpu_memory_fraction=0.333)
conf = tf.ConfigProto(gpu_options=opts)
trainingConfig = tf.estimator.RunConfig(session_config=conf, ...)
tf.estimator.Estimator(model_fn=...,
config=trainingConfig)
同样,在 Eager 模式下(TensorFlow 1.5 及以上版本),
opts = tf.GPUOptions(per_process_gpu_memory_fraction=0.333)
conf = tf.ConfigProto(gpu_options=opts)
tfe.enable_eager_execution(config=conf)
编辑:2018 年 11 月 4 日
例如,如果您要使用tf.contrib.gan.train
,那么您可以使用类似下面的内容:
tf.contrib.gan.gan_train(........, config=conf)
解决方案 7:
您可以使用
TF_FORCE_GPU_ALLOW_GROWTH=true
在你的环境变量中。
在TensorFlow代码中:
bool GPUBFCAllocator::GetAllowGrowthValue(const GPUOptions& gpu_options) {
const char* force_allow_growth_string =
std::getenv("TF_FORCE_GPU_ALLOW_GROWTH");
if (force_allow_growth_string == nullptr) {
return gpu_options.allow_growth();
}
解决方案 8:
Tensorflow 2.0 Beta 版及后续版本
API 再次发生更改。现在可以在以下位置找到:
tf.config.experimental.set_memory_growth(
device,
enable
)
别名:
tf.compat.v1.config.experimental.set_memory_growth
tf.compat.v2.config.experimental.set_memory_growth
参考:
https://www.tensorflow.org/versions/r2.0/api_docs/python/tf/config/experimental/set_memory_growth
https://www.tensorflow.org/guide/gpu#limiting_gpu_memory_growth
另请参阅:
Tensorflow - 使用 GPU:https://www.tensorflow.org/guide/gpu
对于 Tensorflow 2.0 Alpha,请参阅: 此答案
解决方案 9:
所有以上答案均指在版本中将内存设置为一定范围TensorFlow 1.X
或允许内存增长TensorFlow 2.X
。
该方法 tf.config.experimental.set_memory_growth
确实可以在分配/预处理期间允许动态增长。不过,人们可能希望从一开始就分配特定上限的 GPU 内存。
分配特定 GPU 内存背后的逻辑也是为了防止在训练期间出现 OOM 内存。例如,如果在打开占用大量视频内存的 Chrome 标签页/任何其他占用大量视频的进程的同时进行训练,则tf.config.experimental.set_memory_growth(gpu, True)
可能会导致出现 OOM 错误,因此在某些情况下有必要从一开始就分配更多内存。
在 TensorFlow 2.X 中为每个 GPU 分配内存的推荐且正确的方法如下:
gpus = tf.config.experimental.list_physical_devices('GPU')
if gpus:
# Restrict TensorFlow to only allocate 1GB of memory on the first GPU
try:
tf.config.experimental.set_virtual_device_configuration(
gpus[0],
[tf.config.experimental.VirtualDeviceConfiguration(memory_limit=1024)]
解决方案 10:
无耻的插件:如果您安装了支持 GPU 的 Tensorflow,会话将首先分配所有 GPU,无论您将其设置为仅使用 CPU 还是 GPU。我可以补充一点,即使您将图形设置为仅使用 CPU,您也应该设置相同的配置(如上所述:))以防止不必要的 GPU 占用。
在 IPython 和 Jupyter 等交互式界面中,你也应该设置该配置,否则,它将分配所有内存,而几乎不为其他内存留下任何空间。这有时很难注意到。
解决方案 11:
如果您使用 Tensorflow 2,请尝试以下操作:
config = tf.compat.v1.ConfigProto()
config.gpu_options.allow_growth = True
session = tf.compat.v1.Session(config=config)
解决方案 12:
对于Tensorflow 2.0,这个解决方案对我有用。(TF-GPU 2.0、Windows 10、GeForce RTX 2070)
physical_devices = tf.config.experimental.list_physical_devices('GPU')
assert len(physical_devices) > 0, "Not enough GPU hardware devices available"
tf.config.experimental.set_memory_growth(physical_devices[0], True)
解决方案 13:
# allocate 60% of GPU memory
from keras.backend.tensorflow_backend import set_session
import tensorflow as tf
config = tf.ConfigProto()
config.gpu_options.per_process_gpu_memory_fraction = 0.6
set_session(tf.Session(config=config))
解决方案 14:
该代码对我有用:
import tensorflow as tf
config = tf.compat.v1.ConfigProto()
config.gpu_options.allow_growth = True
session = tf.compat.v1.InteractiveSession(config=config)
解决方案 15:
我尝试在 voc 数据集上训练 unet,但由于图像尺寸过大,内存耗尽。我尝试了上述所有技巧,甚至尝试使用 batch size==1,但没有任何改善。有时 TensorFlow 版本也会导致内存问题。尝试使用
pip 安装 tensorflow-gpu==1.8.0
解决方案 16:
好吧,我是 tensorflow 的新手,我有 Geforce 740m 或带有 2GB 内存的 GPU,我正在运行 mnist 手写类型的母语示例,其训练数据包含 38700 张图像和 4300 张测试图像,并尝试使用以下代码获取精度、召回率、F1,因为 sklearn 没有给我精确的结果。一旦我将其添加到我现有的代码中,我就会开始收到 GPU 错误。
TP = tf.count_nonzero(predicted * actual)
TN = tf.count_nonzero((predicted - 1) * (actual - 1))
FP = tf.count_nonzero(predicted * (actual - 1))
FN = tf.count_nonzero((predicted - 1) * actual)
prec = TP / (TP + FP)
recall = TP / (TP + FN)
f1 = 2 * prec * recall / (prec + recall)
另外,我的模型可能太重了,在 147、148 个 epoch 之后出现了内存错误,然后我想为什么不为这些任务创建函数,所以我不知道在 tensrorflow 中它是否以这种方式工作,但我想如果使用局部变量并且超出范围时它可能会释放内存,并且我在模块中定义了上述用于训练和测试的元素,我能够毫无问题地实现 10000 个 epoch,我希望这会有所帮助..