Commit 84909181 by vincent

weight loading of quantized tiny-yolov2-seperable-conv2d + use separable conv…

weight loading of quantized tiny-yolov2-seperable-conv2d + use separable conv model by default + testcases
parent 4f45297b
...@@ -20,17 +20,17 @@ import { NetParams, PostProcessingParams, TinyYolov2ForwardParams } from './type ...@@ -20,17 +20,17 @@ import { NetParams, PostProcessingParams, TinyYolov2ForwardParams } from './type
export class TinyYolov2 extends NeuralNetwork<NetParams> { export class TinyYolov2 extends NeuralNetwork<NetParams> {
private _hasSeparableConvs: boolean private _withSeparableConvs: boolean
private _anchors: Point[] private _anchors: Point[]
constructor(hasSeparableConvs: boolean = false) { constructor(withSeparableConvs: boolean = true) {
super('TinyYolov2') super('TinyYolov2')
this._hasSeparableConvs = hasSeparableConvs this._withSeparableConvs = withSeparableConvs
this._anchors = hasSeparableConvs ? BOX_ANCHORS_SEPARABLE : BOX_ANCHORS this._anchors = withSeparableConvs ? BOX_ANCHORS_SEPARABLE : BOX_ANCHORS
} }
public get hasSeparableConvs(): boolean { public get withSeparableConvs(): boolean {
return this._hasSeparableConvs return this._withSeparableConvs
} }
public get anchors(): Point[] { public get anchors(): Point[] {
...@@ -48,7 +48,7 @@ export class TinyYolov2 extends NeuralNetwork<NetParams> { ...@@ -48,7 +48,7 @@ export class TinyYolov2 extends NeuralNetwork<NetParams> {
const out = tf.tidy(() => { const out = tf.tidy(() => {
let batchTensor = input.toBatchTensor(inputSize, false) let batchTensor = input.toBatchTensor(inputSize, false)
batchTensor = this.hasSeparableConvs batchTensor = this.withSeparableConvs
? normalize(batchTensor, MEAN_RGB) ? normalize(batchTensor, MEAN_RGB)
: batchTensor : batchTensor
batchTensor = batchTensor.div(tf.scalar(256)) as tf.Tensor4D batchTensor = batchTensor.div(tf.scalar(256)) as tf.Tensor4D
...@@ -132,7 +132,7 @@ export class TinyYolov2 extends NeuralNetwork<NetParams> { ...@@ -132,7 +132,7 @@ export class TinyYolov2 extends NeuralNetwork<NetParams> {
const numCells = outputTensor.shape[1] const numCells = outputTensor.shape[1]
const [boxesTensor, scoresTensor] = tf.tidy(() => { const [boxesTensor, scoresTensor] = tf.tidy(() => {
const reshaped = outputTensor.reshape([numCells, numCells, NUM_BOXES, this.hasSeparableConvs ? 5 : 6]) const reshaped = outputTensor.reshape([numCells, numCells, NUM_BOXES, this.withSeparableConvs ? 5 : 6])
const boxes = reshaped.slice([0, 0, 0, 0], [numCells, numCells, NUM_BOXES, 4]) const boxes = reshaped.slice([0, 0, 0, 0], [numCells, numCells, NUM_BOXES, 4])
const scores = reshaped.slice([0, 0, 0, 4], [numCells, numCells, NUM_BOXES, 1]) const scores = reshaped.slice([0, 0, 0, 4], [numCells, numCells, NUM_BOXES, 1])
...@@ -172,10 +172,10 @@ export class TinyYolov2 extends NeuralNetwork<NetParams> { ...@@ -172,10 +172,10 @@ export class TinyYolov2 extends NeuralNetwork<NetParams> {
} }
protected loadQuantizedParams(uri: string | undefined) { protected loadQuantizedParams(uri: string | undefined) {
return loadQuantizedParams(uri) return loadQuantizedParams(uri, this.withSeparableConvs)
} }
protected extractParams(weights: Float32Array) { protected extractParams(weights: Float32Array) {
return extractParams(weights, this.hasSeparableConvs) return extractParams(weights, this.withSeparableConvs)
} }
} }
\ No newline at end of file
...@@ -56,7 +56,7 @@ function extractorsFactory(extractWeights: ExtractWeightsFunction, paramMappings ...@@ -56,7 +56,7 @@ function extractorsFactory(extractWeights: ExtractWeightsFunction, paramMappings
} }
export function extractParams(weights: Float32Array, hasSeparableConvs: boolean): { params: NetParams, paramMappings: ParamMapping[] } { export function extractParams(weights: Float32Array, withSeparableConvs: boolean): { params: NetParams, paramMappings: ParamMapping[] } {
const { const {
extractWeights, extractWeights,
...@@ -71,8 +71,8 @@ export function extractParams(weights: Float32Array, hasSeparableConvs: boolean) ...@@ -71,8 +71,8 @@ export function extractParams(weights: Float32Array, hasSeparableConvs: boolean)
extractSeparableConvParams extractSeparableConvParams
} = extractorsFactory(extractWeights, paramMappings) } = extractorsFactory(extractWeights, paramMappings)
const extractConvFn = hasSeparableConvs ? extractSeparableConvParams : extractConvWithBatchNormParams const extractConvFn = withSeparableConvs ? extractSeparableConvParams : extractConvWithBatchNormParams
const numAnchorEncodings = hasSeparableConvs ? 5 : 6 const numAnchorEncodings = withSeparableConvs ? 5 : 6
const conv0 = extractConvFn(3, 16, 'conv0',) const conv0 = extractConvFn(3, 16, 'conv0',)
const conv1 = extractConvFn(16, 32, 'conv1') const conv1 = extractConvFn(16, 32, 'conv1')
......
...@@ -2,8 +2,8 @@ import { TinyYolov2 } from './TinyYolov2'; ...@@ -2,8 +2,8 @@ import { TinyYolov2 } from './TinyYolov2';
export * from './TinyYolov2'; export * from './TinyYolov2';
export function createTinyYolov2(weights: Float32Array) { export function createTinyYolov2(weights: Float32Array, withSeparableConvs: boolean = true) {
const net = new TinyYolov2() const net = new TinyYolov2(withSeparableConvs)
net.extractWeights(weights) net.extractWeights(weights)
return net return net
} }
\ No newline at end of file
...@@ -4,9 +4,10 @@ import { disposeUnusedWeightTensors } from '../commons/disposeUnusedWeightTensor ...@@ -4,9 +4,10 @@ import { disposeUnusedWeightTensors } from '../commons/disposeUnusedWeightTensor
import { extractWeightEntryFactory } from '../commons/extractWeightEntryFactory'; import { extractWeightEntryFactory } from '../commons/extractWeightEntryFactory';
import { loadWeightMap } from '../commons/loadWeightMap'; import { loadWeightMap } from '../commons/loadWeightMap';
import { ConvParams, ParamMapping } from '../commons/types'; import { ConvParams, ParamMapping } from '../commons/types';
import { BatchNorm, ConvWithBatchNorm, NetParams } from './types'; import { BatchNorm, ConvWithBatchNorm, NetParams, SeparableConvParams } from './types';
const DEFAULT_MODEL_NAME = 'tiny_yolov2_model' const DEFAULT_MODEL_NAME = 'tiny_yolov2_model'
const DEFAULT_MODEL_NAME_SEPARABLE_CONV = 'tiny_yolov2_separable_conv_model'
function extractorsFactory(weightMap: any, paramMappings: ParamMapping[]) { function extractorsFactory(weightMap: any, paramMappings: ParamMapping[]) {
...@@ -30,35 +31,51 @@ function extractorsFactory(weightMap: any, paramMappings: ParamMapping[]) { ...@@ -30,35 +31,51 @@ function extractorsFactory(weightMap: any, paramMappings: ParamMapping[]) {
return { conv, bn } return { conv, bn }
} }
function extractSeparableConvParams(prefix: string): SeparableConvParams {
const depthwise_filter = extractWeightEntry<tf.Tensor4D>(`${prefix}/depthwise_filter`, 4)
const pointwise_filter = extractWeightEntry<tf.Tensor4D>(`${prefix}/pointwise_filter`, 4)
const bias = extractWeightEntry<tf.Tensor1D>(`${prefix}/bias`, 1)
return new SeparableConvParams(
depthwise_filter,
pointwise_filter,
bias
)
}
return { return {
extractConvParams, extractConvParams,
extractConvWithBatchNormParams extractConvWithBatchNormParams,
extractSeparableConvParams
} }
} }
export async function loadQuantizedParams( export async function loadQuantizedParams(
uri: string | undefined uri: string | undefined,
withSeparableConvs: boolean
): Promise<{ params: NetParams, paramMappings: ParamMapping[] }> { ): Promise<{ params: NetParams, paramMappings: ParamMapping[] }> {
const weightMap = await loadWeightMap(uri, DEFAULT_MODEL_NAME) const weightMap = await loadWeightMap(uri, withSeparableConvs ? DEFAULT_MODEL_NAME_SEPARABLE_CONV : DEFAULT_MODEL_NAME)
const paramMappings: ParamMapping[] = [] const paramMappings: ParamMapping[] = []
const { const {
extractConvParams, extractConvParams,
extractConvWithBatchNormParams extractConvWithBatchNormParams,
extractSeparableConvParams
} = extractorsFactory(weightMap, paramMappings) } = extractorsFactory(weightMap, paramMappings)
const extractConvFn = withSeparableConvs ? extractSeparableConvParams : extractConvWithBatchNormParams
const params = { const params = {
conv0: extractConvWithBatchNormParams('conv0'), conv0: extractConvFn('conv0'),
conv1: extractConvWithBatchNormParams('conv1'), conv1: extractConvFn('conv1'),
conv2: extractConvWithBatchNormParams('conv2'), conv2: extractConvFn('conv2'),
conv3: extractConvWithBatchNormParams('conv3'), conv3: extractConvFn('conv3'),
conv4: extractConvWithBatchNormParams('conv4'), conv4: extractConvFn('conv4'),
conv5: extractConvWithBatchNormParams('conv5'), conv5: extractConvFn('conv5'),
conv6: extractConvWithBatchNormParams('conv6'), conv6: extractConvFn('conv6'),
conv7: extractConvWithBatchNormParams('conv7'), conv7: extractConvFn('conv7'),
conv8: extractConvParams('conv8') conv8: extractConvParams('conv8')
} }
......
...@@ -29,6 +29,15 @@ export const expectedTinyYolov2Boxes = [ ...@@ -29,6 +29,15 @@ export const expectedTinyYolov2Boxes = [
{ x: 87, y: 30, width: 92, height: 93 } { x: 87, y: 30, width: 92, height: 93 }
] ]
export const expectedTinyYolov2SeparableConvBoxes = [
{ x: 42, y: 257, width: 111, height: 121 },
{ x: 454, y: 175, width: 104, height: 121 },
{ x: 230, y: 45, width: 94, height: 104 },
{ x: 574, y: 62, width: 88, height: 113 },
{ x: 260, y: 233, width: 82, height: 104 },
{ x: 83, y: 24, width: 85, height: 111 }
]
export const expectedMtcnnFaceLandmarks = [ export const expectedMtcnnFaceLandmarks = [
[new Point(117, 58), new Point(156, 63), new Point(141, 86), new Point(109, 98), new Point(147, 104)], [new Point(117, 58), new Point(156, 63), new Point(141, 86), new Point(109, 98), new Point(147, 104)],
[new Point(82, 292), new Point(134, 304), new Point(104, 330), new Point(72, 342), new Point(120, 353)], [new Point(82, 292), new Point(134, 304), new Point(104, 330), new Point(72, 342), new Point(120, 353)],
...@@ -38,7 +47,6 @@ export const expectedMtcnnFaceLandmarks = [ ...@@ -38,7 +47,6 @@ export const expectedMtcnnFaceLandmarks = [
[new Point(489, 224), new Point(534, 223), new Point(507, 250), new Point(493, 271), new Point(530, 270)] [new Point(489, 224), new Point(534, 223), new Point(507, 250), new Point(493, 271), new Point(530, 270)]
] ]
export function expectMtcnnResults( export function expectMtcnnResults(
results: { faceDetection: faceapi.FaceDetection, faceLandmarks: faceapi.FaceLandmarks5 }[], results: { faceDetection: faceapi.FaceDetection, faceLandmarks: faceapi.FaceLandmarks5 }[],
boxOrder: number[], boxOrder: number[],
......
...@@ -5,8 +5,7 @@ import * as faceapi from '../src/'; ...@@ -5,8 +5,7 @@ import * as faceapi from '../src/';
import { NeuralNetwork } from '../src/commons/NeuralNetwork'; import { NeuralNetwork } from '../src/commons/NeuralNetwork';
import { IPoint } from '../src/'; import { IPoint } from '../src/';
import { allFacesFactory, allFacesMtcnnFactory } from '../src/allFacesFactory'; import { allFacesFactory, allFacesMtcnnFactory } from '../src/allFacesFactory';
import { allFacesMtcnnFunction, allFacesFunction, tinyYolov2 } from '../src/globalApi'; import { allFacesMtcnnFunction, allFacesFunction } from '../src/globalApi';
import { TinyYolov2 } from '../src/tinyYolov2/TinyYolov2';
export function zeros(length: number): Float32Array { export function zeros(length: number): Float32Array {
return new Float32Array(length) return new Float32Array(length)
...@@ -55,6 +54,10 @@ export type WithNetOptions = { ...@@ -55,6 +54,10 @@ export type WithNetOptions = {
quantized?: boolean quantized?: boolean
} }
export type WithTinyYolov2Options = WithNetOptions & {
withSeparableConv?: boolean
}
export type InjectNetArgs = { export type InjectNetArgs = {
allFaces: allFacesFunction allFaces: allFacesFunction
allFacesMtcnn: allFacesMtcnnFunction allFacesMtcnn: allFacesMtcnnFunction
...@@ -73,7 +76,7 @@ export type DescribeWithNetsOptions = { ...@@ -73,7 +76,7 @@ export type DescribeWithNetsOptions = {
withFaceLandmarkNet?: WithNetOptions withFaceLandmarkNet?: WithNetOptions
withFaceRecognitionNet?: WithNetOptions withFaceRecognitionNet?: WithNetOptions
withMtcnn?: WithNetOptions withMtcnn?: WithNetOptions
withTinyYolov2?: WithNetOptions withTinyYolov2?: WithTinyYolov2Options
} }
async function loadNetWeights(uri: string): Promise<Float32Array> { async function loadNetWeights(uri: string): Promise<Float32Array> {
...@@ -102,7 +105,7 @@ export function describeWithNets( ...@@ -102,7 +105,7 @@ export function describeWithNets(
let faceLandmarkNet: faceapi.FaceLandmarkNet = new faceapi.FaceLandmarkNet() let faceLandmarkNet: faceapi.FaceLandmarkNet = new faceapi.FaceLandmarkNet()
let faceRecognitionNet: faceapi.FaceRecognitionNet = new faceapi.FaceRecognitionNet() let faceRecognitionNet: faceapi.FaceRecognitionNet = new faceapi.FaceRecognitionNet()
let mtcnn: faceapi.Mtcnn = new faceapi.Mtcnn() let mtcnn: faceapi.Mtcnn = new faceapi.Mtcnn()
let tinyYolov2: faceapi.TinyYolov2 = new faceapi.TinyYolov2() let tinyYolov2: faceapi.TinyYolov2 = new faceapi.TinyYolov2(options.withTinyYolov2 && options.withTinyYolov2.withSeparableConv)
let allFaces = allFacesFactory(faceDetectionNet, faceLandmarkNet, faceRecognitionNet) let allFaces = allFacesFactory(faceDetectionNet, faceLandmarkNet, faceRecognitionNet)
let allFacesMtcnn = allFacesMtcnnFactory(mtcnn, faceRecognitionNet) let allFacesMtcnn = allFacesMtcnnFactory(mtcnn, faceRecognitionNet)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment