应用场景:
-
微积分:重点关注微分(对函数进行求导)部分,因为人工智能领域有一个很重要的算法,叫做神级网络反向传播,通过反向传播算法,可以更新神经网络里面的每一个参数,更新的时候是要计算出每一个参数的导数等于多少,也就是要求出微分是多少?
以下几个案例:
1、激活函数作图:用于描述激活函数。
2、展示二维图像切线
3、展示三维函数切面
4、神经网络反向传播:链式求导法则
5、制作梯度下降求最小值的动画
6、实现三维平面的梯度下降
-
线性代数:在人工智能领域,有一块叫计算机视觉,要处理的就是一些图像信息,图像信息对于电脑而言是一个矩阵,这样就和线性代数的矩阵产生关联了
相关案例:
1、创建矩阵
2、把矩阵保存成图片:可以知道神经网络,在中间层通过特征图学了些什么东西
3、图像亮度增强
4、图像对比度增强
5、矩阵基本运算
6、计算特征值与特征向量
7、图像的SVD压缩
-
概率论:在人工智能领域,例如图形操作用到了线性代数,通过矩阵相加实现亮度增强或下降,添加的内容可以再加入一些噪声,使用python模拟随机试验概率质量函数示意图求期望、方差、协方差模拟常见的概率分布,模拟大数定律、模拟中心极限定理
线性代数:人工智能数据基础
基础概念
- 标量(Scalar):一个标量是一个单独的数值,它只有大小,没有方向。在数学中,通常用实数或复数表示。例如,温度、质量、时间等都是标量。
- 向量(Vector):一个向量是具有大小和方向的量。它由一系列有序的数值组成,表示空间中的一个点或物体的位置或移动方向。在数学中,向量通常表示为一个列或行矩阵。例如,速度、力、位移等都是向量。
- 矩阵(Matrix):一个矩阵是一个二维数组,其中的每个元素都是一个标量。它可以表示多个向量或者多个量之间的关系,也可以表示线性变换。在数学和计算机科学中,矩阵常用于解线性方程组、表示图形变换等。
- 张量(Tensor):张量是一个可以在多个方向上有分量的数学对象。它是向量的推广,可以看作多维数组。标量是零阶张量,向量是一阶张量,矩阵是二阶张量,而更高阶的张量可以有更多的维度。在物理学、工程学和机器学习等领域中,张量常用于表示物理量、数据集合等复杂的数据结构。
实战案例:创建向量、矩阵、张量
- 创建向量(一维)
import numpy as np
# 创建向量(一维)
vector = np.array([1, 2, 3, 4, 5])
vector_norm = np.linalg.norm(vector)
print("Vector:\n", vector)
print("Vector的范数长度:\n", vector_norm)
运行结果:
Vector:
[1 2 3 4 5]
Vector的范数长度:
7.416198487095663
- 创建矩阵(二维)
import numpy as np
# 创建矩阵(二维)
matrix = np.array([
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
])
matrix_norm = np.linalg.norm(matrix)
print("matrix:\n", matrix)
print("matrix的范数长度:\n", matrix_norm)
运行结果:
matrix:
[[1 2 3]
[4 5 6]
[7 8 9]]
matrix的范数长度:
16.881943016134134
- 创建张量(三维)
import numpy as np
# 创建张量(三维)
tensor = np.array([
[[1,2],[3,4]],
[[5,6],[7,8]],
[[9,10],[11,12]]
])
tensor_norm = np.linalg.norm(tensor)
print("tensor:\n", tensor)
print("tensor的范数长度:\n", tensor_norm)
运行结果:
tensor:
[[[ 1 2]
[ 3 4]]
[[ 5 6]
[ 7 8]]
[[ 9 10]
[11 12]]]
tensor的范数长度:
25.495097567963924
实战案例:将Numpy矩阵保存成本地图像
import numpy as np
import cv2
# 创建一个大小为 224*224 的二维矩阵,值为0-255之间
two_d_matrix = np.random.randint(0, 256, (224, 224), dtype=np.uint8)
# 创建一个大小为 3*224*224 的三维矩阵,值为0-255之间
three_d_matrix = np.random.randint(0, 256, (3, 224, 224), dtype=np.uint8)
# 在 OpenCv 中,图像的通道顺序为 高 * 宽 * 通道数
three_d_matrix_transposed = three_d_matrix.transpose(1, 2, 0)
# 将画面显示出来
cv2.imshow('two_d_matrix', two_d_matrix)
cv2.imshow('three_d_matrix', three_d_matrix_transposed)
cv2.waitKey(0)
cv2.destroyAllWindows()
# 使用 OpenCv 将图片保存本地
cv2.imwrite('two_d_matrix.jpg', two_d_matrix)
cv2.imwrite('three_d_matrix.jpg', three_d_matrix_transposed)
实战案例:图像增强(调整对比度)
-
标量与矩阵的乘法,即可实现对比度增强及减弱
-
代码如下:
import numpy as np import cv2 # 读取图像 image = cv2.imread('robot.png') # 增加对比度 increased_contrast = cv2.convertScaleAbs(image, alpha=1.5) # 减少对比度 decreased_contrast = cv2.convertScaleAbs(image, alpha=0.5) # 将图像进行横向拼接 combined_image = np.hstack((image, increased_contrast, decreased_contrast)) # 显示图片 cv2.imshow('image, increased_contrast, decreased_contrast', combined_image) # 画面固定屏幕当中 cv2.waitKey(0) # 关闭所有已经打开的窗口,可以帮助释放资源并关闭窗口,确保程序的正常退出 cv2.destroyAllWindows() -
练习:标量与矩阵相乘以及矩阵相加
import numpy as np # 定义矩阵A和B A = np.array([[1, 2], [3, 4]]) B = np.array([[5, 6], [7, 8]]) # 定义标量C C = 3 # 标量与矩阵的乘法 scalar_matrix_multiplication = C * A # 矩阵的加法 matrix_addition = A + B print('标量与矩阵的乘法:', scalar_matrix_multiplication) print('矩阵的加法:', matrix_addition) 运行结果: 标量与矩阵的乘法: [[ 3 6] [ 9 12]] 矩阵的加法: [[ 6 8] [10 12]]
Python 实现解方程组
解以下方程: X1 + 2X2 + 3X3 = 5 X1 + 6X2 + 7X3 = 9 X1 + 10X2 + 6X3 = 8
-
手推
| 1 2 3 | | 5 | A = | 1 6 7 | B = | 9 | | 1 10 6 | | 8 | | 1 2 3 | 5 | (A | B) = | 1 6 7 | 9 | | 1 10 6 | 8 | | 1 2 3 | 5 | r3 - r2 = | 1 6 7 | 9 | | 0 4 -1 |-1 | | 1 2 3 | 5 | r2 - r1 = | 0 4 4 | 4 | | 0 4 -1 |-1 | | 1 2 3 | 5 | r3 - r2 = | 0 4 4 | 4 | | 0 0 -5 |-5 | r2 * 1/4 | 1 2 3 | 5 | ------- = | 0 1 1 | 1 | r3 * -1/5 | 0 0 1 | 1 | x1 + 2X2 + 3X3 = 5 X2 + X3 = 1 X3 = 1 所以最终结果: X3 = 1 X2 = 0 X1 = 2 -
代码
import numpy as np # 创建系数矩阵 A = np.array([ [1, 2, 3], [1, 6, 7], [1, 10, 6] ]) # 创建常数向量 B = np.array([5, 9, 8]) # 解方程 x = np.linalg.solve(A, B) # 打印结果 print('解:', x) 运行结果: 解: [2. 0. 1.]
特征向量与特征值实操
特征值和特征向量是线性代数中的重要概念,它们通常在矩阵和线性变换的理论中发挥作用。
- 特征值是一个标量,用来表示线性变换对应的特定方向上的缩放比例。如果我们把线性变换想象成一个拉伸机,特征值就是拉伸或缩放的倍数,它反映了变换对于特定方向上向量的伸缩程度。
- 特征向量则是在线性变换下不改变方向的向量。换句话说,它们是变换后的向量方向保持不变的向量。在拉伸机的例子中,特征向量就是被拉伸后方向不变的箭头,它们指示了变换的主要方向。
这两个概念通常是通过矩阵的特征方程来计算的,特征方程是一个关于特征值的多项式方程。解这个方程可以得到特征值,而对应每个特征值,我们可以找到对应的特征向量。
-
求解以下矩阵的特征值与特征向量
A = | 4 1 | | 2 3 |-
计算特征值方程
det(A - λI) = det( 4 - λ 1 ) = ( 4 - λ)( 3 - λ) - 2 = λ² - 7λ + 10 = 0 ( 2 3 - λ ) -
求特征值方程
λ² - 7λ + 10 = 0 λ1 = 5, λ2 = 2 -
求特征向量方程
(A - λI)χ = 0 -
计算结果
当 λ1 = 5 时,特征向量为 0.707 0.707 当 λ1 = 5 时,特征向量为 -0.447 0.894
-
-
代码解方程
import numpy as np # 定义矩阵A A = np.array([ [4,1], [2,3] ]) # 使用numpy求特征值和特征向量 eigenvalues, eigenvectors = np.linalg.eig(A) print('特征值',eigenvalues) print('特征向量',eigenvectors) 运行结果: 特征值 [5. 2.] 特征向量 [[ 0.70710678 -0.4472136 ] [ 0.70710678 0.89442719]] -
案例实战:图像的SVD分解
对一幅图像进行SVD分解后可以得到三个矩阵:
- U矩阵:包含了“左奇异向量”,可以想象成是一组基础的图像模式。
- Σ矩阵:包含了“奇异值”,表明了每个图像模式的重要性或权重。较大的奇异值对应于图像中更重要的特征。
- V矩阵:包含了“右奇异向量”,它与U矩阵类似,但从不同角度描述了图像的特征。
通过这种分解,图像转化为一系列的模式和对应的权重。可通过用较少的数据来描述一幅图像,同时保留其关键特征,从而实现图片的信息压缩功能。
import cv2 # 导入 OpenCV 库 import numpy as np # 导入 NumPy 库用于科学计算 # 读取图像 image = cv2.imread('robot.bmp', 0) # 使用 OpenCV 读取灰度图像 print("Shape of image:", image.shape) # 打印图像的形状 # 对图像进行 SVD 分解 U, S, V = np.linalg.svd(image.astype(np.float64), full_matrices=False) # image.astype(np.float64) 将图像数据类型转换为 float64,以便进行数值计算 # full_matrices=False 表示不返回完整的 U 和 V 矩阵 # 定义要保留的奇异值数量 k = 10 # 选择保留的奇异值数量 s_k = np.diag(S[:k]) # 提取前 k 个奇异值构成的对角矩阵 # 重构图像 compressed_image = np.dot(U[:, :k], np.dot(s_k, V[:k, :])) # 使用前 k 个奇异值重构图像 # np.dot() 用于矩阵乘法 compressed_image = np.clip(compressed_image, 0, 255).astype(np.uint8) # 将图像像素值限制在 0 到 255 之间,并将数据类型转换为 uint8 # 显示图像 cv2.imshow('Original Image', image) # 显示原始图像 cv2.imshow('Compressed Image', compressed_image) # 显示压缩后的图像 cv2.waitKey(0) # 等待按键 cv2.destroyAllWindows() # 关闭所有窗口
微积分:数学背后的AI力量
基本概念
是数学中的一个基本概念,主要用于研究函数随变量变化的快慢,即变化率。给出一个函数 f(x),如果我们想要计算在某一点 x = a 处的导数,我们会考虑函数在 x 接近 a 时的变化情况。
更正式地说,函数 f(x) 在点 x = a 处的导数定义为:
如果这个极限存在,我们就说函数在点 a 是可导的。
几何意义:在几何上,导数表示的是曲线在某一点处切线的斜率。假设你有一个函数 f(x) 的图形,这个图形在每一点上都有一个斜率,这个斜率就是该点处的导数。当你在图形上选择一个点,并尝试画出恰好触碰曲线在那一点的直线(即切线),那么这条切线的斜率(即斜率的升高与横向移动的比率)就是那点处函数的导数。如果导数是正值,切线向上倾斜;如果导数是负值,切线向下倾斜;如果导数是零,切线是水平的。
常见导数
| 初等函数 | 导数 |
|---|---|
深度学习中的激活函数
| 激活函数 | 表达式 | 导数 | 特点 |
|---|---|---|---|
| Sigmoid | 将输入压缩到(0,1)区间,用于二分类问题,在深层网络中容易产生梯度消失 | ||
| Tanh | 将输入压缩到(-1,1)区间,比sigmoid有更大的输出范围,也可能导致梯度消失 | ||
| ReLU | 在正区间内保持梯度不变,解决了梯度消失问题,但在负区间梯度为0 | ||
| Leaky ReLU | 解决了ReLU在负区间梯度为0的问题,允许小梯度存在 | ||
| Parametric ReLU | ReLU的泛化形式,其中α是一个可学习的参数 | ||
| ELU | 试图结合sigmoid和ReLU的优点,输出对负值有小幅度的响应 | ||
| Softmax | 用于多分类问题的输出层,输出值的和为1,代表概率分布 |
Python绘制激活函数
-
Sigmoid
import numpy as np import matplotlib.pyplot as plt # 定义 Sigmoid 激活函数 def sigmoid(x): return 1 / (1 + np.exp(-x)) # 绘制激活函数图像的函数 def plot_activation_function(func, x, title): # 计算函数值 y = func(x) # 绘制函数图像 plt.plot(x, y) plt.title(title) plt.xlabel('x') plt.ylabel('f(x)') plt.grid(True) plt.show() # 生成 x 范围数组 x_value = np.arange(-10, 10, 0.1) # 绘制 Sigmoid 函数图像 plot_activation_function(sigmoid, x_value, 'Sigmoid') -
tanh
import numpy as np import matplotlib.pyplot as plt # 定义 Sigmoid 激活函数 def sigmoid(x): return 1 / (1 + np.exp(-x)) def tanh(x): return np.tanh(x) # 绘制激活函数图像的函数 def plot_activation_function(func, x, title): # 计算函数值 y = func(x) # 绘制函数图像 plt.plot(x, y) plt.title(title) plt.xlabel('x') plt.ylabel('f(x)') plt.grid(True) plt.show() # 生成 x 范围数组 x_value = np.arange(-10, 10, 0.1) # 绘制 Sigmoid 函数图像 plot_activation_function(sigmoid, x_value, 'Sigmoid') plot_activation_function(tanh, x_value, 'tanh') -
relu
import numpy as np import matplotlib.pyplot as plt # 定义 Sigmoid 激活函数 def sigmoid(x): return 1 / (1 + np.exp(-x)) def tanh(x): return np.tanh(x) def relu(x): return np.maximum(0,x) # 绘制激活函数图像的函数 def plot_activation_function(func, x, title): # 计算函数值 y = func(x) # 绘制函数图像 plt.plot(x, y) plt.title(title) plt.xlabel('x') plt.ylabel('f(x)') plt.grid(True) plt.show() # 生成 x 范围数组 x_value = np.arange(-10, 10, 0.1) # 绘制 Sigmoid 函数图像 # plot_activation_function(sigmoid, x_value, 'Sigmoid') # plot_activation_function(tanh, x_value, 'tanh') plot_activation_function(relu, x_value, 'relu') -
leak_relu
import numpy as np import matplotlib.pyplot as plt # 定义 Sigmoid 激活函数 def sigmoid(x): return 1 / (1 + np.exp(-x)) def tanh(x): return np.tanh(x) def relu(x): return np.maximum(0,x) def leak_relu(x,alpha=0.01): return np.where(x>0,x,x*alpha) # 绘制激活函数图像的函数 def plot_activation_function(func, x, title): # 计算函数值 y = func(x) # 绘制函数图像 plt.plot(x, y) plt.title(title) plt.xlabel('x') plt.ylabel('f(x)') plt.grid(True) plt.show() # 生成 x 范围数组 x_value = np.arange(-10, 10, 0.1) # 绘制 Sigmoid 函数图像 # plot_activation_function(sigmoid, x_value, 'Sigmoid') # plot_activation_function(tanh, x_value, 'tanh') # plot_activation_function(relu, x_value, 'relu') plot_activation_function(leak_relu, x_value, 'leak_relu') -
parametric_relu
import numpy as np import matplotlib.pyplot as plt # 定义 Sigmoid 激活函数 def sigmoid(x): return 1 / (1 + np.exp(-x)) def tanh(x): return np.tanh(x) def relu(x): return np.maximum(0,x) def leak_relu(x,alpha=0.01): return np.where(x>0,x,x*alpha) def parametric_relu(x,parm=0.5): return np.where(x>0,x,x*parm) # 绘制激活函数图像的函数 def plot_activation_function(func, x, title): # 计算函数值 y = func(x) # 绘制函数图像 plt.plot(x, y) plt.title(title) plt.xlabel('x') plt.ylabel('f(x)') plt.grid(True) plt.show() # 生成 x 范围数组 x_value = np.arange(-10, 10, 0.1) # 绘制 Sigmoid 函数图像 # plot_activation_function(sigmoid, x_value, 'Sigmoid') # plot_activation_function(tanh, x_value, 'tanh') # plot_activation_function(relu, x_value, 'relu') # plot_activation_function(leak_relu, x_value, 'leak_relu') plot_activation_function(parametric_relu, x_value, 'parametric_relu') -
elu
import numpy as np import matplotlib.pyplot as plt # 定义 Sigmoid 激活函数 def sigmoid(x): return 1 / (1 + np.exp(-x)) def tanh(x): return np.tanh(x) def relu(x): return np.maximum(0,x) def leak_relu(x,alpha=0.01): return np.where(x>0,x,x*alpha) def parametric_relu(x,parm=0.5): return np.where(x>0,x,x*parm) def elu(x,alph=1): return np.where(x>0,x,alph*(np.exp(x)-1)) # 绘制激活函数图像的函数 def plot_activation_function(func, x, title): # 计算函数值 y = func(x) # 绘制函数图像 plt.plot(x, y) plt.title(title) plt.xlabel('x') plt.ylabel('f(x)') plt.grid(True) plt.show() # 生成 x 范围数组 x_value = np.arange(-10, 10, 0.1) # 绘制 Sigmoid 函数图像 # plot_activation_function(sigmoid, x_value, 'Sigmoid') # plot_activation_function(tanh, x_value, 'tanh') # plot_activation_function(relu, x_value, 'relu') # plot_activation_function(leak_relu, x_value, 'leak_relu') # plot_activation_function(parametric_relu, x_value, 'parametric_relu') plot_activation_function(elu, x_value, 'elu')
微分和积分
-
微分概念:函数 f(x) 在点 的微分,通常表示为 df 或 df(x) ,在几何上对应于函数图像在 x 点的且线上,x 的一个小变化 dx 所引起的函数值 f(x) 的变化。这个变化成为函数 f 的微分,在数学上可以写作:
其中 f'(x) 是函数 f 在 x 处的导数。
-
加法法则:如果有两个函数 u(x) 和 v(x),它们的和为 f(x) = u(x) + v(x), 那么 f(x) 的导数是这两个函数导数的和:
-
乘法法则:如果有两个函数 u(x) 和 v(x),它们的乘积为 f(x) = u(x) * v(x),那么 f(x) 的导数是:
-
除法法则:如果有两个函数 u(x) 和 v(x),它们的商为 f(x) = u(x) / v(x),那么 f(x) 的导数是:
-
-
积分:求曲线面积
案例:二维图像切线
import numpy as np # 导入NumPy库,用于数值计算
import matplotlib.pyplot as plt # 导入matplotlib库,用于绘图
# 定义函数
def f(x):
return x ** 2 # 定义函数 f(x) = x²
# 导数(梯度)
def df(x):
return 2 * x # 函数 f(x) 的导数(梯度)为 2x
# 检测原始函数
x = np.linspace(-3, 3, 100) # 在区间[-3, 3]内生成100个等间距的点作为横坐标
y = f(x) # 计算对应的纵坐标值
plt.figure(figsize=(8, 6)) # 创建一个8x6的图形窗口
plt.plot(x, y, label="f(x) = x²") # 绘制原始函数曲线,标签为"f(x) = x²"
# 计算当 x = 1 时的梯度和切线
x1 = 1 # 切线所在点的横坐标
y1 = f(x1) # 切线所在点的纵坐标
slope = df(x1) # 切线的斜率(梯度)
# 切线方程, y = m(x - x1) + y1
def tangent_line(x, x1, y1, slope):
return slope * (x - x1) + y1 # 计算切线的纵坐标
# 切点附近绘制切线
x_tangent = np.linspace(x1 - 1, x1 + 1, 10) # 在 x=1 附近生成横坐标
y_tangent = tangent_line(x_tangent, x1, y1, slope) # 计算切线的纵坐标
# 绘制切线
plt.plot(x_tangent, y_tangent, label="Tangent at x = 1", color='red') # 绘制切线,标签为"Tangent at x = 1",颜色为红色
# 绘制切点
plt.scatter([x1], [y1], color='black') # 在切点处绘制黑色的点
# 设置图形
plt.xlabel('x') # 设置横坐标轴标签为"x"
plt.ylabel('f(x)') # 设置纵坐标轴标签为"f(x)"
plt.title('Function and Its Tangent at x = 1') # 设置图形标题为"Function and Its Tangent at x = 1"
plt.legend() # 显示图例
plt.grid(True) # 显示网格线
plt.show() # 显示图形
案例:三位函数切面
import numpy as np
import matplotlib.pyplot as plt
# 创建 x , y 数据点
x = np.linspace(-5, 5, 100)
y = np.linspace(-5, 5, 100)
# 生成网格坐标矩阵
x, y = np.meshgrid(x, y)
# 定义三维函数
def f(x, y):
return x ** 2 + y ** 2
# 计算z的值
z = f(x, y)
# 创建图形和轴
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
# 绘制表面
surf = ax.plot_surface(x, y, z, cmap='viridis', alpha=0.5)
# 定义要突出显示的点
point_x, point_y = 1.0, 1.0
point_z = f(point_x, point_y)
# 绘制该点
ax.scatter(point_x, point_y, point_z, color='red', s=50)
# 切平面的法线
normal = np.array([2 * point_x, 2 * point_y, -1])
# 定义平面上所有的点 x_plan, y_plan, z_plan
x_plan = np.linspace(-5, 5, 10)
y_plan = np.linspace(-5, 5, 10)
# 转为网格坐标
x_plan, y_plan = np.meshgrid(x_plan, y_plan)
z_plan = (-normal[0] * (x_plan - point_x) - normal[1] * (y_plan - point_y)) / normal[2] + point_z
# 绘制切平面
ax.plot_surface(x_plan, y_plan, z_plan, color='yellow', alpha=0.5)
# 设置标签和标题
ax.set_xlabel('x axis')
ax.set_ylabel('y axis')
ax.set_zlabel('z axis')
ax.set_title("3D Surface Plot whith Tangent Plane")
plt.show()
链式求导法
设有两个函数 y=f(u) 和 u=g(x),它们都在相应的点可导。如果我们定义一个复合函数 y=f(g(x)),那么复合函数 y 关于 x 的导数是:
这里,du/dy 是外函数 f(u) 关于其变量 u 的导数,而 dx/du 是内函数 g(x) 关于 x 的导数。
-
小案例
假设有符合函数
,对它进行求导,令 :
-
首先求 g(x)的导数:
-
然后求 f(u) 对 u 的导数:
-
将 g(x) 代入 f'(u) 得到 f'(g(x)) = 2(3x+2)
-
最后将 f'(g(x)) 和 g'(x) 相乘得到 h'(x): h'(x) = 2(3x+2)*3。
-