为什么重新开始学习线性代数?

从小数学就比较一般,一直不太喜欢数学。2015年,我大学一年级,线性代数成了我数学课的"开门红"。说实话,那会儿我完全懵了,满脑子都是问号:这矩阵算来算去到底有啥用?为啥非得折腾这些数字方块?考试前拼命刷题,考完试立马把书扔一边,心里还嘀咕着"这辈子估计用不上了"。

可谁能想到,十年后的今天,我居然又翻开了线性代数的课本,而且这次是心甘情愿的!为什么?因为 AI 火了,而我发现,当年那些让我头大的矩阵运算,现在居然成了理解人工智能的"基本功"。从机器学习到图像识别,从神经网络到数据降维,线性代数无处不在。

矩阵运算基础

你可以把矩阵想象成一个数据表格,每一行代表一个样本,每一列代表一个特征。比如,你想训练一个 AI 识别猫和狗,矩阵里的数据可能就是一堆猫狗图片的像素值。

深度学习的过程,本质上就是对这些矩阵进行各种加减乘除、变形和组合,最终让 AI 学会从数据中提取规律。神经网络里的每一层都在做矩阵乘法,通过调整矩阵里的参数(也就是权重),AI 就能慢慢学会区分猫和狗。

使用 NumPy 进行矩阵运算

在实际应用中,我们通常使用 NumPy 这个强大的库来实现矩阵运算,无需手动进行计算。

环境准备

安装 NumPy:

pip3 install numpy

导入 NumPy 模块:

import numpy as np

创建矩阵:

matrix1 = np.array([[1, 2], [3, 4]])

矩阵相加

矩阵相加要求两个矩阵的维度完全相同(行数和列数都相等)。

matrix1 = np.array([[1, 2], [3, 4]])  # 2x2 矩阵
matrix2 = np.array([[5, 6], [7, 8]])  # 2x2 矩阵
result = matrix1 + matrix2
print(result)
# 输出: [[ 6  8]
#       [10 12]]

应用场景: 矩阵相加是机器学习中的基本操作之一,广泛应用于特征工程、模型训练、深度学习、数据增强等领域。

矩阵相减

矩阵相减同样要求两个矩阵的维度完全相同。

matrix1 = np.array([[1, 2], [3, 4]])
matrix2 = np.array([[5, 6], [7, 8]])
result = matrix1 - matrix2
print(result)
# 输出: [[-4 -4]
#       [-4 -4]]

应用场景: 矩阵相减在机器学习中主要用于计算差异、误差、残差等,是优化模型、分析数据和实现特定任务(如图像处理、异常检测)的重要工具。

矩阵转置

矩阵转置是线性代数中的一个基本操作,它将矩阵的行和列互换。可以理解为将矩阵沿着主对角线进行翻转。

matrix1 = np.array([[1, 2, 3], [4, 5, 6]])  # 2x3 矩阵
print("原矩阵:")
print(matrix1)

# 方法1:使用 .T 属性
matrix1T = matrix1.T
print("转置矩阵(方法1):")
print(matrix1T)

# 方法2:使用 transpose() 函数
matrix1T = np.transpose(matrix1)
print("转置矩阵(方法2):")
print(matrix1T)
# 输出: [[1 4]
#       [2 5]
#       [3 6]]  # 3x2 矩阵

矩阵相乘

矩阵相乘要求第一个矩阵的列数必须等于第二个矩阵的行数。结果矩阵的行数等于第一个矩阵的行数,列数等于第二个矩阵的列数。

matrix1 = np.array([[1, 2], [3, 4], [5, 6]])  # 3x2 矩阵
matrix2 = np.array([[7, 8], [9, 10]])  # 2x2 矩阵

print("matrix1 形状:", np.shape(matrix1))  # (3, 2)
print("matrix2 形状:", np.shape(matrix2))  # (2, 2)

result = np.dot(matrix1, matrix2)
print("矩阵相乘结果:")
print(result)
# 输出: [[ 25  28]
#       [ 57  64]
#       [ 89 100]]  # 3x2 矩阵

应用场景: 矩阵相乘在机器学习中非常重要,常用于神经网络的前向传播、线性回归、特征变换等任务。

单位矩阵和逆矩阵

单位矩阵是一个主对角线上元素全为 1,其他元素全为 0 的方阵。对于维度匹配的矩阵 A,有 I × A = A 和 A × I = A(其中 I 是相应维度的单位矩阵)。

逆矩阵:对于方阵 A,如果存在矩阵 B,使得 AB = BA = I(I 为单位矩阵),则 B 称为 A 的逆矩阵,记为 A⁻¹。

矩阵与其逆矩阵的乘积等于单位矩阵:A × A⁻¹ = I

# 定义一个 3x3 单位矩阵
identity_matrix = np.eye(3)
print("单位矩阵:")
print(identity_matrix)
# 输出: [[1. 0. 0.]
#       [0. 1. 0.]
#       [0. 0. 1.]]

# 计算逆矩阵
matrix = np.array([[4, 7],
                   [2, 6]])
matrix_inv = np.linalg.inv(matrix)
print("原矩阵:")
print(matrix)
print("逆矩阵:")
print(matrix_inv)

# 验证:矩阵与逆矩阵的乘积应该等于单位矩阵
result = np.dot(matrix, matrix_inv)
print("验证乘积(应该接近单位矩阵):")
print(result)
# 输出应该接近: [[1. 0.]
#                [0. 1.]]

注意: 只有方阵(行数等于列数)且行列式不为 0 的矩阵才有逆矩阵。

线性相关与线性无关

线性相关: 向量组中存在"冗余",即至少有一个向量可以被其他向量通过缩放和相加(线性组合)表示出来。

线性无关: 向量组中没有"冗余",每个向量都提供了新的方向信息。

几何理解:

  • 在二维空间中:

    • 两个向量线性相关:它们在同一条直线上(一个向量是另一个向量的倍数)
    • 两个向量线性无关:它们不在同一条直线上(可以张成整个二维平面)
  • 在三维空间中:

    • 三个向量线性相关:它们在同一平面上(其中一个向量可以由另外两个表示)
    • 三个向量线性无关:它们不在同一平面上(可以张成整个三维空间)

判断方法:

  • 对于方阵(向量个数等于向量维度):可以通过计算由这些向量组成的矩阵的行列式来判断。如果行列式为 0,则向量线性相关;如果行列式不为 0,则向量线性无关。
  • 对于非方阵:应该通过计算矩阵的秩来判断。如果矩阵的秩小于向量个数,则向量线性相关;如果秩等于向量个数,则向量线性无关。
# 判断两个向量是否线性相关
v1 = np.array([1, 2])
v2 = np.array([2, 4])  # v2 = 2 * v1,所以线性相关

# 组成矩阵:将向量作为列向量组成矩阵
# np.array([v1, v2]) 创建 2x2 矩阵,每行是一个向量
# 转置后变成列向量形式,便于计算行列式
A = np.array([v1, v2]).T  # 转置后变成 2x2 矩阵
print("向量矩阵:")
print(A)

# 计算行列式
det = np.linalg.det(A)
print("行列式:", det)  # 输出: 0.0(线性相关)

# 线性无关的例子
v3 = np.array([1, 2])
v4 = np.array([3, 1])  # 不在同一直线上
B = np.array([v3, v4]).T
det2 = np.linalg.det(B)
print("行列式:", det2)  # 输出: -5.0(线性无关)

生成子空间

生成子空间指的是一组向量通过线性组合所能生成的所有向量的集合。

理解方式:

  • 给定一组向量,通过它们的缩放和相加(线性组合),能够"覆盖"的所有可能的向量
  • 这些向量"张成"的空间可以是直线、平面、三维空间,甚至更高维的空间
  • 生成子空间的维度等于这组向量中线性无关向量的最大个数

例子:

  • 在二维空间中,两个线性无关的向量可以生成整个二维平面
  • 在三维空间中,两个线性无关的向量只能生成一个平面(二维子空间)

范数

范数用来衡量向量或矩阵"大小"或"长度"的一种函数。对于一个向量 $\mathbf{x} = (x_1, x_2, \ldots, x_n)$,范数记为 $|\mathbf{x}|$。

常见范数:

  1. L¹ 范数(曼哈顿范数): $$|\mathbf{x}|1 = \sum{i=1}^n |x_i|$$

  2. L² 范数(欧几里得范数): $$|\mathbf{x}|2 = \sqrt{\sum{i=1}^n x_i^2}$$

  3. L∞ 范数(切比雪夫范数): $$|\mathbf{x}|\infty = \max{i} |x_i|$$

NumPy 实现:

# 定义向量
x = np.array([1, 2, 3])

# 计算 L1 范数(曼哈顿距离)
l1_norm = np.linalg.norm(x, ord=1)
print("L1 范数:", l1_norm)  # 输出: 6.0 (|1| + |2| + |3| = 6)

# 计算 L2 范数(欧几里得距离)
l2_norm = np.linalg.norm(x, ord=2)
print("L2 范数:", l2_norm)  # 输出: 3.741657... (√(1² + 2² + 3²) = √14)

# 计算 L∞ 范数(最大绝对值)
linf_norm = np.linalg.norm(x, ord=np.inf)
print("L∞ 范数:", linf_norm)  # 输出: 3.0 (max(|1|, |2|, |3|) = 3)

应用场景:

  • L1 范数:常用于稀疏性约束(Lasso 回归)
  • L2 范数:常用于正则化(Ridge 回归)、计算距离
  • L∞ 范数:常用于误差分析、优化问题

总结

线性代数是 AI 和机器学习的数学基础。掌握矩阵运算、线性相关、范数等基本概念,有助于更好地理解神经网络的工作原理、优化算法的设计思路,以及各种机器学习模型的数学本质。通过 NumPy 等工具,我们可以高效地实现这些运算,为 AI 应用开发打下坚实的基础。