2021-07-28 12:04:00 -04:00
|
|
|
import { default as M, Cloud } from "./m.ts";
|
2021-07-28 14:08:46 -04:00
|
|
|
export type N = Array<Array<Array<number>>>
|
2021-07-28 12:04:00 -04:00
|
|
|
|
2021-07-29 08:42:28 -04:00
|
|
|
const Forward = (inData:Cloud.M, inLayers:N):N =>
|
2021-07-28 12:04:00 -04:00
|
|
|
{
|
|
|
|
let i:number;
|
2021-07-29 14:51:00 -04:00
|
|
|
let stages:N = [inData];
|
2021-07-29 08:42:28 -04:00
|
|
|
let process = (index:number):Cloud.M => M.Batch.Sigmoid(M.Batch.Affine(stages[index], inLayers[index]));
|
2021-07-28 12:04:00 -04:00
|
|
|
|
2021-07-29 14:51:00 -04:00
|
|
|
for(i=0; i<inLayers.length-1; i++){ stages[i+1] = M.Mutate.Pad(process(i)); }
|
2021-07-29 08:42:28 -04:00
|
|
|
stages[i+1] = process(i);
|
|
|
|
return stages;
|
2021-07-28 12:04:00 -04:00
|
|
|
};
|
2021-07-28 16:40:58 -04:00
|
|
|
const Backward = (inStages:N, inLayers:N, inGoals:Cloud.M, inRate:number):N =>
|
2021-07-28 12:04:00 -04:00
|
|
|
{
|
|
|
|
let i:number;
|
2021-07-29 08:42:28 -04:00
|
|
|
let errorBack:Cloud.M = M.Batch.Subtract(inStages[inStages.length-1], inGoals);
|
|
|
|
|
2021-07-28 14:08:46 -04:00
|
|
|
for(i=inLayers.length-1; i>=0; i--)
|
2021-07-28 12:04:00 -04:00
|
|
|
{
|
2021-07-29 14:51:00 -04:00
|
|
|
let errorScaled:Cloud.M = M.Batch.Multiply(errorBack, M.Batch.Derivative(inStages[i+1]));
|
2021-07-28 16:40:58 -04:00
|
|
|
errorBack = M.Batch.Affine(errorScaled, M.Create.Transpose(inLayers[i]));
|
2021-07-29 14:51:00 -04:00
|
|
|
errorScaled.forEach((inScaledError:Cloud.V, inIndex:number)=>
|
|
|
|
{
|
|
|
|
inLayers[i] = M.Batch.Subtract(
|
|
|
|
inLayers[i],
|
|
|
|
M.Batch.Scale(M.Create.Outer(inStages[i][inIndex], inScaledError), inRate)
|
|
|
|
);
|
2021-07-28 12:04:00 -04:00
|
|
|
});
|
|
|
|
}
|
2021-07-28 16:40:58 -04:00
|
|
|
return inLayers;
|
2021-07-28 12:04:00 -04:00
|
|
|
};
|
2021-07-29 14:51:00 -04:00
|
|
|
const Split = (inTrainingSet:Cloud.M, inHeaderLabel:Cloud.V, inHeaderKeep:Cloud.V = []):N =>
|
|
|
|
{
|
|
|
|
let data:Cloud.M = [];
|
|
|
|
let label:Cloud.M = [];
|
|
|
|
if(!inHeaderKeep.length)
|
|
|
|
{
|
|
|
|
inTrainingSet[0].forEach( (item:number, index:number)=> inHeaderLabel.includes(index) ? false : inHeaderKeep.push(index) );
|
|
|
|
}
|
2021-07-29 16:15:05 -04:00
|
|
|
inTrainingSet.forEach((row:Cloud.V):void =>
|
2021-07-29 14:51:00 -04:00
|
|
|
{
|
2021-07-29 20:53:31 -04:00
|
|
|
data.push( inHeaderKeep.map((i:number)=>row[i]) );
|
|
|
|
label.push( inHeaderLabel.map((i:number)=>row[i]) );
|
2021-07-29 14:51:00 -04:00
|
|
|
});
|
|
|
|
return [ data, label ];
|
|
|
|
};
|
|
|
|
const Build = (...inLayers:Array<number>):N =>
|
|
|
|
{
|
|
|
|
let i:number;
|
|
|
|
let output:N = [];
|
|
|
|
let rand = (inDimensions:number, inCount:number):Cloud.M => M.Create.Box( new Array(inDimensions).fill(-1), new Array(inDimensions).fill(1), inCount);
|
|
|
|
for(i=0; i<inLayers.length-1; i++)
|
|
|
|
{
|
|
|
|
output.push(rand( inLayers[i]+1, inLayers[i+1]));
|
|
|
|
}
|
|
|
|
return output;
|
|
|
|
};
|
|
|
|
const Label = (inData:Cloud.M, inLayers:N):Cloud.M =>
|
|
|
|
{
|
2021-07-29 20:53:31 -04:00
|
|
|
let stages:N = Forward(M.Create.Padded(inData), inLayers);
|
2021-07-29 14:51:00 -04:00
|
|
|
return stages[stages.length-1];
|
|
|
|
};
|
|
|
|
const Learn = (inData:Cloud.M, inLayers:N, inLabels:Cloud.M, inIterations:number, inRate:number):Cloud.M =>
|
|
|
|
{
|
|
|
|
let stages:N = [];
|
|
|
|
for(let i=0; i<inIterations; i++)
|
|
|
|
{
|
2021-07-29 20:53:31 -04:00
|
|
|
stages = Forward(M.Create.Padded(inData), inLayers);
|
2021-07-29 14:51:00 -04:00
|
|
|
Backward(stages, inLayers, inLabels, inRate);
|
|
|
|
}
|
|
|
|
return M.Batch.Subtract(stages[stages.length-1], inLabels);
|
|
|
|
};
|
2021-07-29 16:15:05 -04:00
|
|
|
const Check = (inData:Cloud.M, inLayers:N, inLabels:Cloud.M):Cloud.M => Learn(inData, inLayers, inLabels, 1, 0);
|
2021-07-28 12:04:00 -04:00
|
|
|
|
2021-07-29 16:15:05 -04:00
|
|
|
export { Split, Build, Label, Learn, Check, Forward, Backward };
|