zoukankan      html  css  js  c++  java
  • [机器学习]第四、五周记录

    这篇记录的内容来自于Andrew Ng教授在coursera网站上的授课。 


    1.为什么使用神经网络:样本的特征数太多了,使用前面的算法都几乎不可能达到一个理想的结果。

    2.神经网络(neural networks):

     受到脑神经的启发,我们有以下结构:

    术语:

    输入层(input layer):输入样本的特征。

    输出层(output layer):输出预测。

    隐藏层(hidden layer):因为“看不到”,所以叫隐藏层。(除非debug)

    激活单元(activation units):即图中的$a_1^{(2)},a_2^{(2)}$,通过前面一层的输出作为输入,经过激活函数来计算输出值。表示方法为$a_i^{j}$,含义为第j层(输入层是第一层)的第i个激活单元。

    激活函数:这里用sigmoid函数。所以每一个输出的值都在(0,1)中。

    z代表这层的输入,a代表这层的输出。

    权重(weights):层与层之间的映射。记为$Theta^{(j)}$,含义为第j层到第j+1层的权重。$Theta^{(j)}_{x,y}$表示第j层的第y个(不要搞反了)激活单元与第j+1层的第x个激活单元的权重。权重矩阵的大小是$s_{j+1}*(s_j+1)$的。+1是因为多了一个偏置(bias)项,老传统了。

    前向传播(forward propagation):根据输入,计算输出的方法。对于第j层的输出,有:$$a^{j}=g(Theta^{j-1}*a^{j-1})$$,其中g是sigmoid函数。

    我们的假设h函数就等于它,它也是个向量而不止是一个数字了。


    1.记号:
    L:总层数。

    $s_i$:第i层的节点数(不包括偏置项)。

    K:分类数。

    那么,整个网络的代价即为:

    $$J(Theta)=-frac{1}{m}sum_{i=1}^{m}sum_{k=1}^{K}(y_k^{(i)}log((h_{ heta}(x^{(i)}))_k)+(1-y_k^{i})log(1-(h_{ heta}(x^{(i)}))_k))+frac{lambda}{2m}sum_{l=1}^{L-1}sum_{i=1}^{s_l}sum_{j=1}^{s_{l+1}}(Theta_{j,i})^2$$

     2.反向传播(backforward propagation):神经网络的梯度下降。

    $delta_{j}^{(l)}$:第l层第j个激活单元的误差(bias从0开始)。对于输出层我们有:

    $$delta^{(l)}=frac{1}{m}sum_{i=1}^{m}(h_{ heta}{(x^{(i)})}-y^{(i)})=frac{1}{m}sum_{i=1}^{m}(g(x^{(i)})-y^{(i)})$$

    接着,

    $$delta^{(l-1)}=(Theta^{(l-1)})^Tdelta^{(l)}.*g'(z^{(l-1)})$$其中$z^{(l)}$指的是第l层在前向传播时获得的输入,.*是点乘。

    注意到,

    $$g'(z^{(l)})=a^{(l)}.*(1-a^{(l)})$$

    并且,

    $$frac{partial}{partialTheta^{(l)}_{i,j}}J(Theta)=a^{(l)}_jdelta_i^{(l+1)}$$

    具体推导此处省略。你可以观看3B1B的相关视频,来进行感性的理解。 


    神经网络的实现还是有点麻烦的。

    我们先实现只有一层hidden layer的神经网络。

    例子

    对某一个人的手写数字进行识别。

    样本:200张20*20的灰度图片。方便起见,我们事先将它们变成了用逗号隔开的长度为401的txt文件,对于前400个数字,由0/1代表对应位置是黑色还是白色,最后一位是它对应的数字。

    样本下载:https://pan.baidu.com/s/1dEL27nMZzMbT3iAPTiJKqA
    提取码:nq18

    最后实现代码:

      1 import numpy as np
      2 import pandas as pd
      3 import matplotlib.pyplot as plt
      4 import matplotlib
      5 from scipy.io import loadmat
      6 from sklearn.preprocessing import OneHotEncoder
      7 from scipy.optimize import minimize
      8 from sklearn.metrics import classification_report###评价报告
      9 """
     10 输入数据为20*20的灰度图像,标签为1~10
     11 只有一层hidden layer
     12 x:样本
     13 y:标签
     14 m:样本数
     15 th:参数
     16 """
     17 size_input=20*20
     18 size_hidden=30
     19 size_labels=10
     20 alpha=3###就是lambda
     21 
     22 #######################################sigmoid函数
     23 def sigmoid(x):
     24     return 1/(1+np.exp(-x))
     25 #######################################fp
     26 def forprop(x,th1,th2):
     27     m=x.shape[0]
     28     a1=np.insert(x,0,values=np.ones(m),axis=1)###添加偏置项
     29     z2=a1*th1.T
     30     a2=np.insert(sigmoid(z2),0,values=np.ones(m),axis=1)###添加偏置项
     31     z3=a2*th2.T
     32     h=sigmoid(z3)
     33     return a1,z2,a2,z3,h###现在的h的列数等于size_labels
     34 #######################################cost函数
     35 def cost(th1,th2,size_input,size_hidden,size_labels,x,y,alpha):
     36     m=x.shape[0]
     37     x=np.matrix(x)
     38     y=np.matrix(y)
     39     a1,z2,a2,z3,h=forprop(x,th1,th2)
     40     A=np.multiply((-y),np.log(h))###数乘
     41     B=np.multiply((1-y),np.log(1-h))
     42     reg=(np.sum(np.power(th1[:,1:],2))+np.sum(np.power(th2[:,1:],2)))*alpha/(2*m)
     43     return np.sum(A-B)/m+reg
     44 #######################################sigmoid导数
     45 def sigmoidGradient(x):
     46     return np.multiply(sigmoid(x),1-sigmoid(x))
     47 #######################################随机初始化
     48 def random():
     49     return (np.random.random(size=size_hidden*(size_input+1)+size_labels*(size_hidden+1))-0.5)*0.24
     50 #######################################bp
     51 
     52 TOT=0
     53 def backprop(th,size_input,size_hidden,size_labels,x,y,alpha):
     54     global TOT
     55     m=x.shape[0]
     56     print(TOT)
     57     TOT=TOT+1
     58     x=np.matrix(x)
     59     y=np.matrix(y)
     60     th1=np.matrix(np.reshape(th[:size_hidden*(size_input+1)],(size_hidden,(size_input+1))))###请注意
     61     th2=np.matrix(np.reshape(th[size_hidden*(size_input+1):],(size_labels,(size_hidden+1))))
     62     a1,z2,a2,z3,h=forprop(x,th1,th2)
     63     A=np.multiply((-y),np.log(h))
     64     B=np.multiply((1-y),np.log(1-h))
     65     reg=(np.sum(np.power(th1[:,1:],2))+np.sum(np.power(th2[:,1:],2)))*alpha/(2*m)
     66     J=np.sum(A-B)/m+reg
     67     
     68     del1=np.zeros(th1.shape)
     69     del2=np.zeros(th2.shape)
     70     
     71     for t in range(m):
     72         a1t=a1[t,:]###(1,401)
     73         z2t=z2[t,:]###(1,25)
     74         a2t=a2[t,:]###(1,26)
     75         ht=h[t,:]  ###(1,10)
     76         yt=y[t,:]  ###(1,10)
     77         
     78         d3t=ht-yt
     79         z2t=np.insert(z2t,0,values=np.ones(1))###(1,26),老传统
     80         d2t=np.multiply((th2.T*d3t.T).T,sigmoidGradient(z2t))
     81         
     82         del1=del1+(d2t[:,1:]).T*a1t
     83         del2=del2+d3t.T*a2t
     84     del1=del1/m
     85     del2=del2/m
     86     
     87     del1[:,1:]=del1[:,1:]+(th1[:,1:]*alpha)/m
     88     del2[:,1:]=del2[:,1:]+(th2[:,1:]*alpha)/m
     89     
     90     tmp=np.concatenate((np.ravel(del1),np.ravel(del2)))
     91     
     92     return J,tmp
     93 #######################################获得数据
     94 maxlen=6
     95 def getStr(x):
     96     y=maxlen-len(str(x))
     97     return "0"*y+str(x)
     98     
     99 def getdata():
    100     file=open("dig/NUM.txt")
    101     m=int(file.read())
    102     x=np.zeros((m,size_input))
    103     y=np.zeros((m,size_labels))
    104     for i in range(m):
    105         path="dig/"+getStr(i)+".txt"
    106         file=open(path)
    107         Q=file.read()
    108         A=Q.split(",")
    109         for j in range(size_input):
    110             x[i,j]=int(A[j])
    111         y[i,int(A[size_input])]=1
    112     print(y)
    113     return x,y
    114 #######################################预测
    115 def predict(x,th1,th2):
    116     a1,z2,a2,z3,h=forprop(x,th1,th2)
    117     print(np.matrix(np.argmax(h,axis=1)))
    118 #######################################主函数
    119 def main():
    120     x,y=getdata()
    121     th=random()
    122     fmin=minimize(fun=backprop,x0=th,args=(size_input,size_hidden,size_labels,x,y,alpha),method='TNC',jac=True,options={'maxiter':1000})
    123     G=fmin.x
    124     file=open("save++.txt","w")
    125     for i in range(G.shape[0]):
    126         file.write(str(G[i])+"
    ")
    127     file.close()
    128     x = np.matrix(x)
    129     th1 = np.matrix(np.reshape(fmin.x[:size_hidden* (size_input + 1)], (size_hidden, (size_input + 1))))
    130     th2 = np.matrix(np.reshape(fmin.x[size_hidden * (size_input + 1):], (size_labels, (size_hidden + 1))))
    131     a1, z2, a2, z3, h = forprop(x, th1, th2 )
    132     y_pred = np.matrix(np.argmax(h, axis=1))
    133     m=x.shape[0]
    134     Y=np.zeros(m)
    135     for i in range(m):
    136         for j in range(size_labels):
    137             if(y[i,j]):
    138                 Y[i]=j
    139     print(classification_report(Y,y_pred))
    140 
    141 if(__name__=="__main__"):
    142     main()
    View Code

     但很显然,没有向量化运行速度太慢,没有结构化修改太复杂!因此博主重构了代码。

    接下来的代码中,一个样本是按列排序,而不是上面按行排序(因为博主从头到尾推了一遍)。

    这份代码是向量化之后的神经网络,只有一层hidden layer,没有正则项:

      1 import numpy as np
      2 #import pandas as pd
      3 #import matplotlib.pyplot as plt
      4 #import matplotlib
      5 #from scipy.io import loadmat
      6 #from sklearn.preprocessing import OneHotEncoder
      7 from scipy.optimize import minimize
      8 #from sklearn.metrics import classification_report
      9 
     10 size_input=20*20
     11 size_output=10
     12 size=[size_input,30,size_output]
     13 theta=[]
     14 maxlen=6
     15 
     16 def init():###随机初始化
     17     global theta
     18     tot=0
     19     for i in range(len(size)-1):
     20         tot+=size[i+1]*(size[i]+1)
     21     theta=(np.array(np.random.random(size=tot))-0.5)*0.24
     22 
     23 def sigmoid(x):
     24     return 1/(1+np.exp(-x))
     25 
     26 def getWeight(theta,size):###获得矩阵
     27     weight=[]
     28     tot=0
     29     for i in range(len(size)-1):
     30         weight.append(np.matrix(np.array(theta[tot:tot+size[i+1]*(size[i]+1)])).reshape((size[i+1],size[i]+1)))
     31         tot+=size[i+1]*(size[i]+1)
     32     return weight
     33 
     34 def forwardProp(theta,size,x):###前向传播
     35     weight=getWeight(theta,size)
     36     m=x.shape[1]
     37     layer=len(size)
     38     for i in range(layer-1):
     39         x=np.insert(x,0,values=np.ones(m),axis=0)###0表示行
     40         x=sigmoid(weight[i]*x)
     41     return x
     42 
     43 def sigmoidGradient(x):
     44     return np.multiply(sigmoid(x),1-sigmoid(x))
     45 
     46 def BP(theta,size,x,y,alpha):
     47     weight=getWeight(theta,size)
     48     m=x.shape[1]
     49     
     50     th1=weight[0]
     51     th2=weight[1]
     52     a1=np.insert(x,0,values=np.ones(m),axis=0)###添加偏置项
     53     z2=th1*a1
     54     a2=np.insert(sigmoid(z2),0,values=np.ones(m),axis=0)###添加偏置项
     55     z3=th2*a2
     56     h=sigmoid(z3)
     57     
     58     A=np.multiply((-y),np.log(h))
     59     B=np.multiply((1-y),np.log(1-h))
     60     J=np.sum(A-B)/m
     61     
     62     del1=np.zeros(th1.shape)
     63     del2=np.zeros(th2.shape)
     64     print(J)
     65     a1t=a1###(401,t)
     66     z2t=z2###(30,t)
     67     a2t=a2###(31,t)
     68     ht=h  ###(10,t)
     69     yt=y  ###(10,t)
     70     
     71     d3t=ht-yt
     72     z2t=np.insert(z2t,0,values=np.ones(m),axis=0)###(31,t)
     73     d2t=np.multiply(th2.T*d3t,sigmoidGradient(z2t))
     74     
     75     th1=(d2t[1:,:])*a1t.T
     76     th2=d3t*a2t.T
     77     print(th2.shape,d3t.shape,z2t.shape)
     78     """
     79     del1=del1+(d2t[1:,:])*a1t.T
     80     del2=del2+d3t*a2t.T
     81 
     82     del1=del1/m
     83     del2=del2/m
     84     
     85     del1[1:,:]=del1[1:,:]#+(th1[1:,:]*alpha)/m
     86     del2[1:,:]=del2[1:,:]#+(th2[1:,:]*alpha)/m
     87     """
     88     tmp=np.concatenate((np.ravel(th1),np.ravel(th2)))
     89     
     90     return J,tmp
     91 
     92 def getStr(x):
     93     y=maxlen-len(str(x))
     94     return "0"*y+str(x)
     95 
     96 def getdata():
     97     file=open("dig/NUM.txt")
     98     m=int(file.read())
     99     print(m)
    100     x=np.zeros((size_input,m))
    101     y=np.zeros((size_output,m))
    102     tot=0
    103     for i in range(m):
    104         path="dig/"+getStr(i)+".txt"
    105         file=open(path)
    106         Q=file.read()
    107         A=Q.split(",")
    108         for j in range(size_input):
    109             x[j,tot]=int(A[j])
    110         y[int(A[size_input]),tot]=1
    111         tot+=1
    112     return np.matrix(x),np.matrix(y)
    113 
    114 def main():
    115     global theta
    116     init()
    117     X,Y=getdata()
    118     
    119     fmin=minimize(fun=BP,x0=theta,args=(size,X,Y,1),method='TNC',jac=True,options={'maxiter':300})
    120     theta=fmin.x
    121     prediction=forwardProp(theta,size,X)
    122     prediction=np.matrix(np.argmax(prediction,axis=0))
    123     print(prediction)
    124     true=np.matrix(np.argmax(Y,axis=0))
    125     print(true)
    126 
    127 if(__name__=="__main__"):
    128     main()
    View Code

    运行速度起码快了十倍。

    需要特别注意的是,代码中a2t与z2t的效果是不一样的!a2t是第二层进行sigmoid后的结果,而z2t是没有sigmoid的输入值。如果混为一谈,那么你就会得到一个虚假的神经网络。

    结构化的神经网络,向量化,能自定义层数、节点数,有正则化:

      1 import numpy as np
      2 #import pandas as pd
      3 #import matplotlib.pyplot as plt
      4 #import matplotlib
      5 #from scipy.io import loadmat
      6 #from sklearn.preprocessing import OneHotEncoder
      7 from scipy.optimize import minimize
      8 #from sklearn.metrics import classification_report
      9 
     10 size_input=20*20
     11 size_output=10
     12 size=[size_input,30,15,size_output]
     13 theta=[]
     14 maxlen=6
     15 
     16 def init():###随机初始化
     17     global theta
     18     tot=0
     19     for i in range(len(size)-1):
     20         tot+=size[i+1]*(size[i]+1)
     21     theta=(np.array(np.random.random(size=tot))-0.5)*0.24
     22 
     23 def sigmoid(x):
     24     return 1/(1+np.exp(-x))
     25 
     26 def getWeight(theta,size):###获得矩阵
     27     weight=[]
     28     tot=0
     29     for i in range(len(size)-1):
     30         weight.append(np.matrix(np.array(theta[tot:tot+size[i+1]*(size[i]+1)])).reshape((size[i+1],size[i]+1)))
     31         tot+=size[i+1]*(size[i]+1)
     32     return weight
     33 
     34 def forwardProp(theta,size,x):###前向传播
     35     weight=getWeight(theta,size)
     36     m=x.shape[1]
     37     layer=len(size)
     38     for i in range(layer-1):
     39         x=np.insert(x,0,values=np.ones(m),axis=0)###0表示行
     40         x=sigmoid(weight[i]*x)
     41     return x
     42 
     43 def sigmoidGradient(x):
     44     return np.multiply(sigmoid(x),sigmoid(1-x))
     45 
     46 def BP(theta,size,x,y,alpha):
     47     weight=getWeight(theta,size)
     48     m=x.shape[1]
     49     layer=len(size)
     50     ###Z:到达这一层的输入,A:sigmoid后的输入
     51     tmpA=[]###注意,下标从0开始
     52     tmpZ=[]
     53     for i in range(layer-1):
     54         x=np.insert(x,0,values=np.ones(m),axis=0)
     55         ###0表示行,添加偏置项
     56         tmpA.append(x)
     57         x=weight[i]*x
     58         tmpZ.append(x)
     59         x=sigmoid(x)
     60     
     61     A=np.multiply((-y),np.log(x))
     62     B=np.multiply((1-y),np.log(1-x))
     63     reg=0###正则化项
     64     for i in range(layer-1):
     65         reg+=np.sum(np.power(weight[i][:,1:],2))*alpha/(2*m)
     66     J=np.sum(A-B)/m+reg###总代价
     67     print(J)
     68     
     69     delta=x-y
     70     for I in range(layer-1):
     71         i=layer-I-1
     72         if(i!=1):
     73             z=np.insert(tmpZ[i-2],0,values=np.ones(m),axis=0)
     74             ###获得第i-1层的没sigmoid的输入
     75             tmpW=delta*tmpA[i-1].T
     76             ###得到cost关于w的偏导
     77             delta=np.multiply(weight[i-1].T*delta,sigmoidGradient(z))
     78             ###得到新的delta
     79             delta=np.delete(delta,0,axis=0)
     80             ###删掉偏置项
     81             weight[i-1][:,0]=0
     82             weight[i-1]*=alpha/m
     83             weight[i-1]+=tmpW/m
     84         else:
     85             tmpW=delta*tmpA[i-1].T
     86             weight[i-1][:,0]=0
     87             weight[i-1]*=alpha/m
     88             weight[i-1]+=tmpW/m
     89     
     90     wait=[]
     91     for i in range(layer-1):
     92         wait=np.concatenate((wait,np.ravel(weight[i])))
     93     return J,wait
     94 
     95 def getStr(x):
     96     y=maxlen-len(str(x))
     97     return "0"*y+str(x)
     98 
     99 def getdata():
    100     file=open("dig/NUM.txt")
    101     m=int(file.read())
    102     x=np.zeros((size_input,m))
    103     y=np.zeros((size_output,m))
    104     tot=0
    105     for i in range(m):
    106         path="dig/"+getStr(i)+".txt"
    107         file=open(path)
    108         Q=file.read()
    109         A=Q.split(",")
    110         for j in range(size_input):
    111             x[j,tot]=int(A[j])
    112         y[int(A[size_input]),tot]=1
    113         tot+=1
    114     return np.matrix(x),np.matrix(y)
    115 
    116 def main():
    117     global theta
    118     init()
    119     X,Y=getdata()
    120     
    121     fmin=minimize(fun=BP,x0=theta,args=(size,X,Y,1),method='TNC',jac=True,options={'maxiter':1000})
    122     theta=fmin.x
    123     print(theta)
    124     
    125     prediction=forwardProp(theta,size,X)
    126     prediction=np.matrix(np.argmax(prediction,axis=0))
    127     print(prediction)
    128     true=np.matrix(np.argmax(Y,axis=0))
    129     print(true)
    130 
    131 if(__name__=="__main__"):
    132     main()
    View Code

    要注意的是,当BP算法到最后一层时,对tmpZ的操作是没有用的,因此要特判。

    但我发现一个奇怪的问题,当alpha=1时(正则化系数)就难以很快地梯度下降了,目前原因不明。

  • 相关阅读:
    分水岭分割算法(watershed segmentation)的C++实现(法2)
    ubuntu16.04下安装opencv3.3
    分水岭分割算法(watershed segmentation)的C++实现(法1)
    dpkg: 处理归档 /var/cache/apt/archives/swig2.0_2.0.12-1ubuntu4_amd64.deb (--unpack)时出错:
    ubuntu16.04安装pycharm
    ImportError: liblapack.so.3: cannot open shared object file问题
    Linux下使用Opencv打开笔记本摄像头
    目标跟踪算法meanshift优缺点
    Jacobian矩阵和Hessian矩阵
    机器视觉中的目标检测
  • 原文地址:https://www.cnblogs.com/GreenDuck/p/12330022.html
Copyright © 2011-2022 走看看