From 4ebdee27c75dbf9cb0eb76f628542a1ac5d9f828 Mon Sep 17 00:00:00 2001 From: Alexander Yermolovich Date: Fri, 5 Apr 2019 17:46:51 -0700 Subject: [PATCH 1/3] ONNX doesn't support extract image patch, but does support spaceToDepth. For this special case they are equivalent. --- darkflow/net/ops/convolution.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/darkflow/net/ops/convolution.py b/darkflow/net/ops/convolution.py index 167b0fd78..d25626eeb 100644 --- a/darkflow/net/ops/convolution.py +++ b/darkflow/net/ops/convolution.py @@ -24,8 +24,8 @@ def _forward(self): def forward(self): inp = self.inp.out s = self.lay.stride - self.out = tf.extract_image_patches( - inp, [1,s,s,1], [1,s,s,1], [1,1,1,1], 'VALID') + self.out = tf.space_to_depth( + inp, s, 'VALID') def speak(self): args = [self.lay.stride] * 2 From 0ad4bff88f4c359e8f19d9d2c6f7c03fde30108a Mon Sep 17 00:00:00 2001 From: Alexander Yermolovich Date: Wed, 25 Sep 2019 12:37:19 -0700 Subject: [PATCH 2/3] Added fusedBatch. --- darkflow/net/ops/convolution.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/darkflow/net/ops/convolution.py b/darkflow/net/ops/convolution.py index d25626eeb..0336ec8ef 100644 --- a/darkflow/net/ops/convolution.py +++ b/darkflow/net/ops/convolution.py @@ -2,6 +2,7 @@ from .baseop import BaseOp import tensorflow as tf import numpy as np +import math class reorg(BaseOp): def _forward(self): @@ -75,17 +76,22 @@ def forward(self): def batchnorm(self, layer, inp): if not self.var: - temp = (inp - layer.w['moving_mean']) - temp /= (np.sqrt(layer.w['moving_variance']) + 1e-5) - temp *= layer.w['gamma'] - return temp + tensor, mean, variance = tf.nn.fused_batch_norm(inp, + layer.w['gamma'], + np.zeros([np.size(layer.w['gamma'])], dtype=np.float32), + mean=layer.w['moving_mean'], + variance = layer.w['moving_variance'], + epsilon= 1e-5, + is_training=False) + return tensor; else: args = dict({ 'center' : False, 'scale' : True, 'epsilon': 1e-5, 'scope' : self.scope, 'updates_collections' : None, 'is_training': layer.h['is_training'], - 'param_initializers': layer.w + 'param_initializers': layer.w, + 'fused' : True }) return slim.batch_norm(inp, **args) From 631ad9f7af47c295dd56d898a7dcf3e1003982ea Mon Sep 17 00:00:00 2001 From: Alexander Yermolovich Date: Fri, 10 Jan 2020 13:39:02 -0800 Subject: [PATCH 3/3] Added basic layers so that Yolo V3 can be saved as TF. Still won't be able to run it, since post processing is different. --- darkflow/dark/darkop.py | 12 +++++++++++- darkflow/net/ops/__init__.py | 5 ++++- darkflow/net/ops/simple.py | 30 ++++++++++++++++++++++++++++++ darkflow/utils/process.py | 11 +++++++++++ 4 files changed, 56 insertions(+), 2 deletions(-) diff --git a/darkflow/dark/darkop.py b/darkflow/dark/darkop.py index bcde00a12..8e9464309 100644 --- a/darkflow/dark/darkop.py +++ b/darkflow/dark/darkop.py @@ -34,6 +34,14 @@ class reorg_layer(Layer): def setup(self, stride): self.stride = stride +class shortcut_layer(Layer): + def setup(self, frmLayer): + self.frmLayer = frmLayer + +class upsample_layer(Layer): + def setup(self, strd): + self.strd = strd + """ Darkop Factory """ @@ -52,7 +60,9 @@ def setup(self, stride): 'reorg': reorg_layer, 'conv-select': conv_select_layer, 'conv-extract': conv_extract_layer, - 'extract': extract_layer + 'extract': extract_layer, + 'shortcut' : shortcut_layer, + 'upsample' : upsample_layer, } def create_darkop(ltype, num, *args): diff --git a/darkflow/net/ops/__init__.py b/darkflow/net/ops/__init__.py index d687cb3dc..27ea9a802 100644 --- a/darkflow/net/ops/__init__.py +++ b/darkflow/net/ops/__init__.py @@ -19,7 +19,10 @@ 'route': route, 'reorg': reorg, 'conv-extract': conv_extract, - 'extract': extract + 'extract': extract, + 'shortcut' : shortcut, + 'yolo' : yolo, + 'upsample' : upsample, } def op_create(*args): diff --git a/darkflow/net/ops/simple.py b/darkflow/net/ops/simple.py index 01e28ced6..873131f88 100644 --- a/darkflow/net/ops/simple.py +++ b/darkflow/net/ops/simple.py @@ -131,3 +131,33 @@ class identity(BaseOp): def __init__(self, inp): self.inp = None self.out = inp + +class shortcut(BaseOp): + def forward(self): + inp = self.inp.out + frm = self.lay.frmLayer + this = self.inp + while this.lay.number != frm: + this = this.inp + assert this is not None, \ + 'Shortcut to non-existence {}'.format(frm) + self.out = inp + this.out + + def speak(self): return 'shortcut' + +class yolo(BaseOp): + def forward(self): + inp = self.inp.out + self.out = inp + + def speak(self): return 'yolo' + +class upsample(BaseOp): + def forward(self): + inp = self.inp.out + strd = self.lay.strd + shape = inp.get_shape() + inp = tf.image.resize_nearest_neighbor(inp, (shape[1] * strd, shape[2] * strd)) + self.out = inp + + def speak(self): return 'upsample' \ No newline at end of file diff --git a/darkflow/utils/process.py b/darkflow/utils/process.py index 0836f4873..ec1e5c991 100644 --- a/darkflow/utils/process.py +++ b/darkflow/utils/process.py @@ -312,6 +312,17 @@ def cfg_yielder(model, binary): c = c * (stride ** 2) l = w * h * c #----------------------------------------------------- + elif d['type'] == '[shortcut]': + frm = d['from'] + yield ['shortcut', i, i + frm] + elif d['type'] == '[yolo]': + yield ['yolo', i] + elif d['type'] == '[upsample]': + strd = d['stride'] + ly = layers[i] + h *= strd + w *= strd + yield ['upsample', i, strd] else: exit('Layer {} not implemented'.format(d['type']))