gpt4 book ai didi

python - Keras/Tensorflow中的类生成器(继承序列)线程安全吗?

转载 作者:行者123 更新时间:2023-12-04 19:27:10 29 4
gpt4 key购买 nike

为了使模型的训练更快,在CPU上填充/生成批次并在GPU上并行运行模型的训练似乎是一个好习惯。为此,可以使用Python编写一个生成器类,该类继承Sequence类。

这是文档的链接:
https://www.tensorflow.org/api_docs/python/tf/keras/utils/Sequence

该文档指出的重要内容是:

Sequence are a safer way to do multiprocessing. This structure guarantees that the network will only train once on each sample per epoch which is not the case with generators.



它给出了一个简单的代码示例,如下所示:
from skimage.io import imread
from skimage.transform import resize
import numpy as np
import math

# Here, `x_set` is list of path to the images
# and `y_set` are the associated classes.

class CIFAR10Sequence(Sequence):

def __init__(self, x_set, y_set, batch_size):
self.x, self.y = x_set, y_set
self.batch_size = batch_size

def __len__(self):
return math.ceil(len(self.x) / self.batch_size)

def __getitem__(self, idx):
batch_x = self.x[idx * self.batch_size:(idx + 1) *
self.batch_size]
batch_y = self.y[idx * self.batch_size:(idx + 1) *
self.batch_size]

return np.array([
resize(imread(file_name), (200, 200))
for file_name in batch_x]), np.array(batch_y)

据我所知,在模型中理想地要做的是创建此生成器类的实例并将其提供给 fit_generator(...)函数。
gen = CIFAR10Sequence(x_set, y_set, batch_size)
# Train the model
model.fit_generator(generator=gen,
use_multiprocessing=True,
workers=6)

这是Keras文档的报价:

The use of keras.utils.Sequence guarantees the ordering and guarantees the single use of every input per epoch when using use_multiprocessing=True.



在这种情况下,我假设此设置是线程安全的。
问题1)我的假设正确吗?

但是,一件令人困惑的事情是,在Windows 10上,参数 use_multiprocessing可能未设置为True。似乎只能在Linux上将其设置为True。 (我不知道在其他平台上情况如何。)但是 workers参数仍然可以设置为大于0的值。

让我们看一下这两个参数的定义:

workers: Integer. Maximum number of processes to spin up when using process-based threading. If unspecified, workers will default to 1. If 0, will execute the generator on the main thread.

use_multiprocessing: Boolean. If True, use process-based threading. If unspecified, use_multiprocessing will default to False. Note that because this implementation relies on multiprocessing, you should not pass non-picklable arguments to the generator as they can't be passed easily to children processes.



因此,通过使用 workers参数,似乎可以创建多个进程来独立于 use_multiprocessing是否为True来加快训练速度。

如果要使用继承 Sequence的生成器类(在Windows 10上为 ),则必须将 use_multiprocessing设置为False,如下所示:
gen = CIFAR10Sequence(x_set, y_set, batch_size)
# Train the model
model.fit_generator(generator=gen,
use_multiprocessing=False, # CHANGED
workers=6)

而且这里仍然有多个进程在运行,因为worker = 6。

问题2)use_multiprocessing参数设置为False之后,此设置是否仍然是线程安全的,或者线程安全特性现在丢失了吗?根据文档,我无法明确说明。

问题3)仍与此主题相关...当以这种方式进行训练(CPU生成数据并在GPU上进行训练)时,如果所训练的模型较浅,则GPU利用率最终会非常低并且GPU利用率不断提高,因为GPU一直在等待来自CPU的数据。在这种情况下,是否有办法利用一些GPU资源进行数据生成?

最佳答案

在看过这篇文章的人中,似乎没有人给出最终答案,因此我想给出对我有用的答案。由于该领域缺乏文档,我的答案可能缺少一些相关细节。请随时添加我在这里没有提及的更多信息。

看来,在 Windows 中不支持使用Python编写继承Sequence类的生成器类。 (您似乎可以使其在Linux上运行。)要使其运行,您需要设置参数use_multiprocessing=True(使用类方法)。但是如上所述,它在Windows上不起作用,因此您必须将use_multiprocessing设置为False(在Windows上)。
但是,这并不意味着多重处理在Windows上不起作用。即使您设置了use_multiprocessing=False,使用以下设置运行代码时仍可以支持多处理,您只需将workers参数设置为任何大于1的值即可。

例子:

history = \
merged_model.fit_generator(generator=train_generator,
steps_per_epoch=trainset_steps_per_epoch,
epochs=300,
verbose=1,
use_multiprocessing=False,
workers=3,
max_queue_size=4)

在这一点上,让我们再次记住Keras文档:

The use of keras.utils.Sequence guarantees the ordering and guarantees the single use of every input per epoch when using use_multiprocessing=True.



据我了解,如果是 use_multiprocessing=False,则生成器不再是线程安全的,这使得编写继承 Sequence生成器类变得很困难。

为了解决这个问题,我自己编写了一个生成器,该生成器手动使线程安全。这是一个示例伪代码:
import tensorflow as tf
import threading

class threadsafe_iter:
"""Takes an iterator/generator and makes it thread-safe by
serializing call to the `next` method of given iterator/generator.
"""
def __init__(self, it):
self.it = it
self.lock = threading.Lock()

def __iter__(self):
return self

def __next__(self): # Py3
return next(self.it)

#def next(self): # Python2 only
# with self.lock:
# return self.it.next()

def threadsafe_generator(f):
"""A decorator that takes a generator function and makes it thread-safe.
"""
def g(*a, **kw):
return threadsafe_iter(f(*a, **kw))
return g


@threadsafe_generator
def generate_data(tfrecord_file_path_list, ...):

dataset = tf.data.TFRecordDataset(tfrecord_file_path_list)

# example proto decode
def _parse_function(example_proto):
...
return batch_data

# Parse the record into tensors.
dataset = dataset.map(_parse_function)

dataset = dataset.shuffle(buffer_size=100000)

# Repeat the input indefinitly
dataset = dataset.repeat()

# Generate batches
dataset = dataset.batch(batch_size)

# Create an initializable iterator
iterator = dataset.make_initializable_iterator()

# Get batch data
batch_data = iterator.get_next()

iterator_init_op = iterator.make_initializer(dataset)

with tf.Session() as sess:

sess.run(iterator_init_op)

while True:
try:
batch_data = sess.run(batch_data)
except tf.errors.OutOfRangeError:
break
yield batch_data

好吧,可以这样进行讨论是否真的很优雅,但似乎工作得很好。

总结一下:
  • 如果在Windows上编写程序,请将use_multiprocessing设置为False
  • (据我所知,截至目前),在Windows上编写代码时,不支持编写继承Sequence的生成器类。 (我猜这是一个Tensorflow/Keras问题)。
  • 要解决此问题,请编写一个普通的生成器,使生成器线程安全,然后将workers设置为大于1的数字。

  • 重要说明:在此设置中,生成器在CPU上运行,而训练在GPU上完成。我可以观察到的一个问题是,如果您正在训练的模型足够浅,则GPU的利用率仍然很低,而CPU利用率却很高。如果模型很浅并且数据集足够小,那么将所有数据存储在内存中并在GPU上运行所有数据可能是一个不错的选择。它应该大大加快培训的速度。如果出于任何原因想要同时使用CPU和GPU,我的建议是尝试使用Tensorflow的tf.data API,该API可显着加快数据预处理和批处理的速度。如果生成器仅使用Python编写,则GPU会一直等待数据以继续进行训练。可以说有关Tensorflow/Keras文档的所有内容,但这确实是高效的代码!

    如果您对API有更全面的了解,并且看到这篇文章,请随时在这里纠正我,以防万一我误解了任何内容,或者更新了API以解决问题,甚至在Windows上也是如此。

    关于python - Keras/Tensorflow中的类生成器(继承序列)线程安全吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52932406/

    29 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com