奇异值分解SVD 原理+作业

奋斗吧
奋斗吧
擅长邻域:未填写

标签: 奇异值分解SVD 原理+作业 HTML5博客 51CTO博客

2023-05-10 18:24:05 52浏览

奇异值分解SVD 原理+作业,矩阵分解在机器学习领域有着广泛应用,是降维相关算法的基本组成部分。矩阵分解的定义把一个矩阵表示成多个矩阵连乘的形式。矩阵分解主要有两个作用常见的矩阵分解方式有以下两种特征分解Eigendecomposition,也叫作谱分解Spectraldecomposition奇异值分解SingularValuedecompositon(SVD)特征值分解是一个提取矩阵特征很不错的方法,可是它只是对方阵而言的,在现实的世界中,咱们看到的大部分矩阵都不是方阵,好比说有NNN个学生,每一个学生有MMM科成绩,这样造



文章目录

  • 奇异值分解SVD 原理+作业
  • 1. 简介
  • 1.1 简介
  • 1.2 正交变换
  • 1.3 特征值和特征向量
  • 1.4 SVD
  • 2. 流程
  • 3. 作业
  • 3.1 手动实现SVD
  • 要求
  • 代码
  • 3.2 人脸识别
  • 要求
  • 数据集介绍
  • 代码


奇异值分解SVD 原理+作业

1. 简介

1.1 简介

矩阵分解在机器学习领域有着广泛应用,是降维相关算法的基本组成部分。

矩阵分解的定义

把一个矩阵表示成多个矩阵连乘的形式。

矩阵分解主要有两个作用

  1. 分解后的每个小矩阵能够更容易的求逆
  2. 分解后的每个小矩阵有特殊的物理意义

常见的矩阵分解方式有以下两种

  1. 特征分解Eigendecomposition, 也叫作谱分解Spectral decomposition
  2. 奇异值分解Singular Value decompositon(SVD)

特征值分解是一个提取矩阵特征很不错的方法,可是它只是对方阵而言的,在现实的世界中,咱们看到的大部分矩阵都不是方阵,好比说有奇异值分解SVD 原理+作业_矩阵个学生,每一个学生有奇异值分解SVD 原理+作业_机器学习_02科成绩,这样造成的一个奇异值分解SVD 原理+作业_正交变换_03的矩阵就不多是方阵,咱们怎样才能描述这样普通的矩阵呢的重要特征呢?奇异值分解能够用来干这个事情,奇异值分解是一个能适用于任意的矩阵的一种分解的方法:

想要理解SVD,必须理解的数学知识

1.2 正交变换

正交变换公式
奇异值分解SVD 原理+作业_机器学习_04
上式表示:奇异值分解SVD 原理+作业_机器学习_05奇异值分解SVD 原理+作业_机器学习_06的正交变换,其中奇异值分解SVD 原理+作业_正交变换_07是正交矩阵,奇异值分解SVD 原理+作业_机器学习_05奇异值分解SVD 原理+作业_机器学习_06为列向量。

下面用─个例子说明正交变换的含义∶

假设有两个单位列向量奇异值分解SVD 原理+作业_奇异值分解_10奇异值分解SVD 原理+作业_矩阵_11,两向量的夹角为奇异值分解SVD 原理+作业_机器学习_12,如下图:

奇异值分解SVD 原理+作业_正交变换_13

现对向量a,b进行正交变换:
奇异值分解SVD 原理+作业_正交变换_14
奇异值分解SVD 原理+作业_正交变换_15的模:
奇异值分解SVD 原理+作业_奇异值分解_16
由上式可知奇异值分解SVD 原理+作业_正交变换_15的模为1

奇异值分解SVD 原理+作业_正交变换_18奇异值分解SVD 原理+作业_线性代数_19的内积为
奇异值分解SVD 原理+作业_奇异值分解_20
由上式可知,正交变换前后的内积相等。

奇异值分解SVD 原理+作业_正交变换_18奇异值分解SVD 原理+作业_线性代数_19的夹角奇异值分解SVD 原理+作业_矩阵_23
奇异值分解SVD 原理+作业_奇异值分解_24
正交变换前后的夹角相等,即奇异值分解SVD 原理+作业_矩阵_25

因此,正交变换的性质可用下图来表示:

奇异值分解SVD 原理+作业_机器学习_26

正交变换的两个重要性质:

1)正交变换不改变向量的模。

2)正交变换不改变向量的夹角。

如果向量奇异值分解SVD 原理+作业_奇异值分解_27奇异值分解SVD 原理+作业_机器学习_28是基向量,那么正交变换的结果如下图:

奇异值分解SVD 原理+作业_机器学习_29

基向量正交变换后的结果仍是基向量 。基向量是表示向量最简洁的方法,向量在基向量的投影就是所在基向量的坐标,我们通过这种思想去理解特征值分解和推导SVD分解。

正交变换只是将变换向量用另一组正交基表示,在这个过程中并没有对向量做拉伸,也不改变向量的空间位置,假如对两个向量同时做正交变换,那么变换前后这两个向量的夹角显然不会改变

1.3 特征值和特征向量

我们首先回顾下特征值和特征向量的定义如下:
奇异值分解SVD 原理+作业_奇异值分解_30
奇异值分解SVD 原理+作业_矩阵_31是一个奇异值分解SVD 原理+作业_机器学习_32的矩阵,奇异值分解SVD 原理+作业_正交变换_33是一个奇异值分解SVD 原理+作业_正交变换_34维向量,则我们说奇异值分解SVD 原理+作业_线性代数_35是矩阵奇异值分解SVD 原理+作业_矩阵_31的一个特征值,而奇异值分解SVD 原理+作业_正交变换_33是矩阵奇异值分解SVD 原理+作业_矩阵_31的特征值奇异值分解SVD 原理+作业_线性代数_35所对应的特征向量。

求出特征值和特征向量有什么好处呢?

我们可以将矩阵奇异值分解SVD 原理+作业_矩阵_31特征分解,如果我们求出了矩阵奇异值分解SVD 原理+作业_矩阵_31奇异值分解SVD 原理+作业_正交变换_34个特征值奇异值分解SVD 原理+作业_机器学习_43,以及这奇异值分解SVD 原理+作业_正交变换_34个特征值对应的特征向量奇异值分解SVD 原理+作业_正交变换_45,如果这奇异值分解SVD 原理+作业_正交变换_34个特征向量线性无关,那么矩阵奇异值分解SVD 原理+作业_矩阵_31就可以用下式的特征分解表示
奇异值分解SVD 原理+作业_矩阵_48
其中奇异值分解SVD 原理+作业_奇异值分解_49是这奇异值分解SVD 原理+作业_正交变换_34个特征向量所张成的奇异值分解SVD 原理+作业_机器学习_32维矩阵,而奇异值分解SVD 原理+作业_线性代数_52为这奇异值分解SVD 原理+作业_正交变换_34个特征值为主对角线的奇异值分解SVD 原理+作业_机器学习_32维矩阵。

为了可视化特征值分解,假设奇异值分解SVD 原理+作业_矩阵_31奇异值分解SVD 原理+作业_正交变换_56的对称矩阵,奇异值分解SVD 原理+作业_奇异值分解_57。把上式展开
奇异值分解SVD 原理+作业_机器学习_58
用图形表示为

奇异值分解SVD 原理+作业_线性代数_59

由上图可知,矩阵A没有旋转特征向量,它只是对特征向量进行了拉伸或缩短(取决于特征值的大小),因此,对称矩阵对其特征向量(基向量)的变换仍然是基向量(单位化) 。

特征向量和特征值的几何意义:若向量经过矩阵变换后保持方向不变,只是进行长度上的伸缩,那么该向量是矩阵的特征向量,伸缩倍数是特征值。

一般我们会把奇异值分解SVD 原理+作业_奇异值分解_49的这个奇异值分解SVD 原理+作业_正交变换_34个特征向量标准化,即满足奇异值分解SVD 原理+作业_线性代数_62,或者说奇异值分解SVD 原理+作业_机器学习_63.此时奇异值分解SVD 原理+作业_奇异值分解_49奇异值分解SVD 原理+作业_正交变换_34个特征向量为标准正交基。满足奇异值分解SVD 原理+作业_奇异值分解_66,即奇异值分解SVD 原理+作业_矩阵_67,也就是说奇异值分解SVD 原理+作业_奇异值分解_49为酉矩阵,在实数矩阵中,酉矩阵指的是转置矩阵与逆矩阵相等的矩阵;在复数矩阵中,酉矩阵指的是共轭转置矩阵(矩阵中各元素实部不变,虚部相反数)与逆矩阵相等的矩阵。

这样我们的特征分解表达式可以写成:
奇异值分解SVD 原理+作业_正交变换_69
注意到要进行特征分解,矩阵A必须为方阵。那么如果A不是方阵,即行和列不相同时,我们还可以对矩阵进行分解吗?答案是可以,此时我们的SVD登场了。

1.4 SVD

假设奇异值分解SVD 原理+作业_矩阵_31是一个奇异值分解SVD 原理+作业_奇异值分解_71的矩阵,那么可以定义奇异值分解SVD 原理+作业_矩阵_31的SVD为
奇异值分解SVD 原理+作业_正交变换_73
其中,奇异值分解SVD 原理+作业_机器学习_74对角矩阵,主对角线上的元素为奇异值,奇异值分解SVD 原理+作业_线性代数_75奇异值分解SVD 原理+作业_矩阵_76都是酉矩阵,即满足奇异值分解SVD 原理+作业_机器学习_77

奇异值分解SVD 原理+作业_矩阵_78

证明如下

先回顾一下正交变换的思想:基向量正交变换后的结果仍是基向量 。

我们用正交变换的思想来推导SVD分解:

假设奇异值分解SVD 原理+作业_矩阵_31奇异值分解SVD 原理+作业_矩阵_80的矩阵,秩为奇异值分解SVD 原理+作业_机器学习_81奇异值分解SVD 原理+作业_线性代数_82

存在一组正交基V:
奇异值分解SVD 原理+作业_奇异值分解_83
矩阵对其变换后仍是正交基,记为奇异值分解SVD 原理+作业_正交变换_07
奇异值分解SVD 原理+作业_矩阵_85
由正交基定义,得:
奇异值分解SVD 原理+作业_线性代数_86
上式展开:
奇异值分解SVD 原理+作业_机器学习_87
如果我们将奇异值分解SVD 原理+作业_机器学习_88奇异值分解SVD 原理+作业_矩阵_31做矩阵乘法,那么会得到奇异值分解SVD 原理+作业_机器学习_32的一个方阵奇异值分解SVD 原理+作业_正交变换_91.既然奇异值分解SVD 原理+作业_正交变换_91是方阵,那么我们就可以进行特征分解,得到特征向量奇异值分解SVD 原理+作业_机器学习_93和特征向量奇异值分解SVD 原理+作业_线性代数_35。当奇异值分解SVD 原理+作业_机器学习_93奇异值分解SVD 原理+作业_正交变换_91的特征向量时,有:
奇异值分解SVD 原理+作业_矩阵_97
根据奇异值分解SVD 原理+作业_正交变换_98,得到
奇异值分解SVD 原理+作业_机器学习_99
即假设成立 。

图形表示如下:

奇异值分解SVD 原理+作业_矩阵_100

正交向量的模:
奇异值分解SVD 原理+作业_机器学习_101
单位化正交向量,得:
奇异值分解SVD 原理+作业_矩阵_102
结论:当基向量是奇异值分解SVD 原理+作业_线性代数_103的特征向量时,矩阵A转换后的向量也是基向量 。用矩阵的形式表示为
奇异值分解SVD 原理+作业_奇异值分解_104
其中奇异值分解SVD 原理+作业_矩阵_105

V是奇异值分解SVD 原理+作业_正交变换_106矩阵,U是奇异值分解SVD 原理+作业_矩阵_107矩阵,奇异值分解SVD 原理+作业_线性代数_52是M*K的矩阵,需要扩展成方阵形式:
奇异值分解SVD 原理+作业_奇异值分解_104
两式右乘奇异值分解SVD 原理+作业_正交变换_110可得矩阵的奇异值分解
奇异值分解SVD 原理+作业_正交变换_73

2. 流程

用一个简单的例子来说明矩阵是如何进行奇异值分解的。矩阵A定义为:
奇异值分解SVD 原理+作业_机器学习_112
首先求出奇异值分解SVD 原理+作业_正交变换_91奇异值分解SVD 原理+作业_线性代数_114
奇异值分解SVD 原理+作业_正交变换_115
奇异值分解SVD 原理+作业_正交变换_91的特征向量奇异值分解SVD 原理+作业_矩阵_117和特征值奇异值分解SVD 原理+作业_线性代数_35
奇异值分解SVD 原理+作业_线性代数_119
对应的特征值为奇异值分解SVD 原理+作业_正交变换_120,对应的平方根奇异值分解SVD 原理+作业_矩阵_121

奇异值分解SVD 原理+作业_线性代数_114的特征向量奇异值分解SVD 原理+作业_正交变换_07
奇异值分解SVD 原理+作业_奇异值分解_124
所以奇异值分解SVD 原理+作业_矩阵_31的奇异值分解
奇异值分解SVD 原理+作业_正交变换_126

3. 作业

3.1 手动实现SVD

要求

根据课堂讲授的SVD分解方法,用 Python 语言编程实现矩阵的SVD 分解和 thin SVD 表达。

要求:

代码要有规范的注释, 输出以下两个测试例的结果
奇异值分解SVD 原理+作业_奇异值分解_127

第二个
奇异值分解SVD 原理+作业_矩阵_128

代码

import numpy as np


def get_data2():
    return np.array([[2, 0],
                     [0, 1 / np.sqrt(2)],
                     [0, 1 / np.sqrt(2)], ])


def get_data():
    return np.array([[1, 0, 0, 0, 2],
                     [0, 0, 3, 0, 0],
                     [0, 0, 0, 0, 0],
                     [0, 4, 0, 0, 0]])


def get_eigenvalue(A):
    return np.linalg.eigvals(A)


def get_U(A):
    return np.linalg.eig(A.dot(A.T))


def get_V(A):
    return np.linalg.eig(A.T.dot(A))


def SVD():
    sigma, V = get_V(A)
    sigma, V, length = bubble_sort(sigma, V)
    sigma2, U = get_U(A)
    sigma, U, _ = bubble_sort(sigma2, U)
    S = np.zeros((m, n))
    for i in range(length):
        S[i][i] = np.sqrt(sigma[i])

    # print(S)
    # U = np.zeros((m, m))
    # print(U.shape)
    for i in range(length):
        # print((1 / np.sqrt(sigma[i])) * np.dot(A, V[:, i]))
        U[:, i] = (1 / np.sqrt(sigma[i])) * np.dot(A, V[:, i])
    return U, S, V


def bubble_sort(sigma, B):
    """
    对奇异值进行排序
    :param sigma:
    :param B:
    :return:
    """
    length = len(sigma)
    for i in range(length - 1):
        # i表示比较多少轮
        for j in range(length - i - 1):
            if sigma[j] < sigma[j + 1]:
                sigma[j], sigma[j + 1] = sigma[j + 1], sigma[j]
                B[:, [j, j + 1]] = B[:, [j + 1, j]]
    temp = 0
    for i in range(length):
        if sigma[i] > 0:
            temp = temp + 1
    return sigma, B, temp


# 获取数据
A = get_data2()
m = A.shape[0]
n = A.shape[1]
k = min(m, n)

U, S, V = SVD()
temp2 = np.dot(np.dot(U, S), V.T)
print("SVD-- \n U=\n{}\n Z=\n{}\n V=\n{}".format(U, S, V))
print("*" * 10)
print(temp2)

结果

SVD-- 
 U=
[[ 1.          0.          0.        ]
 [ 0.          0.70710678  0.70710678]
 [ 0.          0.70710678 -0.70710678]]
 Z=
[[2. 0.]
 [0. 1.]
 [0. 0.]]
 V=
[[1. 0.]
 [0. 1.]]
**********
[[2.         0.        ]
 [0.         0.70710678]
 [0.         0.70710678]]

3.2 人脸识别

要求

作业2:实现基于奇异值分解的人脸识别。

要求:

  1. 提交可运行的python源码(包括数据集、运行代码、运行结果)。
  2. 撰写WORD文档,说明与分析所用人脸识别方法、原理,实现,测试

数据集介绍

数据集如下:ORL数据集

奇异值分解SVD 原理+作业_线性代数_129

目录结构如下

奇异值分解SVD 原理+作业_线性代数_130

数据集下载

我自己上传的 ORL数据集attrface | Kaggle

官网网址,貌似不能用了https://www.cl.cam.ac.uk/research/dtg/attarchive/facedatabase.html

代码

# 人脸识别是一个分类问题
# svc 支持向量解决分类问题
import cv2
import numpy as np
import os

data_path = r"att_faces"
train_data = []
test_data = []
image = []
sigma_data = []

# 使用50个特征值作为该图像的特征信息
K = 80
print("选取了{}个特征".format(K))


def read_image():
    """
    加载图片信息
    :return:
    """
    global train_data, test_data
    root_path = os.listdir(data_path)
    for d in root_path:
        s_path = os.path.join(data_path, d)
        for idx, image_path in enumerate(os.listdir(s_path)):
            # 因为是二维图,所以是二维的 [112,92]
            img = cv2.imread(os.path.join(s_path, image_path), cv2.IMREAD_GRAYSCALE)
            image.append(img)
    train_data = image[0::2]
    test_data = image[1::2]


def train():
    """
    进行训练,训练的目的就是把40 张图片的所有 特征值提取出来,放进sigma_data
    :return:
    """

    for image in train_data:
        # 数据进行展示
        u, sigma, v = np.linalg.svd(image)
        # 对sigma 从小到大排序
        sigma = np.sort(sigma)
        # 选取特征值K个最大特征值作为Sm_i的特征值
        sigma_data.append(sigma[-K:])

    print("训练结束")


def test():
    """
    用提前准备好的图片 做最近邻算法的比较,和谁的最近邻 小

    :return:
    """
    # 分类正确的个数
    acc = 0
    for idx, image in enumerate(test_data):
        u, sigma, v = np.linalg.svd(image)
        # 对sigma 从小到大排序
        sigma = np.sort(sigma)
        # 选取特征值K个最大特征值作为Sm_i的特征值
        sigma = sigma[-K:]
        m = get_index(sigma)
        raw = int(idx / 5) + 1
        predict = int(m / 5) + 1
        if raw == predict:
            acc += 1
            print("这张图预测为{},预测正确".format(predict, raw))
        else:
            print("这张图预测为{},预测错误,本来是{}".format(predict, raw))

    print("最终准确率{}%,--[{}/{}]".format(100 * acc / len(test_data), acc, len(test_data)))
    # 使用


def get_index(sigma):
    """
    求出最小近邻的 所在是索引值
    :param sigma: 测试图像的前 K 个最大特征值
    :return:
    """
    index = []
    for i in sigma_data:
        # 最小近邻,其实就是求第二范数
        index.append(np.linalg.norm(i - sigma))
    return np.argmin(index)


# 加载数据
read_image()
# print(test_data)

# 训练
train()
# 测试
test()

结果如下

这张图预测为21,预测错误,本来是38
这张图预测为38,预测正确
这张图预测为39,预测正确
这张图预测为39,预测正确
这张图预测为39,预测正确
这张图预测为39,预测正确
这张图预测为39,预测正确
这张图预测为34,预测错误,本来是40
这张图预测为40,预测正确
这张图预测为40,预测正确
这张图预测为40,预测正确
这张图预测为40,预测正确
最终准确率73.0%,--[146/200]

好博客就要一起分享哦!分享海报

此处可发布评论

评论(0展开评论

暂无评论,快来写一下吧

展开评论

您可能感兴趣的博客

客服QQ 1913284695