全连接神经网络的概念我就不介绍了,对这个不是很了解的朋友,可以移步其他博主的关于神经网络的文章,这里只介绍我使用基本工具实现全连接神经网络的方法。

  所用工具:

    numpy == 1.16.4

    matplotlib 最新版

  我的思路是定义一个layer类,在这个类里边构建传播的前向传播的逻辑,以及反向传播的逻辑,然后在构建一个model类,在model类里边,将layer类中的对象拼接,就可以得到我们想要的模型。

  在Layers类的传播中,在Dense层中,我是按照公式output = X*w+b,来计算输出。X 是 (m,n)的矩阵,表示有m行数据,每一个数据是n维的向量。w是一个(n,1)的矩阵,是我们要优化的参数。b是一个(m,1)的矩阵,是偏置。在Activation层中,我是按照公式 output = f激活(X) 来计算输出的。f激活是激活函数,是逐元素函数。将Dense层与Activation层叠加,就能实现output = f激活(X*w+b)的效果,如果多次交替叠加,就相当于在计算output = f激活( f激活(f激活(X*w+b)*w+b)*w+b),这里只演示了三层,实际上这个就是全连接神经网络的基本数学表达式。

  构建这个模型的难点在于梯度的计算以及反向传播逻辑。中间层的每一层的输出对输入以及偏置求导,都是一个矩阵对另一个矩阵的求导。而矩阵的求导不同于高数中所学的导数,链式法则也有一些不同。关于这部分内容可参考:矩阵求导术(上)矩阵求导术(下),这里不再讲述。笔者正是在参考了这两篇文章的前提下实现这个过程的。

  导入工具包:

  

import numpy as np
import matplotlib.pyplot as plt

  定义Layer类中的Dense类中类:(这里可以把layers类单独拿出来作为一个父类,其余的层可以继承layers,然后钉子自己的反向传播逻辑,可以减少重复代码,这里为了方便展示,没有那么做)

class Layers:
class Dense:
'''
全连接层
''' def __init__(self, output_category):
'''
接收并初始化一个输出维度,用于确定这一层w的维度,以及用于梯度计算
:param output_category:
'''
self.output_category = output_category def __call__(self, Input):
'''
使用魔法方法,实例化对象后,随机的方式初始化w参数,
实例化输入数据,计算本层前向传播方式
:param Input:
:return:
'''
w_shape = (Input.shape[1], self.output_category)
b_shape = (Input.shape[0], self.output_category)
self.w = np.mat(np.random.random(size=w_shape))
self.b = np.mat(np.random.random(size=b_shape))
self.Input = Input
result = self.Input * self.w +self.b
self.result = result
return result def backpropagation(self, w_grad_from_next_layer=None, learning_rate=None, use_bias=False):
'''
反向传播算法的数学描述,公式参考
https://zhuanlan.zhihu.com/p/24863977
公式 Y = X * w +b ,
dY = dX * w + X * dw + db
= I * dX * w + X * dw * I + I * db * I (I是单位矩阵,
公式里每个I都不一样维度,具体是多少要参考它与谁相乘)
vec(dY) = np.kron(w,I)*vec(dX) + np.kron(I,w)*vec(dw) + np.kron(I,I)*vec(db)
:param w_grad_from_next_layer:从下一层传过来的梯度
:param learning_rate:学习率
:return:
'''
mid_w_grad = np.mat(np.kron(np.eye(self.output_category), self.Input))
self.w_grad = w_grad_from_next_layer * mid_w_grad mid_x_grad = np.kron(self.w.T, np.eye(self.Input.shape[0]))
self.x_grad = w_grad_from_next_layer * mid_x_grad if use_bias == True:
mid_b_grad = np.kron(np.eye(self.output_category), np.eye(self.Input.shape[0]))
self.b_grad = w_grad_from_next_layer * mid_b_grad if learning_rate is not None:
self.w = self.w - learning_rate * self.w_grad.T
if use_bias == True:
self.b = self.b - learning_rate * self.b_grad
return self.x_grad

  定义Layers 中的Activation类:(这里初始化的时候必须传入一个激活函数,这个激活函数应该是一个类,应该有一个call方法来定义它的前向逻辑,应该有一个grad方法来计算梯度)

class Layers:
  class Activation:
'''
激活层
'''
def __init__(self, activate_func):
'''
传入激活方程类
:param output_category:
'''
self.activate_func = activate_func def __call__(self, Input):
'''
使用魔法方法,实例化对象后,随机的方式初始化w参数,
实例化输入数据,计算本层前向传播方式
:param Input:
:return:
'''
self.Input = Input
       self.activate_func_obj = self.activate_func(self.Input)
result = self.activate_func_obj.call()
self.result = result
return result def backpropagation(self, w_grad_from_next_layer=None, learning_rate=None, ):
'''
反向传播算法的数学描述,公式参考
https://zhuanlan.zhihu.com/p/24863977
公式 Y = f(X) (f是逐元素函数)
dY = df(X)
= f'(X) ⊙ dX (⊙表示出逐元素相乘,也就是通缩意义上的对应位置相乘)
所以
vec(dY) = np.diagflat(f'(X))* vec(dX) :param w_grad_from_next_layer:从下一层传过来的梯度
:param learning_rate:学习率
:return:
''' mid_x_grad = self.activate_func_obj.grad()
self.x_grad = w_grad_from_next_layer * mid_x_grad return self.x_grad

  定义了Activation后,但这个方程需要传入一个激活函数类,现在我们顺从定义一个函数类,用来给激活层提供激活函数类。这个类有两个功能,一是定义正向传播方法,一种是定义梯度计算。

class Funcs:
'''
方程
'''
class Relu:
'''
Relu函数
''' def __init__(self,Input):
self.Input = Input
pass def call(self):
'''
计算结果,并返回
:return:
''' result = np.multiply((self.Input>0),self.Input)
return result def grad(self):
'''
梯度计算
:return:
''' mid_grad = (self.Input>0)*1.0 #乘1 讲bollen类型转化为float类型
result = np.diagflat(mid_grad)
return result

  类似的,我们可以定义更多的种类的激活函数,比如selu,sigmoid等等。到目前为止,如果我们可以定义一个常用的损失函数,那么我们就具备了搭建简单的神经网络的基本要求了。这里我们的定义一个平方差损失函数。

class Funcs:
'''
方程
''' class SqureLossError:
'''
平方误差类
'''
def __init__(self,y,pred):
self.y=y
self.pred = pred def call(self):
'''
计算损失,并返回
:return:
'''
result = np.linalg.norm(self.y-self.pred)
return result def grad(self):
'''
梯度计算
:return:
'''
result = np.mat(2*(self.pred-self.y).T)
return result

  到这里,我们已经具备了搭建神经网络的基本板块了,我们可以用这些基本模块来搭建一个简单的神经网络模型。下一章,我会继续详述一下这个过程。

如何使用numpy实现一个全连接神经网络?(上)的更多相关文章

  1. TensorFlow之DNN(二):全连接神经网络的加速技巧(Xavier初始化、Adam、Batch Norm、学习率衰减与梯度截断)

    在上一篇博客<TensorFlow之DNN(一):构建“裸机版”全连接神经网络>中,我整理了一个用TensorFlow实现的简单全连接神经网络模型,没有运用加速技巧(小批量梯度下降不算哦) ...

  2. TensorFlow之DNN(一):构建“裸机版”全连接神经网络

    博客断更了一周,干啥去了?想做个聊天机器人出来,去看教程了,然后大受打击,哭着回来补TensorFlow和自然语言处理的基础了.本来如意算盘打得挺响,作为一个初学者,直接看项目(不是指MINIST手写 ...

  3. 【TensorFlow/简单网络】MNIST数据集-softmax、全连接神经网络,卷积神经网络模型

    初学tensorflow,参考了以下几篇博客: soft模型 tensorflow构建全连接神经网络 tensorflow构建卷积神经网络 tensorflow构建卷积神经网络 tensorflow构 ...

  4. Tensorflow 多层全连接神经网络

    本节涉及: 身份证问题 单层网络的模型 多层全连接神经网络 激活函数 tanh 身份证问题新模型的代码实现 模型的优化 一.身份证问题 身份证号码是18位的数字[此处暂不考虑字母的情况],身份证倒数第 ...

  5. tensorflow中使用mnist数据集训练全连接神经网络-学习笔记

    tensorflow中使用mnist数据集训练全连接神经网络 ——学习曹健老师“人工智能实践:tensorflow笔记”的学习笔记, 感谢曹老师 前期准备:mnist数据集下载,并存入data目录: ...

  6. 深度学习tensorflow实战笔记(1)全连接神经网络(FCN)训练自己的数据(从txt文件中读取)

    1.准备数据 把数据放进txt文件中(数据量大的话,就写一段程序自己把数据自动的写入txt文件中,任何语言都能实现),数据之间用逗号隔开,最后一列标注数据的标签(用于分类),比如0,1.每一行表示一个 ...

  7. MINIST深度学习识别:python全连接神经网络和pytorch LeNet CNN网络训练实现及比较(三)

    版权声明:本文为博主原创文章,欢迎转载,并请注明出处.联系方式:460356155@qq.com 在前两篇文章MINIST深度学习识别:python全连接神经网络和pytorch LeNet CNN网 ...

  8. tensorflow 添加一个全连接层

    对于一个全连接层,tensorflow都为我们封装好了. 使用:tf.layers.dense() tf.layers.dense( inputs, units, activation=None, u ...

  9. 基于MNIST数据集使用TensorFlow训练一个包含一个隐含层的全连接神经网络

    包含一个隐含层的全连接神经网络结构如下: 包含一个隐含层的神经网络结构图 以MNIST数据集为例,以上结构的神经网络训练如下: #coding=utf-8 from tensorflow.exampl ...

随机推荐

  1. Educational Codeforces Round 77 (Rated for Div. 2) D A game with traps

    题意:x正轴上有着一个陷阱的位置,开关和灵敏度,如果一个士兵灵敏度输给陷阱,他是过不去这个陷阱的幸运的是,你可以先过去把开关给关了,没错你是不怕陷阱的接下来呢你有操作,你移动一个,耗费一秒而你的团队需 ...

  2. Java之Iterator接口(遍历单列集合的迭代器)

    Iterator接口概述 在程序开发中,经常需要遍历集合中的所有元素.针对这种需求,JDK专门提供了一个接口java.util.Iterator . Iterator 接口也是Java集合中的一员,但 ...

  3. doc 如何在指定的位置打印字符和颜色

    编程:在屏幕中间分别显示绿色,绿底红色,白底蓝色的字符串weclome to masm! B8000H~BFFFFH共32KB 的空间,为80*25彩色字符模式的显示缓冲区. 在80*25彩色字符模式 ...

  4. 基于appium的fixture应用之代码重构

    一.痛点分析 在appium自动化中,会话启动参数较多,我们使用了yaml配置文件来进行管理,并使用了PyYaml模块进行yaml文件内容的读取,我们知道,在测试场景中,不可能只会用到一种启动类型的参 ...

  5. Exe4j 打包: this executable was created with an evaluation version of exe4j

    异常 this executable was created with an evaluation version of exe4j   异常.png 问题原因 当前打包使用exe4j未授权 解决方法 ...

  6. cocoscreator查找节点的方法 (跟jquery find一样)

    var each = function(object, callback) { var type = (function() { switch (object.constructor) { case ...

  7. Linux平台安装python的psutil包

    在Linux平台下,pip install psutil 安装python psutil包,出现下面的错误: psutil/_psutil_common.c:9:20: fatal error: Py ...

  8. UTXO和Account模型一个都不能少

    UTXO对于非区块链从业人员来说可能比较陌生,UTXO的全称是Unspent Transaction Output,这中本聪在比特币中的一个天才设计.而Account模型就很常见,也很容易理解,你银行 ...

  9. Java描述设计模式(08):桥接模式

    本文源码:GitHub·点这里 || GitEE·点这里 一.桥接模式简介 1.基础描述 桥梁模式是对象的结构模式.又称为柄体(Handle and Body)模式或接口(Interface)模式.桥 ...

  10. ubuntu18.04 安装 WPS 2019

    ubuntu自带的文字处理软件对来自windows下office或在WPS创建的ppt有点不兼容,看到WPS有linux版本的,便果断安装试一试. 一.卸载原生liboffice sudo apt-g ...