Я писал нейронную сеть с нуля, чтобы учиться. но так как я все еще учусь - я хочу убедиться, что то, что я пишу, на самом деле правильно. У меня есть массив массивов (матрица), объектов ячеек. прикрепленный к объекту «мозг», который имеет следующие два метода:
train: function(data)
{
for (let b=0; b< data.length; b++)// for the length of the training data - I.E. we are going assume we are getting many relatively shortly indexed arrays
{
if(data[b].answers.length != data[b].questions.length)
{
console.log("bad data");
return false;
}
for(let c=0;c<data[b].questions.length;c++)
{
brain.attachInputLayer(data[b].questions[c]);
brain.updateForward();
let direction = brain.determinDirection(data[b].answers[c]); //return an array of updateObject with determined weights bias value adjustments, which each cell gets updated order should be from generation by column;
brain.cellMatrix.forEach(cellArray=> cellArray.forEach(cell=> cell.adjust(direction.find(x=> x.ID ===cell.ID))));
brain.updateForward();
brain.displayBrain();
}
}
console.log("all training data done");
alert("win?");
console.log(brain.cellMatrix);
console.log("brain");
}
and
determinDirection:function(answer)
{
// answer is the array of values of each answer cell we want as a result
let arrayOfUpDateObjectsForCell = [];
for(let e=0; e<answer.length; e++)
{
let answerCell = brain.cellMatrix[cellMatrix.length-1][e];
let returnBucket = [];
arrayOfUpDateObjectsForCell.push(answerCell.whatIwant(answer[e], returnBucket));
}
let list = Flat(arrayOfUpDateObjectsForCell);
let realList = Clean(list);
return realList;
}
, поэтому каждая ячейка последнего поколения (вывод ответа) вызывает метод whatIwant в brain.train (), эта функция распространяется в обратном направлении по сети ... но мой вопрос на самом деле заключается в следующем :::
::: похоже, что я вычисляю ошибку / направление для правильного перемещения каждого значения? правильно ли усреднять изменения между дублированными объектами updateObjects? (требуемыйObjectchange для cell.gen = 3, order = 0 создается из каждой ячейки следующего слоя, вызывающей whatIwant. Изменения cell.gen = 4, order = 0 хочет cell.gen = 3, order = 0 для усреднения с изменениями cell.gen = 4, order = 1 хочет для cell.gen = 3, order = 0). усредняет правильную операцию здесь?
:::
whatIwant:function(answerValue, returnArray)
{
let desiredWeights = this.weights;
let desiredBias = this.bias;
let desiredActivations = this.activations;
let error = (1/2)*Math.pow(cell.value-answerValue,2);
let desiredObjectChange =
{
ID:this.ID,
weights:this.weights,
bias:this.bias,
activations:this.activations,
value:answerValue,
combine:function(yourCloneFriend)
{
if(yourCloneFriend == false)
{
return;
}
this.bias = (1/2)*(this.bias+yourCloneFriend.bias);
let cWeight = yourCloneFriend.weights[Symbol.iterator]();
let cActivations = yourCloneFriend.activations[Symbol.iterator]();
this.weights.forEach(x=> (1/2)*(x+cWeight.next().value));
this.activations.forEach(y=> (1/2)*(y+cActivations.next().value));
this.recalculateValue();
return this;
},
recalculateValue:function()
{
this.value = Sigmoid(arrayMultiply(this.weights, this.activations)+this.bias);
}
}
for(let k = 0; k< this.weights.length; k++)
{
let lastValue = Sigmoid(arrayMultiply(desiredWeights, desiredActivations)+desiredBias);
let lastError = (1/2)*Math.pow(lastValue-answerValue,2);
for(let l=0;l<3;l++)
{
let currentValue = Sigmoid(arrayMultiply(desiredObjectChange.weights, desiredObjectChange.activations)+desiredObjectChange.bias);
let currentError = (1/2)*Math.pow(currentValue-answerValue,2);
let positiveRange = false;
if(desiredWeights[k] < 0){ positiveRange = true;}
let nudgedWeightArray = NudgeArray(desiredWeights, k, l, positiveRange); //returns a copy array to test, with weight adjusted.
let testWeightChange = Sigmoid(arrayMultiply(nudgedWeightArray,desiredActivations)+desiredBias);
let testWeightError = (1/nudgedWeightArray.length)*Math.pow(testWeightChange - answerValue, 2);
let testWeightResult = compareSmallnumbers('isSmaller', currentError, testWeightError);
if(testWeightResult);
{
desiredWeights = nudgedWeightArray;
currentError = testWeightError;
}
positiveRange=false;
if(desiredBias < 0){positiveRange = true;}
let nudgedBiasVal = this.nudge(desiredBias,l,positiveRange);
let testBiasChange = Sigmoid(nudgedBiasVal+desiredWeights[k]*desiredActivations[k]);
let testBiasError = (1/1)*Math.pow(testBiasChange - answerValue, 2);
let testBiastResult = ('isSmaller', currentError, testBiasError);
if(testBiastResult);
{
desiredBias = nudgedBiasVal;
currentError = testBiasError;
}
positiveRange=!!Math.random(0,1)>5;
let nudgedAcitivationArray = NudgeArray(desiredActivations,k,l,positiveRange);
let testActivationChange = Sigmoid(arrayMultiply(nudgedAcitivationArray,desiredWeights)+desiredBias);
let testActivationError = (1/nudgedAcitivationArray.length)*Math.pow(testActivationChange - answerValue, 2);
let testActivationResult = compareSmallnumbers('isSmaller', currentError, testActivationError);
if(testActivationResult);
{
desiredActivations[k] = nudgedAcitivationArray[k];
currentError = testActivationError;
}
//and the end of the loop, update the error to the new value
let errorResult = compareSmallnumbers('isSmaller',lastError, currentError);
if(errorResult)
{
lastError = currentError;
}
}
desiredObjectChange.weights[k] = desiredWeights[k];
desiredObjectChange.bias = desiredBias;
desiredObjectChange.activations[k] = desiredActivations[k];
desiredObjectChange.value = Sigmoid(arrayMultiply(desiredObjectChange.weights, desiredObjectChange.activations)+desiredObjectChange.bias);
}
let combineObject = returnArray.find(x=>x.ID === desiredObjectChange.ID);
if(!combineObject)
{
returnArray.push(desiredObjectChange);
}
//that was this object - simple stuff, now we need to call this function
if(Array.isArray(cell.lastGenerationTargetKeys) && cell.lastGenerationTargetKeys.length)
{
let nextActivation = desiredObjectChange.activations[Symbol.iterator]();
brain.cellMatrix[cell.generation-1].forEach(x=> x.whatIwant(nextActivation.next().value, returnArray));
return returnArray;
}
else
{
return;
}
},
clean, flat и NudgeArray - это: *
function Clean(array)
{
let rArray = [];
array.forEach((x)=>
{
let search = rArray.find(y=>y.ID ===x.ID);
if(search === undefined)
{
rArray.push(x);
}
else
{
rArray[rArray.indexOf(search)].combine(x);
}
});
return rArray;
}
function Flat(array)
{
let holdBucket = [];
let flatten = function(array)
{
for(let i = 0; i<array.length;i++)
{
if(Array.isArray(array[i]))
{
flatten(array[i]);
}
else
{
holdBucket.push(array[i]);
}
}
}
flatten(array);
return holdBucket;
}
function NudgeArray(array ,arrayIndex, Nudgeindex, isPositive)
{//nudge index is designed to act like a variable learning rate modifier, as it tests, jumps decrease in size
let returnArray = [];
array.forEach(x=>returnArray.push(x));
let value = returnArray[arrayIndex];
if(isPositive)
{
value+=(Math.random(0,1)/(Nudgeindex+3));
value = Sigmoid(value);
}
else
{
value+=(Math.random(-1,1)/(Nudgeindex+3));
value = Sigmoid(value);
}
returnArray.splice(arrayIndex,1,value);
return returnArray;
}