【问题标题】:Keras not using multiple coresKeras 不使用多核
【发布时间】:2016-08-22 21:09:56
【问题描述】:

基于著名的check_blas.py 脚本,我写了这个来检查theano实际上是否可以使用多个内核:

import os
os.environ['MKL_NUM_THREADS'] = '8'
os.environ['GOTO_NUM_THREADS'] = '8'
os.environ['OMP_NUM_THREADS'] = '8'
os.environ['THEANO_FLAGS'] = 'device=cpu,blas.ldflags=-lblas -lgfortran'

import numpy
import theano
import theano.tensor as T

M=2000
N=2000
K=2000
iters=100
order='C'

a = theano.shared(numpy.ones((M, N), dtype=theano.config.floatX, order=order))
b = theano.shared(numpy.ones((N, K), dtype=theano.config.floatX, order=order))
c = theano.shared(numpy.ones((M, K), dtype=theano.config.floatX, order=order))
f = theano.function([], updates=[(c, 0.4 * c + .8 * T.dot(a, b))])

for i in range(iters):
    f(y)

python3 check_theano.py 运行它表明正在使用 8 个线程。更重要的是,该代码的运行速度比没有 os.environ 设置的情况快大约 9 倍,后者仅应用 1 个内核:7.863 秒 vs 71.292 秒一次运行。

所以,我希望 Keras 现在在调用 fit(或 predict)时也使用多个内核。但是,以下代码并非如此:

import os
os.environ['MKL_NUM_THREADS'] = '8'
os.environ['GOTO_NUM_THREADS'] = '8'
os.environ['OMP_NUM_THREADS'] = '8'
os.environ['THEANO_FLAGS'] = 'device=cpu,blas.ldflags=-lblas -lgfortran'

import numpy
from keras.models import Sequential
from keras.layers import Dense

coeffs = numpy.random.randn(100)

x = numpy.random.randn(100000, 100);
y = numpy.dot(x, coeffs) + numpy.random.randn(100000) * 0.01

model = Sequential()
model.add(Dense(20, input_shape=(100,)))
model.add(Dense(1, input_shape=(20,)))
model.compile(optimizer='rmsprop', loss='categorical_crossentropy')

model.fit(x, y, verbose=0, nb_epoch=10)

此脚本仅使用 1 个内核和此输出:

Using Theano backend.
/home/herbert/venv3/lib/python3.4/site-packages/theano/tensor/signal/downsample.py:5: UserWarning: downsample module has been moved to the pool module.
warnings.warn("downsample module has been moved to the pool module.")

为什么 Keras 的 fit 只使用 1 个内核进行相同的设置? check_blas.py 脚本是否真的代表神经网络训练计算?

仅供参考:

(venv3)herbert@machine:~/ $ python3 -c 'import numpy, theano, keras; print(numpy.__version__); print(theano.__version__); print(keras.__version__);'
ERROR (theano.sandbox.cuda): nvcc compiler not found on $PATH. Check your nvcc installation and try again.
1.11.0
0.8.0rc1.dev-e6e88ce21df4fbb21c76e68da342e276548d4afd
0.3.2
(venv3)herbert@machine:~/ $

编辑

我还创建了一个简单 MLP 的 Theano 实现,它也不运行多核:

import os
os.environ['MKL_NUM_THREADS'] = '8'
os.environ['GOTO_NUM_THREADS'] = '8'
os.environ['OMP_NUM_THREADS'] = '8'
os.environ['THEANO_FLAGS'] = 'device=cpu,blas.ldflags=-lblas -lgfortran'

import numpy
import theano
import theano.tensor as T

M=2000
N=2000
K=2000
iters=100
order='C'

coeffs = numpy.random.randn(100)
x = numpy.random.randn(100000, 100).astype(theano.config.floatX)
y = (numpy.dot(x, coeffs) + numpy.random.randn(100000) * 0.01).astype(theano.config.floatX).reshape(100000, 1)

x_shared = theano.shared(x)
y_shared = theano.shared(y)

x_tensor = T.matrix('x')
y_tensor = T.matrix('y')

W0_values = numpy.asarray(
    numpy.random.uniform(
        low=-numpy.sqrt(6. / 120),
        high=numpy.sqrt(6. / 120),
        size=(100, 20)
    ),
    dtype=theano.config.floatX
)
W0 = theano.shared(value=W0_values, name='W0', borrow=True)

b0_values = numpy.zeros((20,), dtype=theano.config.floatX)
b0 = theano.shared(value=b0_values, name='b0', borrow=True)

output0 = T.dot(x_tensor, W0) + b0

W1_values = numpy.asarray(
    numpy.random.uniform(
        low=-numpy.sqrt(6. / 120),
        high=numpy.sqrt(6. / 120),
        size=(20, 1)
    ),
    dtype=theano.config.floatX
)
W1 = theano.shared(value=W1_values, name='W1', borrow=True)

b1_values = numpy.zeros((1,), dtype=theano.config.floatX)
b1 = theano.shared(value=b1_values, name='b1', borrow=True)

output1 = T.dot(output0, W1) + b1

params = [W0, b0, W1, b1]
cost = ((output1 - y_tensor) ** 2).sum()

gradients = [T.grad(cost, param) for param in params]

learning_rate = 0.0000001

updates = [
    (param, param - learning_rate * gradient)
    for param, gradient in zip(params, gradients)
]

train_model = theano.function(
    inputs=[],#x_tensor, y_tensor],
    outputs=cost,
    updates=updates,
    givens={
        x_tensor: x_shared,
        y_tensor: y_shared
    }
)

errors = []
for i in range(1000):
    errors.append(train_model())

print(errors[0:50:])

【问题讨论】:

  • 在 Theano 中启用 OpenMP 是否有效?您可以通过将 openmp = True 添加到 theano 配置来做到这一点。
  • @MatiasValdenegro 谢谢。您在上面的脚本中看不到这一点,但我确实尝试过,但没有帮助。但是,现在似乎openmp_elemwise_minsize 阻止了使用多个内核。我需要更多的实验才能完全理解这一点。
  • 我打算提出同样的问题。您在这里缺少指向 github 问题的链接,看起来您实际上能够使用多个内核(将性能提高到 4 个线程)。所以现在我有点迷失了,但在我的安装中,我仍然只看到一个内核被使用,并且文档说默认情况下应该使用所有内核。
  • 不 :( 不幸的是我没有。
  • openmp_elemwise_minsize 是低于该大小的并行化加速不值得开销的大小。如果您降低该阈值,您将更频繁地并行运行代码,但实际上可能不会变得更快。

标签: python-3.4 theano blas keras openblas


【解决方案1】:

Keras 和 TF 本身并不使用整个内核和 CPU 容量!如果您有兴趣使用所有 100% 的 CPU,那么 multiprocessing.Pool 基本上会创建一个需要执行的作业池。这些进程将获取这些作业并运行它们。当一个作业完成后,该进程将从池中拾取另一个作业。

注意:如果您只想加快此模型的速度,请查看 GPU 或更改超参数,例如批量大小和神经元数量(层大小)。

这里介绍了如何使用 multiprocessing 同时训练多个模型(使用在机器的每个单独 CPU 内核上并行运行的进程)。

这个答案灵感来自@repploved

import time
import signal
import multiprocessing

def init_worker():
    ''' Add KeyboardInterrupt exception to mutliprocessing workers '''
    signal.signal(signal.SIGINT, signal.SIG_IGN)


def train_model(layer_size):
    '''
    This code is parallelized and runs on each process
    It trains a model with different layer sizes (hyperparameters)
    It saves the model and returns the score (error)
    '''
    import keras
    from keras.models import Sequential
    from keras.layers import Dense

    print(f'Training a model with layer size {layer_size}')

    # build your model here
    model_RNN = Sequential()
    model_RNN.add(Dense(layer_size))

    # fit the model (the bit that takes time!)
    model_RNN.fit(...)

    # lets demonstrate with a sleep timer
    time.sleep(5)

    # save trained model to a file
    model_RNN.save(...)

    # you can also return values eg. the eval score
    return model_RNN.evaluate(...)


num_workers = 4
hyperparams = [800, 960, 1100]

pool = multiprocessing.Pool(num_workers, init_worker)

scores = pool.map(train_model, hyperparams)

print(scores)

输出:

Training a model with layer size 800
Training a model with layer size 960
Training a model with layer size 1100
[{'size':960,'score':1.0}, {'size':800,'score':1.2}, {'size':1100,'score':0.7}]

这很容易在代码中使用time.sleep 进行演示。您会看到所有 3 个流程都开始了训练作业,然后它们几乎同时完成。如果这是单次处理,则必须等待每个处理完成才能开始下一个(打哈欠!)。

【讨论】:

  • 您声称 Keras 和 TF 不使用整个内核和 CPU 容量的说法是不正确的,这取决于模型大小和它可以自动并行化的级别,当我训练大型模型时CPU 我可以看到使用所有可用内核的 tensorflow。
  • 当我从windows任务管理器中查看CPU性能从未超过30%时,这也是SOF中许多用户的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-26
  • 2014-07-31
  • 2019-05-09
  • 2018-03-07
  • 1970-01-01
  • 2021-02-16
相关资源
最近更新 更多