1 sigmoid方法

import numpy as np

def sigmoid(z):
    return 1/(1+np.exp(-z))

def sigmoidDerivative(a):
    """
    sigmoid 求导
    注意,这里传入的是a值,不是z值
    """
    return np.nultiply(a,(1-a))#a是计算结果

2 初始化权值矩阵

def initThetas(hiddenNum,unitNum,inputSize,classNum,epsilon):
    """初始化权值矩阵
    Args:
        hiddenNum 隐层数目
        unitNum每个隐层的神经元数目
        inputSize 输入层规模
        classNum 分类数目
        epsilon   误差
    return:
        Thetas 权值矩阵序列
    """
    hiddens=[unitNum for i in range(hiddenNum)]
    units=[inputSize]+hiddens+[classNum]
    Thetas=[]
    for idx,unit in enumerate(units):
        if idx==len(units)-1:
            break
        nextUnit=units[idx+1]
        
        Theta=np.random.rand(nextUnit,unit+1)*2*epsilon-epsilon
        Thetas.append(Theta)
    return Thetas

3 代价函数设置

def computeCost(Thetas,y,theLambda,X=None,a=None):
    """计算代价
    Args:
        Thetas:权值矩阵序列
        X 样本
        y 标签化
        a 各层激活值
    returns:
        J 预测代价
    """
    m=y.shape[0]
    if a is None:
        a=fp(Thetas,X)
        
    #注意,计算代价时,我们只需要关注整个网络的预测和标注之间的差异即可,因此只需要看a[-1]
    #另外一点注意是,标注y已经被向量化,有且仅有一位为1,其它是0
    error=-np.sum(np.multiply(y.T,np.log(a[-1]))+np.nultiply((1-y).T,np.log(1-a[-1])))
    #正则化,但不包括偏置项,theta的下标是下一层神经元编号,下标j是当前节点编号,所有偏置项在第二维的第0个位置
    reg=-np.sum([np.sum(Theta[:,1:])for Theta in Thetas])
    return (1.0/m)*error+(1.0/(2*m))*theLambda*reg

4 标签化

def adjustLabels(y):
    """标签化
    Args:
        y 标签集
    returns:
        yAdjusted 向量化后的标签
    """
    if y.shape[1]==1:
        classes=set(np.ravel(y))
        classNum=len(classes)
        minClass=min(classes)
        if classNum>2:
            yAdjusted=np.zeros((y.shape[0],classNum),np.float64)
            for row,label in enumerate(y):
                yAdjusted[row,label-minClass]=1
        else:
            yAdjusted=np.zeros((y.shape[0],1),np.float64)
            for row,label in enumerate(y):
                if label!=minClass:
                    yAdjusted[row,0]=1.0
        return yAdjusted
    return y

5 参数展开

def unroll(matrixes):
    """参数展开
    Args:
        matrixes 矩阵
    Return:
        vec向量
    """
    vec=[]
    for matrix in matrixes:
        vector=matrix.reshape(1,-1)[0]
        vec=np.concatenate((vec,vector))
    return vec

def roll(vector,shapes):
    """参数恢复
    Arags:
        vector 向量
        shape shape list
    Returns:
        matrixes 恢复的矩阵序列
    """
    matrixes=[]
    begin=0
    for shape in shapes:
        end=begin+shape[0]*shape[1]
        matrix=vector[begin:end].reshape(shape)
        begin=end
        matrixes.append(matrix)
    return matrixes

6 前向传递

def fp(Thetas,X):
    """前向反馈过程
    Args:
        Thetas 权值矩阵
        X 输入样本
    Returns:
        a 各层激活向量
    """
    layers=range(len(Thetas)+1)
    layerNum=len(layers)
    #激活向量序列
    a=range(layerNum)#要的仅仅是定长的list结构,内部元素在下面的for循环被重新赋值
    #前向传播计算各层输出
    for l in layers:
        if l ==0:
            a[l]=X.T
        else:
            z=Thetas[1-l]*a[l-1]
            a[l]=sigmoid(z)
            
        #各输出层外,需要添加偏置
        if l!=layerNum-1:
            a[l]=np.concatenate((np.ones((1,a[l].shape[1])),a[l]))
    return a

7 反向传递

def bp(Thetas,a,y,theLambel):
    """反向传播过程
    Args:
        a 激活值
        y 标签
    Returns:
        D 权值梯度
    """
    m=y.shape[0]
    layers=range(len(Thetas)+1)
    layerNum=len(layers)
    d=range(len(layers))
    delta=[np.zeros(Theta.shape)for Theta in Thetas]
    
    for l in layers[::-1]:#反向传播遍历层
        if l==0:
            #输入层不计算误差
            break
        if l==layerNum-1:
            #输出层误差
            d[l]=a[l]-y.T
        else:
            #忽略偏置
            d[l]=np.multiply((Thetas[l][:,1:].T*d[l+1]),sigmoidDerivative(a[l][1:,:]))
            
    for l in layer[0:layerNum-1]:
        delta[l]=d[l+1]*(a[l].T)
        
    D=[np.zeros(Theta.shape)for Theta in Thetas]
    for l in range(len(Thetas)):
        Theta=Thetas[l]
        #偏置更新增量
        D[l][:,0]=(1.0/m)*(delta[l][0:,0].reshape(1,-1))
        #权值更新增量
        D[l][:,1:]=(1.0/m)*(delta[l][0:,1].reshape(1,-1))
    return D  

8 更新权值

def updateThetas(m,Thetas,D,alpha,theLambda):
    """更新权值
        Args:
        m:样本量
        Thetas 各层权值矩阵
        D 梯度
        alpha 学习率
        thelambda 正则化参数
    Returns:
        Thetas 更新后的权值矩阵:
    """
    for l in range(len(Thetas)):
        Thetas[l]=Thetas[l]-alpha*D[l]
    return Thetas 

9 梯度下降

def gradientDescent(Thetas,X,y,alpha,theLambda):
    """梯度下降
    Args:
        X 样本
        y 标签
        alpha 学习率
        theLambda 正则化参数
    Returns:
        J 预测代价
        Thetas 更新后的各层权值矩阵        
    """
    # 样本数,特征数
    m,n=X.shape
    #向前传播各个神经元的激活值
    a=fp(Theta,X)
    #反向传播计算梯度增量
    D=bp(Thetas,a,y,theLambda)
    #计算预测代价
    J=computeCost(Thetas,y,theLambda,a=a)
    DVec=unroll(D)
    
    #数值化计算梯度
    epsilon=1e-4 #注意,这个epsilon的意义
    gradApprox=np.zeros(DVec.shape)
    ThetaVec=unroll(Thetas)
    shapes=[Theta.shape for Theta in Thetas]
    for i,item in enumerate(ThetaVec):
        Thetavec[i]=item-epsilon
        JMinus=computeCost(roll(ThetaVec,shapes),y,theLambda,X=X)
        ThetaVec[i]=item+epsilon
        JPlus=computeCost(roll(ThetaVec,shapes),y,theLambda,X=X)
        gradApprox[i]=(Jplus-JMinus)/(2*epsilon)
        
    #平均差距
    diff=np.average(gradApprox-DVec)
    print('gradient checking diff:',diff)
    
    if diff<1e-5:
        return True
    else:
        return False

10 训练网络

def train(X,y,checkFlag=False,Thetas=None,hiddenNum=0,unitNum=5,epsilon=1,alpha=1,theLambda=0,precision=0.0001,maxIters=50):
    """网络训练
    Args:
        X 训练样本
        y 标签集
        checkFlag 是否进行梯度校验,默认为False,即不进行校验。校验梯度费时
        Thetas 初始化的Thetas,如果为None,由系统随机初始化Thetas
        hiddenNum 隐藏层数目
        unitNum 隐藏层的单元数
        epsilon 初始化的权值范围[-epsilon,epsilon]
        alpha 学习率
        theLambda 正则化参数
        precision 误差精度
        maxIters 最大迭代次数
    """
    # 样本数,特征数
    m,n=X.shape
    # 标注标签向量化,比如多分类标签要转成向量
    y=adjustLabels(y)
    classNum=y.shape[1]
    #初始化Theta
    if Thetas is None:
        Thetas=initThetas(
            inputSize=n,
            hiddenNum=hiddenNum,
            unitNum=unitNum,
            classNum=classNum,
            epsilon=epsilon
        )
    #梯度校验
    print('Doing Gradient Checking')
    if checkFlag:
        checked=gradientCheck(Thetas,X,y,theLambda)
    else:
        checked=True
    print('Gradient Checked')
    
    if checked:
        last_error=np.inf
        for i in range(maxIters):
            error,Thetas=gradientDescent(
            Thetas,X,y,alpha=alpha,theLambda=theLambda
            )
            if abs(error-last_error)<precision:
                last_error=error
                break
            if error==inf:
                last_error=error
                break
            last_error=error
            
        return {
            'error':error,
            'Thetas':Thetas,
            'iters':i
        }
    else:
        print('Error:Gradient Checking Failed!!!')
        return {
            'error':None,
            'Thetas':None,
            'iters':0
        }

11 预测

def predict(X,Thetas):
    """预测函数
    Arags:
        X:样本
        Thetas:训练后得到的参数
    Return:
        a
    """
    a=fp(Thetas,X)
    return a[-1]

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐