Commit 91ad7ab0 by vincent

allow loading of quantized weights + quantized face landmark model

parent 9db970d6
import * as tf from '@tensorflow/tfjs-core';
export declare function isTensor(tensor: tf.Tensor, dim: number): boolean;
export declare function isTensor1D(tensor: tf.Tensor): boolean;
export declare function isTensor2D(tensor: tf.Tensor): boolean;
export declare function isTensor3D(tensor: tf.Tensor): boolean;
export declare function isTensor4D(tensor: tf.Tensor): boolean;
import * as tf from '@tensorflow/tfjs-core';
export function isTensor(tensor, dim) {
return tensor instanceof tf.Tensor && tensor.shape.length === dim;
}
export function isTensor1D(tensor) {
return isTensor(tensor, 1);
}
export function isTensor2D(tensor) {
return isTensor(tensor, 2);
}
export function isTensor3D(tensor) {
return isTensor(tensor, 3);
}
export function isTensor4D(tensor) {
return isTensor(tensor, 4);
}
//# sourceMappingURL=isTensor.js.map
\ No newline at end of file
{"version":3,"file":"isTensor.js","sourceRoot":"","sources":["../../src/commons/isTensor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAE5C,MAAM,mBAAmB,MAAiB,EAAE,GAAW;IACrD,OAAO,MAAM,YAAY,EAAE,CAAC,MAAM,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,KAAK,GAAG,CAAA;AACnE,CAAC;AAED,MAAM,qBAAqB,MAAiB;IAC1C,OAAO,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,CAAA;AAC5B,CAAC;AAED,MAAM,qBAAqB,MAAiB;IAC1C,OAAO,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,CAAA;AAC5B,CAAC;AAED,MAAM,qBAAqB,MAAiB;IAC1C,OAAO,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,CAAA;AAC5B,CAAC;AAED,MAAM,qBAAqB,MAAiB;IAC1C,OAAO,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,CAAA;AAC5B,CAAC"}
\ No newline at end of file
export declare function getModelUris(uri: string | undefined, defaultModelName: string): {
manifestUri: string;
modelBaseUri: string;
};
export declare function loadWeightMap(uri: string | undefined, defaultModelName: string): Promise<any>;
import * as tslib_1 from "tslib";
import * as tf from '@tensorflow/tfjs-core';
export function getModelUris(uri, defaultModelName) {
var parts = (uri || '').split('/');
var modelBaseUri = ((uri || '').endsWith('.json')
? parts.slice(0, parts.length - 1)
: parts).filter(function (s) { return s; }).join('/');
var defaultManifestFilename = defaultModelName + "-weights_manifest.json";
var manifestUri = !uri || !modelBaseUri
? defaultManifestFilename
: (uri.endsWith('.json')
? uri
: modelBaseUri + "/" + defaultManifestFilename);
return { manifestUri: manifestUri, modelBaseUri: modelBaseUri };
}
export function loadWeightMap(uri, defaultModelName) {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var _a, manifestUri, modelBaseUri, manifest;
return tslib_1.__generator(this, function (_b) {
switch (_b.label) {
case 0:
_a = getModelUris(uri, defaultModelName), manifestUri = _a.manifestUri, modelBaseUri = _a.modelBaseUri;
return [4 /*yield*/, fetch(manifestUri)];
case 1: return [4 /*yield*/, (_b.sent()).json()];
case 2:
manifest = _b.sent();
return [2 /*return*/, tf.io.loadWeights(manifest, modelBaseUri)];
}
});
});
}
//# sourceMappingURL=loadWeightMap.js.map
\ No newline at end of file
{"version":3,"file":"loadWeightMap.js","sourceRoot":"","sources":["../../src/commons/loadWeightMap.ts"],"names":[],"mappings":";AAAA,OAAO,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAE5C,MAAM,uBAAuB,GAAuB,EAAE,gBAAwB;IAC5E,IAAM,KAAK,GAAG,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;IAEpC,IAAM,YAAY,GAAG,CACnB,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC;QAC3B,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;QAClC,CAAC,CAAC,KAAK,CACV,CAAC,MAAM,CAAC,UAAA,CAAC,IAAI,OAAA,CAAC,EAAD,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IAE1B,IAAM,uBAAuB,GAAM,gBAAgB,2BAAwB,CAAA;IAC3E,IAAM,WAAW,GAAG,CAAC,GAAG,IAAI,CAAC,YAAY;QACvC,CAAC,CAAC,uBAAuB;QACzB,CAAC,CAAC,CACA,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC;YACnB,CAAC,CAAC,GAAG;YACL,CAAC,CAAI,YAAY,SAAI,uBAAyB,CACjD,CAAA;IAEH,OAAO,EAAE,WAAW,aAAA,EAAE,YAAY,cAAA,EAAE,CAAA;AACtC,CAAC;AAED,MAAM,wBACJ,GAAuB,EACvB,gBAAwB;;;;;;oBAGlB,KAAgC,YAAY,CAAC,GAAG,EAAE,gBAAgB,CAAC,EAAjE,WAAW,iBAAA,EAAE,YAAY,kBAAA,CAAwC;oBAEjD,qBAAM,KAAK,CAAC,WAAW,CAAC,EAAA;wBAA/B,qBAAM,CAAC,SAAwB,CAAC,CAAC,IAAI,EAAE,EAAA;;oBAAlD,QAAQ,GAAG,SAAuC;oBAExD,sBAAO,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,QAAQ,EAAE,YAAY,CAAC,EAAA;;;;CACjD"}
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
import * as tf from '@tensorflow/tfjs-core';
import { NetInput } from '../NetInput';
import { TNetInput } from '../types';
import { FaceLandmarks } from './FaceLandmarks';
export declare class FaceLandmarkNet {
private _params;
load(weightsOrUrl: Float32Array | string | undefined): Promise<void>;
extractWeights(weights: Float32Array): void;
detectLandmarks(input: tf.Tensor | NetInput | TNetInput): Promise<FaceLandmarks>;
}
import * as tslib_1 from "tslib";
import * as tf from '@tensorflow/tfjs-core';
import { convLayer } from '../commons/convLayer';
import { getImageTensor } from '../getImageTensor';
import { Point } from '../Point';
import { extractParams } from './extractParams';
import { FaceLandmarks } from './FaceLandmarks';
import { fullyConnectedLayer } from './fullyConnectedLayer';
import { loadQuantizedParams } from './loadQuantizedParams';
function conv(x, params) {
return convLayer(x, params, 'valid', true);
}
function maxPool(x, strides) {
if (strides === void 0) { strides = [2, 2]; }
return tf.maxPool(x, [2, 2], strides, 'valid');
}
var FaceLandmarkNet = /** @class */ (function () {
function FaceLandmarkNet() {
}
FaceLandmarkNet.prototype.load = function (weightsOrUrl) {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var _a;
return tslib_1.__generator(this, function (_b) {
switch (_b.label) {
case 0:
if (weightsOrUrl instanceof Float32Array) {
this.extractWeights(weightsOrUrl);
return [2 /*return*/];
}
if (weightsOrUrl && typeof weightsOrUrl !== 'string') {
throw new Error('FaceLandmarkNet.load - expected model uri, or weights as Float32Array');
}
_a = this;
return [4 /*yield*/, loadQuantizedParams(weightsOrUrl)];
case 1:
_a._params = _b.sent();
return [2 /*return*/];
}
});
});
};
FaceLandmarkNet.prototype.extractWeights = function (weights) {
this._params = extractParams(weights);
};
FaceLandmarkNet.prototype.detectLandmarks = function (input) {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var _this = this;
var imageDimensions, outTensor, faceLandmarksArray, _a, _b, xCoords, yCoords;
return tslib_1.__generator(this, function (_c) {
switch (_c.label) {
case 0:
if (!this._params) {
throw new Error('FaceLandmarkNet - load model before inference');
}
outTensor = tf.tidy(function () {
var params = _this._params;
var imgTensor = getImageTensor(input);
var _a = imgTensor.shape.slice(1), height = _a[0], width = _a[1];
imageDimensions = { width: width, height: height };
// work with 128 x 128 sized face images
if (imgTensor.shape[1] !== 128 || imgTensor.shape[2] !== 128) {
imgTensor = tf.image.resizeBilinear(imgTensor, [128, 128]);
}
var out = conv(imgTensor, params.conv0_params);
out = maxPool(out);
out = conv(out, params.conv1_params);
out = conv(out, params.conv2_params);
out = maxPool(out);
out = conv(out, params.conv3_params);
out = conv(out, params.conv4_params);
out = maxPool(out);
out = conv(out, params.conv5_params);
out = conv(out, params.conv6_params);
out = maxPool(out, [1, 1]);
out = conv(out, params.conv7_params);
var fc0 = tf.relu(fullyConnectedLayer(out.as2D(out.shape[0], -1), params.fc0_params));
var fc1 = fullyConnectedLayer(fc0, params.fc1_params);
return fc1;
});
_b = (_a = Array).from;
return [4 /*yield*/, outTensor.data()];
case 1:
faceLandmarksArray = _b.apply(_a, [_c.sent()]);
outTensor.dispose();
xCoords = faceLandmarksArray.filter(function (c, i) { return (i - 1) % 2; });
yCoords = faceLandmarksArray.filter(function (c, i) { return i % 2; });
return [2 /*return*/, new FaceLandmarks(Array(68).fill(0).map(function (_, i) { return new Point(xCoords[i], yCoords[i]); }), imageDimensions)];
}
});
});
};
return FaceLandmarkNet;
}());
export { FaceLandmarkNet };
//# sourceMappingURL=FaceLandmarkNet.js.map
\ No newline at end of file
{"version":3,"file":"FaceLandmarkNet.js","sourceRoot":"","sources":["../../src/faceLandmarkNet/FaceLandmarkNet.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
import { FaceLandmarkNet } from './types';
export declare function extractParams(weights: Float32Array): FaceLandmarkNet.NetParams;
import { NetParams } from './types';
export declare function extractParams(weights: Float32Array): NetParams;
import * as tf from '@tensorflow/tfjs-core';
import { FaceLandmarkNet } from './types';
export declare function fullyConnectedLayer(x: tf.Tensor2D, params: FaceLandmarkNet.FCParams): tf.Tensor2D;
import { FCParams } from './types';
export declare function fullyConnectedLayer(x: tf.Tensor2D, params: FCParams): tf.Tensor2D;
{"version":3,"file":"fullyConnectedLayer.js","sourceRoot":"","sources":["../../src/faceLandmarkNet/fullyConnectedLayer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAI5C,MAAM,8BACJ,CAAc,EACd,MAAgC;IAEhC,OAAO,EAAE,CAAC,IAAI,CAAC;QACb,OAAA,EAAE,CAAC,GAAG,CACJ,EAAE,CAAC,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC,EAC5B,MAAM,CAAC,IAAI,CACZ;IAHD,CAGC,CACF,CAAA;AACH,CAAC"}
\ No newline at end of file
{"version":3,"file":"fullyConnectedLayer.js","sourceRoot":"","sources":["../../src/faceLandmarkNet/fullyConnectedLayer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAI5C,MAAM,8BACJ,CAAc,EACd,MAAgB;IAEhB,OAAO,EAAE,CAAC,IAAI,CAAC;QACb,OAAA,EAAE,CAAC,GAAG,CACJ,EAAE,CAAC,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC,EAC5B,MAAM,CAAC,IAAI,CACZ;IAHD,CAGC,CACF,CAAA;AACH,CAAC"}
\ No newline at end of file
import * as tf from '@tensorflow/tfjs-core';
import { NetInput } from '../NetInput';
import { FaceLandmarks } from './FaceLandmarks';
export declare function faceLandmarkNet(weights: Float32Array): {
detectLandmarks: (input: string | HTMLCanvasElement | HTMLImageElement | HTMLVideoElement | (string | HTMLCanvasElement | HTMLImageElement | HTMLVideoElement)[] | tf.Tensor<tf.Rank> | NetInput) => Promise<FaceLandmarks>;
};
import { FaceLandmarkNet } from './FaceLandmarkNet';
export * from './FaceLandmarkNet';
export declare function faceLandmarkNet(weights: Float32Array): FaceLandmarkNet;
import * as tslib_1 from "tslib";
import * as tf from '@tensorflow/tfjs-core';
import { convLayer } from '../commons/convLayer';
import { getImageTensor } from '../getImageTensor';
import { Point } from '../Point';
import { extractParams } from './extractParams';
import { FaceLandmarks } from './FaceLandmarks';
import { fullyConnectedLayer } from './fullyConnectedLayer';
function conv(x, params) {
return convLayer(x, params, 'valid', true);
}
function maxPool(x, strides) {
if (strides === void 0) { strides = [2, 2]; }
return tf.maxPool(x, [2, 2], strides, 'valid');
}
import { FaceLandmarkNet } from './FaceLandmarkNet';
export * from './FaceLandmarkNet';
export function faceLandmarkNet(weights) {
var params = extractParams(weights);
function detectLandmarks(input) {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var imageDimensions, outTensor, faceLandmarksArray, _a, _b, xCoords, yCoords;
return tslib_1.__generator(this, function (_c) {
switch (_c.label) {
case 0:
outTensor = tf.tidy(function () {
var imgTensor = getImageTensor(input);
var _a = imgTensor.shape.slice(1), height = _a[0], width = _a[1];
imageDimensions = { width: width, height: height };
// work with 128 x 128 sized face images
if (imgTensor.shape[1] !== 128 || imgTensor.shape[2] !== 128) {
imgTensor = tf.image.resizeBilinear(imgTensor, [128, 128]);
}
var out = conv(imgTensor, params.conv0_params);
out = maxPool(out);
out = conv(out, params.conv1_params);
out = conv(out, params.conv2_params);
out = maxPool(out);
out = conv(out, params.conv3_params);
out = conv(out, params.conv4_params);
out = maxPool(out);
out = conv(out, params.conv5_params);
out = conv(out, params.conv6_params);
out = maxPool(out, [1, 1]);
out = conv(out, params.conv7_params);
var fc0 = tf.relu(fullyConnectedLayer(out.as2D(out.shape[0], -1), params.fc0_params));
var fc1 = fullyConnectedLayer(fc0, params.fc1_params);
return fc1;
});
_b = (_a = Array).from;
return [4 /*yield*/, outTensor.data()];
case 1:
faceLandmarksArray = _b.apply(_a, [_c.sent()]);
outTensor.dispose();
xCoords = faceLandmarksArray.filter(function (c, i) { return (i - 1) % 2; });
yCoords = faceLandmarksArray.filter(function (c, i) { return i % 2; });
return [2 /*return*/, new FaceLandmarks(Array(68).fill(0).map(function (_, i) { return new Point(xCoords[i], yCoords[i]); }), imageDimensions)];
}
});
});
}
return {
detectLandmarks: detectLandmarks
};
var faceLandmarkNet = new FaceLandmarkNet();
faceLandmarkNet.extractWeights(weights);
return faceLandmarkNet;
}
//# sourceMappingURL=index.js.map
\ No newline at end of file
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/faceLandmarkNet/index.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/faceLandmarkNet/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD,cAAc,mBAAmB,CAAC;AAElC,MAAM,0BAA0B,OAAqB;IACnD,IAAM,eAAe,GAAG,IAAI,eAAe,EAAE,CAAA;IAC7C,eAAe,CAAC,cAAc,CAAC,OAAO,CAAC,CAAA;IACvC,OAAO,eAAe,CAAA;AACxB,CAAC"}
\ No newline at end of file
import { NetParams } from './types';
export declare function loadQuantizedParams(uri: string | undefined): Promise<NetParams>;
import * as tslib_1 from "tslib";
import { loadWeightMap } from '../commons/loadWeightMap';
import { isTensor4D, isTensor1D, isTensor2D } from '../commons/isTensor';
var DEFAULT_MODEL_NAME = 'face_landmark_68_model';
export function loadQuantizedParams(uri) {
return tslib_1.__awaiter(this, void 0, void 0, function () {
function extractConvParams(prefix) {
var params = {
filters: weightMap[prefix + "/kernel"],
bias: weightMap[prefix + "/bias"]
};
if (!isTensor4D(params.filters)) {
throw new Error("expected weightMap[" + prefix + "/kernel] to be a Tensor4D, instead have " + params.filters);
}
if (!isTensor1D(params.bias)) {
throw new Error("expected weightMap[" + prefix + "/bias] to be a Tensor1D, instead have " + params.bias);
}
return params;
}
function extractFcParams(prefix) {
var params = {
weights: weightMap[prefix + "/kernel"],
bias: weightMap[prefix + "/bias"]
};
if (!isTensor2D(params.weights)) {
throw new Error("expected weightMap[" + prefix + "/kernel] to be a Tensor2D, instead have " + params.weights);
}
if (!isTensor1D(params.bias)) {
throw new Error("expected weightMap[" + prefix + "/bias] to be a Tensor1D, instead have " + params.bias);
}
return params;
}
var weightMap;
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, loadWeightMap(uri, DEFAULT_MODEL_NAME)];
case 1:
weightMap = _a.sent();
return [2 /*return*/, {
conv0_params: extractConvParams('conv2d_0'),
conv1_params: extractConvParams('conv2d_1'),
conv2_params: extractConvParams('conv2d_2'),
conv3_params: extractConvParams('conv2d_3'),
conv4_params: extractConvParams('conv2d_4'),
conv5_params: extractConvParams('conv2d_5'),
conv6_params: extractConvParams('conv2d_6'),
conv7_params: extractConvParams('conv2d_7'),
fc0_params: extractFcParams('dense'),
fc1_params: extractFcParams('logits')
}];
}
});
});
}
//# sourceMappingURL=loadQuantizedParams.js.map
\ No newline at end of file
{"version":3,"file":"loadQuantizedParams.js","sourceRoot":"","sources":["../../src/faceLandmarkNet/loadQuantizedParams.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAGzD,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEzE,IAAM,kBAAkB,GAAG,wBAAwB,CAAA;AAEnD,MAAM,8BAAoC,GAAuB;;QAG/D,2BAA2B,MAAc;YACvC,IAAM,MAAM,GAAG;gBACb,OAAO,EAAE,SAAS,CAAI,MAAM,YAAS,CAAgB;gBACrD,IAAI,EAAE,SAAS,CAAI,MAAM,UAAO,CAAgB;aACjD,CAAA;YAED,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE;gBAC/B,MAAM,IAAI,KAAK,CAAC,wBAAsB,MAAM,gDAA2C,MAAM,CAAC,OAAS,CAAC,CAAA;aACzG;YAED,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE;gBAC5B,MAAM,IAAI,KAAK,CAAC,wBAAsB,MAAM,8CAAyC,MAAM,CAAC,IAAM,CAAC,CAAA;aACpG;YAED,OAAO,MAAM,CAAA;QACf,CAAC;QAED,yBAAyB,MAAc;YACrC,IAAM,MAAM,GAAG;gBACb,OAAO,EAAE,SAAS,CAAI,MAAM,YAAS,CAAgB;gBACrD,IAAI,EAAE,SAAS,CAAI,MAAM,UAAO,CAAgB;aACjD,CAAA;YAED,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE;gBAC/B,MAAM,IAAI,KAAK,CAAC,wBAAsB,MAAM,gDAA2C,MAAM,CAAC,OAAS,CAAC,CAAA;aACzG;YAED,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE;gBAC5B,MAAM,IAAI,KAAK,CAAC,wBAAsB,MAAM,8CAAyC,MAAM,CAAC,IAAM,CAAC,CAAA;aACpG;YAED,OAAO,MAAM,CAAA;QACf,CAAC;;;;wBAlCiB,qBAAM,aAAa,CAAC,GAAG,EAAE,kBAAkB,CAAC,EAAA;;oBAAxD,SAAS,GAAG,SAA4C;oBAoC9D,sBAAO;4BACL,YAAY,EAAE,iBAAiB,CAAC,UAAU,CAAC;4BAC3C,YAAY,EAAE,iBAAiB,CAAC,UAAU,CAAC;4BAC3C,YAAY,EAAE,iBAAiB,CAAC,UAAU,CAAC;4BAC3C,YAAY,EAAE,iBAAiB,CAAC,UAAU,CAAC;4BAC3C,YAAY,EAAE,iBAAiB,CAAC,UAAU,CAAC;4BAC3C,YAAY,EAAE,iBAAiB,CAAC,UAAU,CAAC;4BAC3C,YAAY,EAAE,iBAAiB,CAAC,UAAU,CAAC;4BAC3C,YAAY,EAAE,iBAAiB,CAAC,UAAU,CAAC;4BAC3C,UAAU,EAAE,eAAe,CAAC,OAAO,CAAC;4BACpC,UAAU,EAAE,eAAe,CAAC,QAAQ,CAAC;yBACtC,EAAA;;;;CACF"}
\ No newline at end of file
import * as tf from '@tensorflow/tfjs-core';
import { ConvParams } from '../commons/types';
export declare namespace FaceLandmarkNet {
type FCParams = {
weights: tf.Tensor2D;
bias: tf.Tensor1D;
};
type NetParams = {
conv0_params: ConvParams;
conv1_params: ConvParams;
conv2_params: ConvParams;
conv3_params: ConvParams;
conv4_params: ConvParams;
conv5_params: ConvParams;
conv6_params: ConvParams;
conv7_params: ConvParams;
fc0_params: FCParams;
fc1_params: FCParams;
};
}
export declare type FCParams = {
weights: tf.Tensor2D;
bias: tf.Tensor1D;
};
export declare type NetParams = {
conv0_params: ConvParams;
conv1_params: ConvParams;
conv2_params: ConvParams;
conv3_params: ConvParams;
conv4_params: ConvParams;
conv5_params: ConvParams;
conv6_params: ConvParams;
conv7_params: ConvParams;
fc0_params: FCParams;
fc1_params: FCParams;
};
import * as tf from '@tensorflow/tfjs-core';
import { euclideanDistance } from './euclideanDistance';
import { faceDetectionNet } from './faceDetectionNet';
import { faceLandmarkNet } from './faceLandmarkNet';
import { faceRecognitionNet } from './faceRecognitionNet';
import { NetInput } from './NetInput';
import { padToSquare } from './padToSquare';
export { euclideanDistance, faceDetectionNet, faceLandmarkNet, faceRecognitionNet, NetInput, tf, padToSquare };
export { euclideanDistance, faceDetectionNet, faceRecognitionNet, NetInput, tf, padToSquare };
export * from './extractFaces';
export * from './extractFaceTensors';
export * from './faceLandmarkNet';
export * from './utils';
import * as tf from '@tensorflow/tfjs-core';
import { euclideanDistance } from './euclideanDistance';
import { faceDetectionNet } from './faceDetectionNet';
import { faceLandmarkNet } from './faceLandmarkNet';
import { faceRecognitionNet } from './faceRecognitionNet';
import { NetInput } from './NetInput';
import { padToSquare } from './padToSquare';
export { euclideanDistance, faceDetectionNet, faceLandmarkNet, faceRecognitionNet, NetInput, tf, padToSquare };
export { euclideanDistance, faceDetectionNet, faceRecognitionNet, NetInput, tf, padToSquare };
export * from './extractFaces';
export * from './extractFaceTensors';
export * from './faceLandmarkNet';
export * from './utils';
//# sourceMappingURL=index.js.map
\ No newline at end of file
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAE5C,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5C,OAAO,EACL,iBAAiB,EACjB,gBAAgB,EAChB,eAAe,EACf,kBAAkB,EAClB,QAAQ,EACR,EAAE,EACF,WAAW,EACZ,CAAA;AAED,cAAc,gBAAgB,CAAA;AAC9B,cAAc,sBAAsB,CAAA;AACpC,cAAc,SAAS,CAAA"}
\ No newline at end of file
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAE5C,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5C,OAAO,EACL,iBAAiB,EACjB,gBAAgB,EAChB,kBAAkB,EAClB,QAAQ,EACR,EAAE,EACF,WAAW,EACZ,CAAA;AAED,cAAc,gBAAgB,CAAA;AAC9B,cAAc,sBAAsB,CAAA;AACpC,cAAc,mBAAmB,CAAC;AAClC,cAAc,SAAS,CAAA"}
\ No newline at end of file
......@@ -56,7 +56,8 @@
}
async function run() {
net = await initFaceLandmarkNet()
net = new faceapi.FaceLandmarkNet()
await net.load('/')
$('#loader').hide()
await onSelectionChanged($('#selectList select').val())
}
......
import * as tf from '@tensorflow/tfjs-core';
export function isTensor(tensor: tf.Tensor, dim: number) {
return tensor instanceof tf.Tensor && tensor.shape.length === dim
}
export function isTensor1D(tensor: tf.Tensor) {
return isTensor(tensor, 1)
}
export function isTensor2D(tensor: tf.Tensor) {
return isTensor(tensor, 2)
}
export function isTensor3D(tensor: tf.Tensor) {
return isTensor(tensor, 3)
}
export function isTensor4D(tensor: tf.Tensor) {
return isTensor(tensor, 4)
}
\ No newline at end of file
import * as tf from '@tensorflow/tfjs-core';
export function getModelUris(uri: string | undefined, defaultModelName: string) {
const parts = (uri || '').split('/')
const modelBaseUri = (
(uri || '').endsWith('.json')
? parts.slice(0, parts.length - 1)
: parts
).filter(s => s).join('/')
const defaultManifestFilename = `${defaultModelName}-weights_manifest.json`
const manifestUri = !uri || !modelBaseUri
? defaultManifestFilename
: (
uri.endsWith('.json')
? uri
: `${modelBaseUri}/${defaultManifestFilename}`
)
return { manifestUri, modelBaseUri }
}
export async function loadWeightMap(
uri: string | undefined,
defaultModelName: string
): Promise<any> {
const { manifestUri, modelBaseUri } = getModelUris(uri, defaultModelName)
const manifest = await (await fetch(manifestUri)).json()
return tf.io.loadWeights(manifest, modelBaseUri)
}
\ No newline at end of file
import * as tf from '@tensorflow/tfjs-core';
import { convLayer } from '../commons/convLayer';
import { ConvParams } from '../commons/types';
import { getImageTensor } from '../getImageTensor';
import { NetInput } from '../NetInput';
import { Point } from '../Point';
import { Dimensions, TNetInput } from '../types';
import { extractParams } from './extractParams';
import { FaceLandmarks } from './FaceLandmarks';
import { fullyConnectedLayer } from './fullyConnectedLayer';
import { loadQuantizedParams } from './loadQuantizedParams';
import { NetParams } from './types';
function conv(x: tf.Tensor4D, params: ConvParams): tf.Tensor4D {
return convLayer(x, params, 'valid', true)
}
function maxPool(x: tf.Tensor4D, strides: [number, number] = [2, 2]): tf.Tensor4D {
return tf.maxPool(x, [2, 2], strides, 'valid')
}
export class FaceLandmarkNet {
private _params: NetParams
public async load(weightsOrUrl: Float32Array | string | undefined): Promise<void> {
if (weightsOrUrl instanceof Float32Array) {
this.extractWeights(weightsOrUrl)
return
}
if (weightsOrUrl && typeof weightsOrUrl !== 'string') {
throw new Error('FaceLandmarkNet.load - expected model uri, or weights as Float32Array')
}
this._params = await loadQuantizedParams(weightsOrUrl)
}
public extractWeights(weights: Float32Array) {
this._params = extractParams(weights)
}
public async detectLandmarks(input: tf.Tensor | NetInput | TNetInput) {
if (!this._params) {
throw new Error('FaceLandmarkNet - load model before inference')
}
let imageDimensions: Dimensions | undefined
const outTensor = tf.tidy(() => {
const params = this._params
let imgTensor = getImageTensor(input)
const [height, width] = imgTensor.shape.slice(1)
imageDimensions = { width, height }
// work with 128 x 128 sized face images
if (imgTensor.shape[1] !== 128 || imgTensor.shape[2] !== 128) {
imgTensor = tf.image.resizeBilinear(imgTensor, [128, 128])
}
let out = conv(imgTensor, params.conv0_params)
out = maxPool(out)
out = conv(out, params.conv1_params)
out = conv(out, params.conv2_params)
out = maxPool(out)
out = conv(out, params.conv3_params)
out = conv(out, params.conv4_params)
out = maxPool(out)
out = conv(out, params.conv5_params)
out = conv(out, params.conv6_params)
out = maxPool(out, [1, 1])
out = conv(out, params.conv7_params)
const fc0 = tf.relu(fullyConnectedLayer(out.as2D(out.shape[0], -1), params.fc0_params))
const fc1 = fullyConnectedLayer(fc0, params.fc1_params)
return fc1
})
const faceLandmarksArray = Array.from(await outTensor.data())
outTensor.dispose()
const xCoords = faceLandmarksArray.filter((c, i) => (i - 1) % 2)
const yCoords = faceLandmarksArray.filter((c, i) => i % 2)
return new FaceLandmarks(
Array(68).fill(0).map((_, i) => new Point(xCoords[i], yCoords[i])),
imageDimensions as Dimensions
)
}
}
\ No newline at end of file
......@@ -2,9 +2,9 @@ import * as tf from '@tensorflow/tfjs-core';
import { extractConvParamsFactory } from '../commons/extractConvParamsFactory';
import { extractWeightsFactory } from '../commons/extractWeightsFactory';
import { FaceLandmarkNet } from './types';
import { FCParams, NetParams } from './types';
export function extractParams(weights: Float32Array): FaceLandmarkNet.NetParams {
export function extractParams(weights: Float32Array): NetParams {
const {
extractWeights,
getRemainingWeights
......@@ -12,7 +12,7 @@ export function extractParams(weights: Float32Array): FaceLandmarkNet.NetParams
const extractConvParams = extractConvParamsFactory(extractWeights)
function extractFcParams(channelsIn: number, channelsOut: number,): FaceLandmarkNet.FCParams {
function extractFcParams(channelsIn: number, channelsOut: number,): FCParams {
const fc_weights = tf.tensor2d(extractWeights(channelsIn * channelsOut), [channelsIn, channelsOut])
const fc_bias = tf.tensor1d(extractWeights(channelsOut))
return {
......
import * as tf from '@tensorflow/tfjs-core';
import { FaceLandmarkNet } from './types';
import { FCParams } from './types';
export function fullyConnectedLayer(
x: tf.Tensor2D,
params: FaceLandmarkNet.FCParams
params: FCParams
): tf.Tensor2D {
return tf.tidy(() =>
tf.add(
......
import * as tf from '@tensorflow/tfjs-core';
import { FaceLandmarkNet } from './FaceLandmarkNet';
import { convLayer } from '../commons/convLayer';
import { ConvParams } from '../commons/types';
import { getImageTensor } from '../getImageTensor';
import { NetInput } from '../NetInput';
import { Point } from '../Point';
import { Dimensions, TNetInput } from '../types';
import { extractParams } from './extractParams';
import { FaceLandmarks } from './FaceLandmarks';
import { fullyConnectedLayer } from './fullyConnectedLayer';
function conv(x: tf.Tensor4D, params: ConvParams): tf.Tensor4D {
return convLayer(x, params, 'valid', true)
}
function maxPool(x: tf.Tensor4D, strides: [number, number] = [2, 2]): tf.Tensor4D {
return tf.maxPool(x, [2, 2], strides, 'valid')
}
export * from './FaceLandmarkNet';
export function faceLandmarkNet(weights: Float32Array) {
const params = extractParams(weights)
async function detectLandmarks(input: tf.Tensor | NetInput | TNetInput) {
let imageDimensions: Dimensions | undefined
const outTensor = tf.tidy(() => {
let imgTensor = getImageTensor(input)
const [height, width] = imgTensor.shape.slice(1)
imageDimensions = { width, height }
// work with 128 x 128 sized face images
if (imgTensor.shape[1] !== 128 || imgTensor.shape[2] !== 128) {
imgTensor = tf.image.resizeBilinear(imgTensor, [128, 128])
}
let out = conv(imgTensor, params.conv0_params)
out = maxPool(out)
out = conv(out, params.conv1_params)
out = conv(out, params.conv2_params)
out = maxPool(out)
out = conv(out, params.conv3_params)
out = conv(out, params.conv4_params)
out = maxPool(out)
out = conv(out, params.conv5_params)
out = conv(out, params.conv6_params)
out = maxPool(out, [1, 1])
out = conv(out, params.conv7_params)
const fc0 = tf.relu(fullyConnectedLayer(out.as2D(out.shape[0], -1), params.fc0_params))
const fc1 = fullyConnectedLayer(fc0, params.fc1_params)
return fc1
})
const faceLandmarksArray = Array.from(await outTensor.data())
outTensor.dispose()
const xCoords = faceLandmarksArray.filter((c, i) => (i - 1) % 2)
const yCoords = faceLandmarksArray.filter((c, i) => i % 2)
return new FaceLandmarks(
Array(68).fill(0).map((_, i) => new Point(xCoords[i], yCoords[i])),
imageDimensions as Dimensions
)
}
return {
detectLandmarks
}
const faceLandmarkNet = new FaceLandmarkNet()
faceLandmarkNet.extractWeights(weights)
return faceLandmarkNet
}
\ No newline at end of file
import * as tf from '@tensorflow/tfjs-core';
import { loadWeightMap } from '../commons/loadWeightMap';
import { ConvParams } from '../commons/types';
import { FCParams, NetParams } from './types';
import { isTensor4D, isTensor1D, isTensor2D } from '../commons/isTensor';
const DEFAULT_MODEL_NAME = 'face_landmark_68_model'
export async function loadQuantizedParams(uri: string | undefined): Promise<NetParams> {
const weightMap = await loadWeightMap(uri, DEFAULT_MODEL_NAME)
function extractConvParams(prefix: string): ConvParams {
const params = {
filters: weightMap[`${prefix}/kernel`] as tf.Tensor4D,
bias: weightMap[`${prefix}/bias`] as tf.Tensor1D
}
if (!isTensor4D(params.filters)) {
throw new Error(`expected weightMap[${prefix}/kernel] to be a Tensor4D, instead have ${params.filters}`)
}
if (!isTensor1D(params.bias)) {
throw new Error(`expected weightMap[${prefix}/bias] to be a Tensor1D, instead have ${params.bias}`)
}
return params
}
function extractFcParams(prefix: string): FCParams {
const params = {
weights: weightMap[`${prefix}/kernel`] as tf.Tensor2D,
bias: weightMap[`${prefix}/bias`] as tf.Tensor1D
}
if (!isTensor2D(params.weights)) {
throw new Error(`expected weightMap[${prefix}/kernel] to be a Tensor2D, instead have ${params.weights}`)
}
if (!isTensor1D(params.bias)) {
throw new Error(`expected weightMap[${prefix}/bias] to be a Tensor1D, instead have ${params.bias}`)
}
return params
}
return {
conv0_params: extractConvParams('conv2d_0'),
conv1_params: extractConvParams('conv2d_1'),
conv2_params: extractConvParams('conv2d_2'),
conv3_params: extractConvParams('conv2d_3'),
conv4_params: extractConvParams('conv2d_4'),
conv5_params: extractConvParams('conv2d_5'),
conv6_params: extractConvParams('conv2d_6'),
conv7_params: extractConvParams('conv2d_7'),
fc0_params: extractFcParams('dense'),
fc1_params: extractFcParams('logits')
}
}
\ No newline at end of file
......@@ -2,24 +2,20 @@ import * as tf from '@tensorflow/tfjs-core';
import { ConvParams } from '../commons/types';
export namespace FaceLandmarkNet {
export type FCParams = {
weights: tf.Tensor2D
bias: tf.Tensor1D
}
export type NetParams = {
conv0_params: ConvParams
conv1_params: ConvParams
conv2_params: ConvParams
conv3_params: ConvParams
conv4_params: ConvParams
conv5_params: ConvParams
conv6_params: ConvParams
conv7_params: ConvParams
fc0_params: FCParams
fc1_params: FCParams
}
export type FCParams = {
weights: tf.Tensor2D
bias: tf.Tensor1D
}
export type NetParams = {
conv0_params: ConvParams
conv1_params: ConvParams
conv2_params: ConvParams
conv3_params: ConvParams
conv4_params: ConvParams
conv5_params: ConvParams
conv6_params: ConvParams
conv7_params: ConvParams
fc0_params: FCParams
fc1_params: FCParams
}
\ No newline at end of file
......@@ -2,7 +2,6 @@ import * as tf from '@tensorflow/tfjs-core';
import { euclideanDistance } from './euclideanDistance';
import { faceDetectionNet } from './faceDetectionNet';
import { faceLandmarkNet } from './faceLandmarkNet';
import { faceRecognitionNet } from './faceRecognitionNet';
import { NetInput } from './NetInput';
import { padToSquare } from './padToSquare';
......@@ -10,7 +9,6 @@ import { padToSquare } from './padToSquare';
export {
euclideanDistance,
faceDetectionNet,
faceLandmarkNet,
faceRecognitionNet,
NetInput,
tf,
......@@ -19,4 +17,5 @@ export {
export * from './extractFaces'
export * from './extractFaceTensors'
export * from './faceLandmarkNet';
export * from './utils'
\ No newline at end of file
import { getModelUris } from '../src/commons/loadWeightMap';
const FAKE_DEFAULT_MODEL_NAME = 'default_model_name'
describe('loadWeightMap', () => {
describe('getModelUris', () => {
it('returns uris from top level url if no argument passed', () => {
const result = getModelUris(undefined, FAKE_DEFAULT_MODEL_NAME)
expect(result.manifestUri).toEqual(`${FAKE_DEFAULT_MODEL_NAME}-weights_manifest.json`)
expect(result.modelBaseUri).toEqual('')
})
it('returns uris from top level url for empty string', () => {
const result = getModelUris('', FAKE_DEFAULT_MODEL_NAME)
expect(result.manifestUri).toEqual(`${FAKE_DEFAULT_MODEL_NAME}-weights_manifest.json`)
expect(result.modelBaseUri).toEqual('')
})
it('returns uris for top level url', () => {
const result = getModelUris('/', FAKE_DEFAULT_MODEL_NAME)
expect(result.manifestUri).toEqual(`${FAKE_DEFAULT_MODEL_NAME}-weights_manifest.json`)
expect(result.modelBaseUri).toEqual('')
})
it('returns uris, given url path', () => {
const uri = 'path/to/modelfiles'
const result = getModelUris(uri, FAKE_DEFAULT_MODEL_NAME)
expect(result.manifestUri).toEqual(`${uri}/${FAKE_DEFAULT_MODEL_NAME}-weights_manifest.json`)
expect(result.modelBaseUri).toEqual(uri)
})
it('returns uris, given url path, leading slash', () => {
const uri = 'path/to/modelfiles'
const result = getModelUris(`/${uri}`, FAKE_DEFAULT_MODEL_NAME)
expect(result.manifestUri).toEqual(`${uri}/${FAKE_DEFAULT_MODEL_NAME}-weights_manifest.json`)
expect(result.modelBaseUri).toEqual(uri)
})
it('returns uris, given manifest uri', () => {
const uri = 'path/to/modelfiles/model-weights_manifest.json'
const result = getModelUris(uri, FAKE_DEFAULT_MODEL_NAME)
expect(result.manifestUri).toEqual(uri)
expect(result.modelBaseUri).toEqual('path/to/modelfiles')
})
})
})
This source diff could not be displayed because it is too large. You can view the blob instead.
[{"weights": [{"name": "unused_Reshape/shape", "dtype": "int32", "shape": [4], "quantization": {"dtype": "uint8", "scale": 0.5058823529411764, "min": -1.011764705882353}}, {"name": "conv2d_0/kernel", "dtype": "float32", "shape": [3, 3, 3, 32], "quantization": {"dtype": "uint8", "scale": 0.006229220535240922, "min": -1.0963428142024023}}, {"name": "conv2d_0/bias", "dtype": "float32", "shape": [32], "quantization": {"dtype": "uint8", "scale": 0.009229176067838482, "min": -2.0211895588566273}}, {"name": "conv2d_1/kernel", "dtype": "float32", "shape": [3, 3, 32, 64], "quantization": {"dtype": "uint8", "scale": 0.00794055274888581, "min": -1.1513801485884423}}, {"name": "conv2d_1/bias", "dtype": "float32", "shape": [64], "quantization": {"dtype": "uint8", "scale": 0.004187015750828911, "min": -0.9839487014447941}}, {"name": "conv2d_2/kernel", "dtype": "float32", "shape": [3, 3, 64, 64], "quantization": {"dtype": "uint8", "scale": 0.013999465633841121, "min": -2.6318995391621307}}, {"name": "conv2d_2/bias", "dtype": "float32", "shape": [64], "quantization": {"dtype": "uint8", "scale": 0.0037124345699946085, "min": -0.8427226473887761}}, {"name": "conv2d_3/kernel", "dtype": "float32", "shape": [3, 3, 64, 64], "quantization": {"dtype": "uint8", "scale": 0.008715396301419128, "min": -1.368317219322803}}, {"name": "conv2d_3/bias", "dtype": "float32", "shape": [64], "quantization": {"dtype": "uint8", "scale": 0.0022804437753032236, "min": -0.5290629558703479}}, {"name": "conv2d_4/kernel", "dtype": "float32", "shape": [3, 3, 64, 64], "quantization": {"dtype": "uint8", "scale": 0.011885881891437605, "min": -2.2226599136988323}}, {"name": "conv2d_4/bias", "dtype": "float32", "shape": [64], "quantization": {"dtype": "uint8", "scale": 0.0020124191893082038, "min": -0.4809681862446607}}, {"name": "conv2d_5/kernel", "dtype": "float32", "shape": [3, 3, 64, 128], "quantization": {"dtype": "uint8", "scale": 0.011104925941018497, "min": -1.8212078543270336}}, {"name": "conv2d_5/bias", "dtype": "float32", "shape": [128], "quantization": {"dtype": "uint8", "scale": 0.0011017150592570212, "min": -0.24017388291803063}}, {"name": "conv2d_6/kernel", "dtype": "float32", "shape": [3, 3, 128, 128], "quantization": {"dtype": "uint8", "scale": 0.012181366191190831, "min": -2.009925421546487}}, {"name": "conv2d_6/bias", "dtype": "float32", "shape": [128], "quantization": {"dtype": "uint8", "scale": 0.0015788526511659809, "min": -0.3347167620471879}}, {"name": "conv2d_7/kernel", "dtype": "float32", "shape": [3, 3, 128, 256], "quantization": {"dtype": "uint8", "scale": 0.013691982100991642, "min": -2.3550209213705626}}, {"name": "conv2d_7/bias", "dtype": "float32", "shape": [256], "quantization": {"dtype": "uint8", "scale": 0.0009620819898212657, "min": -0.1452743804630111}}, {"name": "unused_flatten/Reshape/shape", "dtype": "int32", "shape": [2], "quantization": {"dtype": "uint8", "scale": 0.00784313725490196, "min": -1.003921568627451}}, {"name": "dense/kernel", "dtype": "float32", "shape": [6400, 1024], "quantization": {"dtype": "uint8", "scale": 0.01880466704275094, "min": -3.2720120654386635}}, {"name": "dense/bias", "dtype": "float32", "shape": [1024], "quantization": {"dtype": "uint8", "scale": 0.00283245981908312, "min": -0.24642400426023145}}, {"name": "logits/kernel", "dtype": "float32", "shape": [1024, 136], "quantization": {"dtype": "uint8", "scale": 0.005545294986051672, "min": -0.7818865930332858}}, {"name": "logits/bias", "dtype": "float32", "shape": [136], "quantization": {"dtype": "uint8", "scale": 0.002829533581640206, "min": 0.13660642504692078}}], "paths": ["face_landmark_68_model-shard1", "face_landmark_68_model-shard2"]}]
\ No newline at end of file
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