3.深度学习入门:多维数组的运算 多维数组 矩阵乘法 神经网络的内积 层神经网络的实现 符号确认 各层间信号传递的实现
多维数组的运算
多维数组
在深度学习中,多维数组是非常重要的数据结构。通常,我们使用 numpy 库来处理多维数组。以下是一些基本的 numpy 操作:
创建一个数组:
import numpy as np
a = np.array([1, 2, 3]) # 一维数组
b = np.array([[1, 2, 3], [4, 5, 6]]) # 二维数组
c = np.array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]]) # 三维数组
获取数组的形状:
print(a.shape) # 输出 (3,)
print(b.shape) # 输出 (2, 3)
print(c.shape) # 输出 (2, 2, 2)
获取数组的元素个数:
print(a.size) # 输出 3
print(b.size) # 输出 6
print(c.size) # 输出 8
获取数组的数据类型:
print(a.dtype) # 输出 int64
print(b.dtype) # 输出 int64
print(c.dtype) # 输出 int64
改变数组的形状:
d = np.array([1, 2, 3, 4, 5, 6])
d = d.reshape((2, 3)) # 将一维数组转换为二维数组
print(d) # 输出 [[1 2 3] [4 5 6]]
数组的索引和切片:
print(a[0]) # 输出 1
print(b[0, 1]) # 输出 2
print(c[1, 0, 1]) # 输出 6
print(a[:2]) # 输出 [1 2]
print(b[1, :2]) # 输出 [4 5]
print(c[0, :, 1]) # 输出 [2 4]
这些是 numpy中基本的多维数组操作,深度学习中的神经网络模型也是基于多维数组进行计算的。因此,深入理解多维数组的操作和特性是非常重要的。
矩阵乘法
- 矩阵乘法是线性代数中的一种基本运算,也是深度学习中常用的运算。在深度学习中,矩阵乘法通常用于计算神经网络中的前向传播和反向传播。
- 假设有两个矩阵 A 和 B,它们的形状分别为 (m, n) 和 (n, p),其中 m、n、p 分别表示矩阵的行数和列数。那么矩阵 A和矩阵 B 的乘积 C 的形状为 (m, p)。
矩阵乘法的计算方式如下:
C
i
,
j
=
∑
k
=
1
n
A
i
,
k
×
B
k
,
j
C_{i,j} = \sum_{k=1}^{n} A_{i,k} \times B_{k,j}
Ci,j=k=1∑nAi,k×Bk,j
其中, C i , j C_{i,j} Ci,j 表示矩阵 C 在第 i i i 行、第 j j j 列的元素, A i , k A_{i,k} Ai,k 表示矩阵 A 在第 i i i 行、第
k k k 列的元素, B k , j B_{k,j} Bk,j 表示矩阵 B 在第 k k k 行、第 j j j 列的元素。
在 Python 中,可以使用 numpy 库来进行矩阵乘法的计算。代码如下:
import numpy as np
A = np.array([[1, 2], [3, 4], [5, 6]]) # 形状为 (3, 2) 的矩阵
B = np.array([[7, 8, 9], [10, 11, 12]]) # 形状为 (2, 3) 的矩阵
C = np.dot(A, B) # 矩阵乘法,结果为形状为 (3, 3) 的矩阵
print(C)
输出结果为:
[[ 27 30 33]
[ 61 68 75]
[ 95 106 117]]
其中,np.dot 函数表示矩阵乘法。
神经网络的内积
神经网络中的内积,也称为点积,是指两个向量的对应元素相乘后相加的结果。在神经网络中,内积通常用于计算神经元之间的连接权重和输入信号的乘积之和。
假设有两个向量
x
x
x 和
y
y
y,它们的长度相同,即都有
n
n
n 个元素。那么它们的内积可以表示为:
x
⋅
y
=
∑
i
=
1
n
x
i
y
i
x \cdot y = \sum_{i=1}^{n} x_i y_i
x⋅y=i=1∑nxiyi
在神经网络中,内积通常用于计算神经元之间的连接权重和输入信号的乘积之和,可以表示为:
z
=
∑
i
=
1
n
w
i
x
i
+
b
z = \sum_{i=1}^{n} w_i x_i + b
z=i=1∑nwixi+b
其中,
w
i
w_i
wi 表示连接权重,
x
i
x_i
xi 表示输入信号,
b
b
b 表示偏置。
在 Python 中,可以使用 numpy 库来计算两个向量的内积。代码如下:
import numpy as np
x = np.array([1, 2, 3])
y = np.array([4, 5, 6])
z = np.dot(x, y) # 计算内积
print(z) # 输出 32
在神经网络中,可以使用 numpy 库来计算神经元之间的内积。代码如下:
import numpy as np
x = np.array([1, 2, 3])
w = np.array([0.1, 0.2, 0.3])
b = 0.4
z = np.dot(w, x) + b # 计算神经元之间的内积
print(z) # 输出 1.2
其中, x x x 表示输入信号, w w w 表示连接权重, b b b 表示偏置, z z z 表示神经元之间的内积。
层神经网络的实现
符号确认
在实现一个层神经网络之前,需要确认一些符号的含义:
- 输入层:输入层是神经网络的第一层,用于接收输入数据。输入层通常表示为 x x x。
- 隐藏层:隐藏层是在输入层和输出层之间的一层或多层,用于对输入数据进行加工和转换。隐藏层通常表示为 h h h。
- 输出层:输出层是神经网络的最后一层,用于输出神经网络的预测结果。输出层通常表示为 y y y。
- 权重:权重是神经元之间的连接强度,用于计算神经元之间的内积。权重通常表示为 w w w。
- 偏置:偏置是神经元的激活阈值,用于调整神经元的输出值。偏置通常表示为
b
b
b。
激活函数:激活函数是神经元的非线性变换,用于增强神经网络的表达能力。激活函数通常表示为 σ \sigma σ。
各层间信号传递的实现
层神经网络的实现通常需要实现各层之间信号传递的过程,包括前向传播和反向传播。下面是一个简单的层神经网络的实现,包括输入层、隐藏层和输出层。
首先,需要导入 numpy 库,用于实现矩阵乘法和激活函数等操作。
import numpy as np
然后,定义一个 NeuralNetwork 类,用于实现层神经网络。该类包括以下方法:
init:初始化神经网络,包括输入层、隐藏层和输出层的大小、权重和偏置。
sigmoid:sigmoid 激活函数,用于增强神经网络的表达能力。
sigmoid_derivative:sigmoid 激活函数的导数,用于反向传播时计算梯度。
feedforward:前向传播,用于将输入信号传递到输出层。
backpropagation:反向传播,用于计算损失函数的梯度并更新权重和偏置。
train:训练神经网络,包括多次迭代前向传播和反向传播。
predict:预测输出结果。
代码如下:
class NeuralNetwork:
# 初始化神经网络
def __init__(self, X, y, hidden_size):
# 输入层大小为 X 的列数
self.input_size = X.shape[1]
# 输出层大小为 y 的列数
self.output_size = y.shape[1]
# 隐藏层大小
self.hidden_size = hidden_size
# 权重
self.weights1 = np.random.randn(self.input_size, self.hidden_size)
self.weights2 = np.random.randn(self.hidden_size, self.output_size)
# 偏置
self.bias1 = np.zeros((1, self.hidden_size))
self.bias2 = np.zeros((1, self.output_size))
<span class="hljs-comment"># sigmoid 激活函数</span>
<span class="hljs-keyword">def</span> <span class="hljs-function">sigmoid</span><span class="hljs-params">(self, z)</span>:
return <span class="hljs-number">1</span> / ( <span class="hljs-number">1</span> + np.exp(-z))
<span class="hljs-comment"># sigmoid 激活函数的导数</span>
<span class="hljs-keyword">def</span> <span class="hljs-function">sigmoid_derivative</span><span class="hljs-params">(self, z)</span>:
return self.sigmoid(z) * ( <span class="hljs-number">1</span> - self.sigmoid(z))
<span class="hljs-comment"># 前向传播</span>
<span class="hljs-keyword">def</span> <span class="hljs-function">feedforward</span><span class="hljs-params">(self, X)</span>:
<span class="hljs-comment"># 输入层到隐藏层的信号传递</span>
self.z1 = np.dot(X, self.weights1) + self.bias1
self.a1 = self.sigmoid(self.z1)
<span class="hljs-comment"># 隐藏层到输出层的信号传递</span>
self.z2 = np.dot(self.a1, self.weights2) + self.bias2
self.a2 = self.sigmoid(self.z2)
<span class="hljs-comment"># 返回输出层的结果</span>
<span class="hljs-keyword">return</span> self.a2
<span class="hljs-comment"># 反向传播</span>
<span class="hljs-keyword">def</span> <span class="hljs-function">backpropagation</span><span class="hljs-params">(self, X, y, output)</span>:
<span class="hljs-comment"># 计算输出层的误差</span>
self.output_error = y - output
<span class="hljs-comment"># 计算输出层的梯度</span>
self.output_delta = self.output_error * self.sigmoid_derivative(self.z2)
<span class="hljs-comment"># 计算隐藏层的误差</span>
self.hidden_error = self.output_delta.dot(self.weights2.T)
<span class="hljs-comment"># 计算隐藏层的梯度</span>
self.hidden_delta = self.hidden_error * self.sigmoid_derivative(self.z1)
<span class="hljs-comment"># 更新权重和偏置</span>
self.weights1 += X.T.dot(self.hidden_delta)
self.weights2 += self.a1.T.dot(self.output_delta)
self.bias1 += np.sum(self.hidden_delta, axis=<span class="hljs-number">0</span>, keepdims=<span class="hljs-literal">True</span>)
self.bias2 += np.sum(self.output_delta, axis=<span class="hljs-number">0</span>, keepdims=<span class="hljs-literal">True</span>)
<span class="hljs-comment"># 训练神经网络</span>
<span class="hljs-keyword">def</span> <span class="hljs-function">train</span><span class="hljs-params">(self, X, y, epochs)</span>:
<span class="hljs-keyword">for</span> epoch <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(epochs):
output = self.feedforward(X)
self.backpropagation(X, y, output)
<span class="hljs-comment"># 预测输出结果</span>
<span class="hljs-keyword">def</span> <span class="hljs-function">predict</span><span class="hljs-params">(self, X)</span>:
<span class="hljs-keyword">return</span> self.feedforward(X)
在实现层神经网络的过程中,需要注意以下几点:
- 初始化权重时,可以使用随机数来初始化,以避免权重的初始值对神经网络的训练产生影响。
- 在前向传播中,需要对输入信号进行加权和加偏置,并经过激活函数进行非线性变换。
- 在反向传播中,需要计算损失函数的梯度,并根据梯度来更新权重和偏置。
- 在训练神经网络时,需要进行多次迭代,每次迭代都包括前向传播和反向传播。