Skip to content

Commit 4695c1b

Browse files
1 parent 5b8bb8c commit 4695c1b

24 files changed

+248
-112
lines changed

.travis.yml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
sudo: required
2+
language: node_js
3+
node_js:
4+
- "10"
5+
env:
6+
- BACKEND_CPU=true EXCLUDE_UNCOMPRESSED=true
7+
before_script:
8+
- wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add -
9+
- sudo sh -c 'echo "deb http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list'
10+
- sudo apt-get update
11+
- sudo apt-get install google-chrome-stable
12+
- export DISPLAY=:99.0
13+
- sh -e /etc/init.d/xvfb start
14+
script:
15+
- npm run test-travis
16+
- npm install
17+
- npm run build

karma.conf.js

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,21 +14,35 @@ const dataFiles = [
1414
nocache: false
1515
}))
1616

17-
const exclude = process.env.UUT
18-
? [
19-
'dom',
20-
'faceLandmarkNet',
21-
'faceRecognitionNet',
22-
'ssdMobilenetv1',
23-
'tinyFaceDetector',
24-
'mtcnn',
25-
'tinyYolov2'
26-
]
17+
let exclude = (
18+
process.env.UUT
19+
? [
20+
'dom',
21+
'faceLandmarkNet',
22+
'faceRecognitionNet',
23+
'ssdMobilenetv1',
24+
'tinyFaceDetector',
25+
'mtcnn',
26+
'tinyYolov2'
27+
]
28+
: ['tinyYolov2']
29+
)
2730
.filter(ex => ex !== process.env.UUT)
2831
.map(ex => `test/tests/${ex}/*.ts`)
29-
: []
32+
33+
34+
exclude = exclude.concat(
35+
process.env.EXCLUDE_UNCOMPRESSED
36+
? ['**/*.uncompressed.test.ts']
37+
: []
38+
)
3039

3140
module.exports = function(config) {
41+
const args = []
42+
if (process.env.BACKEND_CPU) {
43+
args.push('backend_cpu')
44+
}
45+
3246
config.set({
3347
frameworks: ['jasmine', 'karma-typescript'],
3448
files: [
@@ -44,10 +58,13 @@ module.exports = function(config) {
4458
},
4559
browsers: ['Chrome'],
4660
browserNoActivityTimeout: 120000,
61+
browserDisconnectTolerance: 3,
62+
browserDisconnectTimeout : 120000,
4763
captureTimeout: 60000,
4864
client: {
4965
jasmine: {
50-
timeoutInterval: 60000
66+
timeoutInterval: 60000,
67+
args
5168
}
5269
}
5370
})

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818
"test-tinyfacedetector": "set UUT=tinyFaceDetector&& karma start",
1919
"test-mtcnn": "set UUT=mtcnn&& karma start",
2020
"test-tinyyolov2": "set UUT=tinyYolov2&& karma start",
21+
"test-cpu": "set BACKEND_CPU=true&& karma start",
22+
"test-exclude-uncompressed": "set EXCLUDE_UNCOMPRESSED=true&& karma start",
23+
"test-travis": "karma start --single-run",
2124
"docs": "typedoc --options ./typedoc.config.js ./src"
2225
},
2326
"keywords": [

test/expectFaceDetections.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ export function expectFaceDetections(
66
results: FaceDetection[],
77
allExpectedFaceDetections: IRect[],
88
expectedScores: number[],
9+
maxScoreDelta: number,
910
maxBoxDelta: number
1011
) {
1112

@@ -20,7 +21,7 @@ export function expectFaceDetections(
2021

2122
expectedDetections.forEach((expectedDetection, i) => {
2223
const det = sortedResults[i]
23-
expect(det.score).toBeCloseTo(expectedDetection.score, 2)
24+
expect(Math.abs(det.score - expectedDetection.score)).toBeLessThan(maxScoreDelta)
2425
expectRectClose(det.box, expectedDetection, maxBoxDelta)
2526
})
2627
}

test/expectFaceDetectionsWithLandmarks.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { FaceLandmarks68 } from '../src/classes/FaceLandmarks68';
44
import { ExpectedFaceDetectionWithLandmarks, expectPointClose, expectRectClose, sortByFaceDetection } from './utils';
55

66
export type BoxAndLandmarksDeltas = {
7+
maxScoreDelta: number
78
maxBoxDelta: number
89
maxLandmarksDelta: number
910
}
@@ -26,7 +27,7 @@ export function expectFaceDetectionsWithLandmarks<TFaceLandmarks extends FaceLan
2627

2728
expectedFullFaceDescriptions.forEach((expected, i) => {
2829
const { detection, landmarks } = sortedResults[i]
29-
expect(detection.score).toBeCloseTo(expected.score, 2)
30+
expect(Math.abs(detection.score - expected.score)).toBeLessThan(deltas.maxScoreDelta)
3031
expectRectClose(detection.box, expected.detection, deltas.maxBoxDelta)
3132
landmarks.positions.forEach((pt, j) => expectPointClose(pt, expected.landmarks[j], deltas.maxLandmarksDelta))
3233
})

test/expectFullFaceDescriptions.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ export function expectFullFaceDescriptions(
2525

2626
expectedFullFaceDescriptions.forEach((expected, i) => {
2727
const { detection, landmarks, descriptor } = sortedResults[i]
28-
expect(detection.score).toBeCloseTo(expected.score, 2)
28+
expect(detection.score - expected.score).toBeLessThan(deltas.maxScoreDelta)
2929
expectRectClose(detection.box, expected.detection, deltas.maxBoxDelta)
3030
landmarks.positions.forEach((pt, j) => expectPointClose(pt, expected.landmarks[j], deltas.maxLandmarksDelta))
3131
expect(euclideanDistance(descriptor, expected.descriptor)).toBeLessThan(deltas.maxDescriptorDelta)

test/tests/faceLandmarkNet/faceLandmark68Net.test.ts

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ describe('faceLandmark68Net', () => {
6464

6565
})
6666

67-
describeWithNets('batch inputs', { withFaceLandmark68Net: { quantized: false } }, ({ faceLandmark68Net }) => {
67+
describeWithNets('batch inputs', { withFaceLandmark68Net: { quantized: true } }, ({ faceLandmark68Net }) => {
6868

6969
it('computes face landmarks for batch of image elements', async () => {
7070
const inputs = [imgEl1, imgEl2, imgElRect]
@@ -145,19 +145,6 @@ describe('faceLandmark68Net', () => {
145145

146146
describeWithNets('no memory leaks', { withFaceLandmark68Net: { quantized: true } }, ({ faceLandmark68Net }) => {
147147

148-
describe('NeuralNetwork, uncompressed model', () => {
149-
150-
it('disposes all param tensors', async () => {
151-
await expectAllTensorsReleased(async () => {
152-
const res = await fetch('base/weights_uncompressed/face_landmark_68_model.weights')
153-
const weights = new Float32Array(await res.arrayBuffer())
154-
const net = createFaceLandmarkNet(weights)
155-
net.dispose()
156-
})
157-
})
158-
159-
})
160-
161148
describe('NeuralNetwork, quantized model', () => {
162149

163150
it('disposes all param tensors', async () => {

test/tests/faceLandmarkNet/faceLandmark68Net.uncompressed.test.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { fetchImage, fetchJson, Point } from '../../../src';
22
import { FaceLandmarks68 } from '../../../src/classes/FaceLandmarks68';
3-
import { describeWithNets, expectPointClose } from '../../utils';
3+
import { createFaceLandmarkNet } from '../../../src/faceLandmarkNet';
4+
import { describeWithNets, expectAllTensorsReleased, expectPointClose } from '../../utils';
45

56
describe('faceLandmark68Net, uncompressed', () => {
67

@@ -46,6 +47,15 @@ describe('faceLandmark68Net, uncompressed', () => {
4647
})
4748
})
4849

50+
it('no memory leaks', async () => {
51+
await expectAllTensorsReleased(async () => {
52+
const res = await fetch('base/weights_uncompressed/face_landmark_68_model.weights')
53+
const weights = new Float32Array(await res.arrayBuffer())
54+
const net = createFaceLandmarkNet(weights)
55+
net.dispose()
56+
})
57+
})
58+
4959
})
5060

5161
})

test/tests/faceLandmarkNet/faceLandmark68TinyNet.test.ts

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -145,19 +145,6 @@ describe('faceLandmark68TinyNet', () => {
145145

146146
describeWithNets('no memory leaks', { withFaceLandmark68TinyNet: { quantized: true } }, ({ faceLandmark68TinyNet }) => {
147147

148-
describe('NeuralNetwork, uncompressed model', () => {
149-
150-
it('disposes all param tensors', async () => {
151-
await expectAllTensorsReleased(async () => {
152-
const res = await fetch('base/weights_uncompressed/face_landmark_68_model.weights')
153-
const weights = new Float32Array(await res.arrayBuffer())
154-
const net = createFaceLandmarkNet(weights)
155-
net.dispose()
156-
})
157-
})
158-
159-
})
160-
161148
describe('NeuralNetwork, quantized model', () => {
162149

163150
it('disposes all param tensors', async () => {

test/tests/faceLandmarkNet/faceLandmark68TinyNet.uncompressed.test.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { fetchImage, fetchJson, Point } from '../../../src';
22
import { FaceLandmarks68 } from '../../../src/classes/FaceLandmarks68';
3-
import { describeWithNets, expectPointClose } from '../../utils';
3+
import { createFaceLandmarkNet } from '../../../src/faceLandmarkNet';
4+
import { describeWithNets, expectAllTensorsReleased, expectPointClose } from '../../utils';
45

56
describe('faceLandmark68TinyNet, uncompressed', () => {
67

@@ -46,6 +47,15 @@ describe('faceLandmark68TinyNet, uncompressed', () => {
4647
})
4748
})
4849

50+
it('no memory leaks', async () => {
51+
await expectAllTensorsReleased(async () => {
52+
const res = await fetch('base/weights_uncompressed/face_landmark_68_model.weights')
53+
const weights = new Float32Array(await res.arrayBuffer())
54+
const net = createFaceLandmarkNet(weights)
55+
net.dispose()
56+
})
57+
})
58+
4959
})
5060

5161
})

test/tests/faceRecognitionNet/faceRecognitionNet.test.ts

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import * as tf from '@tensorflow/tfjs-core';
22

33
import { FaceRecognitionNet, fetchImage, fetchJson, NetInput, toNetInput } from '../../../src';
44
import { euclideanDistance } from '../../../src/euclideanDistance';
5-
import { createFaceRecognitionNet } from '../../../src/faceRecognitionNet';
65
import { describeWithNets, expectAllTensorsReleased } from '../../utils';
76

87
describe('faceRecognitionNet', () => {
@@ -97,19 +96,6 @@ describe('faceRecognitionNet', () => {
9796

9897
describeWithNets('no memory leaks', { withFaceRecognitionNet: { quantized: true } }, ({ faceRecognitionNet }) => {
9998

100-
describe('NeuralNetwork, uncompressed model', () => {
101-
102-
it('disposes all param tensors', async () => {
103-
await expectAllTensorsReleased(async () => {
104-
const res = await fetch('base/weights_uncompressed/face_recognition_model.weights')
105-
const weights = new Float32Array(await res.arrayBuffer())
106-
const net = createFaceRecognitionNet(weights)
107-
net.dispose()
108-
})
109-
})
110-
111-
})
112-
11399
describe('NeuralNetwork, quantized model', () => {
114100

115101
it('disposes all param tensors', async () => {

test/tests/faceRecognitionNet/faceRecognitionNet.uncompressed.test.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { fetchImage, fetchJson } from '../../../src';
22
import { euclideanDistance } from '../../../src/euclideanDistance';
3-
import { describeWithNets } from '../../utils';
3+
import { createFaceRecognitionNet } from '../../../src/faceRecognitionNet';
4+
import { describeWithNets, expectAllTensorsReleased } from '../../utils';
45

56
describe('faceRecognitionNet, uncompressed', () => {
67

@@ -30,5 +31,14 @@ describe('faceRecognitionNet, uncompressed', () => {
3031
expect(euclideanDistance(result, faceDescriptorRect)).toBeLessThan(0.1)
3132
})
3233

34+
it('no memory leaks', async () => {
35+
await expectAllTensorsReleased(async () => {
36+
const res = await fetch('base/weights_uncompressed/face_recognition_model.weights')
37+
const weights = new Float32Array(await res.arrayBuffer())
38+
const net = createFaceRecognitionNet(weights)
39+
net.dispose()
40+
})
41+
})
42+
3343
})
3444
})

test/tests/mtcnn/mtcnn.forward.test.ts

Lines changed: 11 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ describe('mtcnn.forward', () => {
1313
expectedMtcnnLandmarks = await fetchJson<IPoint[][]>('base/test/data/mtcnnFaceLandmarkPositions.json')
1414
})
1515

16-
describeWithNets('uncompressed weights', { withMtcnn: { quantized: false } }, ({ mtcnn }) => {
17-
16+
// "quantized" actually means loaded from manifest.json, since there is no quantization applied to the mtcnn model
17+
describeWithNets('quantized weights', { withMtcnn: { quantized: true } }, ({ mtcnn }) => {
1818

1919
it('minFaceSize = 20, finds all faces', async () => {
2020
const forwardParams = {
@@ -25,6 +25,7 @@ describe('mtcnn.forward', () => {
2525
expect(results.length).toEqual(6)
2626

2727
const deltas = {
28+
maxScoreDelta: 0.01,
2829
maxBoxDelta: 2,
2930
maxLandmarksDelta: 5
3031
}
@@ -40,6 +41,7 @@ describe('mtcnn.forward', () => {
4041

4142
expect(results.length).toEqual(6)
4243
const deltas = {
44+
maxScoreDelta: 0.01,
4345
maxBoxDelta: 15,
4446
maxLandmarksDelta: 13
4547
}
@@ -58,6 +60,7 @@ describe('mtcnn.forward', () => {
5860
expect(results.length).toEqual(6)
5961

6062
const deltas = {
63+
maxScoreDelta: 0.01,
6164
maxBoxDelta: 8,
6265
maxLandmarksDelta: 7
6366
}
@@ -73,39 +76,19 @@ describe('mtcnn.forward', () => {
7376
expect(results.length).toEqual(6)
7477

7578
const deltas = {
79+
maxScoreDelta: 0.01,
7680
maxBoxDelta: 8,
7781
maxLandmarksDelta: 10
7882
}
7983
expectMtcnnResults(results, expectedMtcnnLandmarks, [1.0, 1.0, 1.0, 1.0, 1.0, 1.0], deltas)
8084
})
8185

82-
})
83-
84-
describe('no memory leaks', () => {
85-
86-
describe('NeuralNetwork, uncompressed model', () => {
87-
88-
it('disposes all param tensors', async () => {
89-
await expectAllTensorsReleased(async () => {
90-
const res = await fetch('base/weights_uncompressed/mtcnn_model.weights')
91-
const weights = new Float32Array(await res.arrayBuffer())
92-
const net = faceapi.createMtcnn(weights)
93-
net.dispose()
94-
})
86+
it('no memory leaks', async () => {
87+
await expectAllTensorsReleased(async () => {
88+
const net = new faceapi.Mtcnn()
89+
await net.load('base/weights')
90+
net.dispose()
9591
})
96-
97-
})
98-
99-
describe('NeuralNetwork, quantized model', () => {
100-
101-
it('disposes all param tensors', async () => {
102-
await expectAllTensorsReleased(async () => {
103-
const net = new faceapi.Mtcnn()
104-
await net.load('base/weights')
105-
net.dispose()
106-
})
107-
})
108-
10992
})
11093

11194
})

0 commit comments

Comments
 (0)