主成分分析(PCA,Principal Component Analysis)是一项在高维数据中,寻找最重要特征的降维技术,大大减少数据的维度,而不显著损失信息量。本文将通过基于飞桨框架的实际代码示例,来展示所提供的高效、灵活的线性代数 API,如何简化机器学习和深度学习中的数据处理和分析工作,为高维数据集的处理和分析提供了有效工具。主成分分析在人脸识别项目中完整代码及数据集已上传至飞桨星河社区:
https://aistudio.baidu.com/projectdetail/8055072
01
本文使用的是 ORL 官方数据集,下载网址:
http://www.cl.cam.ac.uk/Research/DTG/attarchive/pub/data/att_faces.tar.Z
该数据集包含40个人的人脸图像,其中每一个人有10张人脸图像。相应的 PGM 文件为说明。
02
pip install opencv-python
pip install paddle
03
3.1 图片矢量化
import cv2
import paddle
# 图片矢量化
def img2vector(image):
img = cv2.imread(image, 0) # 读取图片
imgVector = paddle.reshape(paddle.to_tensor(img, dtype='float32'), [1, -1]) # 重塑为1行多列
return imgVector
3.2 标读取数据并进行矢量化
import os
import numpy as np
class ORLDataset:
def __init__(self, data_path, k, train=True):
self.data_path = data_path
self.k = k
self.train = train
def load_orl(self):
train_images = []
train_labels = []
test_images = []
test_labels = []
sample = np.random.permutation(10) + 1 # 生成随机序列
for i in range(40): # 共有40个人
people_num = i + 1
for j in range(10): # 每人10张照片
image_path = os.path.join(self.data_path, 's' + str(people_num), str(sample[j]) + '.pgm')
img = img2vector(image_path) # 读取图片并进行矢量化
if j < self.k: # 构成训练集
train_images.append(img)
train_labels.append(people_num)
else: # 构成测试集
test_images.append(img)
test_labels.append(people_num)
if self.train:
return paddle.concat(train_images, axis=0), paddle.to_tensor(train_labels, dtype='int64')
else:
return paddle.concat(test_images, axis=0), paddle.to_tensor(test_labels, dtype='int64')
3.3 PCA降纬操作
data = paddle.cast(data, 'float32')
rows, cols = data.shape
data_mean = paddle.mean(data, axis=0) # 计算均值
A = data - paddle.tile(data_mean, repeat_times=[rows, 1]) # 数据中心化
数据中心化的公式为:
$A = X - \bar{X}$$
C = paddle.matmul(A, A, transpose_y=True)
$C = AA^T$$
(4) 计算特征值和特征向量:使用协方差矩阵 $C$ 计算特征值 $\lambda$ 和特征向量 $\vec{v}$。
eig_vals, eig_vects = paddle.linalg.eigh(C)
$C\vec{v} = \lambda\vec{v}$$
eig_vects = paddle.matmul(A.T, eig_vects[:, :r])
$$Vr = [\vec{v}1, \vec{v}2, \ldots, \vec{v}r]$$
for i in range(r):
eig_vects[:, i] = eig_vects[:, i] / paddle.norm(eig_vects[:, i])
特征向量标准化的公式为:
$$\hat{\vec{v}}i = \frac{\vec{v}i}{|\vec{v}_i|}$$
final_data = paddle.matmul(A, eig_vects) # 降维后的数据
return final_data, data_mean, eig_vects
$Y = AV_r$$
def PCA(data, r): # 降低到r维
data = paddle.cast(data, 'float32')
rows, cols = data.shape
data_mean = paddle.mean(data, axis=0) # 计算均值
A = data - paddle.tile(data_mean, repeat_times=[rows, 1]) # 数据中心化
# 计算协方差矩阵
C = paddle.matmul(A, A, transpose_y=True)
# 计算特征值和特征向量
eig_vals, eig_vects = paddle.linalg.eigh(C)
# 选取前r个特征向量
eig_vects = paddle.matmul(A.T, eig_vects[:, :r])
for i inrange(r):
eig_vects[:, i] = eig_vects[:, i] / paddle.norm(eig_vects[:, i]) # 特征向量标准化
final_data = paddle.matmul(A, eig_vects) # 降维后的数据
return final_data, data_mean, eig_vects
3.4 训练与测试
def face_recognize(data_path):
for r in range(10, 41, 10):
print(f"当降维到{r}时:")
dataset_train = ORLDataset(data_path, k=7, train=True)
dataset_test = ORLDataset(data_path, k=7, train=False)
train_data, train_labels = dataset_train.load_orl()
test_data, test_labels = dataset_test.load_orl()
data_train_new, data_mean, V_r = PCA(train_data, r)
temp_face = test_data - data_mean
data_test_new = paddle.matmul(temp_face, V_r)
true_num = 0
for i in range(len(test_labels)):
diffMat = data_train_new - data_test_new[i]
sqDiffMat = paddle.square(diffMat)
sqDistances = paddle.sum(sqDiffMat, axis=1)
sortedDistIndices = paddle.argsort(sqDistances)
if train_labels[sortedDistIndices[0]] == test_labels[i]:
true_num += 1
accuracy = float(true_num) / len(test_labels)
print(f'当每个人选择7张照片进行训练时,The classify accuracy is: {accuracy:.2%}')
3.5 结果
当降维到10时:当每个人选择7张照片进行训练时,The classify accuracy is: 67.50%
当降维到20时:当每个人选择7张照片进行训练时,The classify accuracy is: 35.00%
当降维到30时:当每个人选择7张照片进行训练时,The classify accuracy is: 67.50%
当降维到40时:当每个人选择7张照片进行训练时,The classify accuracy is: 40.00%
以上是基于飞桨框架实现 PCA 的人脸识别算法的完整代码和结果。
04
基于飞桨框架的 paddle.linalg API 为进行数据降维和特征提取提供了强大的支持,这对于机器学习和深度学习应用来说是非常重要的。特别是,paddle.linalg.eig 和 paddle.linalg.svd 函数允许用户有效地计算数据的特征值和特征向量,这是执行主成分分析(PCA)和奇异值分解(SVD)等降维方法的关键。此外,paddle.linalg.matmul 可以用于矩阵乘法,帮助将数据从高维空间映射到低维空间,保留了数据中最重要的信息。
这些功能的广泛应用不仅限于 PCA 相关的任务,还包括数据压缩、特征选择和提高学习算法的效率等领域。通过降维,可以显著减少模型训练的计算资源需求,提高模型的泛化能力,减少过拟合的风险。飞桨通过提供这些高效、灵活的线性代数 API,极大地简化了机器学习和深度学习中的数据处理和分析工作,为高维数据集的处理和分析提供了有效工具。
END
推荐阅读
统一多场景自动编译加速——支持动态shape场景,一套架构搞定训推需求