Skip to content

Commit b396559

Browse files
fix: Ts & lint
1 parent c8a62f1 commit b396559

File tree

3 files changed

+94
-83
lines changed

3 files changed

+94
-83
lines changed

src/autoencoder.test.ts

+47-58
Original file line numberDiff line numberDiff line change
@@ -1,79 +1,68 @@
1-
import AE from "./autoencoder";
1+
import AE from './autoencoder';
22

33
const trainingData = [
44
[0, 0, 0],
55
[0, 1, 1],
66
[1, 0, 1],
7-
[1, 1, 0]
7+
[1, 1, 0],
88
];
99

10-
const xornet = new AE<number[], number[]>(
11-
{
12-
decodedSize: 3,
13-
hiddenLayers: [ 5, 2, 5 ]
14-
}
15-
);
10+
const xornet = new AE<number[], number[]>({
11+
decodedSize: 3,
12+
hiddenLayers: [5, 2, 5],
13+
});
1614

1715
const errorThresh = 0.011;
1816

19-
const result = xornet.train(
20-
trainingData, {
21-
iterations: 100000,
22-
errorThresh
23-
}
24-
);
25-
26-
test(
27-
"denoise a data sample",
28-
async () => {
29-
expect(result.error).toBeLessThanOrEqual(errorThresh);
30-
31-
function xor(...args: number[]) {
32-
return Math.round(xornet.denoise(args)[2]);
33-
}
17+
const result = xornet.train(trainingData, {
18+
iterations: 100000,
19+
errorThresh,
20+
});
3421

35-
const run1 = xor(0, 0, 0);
36-
const run2 = xor(0, 1, 1);
37-
const run3 = xor(1, 0, 1);
38-
const run4 = xor(1, 1, 0);
22+
test('denoise a data sample', async () => {
23+
expect(result.error).toBeLessThanOrEqual(errorThresh);
3924

40-
expect(run1).toBe(0);
41-
expect(run2).toBe(1);
42-
expect(run3).toBe(1);
43-
expect(run4).toBe(0);
25+
function xor(...args: number[]) {
26+
return Math.round(xornet.denoise(args)[2]);
4427
}
45-
);
4628

47-
test(
48-
"encode and decode a data sample",
49-
async () => {
50-
expect(result.error).toBeLessThanOrEqual(errorThresh);
29+
const run1 = xor(0, 0, 0);
30+
const run2 = xor(0, 1, 1);
31+
const run3 = xor(1, 0, 1);
32+
const run4 = xor(1, 1, 0);
5133

52-
const run1$input = [0, 0, 0];
53-
const run1$encoded = xornet.encode(run1$input);
54-
const run1$decoded = xornet.decode(run1$encoded);
34+
expect(run1).toBe(0);
35+
expect(run2).toBe(1);
36+
expect(run3).toBe(1);
37+
expect(run4).toBe(0);
38+
});
5539

56-
const run2$input = [0, 1, 1];
57-
const run2$encoded = xornet.encode(run2$input);
58-
const run2$decoded = xornet.decode(run2$encoded);
40+
test('encode and decode a data sample', async () => {
41+
expect(result.error).toBeLessThanOrEqual(errorThresh);
5942

60-
for (let i = 0; i < 3; i++) expect(Math.round(run1$decoded[i])).toBe(run1$input[i]);
61-
for (let i = 0; i < 3; i++) expect(Math.round(run2$decoded[i])).toBe(run2$input[i]);
62-
}
63-
);
43+
const run1$input = [0, 0, 0];
44+
const run1$encoded = xornet.encode(run1$input);
45+
const run1$decoded = xornet.decode(run1$encoded);
46+
47+
const run2$input = [0, 1, 1];
48+
const run2$encoded = xornet.encode(run2$input);
49+
const run2$decoded = xornet.decode(run2$encoded);
6450

65-
test(
66-
"test a data sample for anomalies",
67-
async () => {
68-
expect(result.error).toBeLessThanOrEqual(errorThresh);
51+
for (let i = 0; i < 3; i++)
52+
expect(Math.round(run1$decoded[i])).toBe(run1$input[i]);
53+
for (let i = 0; i < 3; i++)
54+
expect(Math.round(run2$decoded[i])).toBe(run2$input[i]);
55+
});
6956

70-
function includesAnomalies(...args: number[]) {
71-
expect(xornet.likelyIncludesAnomalies(args)).toBe(false);
72-
}
57+
test('test a data sample for anomalies', async () => {
58+
expect(result.error).toBeLessThanOrEqual(errorThresh);
7359

74-
includesAnomalies(0, 0, 0);
75-
includesAnomalies(0, 1, 1);
76-
includesAnomalies(1, 0, 1);
77-
includesAnomalies(1, 1, 0);
60+
function includesAnomalies(...args: number[]) {
61+
expect(xornet.likelyIncludesAnomalies(args)).toBe(false);
7862
}
79-
);
63+
64+
includesAnomalies(0, 0, 0);
65+
includesAnomalies(0, 1, 1);
66+
includesAnomalies(1, 0, 1);
67+
includesAnomalies(1, 1, 0);
68+
});

src/autoencoder.ts

+40-20
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,16 @@
1-
import { KernelOutput, Texture, TextureArrayOutput } from "gpu.js";
2-
import { IJSONLayer, INeuralNetworkData, INeuralNetworkDatum, INeuralNetworkTrainOptions } from "./neural-network";
3-
import { INeuralNetworkGPUOptions, NeuralNetworkGPU } from "./neural-network-gpu";
4-
import { INeuralNetworkState } from "./neural-network-types";
5-
import { UntrainedNeuralNetworkError } from "./errors/untrained-neural-network-error";
1+
import { KernelOutput, Texture, TextureArrayOutput } from 'gpu.js';
2+
import {
3+
IJSONLayer,
4+
INeuralNetworkData,
5+
INeuralNetworkDatum,
6+
INeuralNetworkTrainOptions,
7+
} from './neural-network';
8+
import {
9+
INeuralNetworkGPUOptions,
10+
NeuralNetworkGPU,
11+
} from './neural-network-gpu';
12+
import { INeuralNetworkState } from './neural-network-types';
13+
import { UntrainedNeuralNetworkError } from './errors/untrained-neural-network-error';
614

715
export interface IAEOptions {
816
binaryThresh: number;
@@ -13,13 +21,14 @@ export interface IAEOptions {
1321
/**
1422
* An autoencoder learns to compress input data down to relevant features and reconstruct input data from its compressed representation.
1523
*/
16-
export class AE<DecodedData extends INeuralNetworkData, EncodedData extends INeuralNetworkData> {
24+
export class AE<
25+
DecodedData extends INeuralNetworkData,
26+
EncodedData extends INeuralNetworkData
27+
> {
1728
private decoder?: NeuralNetworkGPU<EncodedData, DecodedData>;
18-
private denoiser: NeuralNetworkGPU<DecodedData, DecodedData>;
29+
private readonly denoiser: NeuralNetworkGPU<DecodedData, DecodedData>;
1930

20-
constructor (
21-
options?: Partial<IAEOptions>
22-
) {
31+
constructor(options?: Partial<IAEOptions>) {
2332
// Create default options for the autoencoder.
2433
options ??= {};
2534

@@ -32,7 +41,9 @@ export class AE<DecodedData extends INeuralNetworkData, EncodedData extends INeu
3241
denoiserOptions.hiddenLayers = options.hiddenLayers;
3342

3443
// Define the denoiser subnet's input and output sizes.
35-
if (options.decodedSize) denoiserOptions.inputSize = denoiserOptions.outputSize = options.decodedSize;
44+
if (options.decodedSize)
45+
denoiserOptions.inputSize = denoiserOptions.outputSize =
46+
options.decodedSize;
3647

3748
// Create the denoiser subnet of the autoencoder.
3849
this.denoiser = new NeuralNetworkGPU<DecodedData, DecodedData>(options);
@@ -82,7 +93,8 @@ export class AE<DecodedData extends INeuralNetworkData, EncodedData extends INeu
8293
this.denoiser.run(input);
8394

8495
// Get the auto-encoded input.
85-
let encodedInput: TextureArrayOutput = this.encodedLayer as TextureArrayOutput;
96+
let encodedInput: TextureArrayOutput = this
97+
.encodedLayer as TextureArrayOutput;
8698

8799
// If the encoded input is a `Texture`, convert it into an `Array`.
88100
if (encodedInput instanceof Texture) encodedInput = encodedInput.toArray();
@@ -100,7 +112,7 @@ export class AE<DecodedData extends INeuralNetworkData, EncodedData extends INeu
100112
* @param {DecodedData} input
101113
* @returns {boolean}
102114
*/
103-
likelyIncludesAnomalies(input: DecodedData, anomalyThreshold: number = 0.2): boolean {
115+
likelyIncludesAnomalies(input: DecodedData, anomalyThreshold = 0.2): boolean {
104116
// Create the anomaly vector.
105117
const anomalies: number[] = [];
106118

@@ -109,7 +121,9 @@ export class AE<DecodedData extends INeuralNetworkData, EncodedData extends INeu
109121

110122
// Calculate the anomaly vector.
111123
for (let i = 0; i < (input.length ?? 0); i++) {
112-
anomalies[i] = Math.abs((input as number[])[i] - (denoised as number[])[i]);
124+
anomalies[i] = Math.abs(
125+
(input as number[])[i] - (denoised as number[])[i]
126+
);
113127
}
114128

115129
// Calculate the sum of all anomalies within the vector.
@@ -131,11 +145,17 @@ export class AE<DecodedData extends INeuralNetworkData, EncodedData extends INeu
131145
* @param {Partial<INeuralNetworkTrainOptions>} options
132146
* @returns {INeuralNetworkState}
133147
*/
134-
train(data: DecodedData[], options?: Partial<INeuralNetworkTrainOptions>): INeuralNetworkState {
135-
const preprocessedData: INeuralNetworkDatum<Partial<DecodedData>, Partial<DecodedData>>[] = [];
136-
137-
for (let datum of data) {
138-
preprocessedData.push( { input: datum, output: datum } );
148+
train(
149+
data: DecodedData[],
150+
options?: Partial<INeuralNetworkTrainOptions>
151+
): INeuralNetworkState {
152+
const preprocessedData: Array<INeuralNetworkDatum<
153+
Partial<DecodedData>,
154+
Partial<DecodedData>
155+
>> = [];
156+
157+
for (const datum of data) {
158+
preprocessedData.push({ input: datum, output: datum });
139159
}
140160

141161
const results = this.denoiser.train(preprocessedData, options);
@@ -168,7 +188,7 @@ export class AE<DecodedData extends INeuralNetworkData, EncodedData extends INeu
168188

169189
const decoder = new NeuralNetworkGPU().fromJSON(json);
170190

171-
return decoder as unknown as NeuralNetworkGPU<EncodedData, DecodedData>;
191+
return (decoder as unknown) as NeuralNetworkGPU<EncodedData, DecodedData>;
172192
}
173193

174194
/**
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1-
export class UntrainedNeuralNetworkError extends Error {
2-
constructor (
3-
neuralNetwork: any
4-
) {
5-
super(`Cannot run a ${neuralNetwork.constructor.name} before it is trained.`);
1+
export class UntrainedNeuralNetworkError<
2+
T extends { constructor: { name: string } }
3+
> extends Error {
4+
constructor(neuralNetwork: T) {
5+
super(
6+
`Cannot run a ${neuralNetwork.constructor.name} before it is trained.`
7+
);
68
}
79
}

0 commit comments

Comments
 (0)