Во время моего исследования я нашел информацию, отвечающую на мои вопросы.
1. Издает ли Keras это предупреждение только потому, что генератор не наследует последовательности, илиKeras также проверяет, является ли генератор в целом безопасным для потоков?
Взято из gitRepo Keras ( training_generators.py ) Я обнаружил в строках 46-52
следующее:
use_sequence_api = is_sequence(generator)
if not use_sequence_api and use_multiprocessing and workers > 1:
warnings.warn(
UserWarning('Using a generator with `use_multiprocessing=True`'
' and multiple workers may duplicate your data.'
' Please consider using the `keras.utils.Sequence'
' class.'))
Определение is_sequence()
взято из training_utils.py в строках 624-635
:
def is_sequence(seq):
"""Determine if an object follows the Sequence API.
# Arguments
seq: a possible Sequence object
# Returns
boolean, whether the object follows the Sequence API.
"""
# TODO Dref360: Decide which pattern to follow. First needs a new TF Version.
return (getattr(seq, 'use_sequence_api', False)
or set(dir(Sequence())).issubset(set(dir(seq) + ['use_sequence_api'])))
Раггинг этого фрагмента кода Keras проверяет только, прошел ли генераторявляется последовательностью Keras (или, скорее, использует API последовательности Keras) и не проверяет, является ли генератор вообще безопасным для потоков.
2. Использует ли я подход, который я выбрал как потокобезопасный, как использование generatorClass (Sequence) -version из Keras-docs ?
Как Омер Зохар показал на gitHub его декоратор безопасен для потоков - не вижу причинпочему он не должен быть настолько безопасным для Keras (даже если Keras будет предупреждать, как показано в 1.).Реализация thread.Lock()
может считаться поточно-безопасной в соответствии с документами :
Заводской функцией, которая возвращает новый объект блокировки примитива. Как только поток получил его, последующие попытки получить его блокируют, пока он не будет освобожден ;любой поток может освободить его.
Генератор также можно отцепить, что можно проверить, как (см. эту SO-Q & A здесь для получения дополнительной информации):
#Dump yielded data in order to check if picklable
with open("test.pickle", "wb") as outfile:
for yielded_data in generator(data):
pickle.dump(yielded_data, outfile, protocol=pickle.HIGHEST_PROTOCOL)
Продолжая это, я бы даже предложил реализовать thread.Lock()
при расширении Keras 'Sequence()
, например:
import threading
class generatorClass(Sequence):
def __init__(self, x_set, y_set, batch_size):
self.x, self.y = x_set, y_set
self.batch_size = batch_size
self.lock = threading.Lock() #Set self.lock
def __len__(self):
return int(np.ceil(len(self.x) / float(self.batch_size)))
def __getitem__(self, idx):
with self.lock: #Use self.lock
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 ...
3. Существуют ли какие-либо другие подходы, ведущие к созданию потоково-безопасного генератора, с которыми Keras может иметь дело, которые отличаются от этих двух примеров?
Во время моего исследования я не встречал никакого другого метода.Конечно, я не могу сказать это со 100% уверенностью.