如何在多个 GPU 上 运行 classify_image?

How to run classify_image on multiple GPU?

我想 运行 使用多个 GPU 对图像进行矢量化(目前我的脚本只使用一个 GPU)。我有一个图像、图表和会话列表。脚本的输出是保存的向量。我的机器有 3 个 NVIDIA GPU。环境:Ubuntu、python 3.7、Tensorflow 2.0(支持 GPU)。 这是我的代码示例(初始化会话):

def load_graph(frozen_graph_filename):
     # We load the protobuf file from the disk and parse it to retrieve the
     # unserialized graph_def
     with tf.io.gfile.GFile(frozen_graph_filename, "rb") as f:
         graph_def = tf.compat.v1.GraphDef()
         graph_def.ParseFromString(f.read())
     # Then, we import the graph_def into a new Graph and returns it
     with tf.Graph().as_default() as graph:
         # The name var will prefix every op/nodes in your graph
         # Since we load everything in a new graph, this is not needed
         tf.import_graph_def(graph_def, name="")
     return graph

GRAPH = load_graph(os.path.join(settings.IMAGENET_PATH['PATH'], 'classify_image_graph_def.pb'))
config = tf.compat.v1.ConfigProto()
config.gpu_options.per_process_gpu_memory_fraction = 0.9
config.gpu_options.allow_growth = True
SESSION = tf.compat.v1.Session(graph=GRAPH, config=config)

之后,我将 运行 矢量化称为:

sess = SESSION
for image_index, image in enumerate(image_list):
    with Image.open(image) as f:
        image_data = f.convert('RGB')
        feature_tensor = POOL_TENSOR
        feature_set = sess.run(feature_tensor, {'DecodeJpeg:0': image_data})
        feature_vector = np.squeeze(feature_set)
        outfile_name = os.path.basename(image) + ".vc"
        this_is_path = settings.VECTORS_DIR_PATH['PATH']
        out_path = os.path.join(this_is_path, outfile_name)
        np.savetxt(out_path, feature_vector, delimiter=',')

这个工作示例 运行s 在第一个 GPU 100 向量上用了 29 秒。 因此,我在多个 GPU 上尝试从 Tensorflow 文档 this distributed training method 到 运行:

mirorred_strategy = tf.distribute.MirorredStrategy()
with mirorred_strategy.scope():
    sess = SESSION
    # and here all the code from previous example after session:
    for image_index, image in enumerate(image_list):
        with Image.open(image) as f:
            image_data = f.convert('RGB')
            feature_tensor = POOL_TENSOR
            feature_set = sess.run(feature_tensor, {'DecodeJpeg:0': image_data})
            feature_vector = np.squeeze(feature_set)
            outfile_name = os.path.basename(image) + ".vc"
            this_is_path = settings.VECTORS_DIR_PATH['PATH']
            out_path = os.path.join(this_is_path, outfile_name)
            np.savetxt(out_path, feature_vector, delimiter=',')

查看日志后,我可以断定 Tensorflow 可以访问所有三个 GPU。然而,这并没有改变任何东西:当 运行ning 时,Tensorflow 仍然只使用第一个 GPU(29 秒内 100 个向量)。 我尝试的另一种方法是我手动将每个项目设置为具体的 GPU 实例:

sess = SESSION
for image_index, image in enumerate(image_list):
    if image_index % 2 == 0:
        device_name = '/gpu:1'
    elif image_index % 3 == 0:
        device_name = '/gpu:2'
    else:
        device_name = '/gpu:0'
    with tf.device(device_name):
        with Image.open(image) as f:
            image_data = f.convert('RGB')
            feature_tensor = POOL_TENSOR
            feature_set = sess.run(feature_tensor, {'DecodeJpeg:0': image_data})
            feature_vector = np.squeeze(feature_set)
            outfile_name = os.path.basename(image) + ".vc"
            this_is_path = settings.VECTORS_DIR_PATH['PATH']
            out_path = os.path.join(this_is_path, outfile_name)
            np.savetxt(out_path, feature_vector, delimiter=',')

监控此方法我观察到每个 GPU 都在使用,但没有看到性能加速,因为 Tensorflow 正在从一个 GPU 设备切换到另一个。因此,第一项 GPU:0 将被使用并且 GPU:1GPU:2 正在等待,第二项 GPU:1 将起作用并且 GPU:0GPU:2 将等待。 我还尝试了 tf docs - without any changes. Also tried to define tf.Session() inside the for loop - without success. And found this 的另一种 Tensorflow 策略 - 但无法使其适用于我的代码。

我的问题是:

1) 是否有办法修改 tf.distribute.MirorredStrategy() 让 Tensorflow 使用所有三个 GPU?

2) 如果 (1) 的答案不是,我如何 运行 使用所有 GPU 能力进行矢量化(也许这里存在用于执行此操作或其他操作的异步方式)?

您的 mirorred_strategy(来自第三个代码片段)没有使用所有 GPU 的原因是您的模型输入是手动给出的(使用 TF1 样式 feature_tensor 张量)而 TensorFlow 没有如果你不知道如何自动将数据平均分配给你的 GPU,你可以看看文档 here

第四个片段(最后一个)也失败了,因为你使用它的方式不正确,你可以尝试先构建你的模型图,然后 运行 会话中的图,但不要把它们在一起,您可以尝试将 feature_set = sess.run(feature_tensor, {'DecodeJpeg:0': image_data}) 移到 for 循环之外。指南 here 可能会说明得更好一些。