神经网络设计

在神经网络的结构设计方面,往往遵循如下要点:

  1. 输入层的单元数等于样本特征数。
  2. 输出层的单元数等于分类的类型数。
  3. 每个隐层的单元数通常是越多分类精度越高,但是也会带来计算性能的下降,因此,要平衡质量和性能间的关系。
  4. 默认不含有隐藏层(感知器),如果含有多个隐层,则每个隐层上的单元数最好保持一致。

因此,对于神经网络模块,我们考虑如下设计:

  • 设计 sigmoid 函数作为激励函数:
    g(z)=11+e−zg(z)=\frac1{1+e^{−z}}g(z)=1+e−z1​g′(z)=g(z)(1−(g(z)))g′(z)=g(z)(1−(g(z)))g′(z)=g(z)(1−(g(z)))=a(1−a)=a(1−a)=a(1−a)a=g(z)a=g(z)a=g(z)
def sigmoid(z):"""sigmoid"""return 1 / (1 + np.exp(-z))def sigmoidDerivative(a):"""sigmoid求导"""return np.multiply(a, (1-a))
  • 设计初始化权值矩阵的函数:
def initThetas(hiddenNum, unitNum, inputSize, classNum, epsilon):"""初始化权值矩阵Args:hiddenNum 隐层数目unitNum 每个隐层的神经元数目inputSize 输入层规模classNum 分类数目epsilon epsilonReturns:Thetas 权值矩阵序列"""hiddens = [unitNum for i in range(hiddenNum)]units = [inputSize] + hiddens + [classNum]Thetas = []for idx, unit in enumerate(units):if idx == len(units) - 1:breaknextUnit = units[idx + 1]# 考虑偏置Theta = np.random.rand(nextUnit, unit + 1) * 2 * epsilon - epsilonThetas.append(Theta)return Thetas
  • 定义参数展开和参数还原函数:
def unroll(matrixes):"""参数展开Args:matrixes 矩阵Return:vec 向量"""vec = []for matrix in matrixes:vetor = matrix.reshape(1,-1)[0]vec = np.concatenate((vec,vector))return vecdef roll(vector, shapes):"""参数恢复Args:vector 向量shapes shape listReturns:matrixes 恢复的矩阵序列"""matrixes = []begin = 0for shape in shapes:end = begin + shape[0] * shape[1]matrix = vector[begin:end].reshape(shape)begin = endmatrixes.append(matrix)return matrixes
  • 定义梯度校验过程:
def gradientCheck(Thetas,X,y,theLambda):"""梯度校验Args:Thetas 权值矩阵X 样本y 标签theLambda 正规化参数Returns:checked 是否检测通过"""m, n = X.shape# 前向传播计算各个神经元的激活值a = fp(Thetas, X)# 反向传播计算梯度增量D = bp(Thetas, a, y, theLambda)# 计算预测代价J = computeCost(Thetas, y, theLambda, a=a)DVec = unroll(D)# 求梯度近似epsilon = 1e-4gradApprox = np.zeros(DVec.shape)ThetaVec = unroll(Thetas)shapes = [Theta.shape for Theta in Thetas]for i,item in enumerate(ThetaVec):ThetaVec[i] = item - epsilonJMinus = computeCost(roll(ThetaVec,shapes),y,theLambda,X=X)ThetaVec[i] = item + epsilonJPlus = computeCost(roll(ThetaVec,shapes),y,theLambda,X=X)gradApprox[i] = (JPlus-JMinus) / (2*epsilon)# 用欧氏距离表示近似程度diff = np.linalg.norm(gradApprox - DVec)if diff < 1e-2:return Trueelse:return False
  • 计算代价计算函数:
    J(Θ)J(Θ)=−1m∑i=1m∑k=1K[yk(i)log((hΘ(x(i)))k)+(1−yk(i))log(1−(hΘ(x(i)))k)]+λ2m∑l=1L−1∑i=1sl∑j=1sl+1(Θj,i(l))2J(Θ)J(Θ)=−\frac 1m∑_{i=1}^m∑_{k=1}^K[y^{(i)}_k\ log((h_Θ(x^{(i)}))_k)+(1−y^{(i)}_k)\ log(1−(h_Θ(x^{(i)}))_k)]+\frac λ{2m}∑_{l=1}^{L−1}∑_{i=1}^{s_l}∑_{j=1}^{s_l+1}(Θ^{(l)}_{j,i})^2J(Θ)J(Θ)=−m1​i=1∑m​k=1∑K​[yk(i)​ log((hΘ​(x(i)))k​)+(1−yk(i)​) log(1−(hΘ​(x(i)))k​)]+2mλ​l=1∑L−1​i=1∑sl​​j=1∑sl​+1​(Θj,i(l)​)2矩阵表示为:J(Θ)=−1m∑(YT.∗log(ΘA))+log(1−ΘA).∗(1−YT))矩阵表示为:J(\Theta)=-\frac1m\sum(Y^T.*\ log(\Theta A))+log(1-\Theta A).*(1-Y^T))矩阵表示为:J(Θ)=−m1​∑(YT.∗ log(ΘA))+log(1−ΘA).∗(1−YT))
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)error = -np.sum(np.multiply(y.T,np.log(a[-1]))+np.multiply((1-y).T, np.log(1-a[-1])))# 正规化参数reg = -np.sum([np.sum(Theta[:, 1:]) for Theta in Thetas])return (1.0 / m) * error + (1.0 / (2 * m)) * theLambda * reg
  • 设计前向传播过程:
    a(1)=xa^{(1)}=xa(1)=xz(2)=Θ(1)a(1)z^{(2)}=\Theta^{(1)}a^{(1)}z(2)=Θ(1)a(1)a(2)=g(z(2))a^{(2)}=g(z^{(2)})a(2)=g(z(2))z(3)=Θ(3)a(3)z^{(3)}=\Theta^{(3)}a^{(3)}z(3)=Θ(3)a(3)a(3)=g(z(3))a^{(3)}=g(z^{(3)})a(3)=g(z(3))hΘ(x)=a(3)h_\Theta(x)=a^{(3)} hΘ​(x)=a(3)
def fp(Thetas, X):"""前向反馈过程Args:Thetas 权值矩阵X 输入样本Returns:a 各层激活向量"""layers = range(len(Thetas) + 1)layerNum = len(layers)# 激活向量序列a = range(layerNum)# 前向传播计算各层输出for l in layers:if l == 0:a[l] = X.Telse:z = Thetas[l - 1] * 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
  • 设计反向传播过程
    σ(l)={a(l)−yl=L(Θ(l)σ(l+1))T.∗g′(z(l))l=2,3,...,L−1\sigma^{(l)}=\begin{cases} a^{(l)}-y\quad\quad\quad\ \quad\quad\quad\quad l=L\\ (\Theta^{(l)}\sigma^{(l+1)})^T.*g^′(z^{(l)})\quad l=2,3,...,L-1 \end{cases}σ(l)={a(l)−y l=L(Θ(l)σ(l+1))T.∗g′(z(l))l=2,3,...,L−1​

Δ(l)=δ(l+1)(a(l))T\Delta^{(l)}=\delta^{(l+1)}(a^{(l)})^TΔ(l)=δ(l+1)(a(l))T

Di,j(l)={1m(Δi,j(l)+λΘi,j(l)),ifj≠01m(Δij(l)),ifj=0D^{(l)}_{i,j}=\begin{cases} \frac 1m(\Delta^{(l)}_{i,j}+\lambda\Theta^{(l)}_{i,j}), \ \ \quad\quad if\ j \ne 0\\ \frac1m(\Delta^{(l)}_{ij}),\quad\quad\quad\quad\quad\quad if j=0 \end{cases}Di,j(l)​={m1​(Δi,j(l)​+λΘi,j(l)​),  if j​=0m1​(Δij(l)​),ifj=0​

def bp(Thetas, a, y, theLambda):"""反向传播过程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:# 输入层不计算误差breakif l == layerNum - 1:# 输出层误差d[l] = a[l] - y.Telse:# 忽略偏置d[l] = np.multiply((Thetas[l][:,1:].T * d[l + 1]), sigmoidDerivative(a[l][1:, :]))for l in layers[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:] +theLambda * Theta[:, 1:])return D
  • 获得了梯度后,设计权值更新过程:
    Θ(l)=Θ(l)+αD(l)\Theta^{(l)}=\Theta^{(l)}+\alpha D^{(l)}Θ(l)=Θ(l)+αD(l)
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
  • 综上,我们能得到梯度下降过程:
    1.前向传播计算各层激活值
    2.反向计算权值的更新梯度
    3.更新权值
def gradientDescent(Thetas, X, y, alpha, theLambda):"""梯度下降Args:X 样本y 标签alpha 学习率theLambda 正规化参数Returns:J 预测代价Thetas 更新后的各层权值矩阵"""# 样本数,特征数m, n = X.shape# 前向传播计算各个神经元的激活值a = fp(Thetas, X)# 反向传播计算梯度增量D = bp(Thetas, a, y, theLambda)# 计算预测代价J = computeCost(Thetas,y,theLambda,a=a)# 更新权值Thetas = updateThetas(m, Thetas, D, alpha, theLambda)if np.isnan(J):J = np.infreturn J, Thetas
  • 则整个网络的训练过程如下:

    • 默认由系统自动初始化权值矩阵
    • 默认为不含有隐层的感知器神经网络
    • 默认隐层单元数为 5 个
    • 默认学习率为 1
    • 默认不进行正规化
    • 默认误差精度为 10−2
    • 默认最大迭代次数为 50 次

在训练之前,我们会进行一次梯度校验来确定网络是否正确:

def train(X, y, Thetas=None, hiddenNum=0, unitNum=5, epsilon=1, alpha=1, theLambda=0, precision=0.01, maxIters=50):"""网络训练Args:X 训练样本y 标签集Thetas 初始化的Thetas,如果为None,由系统随机初始化ThetashiddenNum 隐藏层数目unitNum 隐藏层的单元数epsilon 初始化权值的范围[-epsilon, epsilon]alpha 学习率theLambda 正规化参数precision 误差精度maxIters 最大迭代次数"""# 样本数,特征数m, n = X.shape# 矫正标签集y = adjustLabels(y)classNum = y.shape[1]# 初始化Thetaif Thetas is None:Thetas = initThetas(inputSize=n,hiddenNum=hiddenNum,unitNum=unitNum,classNum=classNum,epsilon=epsilon)# 先进性梯度校验print 'Doing Gradient Checking....'checked = gradientCheck(Thetas, X, y, theLambda)if checked:for i in range(maxIters):error, Thetas = gradientDescent(Thetas, X, y, alpha=alpha, theLambda=theLambda)if error < precision:breakif error == np.inf:breakif error < precision:success = Trueelse:success = Falsereturn {'error': error,'Thetas': Thetas,'iters': i,'success': error}else:print 'Error: Gradient Cheching Failed!!!'return {'error': None,'Thetas': None,'iters': 0,'success': False}

训练结果将包含如下信息:(1)网络的预测误差 error;(2)各层权值矩阵 Thetas;(3)迭代次数 iters;(4)是否训练成功 success

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

完整的神经网络模块为:

# coding: utf-8
# neural_network/nn.py
import numpy as np
from scipy.optimize import minimize
from scipy import statsdef sigmoid(z):"""sigmoid"""return 1 / (1 + np.exp(-z))def sigmoidDerivative(a):"""sigmoid求导"""return np.multiply(a, (1-a))def initThetas(hiddenNum, unitNum, inputSize, classNum, epsilon):"""初始化权值矩阵Args:hiddenNum 隐层数目unitNum 每个隐层的神经元数目inputSize 输入层规模classNum 分类数目epsilon epsilonReturns:Thetas 权值矩阵序列"""hiddens = [unitNum for i in range(hiddenNum)]units = [inputSize] + hiddens + [classNum]Thetas = []for idx, unit in enumerate(units):if idx == len(units) - 1:breaknextUnit = units[idx + 1]# 考虑偏置Theta = np.random.rand(nextUnit, unit + 1) * 2 * epsilon - epsilonThetas.append(Theta)return Thetasdef 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)error = -np.sum(np.multiply(y.T,np.log(a[-1]))+np.multiply((1-y).T, np.log(1-a[-1])))# 正规化参数reg = -np.sum([np.sum(Theta[:, 1:]) for Theta in Thetas])return (1.0 / m) * error + (1.0 / (2 * m)) * theLambda * regdef gradientCheck(Thetas,X,y,theLambda):"""梯度校验Args:Thetas 权值矩阵X 样本y 标签theLambda 正规化参数Returns:checked 是否检测通过"""m, n = X.shape# 前向传播计算各个神经元的激活值a = fp(Thetas, X)# 反向传播计算梯度增量D = bp(Thetas, a, y, theLambda)# 计算预测代价J = computeCost(Thetas, y, theLambda, a=a)DVec = unroll(D)# 求梯度近似epsilon = 1e-4gradApprox = np.zeros(DVec.shape)ThetaVec = unroll(Thetas)shapes = [Theta.shape for Theta in Thetas]for i,item in enumerate(ThetaVec):ThetaVec[i] = item - epsilonJMinus = computeCost(roll(ThetaVec,shapes),y,theLambda,X=X)ThetaVec[i] = item + epsilonJPlus = computeCost(roll(ThetaVec,shapes),y,theLambda,X=X)gradApprox[i] = (JPlus-JMinus) / (2*epsilon)# 用欧氏距离表示近似程度diff = np.linalg.norm(gradApprox - DVec)if diff < 1e-2:return Trueelse:return Falsedef 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] = 1else:yAdjusted = np.zeros((y.shape[0], 1), np.float64)for row, label in enumerate(y):if label != minClass:yAdjusted[row, 0] = 1.0return yAdjustedreturn ydef unroll(matrixes):"""参数展开Args:matrixes 矩阵Return:vec 向量"""vec = []for matrix in matrixes:vector = matrix.reshape(1, -1)[0]vec = np.concatenate((vec, vector))return vecdef roll(vector, shapes):"""参数恢复Args:vector 向量shapes shape listReturns:matrixes 恢复的矩阵序列"""matrixes = []begin = 0for shape in shapes:end = begin + shape[0] * shape[1]matrix = vector[begin:end].reshape(shape)begin = endmatrixes.append(matrix)return matrixesdef fp(Thetas, X):"""前向反馈过程Args:Thetas 权值矩阵X 输入样本Returns:a 各层激活向量"""layers = range(len(Thetas) + 1)layerNum = len(layers)# 激活向量序列a = range(layerNum)# 前向传播计算各层输出for l in layers:if l == 0:a[l] = X.Telse:z = Thetas[l - 1] * 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 adef bp(Thetas, a, y, theLambda):"""反向传播过程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:# 输入层不计算误差breakif l == layerNum - 1:# 输出层误差d[l] = a[l] - y.Telse:# 忽略偏置d[l] = np.multiply((Thetas[l][:,1:].T * d[l + 1]), sigmoidDerivative(a[l][1:, :]))for l in layers[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:] +theLambda * Theta[:, 1:])return Ddef 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 Thetasdef gradientDescent(Thetas, X, y, alpha, theLambda):"""梯度下降Args:X 样本y 标签alpha 学习率theLambda 正规化参数Returns:J 预测代价Thetas 更新后的各层权值矩阵"""# 样本数,特征数m, n = X.shape# 前向传播计算各个神经元的激活值a = fp(Thetas, X)# 反向传播计算梯度增量D = bp(Thetas, a, y, theLambda)# 计算预测代价J = computeCost(Thetas,y,theLambda,a=a)# 更新权值Thetas = updateThetas(m, Thetas, D, alpha, theLambda)if np.isnan(J):J = np.infreturn J, Thetasdef train(X, y, Thetas=None, hiddenNum=0, unitNum=5, epsilon=1, alpha=1, theLambda=0, precision=0.01, maxIters=50):"""网络训练Args:X 训练样本y 标签集Thetas 初始化的Thetas,如果为None,由系统随机初始化ThetashiddenNum 隐藏层数目unitNum 隐藏层的单元数epsilon 初始化权值的范围[-epsilon, epsilon]alpha 学习率theLambda 正规化参数precision 误差精度maxIters 最大迭代次数"""# 样本数,特征数m, n = X.shape# 矫正标签集y = adjustLabels(y)classNum = y.shape[1]# 初始化Thetaif Thetas is None:Thetas = initThetas(inputSize=n,hiddenNum=hiddenNum,unitNum=unitNum,classNum=classNum,epsilon=epsilon)# 先进性梯度校验print 'Doing Gradient Checking....'checked = gradientCheck(Thetas, X, y, theLambda)if checked:for i in range(maxIters):error, Thetas = gradientDescent(Thetas, X, y, alpha=alpha, theLambda=theLambda)if error < precision:breakif error == np.inf:breakif error < precision:success = Trueelse:success = Falsereturn {'error': error,'Thetas': Thetas,'iters': i,'success': error}else:print 'Error: Gradient Cheching Failed!!!'return {'error': None,'Thetas': None,'iters': 0,'success': False}def predict(X, Thetas):"""预测函数Args:X: 样本Thetas: 训练后得到的参数Return:a"""a = fp(Thetas,X)return a[-1]

3.10 程序示例--神经网络设计-机器学习笔记-斯坦福吴恩达教授相关推荐

  1. 5.10 程序示例--模型选择-机器学习笔记-斯坦福吴恩达教授

    程序示例–模型选择 在新的一组样本中,我们将通过交叉验证集选择模型,参数 CCC 和 高斯核的参数 δδδ 我们都将在以下 8 个值中选取测试,则总共构成了 8×8=648×8=648×8=64 个模 ...

  2. 8.7 程序示例--异常检测-机器学习笔记-斯坦福吴恩达教授

    程序示例–异常检测 异常检测模型 提供了一般高斯分布模型和多元高斯分布模型.其中,多元高斯分布模型被限制到了同轴分布: # coding: utf8 # anomaly_detection/anoma ...

  3. 4.7 程序示例--算法诊断-机器学习笔记-斯坦福吴恩达教授

    程序示例–算法诊断 我们手头有一份大坝水的流量与水位关系的数据,首先我们将其划分为训练集.交叉验证集和测试集: # coding: utf-8 # algorithm_analysis/diagnos ...

  4. 7.3 程序示例--PCA 模型-机器学习笔记-斯坦福吴恩达教授

    程序示例–PCA 模型 # coding: utf8 # pca/pca.pyimport numpy as npdef normalize(X):"""数据标准化处理A ...

  5. 5.9 程序示例--非线性分类-机器学习笔记-斯坦福吴恩达教授

    程序示例–非线性分类 接下来,我们采用高斯核函数来解决非线性可分问题,由于数据集较大,我们使用性能更好的完整版 SMO 算法进行训练: # coding: utf8 # svm/test_non_li ...

  6. 5.8 程序示例--线性分类-机器学习笔记-斯坦福吴恩达教授

    程序示例–线性分类 首先,我们使用线性核函数来训练线性可分问题,这里,我们使用的是简化版 SMO 算法: # coding: utf8 # svm/test_linear import smo imp ...

  7. 1.3 程序示例--梯度下降-机器学习笔记-斯坦福吴恩达教授

    回归模块 回归模块中提供了批量梯度下降和随机梯度下降两种学习策略来训练模型: # coding: utf-8 # linear_regression/regression.py import nump ...

  8. 6.7 程序示例--K-Means-机器学习笔记-斯坦福吴恩达教授

    程序示例–K-Means 函数定义 # coding: utf-8 # kmeans/kmeans.py import numpy as npdef loadDataSet(filename):&qu ...

  9. 10.1 掌握大数据-机器学习笔记-斯坦福吴恩达教授

    掌握大数据 在算法分析与优化一节中,我们就提到,在机器学习界流传着这样一句话: It's not who has the best algorithm that wins. It's who has ...

最新文章

  1. MySQL · myrocks · MyRocks之memtable切换与刷盘
  2. UVA 10304 Optimal Binary Search Tree
  3. 戴尔塔式服务器各型号,戴尔_PowerEdge T440_塔式服务器_网络存储服务器_服务器 | Dell 中国大陆...
  4. 121. Leetcode 5. 最长回文子串 (动态规划-子序列问题)
  5. 转 公有密匙 私有密匙
  6. 在C/C++中嵌入Python
  7. boost::set_symmetric_difference相关的测试程序
  8. bashdb常用命令
  9. Linux-C实现GPRS模块发送短信
  10. 将一副图片编译进uboot
  11. Python基础知识汇总
  12. 如何区分家里的网线是超五类还是超六类的呢?
  13. oracle 日期格式化_日期格式化跨年bug,是否与你不期而遇?
  14. 手把手图文并茂教你用Android Studio编译FFmpeg库并移植
  15. Kotlin | Kotlin教程
  16. 电脑COM串口管理芯片75232、75185及电路(两者可代换)
  17. 用react-custom-scrollbars插件美化 滚动条
  18. DM 源码阅读系列文章(七)定制化数据同步功能的实现
  19. 分享蔡澜老师的自问自答
  20. 解决OBS录屏黑屏问题

热门文章

  1. HDU 1221: Cube
  2. dynamic_caast操作符
  3. 敏捷转型历程 - Sprint3 回顾会
  4. 使用Windbg调试StackOverflowException异常
  5. bzoj 1010: [HNOI2008]玩具装箱toy 2011-12-27
  6. Java排序算法总结
  7. 主表关联字表,主表自增长,同时插入
  8. 国庆七天乐 Day5
  9. UA MATH566 统计理论 概念与定理总结
  10. 体感Kinect手势识别开发基本原理