你好!欢迎来到这个系列的第一篇文章,我们将尝试用Python构建自己的深度学习库。在这篇文章中,我们将开始编写一个简单的前馈神经网络。我们将仅在这篇文章中处理前向传播,并在下一篇文章中处理网络的训练。这篇文章将介绍基本的前馈神经网络如何接收输入并从中产生输出。
首先,什么是神经网络?
神经网络是一种机器学习技术,它大致模仿了大脑的模型。和所有机器学习技术一样,它通过包含输入及其对应输出的数据集来学习。神经网络由层组成。每一层都通过权重和偏置与下一层相连。这些权重和偏置被网络用来计算它将给出的输出。在网络训练时,这些权重和偏置会被调整,以便网络根据其训练的数据产生最优输出。
这张图展示了一个三层的神经网络。连接节点的线条用于表示网络的权重和偏置。
它们是如何工作的?(数学原理)
每一层都有自己的权重和偏置。
权重和偏置最初开始时是一个随机值矩阵。
一个基本的前馈神经网络只包含线性层。
线性层使用以下公式产生它们的输出。
x @ w + b
其中...
x 是输入到该层的数据
w 是该层的权重
b 是该层的偏置
(@ 表示矩阵乘法)
每层的输出作为下一层的输入。
注意
如果你不了解矩阵乘法是如何工作的,这个网站很好地解释了这一点。
我们现在只讨论到这里 - 下一篇文章我们将深入研究这些权重和偏置在训练中是如何被纠正的!
激活函数
神经网络的层由节点组成。
激活函数应用于层,以确定哪些节点应该“触发”/“激活”。这种“触发”在人类大脑中也可以观察到,因此在神经网络中引入了激活函数,因为它们大致基于大脑的模型。
激活函数还允许网络模拟非线性数据。没有激活函数,神经网络只会是一个线性回归模型,这意味着它无法模拟大多数现实世界的数据。
有多种激活函数,但以下是最常用的几种…
Sigmoid
Sigmoid函数将输入映射到0到1之间的值,如下图所示。
x是输入向量
Relu(修正线性单元)
Relu函数只允许输入向量的正值通过。负值被映射为0。
例如,
[[-5, 10]
[15, -10] --> relu --> [[0, 10]
[15, 0]]
Tanh
Tanh与Sigmoid类似,不同之处在于它将输入映射到-1到1之间的值。
Softmax
Softmax接收一个输入,并将其映射为概率分布(这意味着输出中的所有值之和为1)。
(z是输入向量,K是输入向量的长度)
编写代码
我们的矩阵操作需要numpy…
import numpy as np
首先,让我们写我们的线性层类
class Linear:
def __init__(self, units):
# units指定层中有多少节点
self.units = units
self.initialized = False
def __call__(self, x):
# 如果层之前没有被调用过,初始化权重和偏置
if not self.initialized:
self.w = np.random.randn(self.input.shape[-1], self.units)
self.b = np.random.randn(self.units)
self.initialized = True
return self.input @ self.w + self.b
示例用法
x = np.array([[0, 1]])
layer = Linear(5)
print (layer(x))
# => [[-2.63399933 -1.18289984 0.32129587 0.2903246 -0.2602642 ]]
现在,让我们按照之前给出的公式编写我们所有的激活函数类
class Sigmoid:
def __call__(self, x):
return 1 / (1 + np.exp(-x))
class Relu:
def __call__(self, x):
return np.maximum(0, x)
class Softmax:
def __call__(self, x):
return np.exp(x) / np.sum(np.exp(x))
class Tanh:
def __call__(self, x):
return np.tanh(x)
现在让我们编写一个“model”类,它将作为我们所有层的容器/实际的神经网络类。
class Model:
def __init__(self, layers):
self.layers = layers
def __call__(self, x):
output = x
for layer in self.layers:
output = layer(x)
return output
将所有这些类保存到layer.py
(或您喜欢的任何名称)中。
现在我们可以使用我们迄今为止的小型库来构建一个简单的神经网络。
import layers
import numpy as np
# 输入数组
x = np.array([[0, 1], [0, 0], [1, 1], [0, 1]])
# 网络使用我们迄今为止设计的所有层
net = layers.Model([
layers.Linear(32),
layers.Sigmoid(),
layers.Linear(16),
layers.Softmax(),
layers.Linear(8),
layers.Tanh(),
layers.Linear(4),
layers.Relu(),
])
print (net(x))
Output:
[[0. 3.87770361 0.17602662 0. ]
[0. 3.85640582 0.22373699 0. ]
[0. 3.77290517 0.2469388 0. ]
[0. 3.87770361 0.17602662 0. ]]