背景:MTCNN的prelu需要训练,并且prelu需要有参数。prelu改为relu之后,相应的参数量会降低并且实现也更简单。
目的:更改MTCNN的prelu为ReLU,并在python端训练出相应的代码,c端结构改为与python端一致。
参考相关:
MTCNN(三)基于python代码的网络结构更改 https://blog.csdn.net/weixin_36474809/article/details/82856171
MTCNN(一)训练与运行 https://blog.csdn.net/weixin_36474809/article/details/82752199
目录
一、python端结构的更改与参数训练
1.1 更改的位置
更改前的prelu
@layer
def prelu(self, inp, name):
with tf.variable_scope(name):
i = int(inp.get_shape()[-1])
alpha = self.make_var('alpha', shape=(i,))
return tf.nn.relu(inp) + tf.multiply(alpha, -tf.nn.relu(-inp))
加上relu
@layer
def relu(self, inp, name):
return tf.nn.relu(inp, name=name)
然后把pnet/rnet/onet中的prelu函数全部改为relu函数。
这里批评一下Notepad++之中的空格总是与python需要的空格不一致。每次编辑好之后还要用spyder再进行一次空格,免得报错。IndentationError: unexpected unindent
网络结构定义之中的更改:prelu改为了relu,(层的名字方便起见暂时没有更改)
class PNet(NetWork):
def setup(self, task='data', reuse=False):
with tf.variable_scope('pnet', reuse=reuse):
(
self.feed(task) .conv(
3,
3,
10,
1,
1,
padding='VALID',
relu=False,
name='conv1') .relu(
name='ReLU1') .conv(
3,
3,
16,
2,
2,
padding='SAME',
relu=False,
name='pool1_conv1') .relu(
name='pool1_ReLU1') .conv(
3,
3,
32,
1,
1,
padding='VALID',
relu=False,
name='conv2') .relu(
name='ReLU2') .conv(
3,
3,
32,
1,
1,
task=task,
padding='VALID',
relu=False,
name='conv3',
wd=self.weight_decay_coeff) .relu(
name='ReLU3'))
if self.mode == 'train':
if task == 'cls':
(self.feed('ReLU3')
.conv(1, 1, 2, 1, 1, task=task, relu=False,
name='pnet/conv4-1', wd=self.weight_decay_coeff))
elif task == 'bbx':
(self.feed('ReLU3')
.conv(1, 1, 4, 1, 1, task=task, relu=False,
name='pnet/conv4-2', wd=self.weight_decay_coeff))
elif task == 'pts':
(self.feed('ReLU3')
.conv(1, 1, 10, 1, 1, task=task, relu=False,
name='pnet/conv4-3', wd=self.weight_decay_coeff))
self.out_put.append(self.get_output())
else:
(self.feed('ReLU3')
.conv(1, 1, 2, 1, 1, relu=False, name='pnet/conv4-1')
.softmax(name='softmax'))
self.out_put.append(self.get_output())
(self.feed('ReLU3')
.conv(1, 1, 4, 1, 1, relu=False, name='pnet/conv4-2'))
self.out_put.append(self.get_output())
1.2 实验结果
初步结果:
后续检验过的结果:mAP 57.85%
1.3 重新训练与测试
Pnet
把其中的prelu改为relu,然后训练。
all trainable variables:
<tf.Variable 'pnet/conv1/weights:0' shape=(3, 3, 3, 10) dtype=float32_ref>
<tf.Variable 'pnet/conv1/biases:0' shape=(10,) dtype=float32_ref>
<tf.Variable 'pnet/pool1_conv1/weights:0' shape=(3, 3, 10, 16) dtype=float32_ref>
<tf.Variable 'pnet/pool1_conv1/biases:0' shape=(16,) dtype=float32_ref>
<tf.Variable 'pnet/conv2/weights:0' shape=(3, 3, 16, 32) dtype=float32_ref>
<tf.Variable 'pnet/conv2/biases:0' shape=(32,) dtype=float32_ref>
<tf.Variable 'pnet/conv3/weights:0' shape=(3, 3, 32, 32) dtype=float32_ref>
<tf.Variable 'pnet/conv3/biases:0' shape=(32,) dtype=float32_ref>
<tf.Variable 'pnet/conv4-1/weights:0' shape=(1, 1, 32, 2) dtype=float32_ref>
<tf.Variable 'pnet/conv4-1/biases:0' shape=(2,) dtype=float32_ref>
<tf.Variable 'pnet/conv4-2/weights:0' shape=(1, 1, 32, 4) dtype=float32_ref>
<tf.Variable 'pnet/conv4-2/biases:0' shape=(4,) dtype=float32_ref>
<tf.Variable 'pnet/conv4-3/weights:0' shape=(1, 1, 32, 10) dtype=float32_ref>
<tf.Variable 'pnet/conv4-3/biases:0' shape=(10,) dtype=float32_ref>
all local variable:
input/input_producer/limit_epochs/epochs:0
input_1/input_producer/limit_epochs/epochs:0
只有卷积核与bias需要训练,没有了prelu的斜率。
Rnet
all trainable variables:
<tf.Variable 'rnet/conv1/weights:0' shape=(3, 3, 3, 28) dtype=float32_ref>
<tf.Variable 'rnet/conv1/biases:0' shape=(28,) dtype=float32_ref>
<tf.Variable 'rnet/pool1_conv1/weights:0' shape=(3, 3, 28, 28) dtype=float32_ref>
<tf.Variable 'rnet/pool1_conv1/biases:0' shape=(28,) dtype=float32_ref>
<tf.Variable 'rnet/conv2/weights:0' shape=(3, 3, 28, 48) dtype=float32_ref>
<tf.Variable 'rnet/conv2/biases:0' shape=(48,) dtype=float32_ref>
<tf.Variable 'rnet/pool2_conv3/weights:0' shape=(3, 3, 48, 48) dtype=float32_ref>
<tf.Variable 'rnet/pool2_conv3/biases:0' shape=(48,) dtype=float32_ref>
<tf.Variable 'rnet/conv3/weights:0' shape=(3, 3, 48, 64) dtype=float32_ref>
<tf.Variable 'rnet/conv3/biases:0' shape=(64,) dtype=float32_ref>
<tf.Variable 'rnet/conv4/weights:0' shape=(576, 128) dtype=float32_ref>
<tf.Variable 'rnet/conv4/biases:0' shape=(128,) dtype=float32_ref>
<tf.Variable 'rnet/conv5-1/weights:0' shape=(128, 2) dtype=float32_ref>
<tf.Variable 'rnet/conv5-1/biases:0' shape=(2,) dtype=float32_ref>
<tf.Variable 'rnet/conv5-2/weights:0' shape=(128, 4) dtype=float32_ref>
<tf.Variable 'rnet/conv5-2/biases:0' shape=(4,) dtype=float32_ref>
<tf.Variable 'rnet/conv5-3/weights:0' shape=(128, 10) dtype=float32_ref>
<tf.Variable 'rnet/conv5-3/biases:0' shape=(10,) dtype=float32_ref>
all local variable:
input/input_producer/limit_epochs/epochs:0
Onet
all trainable variables:
<tf.Variable 'onet/conv1/weights:0' shape=(3, 3, 3, 32) dtype=float32_ref>
<tf.Variable 'onet/conv1/biases:0' shape=(32,) dtype=float32_ref>
<tf.Variable 'onet/conv2/weights:0' shape=(3, 3, 32, 32) dtype=float32_ref>
<tf.Variable 'onet/conv2/biases:0' shape=(32,) dtype=float32_ref>
<tf.Variable 'onet/conv3/weights:0' shape=(3, 3, 32, 64) dtype=float32_ref>
<tf.Variable 'onet/conv3/biases:0' shape=(64,) dtype=float32_ref>
<tf.Variable 'onet/conv4_/weights:0' shape=(3, 3, 64, 64) dtype=float32_ref>
<tf.Variable 'onet/conv4_/biases:0' shape=(64,) dtype=float32_ref>
<tf.Variable 'onet/conv5_/weights:0' shape=(3, 3, 64, 128) dtype=float32_ref>
<tf.Variable 'onet/conv5_/biases:0' shape=(128,) dtype=float32_ref>
<tf.Variable 'onet/conv6_/weights:0' shape=(3, 3, 128, 128) dtype=float32_ref>
<tf.Variable 'onet/conv6_/biases:0' shape=(128,) dtype=float32_ref>
<tf.Variable 'onet/conv5/weights:0' shape=(1152, 256) dtype=float32_ref>
<tf.Variable 'onet/conv5/biases:0' shape=(256,) dtype=float32_ref>
<tf.Variable 'onet/conv6-1/weights:0' shape=(256, 2) dtype=float32_ref>
<tf.Variable 'onet/conv6-1/biases:0' shape=(2,) dtype=float32_ref>
<tf.Variable 'onet/conv6-2/weights:0' shape=(256, 4) dtype=float32_ref>
<tf.Variable 'onet/conv6-2/biases:0' shape=(4,) dtype=float32_ref>
<tf.Variable 'onet/conv6-3/weights:0' shape=(256, 10) dtype=float32_ref>
<tf.Variable 'onet/conv6-3/biases:0' shape=(10,) dtype=float32_ref>
all local variable:
input/input_producer/limit_epochs/epochs:0
二、采用网络结构表
Pnet
Feature size | name | Kernel size | Stride | Padding |
12*12*3 | conv1 ReLU1 | 3*3*10 | 1 | Valid |
10*10*10 | pool1_conv1 pool1_ReLU1 | 3*3*16 | 2 | Same |
5*5*16 | conv2 ReLU2 | 3*3*32 | 1 | Valid |
3*3*32 | conv3 ReLU3 | 3*3*32 | 1 | Valid |
1*1*32 |
|
|
|
Rnet
Feature size | name | Kernel size | Stride | Padding |
24*24*3 | conv1 relu1 | 3*3*28 | 1 | Same |
24*24*28 | pool1_conv1 pool1_relu1 | 3*3*28 | 2 | Same |
12*12*28 | conv2 relu2 | 3*3*48 | 1 | Same |
12*12*48 | pool2_conv3 poo2_relu3 | 3*3*48 | 2 | Same |
6*6*48 | conv3 relu3 | 3*3*64 | 2 | Same |
3*3*64 |
|
|
Onet
Feature size | name | Kernel size | Stride | Padding |
48*48*3 | conv1 relu1 | 3*3*32 | 1 | Same |
48*48*32 | conv2 relu2 | 3*3*32 | 2 | Same |
24*24*32 | conv3 relu3 | 3*3*64 | 1 | Same |
24*24*64 | conv4_ relu4_ | 3*3*64 | 2 | Same |
12*12*64 | conv5_ relu5_ | 3*3*128 | 2 | Same |
6*6*128 | conv6_ relu6_ | 3*3*128 | 2 | Same |
3*3*128 |
三、c代码端结构的更改
3.1 函数的定义
在network.cpp之中
void relu(struct pBox *pbox, mydataFmt *pbias){
if (pbox->pdata == NULL){
cout << "the Relu feature is NULL!!" << endl;
return;
}
if (pbias == NULL){
cout << "the Relu bias is NULL!!" << endl;
return;
}
mydataFmt *op = pbox->pdata;
mydataFmt *pb = pbias;
long dis = pbox->width*pbox->height;
for(int channel =0;channel<pbox->channel; channel++){
for(int col=0; col<dis; col++){
*op += *pb;
if(*op<0)*op=0;
op++;
}
pb++;
}
}
void prelu(struct pBox *pbox, mydataFmt *pbias, mydataFmt *prelu_gmma){
if (pbox->pdata == NULL){
cout << "the Relu feature is NULL!!" << endl;
return;
}
if (pbias == NULL){
cout << "the Relu bias is NULL!!" << endl;
return;
}
mydataFmt *op = pbox->pdata;
mydataFmt *pb = pbias;
mydataFmt *pg = prelu_gmma;
long dis = pbox->width*pbox->height;
for(int channel =0;channel<pbox->channel; channel++){
for(int col=0; col<dis; col++){
*op = *op + *pb;
*op = (*op>0)?(*op):((*op)*(*pg));
op++;
}
pb++;
pg++;
}
}
3.2 网络的更改
因为relu直接将值进行了替换,所以不存在开辟内存空间的问题,只有运算,并且维度一样,可以直接将prelu函数换位relu函数。