我已经训练了3个模型,现在正在运行代码,按顺序加载3个检查点中的每一个并使用它们运行预测。我正在使用GPU。
当加载第一个模型时,它预先分配整个GPU内存(我想要通过第一批数据)。但是当它完成时它不会卸载内存。当加载第二个模型时,同时使用tf.reset_default_graph()
和with tf.Graph().as_default()
,GPU内存仍然会从第一个模型中完全消耗,然后第二个模型将缺乏内存。
有没有办法解决这个问题,除了使用Python子进程或多处理来解决问题(我通过谷歌搜索找到的唯一解决方案)?
答案 0 :(得分:12)
2016年6月发出的git问题(https://github.com/tensorflow/tensorflow/issues/1727)表明存在以下问题:
目前GPUDevice中的Allocator属于ProcessState, 这本质上是一个全球性的单身人士。第一个会话使用GPU 初始化它,并在进程关闭时释放自己。
因此,唯一的解决方法是使用进程并在计算后关闭它们。
示例代码:
import tensorflow as tf
import multiprocessing
import numpy as np
def run_tensorflow():
n_input = 10000
n_classes = 1000
# Create model
def multilayer_perceptron(x, weight):
# Hidden layer with RELU activation
layer_1 = tf.matmul(x, weight)
return layer_1
# Store layers weight & bias
weights = tf.Variable(tf.random_normal([n_input, n_classes]))
x = tf.placeholder("float", [None, n_input])
y = tf.placeholder("float", [None, n_classes])
pred = multilayer_perceptron(x, weights)
cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=pred, labels=y))
optimizer = tf.train.AdamOptimizer(learning_rate=0.001).minimize(cost)
init = tf.global_variables_initializer()
with tf.Session() as sess:
sess.run(init)
for i in range(100):
batch_x = np.random.rand(10, 10000)
batch_y = np.random.rand(10, 1000)
sess.run([optimizer, cost], feed_dict={x: batch_x, y: batch_y})
print "finished doing stuff with tensorflow!"
if __name__ == "__main__":
# option 1: execute code with extra process
p = multiprocessing.Process(target=run_tensorflow)
p.start()
p.join()
# wait until user presses enter key
raw_input()
# option 2: just execute the function
run_tensorflow()
# wait until user presses enter key
raw_input()
因此,如果您在创建的进程中调用函数run_tensorflow()
并关闭进程(选项1),则释放内存。如果只运行run_tensorflow()
(选项2),则在函数调用后不会释放内存。
答案 1 :(得分:7)
您可以使用numba库释放所有gpu内存
pip install numba
from numba import cuda
device = cuda.get_current_device()
device.reset()
这将释放所有内存
答案 2 :(得分:2)
只要不再需要张量(在.run调用终止之前),就会释放由张量分配的GPU内存(回到TensorFlow内存池)。为变量分配的GPU内存在变量容器被销毁时释放。对于DirectSession(即sess = tf.Session(“”)),会话关闭或显式重置(在62c159ff中添加)
答案 3 :(得分:2)
我使用numba释放gpu,使用tensorflow我找不到效果方法。
import tensorflow as tf
from numba import cuda
a = tf.constant([1.0,2.0,3.0],shape=[3],name='a')
b = tf.constant([1.0,2.0,3.0],shape=[3],name='b')
with tf.device('/gpu:1'):
c = a+b
TF_CONFIG = tf.ConfigProto(
gpu_options=tf.GPUOptions(per_process_gpu_memory_fraction=0.1),
allow_soft_placement=True)
sess = tf.Session(config=TF_CONFIG)
sess.run(tf.global_variables_initializer())
i=1
while(i<1000):
i=i+1
print(sess.run(c))
sess.close() # if don't use numba,the gpu can't be released
cuda.select_device(1)
cuda.close()
with tf.device('/gpu:1'):
c = a+b
TF_CONFIG = tf.ConfigProto(
gpu_options=tf.GPUOptions(per_process_gpu_memory_fraction=0.5),
allow_soft_placement=True)
sess = tf.Session(config=TF_CONFIG)
sess.run(tf.global_variables_initializer())
while(1):
print(sess.run(c))
答案 4 :(得分:1)
我正在寻找Jupyter Notebook中哪个选项更好。即使深度学习应用程序完成,Jupyter Notebook也会永久占用GPU内存。通常会引起GPU风扇错误,这是一个令人头疼的问题。在这种情况下,我必须重置nvidia_uvm并定期重新启动linux系统。我总结出以下两个选项可以消除GPU风扇错误的困扰,但想知道哪个更好。
环境:
第一个选项
将以下代码放在单元格的末尾。内核在应用程序运行时完成后立即结束。但这并不优雅。 Juputer将弹出一条消息,提示已死亡的内核。
import os
pid = os.getpid()
!kill -9 $pid
部分选项
以下代码也可以使用Jupyter Notebook结束内核。我不知道numba是否安全。 Nvidia更喜欢“ 0” GPU,它是个人开发人员(而非服务器人员)使用最多的GPU。但是,Neil G和mradul dubey都做出了回应:这使GPU处于不良状态。
from numba import cuda
cuda.select_device(0)
cuda.close()
第二个选项似乎更优雅。有人可以确认哪个是最佳选择吗?
注意:
通过直接执行“ $ python abc.py”在Anaconda环境中自动释放GPU内存并不是这样的问题。但是,有时我需要使用Jyputer Notebook来处理.ipynb应用程序。
答案 5 :(得分:0)
现在似乎有两种方法可以解决迭代训练模型,或者如果您使用将来的多进程池来服务于模型训练,则如果将来完成,池中的进程将不会被杀死。您可以在训练过程中应用两种方法来释放GPU内存,同时希望保留主过程。
这是一个使用multiprocess.Process的辅助函数,它可以打开一个新进程来运行您的python编写的函数和reture值,而不是使用Subprocess,
# open a new process to run function
def process_run(func, *args):
def wrapper_func(queue, *args):
try:
logger.info('run with process id: {}'.format(os.getpid()))
result = func(*args)
error = None
except Exception:
result = None
ex_type, ex_value, tb = sys.exc_info()
error = ex_type, ex_value,''.join(traceback.format_tb(tb))
queue.put((result, error))
def process(*args):
queue = Queue()
p = Process(target = wrapper_func, args = [queue] + list(args))
p.start()
result, error = queue.get()
p.join()
return result, error
result, error = process(*args)
return result, error