【问题标题】:Performance issues for a keras 1D ResNeXT based network基于 keras 1D ResNeXT 的网络的性能问题
【发布时间】:2018-12-17 09:06:08
【问题描述】:

我正在尝试使用 ResNeXT 类型的架构对一些 77 长度信号对进行分类。然而,即使使用相对适中的 38k 参数,该模型的运行速度也非常慢,每个 epoch 大约需要 12 天 60M 训练示例。内存使用量也会上下波动约 10 GB,这表明分配和垃圾收集出现问题。

我希望 1D 模型相对较快,因为这些模型通常应用于更大尺寸和更多层的图像。

我尝试使用 tensorflow-chrome 分析 Keras,但只得到空的输出文件。我采用的方法是否有问题,如何有效诊断和优化 keras 模型中的性能问题?

此外,模型有点疯狂(占用 100% cpu 并锁定整个计算机,除非 CPU 内核限制为 1)

batch size 从 5000 增加到 50000 会使内存使用的波动更大,并占用所有可用的(64G)内存)。将其减少到 500 可以阻止大的波动,但是对于训练时间的估计仍然在 200+ 小时的范围内。

正确安装 CUDA9 + cudnn + tensorflow-gpu 可将每个 epoch 的预期运行时间缩短约 2 倍至 100 小时。 CPU 负载仍然很高,GPU 负载很低,但不再锁定。

我已经运行了具有更多参数的其他模型而没有任何问题,所以我认为这与这个特定模型的不寻常结构有关。

型号代码如下:

def relubn(b): 
  return BatchNormalization()(  ReLU()( b ) )


def resnext_1d( layer_in, n_in, n_paths, n_bottleneck, kernel_size ):
  paths = []
  b = Conv1D(n_bottleneck * n_paths,1)( layer_in )  
  b = relubn(b)
  for i in range(0,n_paths):
    group = Lambda(lambda z: z[:, :, i * n_bottleneck:(i + 1) * n_bottleneck])( b )
    c = Conv1D(n_bottleneck,kernel_size, padding='same')( group )
    paths.append( c )

  con  = concatenate(paths)
  comb = Conv1D(n_in,1)( con )  
  comb = relubn( comb )

  return relubn( add( [layer_in, comb] ) )

in1 = Input(shape=(77,2))

l1 = Conv1D(64, (9,), padding='same')( in1 )
l2 = resnext_1d( l1, 64, 8, 4, 9 )
l3 = resnext_1d( l2, 64, 8, 4, 9 )
l4 = resnext_1d( l3, 64, 8, 4, 9 )
l5 = resnext_1d( l4, 64, 8, 4, 9 )
l6 = resnext_1d( l5, 64, 8, 4, 9 )
l7 = resnext_1d( l6, 64, 8, 4, 9 )
l8 = resnext_1d( l6, 64, 8, 4, 9 )
ap = GlobalAveragePooling1D()( relubn(l8) ) # 64x1

out_class = Dense(28, activation='softmax')( ap ) 

【问题讨论】:

  • 1.对于大型模型,Keras 的设计速度非常慢。 (github.com/tensorpack/benchmarks/tree/master/other-wrappers)。 2. 使用tf.split 比在 for 循环中切片张量更有效。
  • 1.也许吧,但按照当今的标准,这个模型很小。 2. 我刚试过 tf.split,效果不明显。
  • @ppwwyyxx 声称“按设计非常慢”是一个非常强烈的主张,不支持您的链接。
  • 您使用的是 GPU 吗?您使用的是什么批量大小?训练期间的 GPU/CPU 利用率是多少?
  • 您的批处理大小听起来太大了,使用 32/64 之类的值并增加它直到获得最佳性能

标签: python tensorflow keras deep-learning profiling


【解决方案1】:

每当提出问题时,最好附上Minimal, Complete, Verifiable example,这样人们就可以开始谈论同样的事情。

就您的情况而言,您提供的部分、不可运行的示例似乎并未包含所有信息。我试图从您的代码中创建一个可运行的示例:我复制了您发布的整个模型,并将批量大小设置为 500,将总 #example 设置为 60M。我使用了假数据。你的模型有一个错误(l7 没有连接到任何东西),我保留了这个错误。

#!/usr/bin/env python

import keras
from keras.models import Model
from keras.utils import np_utils
from keras.layers import *
import numpy as np

batch_size = 500
nb_classes = 1000
nb_epoch = 200

X_train = np.random.random((batch_size, 77, 2))
Y_train = np.random.random((batch_size,)).astype('int32')
Y_train = np_utils.to_categorical(Y_train, 28)

def gen():
    while True:
        yield (X_train, Y_train)


def relubn(b):
  return BatchNormalization()(  ReLU()( b ) )


def resnext_1d( layer_in, n_in, n_paths, n_bottleneck, kernel_size ):
  paths = []
  b = Conv1D(n_bottleneck * n_paths,1)( layer_in )
  b = relubn(b)
  for i in range(0,n_paths):
    group = Lambda(lambda z: z[:, :, i * n_bottleneck:(i + 1) * n_bottleneck])( b )
    c = Conv1D(n_bottleneck,kernel_size, padding='same')( group )
    paths.append( c )

  con  = concatenate(paths)
  comb = Conv1D(n_in,1)( con )
  comb = relubn( comb )

  return relubn( add( [layer_in, comb] ) )

in1 = Input(shape=(77,2))
l1 = Conv1D(64, (9,), padding='same')( in1 )
l2 = resnext_1d( l1, 64, 8, 4, 9 )
l3 = resnext_1d( l2, 64, 8, 4, 9 )
l4 = resnext_1d( l3, 64, 8, 4, 9 )
l5 = resnext_1d( l4, 64, 8, 4, 9 )
l6 = resnext_1d( l5, 64, 8, 4, 9 )
#l7 = resnext_1d( l6, 64, 8, 4, 9 )
l8 = resnext_1d( l6, 64, 8, 4, 9 )
ap = GlobalAveragePooling1D()( relubn(l8) ) # 64x1
out_class = Dense(28, activation='softmax')( ap )
model = Model(in1, out_class)
model.summary()
model.compile(loss='categorical_crossentropy',
              optimizer='sgd',
              metrics=['accuracy'])
model.fit_generator(gen(), epochs=nb_epoch, steps_per_epoch=60000000 // batch_size)
#model.fit_generator(gen(), epochs=nb_epoch, steps_per_epoch=200)

以上代码在我的机器上运行速度是2h/epoch,和你报的相差甚远。因此,您很可能被与您提供的代码无关的其他内容所阻止。您可能需要更深入地了解这一点。

正如我在评论中提到的,Keras 本身很慢,所以我将上面的代码翻译成它在 tensorpack 中的等效代码。然后代码以 1.5h/epoch 的速度运行。

from tensorpack import *
import tensorflow as tf
import numpy as np

batch_size = 500

X_train = np.random.random((batch_size, 77, 2))
Y_train = np.random.random((batch_size,)).astype('int32')
Y_train = np_utils.to_categorical(Y_train, 28)

def gen():
    while True:
        yield (X_train, Y_train)


def relubn(b):
  ret = tf.layers.batch_normalization(
          tf.nn.relu(b), training=get_current_tower_context().is_training
          )
  return ret


def resnext_1d( layer_in, n_in, n_paths, n_bottleneck, kernel_size ):
  paths = []
  b = tf.layers.conv1d(layer_in, n_bottleneck * n_paths,1)
  b = relubn(b)
  #splits = tf.split(b, n_paths, axis=2)
  for i in range(0,n_paths):
    group = b[:, :, i * n_bottleneck:(i + 1) * n_bottleneck]
    #group = splits[i]
    c = tf.layers.conv1d(group, n_bottleneck,kernel_size, padding='same')
    paths.append( c )

  con  = tf.concat(paths, axis=-1)
  comb = tf.layers.conv1d(con,n_in,1)
  comb = relubn( comb )

  return relubn( layer_in+ comb)

def tower_func(input, labels):
    l1 = tf.layers.conv1d(input, 64, (9,), padding='same')
    l2 = resnext_1d( l1, 64, 8, 4, 9 )
    l3 = resnext_1d( l2, 64, 8, 4, 9 )
    l4 = resnext_1d( l3, 64, 8, 4, 9 )
    l5 = resnext_1d( l4, 64, 8, 4, 9 )
    l6 = resnext_1d( l5, 64, 8, 4, 9 )
    #l7 = resnext_1d( l6, 64, 8, 4, 9 )
    l8 = resnext_1d( l6, 64, 8, 4, 9 )
    ap = tf.reduce_mean(relubn(l8) , axis=1) # 64x1
    out_class = tf.layers.dense(ap, 28)
    loss = tf.nn.softmax_cross_entropy_with_logits_v2(labels=labels,
            logits=out_class)
    return tf.reduce_mean(loss)

trainer = SimpleTrainer()
trainer.setup_graph(
        inputs_desc=[InputDesc(tf.float32, [None, 77, 2], 'images'),
                     InputDesc(tf.float32, [None, 28], 'labels')],
        input=QueueInput(DataFromGenerator(gen)),
        get_cost_fn=tower_func,
        get_opt_fn=lambda: tf.train.GradientDescentOptimizer(1e-3)
        )
trainer.train_with_defaults(
        steps_per_epoch=60000000//batch_size
        )

我提到的拆分操作似乎不影响速度。

我的环境:GTX1080Ti;蟒蛇3.6;库达 10; cudnn 7.4.1; tensorflow nightly build 昨天;凯拉斯 2.2.4;截至 12 月 19 日的 tensorpack master;

【讨论】:

  • 感谢您的努力并在层中发现错误。经过进一步检查,似乎我的 tensorflow 首先忽略了我的 gpu,现在拒绝使用我的 GT730 GPU,因为它的 cuda 能力 = 3.5。使用 Cuda 计算能力 3.5 忽略可见 gpu 设备(设备:0,名称:GeForce GT 730,pci 总线 ID:0000:01:00.0,计算能力:3.5)。所需的最低 Cuda 能力为 3.7。
猜你喜欢
  • 2013-04-04
  • 2013-03-10
  • 1970-01-01
  • 1970-01-01
  • 2017-11-27
  • 1970-01-01
  • 2019-02-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多