8000 Boost Haar feature calculation for meeting training and real-time inference request by WeiChungChang · Pull Request #4399 · scikit-image/scikit-image · GitHub
[go: up one dir, main page]

Skip to content

Boost Haar feature calculation for meeting training and real-time inference request #4399

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

Open
wants to merge 9 commits into
base: main
Choose a base branch
from

Conversation

WeiChungChang
Copy link
Contributor
@WeiChungChang WeiChungChang commented Jan 16, 2020

Description

[Purpose]

  1. Propose x300~x1000 speedup when calculating Haar feature.
  2. Propose new Pytest procedure for Haar feature.
  3. Correct Haar feature bug.

[Summarize current issues]

We summarize current issues here first.

Image of Yaktocat

  1. common issues
    1.as fix boundary condition when calculating Haar features #4076
    2.as sample code shows.
    3.Currently pytest only has limited & fixed test patterns.
  2. issues when inference
    1.as 1.2.
    2.too slow when inference.
  3. issues when train
    1.too slow when train.

We give a classification of how Haar feature will be applied for common use cases.
Image of classfication

For inference, assume we have trained a model to detect human face by detection window = 24 * 24.
Given an image, ex 640*480, we will

  1. create an image pyramid in order to capture different size human face.
  2. apply detect algorithm, ex well-known Viola-Jones algorithm.
  3. Usually an algorithm with cascade filters will perform much better. For an image of cascade algorithm with Haar feature, after passing the first several classifiers, some regions are filtered out so they will be skipped at following stages. However, for filters at initial stage, we need to apply them to all legal detection window (may have stride, ex: move 2 pixels every step).

This figure shows the original image and the places having strong response for first stage.
Image of example

This figure shows the candidate windows after the first stage. The black holes have been filtered out as they are possibly NOT as human faces.
Image of example

This figure shows typical inference flow of cascaded classifiers when doing inference.
Assume we have trained a set of features which work well.
At 1st(initial) stage, we apply the set of features to all detection window. The purpose is to discard as many regions where seems to have no faces within it as possible.
At 2nd(refine) stage, the inputs now are blocks survive from initial classifier. We apply the set of features within it to refine the result.
The procedures keep on going until we have reached the output (final) classifier where all identified results are output.
Current implementation is good for refine classifiers with few blocks but very slow and hard to be used at initial classifiers. Also, Current implementation has bug in detection window.
Image of example

To understand why "current implementation has bug in detection window."
Please refer to the sample code here:

'''
    File name: verify_detection_window.py
    Author: WeiChung Chang (cweichun@amazon.com)
    Date created: 01/10/2020
    Date last modified:
    Python Version: 3.5
'''
import numpy as np
from skimage.transform import integral_image
from skimage.feature import haar_like_feature

train_raw_data =  np.array([
							[1, 2, 3],
							[3, 2, 1]
							])

img_ii = integral_image(train_raw_data)
h = img_ii.shape[0]
w = img_ii.shape[1]
wh = 2
ww = 2

print('integral img = \n', img_ii)

res  = haar_like_feature(img_ii, 0, 0, w, h, np.array(['type-2-x']))
print('res = ', res)

for j in range(0, h-wh + 1):
	for i in range(0, w-ww + 1):
		res  = haar_like_feature(img_ii, j, i, ww, wh, np.array(['type-2-x']))
		print('detection window offset: x = ', i, 'y = ', j, ' res = ', res)

the result shows:

integral img = 
 [[ 1  3  6]
 [ 4  8 12]]
res =  [ 1  0  1  0 -1 -1]
detection window offset: x =  0 y =  0  res =  [ 1  0 -1]
detection window offset: x =  1 y =  0  res =  [ 0 -4 -4]

Notice that the answer should be  [ 1  0  1  0 -1 -1].
However by applying detection window, the result is [1, 0, -1, 0, -4, -4]
The problem is with offset (x=1, y=0), current flow calculates result from partial integral image as below.
[3, 6]
[8, 12]
The partial integral image with wrong padding will create wrong answer.
Image of example
please check the figure above; for 1st detection window it is correct.
For 2nd detection window, notice current padding values are of all zeros. However, we should pad with the actual neighboring values accordingly.

[Algorithm description]
There are two algorithms here to boost speed.
1. apply numpy matrix operation to replace calculate individual feature respectively.
2. apply the algorithm to assemble feature map to save calculation.

We explain the algorithms in this section.

This figure outlines in this proposal where the speedup comes from.
Image of example
Reference: https://californiaconsultants.org/wp-content/uploads/2018/04/CNSV-1806-Patterson.pdf
page 37

This figure shows the fast algorithm of:

  1. operate based on matrix.
  2. reduce # of operations by assemble feature
    Image of example

[Performance]
The experiment shows ~ x50 speedup compared to current method for calculating all features of a single frame by 25x25.
Image of example

The experiment shows ~ x250 speedup compared to current method for calculating all features of a batch consists of 10 frames by 25x25.
Image of example

The experiment shows ~ x1000 speedup compared to current method for calculating all features of a batch consists of 500 frames by 25x25.
Image of example

For training with large batch (typically training need more than ten thousands images), it implies, originally we need 1~2 days to complete the calculation of all features but now can be done within 10 minutes.

[To be done]

  1. Please help review the APIs first. Since there are a lot of changes, once an initial review is done so we finalize the APIs, I will fill create Docstrings accordingly.
  2. A Benchmark is expected to be given before 2020/01/30
  3. The initial Benchmark is given here for checking the effect (to be done later).

Checklist

For reviewers

  • Check that the PR title is short, concise, and will make sense 1 year
    later.
  • Check that new functions are imported in corresponding __init__.py.
  • Check that new features, API changes, and deprecations are mentioned in
    doc/release/release_dev.rst.
  • Consider backporting the PR with @meeseeksdev backport to v0.14.x

2. Propose new Pytest procedure for Haar feature
3. Correct Haar feature bug
@pep8speaks
Copy link
pep8speaks commented Jan 16, 2020

Hello @WeiChungChang! Thanks for updating this PR. We checked the lines you've touched for PEP 8 issues, and found:

There are currently no PEP 8 issues detected in this Pull Request. Cheers! 🍻

Comment last updated at 2020-09-03 03:54:49 UTC

h_l = self.__pad_h - basic_dim[0]
w_l = self.__pad_w - basic_dim[1]
if direction == 'h' or direction == 'd':
basic_fmap =
Copy link
Member

Choose a reason for hiding this comment

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

the syntax is invalid here (missing parenthesis or line continuation), causing the tests to fail.

Copy link
Member
@hmaarrfk hmaarrfk left a comment

Choose a reason for hiding this comment

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

Hey just a few small comments.

Looks like a large amount of code. Are you in a position to give scikit-image a license or will we always have to attribute Amazon?

(Sigh, github seems to wait until all comments are completed. on the phone it isn't always obivous that this is happening, sorry for not pushing send on this before.)

}

def pad_zeros_to_imgs(imgs):
l= len(imgs.shape)
Copy link
Member

Choose a reason for hiding this comment

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

See ndim or ndims


def integral_array_horizontal(imgs):
l= len(imgs.shape)
r = np.zeros(imgs.shape)
Copy link
Member

Choose a reason for hiding this comment

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

This declaration is actually never used

def integral_array_vertical(imgs):
l= len(imgs.shape)
r = np.zeros(imgs.shape)
if l == 3 or l == 4: # "NHW" or "NHWC"
Copy link
Member

Choose a reason for hiding this comment

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

Again, this allocation is never used


def __init__(self, label):
self.__children = []
self.__start = 0
Copy link
Member

Choose a reason for hiding this comment

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

I think double underscores have done name mangling features l. Do you want to use them? If not, please use single underscore

b3_rb = [coord[0] + h - 1, coord[1] + w - 1]
return [[b1_lt, b1_rb], [b2_lt, b2_rb], [b3_lt, b3_rb]]

def __cal_type_4_coord(coord, assem_pat):
Copy link
Member

Choose a reason for hiding this comment

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

Is this supposed to be a static method? If not, why not use the self name?

@@ -0,0 +1,232 @@
# File name: test_haar_new.py
# Contributor: Amazon Lab126 Multimedia team
8000 Copy link
Member

Choose a reason for hiding this comment

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

Are these tests compatible with the old haar features? If so, maybe it makes sense to have them in a seperate PR so as to enable a distinc review for these additions?

Base automatically changed from master to main February 18, 2021 18:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants
0