使用Python构建参数化FNN(一)——构建可自定义结构的FNN

提示:转载请注明出处,若本文无意侵犯到您的合法权益,请及时与作者联系。

使用Python构建全连接神经网络(二)——构建可自定义结构的全连接神经网络

一、 神经元与神经层的输出计算

二、 实现一个2*3*1的FNN

三、 实现一个自定义结构的FNN


一、 神经元与神经层的输出计算

单个神经元的角度看,我们输入一个x,它经过自身的权重w偏置b激励函数(以Sigmoid为例)返还一个输出值f(x)=Sigmoid(wx+b)

单个神经层(假设有3个神经元)的角度看,我们输入一个向量x=(x_{1},x_{2}),它经过自身的权重矩阵w=\begin{bmatrix} w_{11} & w_{21} \\ w_{12} & w_{22} \\ w_{13}& w_{23} \end{bmatrix}偏置向量b=(b_{1},b_{2},b_{3})激励函数(以Sigmoid为例)返还一个输出向量f(x)=Sigmoid(wx+b)

在上述描述中,我们使用了向量矩阵的概念,这个和单个神经元的处理原理是相同的,只是向量和矩阵的运算可以同时包含多个神经元。

矩阵本质上就是为了方便解多个线性方程组中而来的,它就是一个数表,没什么特别。例如:

f(x)=Sigmoid(wx+b)=Sigmoid(\begin{bmatrix} w_{11} & w_{21} \\ w_{12} & w_{22} \\ w_{13}& w_{23} \end{bmatrix}*\begin{bmatrix} x_{1} \\ x_{2} \end{bmatrix}+\begin{bmatrix} b_{1} \\ b_{2}\\ b_{3} \end{bmatrix})=Sigmoid(\begin{bmatrix} w_{11}*x_{1} +w_{21}*x_{2} +b_{1} \\ w_{12}*x_{1} +w_{22}*x_{2} +b_{2}\\w_{13}*x_{1} +w_{23}*x_{2} + b_{3} \end{bmatrix})

将上述计算使用Python3工程化后如下:

import numpy as np

# Sigmoid激活函数: f(x) = 1 / (1 + e^(-x))
def Sigmoid(x):
    # 当x是一个向量时,np自动对向量的每一个元素应用Sigmoid函数
    return 1/(1+np.exp(-x))

# 输入向量、权重矩阵、偏置向量
def feedforward(x,weight,biase):
    out = np.dot(weight, x) + biase
    out = Sigmoid(out)
    return out

从上述代码中可知,我们想要计算一个神经层的输出,除了有需要输入向量,还需要指定权重矩阵偏置向量两个参数(本文的激励函数全部默认为Sigmoid)

二、 实现一个2*3*1的FNN

众所周知,在一个神经网络中,具有输入层中间层输出层,其中中间层可以有多个神经层。

我们以一个简单的二层神经网络为例:

使用Python构建参数化FNN(一)——构建可自定义结构的FNN_第1张图片

如果我们想要定义这个神经网络,则需要为两个神经层分别指定它的1个权重矩阵和1个偏置向量,我们可以得到它的一个简单代码:

class Network_V1(object):
    def __init__(self):
        self.n_input = 2 # 输入层的神经元个数
        self.n_l1 = 3 # 中间层的神经元个数
        self.n_l2 = 1 # 输出层的神经元个数
        # 中间层(1个3*2的权重矩阵、1个3*1的偏置向量)
        self.weight_l1 = np.random.randn(self.n_l1,self.n_input)
        self.biase_l1 = np.random.randn(self.n_l1,1)

        # 输出层(1个1*3的权重矩阵、1个1*1的偏置向量)
        self.weight_l2 = np.random.randn(self.n_l2, self.n_l1)
        self.biase_l2 = np.random.randn(self.n_l2,1)

    def feedforward(self,x):
        out = x
        out = AF.Sigmoid(np.dot(self.weight_l1, out) + self.biase_l1)
        out = AF.Sigmoid(np.dot(self.weight_l2, out) + self.biase_l2)
        return out

三、 实现一个自定义结构的FNN

上述的代码是针对该2*3*1的网络结构的,我们考虑将上述代码修改成可以自定义层数,且每层的神经元个数也可以自定义的神经网络:

class Network_V2(object):
    def __init__(self,shape_size):
        """shape_size是一个包含有各层神经元数量的列表"""
        self.num_layers = len(shape_size) # 神经层的数量(输入层+中间层+输出层)
        self.shape_size = shape_size # 包含有各层神经元数量的列表
        # 多个权重矩阵的列表,例如weights[0]表示第一层和第二层之间的权重矩阵(行数为第二层神经元数,列数为第一层神经元数)
        self.weights = [np.random.randn(y,x) for x,y in zip(shape_size[:-1],shape_size[1:])]
        # 多个偏置向量的列表,第一层(输入层)没有偏置,所以biases[0]存储的是第二层的偏置参数列表(长度为第二层神经元数)
        self.biases = [np.random.randn(y,1) for y in shape_size[1:]]

    def feedforward(self,x):
        """输入一个多维向量,输出网络的输出"""
        #out = x
        for w,b in zip(self.weights,self.biases):
            x = AF.Sigmoid(np.dot(w,x)+b)
        return x

在上述代码中我们使用了一个shape_size的列表来表示神经元各层数量,这样做的原因是,神经网络的层数可以自定义,意味着传入的参数数量不确定,使用列表作为这个整体参数比较合适。

假如我们想要构建一个2*3*1的神经网络,我们就为它传入一个[2,3,1]的参数。

程序得到这个[2,3,1]的参数后就可以各个层的权重矩阵和偏置矩阵的参数信息,从而进行初始化。

例如这个[2,3,1]参数,程序可以得到需要生成分别为(3,2)、(1,3)的2个权重矩阵、分为为(3,1)、(1,1)的2个偏置向量。

 

测试本次迭代优化的正确性,使用如下代码测试:

测试结果如下,表示迭代没有问题:

使用Python构建参数化FNN(一)——构建可自定义结构的FNN_第2张图片

 

你可能感兴趣的:(机器学习之深度学习,python,神经网络,深度学习)