From 8b01540d739c2351aad2474f3ab51afd06a1e46e Mon Sep 17 00:00:00 2001 From: Pariksheet Pinjari <pariksheet.pinjari@huawei.com> Date: Wed, 17 Oct 2018 06:56:09 +0530 Subject: [PATCH] [FRONTEND][DARKNET] YOLO V3 model support (#1734) --- nnvm/python/nnvm/frontend/darknet.py | 59 +++++- nnvm/python/nnvm/testing/__init__.py | 2 +- nnvm/python/nnvm/testing/darknet.py | 5 +- .../{yolo2_detection.py => yolo_detection.py} | 173 ++++++++++-------- .../python/frontend/darknet/test_forward.py | 110 ++++++++--- tutorials/nnvm/from_darknet.py | 66 ++++--- 6 files changed, 291 insertions(+), 124 deletions(-) rename nnvm/python/nnvm/testing/{yolo2_detection.py => yolo_detection.py} (54%) diff --git a/nnvm/python/nnvm/frontend/darknet.py b/nnvm/python/nnvm/frontend/darknet.py index 7fb3e3475..bf3a16cdb 100644 --- a/nnvm/python/nnvm/frontend/darknet.py +++ b/nnvm/python/nnvm/frontend/darknet.py @@ -440,11 +440,13 @@ class GraphProto(object): self._state_ctr['cell_state'] = 0 self._state_ctr['gru'] = 0 - def _read_memory_buffer(self, shape, data): + def _read_memory_buffer(self, shape, data, dtype=None): + if dtype is None: + dtype = self.dtype length = 1 for x in shape: length *= x - data_np = np.zeros(length, dtype=self.dtype) + data_np = np.zeros(length, dtype=dtype) for i in range(length): data_np[i] = data[i] return data_np.reshape(shape) @@ -493,6 +495,31 @@ class GraphProto(object): k = self._get_tvm_params_name(opname[0], 'bias') self._tvmparams[k] = tvm.nd.array(biases) + def _get_region_weights(self, layer, opname): + """Parse the biases for region layer.""" + biases = self._read_memory_buffer((layer.n*2, ), layer.biases) + attributes = np.array([layer.n, layer.out_c, layer.out_h, layer.out_w, + layer.classes, layer.coords, layer.background], + dtype=np.int32) + k = self._get_tvm_params_name(opname, 'bias') + self._tvmparams[k] = tvm.nd.array(biases) + k = self._get_tvm_params_name(opname, 'attr') + self._tvmparams[k] = tvm.nd.array(attributes) + + def _get_yolo_weights(self, layer, opname): + """Parse the biases and mask for yolo layer.""" + biases = self._read_memory_buffer((layer.total*2, ), layer.biases) + mask = self._read_memory_buffer((layer.n, ), layer.mask, dtype='int32') + attributes = np.array([layer.n, layer.out_c, layer.out_h, layer.out_w, + layer.classes, layer.total], + dtype=np.int32) + k = self._get_tvm_params_name(opname, 'bias') + self._tvmparams[k] = tvm.nd.array(biases) + k = self._get_tvm_params_name(opname, 'mask') + self._tvmparams[k] = tvm.nd.array(mask) + k = self._get_tvm_params_name(opname, 'attr') + self._tvmparams[k] = tvm.nd.array(attributes) + def _get_batchnorm_weights(self, layer, opname, size): """Parse the weights for batchnorm, which includes, scales, moving mean and moving variances.""" @@ -621,6 +648,11 @@ class GraphProto(object): elif LAYERTYPE.CONNECTED == layer.type: self._get_connected_weights(layer, opname) + elif LAYERTYPE.REGION == layer.type: + self._get_region_weights(layer, opname) + + elif LAYERTYPE.YOLO == layer.type: + self._get_yolo_weights(layer, opname) def _preproc_layer(self, layer, layer_num): """To preprocess each darknet layer, some layer doesnt need processing.""" if layer_num == 0: @@ -850,6 +882,27 @@ class GraphProto(object): return processed, sym + def _make_outlist(self, sym, op_name, layer, layer_num): + if layer.type == LAYERTYPE.REGION: + k = self._get_tvm_params_name(op_name, 'attr') + self._outs.insert(0, _sym.Variable(name=k, init=self._tvmparams[k].asnumpy())) + k = self._get_tvm_params_name(op_name, 'bias') + self._outs.insert(0, _sym.Variable(name=k, init=self._tvmparams[k].asnumpy())) + if layer_num != self.net.n-1: + self._outs.insert(0, sym) + + elif layer.type == LAYERTYPE.YOLO: + k = self._get_tvm_params_name(op_name, 'attr') + self._outs.insert(0, _sym.Variable(name=k, init=self._tvmparams[k].asnumpy())) + k = self._get_tvm_params_name(op_name, 'bias') + self._outs.insert(0, _sym.Variable(name=k, init=self._tvmparams[k].asnumpy())) + k = self._get_tvm_params_name(op_name, 'mask') + self._outs.insert(0, _sym.Variable(name=k, init=self._tvmparams[k].asnumpy())) + if layer_num != self.net.n-1: + self._outs.insert(0, sym) + + return + def from_darknet(self): """To convert the darknet symbol to nnvm symbols.""" for i in range(self.net.n): @@ -867,6 +920,8 @@ class GraphProto(object): layer_name, sym = _darknet_convert_symbol(op_name, _as_list(sym), attr) self._get_darknet_params(self.net.layers[i], layer_name) self._sym_array[i] = sym + self._make_outlist(sym, layer_name, layer, i) + self._outs = _as_list(sym) + self._outs if isinstance(self._outs, list): sym = _sym.Group(self._outs) diff --git a/nnvm/python/nnvm/testing/__init__.py b/nnvm/python/nnvm/testing/__init__.py index 3bf03a1e0..44b852982 100644 --- a/nnvm/python/nnvm/testing/__init__.py +++ b/nnvm/python/nnvm/testing/__init__.py @@ -13,5 +13,5 @@ from . import squeezenet from . import inception_v3 from . import dcgan from . import dqn -from . import yolo2_detection +from . import yolo_detection from . import check_computation diff --git a/nnvm/python/nnvm/testing/darknet.py b/nnvm/python/nnvm/testing/darknet.py index 9a346e01b..d4d33a694 100644 --- a/nnvm/python/nnvm/testing/darknet.py +++ b/nnvm/python/nnvm/testing/darknet.py @@ -55,10 +55,10 @@ def _letterbox_image(img, w_in, h_in): imc, imh, imw = img.shape if (w_in / imw) < (h_in / imh): new_w = w_in - new_h = imh * w_in / imw + new_h = imh * w_in // imw else: new_h = h_in - new_w = imw * h_in/imh + new_w = imw * h_in // imh resized = _resize_image(img, new_w, new_h) boxed = np.full((imc, h_in, w_in), 0.5, dtype=float) _, resizedh, resizedw = resized.shape @@ -511,6 +511,7 @@ layer make_yolo_layer(int batch, int w, int h, int n, int total, int *mask, int layer make_crnn_layer(int batch, int h, int w, int c, int hidden_filters, int output_filters, int steps, ACTIVATION activation, int batch_normalize); 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); void free_network(network *net); """ ) diff --git a/nnvm/python/nnvm/testing/yolo2_detection.py b/nnvm/python/nnvm/testing/yolo_detection.py similarity index 54% rename from nnvm/python/nnvm/testing/yolo2_detection.py rename to nnvm/python/nnvm/testing/yolo_detection.py index 0b229149b..86f19297c 100644 --- a/nnvm/python/nnvm/testing/yolo2_detection.py +++ b/nnvm/python/nnvm/testing/yolo_detection.py @@ -9,27 +9,22 @@ These are utility functions used for testing and tutorial file. from __future__ import division import math from collections import namedtuple +from functools import cmp_to_key import numpy as np -def _entry_index(batch, w, h, outputs, classes, coords, location, entry): - n = int(location/(w*h)) - loc = location%(w*h) - return batch*outputs + n*w*h*(coords+classes+1) + entry*w*h + loc - Box = namedtuple('Box', ['x', 'y', 'w', 'h']) -def _get_region_box(x, biases, n, index, i, j, w, h, stride): - b = Box(0, 0, 0, 0) - b = b._replace(x=(i + x[index + 0*stride]) / w) - b = b._replace(y=(j + x[index + 1*stride]) / h) - b = b._replace(w=np.exp(x[index + 2*stride]) * biases[2*n] / w) - b = b._replace(h=np.exp(x[index + 3*stride]) * biases[2*n+1] / h) - return b - -def _correct_region_boxes(boxes, n, w, h, netw, neth, relative): - new_w, new_h = (netw, (h*netw)/w) if (netw/w < neth/h) else ((w*neth/h), neth) - for i in range(n): - b = boxes[i] - b = boxes[i] + +def nms_comparator(a, b): + if 'sort_class' in b and b['sort_class'] >= 0: + diff = a['prob'][b['sort_class']] - b['prob'][b['sort_class']] + else: + diff = a['objectness'] - b['objectness'] + return diff + +def _correct_boxes(dets, w, h, netw, neth, relative): + new_w, new_h = (netw, (h*netw)//w) if (netw/w < neth/h) else ((w*neth//h), neth) + for det in dets: + b = det['bbox'] b = b._replace(x=(b.x - (netw - new_w)/2/netw) / (new_w/netw)) b = b._replace(y=(b.y - (neth - new_h)/2/neth) / (new_h/neth)) b = b._replace(w=b.w * netw/new_w) @@ -39,7 +34,8 @@ def _correct_region_boxes(boxes, n, w, h, netw, neth, relative): b = b._replace(w=b.w * w) b = b._replace(y=b.y * h) b = b._replace(h=b.h * h) - boxes[i] = b + det['bbox'] = b + return dets def _overlap(x1, w1, x2, w2): l1 = x1 - w1/2 @@ -65,72 +61,103 @@ def _box_union(a, b): def _box_iou(a, b): return _box_intersection(a, b)/_box_union(a, b) -def get_region_boxes(layer_in, imw, imh, netw, neth, thresh, probs, - boxes, relative, tvm_out): - "To get the boxes for the image based on the prediction" - lw = layer_in.w - lh = layer_in.h - probs = [[0 for i in range(layer_in.classes + 1)] for y in range(lw*lh*layer_in.n)] - boxes = [Box(0, 0, 0, 0) for i in range(lw*lh*layer_in.n)] - for i in range(lw*lh): - row = int(i / lw) - col = int(i % lw) - for n in range(layer_in.n): - index = n*lw*lh + i - obj_index = _entry_index(0, lw, lh, layer_in.outputs, layer_in.classes, - layer_in.coords, n*lw*lh + i, layer_in.coords) - box_index = _entry_index(0, lw, lh, layer_in.outputs, layer_in.classes, - layer_in.coords, n*lw*lh + i, 0) - mask_index = _entry_index(0, lw, lh, layer_in.outputs, layer_in.classes, - layer_in.coords, n*lw*lh + i, 4) - scale = 1 if layer_in.background else tvm_out[obj_index] - boxes[index] = _get_region_box(tvm_out, layer_in.biases, n, box_index, col, - row, lw, lh, lw*lh) - if not layer_in.softmax_tree: - max_element = 0 - for j in range(layer_in.classes): - class_index = _entry_index(0, lw, lh, layer_in.outputs, layer_in.classes, - layer_in.coords, n*lw*lh + i, layer_in.coords+1+j) - prob = scale*tvm_out[class_index] - probs[index][j] = prob if prob > thresh else 0 - max_element = max(max_element, prob) - probs[index][layer_in.classes] = max_element - - _correct_region_boxes(boxes, lw*lh*layer_in.n, imw, imh, netw, neth, relative) - return boxes, probs - - -def do_nms_sort(boxes, probs, total, classes, thresh): - "Does the sorting based on the threshold values" - SortableBbox = namedtuple('SortableBbox', ['index_var', 'class_var', 'probs']) +def _get_box(data, biases, n, location, lw, lh, w, h): + bx = (location[2] + data[location[0]][0][location[1]][location[2]]) / lw + by = (location[1] + data[location[0]][1][location[1]][location[2]]) / lh + bw = np.exp(data[location[0]][2][location[1]][location[2]]) * biases[2*n] / w + bh = np.exp(data[location[0]][3][location[1]][location[2]]) * biases[2*n+1] / h + return Box(bx, by, bw, bh) - s = [SortableBbox(0, 0, []) for i in range(total)] - for i in range(total): - s[i] = s[i]._replace(index_var=i) - s[i] = s[i]._replace(class_var=0) - s[i] = s[i]._replace(probs=probs) +def _get_yolo_detections(l, im_shape, net_shape, thresh, relative, dets): + data = l['output'] + active_data_loc = np.asarray(np.where(data[:, 4, :, :] > thresh)) + before_correct_dets = [] + for i in range(active_data_loc.shape[1]): + location = [active_data_loc[0][i], active_data_loc[1][i], active_data_loc[2][i]] + box_b = _get_box(data, l['biases'], np.asarray(l['mask'])[location[0]], location, + data.shape[2], data.shape[3], net_shape[0], net_shape[1]) + objectness = data[location[0]][4][location[1]][location[2]] + classes = l['classes'] + prob = objectness*data[location[0], 5:5 + 1 + classes, location[1], location[2]] + prob[prob < thresh] = 0 + detection = {} + detection['bbox'] = box_b + detection['classes'] = classes + detection['prob'] = prob + detection['objectness'] = objectness + before_correct_dets.append(detection) + dets.extend(_correct_boxes(before_correct_dets, im_shape[0], im_shape[1], + net_shape[0], net_shape[1], relative)) + return +def _get_region_detections(l, im_shape, net_shape, thresh, relative, dets): + data = l['output'] + before_correct_dets = [] + for row in range(data.shape[2]): + for col in range(data.shape[3]): + for n in range(data.shape[0]): + prob = [0]*l['classes'] + scale = data[n, l['coords'], row, col] if not l['background'] else 1 + location = [n, row, col] + box_b = _get_box(data, l['biases'], n, location, + data.shape[2], data.shape[3], data.shape[2], data.shape[3]) + objectness = scale if scale > thresh else 0 + if objectness: + prob = scale * data[n, l['coords']+1: l['coords']+1+l['classes'], + row, col] + prob[prob < thresh] = 0 + detection = {} + detection['bbox'] = box_b + detection['prob'] = prob + detection['objectness'] = objectness + before_correct_dets.append(detection) + _correct_boxes(before_correct_dets, im_shape[0], im_shape[1], + net_shape[0], net_shape[1], relative) + dets.extend(before_correct_dets) + return + +def fill_network_boxes(net_shape, im_shape, + thresh, relative, tvm_out): + dets = [] + for layer in tvm_out: + if layer['type'] == 'Yolo': + _get_yolo_detections(layer, im_shape, net_shape, thresh, relative, dets) + elif layer['type'] == 'Region': + _get_region_detections(layer, im_shape, net_shape, thresh, relative, dets) + return dets + +def do_nms_sort(dets, classes, thresh): + "Does the sorting based on the threshold values" + k = len(dets)-1 + cnt = 0 + while cnt < k: + if dets[cnt]['objectness'] == 0: + dets[k], dets[cnt] = dets[cnt], dets[k] + k = k - 1 + else: + cnt = cnt + 1 + total = k+1 for k in range(classes): for i in range(total): - s[i] = s[i]._replace(class_var=k) - s = sorted(s, key=lambda x: x.probs[x.index_var][x.class_var], reverse=True) + dets[i]['sort_class'] = k + dets[0:total] = sorted(dets[0:total], + key=cmp_to_key(nms_comparator), reverse=True) for i in range(total): - if probs[s[i].index_var][k] == 0: + if dets[i]['prob'][k] == 0: continue - a = boxes[s[i].index_var] + a = dets[i]['bbox'] for j in range(i+1, total): - b = boxes[s[j].index_var] + b = dets[j]['bbox'] if _box_iou(a, b) > thresh: - probs[s[j].index_var][k] = 0 - return boxes, probs + dets[j]['prob'][k] = 0 -def draw_detections(im, num, thresh, boxes, probs, names, classes): +def draw_detections(im, dets, thresh, names, classes): "Draw the markings around the detected region" - for i in range(num): + for det in dets: labelstr = [] category = -1 for j in range(classes): - if probs[i][j] > thresh: + if det['prob'][j] > thresh: if category == -1: category = j labelstr.append(names[j]) @@ -142,7 +169,7 @@ def draw_detections(im, num, thresh, boxes, probs, names, classes): green = _get_color(1, offset, classes) blue = _get_color(0, offset, classes) rgb = [red, green, blue] - b = boxes[i] + b = det['bbox'] left = int((b.x-b.w/2.)*imw) right = int((b.x+b.w/2.)*imw) top = int((b.y-b.h/2.)*imh) diff --git a/nnvm/tests/python/frontend/darknet/test_forward.py b/nnvm/tests/python/frontend/darknet/test_forward.py index 3d7d06b48..b1d5e7356 100644 --- a/nnvm/tests/python/frontend/darknet/test_forward.py +++ b/nnvm/tests/python/frontend/darknet/test_forward.py @@ -13,6 +13,7 @@ import numpy as np import tvm from tvm.contrib import graph_runtime from nnvm import frontend +from nnvm.testing.darknet import LAYERTYPE from nnvm.testing.darknet import __darknetffi__ import nnvm.compiler if sys.version_info >= (3,): @@ -50,14 +51,24 @@ DARKNETLIB_URL = 'https://github.com/siju-samuel/darknet/blob/master/lib/' \ _download(DARKNETLIB_URL, DARKNET_LIB) LIB = __darknetffi__.dlopen('./' + DARKNET_LIB) -def _get_tvm_output(net, data): +def _read_memory_buffer(shape, data, dtype='float32'): + length = 1 + for x in shape: + length *= x + data_np = np.zeros(length, dtype=dtype) + for i in range(length): + data_np[i] = data[i] + return data_np.reshape(shape) + +def _get_tvm_output(net, data, build_dtype='float32'): '''Compute TVM output''' dtype = 'float32' sym, params = frontend.darknet.from_darknet(net, dtype) target = 'llvm' shape_dict = {'data': data.shape} - graph, library, params = nnvm.compiler.build(sym, target, shape_dict, dtype, params=params) + graph, library, params = nnvm.compiler.build(sym, target, shape_dict, + build_dtype, params=params) # Execute on TVM ctx = tvm.cpu(0) m = graph_runtime.create(graph, library, ctx) @@ -66,14 +77,50 @@ def _get_tvm_output(net, data): m.set_input(**params) m.run() # get outputs - out_shape = (net.outputs,) - tvm_out = m.get_output(0, tvm.nd.empty(out_shape, dtype)).asnumpy() + tvm_out = [] + for i in range(m.get_num_outputs()): + tvm_out.append(m.get_output(i).asnumpy()) return tvm_out -def test_forward(net): +def test_forward(net, build_dtype='float32'): '''Test network with given input image on both darknet and tvm''' def get_darknet_output(net, img): - return LIB.network_predict_image(net, img) + LIB.network_predict_image(net, img) + out = [] + for i in range(net.n): + layer = net.layers[i] + if layer.type == LAYERTYPE.REGION: + attributes = np.array([layer.n, layer.out_c, layer.out_h, + layer.out_w, layer.classes, + layer.coords, layer.background], + dtype=np.int32) + out.insert(0, attributes) + out.insert(0, _read_memory_buffer((layer.n*2, ), layer.biases)) + layer_outshape = (layer.batch, layer.out_c, + layer.out_h, layer.out_w) + out.insert(0, _read_memory_buffer(layer_outshape, layer.output)) + elif layer.type == LAYERTYPE.YOLO: + attributes = np.array([layer.n, layer.out_c, layer.out_h, + layer.out_w, layer.classes, + layer.total], + dtype=np.int32) + 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.out_h, layer.out_w) + out.insert(0, _read_memory_buffer(layer_outshape, layer.output)) + elif i == net.n-1: + if layer.type == LAYERTYPE.CONNECTED: + darknet_outshape = (layer.batch, layer.out_c) + elif layer.type in [LAYERTYPE.SOFTMAX]: + darknet_outshape = (layer.batch, layer.outputs) + else: + darknet_outshape = (layer.batch, layer.out_c, + layer.out_h, layer.out_w) + out.insert(0, _read_memory_buffer(darknet_outshape, layer.output)) + return out + dtype = 'float32' test_image = 'dog.jpg' @@ -81,11 +128,7 @@ def test_forward(net): _download(img_url, test_image) img = LIB.letterbox_image(LIB.load_image_color(test_image.encode('utf-8'), 0, 0), net.w, net.h) darknet_output = get_darknet_output(net, img) - darknet_out = np.zeros(net.outputs, dtype='float32') - for i in range(net.outputs): - darknet_out[i] = darknet_output[i] batch_size = 1 - data = np.empty([batch_size, img.c, img.h, img.w], dtype) i = 0 for c in range(img.c): @@ -94,8 +137,9 @@ def test_forward(net): data[0][c][h][k] = img.data[i] i = i + 1 - tvm_out = _get_tvm_output(net, data) - np.testing.assert_allclose(darknet_out, tvm_out, rtol=1e-3, atol=1e-3) + tvm_out = _get_tvm_output(net, data, build_dtype) + for tvm_outs, darknet_out in zip(tvm_out, darknet_output): + np.testing.assert_allclose(darknet_out, tvm_outs, rtol=1e-3, atol=1e-3) def test_rnn_forward(net): '''Test network with given input data on both darknet and tvm''' @@ -106,11 +150,14 @@ def test_rnn_forward(net): np_arr = np.zeros([1, net.inputs], dtype='float32') np_arr[0, 84] = 1 cffi_arr = ffi.cast('float*', np_arr.ctypes.data) - tvm_out = _get_tvm_output(net, np_arr) + tvm_out = _get_tvm_output(net, np_arr)[0] darknet_output = get_darknet_network_predict(net, cffi_arr) darknet_out = np.zeros(net.outputs, dtype='float32') for i in range(net.outputs): darknet_out[i] = darknet_output[i] + last_layer = net.layers[net.n-1] + darknet_outshape = (last_layer.batch, last_layer.outputs) + darknet_out = darknet_out.reshape(darknet_outshape) np.testing.assert_allclose(darknet_out, tvm_out, rtol=1e-4, atol=1e-4) def test_forward_extraction(): @@ -152,8 +199,8 @@ def test_forward_resnet50(): test_forward(net) LIB.free_network(net) -def test_forward_yolo(): - '''test yolo model''' +def test_forward_yolov2(): + '''test yolov2 model''' model_name = 'yolov2' cfg_name = model_name + '.cfg' weights_name = model_name + '.weights' @@ -162,7 +209,22 @@ def test_forward_yolo(): _download(cfg_url, cfg_name) _download(weights_url, weights_name) net = LIB.load_network(cfg_name.encode('utf-8'), weights_name.encode('utf-8'), 0) - test_forward(net) + build_dtype = {} + test_forward(net, build_dtype) + LIB.free_network(net) + +def test_forward_yolov3(): + '''test yolov3 model''' + model_name = 'yolov3' + cfg_name = model_name + '.cfg' + weights_name = model_name + '.weights' + cfg_url = 'https://github.com/pjreddie/darknet/blob/master/cfg/' + cfg_name + '?raw=true' + weights_url = 'http://pjreddie.com/media/files/' + weights_name + '?raw=true' + _download(cfg_url, cfg_name) + _download(weights_url, weights_name) + net = LIB.load_network(cfg_name.encode('utf-8'), weights_name.encode('utf-8'), 0) + build_dtype = {} + test_forward(net, build_dtype) LIB.free_network(net) def test_forward_convolutional(): @@ -271,20 +333,21 @@ def test_forward_region(): net.layers[1] = layer_2 net.w = net.h = 224 LIB.resize_network(net, 224, 224) - test_forward(net) + build_dtype = {} + test_forward(net, build_dtype) LIB.free_network(net) def test_forward_yolo_op(): '''test yolo layer''' net = LIB.make_network(2) layer_1 = LIB.make_convolutional_layer(1, 224, 224, 3, 14, 1, 3, 2, 0, 1, 0, 0, 0, 0) - a = [] - layer_2 = LIB.make_yolo_layer(1, 111, 111, 2, 0, a, 2) + layer_2 = LIB.make_yolo_layer(1, 111, 111, 2, 9, __darknetffi__.NULL, 2) net.layers[0] = layer_1 net.layers[1] = layer_2 net.w = net.h = 224 LIB.resize_network(net, 224, 224) - test_forward(net) + build_dtype = {} + test_forward(net, build_dtype) LIB.free_network(net) def test_forward_upsample(): @@ -313,7 +376,7 @@ def test_forward_softmax(): '''test softmax layer''' net = LIB.make_network(1) layer_1 = LIB.make_softmax_layer(1, 75, 1) - layer_1.temperature=1 + layer_1.temperature = 1 net.layers[0] = layer_1 net.w = net.h = 5 LIB.resize_network(net, net.w, net.h) @@ -324,7 +387,7 @@ def test_forward_softmax_temperature(): '''test softmax layer''' net = LIB.make_network(1) layer_1 = LIB.make_softmax_layer(1, 75, 1) - layer_1.temperature=0.8 + layer_1.temperature = 0.8 net.layers[0] = layer_1 net.w = net.h = 5 LIB.resize_network(net, net.w, net.h) @@ -441,7 +504,8 @@ if __name__ == '__main__': test_forward_resnet50() test_forward_alexnet() test_forward_extraction() - test_forward_yolo() + test_forward_yolov2() + test_forward_yolov3() test_forward_convolutional() test_forward_maxpooling() test_forward_avgpooling() diff --git a/tutorials/nnvm/from_darknet.py b/tutorials/nnvm/from_darknet.py index 87ab60fc2..f0eec98c0 100644 --- a/tutorials/nnvm/from_darknet.py +++ b/tutorials/nnvm/from_darknet.py @@ -1,11 +1,11 @@ """ -Compile YOLO-V2 in DarkNet Models +Compile YOLO-V2 and YOLO-V3 in DarkNet Models ================================= **Author**: `Siju Samuel <https://siju-samuel.github.io/>`_ This article is an introductory tutorial to deploy darknet models with NNVM. All the required models and libraries will be downloaded from the internet by the script. -This script runs the YOLO-V2 Model with the bounding boxes +This script runs the YOLO-V2 and YOLO-V3 Model with the bounding boxes Darknet parsing have dependancy with CFFI and CV2 library Please install CFFI and CV2 before executing this script @@ -17,6 +17,7 @@ Please install CFFI and CV2 before executing this script import nnvm import nnvm.frontend.darknet +import nnvm.testing.yolo_detection import nnvm.testing.darknet import matplotlib.pyplot as plt import numpy as np @@ -28,7 +29,7 @@ from tvm.contrib.download import download from nnvm.testing.darknet import __darknetffi__ # Model name -MODEL_NAME = 'yolo' +MODEL_NAME = 'yolov3' ###################################################################### # Download required files @@ -75,9 +76,11 @@ ctx = tvm.cpu(0) data = np.empty([batch_size, net.c, net.h, net.w], dtype) shape = {'data': data.shape} print("Compiling the model...") +dtype_dict = {} with nnvm.compiler.build_config(opt_level=2): - graph, lib, params = nnvm.compiler.build(sym, target, shape, dtype, params) + graph, lib, params = nnvm.compiler.build(sym, target, shape, dtype_dict, params) +[neth, netw] = shape['data'][2:] # Current image shape is 608x608 ###################################################################### # Load a test image # -------------------------------------------------------------------- @@ -87,8 +90,7 @@ img_url = 'https://github.com/siju-samuel/darknet/blob/master/data/' + \ test_image + '?raw=true' download(img_url, test_image) -data = nnvm.testing.darknet.load_image(test_image, net.w, net.h) - +data = nnvm.testing.darknet.load_image(test_image, netw, neth) ###################################################################### # Execute on TVM Runtime # ---------------------- @@ -105,24 +107,44 @@ print("Running the test image...") m.run() # get outputs -out_shape = (net.outputs,) -tvm_out = m.get_output(0).asnumpy().flatten() +tvm_out = [] +if MODEL_NAME == 'yolov2': + layer_out = {} + layer_out['type'] = 'Region' + # Get the region layer attributes (n, out_c, out_h, out_w, classes, coords, background) + layer_attr = m.get_output(2).asnumpy() + layer_out['biases'] = m.get_output(1).asnumpy() + out_shape = (layer_attr[0], layer_attr[1]//layer_attr[0], + layer_attr[2], layer_attr[3]) + layer_out['output'] = m.get_output(0).asnumpy().reshape(out_shape) + layer_out['classes'] = layer_attr[4] + layer_out['coords'] = layer_attr[5] + layer_out['background'] = layer_attr[6] + tvm_out.append(layer_out) + +elif MODEL_NAME == 'yolov3': + for i in range(3): + layer_out = {} + layer_out['type'] = 'Yolo' + # Get the yolo layer attributes (n, out_c, out_h, out_w, classes, total) + layer_attr = m.get_output(i*4+3).asnumpy() + layer_out['biases'] = m.get_output(i*4+2).asnumpy() + layer_out['mask'] = m.get_output(i*4+1).asnumpy() + out_shape = (layer_attr[0], layer_attr[1]//layer_attr[0], + layer_attr[2], layer_attr[3]) + layer_out['output'] = m.get_output(i*4).asnumpy().reshape(out_shape) + layer_out['classes'] = layer_attr[4] + tvm_out.append(layer_out) # do the detection and bring up the bounding boxes -thresh = 0.24 -hier_thresh = 0.5 +thresh = 0.5 +nms_thresh = 0.45 img = nnvm.testing.darknet.load_image_color(test_image) _, im_h, im_w = img.shape -probs = [] -boxes = [] -region_layer = net.layers[net.n - 1] -boxes, probs = nnvm.testing.yolo2_detection.get_region_boxes( - region_layer, im_w, im_h, net.w, net.h, - thresh, probs, boxes, 1, tvm_out) - -boxes, probs = nnvm.testing.yolo2_detection.do_nms_sort( - boxes, probs, - region_layer.w*region_layer.h*region_layer.n, region_layer.classes, 0.3) +dets = nnvm.testing.yolo_detection.fill_network_boxes((netw, neth), (im_w, im_h), thresh, + 1, tvm_out) +last_layer = net.layers[net.n - 1] +nnvm.testing.yolo_detection.do_nms_sort(dets, last_layer.classes, nms_thresh) coco_name = 'coco.names' coco_url = 'https://github.com/siju-samuel/darknet/blob/master/data/' + coco_name + '?raw=true' @@ -136,8 +158,6 @@ with open(coco_name) as f: names = [x.strip() for x in content] -nnvm.testing.yolo2_detection.draw_detections( - img, region_layer.w*region_layer.h*region_layer.n, - thresh, boxes, probs, names, region_layer.classes) +nnvm.testing.yolo_detection.draw_detections(img, dets, thresh, names, last_layer.classes) plt.imshow(img.transpose(1, 2, 0)) plt.show() -- GitLab