关于同时运行多个tensorflow模型时线程创建失败

Posted silly丶

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于同时运行多个tensorflow模型时线程创建失败相关的知识,希望对你有一定的参考价值。

OpenMP: "libgomp: Thread creation failed: Resource temporarily unavailable" when code run as regular user

这几天在跑代码的时候,因为模型需要调参,方便起见打算同时运行25个程序。但是在使用bash脚本,同时启动25个进程的时候,发现制启动了12个进程。尝试用vscode打开调试模式,刚刚运行起来,就报错

OpenMP: "libgomp: Thread creation failed: Resource temporarily unavailable" when code run as regular user

看意思是线程资源用完了。

运行指令

ulimit -a

发现用户能开的最大线程数量为4096.

运行指令

ps -u <username> -o nlwp --no-headers | awk \' sum += $1  END  print sum \'

返回4010。表示用户已经使用了4010个线程。

运行指令

ps -u <username> -o nlwp,pid,cmd

查看每个进程所占用的具体线程数量。

发现每个跑模型的代码占用了300个线程。如果要25个同时运行,则需要300*25=7500个线程才行。

本人使用的是tensorflow-gpu1.15版本。tensorflow中可以使用tf.ConfigProto()配置Session运行参数

参考tensorflow的API文档 https://www.tensorflow.org/api_docs/python/tf/compat/v1/ConfigProto

其中,ConfigProto有两个属性 inter_op_parallelism_threads intra_op_parallelism_threads 可以调整程序的并行程度。

stack overflow上对这两个属性做出了解释 https://stackoverflow.com/questions/41233635/meaning-of-inter-op-parallelism-threads-and-intra-op-parallelism-threads。

大致意思如下

  1. inter_op_parallelism_threads:该参数用于控制 TensorFlow 操作之间的并行度,即不同操作之间的并发执行。它指定了 TensorFlow 运行时使用的线程数,以便同时运行多个操作。增加此参数的值可以提高 TensorFlow 在执行多个操作时的并行性,从而加快整体的计算速度。
  2. intra_op_parallelism_threads:该参数用于控制 TensorFlow 操作内部的并行度,即单个操作内部的并发执行。它指定了每个操作使用的线程数,以便在操作内部并行地执行子任务。增加此参数的值可以提高 TensorFlow 操作内部并发执行的能力,从而加快单个操作的计算速度。

通常,TensorFlow 会根据系统的线程配置和硬件资源自动确定线程的分配。

所以只要认为设定这连个属性的值,就可以限制每个程序开启的线程数量。

os.environ["CUDA_VISIBLE_DEVICES"] = gpu
gpu_options = tf.GPUOptions(per_process_gpu_memory_fraction=0.05)
config = tf.ConfigProto(
    gpu_options = gpu_options,
    inter_op_parallelism_threads = 8,  # 设置较小的值,将线程分配给不同的程序
    intra_op_parallelism_threads = 30  # 设置较大的值,充分利用单个程序的并发性
)
sess = tf.Session(config=config)

上述代码同时限制了可用的gpu的

TensorFlow/Keras 多线程模型拟合

【中文标题】TensorFlow/Keras 多线程模型拟合【英文标题】:TensorFlow/Keras multi-threaded model fitting 【发布时间】:2017-07-08 10:36:08 【问题描述】:

我正在尝试使用多个线程(和 tensorflow 后端)训练具有不同参数值的多个 keras 模型。我已经看到了一些在多个线程中使用相同模型的示例,但在这种特殊情况下,我遇到了关于冲突图等的各种错误。这是我希望能够做的一个简单示例:

from concurrent.futures import ThreadPoolExecutor
import numpy as np
import tensorflow as tf
from keras import backend as K
from keras.layers import Dense
from keras.models import Sequential


sess = tf.Session()


def example_model(size):
    model = Sequential()
    model.add(Dense(size, input_shape=(5,)))
    model.add(Dense(1))
    model.compile(optimizer='sgd', loss='mse')
    return model


if __name__ == '__main__':
    K.set_session(sess)
    X = np.random.random((10, 5))
    y = np.random.random((10, 1))
    models = [example_model(i) for i in range(5, 10)]

    e = ThreadPoolExecutor(4)
    res_list = [e.submit(model.fit, X, y) for model in models]

    for res in res_list:
        print(res.result())

产生的错误是ValueError: Tensor("Variable:0", shape=(5, 5), dtype=float32_ref) must be from the same graph as Tensor("Variable_2/read:0", shape=(), dtype=float32).。我也尝试过在线程中初始化模型,这会导致类似的失败。

对解决此问题的最佳方法有什么想法吗?我完全不依赖这个确切的结构,但我更喜欢能够使用多个线程而不是进程,因此所有模型都在相同的 GPU 内存分配中进行训练。

【问题讨论】:

【参考方案1】:

Tensorflow Graphs 不是线程安全的(请参阅https://www.tensorflow.org/api_docs/python/tf/Graph),当您创建新的 Tensorflow Session 时,它默认使用默认图。

您可以通过在并行函数中使用新图创建新会话并在那里构建 keras 模型来解决此问题。

这里有一些代码可以在每个可用的 gpu 上并行创建和拟合模型:

import concurrent.futures
import numpy as np

import keras.backend as K
from keras.layers import Dense
from keras.models import Sequential

import tensorflow as tf
from tensorflow.python.client import device_lib

def get_available_gpus():
    local_device_protos = device_lib.list_local_devices()
    return [x.name for x in local_device_protos if x.device_type == 'GPU']

xdata = np.random.randn(100, 8)
ytrue = np.random.randint(0, 2, 100)

def fit(gpu):
    with tf.Session(graph=tf.Graph()) as sess:
        K.set_session(sess)
        with tf.device(gpu):
            model = Sequential()
            model.add(Dense(12, input_dim=8, activation='relu'))
            model.add(Dense(8, activation='relu'))
            model.add(Dense(1, activation='sigmoid'))

            model.compile(loss='binary_crossentropy', optimizer='adam')
            model.fit(xdata, ytrue, verbose=0)

            return model.evaluate(xdata, ytrue, verbose=0)

gpus = get_available_gpus()
with concurrent.futures.ThreadPoolExecutor(len(gpus)) as executor:
    results = [x for x in executor.map(fit, gpus)]
print('results: ', results)

【讨论】:

这解决了我的问题,我有两个模型在一个进程中运行,它总是向我显示 ValueError: Fetch 参数不能被解释为张量。 (Tensor Tensor("input:0", shape=(2, 2), dtype=float32_ref) 不是这个图的元素。) 只是想补充一点,根据模型是否使用没有 GPU 实现的 tensorflow 操作,有时需要在会话中允许软放置。这可以通过 tf.Session(config=tf.ConfigProto(allow_soft_placement=True), graph=tf.Graph()) 来完成更多细节github.com/keras-team/keras/issues/1602#issuecomment-193369220

以上是关于关于同时运行多个tensorflow模型时线程创建失败的主要内容,如果未能解决你的问题,请参考以下文章

TensorFlow 同时调用多个预训练好的模型

关于多线程的名词解释

关于Servlet线程安全的问题

关于JAVA中的static方法并发问题以及JAVA运行时内存模型

关于多个程序同时launch kernels on the same GPU

关于线程安全的例子(电影票出售)