Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Frontend][Darknet] L2 normalization support in darknet #1916

Merged
merged 2 commits into from
Oct 24, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions nnvm/python/nnvm/frontend/darknet.py
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,13 @@ def _darknet_upsampling(inputs, attrs):
new_attrs['scale'] = attrs.get('scale', 1)
return _darknet_get_nnvm_op(op_name)(*inputs, **new_attrs), None

def _darknet_l2normalize(inputs, attrs):
"""Process the l2 normalization operation."""
op_name, new_attrs = 'l2_normalize', {}
new_attrs['eps'] = attrs.get('eps', 0)
new_attrs['axis'] = attrs.get('axis', 1)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't really know darknet, would appreciate if you could point out where these two attrs come from. The overall functionality looks good to me.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. The darknet computes the l2 normalization always along the channel axis. So it doesn't store the axis information anywhere. And while dividing by sum it doesn't check if sum is greater than eps or not.
So i have made default eps as 0 and axis as 1 to make it compatible with TVM's L2 normalization implementation. You can have look at darknet's l2 normalization implementation here

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

got it. thanks!

return _darknet_get_nnvm_op(op_name)(*inputs, **new_attrs), None

def _darknet_softmax_output(inputs, attrs):
"""Process the softmax operation."""
temperature = attrs.get('temperature', 1)
Expand Down Expand Up @@ -370,6 +377,7 @@ def _darknet_op_not_support(inputs, attrs):
LAYERTYPE.REGION : _darknet_region,
LAYERTYPE.SHORTCUT : _darknet_shortcut,
LAYERTYPE.UPSAMPLE : _darknet_upsampling,
LAYERTYPE.L2NORM : _darknet_l2normalize,
LAYERTYPE.YOLO : _darknet_yolo,
LAYERTYPE.DETECTION : _darknet_op_not_support,
LAYERTYPE.CROP : _darknet_op_not_support,
Expand Down Expand Up @@ -630,6 +638,10 @@ def _get_darknet_attrs(self, layer, layer_num):

elif LAYERTYPE.UPSAMPLE == layer.type:
attr.update({'scale' : layer.stride})

elif LAYERTYPE.L2NORM == layer.type:
pass

else:
err = "Darknet layer type {} is not supported in nnvm.".format(layer.type)
raise NotImplementedError(err)
Expand Down
1 change: 1 addition & 0 deletions nnvm/python/nnvm/testing/darknet.py
Original file line number Diff line number Diff line change
Expand Up @@ -512,6 +512,7 @@ class ACTIVATION(object):
layer make_lstm_layer(int batch, int inputs, int outputs, int steps, int batch_normalize, int adam);
layer make_gru_layer(int batch, int inputs, int outputs, int steps, int batch_normalize, int adam);
layer make_upsample_layer(int batch, int w, int h, int c, int stride);
layer make_l2norm_layer(int batch, int inputs);
void free_network(network *net);
"""
)
16 changes: 15 additions & 1 deletion nnvm/tests/python/frontend/darknet/test_forward.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ def get_darknet_output(net, img):
out.insert(0, attributes)
out.insert(0, _read_memory_buffer((layer.total*2, ), layer.biases))
out.insert(0, _read_memory_buffer((layer.n, ), layer.mask, dtype='int32'))
layer_ou tshape = (layer.batch, layer.out_c,
layer_outshape = (layer.batch, layer.out_c,
layer.out_h, layer.out_w)
out.insert(0, _read_memory_buffer(layer_outshape, layer.output))
elif i == net.n-1:
Expand Down Expand Up @@ -361,6 +361,19 @@ def test_forward_upsample():
test_forward(net)
LIB.free_network(net)

def test_forward_l2normalize():
'''test l2 normalization layer'''
net = LIB.make_network(1)
layer = LIB.make_l2norm_layer(1, 224*224*3)
layer.c = layer.out_c = 3
layer.h = layer.out_h = 224
layer.w = layer.out_w = 224
net.layers[0] = layer
net.w = net.h = 224
LIB.resize_network(net, 224, 224)
test_forward(net)
LIB.free_network(net)

def test_forward_elu():
'''test elu activation layer'''
net = LIB.make_network(1)
Expand Down Expand Up @@ -520,6 +533,7 @@ def test_forward_activation_logistic():
test_forward_region()
test_forward_yolo_op()
test_forward_upsample()
test_forward_l2normalize()
test_forward_elu()
test_forward_rnn()
test_forward_crnn()
Expand Down