本文收录于 《如何实现一个的神经网络》专栏。从零开始,介绍如何开发实现一个的神经网络。
以分类和回归问题为例,由浅入深,依次介绍了神经元、隐藏层、激活函数、损失值、自动微分、模型优化等等内容,最终对实现好的神经网络进行封装,提供给用户可调用的接口。
相信完整学习后会有很多收获。欢迎关注,谢谢!
文章目录
一、概述
人的大脑神经元数量级为10的11次方大约1000亿个,每个神经元又通过神经突触与大约1000个其它神经元相连,形成一个高度复杂高度灵活的动态网络。
人工神经网络的灵感来源于人类的大脑,这样进行比较并不完美,但是其中有很多相似的地方。
人工神经网络的主要任务是根据生物神经网络的原理和实际应用的需要建造实用的人工神经网络模型,设计相应的学习算法,模拟人脑的某种智能活动,然后在技术上实现出来用以解决实际问题。
经过研究发现,单个神经元本身相对无用,但当与数百或数千(或更多)个其他神经元结合时,这种互连性产生的关系和结果往往优于任何其他机器学习方法。
二、组成部分
对于一个简单的神经网络,可以分为输入(input)、输出(output)和一个用于运算的单元,这个单元包含权重(weight)和偏差(bias)两个重要部分。权重和偏差的概念可以被认为是"旋钮",我们可以调整它以使我们的模型与数据相匹配。
在神经网络中,我们通常在训练过程中由优化器调整数千甚至数百万个这些参数。
偏差和权重两者都是可调的参数,两者都会影响神经元的输出,但它们的作用方式不同。
由于权重是相乘的,它们只会改变幅度,甚至完全将符号从正翻转为负,反之亦然。
三、计算方式
最简单的一种情况是和一元一次函数结合起来,对于函数y=mx+by =m**x +b,x和y分别表示输入和输出,m和b分别表示参数和偏差。若m=1.0、b=2.0,即参数部分为1.0,偏差数据为2.0时,可以绘制出如下函数图像:
输入和输出数据一般不会只有一个,所以有一个更一般的公式:
outputs=(∑inputs×weights)+bias
用神经网络实际处理的问题通常是非常复杂、非线性的,因此通常要引入激活函数。激活函数会在后续详细介绍。
outputs=activation((∑inputs×weights)+bias)
在对神经元及其运算方式有了足够的了解后,可以构建简单的神经网络。假设有两个隐藏层,每层4个神经元,神经网络如图所示。
一个典型的神经网络有数千个甚至数百万个可调整的参数(权重和偏差)。
通过这种方式,神经网络充当具有大量参数的巨大函数。
有了这么多与神经元相关的变量,排列成相互连接的层,我们可以想象这些变量存在一些值的组合,这些值将产生所需的输出。找到参数(权重和偏差)值的组合是具有挑战性的部分。
神经网络的最终目标是调整其权重和偏差(参数),因此当应用于输入中尚未看到的示例时,它们会产生所需的输出。
当训练有监督的机器学习算法时,我们展示了输入及其相关期望输出的算法示例。
这个概念的一个主要问题是过拟合------当该算法只学习拟合训练数据,但实际上并没有"理解"任何关于潜在输入输出依赖性的信息。网络基本上只是"记忆"训练数据。
四、编写代码简单神经元实现
设想一种很简单的情况,即该神经网络只有一个神经元。其中,inputs和weights均为3维的列表。
例如:
python
inputs = [1, 2, 3]
weights = [0.2, 0.8, -0.5]
bias = 2
output = (inputs[0] * weights[0] + inputs[1] * weights[1] + inputs[2] * weights[2] + bias)
print(output)
#输出:2.3
以上例子使用for循环方式优化后如下:
python
inputs = [1, 2, 3]
weights = [0.2, 0.8, -0.5]
bias = 2
output = 0.0
for i, _ in enumerate(inputs):
output += weights[i] * inputs[i]
output += bias
print(output)
#输出:2.3
假设有三个神经元,并且引入三个权重和三个偏差,代码示例如下:
python
inputs = [1, 2, 3, 2.5]
weights1 = [0.2, 0.8, -0.5, 1]
weights2 = [0.5, -0.91, 0.26, -0.5]
weights3 = [-0.26, -0.27, 0.17, 0.87]
bias1 = 2
bias2 = 3
bias3 = 0.5
outputs = [
# Neuron 1:
inputs[0] * weights1[0] + inputs[1] * weights1[1] + inputs[2] * weights1[2] + inputs[3] * weights1[3] + bias1,
# Neuron 2:
inputs[0] * weights2[0] + inputs[1] * weights2[1] + inputs[2] * weights2[2] + inputs[3] * weights2[3] + bias2,
# Neuron 3:
inputs[0] * weights3[0] + inputs[1] * weights3[1] + inputs[2] * weights3[2] + inputs[3] * weights3[3] + bias3]
print(outputs)
# 输出 [4.8, 1.21, 2.385]
以上例子使用for循环方式优化后如下:
python
inputs = [1, 2, 3, 2.5]
weights = [[0.2, 0.8, -0.5, 1],
[0.5, -0.91, 0.26, -0.5],
[-0.26, -0.27, 0.17, 0.87]]
biases = [2, 3, 0.5]
# Output of current layer
layer_outputs = []
# For each neuron
for neuron_weights, neuron_bias in zip(weights, biases):
# Zeroed output of given neuron
neuron_output = 0
# For each input and weight to the neuron
for n_input, weight in zip(inputs, neuron_weights):
# Multiply this input by associated weight and add to the neuron's output variable
neuron_output += (n_input * weight)
# Add bias
neuron_output += neuron_bias
# Put neuron's result to the layer's output list
layer_outputs.append(neuron_output)
print(layer_outputs)
# 输出 [4.8, 1.21, 2.385]
在以上示例中,只有三个神经元,引入了三个权重和三个偏差。后面随着学习的深入,神经元的数量会增多。
五、向量、数组和张量
为了后面学习的开展,需要引入三个概念,向量(Vector)、数组(Array)以及张量(Tensor)。
-
向量:向量是一维数组或数字列表,通常表示为列或行矩阵。它包含具有大小和方向的元素。向量广泛应用于数学、物理和计算机科学领域。它们描述了位移、速度和力等量。向量可以进行加法、减法、标量乘法,以及点积或叉积等数学运算。
-
数组:数组是一组存储在连续内存块中的元素,每个元素通过索引或键来标识。它可以有一个或多个维度,例如一维(向量)、二维(矩阵)或多维数组。数组通常用于存储和操作同质数据类型,例如数字或字符。它们通过索引提供高效的随机访问,并支持排序、搜索和逐元素计算等操作。
-
张量:张量是将向量和矩阵推广到更高维度的数学对象。它可以被定义为一个包含数字的n维数组,其中n表示张量的阶或秩。张量在物理、工程和机器学习等各个领域中被使用。在机器学习中,张量用于表示和操作多维数据,例如图像、视频和时间序列。张量可以有效地处理高维数据,包括变换、卷积和其他数学运算。
最后总结一下,关于向量、数组和张量,在不同领域中有不同的习惯和规范。学习过程中无需过分追求张量和向量的区别。在很多机器学习框架上,神经网络中传递的数据均被视作张量。
六、基于NumPy的简单神经元实现
简单神经元实现(一)
NumPy(Numerical Python)是一个用于进行科学计算的Python库,其中提供了一个重要的对象:ndarray(N-dimensional array)。
ndarray是NumPy中用于表示多维数组的数据结构。使用ndarray对象,我们可以进行各种数组操作,如索引和切片、形状操作、数学运算、统计分析等。
该对象在科学计算、数据分析和机器学习等领域中得到广泛应用,因为它提供了高效的、基于数组的数据操作。
接下来借助NumPy对神经元进行重写。
代码如下:
python
import numpy as np
inputs = [1.0, 2.0, 3.0, 2.5]
weights = [[0.2, 0.8, -0.5, 1],
[0.5, -0.91, 0.26, -0.5],
[-0.26, -0.27, 0.17, 0.87]]
biases = [2.0, 3.0, 0.5]
layer_outputs = np.dot(weights, inputs) + biases
print(layer_outputs)
#输出 [4.8 1.21 2.385]
简单神经元实现(二)
在训练过程中,神经网络接受的是成批(batch)的数据。而在前面的例子中,输入只是有多个特征(feature)的单个样本。
接下来,看一下多个样本的情况,这里,需要先了解一下矩阵乘积运算。
我们需要对由输入矩阵和权重矩阵组成的所有向量执行点积,这就是矩阵乘积的运算。
其中,矩阵乘积运算的定义如下:
下面看一下示例,在上面示例的基础上,输入样本数量增加为3个。如下:
python
import numpy as np
inputs = np.array([[1.0, 2.0, 3.0, 2.5],
[2.0, 5.0, -1.0, 2.0],
[-1.5, 2.7, 3.3, -0.8]])
weights = np.array([[0.2, 0.8, -0.5, 1.0],
[0.5, -0.91, 0.26, -0.5],
[-0.26, -0.27, 0.17, 0.87]])
biases = np.array([2.0, 3.0, 0.5])
outputs = np.dot(inputs, weights.T) + biases
print(outputs)
#输出
[[ 4.8 1.21 2.385]
[ 8.9 -1.81 0.2 ]
[ 1.41 1.051 0.026]]
首先,我们只需要对它的第二个参数(在我们的例子中是权重矩阵)进行转置,将它当前包含的行向量转换为列向量。
转置前如下:
转置后如下:
之后,进行矩阵乘积运算,过程如下:
本文内容参考来源于百度飞桨AI社区。如果您对文章中内容有疑问,欢迎在评论区进行留言,我会尽量抽时间给您回复。如果文章对您有帮助,欢迎点赞、收藏。您的点赞,是对我最大的支持和鼓励,谢谢 :-)