Я протестировал скорость separable_conv2d
и normal conv2d
, реализованную в TF, кажется, что depthwise_conv2d
быстрее, чем normal conv2d
, но производительность dw_conv2d, очевидно, плохая.
Сепарабельный_конв2д, упомянутый в MobileNet, его FLOPs
составляет 1/9 от нормального конва, когда kernel_size=3
, но, учитывая Memory Access Cost
, сепарабельный не может быть в 9 раз быстрее обычного, но в моем эксперименте, отделяемый слишком медленный.
Я моделирую эксперимент следующим образом: separable_conv2d слишком медленный . В этом эксперименте separable_conv2d кажется более быстрым, чем нормальный, когда deep_multiply = 1, но когда я использую tf.nn
, чтобы реализовать его следующим образом:
IMAGE_SIZE= 512
REPEAT = 100
KERNEL_SIZE = 3
data_format = 'NCHW'
#CHANNELS_BATCH_SIZE = 2048 # channe# ls * batch_size
os.environ["TF_CPP_MIN_LOG_LEVEL"] = "3"
def normal_layers(inputs, nfilter, name=''):
with tf.variable_scope(name, reuse=tf.AUTO_REUSE):
shape = inputs.shape.as_list()
in_channels = shape[1]
filter = tf.get_variable(initializer=tf.initializers.random_normal,
shape=[KERNEL_SIZE, KERNEL_SIZE,
in_channels, nfilter], name='weight')
conv = tf.nn.conv2d(input= inputs, filter=filter, strides=
[1,1,1,1],padding='SAME',data_format=data_format,
name='conv')
return conv
def sep_layers(inputs, nfilter, name=''):
with tf.variable_scope(name, reuse=tf.AUTO_REUSE):
shape= inputs.shape.as_list()
in_channels = shape[1]
dw_filter=
tf.get_variable(initializer=tf.initializers.random_normal,
shape=[KERNEL_SIZE, KERNEL_SIZE,
in_channels, 1], name='dw_weight')
pw_filter =
tf.get_variable(initializer=tf.initializers.random_normal,
shape=[1,1,in_channels, nfilter],
name='pw_weight')
conv = tf.nn.depthwise_conv2d_native(input=inputs,
filter=dw_filter,
strides=[1,1,1,1],
padding='SAME',
data_format=data_format)
conv = tf.nn.conv2d(input=conv,
filter=pw_filter,
strides=[1,1,1,1],
padding='SAME',
data_format=data_format)
return conv
Каждый слой запускается в 100 times
,
отличается от ссылки, я устанавливаю batch_size
в качестве постоянной 10,
и channels is in [32, 64, 128]
,
входные данные - [batch_size, channel, img_size, img_size]
и duration
из них следующим образом:
Channels: 32
Normal Conv 0.7769527435302734s, Sep Conv 1.4197885990142822s
Channels: 64
Normal Conv 0.8963277339935303s, Sep Conv 1.5703468322753906s
Channels: 128
Normal Conv 0.9741833209991455s, Sep Conv 1.665834665298462s
Похоже, что когда batch_size является каналом только с постоянным изменением, временные затраты обычного и разделяемого каналов постепенно растут.
А при установке batch_size * channels
в качестве постоянной
Форма входов: [CHANNELS_BATCH_SIZE // каналы, каналы, размер, размер]
Channels: 32
Normal Conv 0.871959924697876s, Sep Conv 1.569300651550293s
Channels: 64
Normal Conv 0.909860372543335s, Sep Conv 1.604109525680542s
Channels: 128
Normal Conv 0.9196009635925293s, Sep Conv 1.6144189834594727s
Что меня смущает, так это то, что результат отличается от результата по ссылке выше: временные затраты sep_conv2d не имеют очевидных изменений.
Мои вопросы:
- Что отличает мою ссылку от эксперимента выше?
- Я новичок , так что, в моем коде что-то не так для реализации separable_conv2d?
- Как реализовать separable_conv2d может быть быстрее обычного в TF или в Pytorch ?
Буду признателен за любую помощь. Спасибо заранее.