一文入门BP神经网络——从原理到应用(应用篇)

来源:互联网 发布:定义二维数组可缺省 编辑:程序博客网 时间:2024/06/05 16:45

  • 辅助函数
  • 前向传播过程
  • 反向传播过程
  • 测试结果

  本文是一文搞定BP神经网络——从原理到应用(原理篇)的姊妹篇,主要使用python实现我们之前推导的公式。本文难免会有叙述不合理的地方,希望读者可以在评论区反馈。我会及时吸纳大家的意见,并在之后的chat里进行说明。

本文参考了一些资料,在此一并列出。

  • http://neuralnetworksanddeeplearning.com/chap2.html
  • https://www.deeplearning.ai/ coursera对应课程视频讲义
  • coursera华盛顿大学机器学习专项
  • 周志华《机器学习》
  • 李航《统计学习方法》
  • 张明淳《工程矩阵理论》

本文代码和数据库文件在这里下载http://download.csdn.net/download/u014303046/10035014.

编号 公式 备注 1 Z[l]=w[l]A[l1]+b[l] 2 A[l]=σ(Z[l]) 3 dZ[L]=ACσ(Z[L]) 4 dZ[l]=[w[l+1]TdZ[l+1]]σ(Z[l]) 5 db[l]=Cb[l]=1mmeanOfEachRow(dZ[l]) 6 dw[l]=Cw[l]=1mdZ[l]A[l1]T 7 b[l]b[l]αdb[l] 8 w[l]w[l]αdw[l] 9 dA[l]=w[l]TdZ[l] 10 C=1mmi=1(y(i)log(a[L](i))+(1y(i))log(1a[L](i))) 代价函数

1. 辅助函数

  辅助函数主要包括激活函数以及激活函数的反向传播过程函数:

其中,激活函数反向传播代码对应公式4和9.

def sigmoid(z):    """    使用numpy实现sigmoid函数    参数:    Z numpy array    输出:    A 激活值(维数和Z完全相同)    """    return 1/(1 + np.exp(-z))def relu(z):    """    线性修正函数relu    参数:    z numpy array    输出:    A 激活值(维数和Z完全相同)    """    return np.array(z>0)*zdef sigmoidBackward(dA, cacheA):    """    sigmoid的反向传播    参数:    dA 同层激活值    cacheA 同层线性输出    输出:    dZ 梯度    """    s = sigmoid(cacheA)    diff = s*(1 - s)    dZ = dA * diff    return dZdef reluBackward(dA, cacheA):    """    relu的反向传播    参数:    dA 同层激活值    cacheA 同层线性输出    输出:    dZ 梯度    """    Z = cacheA    dZ = np.array(dA, copy=True)     dZ[Z <= 0] = 0    return dZ

  另外一个重要的辅助函数是数据读取函数和参数初始化函数:

def loadData(dataDir):    """    导入数据    参数:    dataDir 数据集路径    输出:    训练集,测试集以及标签    """    train_dataset = h5py.File(dataDir+'/train.h5', "r")    train_set_x_orig = np.array(train_dataset["train_set_x"][:]) # your train set features    train_set_y_orig = np.array(train_dataset["train_set_y"][:]) # your train set labels    test_dataset = h5py.File(dataDir+'/test.h5', "r")    test_set_x_orig = np.array(test_dataset["test_set_x"][:]) # your test set features    test_set_y_orig = np.array(test_dataset["test_set_y"][:]) # your test set labels    classes = np.array(test_dataset["list_classes"][:]) # the list of classes    train_set_y_orig = train_set_y_orig.reshape((1, train_set_y_orig.shape[0]))    test_set_y_orig = test_set_y_orig.reshape((1, test_set_y_orig.shape[0]))    return train_set_x_orig, train_set_y_orig, test_set_x_orig, test_set_y_orig, classesdef iniPara(laydims):    """    随机初始化网络参数    参数:    laydims 一个python list    输出:    parameters 随机初始化的参数字典(”W1“,”b1“,”W2“,”b2“, ...)    """    np.random.seed(1)    parameters = {}    for i in range(1, len(laydims)):        parameters['W'+str(i)] = np.random.randn(laydims[i], laydims[i-1])/ np.sqrt(laydims[i-1])        parameters['b'+str(i)] = np.zeros((laydims[i], 1))    return parameters

2. 前向传播过程

对应公式1和2.

def forwardLinear(W, b, A_prev):    """    前向传播    """    Z = np.dot(W, A_prev) + b    cache = (W, A_prev, b)    return Z, cachedef forwardLinearActivation(W, b, A_prev, activation):    """    带激活函数的前向传播    """    Z, cacheL = forwardLinear(W, b, A_prev)    cacheA = Z    if activation == 'sigmoid':        A = sigmoid(Z)    if activation == 'relu':        A = relu(Z)    cache = (cacheL, cacheA)    return A, cachedef forwardModel(X, parameters):    """    完整的前向传播过程    """    layerdim = len(parameters)//2    caches = []    A_prev = X    for i in range(1, layerdim):        A_prev, cache = forwardLinearActivation(parameters['W'+str(i)], parameters['b'+str(i)], A_prev, 'relu')        caches.append(cache)    AL, cache = forwardLinearActivation(parameters['W'+str(layerdim)], parameters['b'+str(layerdim)], A_prev, 'sigmoid')    caches.append(cache)    return AL, caches

3. 反向传播过程

线性部分反向传播对应公式5和6。

def linearBackward(dZ, cache):    """    线性部分的反向传播    参数:    dZ 当前层误差    cache (W, A_prev, b)元组    输出:    dA_prev 上一层激活的梯度    dW 当前层W的梯度    db 当前层b的梯度    """    W, A_prev, b = cache    m = A_prev.shape[1]    dW = 1/m*np.dot(dZ, A_prev.T)    db = 1/m*np.sum(dZ, axis = 1, keepdims=True)    dA_prev = np.dot(W.T, dZ)    return dA_prev, dW, db

非线性部分对应公式3、4、5和6 。

def linearActivationBackward(dA, cache, activation):    """    非线性部分的反向传播    参数:    dA 当前层激活输出的梯度    cache (W, A_prev, b)元组    activation 激活函数类型    输出:    dA_prev 上一层激活的梯度    dW 当前层W的梯度    db 当前层b的梯度    """    cacheL, cacheA = cache    if activation == 'relu':        dZ = reluBackward(dA, cacheA)        dA_prev, dW, db = linearBackward(dZ, cacheL)    elif activation == 'sigmoid':        dZ = sigmoidBackward(dA, cacheA)        dA_prev, dW, db = linearBackward(dZ, cacheL)    return dA_prev, dW, db

完整反向传播模型:

def backwardModel(AL, Y, caches):    """    完整的反向传播过程    参数:    AL 输出层结果    Y 标签值    caches 【cacheL, cacheA】    输出:    diffs 梯度字典    """    layerdim = len(caches)    Y = Y.reshape(AL.shape)    L = layerdim    diffs = {}    dAL = - (np.divide(Y, AL) - np.divide(1 - Y, 1 - AL))    currentCache = caches[L-1]    dA_prev, dW, db =  linearActivationBackward(dAL, currentCache, 'sigmoid')    diffs['dA' + str(L)], diffs['dW'+str(L)], diffs['db'+str(L)] = dA_prev, dW, db    for l in reversed(range(L-1)):        currentCache = caches[l]        dA_prev, dW, db =  linearActivationBackward(dA_prev, currentCache, 'relu')        diffs['dA' + str(l+1)], diffs['dW'+str(l+1)], diffs['db'+str(l+1)] = dA_prev, dW, db    return diffs

4. 测试结果

  打开你的jupyter notebook,运行我们的BP.ipynb文件,首先导入依赖库和数据集,然后使用一个循环来确定最佳的迭代次数大约为2000:


enter image description here
【图6】

  最后用一个例子来看一下模型的效果——判断一张图片是不是猫:


enter image description here
【图7】

好了,测试到此结束。你也可以自己尝试其它的神经网络结构和测试其它图片。

阅读全文
1 0
原创粉丝点击