Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 703|回复: 0

自己动手,编写神经网络程序,解决Mnist问题,并网络化部署-编写网络

[复制链接]
  • TA的每日心情
    奋斗
    2024-4-6 11:05
  • 签到天数: 748 天

    [LV.9]以坛为家II

    2034

    主题

    2092

    帖子

    70万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    705612
    发表于 2021-9-5 09:48:10 | 显示全部楼层 |阅读模式

    基于《神经网络和深度学习》这本绝好的教材提供的相关资料和代码,我们自己动手编写“随机取样的梯度下降神经网络”。为了更好地说明问题,我们先从简单的开始:

    1、sigmod函数,基本上就是基于定义的;
     
    #########helper函数########
    #计算sigmoid,这个函数来自定义
    def sigmoid( z):
    return 1.0/( 1.0+np.exp(-z))
    #计算sigmoid的导数,这个函数可以被证明
    def sigmoid_prime( z):
    return sigmoid(z)*( 1 - sigmoid(z))
     
    2、构造函数
    ###########Main函数########
    #使用例子 net = GoNetwork([2, 3, 1])
    class GoNetwork( object):

    def __init__( self, sizes): #构造函数
    self.num_layers = len(sizes) #层数
    self.sizes = sizes #每层size
    #随机生成子节点
    self.biases= [np.random.randn(y, 1) for y in sizes[ 1:]]
    # net.weights[1] 是一个存储着连接第二层和第三层神经元权重的 Numpy 矩阵。
    self.weights = [np.random.randn(y, x)
    for x, y in zip(sizes[:- 1], sizes[ 1:])]
    这个地方有以下几个地方,一个是在Python中类和类的构造函数是这样定义的;二个是Python如何体现出其强大的数据处理能力的。
    这里,如果
    sizes = [2,  3,  1]
    则sizes [1:] = [3,1]
     
    numpy.random.randn(d0, d1, ..., dn)

    这个函数的作用就是从标准正态分布中返回一个或多个样本值,比如

    bbb = [np.random.randn( 3, 2)]
    表示的是生成3X2的随机序列,可以这样来使用,就是加上偏置了
    2.5 * np.random.randn(2, 4) + 3

    返回:

    array([[ 4.128****53,  1.764****44 ,  2.732****92,  2.90839231],
          [ 0.174****86,   4.92026887,  1.574****66, -0.4305991 ]])
    aaa =[ np.random.randn(y, 1) for y in sizes[ 1:]]
    这是一种Python的连写方法,这里就是对[3,1]分别生成随机序列。这个随机是用来干什么的?就是随机的权值。
    描述 zip() 函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表
    这里
    zip(sizes[:-1], sizes[1:])
    表示的是将第1、2层之间,2、3层之间的全连接生成随机权值。
     
    3、前向网络,主要用于测试当前网络
    def feedforward( self, a):
    for b,w in zip( self.biases, self.weights):
    a = sigmoid(np.dot(w,a)+b)
    return a
    非常直接的按照定义,进行上一层到下一层的前向 计算,注意这里得到的a也是x行1列的一个矩阵
     
    4、评价函数,基本上也是按照定义进行设定的
    def evaluate( self, test_data):
    test_results = [(np.argmax( self.feedforward(x)), y) #这里需要注意feedforward的参数x,实际上它是一个in/out参数。
    for (x, y) in test_data]
    return sum( int(x == y) for (x, y) in test_results) #做出了正确的预测
    这个地方调用了feedforward(x),并且和y进行比较,得到准确比对有哪些。应该说代码非常精简。
     
    5、代价函数
    #cost代价函数
    def cost_derivative( self, output_activations, y):
    return (output_activations-y)
     
    以上几项都是非常好理解的,基本上你看到的立刻就能够理解,需要补充的知识并不是很多。结合上一课的相关知识,我们这里提出的所谓随机,就是提取很小的一块数据,而后进行计算梯度下降参数,更新网络的权重和偏置
    def update_mini_batch( self, mini_batch, eta):
    nabla_b = [np.zeros(b.shape) for b in self.biases] #生成b和w形状的以0填充的矩阵
    nabla_w = [np.zeros(w.shape) for w in self.weights]
    for x, y in mini_batch:
    delta_nabla_b, delta_nabla_w = self.backprop(x, y) #理解反向传播就是一种快速计算梯度的方法
    nabla_b = [nb+dnb for nb, dnb in zip(nabla_b, delta_nabla_b)]
    nabla_w = [nw+dnw for nw, dnw in zip(nabla_w, delta_nabla_w)]
    self.weights = [w-(eta/ len(mini_batch))*nw
    for w, nw in zip( self.weights, nabla_w)]
    self.biases = [b-(eta/ len(mini_batch))*nb
    for b, nb in zip( self.biases, nabla_b)]
    其中
       nabla_b = [np.zeros(b.shape) for b in self.biases]
       nabla_w = [np.zeros(w.shape) for w in self.weights]
    生成b和w形状的以0填充的矩阵,这里就是用来填充原始数据的。
    在这个小循环里面,我们可以以“黑箱”的形式来理解backprop函数,就是一种用来计算最快下降梯度的方法。
     for x, y in mini_batch:
                delta_nabla_b, delta_nabla_w = self.backprop(x, y)
                nabla_b = [nb+dnb for nb, dnb in zip(nabla_b, delta_nabla_b)]
                nabla_w = [nw+dnw for nw, dnw in zip(nabla_w, delta_nabla_w)]
    在这里,我们便历所有的mini_batch,注意在上面这行代码中,
    而后,引入eta,以这个梯度作为 delta_nabla_b,  delta_nabla_w  的初始值都为空.
    这样,我们按照定义进行了一次小数据的更新。其能够完成,是因为backprop为我们成功计算了代价函数的两个梯度。
    6、后向传播函数,其目的是进行梯度下降计算,是最为复杂的部分
    #反向传播就是一种快速计算代价函数梯度的方法,也就是计算delta的一种方法
    def backprop( self, x, y):
    #都以空矩阵来进行初始化
    nabla_b = [np.zeros(b.shape) for b in self.biases]
    nabla_w = [np.zeros(w.shape) for w in self.weights]
    # feedforward
    activation = x
    activations = [x] # list to store all the activations, layer by layer
    zs = [] # list to store all the z vectors, layer by layer
    for b, w in zip( self.biases, self.weights):
    z = np.dot(w, activation)+b #前向传播
    zs.append(z)
    activation = sigmoid(z)
    activations.append(activation)
    # backward pass
    delta = self.cost_derivative(activations[- 1], y) * \
    sigmoid_prime(zs[- 1])
    nabla_b[- 1] = delta
    nabla_w[- 1] = np.dot(delta, activations[- 2].transpose())
     
    for l in range( 2, self.num_layers):
    z = zs[-l]
    sp = sigmoid_prime(z)
    delta = np.dot( self.weights[-l+ 1].transpose(), delta) * sp
    nabla_b[-l] = delta
    nabla_w[-l] = np.dot(delta, activations[-l- 1].transpose())
    return (nabla_b, nabla_w)
     
    其中内容比较复杂,一条一条进行解释 
    nabla_b = [np.zeros(b.shape) for b in self.biases]
    nabla_w = [np.zeros(w.shape) for w in self.weights]
    生成空矩阵
    # feedforward
    activation = x
    activations = [x] # list to store all the activations, layer by layer
    zs = [] # list to store all the z vectors, layer by layer
    for b, w in zip( self.biases, self.weights):
    z = np.dot(w, activation)+b #前向传播
    zs.append(z)
    activation = sigmoid(z)
    activations.append(activation)
     
    前向计算,保存所有b、w和 z。后面的几行代码,主要都是和4个公式严格对应的
    delta = self.cost_derivative(activations[- 1], y) * sigmoid_prime(zs[- 1])
     
    对应BP1
     
    nabla_b[- 1] = delta
    nabla_w[- 1] = np.dot(delta, activations[- 2].transpose())
     
    分别对应BP3和BP4,就是最后来计算具体的梯度值
     
    delta = np.dot( self.weights[-l+ 1].transpose(), delta) * sp
     
    对应BP2,反向计算。
     
    7、 随机梯度下降算法,到了这里也就是将上面的合起来
    #随机梯度下降算法
    def SGD( self, training_data, epochs, mini_batch_size, eta, test_data= None):

    training_data = list(training_data)
    n = len(training_data)

    if test_data:
    test_data = list(test_data)
    n_test = len(test_data)
    #⾸先随机地将训练数据打乱
    for j in range(epochs):
    random.shuffle(training_data)
    #再将它分成多个适当⼤⼩的⼩批量数据
    mini_batches = [
    training_data[k:k+mini_batch_size]
    for k in range( 0, n, mini_batch_size)]
    for mini_batch in mini_batches: #最主要的一行代码
    self.update_mini_batch(mini_batch, eta)
    if test_data:
    print( "Epoch {} : {} / {} ".format(j, self.evaluate(test_data),n_test))
    else:
    print( "Epoch {} complete".format(j))
    主要优化的地方,就是将原较大的数据集分成多个部分,而后遍历所有的部分,进行梯度下降运算,并且打印比较的结果。应该说再次体现了Python强大的集成编码能力。
     





    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-4-25 12:18 , Processed in 0.069599 second(s), 29 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表