js 编写神经网络

 

 

更新代码:2016.11.14 

全部代码实现了,B P算法。

 

所有论文公式晦涩难懂,特别是我们这种已经把微积分还给老师的人来说

 

总结下几个重要公式:

 

输出层每个细胞元:

误差=(目标值-输出值)*输出值*(1-输出值)

新权重=现在的权重+(学习率*上一个层每个细胞的输出值* 误差)

 

隐藏层每个细胞元:

误差=与之相连的下一层(输出层)的误差*与之相连的下一层(输出层)的权重

新权重=现在的权重++(学习率*上一个层每个细胞的输出值* 误差)

 

 

以上公式不包换:

动量项

自适应学习率

陡度印字

 

迭代的方式也不是卷积网络

 

此文章会持续更新,直到变完整

 

项目地址:https://github.com/roertech/neural

 

暂时没有上传代码。测试成功后会共享

 

 

 

   /****************************************** */
  //***产生随机数  * */  
 /****************************************** */
 var RandomClamped = (function randomclamped() {           
  function constructor() {
    this.arr=Math.round(((Math.random())*2-1)*100)/100; 
  }
  constructor.prototype ={
       constructor :constructor,
         get:function(){ return this.arr;}
     };
  return constructor;
})(); 
  
  
   /****************************************** */
  //***迭代   * */  
 /****************************************** */
   var Iterator = (function iterator() {           
  function constructor(arr) {
    this.arr=arr;
   this.length=arr.length;
   this.index=0; 
  }
  constructor.prototype ={
       constructor :constructor,
         hasNext:function(x){ 
           if (x==undefined){
                x=0;
              } 
                return this.index<this.length+x;  
            },  
            next:function(){  
                var data=this.arr[this.index];  
                this.index=this.index+1;  
               // return data;  
            },  
            reset:function(){  
                this.index=0;  
            },
            set:function(x){

            this.arr[this.index]=x;
            },
            getall:function(){
               return  this.arr;
         },
         get:function(index){
            var v= this.arr;
            return v[index]
         }
     };
  return constructor;
})(); 
    /****************************************** */
  //***神经元对象   * */  
 /****************************************** */
var SNeuron = (function sneuron() {           
  function constructor(m_NumInputs) {
    this.m_NumInputs=m_NumInputs;
    this.m_dActivation=0;//该神经细胞的激励值
    this.m_dError=0;//误差值
    this.m_vecWeight=new Array();
    this.init();
  }
  constructor.prototype ={
       constructor :constructor,
       init :function(){
          for (var i=0;i<this.m_NumInputs+1;i++) this.m_vecWeight.push(new RandomClamped().get());   
       }
     };
  return constructor;
})();

  /****************************************** */
  //***神经层对象   * */  
 /****************************************** */

var SNeuronLayer = (function sneuronLayer() {           
  function constructor(m_NumNeurons,m_NumInputs) {
    this.m_NumNeurons=m_NumNeurons;// 本层使用的神经细胞数目
   this.m_vecNeurons=new Array(); // 神经细胞的层
    this.init(m_NumInputs);
  }
  constructor.prototype ={
       constructor :constructor,
       init:function(m_NumInputs){
          for (var i=0;i<this.m_NumNeurons;i++) this.m_vecNeurons.push(new SNeuron(m_NumInputs));          
      }
     };
  return constructor;
})();

/****************************************** */
  //***神经网络   * */  
 /****************************************** */
var CNeuralNet = (function cneuralnet() {           
  function constructor(NumInputs,NumOutputs,m_NumHiddenLayers,m_NeuronsPerHiddenLyr,LearningRate) {
    this.m_NumInputs=NumInputs;//输入数目 
    this.m_NumOutputs=NumOutputs;//输出数目
    this.m_NumHiddenLayers=m_NumHiddenLayers;//隐藏层的数目
    this.m_NeuronsPerHiddenLyr=m_NeuronsPerHiddenLyr;//每个隐藏层中神经细胞的个数
    this.m_vecLayers=new Array(); // 为每一层(包括输出层)存放所有神经细胞的存储器
    this.m_dLearningRate=LearningRate;//学习率
    this.m_dErrorSum;//所有误差总和(输出值和期望值)
    this.m_bTrained;//如果训练为真
    this.m_iNumEpochs;//迭代计数器
   this. CreateNet();
  }
  constructor.prototype ={
       constructor :constructor,
       InitializeNetwork:function(){
             //for each layer
	for (var i=0; i<this.m_iNumHiddenLayers+1; i++)
	{
		//for each neuron
		for (var n=0; n<m_vecLayers[i].m_NumNeurons; n++)
		{
			//for each weight
			for (var k=0; k<this.m_vecLayers[i].m_vecNeurons[n].m_NumInputs; k++)
			{  console.log('baomao')
				this.m_vecLayers[i].m_vecNeurons[n].m_vecWeight[k] = new RandomClamped().get();
			}
		}
	}
  this.m_dErrorSum  = 9999;
  this.m_iNumEpochs = 0;
	return;
       },
       NetworkTrainingEpoch:function(setIn,SetOut){//输入值,//二维数组,目标输出值
          this.m_dErrorSum=0;
          
                  //console.log(setIn.length);
          for (var vec=0;vec<setIn.length;vec++){//输入每次输入值
              ///=============//
             // console.log('训练模式次序'+vec);
           
               var outputs=this.Update(setIn[vec]);//一次输入所有训练值,通过UPdate方法计算出输出值(数组)
                
               if (outputs.length==0){
                 return false;
               }
               //遍历输出层每个细胞元
               
               // console.log(outputs)
               for(var op=0;op<this.m_NumOutputs; op++){
                //  console.log( '未调整权重值'+this.m_vecLayers[1].m_vecNeurons[0].m_vecWeight)
                   // console.log('处理第'+op+'个输出元');
                  ///--------------------------------------//

                      var err=(SetOut[vec][op]-outputs[op])*outputs[op]*(1-outputs[op]);//计算误差值
               // console.log(err);
                       this.m_vecLayers[1].m_vecNeurons[op].m_dError = err;//计算出输出层每个细胞的输出误差,值不一样
                  this.m_dErrorSum +=(SetOut[vec][op]-outputs[op])*(SetOut[vec][op]-outputs[op]);
                 

              var curWeight = new Iterator(this.m_vecLayers[1].m_vecNeurons[op].m_vecWeight);//创建输出层每个输入的权重,影藏层有多少个细胞就有多少个权重
              var curNrnHid = new Iterator(this.m_vecLayers[0].m_vecNeurons);//创建隐藏层的细胞数组的迭代
           var i=0;
              while(curWeight.hasNext(-1)){  //内部索引从0 到最后第二个  因为,最后一个创建细胞网的时候是【偏置值】
                var curNrnHidindex=curNrnHid.index;//隐藏层细胞索引
                var curWeightindex=curWeight.index;//输出层每个权重索引
                var value =curWeight.get(curWeightindex);
                
                
             //console.log('权重:'+value);
                       
               // console.log(curNrnHidindex);//显示隐藏层细胞索引
               // console.log(curWeightindex);//显示每个输入权重索引
               i++;
               // console.log('修改每个元的'+i+'次');
                value = value + err * this.m_dLearningRate * curNrnHid.get(curNrnHidindex).m_dActivation;
                //console.log('修改后的权重:'+value);
                curWeight.set(value);//重置当前索引的值 
                curWeight.next();//内部索引向后移动一位
               curNrnHid.next();//隐藏层细胞索引部索引向后移动一位  
              // console.log( this.m_vecLayers[1].m_vecNeurons[op].m_vecWeight)
                  } 

                  //console.log('影藏层权重索引'+curWeight.index);
                  // curWeight.next();//获取最后一个元素的值
               var bia= curWeight.get(curWeight.index);//获取当前权重
             // console.log('影藏层权重权重'+bia);
                 bia =bia+ err*this.m_dLearningRate*BIAS; 
                // console.log(err);
//console.log('学习率'+this.m_dLearningRate);
//console.log('偏移值'+BIAS);
                 // console.log('影藏层权重权重'+bia);
                curWeight.set(bia);//重置当前索引的值 

                // this.m_vecLayers[1].m_vecNeurons[op].m_vecWeight=curWeight.getall();//重置输出层细胞内的权重
                ///----------------------------//
            }

            curNrnHid = new Iterator(this.m_vecLayers[0].m_vecNeurons);//移到隐藏层
            //  console.log('处理隐藏层');
            var n=0;

  
            while(curNrnHid.hasNext(-1)){  //内部索引从0 到最后第二个  因为,最后一个创建细胞网的时候是【偏置值】
              var err=0; 
                 //  console.log('没有执行?');
              var curNrnHidindex=curNrnHid.index;//隐藏层细胞索引
             
              var curNrnOut = new Iterator(this.m_vecLayers[1].m_vecNeurons);//
                                
                    while(curNrnOut.hasNext(-1)){  //内部索引从0 到最后第二个  因为,最后一个创建细胞网的时候是【偏置值】
                                   //影藏层每个细胞元的输出,
                              var curNrnOutindex=curNrnOut.index; //输出层细胞每条输出当前索引
                             // console.log(curNrnOutindex);
                              var value=curNrnOut.get(curNrnOutindex);
                              //  console.log(value);

                              err +=value.m_dError * value.m_vecWeight[n];//算出输出值得误差,结果是X权重的的结果
                           //  console.log(err);
                              curNrnOut.next();//内部索引向后移动一位
                  } 
                    // console.log(curNrnHidindex);
                 // console.log(curNrnHid.get(curNrnHidindex).m_dActivation)
                              var dActivation=curNrnHid.get(curNrnHidindex).m_dActivation;
                err *= curNrnHid.get(curNrnHidindex).m_dActivation * (1 - dActivation);     
                   /下面继续20161020
               //   this.m_vecLayers[0].m_vecNeurons[op].m_dError = err   
                 // console.log('下面继续20161020?');
                 //for each weight in this neuron calculate the new weight based
      //on the error signal and the learning rate
      for (var w=0; w<this.m_NumInputs; w++)
      {
        //calculate the new weight based on the backprop rules
       curNrnHid.get(curNrnHidindex).m_vecWeight[w] += err * this.m_dLearningRate * setIn[vec][w];
      }

      //and the bias
      curNrnHid.get(curNrnHidindex).m_vecWeight[this.m_NumInputs] += err * this.m_dLearningRate * BIAS;
        curNrnHid.next();
     // ++curNrnHid;
     n++;
   
           } 
                
 
  //=============//
          }
 return true;

       },
       Train:function(data){  //输入训练用的参数
         
             var SetIn=data.GetInputSet();
             var SetOut=data.GetOutputSet();
             
            //first make sure the training set is valid
   if ((SetIn.length     != SetOut.length)  || 
       (SetIn[0].length  != this.m_NumInputs)   ||
       (SetOut[0].length != this.m_NumOutputs))
   {
     alert("Inputs != Outputs ,Error");
    
     return false;
   }
  
   //initialize all the weights to small random values
   this.InitializeNetwork();
  
  // console.log('阀值为:'+ERROR_THRESHOLD)
   //train using backprop until the SSE is below the user defined
   //threshold
   while( this.m_dErrorSum > ERROR_THRESHOLD )
   {
     //return false if there are any problems
     if (!this.NetworkTrainingEpoch(SetIn, SetOut))
     {
       return false;
     }
    console.log('当前误差:'+this.m_dErrorSum+';训练中,次数为'+this.m_iNumEpochs)
     this.m_iNumEpochs++;
   event.emit('getAlldata',this.m_vecLayers);
      
     //console.log(this.getAlldata())
      

     //call the render routine to display the error sum
    //InvalidateRect(hwnd, NULL, TRUE);
if (this.m_iNumEpochs>2000){

    return
  }
		// UpdateWindow(hwnd);
   }

   m_bTrained = true;
   
   return true;
       },

       getAlldata:function(){
  this.m_dActivation=0;//该神经细胞的激励值
    this.m_dError=0;//误差值
    this.m_vecWeight=new Array();
    var data=new Array()
    
         for (var i=0; i<this.m_vecLayers.length; i++)
	{
   
  var vecLayers=new  Array();
   
		//for each neuron
		for (var n=0; n<this.m_vecLayers[i].m_NumNeurons; n++)
		{
    var vecNeurons={}
      var vecWeight=new Array();
			//for each weight
     
			for (var k=0; k<this.m_vecLayers[i].m_vecNeurons[n].m_NumInputs; k++)
			{
        
				vecWeight.push(this.m_vecLayers[i].m_vecNeurons[n].m_vecWeight[k]);
			}
        
        vecNeurons.Weight=vecWeight;
        vecLayers.push(vecNeurons);
		}
data.push(vecLayers)


	}

  return data;
       },
       CreateNet:function(){//创建神经网络
         console.log('创建神经元');
          if (this.m_NumHiddenLayers > 0)  // 创建网络的各个层
           {
                //创建第一个隐藏层
              this.m_vecLayers.push(new SNeuronLayer(this.m_NeuronsPerHiddenLyr,this.m_NumInputs));
                for(var i=0; i<this.m_NumHiddenLayers-1; i++)
                 {
                     this.m_vecLayers.push(new SNeuronLayer(this.m_NeuronsPerHiddenLyr,this.m_NeuronsPerHiddenLyr));
                 }
               //如果允许有多个隐藏层,则由接着for循环即能创建其余的隐藏层  
                 this.m_vecLayers.push(new SNeuronLayer(this.m_NumOutputs,this.m_NeuronsPerHiddenLyr));// 创建输出层
                  console.log(this.m_vecLayers);
           }else //无隐藏层时,只需创建输出层
           {
              // 创建输出层
              console.log('只创建输出层');
                 this.m_vecLayers.push(new SNeuronLayer(this.m_NumOutputs, this.m_NumInputs));
           }
           
       },        
       GetWeights:function(){
	              var weights=new Array();//this will hold the weights
	             //遍历每个层
	           for (var i=0; i<this.m_NumHiddenLayers+1; i++)
	           {
		               for (var j=0; j<this.m_vecLayers[i].m_NumNeurons; j++)//遍历每个神经元
		              {
			                    for (var k=0; k<this.m_vecLayers[i].m_vecNeurons[j].m_NumInputs; k++)
			                     {
				                      weights.push(this.m_vecLayers[i].m_vecNeurons[j].m_vecWeight[k]);//遍历每个权重
			                     }
		              }
	            }
	            return weights;// 从神经网络得到(读出)权重
       }, 
      GetNumberOfInput:function(){
          return  this.m_NumInputs;//输入数目
      },
       GetNumberOfOutput:function(){
          return this.m_NumOutputs;//输出数目
       },
       GetNumberOfWeights:function(){
         var weights = 0;
	               //for each layer
	              for (var i=0; i<this.m_NumHiddenLayers+1; i++)
	                 {
		                    //for each neuron
		                    for (var j=0; j<this.m_vecLayers[i].m_NumNeurons; j++)
		                        {
			                            //for each weight
			                          for (var k=0; k<this.m_vecLayers[i].m_vecNeurons[j].m_NumInputs; k++) weights++;                 				
		                        }
	                 }
	              return weights; // 返回网络的权重的总数
       },
       // 用新的权重代替原有的权重, 这一函数所做的工作与函数GetWeights所做的正好相反。当遗传算法执行完一代时,新一代的权重必须重新插入神经网络。为我们完成这一任务的是PutWeight方法。
      PutWeights:function(weights){
             var cWeight = 0;
	//for each layer
	            for (var i=0; i<this.m_NumHiddenLayers+1;i++)
	            {
		//for each neuron
	               	for (var j=0; j<this.m_vecLayers[i].m_NumNeurons; j++)
		              {
			//for each weight
		                 	for (var k=0; k<this.m_vecLayers[i].m_vecNeurons[j].m_NumInputs; k++)
			                {
				                  this.m_vecLayers[i].m_vecNeurons[j].m_vecWeight[k] = weights[cWeight++];
			                }
		              }
	            }
               	return;
      },
     // S形响应曲线
     Sigmoid:function(activation,response){
        return ( 1 / ( 1 + Math.exp(-activation / response)));  
     },
     //当已知一个神经细胞的所有输入*重量的乘积之和时,这一方法将它送入到S形的激励函数。
     // 根据一组输入,来计算输出
      Update:function(inputs){
           // 保存从每一层产生的输出
               var outputs=new Array();
               var cWeight = 0;  
     // 首先检查输入的个数是否正确 inputs为数组
     if (inputs.length != this.m_NumInputs)
      {
          // 如果不正确,就返回一个空向量
          console.log(inputs.length);
          return outputs;
      }
     // 对每一层,...
     for (var i=0; i<this.m_NumHiddenLayers+1; i++)
     {
       if (i>0)
         {
            inputs = outputs;
         }//第一次循环计算隐藏层的输出值

    outputs=[];
    cWeight = 0;
    // 对每个神经细胞,求输入*对应权重乘积之总和。并将总和抛给S形函数,以计算输出
   for (var j=0; j<this.m_vecLayers[i].m_NumNeurons;j++)
        {
          var netinput = 0;
          this.NumInputs = this.m_vecLayers[i].m_vecNeurons[j].m_NumInputs;
         // 对每一个权重
         for (var k=0; k<this.NumInputs-1; k++)
         { 
            // 计算权重*输入的乘积的总和。
            netinput += this.m_vecLayers[i].m_vecNeurons[j].m_vecWeight[k] * inputs[cWeight++];  //权重*输入值然后累加          
         }
        // 加入偏移值
        netinput += this.m_vecLayers[i].m_vecNeurons[j].m_vecWeight[this.NumInputs-1] *BIAS;
   //别忘记每个神经细胞的权重向量的最后一个权重实际是偏移值,这我们已经说明过了,我们总是将它设置成为 –1的。我已经在ini文件中包含了偏移值,你可以围绕它来做文章,考察它对你创建的网络的功能有什么影响。不过,这个值通常是不应该改变的。
     // 每一层的输出,当我们产生了它们后,我们就要将它们保存起来。但用Σ累加在一起的

     this.m_vecLayers[i].m_vecNeurons[j].m_dActivation = this.Sigmoid(netinput, ACTIVATION_RESPONSE);
     // 激励总值首先要通过S形函数的过滤,才能得到输出
           outputs.push(this.m_vecLayers[i].m_vecNeurons[j].m_dActivation);
            cWeight = 0;
    }
  }
        return outputs;
       //对此Update函数函数我马上就会来进行注释的。  
      },
     CalculateSplitPoints: function()
    {
	       var SplitPoints=new Array();
         var WeightCounter = 0;
	//for each layer
	for (var i=0; i<this.m_NumHiddenLayers+1; i++)
	{
		//for each neuron
		for (var j=0; j<this.m_vecLayers[i].m_NumNeurons; j++)
		{
			//for each weight
			for (var k=0; k<this.m_vecLayers[i].m_vecNeurons[j].m_NumInputs; k++)
      {
				WeightCounter++;			
      }
      SplitPoints.push(WeightCounter - 1);
		}
	}
	return SplitPoints;
}
     };
  return constructor;
})();

 

 

 

 


 

 

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值