更改

添加6,031字节 、 2018年12月4日 (二) 00:35
第189行: 第189行:  
==== 递推收敛学习算法(Convergent recursive learning algorithm) ====
 
==== 递推收敛学习算法(Convergent recursive learning algorithm) ====
 
这是一种为[https://en.wikipedia.org/wiki/Cerebellar_model_articulation_controller 小脑模型关节控制器](CMAC)神经网络特别设计的学习方法。2004,递推最小二乘法被引入在线训练CMAC神经网络。<ref name="Qin1">Ting Qin, et al. "A learning algorithm of CMAC based on RLS." Neural Processing Letters 19.1 (2004): 49–61.</ref>这种算法可以使用任何新的输入数据,一步收敛并一步内更新所有权重。最开始,这种算法有[https://en.wikipedia.org/wiki/Computational_complexity_theory 计算复杂度]''O''(''N''<sup>3</sup>). 基于[https://en.wikipedia.org/wiki/QR_decomposition QR分解],这种算法简化到''O''(''N'').<ref name="Qin2">Ting Qin, et al. "Continuous CMAC-QRLS and its systolic array." Neural Processing Letters 22.1 (2005): 1–16.</ref>
 
这是一种为[https://en.wikipedia.org/wiki/Cerebellar_model_articulation_controller 小脑模型关节控制器](CMAC)神经网络特别设计的学习方法。2004,递推最小二乘法被引入在线训练CMAC神经网络。<ref name="Qin1">Ting Qin, et al. "A learning algorithm of CMAC based on RLS." Neural Processing Letters 19.1 (2004): 49–61.</ref>这种算法可以使用任何新的输入数据,一步收敛并一步内更新所有权重。最开始,这种算法有[https://en.wikipedia.org/wiki/Computational_complexity_theory 计算复杂度]''O''(''N''<sup>3</sup>). 基于[https://en.wikipedia.org/wiki/QR_decomposition QR分解],这种算法简化到''O''(''N'').<ref name="Qin2">Ting Qin, et al. "Continuous CMAC-QRLS and its systolic array." Neural Processing Letters 22.1 (2005): 1–16.</ref>
 +
 +
=== 简单实现 ===
 +
 +
<syntaxhighlight lang="python">
 +
# From Programming Collective Intelligence https://resources.oreilly.com/examples/9780596529321/blob/master/PCI_Code%20Folder/chapter4/nn.py
 +
 +
from math import tanh
 +
from pysqlite2 import dbapi2 as sqlite
 +
 +
def dtanh(y):
 +
    return 1.0-y*y
 +
 +
class searchnet:
 +
    def __init__(self,dbname):
 +
      self.con=sqlite.connect(dbname)
 +
 
 +
    def __del__(self):
 +
      self.con.close()
 +
 +
    def maketables(self):
 +
      self.con.execute('create table hiddennode(create_key)')
 +
      self.con.execute('create table wordhidden(fromid,toid,strength)')
 +
      self.con.execute('create table hiddenurl(fromid,toid,strength)')
 +
      self.con.commit()
 +
 +
    def getstrength(self,fromid,toid,layer):
 +
      if layer==0: table='wordhidden'
 +
      else: table='hiddenurl'
 +
      res=self.con.execute('select strength from %s where fromid=%d and toid=%d' % (table,fromid,toid)).fetchone()
 +
      if res==None:
 +
          if layer==0: return -0.2
 +
          if layer==1: return 0
 +
      return res[0]
 +
 +
    def setstrength(self,fromid,toid,layer,strength):
 +
      if layer==0: table='wordhidden'
 +
      else: table='hiddenurl'
 +
      res=self.con.execute('select rowid from %s where fromid=%d and toid=%d' % (table,fromid,toid)).fetchone()
 +
      if res==None:
 +
        self.con.execute('insert into %s (fromid,toid,strength) values (%d,%d,%f)' % (table,fromid,toid,strength))
 +
      else:
 +
        rowid=res[0]
 +
        self.con.execute('update %s set strength=%f where rowid=%d' % (table,strength,rowid))
 +
 +
    def generatehiddennode(self,wordids,urls):
 +
      if len(wordids)>3: return None
 +
      # Check if we already created a node for this set of words
 +
      sorted_words=[str(id) for id in wordids]
 +
      sorted_words.sort()
 +
      createkey='_'.join(sorted_words)
 +
      res=self.con.execute(
 +
      "select rowid from hiddennode where create_key='%s'" % createkey).fetchone()
 +
 +
      # If not, create it
 +
      if res==None:
 +
        cur=self.con.execute(
 +
        "insert into hiddennode (create_key) values ('%s')" % createkey)
 +
        hiddenid=cur.lastrowid
 +
        # Put in some default weights
 +
        for wordid in wordids:
 +
          self.setstrength(wordid,hiddenid,0,1.0/len(wordids))
 +
        for urlid in urls:
 +
          self.setstrength(hiddenid,urlid,1,0.1)
 +
        self.con.commit()
 +
 +
    def getallhiddenids(self,wordids,urlids):
 +
      l1={}
 +
      for wordid in wordids:
 +
        cur=self.con.execute(
 +
        'select toid from wordhidden where fromid=%d' % wordid)
 +
        for row in cur: l1[row[0]]=1
 +
      for urlid in urlids:
 +
        cur=self.con.execute(
 +
        'select fromid from hiddenurl where toid=%d' % urlid)
 +
        for row in cur: l1[row[0]]=1
 +
      return l1.keys()
 +
 +
    def setupnetwork(self,wordids,urlids):
 +
        # value lists
 +
        self.wordids=wordids
 +
        self.hiddenids=self.getallhiddenids(wordids,urlids)
 +
        self.urlids=urlids
 +
 +
        # node outputs
 +
        self.ai = [1.0]*len(self.wordids)
 +
        self.ah = [1.0]*len(self.hiddenids)
 +
        self.ao = [1.0]*len(self.urlids)
 +
       
 +
        # create weights matrix
 +
        self.wi = [[self.getstrength(wordid,hiddenid,0)
 +
                    for hiddenid in self.hiddenids]
 +
                  for wordid in self.wordids]
 +
        self.wo = [[self.getstrength(hiddenid,urlid,1)
 +
                    for urlid in self.urlids]
 +
                  for hiddenid in self.hiddenids]
 +
 +
    def feedforward(self):
 +
        # the only inputs are the query words
 +
        for i in range(len(self.wordids)):
 +
            self.ai[i] = 1.0
 +
 +
        # hidden activations
 +
        for j in range(len(self.hiddenids)):
 +
            sum = 0.0
 +
            for i in range(len(self.wordids)):
 +
                sum = sum + self.ai[i] * self.wi[i][j]
 +
            self.ah[j] = tanh(sum)
 +
 +
        # output activations
 +
        for k in range(len(self.urlids)):
 +
            sum = 0.0
 +
            for j in range(len(self.hiddenids)):
 +
                sum = sum + self.ah[j] * self.wo[j][k]
 +
            self.ao[k] = tanh(sum)
 +
 +
        return self.ao[:]
 +
 +
    def getresult(self,wordids,urlids):
 +
      self.setupnetwork(wordids,urlids)
 +
      return self.feedforward()
 +
 +
    def backPropagate(self, targets, N=0.5):
 +
        # calculate errors for output
 +
        output_deltas = [0.0] * len(self.urlids)
 +
        for k in range(len(self.urlids)):
 +
            error = targets[k]-self.ao[k]
 +
            output_deltas[k] = dtanh(self.ao[k]) * error
 +
 +
        # calculate errors for hidden layer
 +
        hidden_deltas = [0.0] * len(self.hiddenids)
 +
        for j in range(len(self.hiddenids)):
 +
            error = 0.0
 +
            for k in range(len(self.urlids)):
 +
                error = error + output_deltas[k]*self.wo[j][k]
 +
            hidden_deltas[j] = dtanh(self.ah[j]) * error
 +
 +
        # update output weights
 +
        for j in range(len(self.hiddenids)):
 +
            for k in range(len(self.urlids)):
 +
                change = output_deltas[k]*self.ah[j]
 +
                self.wo[j][k] = self.wo[j][k] + N*change
 +
 +
        # update input weights
 +
        for i in range(len(self.wordids)):
 +
            for j in range(len(self.hiddenids)):
 +
                change = hidden_deltas[j]*self.ai[i]
 +
                self.wi[i][j] = self.wi[i][j] + N*change
 +
 +
    def trainquery(self,wordids,urlids,selectedurl):
 +
      # generate a hidden node if necessary
 +
      self.generatehiddennode(wordids,urlids)
 +
 +
      self.setupnetwork(wordids,urlids)     
 +
      self.feedforward()
 +
      targets=[0.0]*len(urlids)
 +
      targets[urlids.index(selectedurl)]=1.0
 +
      error = self.backPropagate(targets)
 +
      self.updatedatabase()
 +
 +
    def updatedatabase(self):
 +
      # set them to database values
 +
      for i in range(len(self.wordids)):
 +
          for j in range(len(self.hiddenids)):
 +
              self.setstrength(self.wordids[i],self. hiddenids[j],0,self.wi[i][j])
 +
      for j in range(len(self.hiddenids)):
 +
          for k in range(len(self.urlids)):
 +
              self.setstrength(self.hiddenids[j],self.urlids[k],1,self.wo[j][k])
 +
      self.con.commit()
 +
</syntaxhighlight>
    
== 变体 ==
 
== 变体 ==