diff --git a/m.ts b/m.ts index 6ea74dd..f09c07d 100644 --- a/m.ts +++ b/m.ts @@ -1,15 +1,18 @@ -export type V = Array; -export type M = Array; -export type HandleLoop = (indexComponent:number, indexRow:number, array:Array) => number; -export type HandleEdit = (component:number, index:number, array:Array) => number; +export namespace Cloud +{ + export type V = Array + export type M = Array> + export type HandleLoop = (indexComponent:number, indexRow:number, array:Array) => number + export type HandleEdit = (component:number, index:number, array:Array) => number +}; const Methods = { Iterate: { - Loop: (inDimensions:number, inCount:number, inFunction:HandleLoop):M => + Loop: (inDimensions:number, inCount:number, inFunction:Cloud.HandleLoop):Cloud.M => { - let i:number, j:number, outputVector:V; - const outputCloud:M = []; + let i:number, j:number, outputVector:Cloud.V; + const outputCloud:Cloud.M = []; for(i=0; i inCloud.map((row:V):V=>row.map(inFunction)) + Edit: (inCloud:Cloud.M, inFunction:Cloud.HandleEdit):Cloud.M=> inCloud.map((row:Cloud.V):Cloud.V=>row.map(inFunction)) }, Create: { - Box: (inV1:V, inV2:V, inCount:number):M=> Methods.Iterate.Loop(inV1.length, inCount, i=> inV1[i]+(inV2[i]-inV1[i])*Math.random()), - Transpose: (inCloud:M):M=> Methods.Iterate.Loop(inCloud.length, inCloud[0].length, (i, row)=> inCloud[i][row]), - Outer: (inV1:V, inV2:V):M=> Methods.Iterate.Loop(inV1.length, inV2.length, (i, row)=> inV1[i]*inV2[row]), - Clone: (inCloud:M):M=> Methods.Iterate.Edit(inCloud, i=> i) + Box: (inV1:Cloud.V, inV2:Cloud.V, inCount:number):Cloud.M=> Methods.Iterate.Loop(inV1.length, inCount, i=> inV1[i]+(inV2[i]-inV1[i])*Math.random()), + Transpose: (inCloud:Cloud.M):Cloud.M=> Methods.Iterate.Loop(inCloud.length, inCloud[0].length, (i, row)=> inCloud[i][row]), + Outer: (inV1:Cloud.V, inV2:Cloud.V):Cloud.M=> Methods.Iterate.Loop(inV1.length, inV2.length, (i, row)=> inV1[i]*inV2[row]), + Clone: (inCloud:Cloud.M):Cloud.M=> Methods.Iterate.Edit(inCloud, i=> i) }, Mutate: { - Pad: (inCloud:M):void=> inCloud.forEach(row=> row.push(1)), - Unpad: (inCloud:M):void=> inCloud.forEach(row=> row.pop()) + Pad: (inCloud:Cloud.M):Cloud.M=> {inCloud.forEach((row:Cloud.V)=> row.push(1)); return inCloud; }, + Unpad: (inCloud:Cloud.M):Cloud.M=> {inCloud.forEach((row:Cloud.V)=> row.pop()); return inCloud; } }, Single: { - Subtract: (inV1:V, inV2:V):V=> inV1.map((component, i)=> component-inV2[i]), - Multiply: (inV1:V, inV2:V):V=> inV1.map((component, i)=> component*inV2[i]), - Affine: (inV:V, inMatrix:M):V=> inMatrix.map(row=> row.reduce((sum, current, index)=> sum + current*inV[index])) + Subtract: (inV1:Cloud.V, inV2:Cloud.V):Cloud.V=> inV1.map((component, i)=> component-inV2[i]), + Multiply: (inV1:Cloud.V, inV2:Cloud.V):Cloud.V=> inV1.map((component, i)=> component*inV2[i]), + Affine: (inV:Cloud.V, inMatrix:Cloud.M):Cloud.V=> inMatrix.map((row:Cloud.V)=> row.reduce((sum, current, index)=> sum + current*inV[index])) }, Batch: { - Subtract: (inCloud1:M, inCloud2:M):M=> inCloud1.map((row, rowIndex)=> Methods.Single.Subtract(row, inCloud2[rowIndex])), - Multiply: (inCloud1:M, inCloud2:M):M=> inCloud1.map((row, rowIndex)=> Methods.Single.Multiply(row, inCloud2[rowIndex])), - Affine: (inCloud:M, inMatrix:M):M=> inCloud.map(row=> Methods.Single.Affine(row, inMatrix)), - Sigmoid: (inCloud:M):M=> Methods.Iterate.Edit(inCloud, i=>1/(1+Math.pow(Math.E, -i))), - Derivative: (inCloud:M):M=> Methods.Iterate.Edit(inCloud, i=>i*(1-i)), - Scale: (inCloud:M, inScalar:number):M=> Methods.Iterate.Edit(inCloud, i=>i*inScalar) + Subtract: (inCloud1:Cloud.M, inCloud2:Cloud.M):Cloud.M=> inCloud1.map((row:Cloud.V, rowIndex:number)=> Methods.Single.Subtract(row, inCloud2[rowIndex])), + Multiply: (inCloud1:Cloud.M, inCloud2:Cloud.M):Cloud.M=> inCloud1.map((row:Cloud.V, rowIndex:number)=> Methods.Single.Multiply(row, inCloud2[rowIndex])), + Affine: (inCloud1:Cloud.M, inCloud2:Cloud.M):Cloud.M=> inCloud1.map((row:Cloud.V)=> Methods.Single.Affine(row, inCloud2)), + Sigmoid: (inCloud:Cloud.M):Cloud.M=> Methods.Iterate.Edit(inCloud, i=>1/(1+Math.pow(Math.E, -i))), + Derivative: (inCloud:Cloud.M):Cloud.M=> Methods.Iterate.Edit(inCloud, i=>i*(1-i)), + Scale: (inCloud:Cloud.M, inScalar:number):Cloud.M=> Methods.Iterate.Edit(inCloud, i=>i*inScalar) } }; + + export default Methods; \ No newline at end of file diff --git a/nn.test.js b/nn.test.js new file mode 100644 index 0000000..6daee12 --- /dev/null +++ b/nn.test.js @@ -0,0 +1,14 @@ +import { assert, assertEquals } from "https://deno.land/std@0.102.0/testing/asserts.ts"; +import * as NN from "./nn.ts"; + +Deno.test("NN.Observe", ()=> +{ + console.log(NN.Observe([[[1, 2, 3]]], [[[0.4, 0.5, 0.6]]])); +}); +Deno.test("NN.Train", ()=> +{ + const stages = [[[1, 2, 3]]]; + const layers = [[[0.4, 0.5, 0.6]]]; + + console.log(NN.Train(stages, layers, [[0, 0, 1]], 0.1)); +}); diff --git a/nn.ts b/nn.ts new file mode 100644 index 0000000..e02fad0 --- /dev/null +++ b/nn.ts @@ -0,0 +1,36 @@ +import { default as M, Cloud } from "./m.ts"; + +const Observe = (inStages:Array, inLayers:Array):Cloud.M => +{ + let i:number; + let process = (index:number):Cloud.M => M.Batch.Sigmoid(M.Batch.Affine(inStages[index], inLayers[index])); + + for(i=0; i, inLayers:Array, inGoals:Cloud.M, inRate:number):void => +{ + let i:number; + let errorBack:Cloud.M = M.Batch.Subtract(Observe(inStages, inLayers), inGoals); + + for(i=inLayers.length-1; i>=0; i++) + { + let layerMatrix:Cloud.M = inLayers[i]; + let layerInput:Cloud.M = inStages[i]; + let layerOutput:Cloud.M = inStages[i+1]; + let errorScaled:Cloud.M = M.Batch.Multiply(errorBack, M.Batch.Derivative(layerOutput)); + + errorBack = M.Batch.Affine(errorScaled, M.Create.Transpose(layerMatrix)); + errorScaled.forEach((inScaledError:Cloud.V, inIndex:number)=> { + const deltas = M.Batch.Scale(M.Create.Outer(layerInput[inIndex], inScaledError), inRate); + layerMatrix = M.Batch.Subtract(layerMatrix, deltas); + }); + } +}; + +export { Observe, Train }; +export type { Cloud }; \ No newline at end of file diff --git a/nn.js b/nn_old.js similarity index 100% rename from nn.js rename to nn_old.js