python-3.x - 让某种形式的 keras 多处理/线程在 Windows 上工作

标签 python-3.x multithreading keras multiprocessing windows-10

为了加速训练神经网络的数据增强,我正在尝试使用某种形式的并行处理来为我的 GPU 提供数据。目前的限制是我生成增强数据的速度,而不是 GPU 训练网络的速度。

如果我尝试使用 multiprocessing=True使用生成器,我在 Windows 10 (v1083) 64 位下的 Python 3.6.6 中使用 keras 2.2.0 出现以下错误:

ValueError: Using a generator with use_multiprocessing=True is not supported on Windows (no marshalling of generators across process boundaries). Instead, use single thread/process or multithreading.



我发现例如the following在 GitHub 上,因此这是 Windows 下 keras 的预期行为。该链接似乎建议移动到序列而不是生成器(即使错误消息似乎建议使用多线程,但我也无法弄清楚如何将多线程与 keras 一起使用而不是多处理 - 我可能忽略了它在文档中,但我只是没有找到它)。因此,我使用了下面的代码(使用序列修改示例),但这也没有实现加速或在带有 use_multiprocessing=True 的变体中只是卡住。

我是否在这里遗漏了一些关于如何使某种形式的并行生成器运行的明显内容?

最小(非)工作示例:
from keras.utils import Sequence
from keras.models import Sequential
from keras.layers import Dense
from keras.utils import to_categorical
import numpy as np

class DummySequence(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 int(np.ceil(len(self.x) / float(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(batch_x), np.array(batch_y)



x = np.random.random((100, 3))
y = to_categorical(np.random.random(100) > .5).astype(int)

seq = DummySequence(x, y, 10)

model = Sequential()
model.add(Dense(32, input_dim=3))
model.add(Dense(2, activation='softmax'))
model.compile(optimizer='rmsprop',
              loss='categorical_crossentropy',
              metrics=['accuracy'])

print('single worker')
model.fit_generator(generator=seq, 
                    steps_per_epoch = 100,
                    epochs = 2, 
                    verbose=2,
                    workers=1)
print('achieves no speed-up')
model.fit_generator(generator=seq, 
                    steps_per_epoch = 100,
                    epochs = 2, 
                    verbose=2,
                    workers=6,
                    use_multiprocessing=False)
print('Does not run')
model.fit_generator(generator=seq, 
                    steps_per_epoch = 100,
                    epochs = 2, 
                    verbose=2,
                    workers=6,
                    use_multiprocessing=True)

最佳答案

结合序列,使用 multi_processing=False 和 workers=e.g. 4 确实有效。

我刚刚意识到在问题的示例代码中,我没有看到加速,因为数据生成得太快了。通过插入 time.sleep(2) 这变得很明显。

class DummySequence(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 int(np.ceil(len(self.x) / float(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]
    time.sleep(2)
    return np.array(batch_x), np.array(batch_y)

x = np.random.random((100, 3))
y = to_categorical(np.random.random(100) > .5).astype(int)

seq = DummySequence(x, y, 10)

model = Sequential()
model.add(Dense(32, input_dim=3))
model.add(Dense(2, activation='softmax'))
model.compile(optimizer='rmsprop',
              loss='categorical_crossentropy',
              metrics=['accuracy'])

print('single worker')
model.fit_generator(generator=seq, 
                    steps_per_epoch = 10,
                    epochs = 2, 
                    verbose=2,
                    workers=1)

print('achieves speed-up!')
model.fit_generator(generator=seq, 
                    steps_per_epoch = 10,
                    epochs = 2, 
                    verbose=2,
                    workers=4,
                    use_multiprocessing=False)

这在我的笔记本电脑上产生了以下内容:
single worker
>>> model.fit_generator(generator=seq,
...                     steps_per_epoch = 10,
...                     epochs = 2,
...                     verbose=2,
...                     workers=1)
Epoch 1/2
 - 20s - loss: 0.6984 - acc: 0.5000
Epoch 2/2
 - 20s - loss: 0.6955 - acc: 0.5100


achieves speed-up!
>>> model.fit_generator(generator=seq,
...                     steps_per_epoch = 10,
...                     epochs = 2,
...                     verbose=2,
...                     workers=4,
...                     use_multiprocessing=False)
Epoch 1/2
 - 6s - loss: 0.6904 - acc: 0.5200
Epoch 2/2
 - 6s - loss: 0.6900 - acc: 0.5000

重要提示:
您可能需要 self.lock = threading.Lock()__init___然后 with self.lock:__getitem__ .尝试在 with self.lock: 内执行绝对最低要求,据我所知,这将是对 self.xxxx 的任何引用。 (多线程在 with self.lock: 块运行时被阻止)。

此外,如果您希望多线程加速计算(即 CPU 操作是限制),不要指望有任何加速。 global-interpreter lock (GIL) 将阻止这种情况。如果限制在 I/O 操作中,多线程只会帮助你。显然,为了加速 CPU 计算,我们需要真正的多处理,即 keras目前不支持 Windows 10。也许可以手工制作一个多处理生成器(我不知道)。

关于python-3.x - 让某种形式的 keras 多处理/线程在 Windows 上工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51672747/

相关文章:

python - 我是否需要创建一个类实例以使用 unittest 进行测试?

python - Ansible 无法通过 pipelinenv 安装依赖项

python - 在python中按天对时间戳字符串进行分组

c++ - 在 Windows 中更改 boost 线程优先级

java - 客户端服务器程序的多线程

python - Keras 在预测时加载神经网络的权重/错误

python-3.x - xml.etree.ElementTree >> Python >> 如何访问子元素并进行断言

c++ - 需要帮助解决 NXP Linux 上的 std::thread::join() 问题

tensorflow - Keras 模型到 tensorflow

python - 喀拉斯 : training with an array as an input