Commit e2158565 by vincent

clean up code

parent 495557a4
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -2,53 +2,51 @@ import * as tf from '@tensorflow/tfjs-core'; ...@@ -2,53 +2,51 @@ import * as tf from '@tensorflow/tfjs-core';
function scale(x, params) { function scale(x, params) {
return tf.add(tf.mul(x, params.weights), params.biases); return tf.add(tf.mul(x, params.weights), params.biases);
} }
function createConvLayer(stride, withRelu) { function convLayer(x, params, stride, withRelu, padding) {
return function (x, params, useValidPadding) { if (padding === void 0) { padding = 'same'; }
if (useValidPadding === void 0) { useValidPadding = false; } var _a = params.conv, filters = _a.filters, biases = _a.biases;
var _a = params.conv, filters = _a.filters, biases = _a.biases; var out = tf.conv2d(x, filters, [stride, stride], padding);
var out = tf.conv2d(x, filters, [stride, stride], useValidPadding ? 'valid' : 'same'); out = tf.add(out, biases);
out = tf.add(out, biases); out = scale(out, params.scale);
out = scale(out, params.scale); return withRelu ? tf.relu(out) : out;
return withRelu ? tf.relu(out) : out;
};
} }
function createResBlock() { function conv(x, params) {
var conv = createConvLayer(1, true); return convLayer(x, params, 1, true);
var convNoRelu = createConvLayer(1, false);
return function (x, params) {
var out = conv(x, params.conv1);
out = convNoRelu(out, params.conv2);
out = tf.add(out, x);
out = tf.relu(out);
return out;
};
} }
function createReduceDimsBlock() { function convNoRelu(x, params) {
var convReduceDims = createConvLayer(2, true); return convLayer(x, params, 1, false);
var convNoRelu = createConvLayer(1, false); }
return function (x, params, useValidPadding) { function convDown(x, params) {
if (useValidPadding === void 0) { useValidPadding = false; } return convLayer(x, params, 2, true, 'valid');
var out = convReduceDims(x, params.conv1, useValidPadding); }
out = convNoRelu(out, params.conv2); function res(x, params) {
var pooled = tf.avgPool(x, 2, 2, useValidPadding ? 'valid' : 'same'); var out = conv(x, params.conv1);
var zeros = tf.zeros(pooled.shape); out = convNoRelu(out, params.conv2);
var isPad = pooled.shape[3] !== out.shape[3]; out = tf.add(out, x);
var isAdjustShape = pooled.shape[1] !== out.shape[1] || pooled.shape[2] !== out.shape[2]; out = tf.relu(out);
if (isAdjustShape) { return out;
var padShapeX = out.shape.slice(); }
padShapeX[1] = 1; function resDown(x, params) {
var zerosW = tf.zeros(padShapeX); var out = convDown(x, params.conv1);
out = tf.concat([out, zerosW], 1); out = convNoRelu(out, params.conv2);
var padShapeY = out.shape.slice(); var pooled = tf.avgPool(x, 2, 2, 'valid');
padShapeY[2] = 1; var zeros = tf.zeros(pooled.shape);
var zerosH = tf.zeros(padShapeY); var isPad = pooled.shape[3] !== out.shape[3];
out = tf.concat([out, zerosH], 2); var isAdjustShape = pooled.shape[1] !== out.shape[1] || pooled.shape[2] !== out.shape[2];
} if (isAdjustShape) {
pooled = isPad ? tf.concat([pooled, zeros], 3) : pooled; var padShapeX = out.shape.slice();
out = tf.add(pooled, out); padShapeX[1] = 1;
out = tf.relu(out); var zerosW = tf.zeros(padShapeX);
return out; out = tf.concat([out, zerosW], 1);
}; var padShapeY = out.shape.slice();
padShapeY[2] = 1;
var zerosH = tf.zeros(padShapeY);
out = tf.concat([out, zerosH], 2);
}
pooled = isPad ? tf.concat([pooled, zeros], 3) : pooled;
out = tf.add(pooled, out);
out = tf.relu(out);
return out;
} }
function normalize(arr) { function normalize(arr) {
var avg_r = 122.782; var avg_r = 122.782;
...@@ -61,31 +59,23 @@ function normalize(arr) { ...@@ -61,31 +59,23 @@ function normalize(arr) {
}); });
} }
function computeFaceDescriptor(input, params) { function computeFaceDescriptor(input, params) {
var conv32_in = createConvLayer(2, true);
var res32 = createResBlock();
var reduceDims64 = createReduceDimsBlock();
var reduceDims128 = createReduceDimsBlock();
var reduceDims256 = createReduceDimsBlock();
var res64 = createResBlock();
var res128 = createResBlock();
var res256 = createResBlock();
var x = tf.tensor4d(normalize(input), [1, 150, 150, 3]); var x = tf.tensor4d(normalize(input), [1, 150, 150, 3]);
var out = conv32_in(x, params.conv32_in, true); var out = convDown(x, params.conv32_in);
out = tf.maxPool(out, 3, 2, 'valid'); out = tf.maxPool(out, 3, 2, 'valid');
out = res32(out, params.conv32_1); out = res(out, params.conv32_1);
out = res32(out, params.conv32_2); out = res(out, params.conv32_2);
out = res32(out, params.conv32_3); out = res(out, params.conv32_3);
out = reduceDims64(out, params.conv64_in, true); out = resDown(out, params.conv64_in);
out = res64(out, params.conv64_1); out = res(out, params.conv64_1);
out = res64(out, params.conv64_2); out = res(out, params.conv64_2);
out = res64(out, params.conv64_3); out = res(out, params.conv64_3);
out = reduceDims128(out, params.conv128_in, true); out = resDown(out, params.conv128_in);
out = res128(out, params.conv128_1); out = res(out, params.conv128_1);
out = res128(out, params.conv128_2); out = res(out, params.conv128_2);
out = reduceDims256(out, params.conv256_in, true); out = resDown(out, params.conv256_in);
out = res256(out, params.conv256_1); out = res(out, params.conv256_1);
out = res256(out, params.conv256_2); out = res(out, params.conv256_2);
out = reduceDims256(out, params.conv256_3, true); out = resDown(out, params.conv256_3);
// global average pooling of each of the 256 filters -> retrieve 256 entry vector // global average pooling of each of the 256 filters -> retrieve 256 entry vector
var global_avg = out.mean([1, 2]); var global_avg = out.mean([1, 2]);
// fully connected // fully connected
......
import * as tf from '@tensorflow/tfjs-core';
import { ConvLayerParams } from './convLayer';
import { ResidualLayerParams } from './residualLayer';
export declare type FaceRecognitionNetParams = {
conv32_down: ConvLayerParams;
conv32_1: ResidualLayerParams;
conv32_2: ResidualLayerParams;
conv32_3: ResidualLayerParams;
conv64_down: ResidualLayerParams;
conv64_1: ResidualLayerParams;
conv64_2: ResidualLayerParams;
conv64_3: ResidualLayerParams;
conv128_down: ResidualLayerParams;
conv128_1: ResidualLayerParams;
conv128_2: ResidualLayerParams;
conv256_down: ResidualLayerParams;
conv256_1: ResidualLayerParams;
conv256_2: ResidualLayerParams;
conv256_down_out: ResidualLayerParams;
fc: tf.Tensor2D;
};
//# sourceMappingURL=FaceRecognitionNetParams.js.map
\ No newline at end of file
{"version":3,"file":"FaceRecognitionNetParams.js","sourceRoot":"","sources":["../../src/faceRecognitionNet/FaceRecognitionNetParams.ts"],"names":[],"mappings":""}
\ No newline at end of file
import * as tf from '@tensorflow/tfjs-core';
import { ScaleLayerParams } from './scaleLayer';
export declare type ConvParams = {
filters: tf.Tensor4D;
biases: tf.Tensor1D;
};
export declare type ConvLayerParams = {
conv: ConvParams;
scale: ScaleLayerParams;
};
export declare function conv(x: tf.Tensor4D, params: ConvLayerParams): tf.Tensor<tf.Rank.R4>;
export declare function convNoRelu(x: tf.Tensor4D, params: ConvLayerParams): tf.Tensor<tf.Rank.R4>;
export declare function convDown(x: tf.Tensor4D, params: ConvLayerParams): tf.Tensor<tf.Rank.R4>;
import * as tf from '@tensorflow/tfjs-core';
import { scale } from './scaleLayer';
function convLayer(x, params, stride, withRelu, padding) {
if (padding === void 0) { padding = 'same'; }
var _a = params.conv, filters = _a.filters, biases = _a.biases;
var out = tf.conv2d(x, filters, [stride, stride], padding);
out = tf.add(out, biases);
out = scale(out, params.scale);
return withRelu ? tf.relu(out) : out;
}
export function conv(x, params) {
return convLayer(x, params, 1, true);
}
export function convNoRelu(x, params) {
return convLayer(x, params, 1, false);
}
export function convDown(x, params) {
return convLayer(x, params, 2, true, 'valid');
}
//# sourceMappingURL=convLayer.js.map
\ No newline at end of file
{"version":3,"file":"convLayer.js","sourceRoot":"","sources":["../../src/faceRecognitionNet/convLayer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAE5C,OAAO,EAAE,KAAK,EAAoB,MAAM,cAAc,CAAC;AAYvD,mBACE,CAAc,EACd,MAAuB,EACvB,MAAc,EACd,QAAiB,EACjB,OAAkC;IAAlC,wBAAA,EAAA,gBAAkC;IAE5B,IAAA,gBAAiC,EAA/B,oBAAO,EAAE,kBAAM,CAAgB;IAEvC,IAAI,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,CAAC,CAAA;IAC1D,GAAG,GAAG,EAAE,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAA;IACzB,GAAG,GAAG,KAAK,CAAC,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,CAAA;IAC9B,OAAO,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAA;AACtC,CAAC;AAED,MAAM,eAAe,CAAc,EAAE,MAAuB;IAC1D,OAAO,SAAS,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,IAAI,CAAC,CAAA;AACtC,CAAC;AAED,MAAM,qBAAqB,CAAc,EAAE,MAAuB;IAChE,OAAO,SAAS,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,CAAC,CAAA;AACvC,CAAC;AAED,MAAM,mBAAmB,CAAc,EAAE,MAAuB;IAC9D,OAAO,SAAS,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,CAAA;AAC/C,CAAC"}
\ No newline at end of file
import { FaceRecognitionNetParams } from './FaceRecognitionNetParams';
export declare function extractParams(weights: Float32Array): FaceRecognitionNetParams;
import * as tf from '@tensorflow/tfjs-core';
function isFloat(num) {
return num % 1 !== 0;
}
function extractorsFactory(extractWeights) {
function extractFilterValues(numFilterValues, numFilters, filterSize) {
var weights = extractWeights(numFilterValues);
var depth = weights.length / (numFilters * filterSize * filterSize);
if (isFloat(depth)) {
throw new Error("depth has to be an integer: " + depth + ", weights.length: " + weights.length + ", numFilters: " + numFilters + ", filterSize: " + filterSize);
}
return tf.transpose(tf.tensor4d(weights, [numFilters, depth, filterSize, filterSize]), [2, 3, 1, 0]);
}
function extractScaleLayerParams(numWeights) {
var weights = tf.tensor1d(extractWeights(numWeights));
var biases = tf.tensor1d(extractWeights(numWeights));
return {
weights: weights,
biases: biases
};
}
function extractConvLayerParams(numFilterValues, numFilters, filterSize) {
var conv_filters = extractFilterValues(numFilterValues, numFilters, filterSize);
var conv_biases = tf.tensor1d(extractWeights(numFilters));
var scale = extractScaleLayerParams(numFilters);
return {
conv: {
filters: conv_filters,
biases: conv_biases
},
scale: scale
};
}
function extractResidualLayerParams(numFilterValues, numFilters, filterSize, isDown) {
if (isDown === void 0) { isDown = false; }
var conv1 = extractConvLayerParams((isDown ? 0.5 : 1) * numFilterValues, numFilters, filterSize);
var conv2 = extractConvLayerParams(numFilterValues, numFilters, filterSize);
return {
conv1: conv1,
conv2: conv2
};
}
return {
extractConvLayerParams: extractConvLayerParams,
extractResidualLayerParams: extractResidualLayerParams
};
}
export function extractParams(weights) {
var extractWeights = function (numWeights) {
var ret = weights.slice(0, numWeights);
weights = weights.slice(numWeights);
return ret;
};
var _a = extractorsFactory(extractWeights), extractConvLayerParams = _a.extractConvLayerParams, extractResidualLayerParams = _a.extractResidualLayerParams;
var conv32_down = extractConvLayerParams(4704, 32, 7);
var conv32_1 = extractResidualLayerParams(9216, 32, 3);
var conv32_2 = extractResidualLayerParams(9216, 32, 3);
var conv32_3 = extractResidualLayerParams(9216, 32, 3);
var conv64_down = extractResidualLayerParams(36864, 64, 3, true);
var conv64_1 = extractResidualLayerParams(36864, 64, 3);
var conv64_2 = extractResidualLayerParams(36864, 64, 3);
var conv64_3 = extractResidualLayerParams(36864, 64, 3);
var conv128_down = extractResidualLayerParams(147456, 128, 3, true);
var conv128_1 = extractResidualLayerParams(147456, 128, 3);
var conv128_2 = extractResidualLayerParams(147456, 128, 3);
var conv256_down = extractResidualLayerParams(589824, 256, 3, true);
var conv256_1 = extractResidualLayerParams(589824, 256, 3);
var conv256_2 = extractResidualLayerParams(589824, 256, 3);
var conv256_down_out = extractResidualLayerParams(589824, 256, 3);
var fc = tf.transpose(tf.tensor2d(extractWeights(256 * 128), [128, 256]), [1, 0]);
if (weights.length !== 0) {
throw new Error("weights remaing after extract: " + weights.length);
}
return {
conv32_down: conv32_down,
conv32_1: conv32_1,
conv32_2: conv32_2,
conv32_3: conv32_3,
conv64_down: conv64_down,
conv64_1: conv64_1,
conv64_2: conv64_2,
conv64_3: conv64_3,
conv128_down: conv128_down,
conv128_1: conv128_1,
conv128_2: conv128_2,
conv256_down: conv256_down,
conv256_1: conv256_1,
conv256_2: conv256_2,
conv256_down_out: conv256_down_out,
fc: fc
};
}
//# sourceMappingURL=extractParams.js.map
\ No newline at end of file
{"version":3,"file":"extractParams.js","sourceRoot":"","sources":["../../src/faceRecognitionNet/extractParams.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
export declare function faceRecognitionNet(weights: Float32Array): (input: number[]) => number[];
import * as tf from '@tensorflow/tfjs-core';
import { normalize } from '../normalize';
import { convDown } from './convLayer';
import { extractParams } from './extractParams';
import { residual, residualDown } from './residualLayer';
export function faceRecognitionNet(weights) {
var params = extractParams(weights);
return function (input) {
var x = tf.tensor4d(normalize(input), [1, 150, 150, 3]);
var out = convDown(x, params.conv32_down);
out = tf.maxPool(out, 3, 2, 'valid');
out = residual(out, params.conv32_1);
out = residual(out, params.conv32_2);
out = residual(out, params.conv32_3);
out = residualDown(out, params.conv64_down);
out = residual(out, params.conv64_1);
out = residual(out, params.conv64_2);
out = residual(out, params.conv64_3);
out = residualDown(out, params.conv128_down);
out = residual(out, params.conv128_1);
out = residual(out, params.conv128_2);
out = residualDown(out, params.conv256_down);
out = residual(out, params.conv256_1);
out = residual(out, params.conv256_2);
out = residualDown(out, params.conv256_down_out);
var globalAvg = out.mean([1, 2]);
var fullyConnected = tf.matMul(globalAvg, params.fc);
return Array.from(fullyConnected.dataSync());
};
}
//# sourceMappingURL=index.js.map
\ No newline at end of file
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/faceRecognitionNet/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAE5C,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAEzD,MAAM,6BAA6B,OAAqB;IACtD,IAAM,MAAM,GAAG,aAAa,CAAC,OAAO,CAAC,CAAA;IAErC,OAAO,UAAU,KAAe;QAE9B,IAAM,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,CAAA;QAEzD,IAAI,GAAG,GAAG,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC,WAAW,CAAC,CAAA;QACzC,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,CAAA;QAEpC,GAAG,GAAG,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAA;QACpC,GAAG,GAAG,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAA;QACpC,GAAG,GAAG,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAA;QAEpC,GAAG,GAAG,YAAY,CAAC,GAAG,EAAE,MAAM,CAAC,WAAW,CAAC,CAAA;QAC3C,GAAG,GAAG,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAA;QACpC,GAAG,GAAG,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAA;QACpC,GAAG,GAAG,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAA;QAEpC,GAAG,GAAG,YAAY,CAAC,GAAG,EAAE,MAAM,CAAC,YAAY,CAAC,CAAA;QAC5C,GAAG,GAAG,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,SAAS,CAAC,CAAA;QACrC,GAAG,GAAG,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,SAAS,CAAC,CAAA;QAErC,GAAG,GAAG,YAAY,CAAC,GAAG,EAAE,MAAM,CAAC,YAAY,CAAC,CAAA;QAC5C,GAAG,GAAG,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,SAAS,CAAC,CAAA;QACrC,GAAG,GAAG,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,SAAS,CAAC,CAAA;QACrC,GAAG,GAAG,YAAY,CAAC,GAAG,EAAE,MAAM,CAAC,gBAAgB,CAAC,CAAA;QAEhD,IAAM,SAAS,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAgB,CAAA;QACjD,IAAM,cAAc,GAAG,EAAE,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,EAAE,CAAC,CAAA;QAEtD,OAAO,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,QAAQ,EAAE,CAAC,CAAA;IAC9C,CAAC,CAAA;AACH,CAAC"}
\ No newline at end of file
import * as tf from '@tensorflow/tfjs-core';
import { ConvLayerParams } from './convLayer';
export declare type ResidualLayerParams = {
conv1: ConvLayerParams;
conv2: ConvLayerParams;
};
export declare function residual(x: tf.Tensor4D, params: ResidualLayerParams): tf.Tensor4D;
export declare function residualDown(x: tf.Tensor4D, params: ResidualLayerParams): tf.Tensor4D;
import * as tf from '@tensorflow/tfjs-core';
import { conv, convNoRelu, convDown } from './convLayer';
export function residual(x, params) {
var out = conv(x, params.conv1);
out = convNoRelu(out, params.conv2);
out = tf.add(out, x);
out = tf.relu(out);
return out;
}
export function residualDown(x, params) {
var out = convDown(x, params.conv1);
out = convNoRelu(out, params.conv2);
var pooled = tf.avgPool(x, 2, 2, 'valid');
var zeros = tf.zeros(pooled.shape);
var isPad = pooled.shape[3] !== out.shape[3];
var isAdjustShape = pooled.shape[1] !== out.shape[1] || pooled.shape[2] !== out.shape[2];
if (isAdjustShape) {
var padShapeX = out.shape.slice();
padShapeX[1] = 1;
var zerosW = tf.zeros(padShapeX);
out = tf.concat([out, zerosW], 1);
var padShapeY = out.shape.slice();
padShapeY[2] = 1;
var zerosH = tf.zeros(padShapeY);
out = tf.concat([out, zerosH], 2);
}
pooled = isPad ? tf.concat([pooled, zeros], 3) : pooled;
out = tf.add(pooled, out);
out = tf.relu(out);
return out;
}
//# sourceMappingURL=residualLayer.js.map
\ No newline at end of file
{"version":3,"file":"residualLayer.js","sourceRoot":"","sources":["../../src/faceRecognitionNet/residualLayer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAE5C,OAAO,EAAE,IAAI,EAAE,UAAU,EAAmB,QAAQ,EAAE,MAAM,aAAa,CAAC;AAO1E,MAAM,mBAAmB,CAAc,EAAE,MAA2B;IAClE,IAAI,GAAG,GAAG,IAAI,CAAC,CAAC,EAAE,MAAM,CAAC,KAAK,CAAC,CAAA;IAC/B,GAAG,GAAG,UAAU,CAAC,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,CAAA;IACnC,GAAG,GAAG,EAAE,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,CAAA;IACpB,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IAClB,OAAO,GAAG,CAAA;AACZ,CAAC;AAED,MAAM,uBAAuB,CAAc,EAAE,MAA2B;IACtE,IAAI,GAAG,GAAG,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC,KAAK,CAAC,CAAA;IACnC,GAAG,GAAG,UAAU,CAAC,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,CAAA;IAEnC,IAAI,MAAM,GAAG,EAAE,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,OAAO,CAAgB,CAAA;IACxD,IAAM,KAAK,GAAG,EAAE,CAAC,KAAK,CAAa,MAAM,CAAC,KAAK,CAAC,CAAA;IAChD,IAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;IAC9C,IAAM,aAAa,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;IAE1F,IAAI,aAAa,EAAE;QACjB,IAAM,SAAS,GAAO,GAAG,CAAC,KAAK,QAAqC,CAAA;QACpE,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;QAChB,IAAM,MAAM,GAAG,EAAE,CAAC,KAAK,CAAa,SAAS,CAAC,CAAA;QAC9C,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC,CAAA;QAEjC,IAAM,SAAS,GAAO,GAAG,CAAC,KAAK,QAAqC,CAAA;QACpE,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;QAChB,IAAM,MAAM,GAAG,EAAE,CAAC,KAAK,CAAa,SAAS,CAAC,CAAA;QAC9C,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC,CAAA;KAClC;IAED,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAA;IACvD,GAAG,GAAG,EAAE,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAgB,CAAA;IAExC,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IAClB,OAAO,GAAG,CAAA;AACZ,CAAC"}
\ No newline at end of file
import * as tf from '@tensorflow/tfjs-core';
export declare type ScaleLayerParams = {
weights: tf.Tensor1D;
biases: tf.Tensor1D;
};
export declare function scale(x: tf.Tensor4D, params: ScaleLayerParams): tf.Tensor4D;
import * as tf from '@tensorflow/tfjs-core';
export function scale(x, params) {
return tf.add(tf.mul(x, params.weights), params.biases);
}
//# sourceMappingURL=scaleLayer.js.map
\ No newline at end of file
{"version":3,"file":"scaleLayer.js","sourceRoot":"","sources":["../../src/faceRecognitionNet/scaleLayer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAO5C,MAAM,gBAAgB,CAAc,EAAE,MAAwB;IAC5D,OAAO,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,CAAA;AACzD,CAAC"}
\ No newline at end of file
import { euclideanDistance } from './euclideanDistance'; import { euclideanDistance } from './euclideanDistance';
import { faceRecognitionNet } from './faceRecognitionNet'; import { faceRecognitionNet } from './faceRecognitionNet';
export { euclideanDistance, faceRecognitionNet }; import { normalize } from './normalize';
export { euclideanDistance, faceRecognitionNet, normalize };
import { euclideanDistance } from './euclideanDistance'; import { euclideanDistance } from './euclideanDistance';
import { faceRecognitionNet } from './faceRecognitionNet'; import { faceRecognitionNet } from './faceRecognitionNet';
export { euclideanDistance, faceRecognitionNet }; import { normalize } from './normalize';
export { euclideanDistance, faceRecognitionNet, normalize };
//# sourceMappingURL=index.js.map //# sourceMappingURL=index.js.map
\ No newline at end of file
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAE1D,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EACnB,CAAA"} {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,SAAS,EACV,CAAA"}
\ No newline at end of file \ No newline at end of file
export declare function normalize(arr: number[]): number[];
export function normalize(arr) {
var avg_r = 122.782;
var avg_g = 117.001;
var avg_b = 104.298;
var avgs = [avg_r, avg_g, avg_b];
return arr.map(function (val, i) {
var avg = avgs[i % 3];
return (val - avg) / 256;
});
}
//# sourceMappingURL=normalize.js.map
\ No newline at end of file
{"version":3,"file":"normalize.js","sourceRoot":"","sources":["../src/normalize.ts"],"names":[],"mappings":"AAAA,MAAM,oBAAoB,GAAa;IACrC,IAAM,KAAK,GAAG,OAAO,CAAC;IACtB,IAAM,KAAK,GAAG,OAAO,CAAC;IACtB,IAAM,KAAK,GAAG,OAAO,CAAC;IACtB,IAAM,IAAI,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,CAAA;IAClC,OAAO,GAAG,CAAC,GAAG,CAAC,UAAC,GAAG,EAAE,CAAC;QACpB,IAAM,GAAG,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;QACvB,OAAO,CAAC,GAAG,GAAG,GAAG,CAAC,GAAG,GAAG,CAAA;IAC1B,CAAC,CAAC,CAAA;AACJ,CAAC"}
\ No newline at end of file
import * as tf from '@tensorflow/tfjs-core';
function scale(x: tf.Tensor4D, params: ScaleLayerParams): tf.Tensor4D {
return tf.add(tf.mul(x, params.weights), params.biases)
}
function createConvLayer(stride: number, withRelu: boolean) {
return function (x: tf.Tensor4D, params: ConvBlockParams, useValidPadding: boolean = false): tf.Tensor4D {
const { filters, biases } = params.conv
let out = tf.conv2d(x, filters, [stride, stride], useValidPadding ? 'valid' : 'same')
out = tf.add(out, biases)
out = scale(out, params.scale)
return withRelu ? tf.relu(out) : out
}
}
function createResBlock() {
const conv = createConvLayer(1, true)
const convNoRelu = createConvLayer(1, false)
return function (x: tf.Tensor4D, params: ResBlockParams): tf.Tensor4D {
let out = conv(x, params.conv1)
out = convNoRelu(out, params.conv2)
out = tf.add(out, x)
out = tf.relu(out)
return out
}
}
function createReduceDimsBlock() {
const convReduceDims = createConvLayer(2, true)
const convNoRelu = createConvLayer(1, false)
return function (x: tf.Tensor4D, params: ResBlockParams, useValidPadding: boolean = false): tf.Tensor4D {
let out = convReduceDims(x, params.conv1, useValidPadding)
out = convNoRelu(out, params.conv2)
let pooled = tf.avgPool(x, 2, 2, useValidPadding ? 'valid' : 'same') as tf.Tensor4D
const zeros = tf.zeros<tf.Rank.R4>(pooled.shape)
const isPad = pooled.shape[3] !== out.shape[3]
const isAdjustShape = pooled.shape[1] !== out.shape[1] || pooled.shape[2] !== out.shape[2]
if (isAdjustShape) {
const padShapeX = [...out.shape] as [number, number, number, number]
padShapeX[1] = 1
const zerosW = tf.zeros<tf.Rank.R4>(padShapeX)
out = tf.concat([out, zerosW], 1)
const padShapeY = [...out.shape] as [number, number, number, number]
padShapeY[2] = 1
const zerosH = tf.zeros<tf.Rank.R4>(padShapeY)
out = tf.concat([out, zerosH], 2)
}
pooled = isPad ? tf.concat([pooled, zeros], 3) : pooled
out = tf.add(pooled, out) as tf.Tensor4D
out = tf.relu(out)
return out
}
}
function normalize(arr: number[]) {
const avg_r = 122.782;
const avg_g = 117.001;
const avg_b = 104.298;
const avgs = [avg_r, avg_g, avg_b]
return arr.map((val, i) => {
const avg = avgs[i % 3]
return (val - avg) / 256
})
}
function computeFaceDescriptor(input: number[], params: ParamMap) {
const conv32_in = createConvLayer(2, true)
const res32 = createResBlock()
const reduceDims64 = createReduceDimsBlock()
const reduceDims128 = createReduceDimsBlock()
const reduceDims256 = createReduceDimsBlock()
const res64 = createResBlock()
const res128 = createResBlock()
const res256 = createResBlock()
const x = tf.tensor4d(normalize(input), [1, 150, 150, 3])
let out = conv32_in(x, params.conv32_in, true)
out = tf.maxPool(out, 3, 2, 'valid')
out = res32(out, params.conv32_1)
out = res32(out, params.conv32_2)
out = res32(out, params.conv32_3)
out = reduceDims64(out, params.conv64_in, true)
out = res64(out, params.conv64_1)
out = res64(out, params.conv64_2)
out = res64(out, params.conv64_3)
out = reduceDims128(out, params.conv128_in, true)
out = res128(out, params.conv128_1)
out = res128(out, params.conv128_2)
out = reduceDims256(out, params.conv256_in, true)
out = res256(out, params.conv256_1)
out = res256(out, params.conv256_2)
out = reduceDims256(out, params.conv256_3, true)
// global average pooling of each of the 256 filters -> retrieve 256 entry vector
const global_avg = out.mean([1, 2]) as tf.Tensor2D
// fully connected
// TODO: kind of slow here
return Array.from(tf.matMul(global_avg, params.fc).dataSync())
}
export type ConvLayerParams = {
filters: tf.Tensor4D
biases: tf.Tensor1D
}
export type ScaleLayerParams = {
weights: tf.Tensor1D
biases: tf.Tensor1D
}
export type ConvBlockParams = {
conv: ConvLayerParams
scale: ScaleLayerParams
}
export type ResBlockParams = {
conv1: ConvBlockParams
conv2: ConvBlockParams
}
export type ParamMap = {
conv32_in: ConvBlockParams
conv32_1: ResBlockParams
conv32_2: ResBlockParams
conv32_3: ResBlockParams
conv64_in: ResBlockParams
conv64_1: ResBlockParams
conv64_2: ResBlockParams
conv64_3: ResBlockParams
conv128_in: ResBlockParams
conv128_1: ResBlockParams
conv128_2: ResBlockParams
conv256_in: ResBlockParams
conv256_1: ResBlockParams
conv256_2: ResBlockParams
conv256_3: ResBlockParams
fc: tf.Tensor2D
}
function isFloat(num: number) {
return num % 1 !== 0
}
function extractorsFactory(extractWeights: (numWeights: number) => Float32Array) {
function extractFilterValues(numFilterValues: number, numFilters: number, filterSize: number): tf.Tensor4D {
const weights = extractWeights(numFilterValues)
const depth = weights.length / (numFilters * filterSize * filterSize)
if (isFloat(depth)) {
throw new Error(`depth has to be an integer: ${depth}, weights.length: ${weights.length}, numFilters: ${numFilters}, filterSize: ${filterSize}`)
}
return tf.transpose(
tf.tensor4d(weights, [numFilters, depth, filterSize, filterSize]),
[2, 3, 1, 0]
)
}
function extractScaleLayerParams(numWeights: number): ScaleLayerParams {
const weights = tf.tensor1d(extractWeights(numWeights))
const biases = tf.tensor1d(extractWeights(numWeights))
return {
weights,
biases
}
}
function extractConvBlockParams(numFilterValues: number, numFilters: number, filterSize: number): ConvBlockParams {
const conv_filters = extractFilterValues(numFilterValues, numFilters, filterSize)
const conv_biases = tf.tensor1d(extractWeights(numFilters))
const scale = extractScaleLayerParams(numFilters)
return {
conv: {
filters: conv_filters,
biases: conv_biases
},
scale
}
}
function extractResBlockParams(numFilterValues: number, numFilters: number, filterSize: number, isInBlock: boolean = false): ResBlockParams {
const conv1: ConvBlockParams = extractConvBlockParams((isInBlock ? 0.5 : 1) * numFilterValues, numFilters, filterSize)
const conv2: ConvBlockParams = extractConvBlockParams(numFilterValues, numFilters, filterSize)
return {
conv1,
conv2
}
}
return {
extractConvBlockParams,
extractResBlockParams
}
}
function extractParams(weights: Float32Array): ParamMap {
const extractWeights = (numWeights: number): Float32Array => {
const ret = weights.slice(0, numWeights)
weights = weights.slice(numWeights)
return ret
}
const {
extractConvBlockParams,
extractResBlockParams
} = extractorsFactory(extractWeights)
const conv32_in = extractConvBlockParams(4704, 32, 7)
const conv32_1 = extractResBlockParams(9216, 32, 3)
const conv32_2 = extractResBlockParams(9216, 32, 3)
const conv32_3 = extractResBlockParams(9216, 32, 3)
const conv64_in = extractResBlockParams(36864, 64, 3, true)
const conv64_1 = extractResBlockParams(36864, 64, 3)
const conv64_2 = extractResBlockParams(36864, 64, 3)
const conv64_3 = extractResBlockParams(36864, 64, 3)
const conv128_in = extractResBlockParams(147456, 128, 3, true)
const conv128_1 = extractResBlockParams(147456, 128, 3)
const conv128_2 = extractResBlockParams(147456, 128, 3)
const conv256_in = extractResBlockParams(589824, 256, 3, true)
const conv256_1 = extractResBlockParams(589824, 256, 3)
const conv256_2 = extractResBlockParams(589824, 256, 3)
const conv256_3 = extractResBlockParams(589824, 256, 3)
const fc = tf.transpose(tf.tensor2d(extractWeights(256 * 128), [128, 256]), [1, 0])
if (weights.length !== 0) {
throw new Error(`weights remaing after extract: ${weights.length}`)
}
return {
conv32_in,
conv32_1,
conv32_2,
conv32_3,
conv64_in,
conv64_1,
conv64_2,
conv64_3,
conv128_in,
conv128_1,
conv128_2,
conv256_in,
conv256_1,
conv256_2,
conv256_3,
fc
}
}
export function faceRecognitionNet(weights: Float32Array) {
const params = extractParams(weights)
return function(input: number[]) {
return computeFaceDescriptor(input, params)
}
}
\ No newline at end of file
import * as tf from '@tensorflow/tfjs-core';
import { ConvLayerParams } from './convLayer';
import { ResidualLayerParams } from './residualLayer';
export type FaceRecognitionNetParams = {
conv32_down: ConvLayerParams
conv32_1: ResidualLayerParams
conv32_2: ResidualLayerParams
conv32_3: ResidualLayerParams
conv64_down: ResidualLayerParams
conv64_1: ResidualLayerParams
conv64_2: ResidualLayerParams
conv64_3: ResidualLayerParams
conv128_down: ResidualLayerParams
conv128_1: ResidualLayerParams
conv128_2: ResidualLayerParams
conv256_down: ResidualLayerParams
conv256_1: ResidualLayerParams
conv256_2: ResidualLayerParams
conv256_down_out: ResidualLayerParams
fc: tf.Tensor2D
}
\ No newline at end of file
import * as tf from '@tensorflow/tfjs-core';
import { scale, ScaleLayerParams } from './scaleLayer';
export type ConvParams = {
filters: tf.Tensor4D
biases: tf.Tensor1D
}
export type ConvLayerParams = {
conv: ConvParams
scale: ScaleLayerParams
}
function convLayer(
x: tf.Tensor4D,
params: ConvLayerParams,
stride: number,
withRelu: boolean,
padding: 'valid' | 'same' = 'same'
): tf.Tensor4D {
const { filters, biases } = params.conv
let out = tf.conv2d(x, filters, [stride, stride], padding)
out = tf.add(out, biases)
out = scale(out, params.scale)
return withRelu ? tf.relu(out) : out
}
export function conv(x: tf.Tensor4D, params: ConvLayerParams) {
return convLayer(x, params, 1, true)
}
export function convNoRelu(x: tf.Tensor4D, params: ConvLayerParams) {
return convLayer(x, params, 1, false)
}
export function convDown(x: tf.Tensor4D, params: ConvLayerParams) {
return convLayer(x, params, 2, true, 'valid')
}
\ No newline at end of file
import * as tf from '@tensorflow/tfjs-core';
import { ConvLayerParams } from './convLayer';
import { FaceRecognitionNetParams } from './FaceRecognitionNetParams';
import { ResidualLayerParams } from './residualLayer';
import { ScaleLayerParams } from './scaleLayer';
function isFloat(num: number) {
return num % 1 !== 0
}
function extractorsFactory(extractWeights: (numWeights: number) => Float32Array) {
function extractFilterValues(numFilterValues: number, numFilters: number, filterSize: number): tf.Tensor4D {
const weights = extractWeights(numFilterValues)
const depth = weights.length / (numFilters * filterSize * filterSize)
if (isFloat(depth)) {
throw new Error(`depth has to be an integer: ${depth}, weights.length: ${weights.length}, numFilters: ${numFilters}, filterSize: ${filterSize}`)
}
return tf.transpose(
tf.tensor4d(weights, [numFilters, depth, filterSize, filterSize]),
[2, 3, 1, 0]
)
}
function extractScaleLayerParams(numWeights: number): ScaleLayerParams {
const weights = tf.tensor1d(extractWeights(numWeights))
const biases = tf.tensor1d(extractWeights(numWeights))
return {
weights,
biases
}
}
function extractConvLayerParams(numFilterValues: number, numFilters: number, filterSize: number): ConvLayerParams {
const conv_filters = extractFilterValues(numFilterValues, numFilters, filterSize)
const conv_biases = tf.tensor1d(extractWeights(numFilters))
const scale = extractScaleLayerParams(numFilters)
return {
conv: {
filters: conv_filters,
biases: conv_biases
},
scale
}
}
function extractResidualLayerParams(numFilterValues: number, numFilters: number, filterSize: number, isDown: boolean = false): ResidualLayerParams {
const conv1: ConvLayerParams = extractConvLayerParams((isDown ? 0.5 : 1) * numFilterValues, numFilters, filterSize)
const conv2: ConvLayerParams = extractConvLayerParams(numFilterValues, numFilters, filterSize)
return {
conv1,
conv2
}
}
return {
extractConvLayerParams,
extractResidualLayerParams
}
}
export function extractParams(weights: Float32Array): FaceRecognitionNetParams {
const extractWeights = (numWeights: number): Float32Array => {
const ret = weights.slice(0, numWeights)
weights = weights.slice(numWeights)
return ret
}
const {
extractConvLayerParams,
extractResidualLayerParams
} = extractorsFactory(extractWeights)
const conv32_down = extractConvLayerParams(4704, 32, 7)
const conv32_1 = extractResidualLayerParams(9216, 32, 3)
const conv32_2 = extractResidualLayerParams(9216, 32, 3)
const conv32_3 = extractResidualLayerParams(9216, 32, 3)
const conv64_down = extractResidualLayerParams(36864, 64, 3, true)
const conv64_1 = extractResidualLayerParams(36864, 64, 3)
const conv64_2 = extractResidualLayerParams(36864, 64, 3)
const conv64_3 = extractResidualLayerParams(36864, 64, 3)
const conv128_down = extractResidualLayerParams(147456, 128, 3, true)
const conv128_1 = extractResidualLayerParams(147456, 128, 3)
const conv128_2 = extractResidualLayerParams(147456, 128, 3)
const conv256_down = extractResidualLayerParams(589824, 256, 3, true)
const conv256_1 = extractResidualLayerParams(589824, 256, 3)
const conv256_2 = extractResidualLayerParams(589824, 256, 3)
const conv256_down_out = extractResidualLayerParams(589824, 256, 3)
const fc = tf.transpose(tf.tensor2d(extractWeights(256 * 128), [128, 256]), [1, 0])
if (weights.length !== 0) {
throw new Error(`weights remaing after extract: ${weights.length}`)
}
return {
conv32_down,
conv32_1,
conv32_2,
conv32_3,
conv64_down,
conv64_1,
conv64_2,
conv64_3,
conv128_down,
conv128_1,
conv128_2,
conv256_down,
conv256_1,
conv256_2,
conv256_down_out,
fc
}
}
\ No newline at end of file
import * as tf from '@tensorflow/tfjs-core';
import { normalize } from '../normalize';
import { convDown } from './convLayer';
import { extractParams } from './extractParams';
import { residual, residualDown } from './residualLayer';
export function faceRecognitionNet(weights: Float32Array) {
const params = extractParams(weights)
return function (input: number[]) {
const x = tf.tensor4d(normalize(input), [1, 150, 150, 3])
let out = convDown(x, params.conv32_down)
out = tf.maxPool(out, 3, 2, 'valid')
out = residual(out, params.conv32_1)
out = residual(out, params.conv32_2)
out = residual(out, params.conv32_3)
out = residualDown(out, params.conv64_down)
out = residual(out, params.conv64_1)
out = residual(out, params.conv64_2)
out = residual(out, params.conv64_3)
out = residualDown(out, params.conv128_down)
out = residual(out, params.conv128_1)
out = residual(out, params.conv128_2)
out = residualDown(out, params.conv256_down)
out = residual(out, params.conv256_1)
out = residual(out, params.conv256_2)
out = residualDown(out, params.conv256_down_out)
const globalAvg = out.mean([1, 2]) as tf.Tensor2D
const fullyConnected = tf.matMul(globalAvg, params.fc)
return Array.from(fullyConnected.dataSync())
}
}
\ No newline at end of file
import * as tf from '@tensorflow/tfjs-core';
import { conv, convNoRelu, ConvLayerParams, convDown } from './convLayer';
export type ResidualLayerParams = {
conv1: ConvLayerParams
conv2: ConvLayerParams
}
export function residual(x: tf.Tensor4D, params: ResidualLayerParams): tf.Tensor4D {
let out = conv(x, params.conv1)
out = convNoRelu(out, params.conv2)
out = tf.add(out, x)
out = tf.relu(out)
return out
}
export function residualDown(x: tf.Tensor4D, params: ResidualLayerParams): tf.Tensor4D {
let out = convDown(x, params.conv1)
out = convNoRelu(out, params.conv2)
let pooled = tf.avgPool(x, 2, 2, 'valid') as tf.Tensor4D
const zeros = tf.zeros<tf.Rank.R4>(pooled.shape)
const isPad = pooled.shape[3] !== out.shape[3]
const isAdjustShape = pooled.shape[1] !== out.shape[1] || pooled.shape[2] !== out.shape[2]
if (isAdjustShape) {
const padShapeX = [...out.shape] as [number, number, number, number]
padShapeX[1] = 1
const zerosW = tf.zeros<tf.Rank.R4>(padShapeX)
out = tf.concat([out, zerosW], 1)
const padShapeY = [...out.shape] as [number, number, number, number]
padShapeY[2] = 1
const zerosH = tf.zeros<tf.Rank.R4>(padShapeY)
out = tf.concat([out, zerosH], 2)
}
pooled = isPad ? tf.concat([pooled, zeros], 3) : pooled
out = tf.add(pooled, out) as tf.Tensor4D
out = tf.relu(out)
return out
}
\ No newline at end of file
import * as tf from '@tensorflow/tfjs-core';
export type ScaleLayerParams = {
weights: tf.Tensor1D
biases: tf.Tensor1D
}
export function scale(x: tf.Tensor4D, params: ScaleLayerParams): tf.Tensor4D {
return tf.add(tf.mul(x, params.weights), params.biases)
}
\ No newline at end of file
import { euclideanDistance } from './euclideanDistance'; import { euclideanDistance } from './euclideanDistance';
import { faceRecognitionNet } from './faceRecognitionNet'; import { faceRecognitionNet } from './faceRecognitionNet';
import { normalize } from './normalize';
export { export {
euclideanDistance, euclideanDistance,
faceRecognitionNet faceRecognitionNet,
normalize
} }
\ No newline at end of file
export function normalize(arr: number[]) {
const avg_r = 122.782;
const avg_g = 117.001;
const avg_b = 104.298;
const avgs = [avg_r, avg_g, avg_b]
return arr.map((val, i) => {
const avg = avgs[i % 3]
return (val - avg) / 256
})
}
\ 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