代码改变世界

[译]深度学习中所需的线性代数知识

2018-06-08 09:47  Fururur  阅读(2362)  评论(0编辑  收藏  举报

每个深度学习项目背后的数学知识。

深度学习是机器学习的一个子领域,涉及一些模仿人脑结构和功能的人工神经网络算法。

线性代数是一种连续的而非离散的数学形式,许多计算机科学家对它几乎没有经验。对于理解和使用许多机器学习算法,特别是深度学习算法,理解线性代数是非常重要的。

为什么是数学?

线性代数,概率论和微积分是组成机器学习的三种“语言”。学习这些数学知识将有助于深入理解底层算法机制,并且开发新的算法。

当我们深入到底层时,深度学习背后的一切都是数学。因此在学习深度学习和编程之前,理解基本的线性代数知识是至关重要的。

源码

深度学习背后的核心数据结构是标量,矢量,矩阵和张量。让我们使用这些数据结构,通过编程的方式来解决所有基本的线性代数问题。

标量

标量是单个数字,也可以视为 0 阶张量。符号 x∈ℝ 表示 x 是一个标量,属于一组实数值 ℝ。

以下是深度学习中不同数集的表示。ℕ 表示正整数集合 (1,2,3,…)。ℤ 表示结合了正值,负值和零值的整数集合。ℚ 表示有理数集合。

在 Python 中有一些内置的标量类型,intfloatcomplexbytes and Unicode。在 Numpy(一个 Python 库)中,有 24 种新的基本数据类型来描述不同类型的标量。有关数据类型的信息,请参阅 文档

在 Python 中定义标量和相关操作:

下面的代码段解释了一些运算运算符在标量中的应用。

# 内置标量
a = 5
b = 7.5
print(type(a))
print(type(b))
print(a + b)
print(a - b)
print(a * b)
print(a / b)
<class 'int'>
<class 'float'>
12.5
-2.5
37.5
0.6666666666666666

下面的代码段可以检查给出的变量是否为标量。

import numpy as np

# 判断是否为标量的函数
def isscalar(num):
    if isinstance(num, generic):
        return True
    else:
        return False

print(np.isscalar(3.1))
print(np.isscalar([3.1]))
print(np.isscalar(False))
True
False
True

向量

向量是单数的有序数组,是一阶张量的例子。向量是被称为矢量空间的对象的片段。向量空间可以被认为是特定长度(或维度)的所有可能向量的整个集合。用 ℝ^3 表示的三维实值向量空间,通常用于从数学角度表示我们对三维空间的现实世界概念。

为了明确地定位到矢量的某个分量,矢量的第 i 个标量元素被写为 x[i]。

在深度学习中,向量通常代表特征向量,其原始组成部分定义了具体特征的相关性。这些元素可以包括二维图像中一组像素的强度的相关重要性或者各种金融工具的历史价格值。

在 Python 中定义向量和相关操作:

import numpy as np

# 定义向量

x = [1, 2, 3]
y = [4, 5, 6]

print(type(x))

# 这样做不会得到向量和
print(x + y)

# 使用 Numpy 进行向量相加

z = np.add(x, y)
print(z)
print(type(z))

# 向量叉乘
mul = np.cross(x, y)
print(mul)
<class 'list'>
[1, 2, 3, 4, 5, 6]
[5 7 9]
<class 'numpy.ndarray'>
[-3  6 -3]

矩阵

矩阵是由数字组成的矩形阵列,是 2 阶张量的一个例子。如果 m 和 n 是正整数,即 m,n∈ℕ,则 m×n 矩阵包含 m*n 个数字,m 行 n 列。

完整的 m×n 矩阵可写为:

将全矩阵显示简写为以下表达式通常很有用:

在 Python 中,我们使用 Numpy 库来帮助我们创建 N 维数组。数组基本上可看做矩阵,我们使用矩阵方法,并通过列表来构造一个矩阵。

$python

>>> import numpy as np
>>> x = np.matrix([[1,2],[2,3]])
>>> x
matrix([[1, 2],
        [2, 3]])

>>> a = x.mean(0)
>>> a
matrix([[1.5, 2.5]])
>>> # 对矩阵求均值。(其中 axis 不设置值,对 m*n 个数求均值,返回一个实数;axis = 0:压缩行,对各列求均值,返回 1* n 矩阵;axis =1 :压缩列,对各行求均值,返回 m *1 矩阵)。
>>> z = x.mean(1)
>>> z
matrix([[1.5],
        [2.5]])
>>> z.shape
(2, 1)
>>> y = x - z
matrix([[-0.5,  0.5],
        [-0.5,  0.5]])
>>> print(type(z))
<class 'numpy.matrixlib.defmatrix.matrix'>

在 Python 中定义矩阵和相关操作:

矩阵加法

矩阵可以与标量、向量和其他矩阵进行加法运算。每个操作都有精确的定义。这些技术经常用于机器学习和深度学习,所以值得花时间去熟悉它们。

# 矩阵加法

import numpy as np

x = np.matrix([[1, 2], [4, 3]])

sum = x.sum()
print(sum)
# Output: 10

矩阵与矩阵相加

C = A + B (**A 与 B 的维度需要相同 **)

shape 方法返回矩阵的维度,add 方法接受两个矩阵参数并返回这两个矩阵的和。如果两个矩阵的维度不一致 add 方法将会抛出一个异常,说无法将其相加。

# 矩阵与矩阵相加

import numpy as np

x = np.matrix([[1, 2], [4, 3]])
y = np.matrix([[3, 4], [3, 10]])

print(x.shape)
# (2, 2)
print(y.shape)
# (2, 2)

m_sum = np.add(x, y)
print(m_sum)
print(m_sum.shape)
"""
Output :
[[4  6]
 [7 13]]
(2, 2)
"""

矩阵与标量相加

将给定的标量添加到给定矩阵中的所有元素。

# 矩阵与标量相加

import numpy as np

x = np.matrix([[1, 2], [4, 3]])
s_sum = x + 1
print(s_sum)
"""
Output:
[[2 3]
 [5 4]]
"""

矩阵与标量的乘法

将给定的标量乘以给定矩阵中的所有元素。

# 矩阵与标量的乘法

import numpy as np

x = np.matrix([[1, 2], [4, 3]])
s_mul = x * 3
print(s_mul)
"""
[[3  6]
 [12  9]]
"""

矩阵乘法

维度为(m x n)的矩阵 A 和维度为(n x p)的矩阵 B 相乘,最终得到维度为(m x p)的矩阵 C。

源码

# 矩阵乘法

import numpy as np

a = [[1, 0], [0, 1]]
b = [1, 2]
np.matmul(a, b)
# Output: array([1, 2])

complex_mul = np.matmul([2j, 3j], [2j, 3j])
print(complex_mul)
# Output: (-13+0j)

矩阵转置

通过转置,您可以将行向量转换为列向量,反之亦然:

A=[a_ij_]mxn

AT=[a_ji_]n×m


# 矩阵转置

import numpy as np

a = np.array([[1, 2], [3, 4]])
print(a)
"""
[[1 2]
 [3 4]]
"""
a.transpose()
print(a)
"""
array([[1, 3],
       [2, 4]])
"""

张量

更加泛化的实体 —— 张量,封装了标量、矢量和矩阵。在物理科学和机器学习中,有时需要使用超过两个顺序的张量。

源码

我们使用像 TensorFlow 或 PyTorch 这样的 Python 库来声明张量,而不是使用嵌套矩阵来表示。

在 PyTorch 中定义一个简单的张量:


import torch

a = torch.Tensor([26])

print(type(a))
# <class 'torch.FloatTensor'>

print(a.shape)
# torch.Size([1])

# 创建一个 5*3 的随机 torch 变量。
t = torch.Tensor(5, 3)
print(t)
"""
 0.0000e+00  0.0000e+00  0.0000e+00
 0.0000e+00  7.0065e-45  1.1614e-41
 0.0000e+00  2.2369e+08  0.0000e+00
 0.0000e+00  0.0000e+00  0.0000e+00
        nan         nan -1.4469e+35
[torch.FloatTensor of size 5x3]
"""
print(t.shape)
# torch.Size([5, 3])

Python 中张量的运算操作:

import torch

# 创建张量

p = torch.Tensor(4,4)
q = torch.Tensor(4,4)
ones = torch.ones(4,4)

print(p, q, ones)
"""
Output:
 0.0000e+00  0.0000e+00  0.0000e+00  0.0000e+00
 1.6009e-19  4.4721e+21  6.2625e+22  4.7428e+30
 3.1921e-09  8.0221e+17  5.1019e-08  8.1121e+17
 8.1631e-07  8.2022e+17  1.1703e-19  1.5637e-01
[torch.FloatTensor of size 4x4]

 0.0000e+00  0.0000e+00  0.0000e+00  0.0000e+00
 1.8217e-44  1.1614e-41  0.0000e+00  2.2369e+08
 0.0000e+00  0.0000e+00  2.0376e-40  2.0376e-40
        nan         nan -5.3105e+37         nan
[torch.FloatTensor of size 4x4]

 1  1  1  1
 1  1  1  1
 1  1  1  1
 1  1  1  1
[torch.FloatTensor of size 4x4]
"""

print("Addition:{}".format(p + q))
print("Subtraction:{}".format(p - ones))
print("Multiplication:{}".format(p * ones))
print("Division:{}".format(q / ones))

"""
Addition:
 0.0000e+00  0.0000e+00  0.0000e+00  0.0000e+00
 1.6009e-19  4.4721e+21  6.2625e+22  4.7428e+30
 3.1921e-09  8.0221e+17  5.1019e-08  8.1121e+17
        nan         nan -5.3105e+37         nan
[torch.FloatTensor of size 4x4]
Subtraction:
-1.0000e+00 -1.0000e+00 -1.0000e+00 -1.0000e+00
-1.0000e+00  4.4721e+21  6.2625e+22  4.7428e+30
-1.0000e+00  8.0221e+17 -1.0000e+00  8.1121e+17
-1.0000e+00  8.2022e+17 -1.0000e+00 -8.4363e-01
[torch.FloatTensor of size 4x4]
Multiplication:
 0.0000e+00  0.0000e+00  0.0000e+00  0.0000e+00
 1.6009e-19  4.4721e+21  6.2625e+22  4.7428e+30
 3.1921e-09  8.0221e+17  5.1019e-08  8.1121e+17
 8.1631e-07  8.2022e+17  1.1703e-19  1.5637e-01
[torch.FloatTensor of size 4x4]
Division:
 0.0000e+00  0.0000e+00  0.0000e+00  0.0000e+00
 1.8217e-44  1.1614e-41  0.0000e+00  2.2369e+08
 0.0000e+00  0.0000e+00  2.0376e-40  2.0376e-40
        nan         nan -5.3105e+37         nan
[torch.FloatTensor of size 4x4]
"""

有关张量和 PyTorch 的更多文档点击这里


** 重要的链接 **

在 Python 中入门深度学习:

结束语

感谢阅读。如果你发现这个故事很有用,请点击下面的 👏 来传播爱心。

特别鸣谢 Samhita Alla 对本文的贡献。