Skip to content

Commit 19836c1

Browse files
copy contents of tfjs-image-recognition-base to face-api.js + remove dependency
1 parent dd5cfcb commit 19836c1

File tree

181 files changed

+3886
-413
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

181 files changed

+3886
-413
lines changed

karma.conf.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ const dataFiles = [
22
'test/images/*.jpg',
33
'test/images/*.png',
44
'test/data/*.json',
5+
'test/data/*.weights',
56
'test/media/*.mp4',
67
'weights/**/*',
78
'weights_uncompressed/**/*',

package-lock.json

Lines changed: 3 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@
4040
"license": "MIT",
4141
"dependencies": {
4242
"@tensorflow/tfjs-core": "1.2.9",
43-
"tfjs-image-recognition-base": "^0.6.2",
4443
"tslib": "^1.10.0"
4544
},
4645
"devDependencies": {

src/NeuralNetwork.ts

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
import * as tf from '@tensorflow/tfjs-core';
2+
3+
import { ParamMapping } from './common';
4+
import { getModelUris } from './common/getModelUris';
5+
import { loadWeightMap } from './dom';
6+
import { env } from './env';
7+
8+
export abstract class NeuralNetwork<TNetParams> {
9+
10+
protected _params: TNetParams | undefined = undefined
11+
protected _paramMappings: ParamMapping[] = []
12+
13+
constructor(protected _name: string) {}
14+
15+
public get params(): TNetParams | undefined { return this._params }
16+
public get paramMappings(): ParamMapping[] { return this._paramMappings }
17+
public get isLoaded(): boolean { return !!this.params }
18+
19+
public getParamFromPath(paramPath: string): tf.Tensor {
20+
const { obj, objProp } = this.traversePropertyPath(paramPath)
21+
return obj[objProp]
22+
}
23+
24+
public reassignParamFromPath(paramPath: string, tensor: tf.Tensor) {
25+
const { obj, objProp } = this.traversePropertyPath(paramPath)
26+
obj[objProp].dispose()
27+
obj[objProp] = tensor
28+
}
29+
30+
public getParamList() {
31+
return this._paramMappings.map(({ paramPath }) => ({
32+
path: paramPath,
33+
tensor: this.getParamFromPath(paramPath)
34+
}))
35+
}
36+
37+
public getTrainableParams() {
38+
return this.getParamList().filter(param => param.tensor instanceof tf.Variable)
39+
}
40+
41+
public getFrozenParams() {
42+
return this.getParamList().filter(param => !(param.tensor instanceof tf.Variable))
43+
}
44+
45+
public variable() {
46+
this.getFrozenParams().forEach(({ path, tensor }) => {
47+
this.reassignParamFromPath(path, tensor.variable())
48+
})
49+
}
50+
51+
public freeze() {
52+
this.getTrainableParams().forEach(({ path, tensor: variable }) => {
53+
const tensor = tf.tensor(variable.dataSync())
54+
variable.dispose()
55+
this.reassignParamFromPath(path, tensor)
56+
})
57+
}
58+
59+
public dispose(throwOnRedispose: boolean = true) {
60+
this.getParamList().forEach(param => {
61+
if (throwOnRedispose && param.tensor.isDisposed) {
62+
throw new Error(`param tensor has already been disposed for path ${param.path}`)
63+
}
64+
param.tensor.dispose()
65+
})
66+
this._params = undefined
67+
}
68+
69+
public serializeParams(): Float32Array {
70+
return new Float32Array(
71+
this.getParamList()
72+
.map(({ tensor }) => Array.from(tensor.dataSync()) as number[])
73+
.reduce((flat, arr) => flat.concat(arr))
74+
)
75+
}
76+
77+
public async load(weightsOrUrl: Float32Array | string | undefined): Promise<void> {
78+
if (weightsOrUrl instanceof Float32Array) {
79+
this.extractWeights(weightsOrUrl)
80+
return
81+
}
82+
83+
await this.loadFromUri(weightsOrUrl)
84+
}
85+
86+
public async loadFromUri(uri: string | undefined) {
87+
if (uri && typeof uri !== 'string') {
88+
throw new Error(`${this._name}.loadFromUri - expected model uri`)
89+
}
90+
91+
const weightMap = await loadWeightMap(uri, this.getDefaultModelName())
92+
this.loadFromWeightMap(weightMap)
93+
}
94+
95+
public async loadFromDisk(filePath: string | undefined) {
96+
if (filePath && typeof filePath !== 'string') {
97+
throw new Error(`${this._name}.loadFromDisk - expected model file path`)
98+
}
99+
100+
const { readFile } = env.getEnv()
101+
102+
const { manifestUri, modelBaseUri } = getModelUris(filePath, this.getDefaultModelName())
103+
104+
const fetchWeightsFromDisk = (filePaths: string[]) => Promise.all(
105+
filePaths.map(filePath => readFile(filePath).then(buf => buf.buffer))
106+
)
107+
const loadWeights = tf.io.weightsLoaderFactory(fetchWeightsFromDisk)
108+
109+
const manifest = JSON.parse((await readFile(manifestUri)).toString())
110+
const weightMap = await loadWeights(manifest, modelBaseUri)
111+
112+
this.loadFromWeightMap(weightMap)
113+
}
114+
115+
public loadFromWeightMap(weightMap: tf.NamedTensorMap) {
116+
const {
117+
paramMappings,
118+
params
119+
} = this.extractParamsFromWeigthMap(weightMap)
120+
121+
this._paramMappings = paramMappings
122+
this._params = params
123+
}
124+
125+
public extractWeights(weights: Float32Array) {
126+
const {
127+
paramMappings,
128+
params
129+
} = this.extractParams(weights)
130+
131+
this._paramMappings = paramMappings
132+
this._params = params
133+
}
134+
135+
private traversePropertyPath(paramPath: string) {
136+
if (!this.params) {
137+
throw new Error(`traversePropertyPath - model has no loaded params`)
138+
}
139+
140+
const result = paramPath.split('/').reduce((res: { nextObj: any, obj?: any, objProp?: string }, objProp) => {
141+
if (!res.nextObj.hasOwnProperty(objProp)) {
142+
throw new Error(`traversePropertyPath - object does not have property ${objProp}, for path ${paramPath}`)
143+
}
144+
145+
return { obj: res.nextObj, objProp, nextObj: res.nextObj[objProp] }
146+
}, { nextObj: this.params })
147+
148+
const { obj, objProp } = result
149+
if (!obj || !objProp || !(obj[objProp] instanceof tf.Tensor)) {
150+
throw new Error(`traversePropertyPath - parameter is not a tensor, for path ${paramPath}`)
151+
}
152+
153+
return { obj, objProp }
154+
}
155+
156+
protected abstract getDefaultModelName(): string
157+
protected abstract extractParamsFromWeigthMap(weightMap: tf.NamedTensorMap): { params: TNetParams, paramMappings: ParamMapping[] }
158+
protected abstract extractParams(weights: Float32Array): { params: TNetParams, paramMappings: ParamMapping[] }
159+
}

src/ageGenderNet/AgeGenderNet.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import * as tf from '@tensorflow/tfjs-core';
2-
import { NetInput, NeuralNetwork, TNetInput, toNetInput } from 'tfjs-image-recognition-base';
32

43
import { fullyConnectedLayer } from '../common/fullyConnectedLayer';
54
import { seperateWeightMaps } from '../faceProcessor/util';
65
import { TinyXception } from '../xception/TinyXception';
76
import { extractParams } from './extractParams';
87
import { extractParamsFromWeigthMap } from './extractParamsFromWeigthMap';
98
import { AgeAndGenderPrediction, Gender, NetOutput, NetParams } from './types';
9+
import { NeuralNetwork } from '../NeuralNetwork';
10+
import { NetInput, TNetInput, toNetInput } from '../dom';
1011

1112
export class AgeGenderNet extends NeuralNetwork<NetParams> {
1213

src/ageGenderNet/extractParams.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,16 @@
1-
import { TfjsImageRecognitionBase } from 'tfjs-image-recognition-base';
2-
1+
import { extractFCParamsFactory, extractWeightsFactory, ParamMapping } from '../common';
32
import { NetParams } from './types';
43

5-
export function extractParams(weights: Float32Array): { params: NetParams, paramMappings: TfjsImageRecognitionBase.ParamMapping[] } {
4+
export function extractParams(weights: Float32Array): { params: NetParams, paramMappings: ParamMapping[] } {
65

7-
const paramMappings: TfjsImageRecognitionBase.ParamMapping[] = []
6+
const paramMappings: ParamMapping[] = []
87

98
const {
109
extractWeights,
1110
getRemainingWeights
12-
} = TfjsImageRecognitionBase.extractWeightsFactory(weights)
11+
} = extractWeightsFactory(weights)
1312

14-
const extractFCParams = TfjsImageRecognitionBase.extractFCParamsFactory(extractWeights, paramMappings)
13+
const extractFCParams = extractFCParamsFactory(extractWeights, paramMappings)
1514

1615
const age = extractFCParams(512, 1, 'fc/age')
1716
const gender = extractFCParams(512, 2, 'fc/gender')
Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
import * as tf from '@tensorflow/tfjs-core';
2-
import { TfjsImageRecognitionBase } from 'tfjs-image-recognition-base';
32

3+
import { disposeUnusedWeightTensors, extractWeightEntryFactory, FCParams, ParamMapping } from '../common';
44
import { NetParams } from './types';
55

66
export function extractParamsFromWeigthMap(
77
weightMap: tf.NamedTensorMap
8-
): { params: NetParams, paramMappings: TfjsImageRecognitionBase.ParamMapping[] } {
8+
): { params: NetParams, paramMappings: ParamMapping[] } {
99

10-
const paramMappings: TfjsImageRecognitionBase.ParamMapping[] = []
10+
const paramMappings: ParamMapping[] = []
1111

12-
const extractWeightEntry = TfjsImageRecognitionBase.extractWeightEntryFactory(weightMap, paramMappings)
12+
const extractWeightEntry = extractWeightEntryFactory(weightMap, paramMappings)
1313

14-
function extractFcParams(prefix: string): TfjsImageRecognitionBase.FCParams {
14+
function extractFcParams(prefix: string): FCParams {
1515
const weights = extractWeightEntry<tf.Tensor2D>(`${prefix}/weights`, 2)
1616
const bias = extractWeightEntry<tf.Tensor1D>(`${prefix}/bias`, 1)
1717
return { weights, bias }
@@ -24,7 +24,7 @@ export function extractParamsFromWeigthMap(
2424
}
2525
}
2626

27-
TfjsImageRecognitionBase.disposeUnusedWeightTensors(weightMap, paramMappings)
27+
disposeUnusedWeightTensors(weightMap, paramMappings)
2828

2929
return { params, paramMappings }
3030
}

src/ageGenderNet/types.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import * as tf from '@tensorflow/tfjs-core';
2-
import { TfjsImageRecognitionBase } from 'tfjs-image-recognition-base';
2+
3+
import { FCParams } from '../common';
34

45
export type AgeAndGenderPrediction = {
56
age: number
@@ -16,7 +17,7 @@ export type NetOutput = { age: tf.Tensor1D, gender: tf.Tensor2D }
1617

1718
export type NetParams = {
1819
fc: {
19-
age: TfjsImageRecognitionBase.FCParams
20-
gender: TfjsImageRecognitionBase.FCParams
20+
age: FCParams
21+
gender: FCParams
2122
}
2223
}

src/classes/BoundingBox.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { Box } from './Box';
2+
3+
export interface IBoundingBox {
4+
left: number
5+
top: number
6+
right: number
7+
bottom: number
8+
}
9+
10+
export class BoundingBox extends Box<BoundingBox> implements IBoundingBox {
11+
constructor(left: number, top: number, right: number, bottom: number, allowNegativeDimensions: boolean = false) {
12+
super({ left, top, right, bottom }, allowNegativeDimensions)
13+
}
14+
}

0 commit comments

Comments
 (0)