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

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. 明解C语言入门篇_第8章_动手编写各种程序吧

    前言 本文为业余学习<明解C语言入门篇>的记录,包含代码清单和练习题. 开始学习时间:2022年8月21日 +++++++++++++++++++++++++++++++ 第1章 初识C语 ...

  2. (6CBIR模拟问题)自己动手,编写神经网络程序,解决Mnist问题,并网络化部署...

    一.CBIR技术简介 传统的图像检索过程,先通过人工对图像进行文字标注,再利用关键字来检索图像,这种依据图像描述的字符匹配程度提供检索结果的方法,简称"以字找图",既耗时又主观多义 ...

  3. 自己动手,编写神经网络程序,解决Mnist问题,并网络化部署-6CBIR模拟问题

    一.CBIR技术简介 传统的图像检索过程,先通过人工对图像进行文字标注,再利用关键字来检索图像,这种依据图像描述的字符匹配程度提供检索结果的方法,简称"以字找图",既耗时又主观多义 ...

  4. 【C++ Primer】自己动手编写函数 atoi(char *str)

    一,要求:自己动手编写 atoi(char *str)函数,功能是将字符串变成数字 简单版本: 需要考虑的地方 1)正负号 2)仅仅考虑十进制 3)如何把数字 字符 变成整数 #include < ...

  5. linux的静态编译elf无法调试,[翻译]自己动手编写一个Linux调试器系列之4 ELF文件格式与DWARF调试格式 by lantie@15PB...

    自己动手编写一个Linux调试器系列之4 ELF文件格式与DWARF调试格式 by lantie@15PB 在上一节中,你已经听说了DWARF调试格式,它是程序的调试信息,是一种可以更好理解源码的方式 ...

  6. python是什么语言编写的程序称为_Python 学习(一)【Python语言简介-Python是什么】...

    Python是一种编程语言,它的名字来源于一个喜剧.也许最初设计Python这种语言的人并没有想到今天Python会在工业和科研上获得如此广泛的使用. Python是什么(转载自Primus) 著名的 ...

  7. 基于Ubuntu(x86)系统和STM32(Keil)编写C程序分别进行编程、验证

    文章目录 实验内容 一.基本概念 (一).全局变量 (二).局部变量 (三).堆和栈 二.编程验证 (一).基于Ubuntu用Linux系统编写C程序 (二).基于STM32用Keil编写C程序 三. ...

  8. 编写一个c语言程序 求e的值,编写一个程序求e的值_相关文章专题_写写帮文库

    时间:2019-05-15 01:58:18 作者:admin 3.2 代数式的值 做课人 尹圣军 [教学目标] 知识与技能 能解释代数式值的实际意义,了解代数式值的概念. 过程与方法 经历观察.实验 ...

  9. 自己动手编写CSDN博客备份工具-blogspider之源码分析(3)

    作者:gzshun. 原创作品,转载请标明出处! 来源:http://blog.csdn.net/gzshun 周星驰:剪头发不应该看别人怎么剪就发神经跟流行,要配合啊!你看你的发型,完全不配合你的脸 ...

最新文章

  1. 学习LINUX的几点注意事项
  2. U盘安装Linux CentOS 6.5 64位操作系统(来自互联网)
  3. python入门之控制结构顺序与选择结构_Python 入门之控制结构 - 顺序与选择结构——第1关:顺序结构...
  4. C专家编程--读书笔记六 运行时数据结构
  5. 茫茫内存,我该如何用 windbg 找到你 ?
  6. Win32ASM学习[11]:逻辑运算
  7. labview的IMAQ中sanp和grab有什么不同
  8. JS二维数组排序组合
  9. layui 监听表单提交form.on(‘submit(sub)‘,function (){}) ajax请求失败问题
  10. 女生也玩橄榄球?而且还有世界杯?!
  11. How do I ensure that data is securely and reliably written to disk?
  12. VS2017 专业版 离线安装实践 Visual Studio 2017
  13. 程序员进阶攻略-笔记-041~050
  14. JS高频面试题,请查阅,务必收藏持续更新
  15. Android10.0 os定制化系列讲解导读
  16. Cross-category Video Highlight Detection via Set-based Learning
  17. Python 多线程下载图片
  18. Mac 连上无线网络,无法上网
  19. Tensorflow图像分类代码理解
  20. 【源码】Wankel旋转式内燃机壳体轮廓的MATLAB程序设计

热门文章

  1. Twitter常用术语和名词解析
  2. ISP 图像测试经常使用的光源色温
  3. Windows Azure真实案例:NeoGeo New Media --SQL Azure提高数字媒体资产解决方案的拓展性...
  4. 分布式服务器架构下的3v3团队对抗游戏
  5. 记一次Powershell反混淆 (1)
  6. 在 tensorrtserver 中使用 saved_model
  7. 一个外汇交易者的爆仓实录,仔细阅读抵做10年交易
  8. 比例阀放大板24V/2a/3A/5a比例阀驱动放大器电磁比例阀控制器电磁比例阀门线性驱动0-5v/0-10v/4-20ma转0-/85MA165ma信号隔离放大器
  9. 【机器人学习】机械臂抓手matlab运动学与admas动力学分析
  10. html实现图片在立体,css3实现图片立体化缩放