LAPACK(Linear Algebra PACKage)库,是用Fortran语言编写的线性代数计算库,包含线性方程组求解(AX=B)、矩阵分解、矩阵求逆、求矩阵特征值、奇异值等。该库用BLAS库做底层运算。

本示例将使用MKL中的LAPACK库计算线性最小二乘问题的解,首先简单介绍最小二乘法原理:

引用自https://www.cnblogs.com/pinard/p/5976811.html

最小二乘法其形式如下式:

\[目标函数=\Sigma(观测值-理论值)^2
\]

观测值就是多组样本,理论值就是假设的拟合函数,目标函数也就是在机器学习中常说的损失函数,我们的目标是得到使损失函数最小化时的拟合函数的模型。

以最简单的线性回归为例,比如有\(m\)个样本,表示为\((x^{(1)},y^{(1)}),(x^{(2)},y^{(2)}),\dots (x^{(m)},y^{(m)})\),每个样本都只有一个特征,那么可采用的拟合函数为\(h_{\theta}\left(x\right)=\theta_{0}+\theta_{1} x\),损失函数为

\[J\left( {{\theta _0},{\theta _1}} \right) = \sum\limits_{i = 1}^m {\left( {{y^{(i)}} - {h_\theta }\left( {{x^{(i)}}} \right)} \right)} = \sum\limits_{i = 1}^m {{{\left( {{y^{(i)}} - {\theta _0} - {\theta _1}{x^{(i)}}} \right)}^2}}
\]

要使损失函数最小化,仅需去求满足\(\frac{\partial}{\partial \theta_0} J(\theta_0,\theta_1)=0,\frac{\partial}{\partial \theta_1} J(\theta_0,\theta_1)=0,\dots\)时的\(\theta_j\)即可。

接下来来到矩阵法求解

假设函数\(h_{\theta}\left(x_{1}, x_{2}, \ldots x_{n}\right)=\theta_{0}+\theta_{1} x_{1}+\ldots+\theta_{n-1} x_{n-1}\),为\(m \times 1\)的向量,其矩阵表达形式为:

\[h_{\theta}\left(x\right)=\boldsymbol {X}\theta
\]

其中\(\theta\)为\(n \times 1\)的向量,\(\boldsymbol{X}\)为\(m \times n\)维的矩阵,其中\(m\)代表样本数,\(n\)代表特征数。则损失函数定义为:

\[J(\theta ) = \frac{1}{2}{({\boldsymbol{X}}\theta - {\boldsymbol{Y}})^T}({\boldsymbol{X}}\theta - {\boldsymbol{Y}})
\]

根据最小二乘法原理,损失函数对\(\theta\)求导,结果为:

\[\frac{\partial}{\partial \theta} J(\theta)=\boldsymbol{X}^{T}(\boldsymbol{X} \theta-\boldsymbol{Y})=0
\]

整理后得到

\[\theta=\left(\boldsymbol{X}^{T} \boldsymbol{X}\right)^{-1} \boldsymbol{X}^{T} \boldsymbol{Y}
\]

即只要有输入数据,无需求导也可完成对系数\(\theta\)的求解。

QR分解

实数矩阵的\(QR\)分解就是把矩阵\(A\)分解为一个正交矩阵\(Q\)和一个上三角矩阵\(R\):

即\(A=QR\),其中\(QQ^T=I\)。回到求解最小二乘的最优解\(\theta^*\):

\[\begin{array}{l}
{\theta ^*} = {\left( {{{\bf{X}}^T}{\bf{X}}} \right)^{ - 1}}{{\bf{X}}^T}{\bf{Y}}\\
\Rightarrow {\left( {{{\bf{X}}^T}{\bf{X}}} \right)^{ - 1}}{\theta ^*} = {{\bf{X}}^T}{\bf{Y}}\\
\Rightarrow \left( {{{(QR)}^T}QR} \right){\theta ^*} = {(QR)^T}{\bf{Y}}\\
\Rightarrow \left( {{R^T}{Q^T}QR} \right){\theta ^*} = {R^T}{Q^T}{\bf{Y}}\\
\Rightarrow {R^T}R{\theta ^*} = {R^T}{Q^T}{\bf{Y}}\\
\Rightarrow R{\theta ^*} = {Q^T}{\bf{Y}}\\
\Rightarrow {\theta ^*} = {R^{ - 1}}{Q^T}{\bf{Y}}
\end{array}
\]

其中\(R\)为上三角矩阵,求逆相对容易,从而规避了直接对\({\left( {{{\bf{X}}^T}{\bf{X}}} \right)^{ - 1}}\)求逆的高复杂度问题。

MKL的LAPACK库中LAPACKE_?gels,采用\(QR\)分解完成最小二乘法求解这一过程。

1 参数详解

lapack_int LAPACKE_dgels( matrix_layout,		// 矩阵布局,行优先或列优先
trans, // 指定矩阵A的计算形式。"N":A,"T":A转置,"C":A共轭转置
m, // 矩阵A的行
n, // 矩阵A的列
nrhs, // 矩阵B的列
a, // 矩阵A,在最小二乘问题中即为X矩阵
lda, // A矩阵的第一维
b, // 矩阵B,在最小二乘问题中即为Y矩阵
ldb ); // B矩阵的第一维

2 定义∥Xθ-Y∥

#include <stdlib.h>
#include <stdio.h>
#include "mkl_lapacke.h" // 参数
#define M 6
#define N 4
#define NRHS 2
#define LDA N
#define LDB NRHS
MKL_INT m = M, n = N, nrhs = NRHS, lda = LDA, ldb = LDB, info;

double X[LDA*M] = {							// X矩阵
1.44, -7.84, -4.39, 4.53,
-9.96, -0.28, -3.24, 3.83,
-7.55, 3.24, 6.27, -6.64,
8.34, 8.09, 5.28, 2.06,
7.08, 2.52, 0.74, -2.47,
-5.45, -5.70, -1.19, 4.70
};
double y[LDB*M] = { // y矩阵
8.58, 9.35,
8.26, -4.43,
8.48, -0.70,
-5.28, -0.26,
5.72, -7.36,
8.93, -2.52
};

3 执行求解

LAPACKE_dgels(LAPACK_ROW_MAJOR, 'N', m, n, nrhs, X, lda, y, ldb)

输出为:

完整代码

#include <stdlib.h>
#include <stdio.h>
#include "mkl_lapacke.h" //展示矩阵和向量
extern void print_matrix(const char* desc, MKL_INT m, MKL_INT n, double* a, MKL_INT lda);
extern void print_vector_norm(const char* desc, MKL_INT m, MKL_INT n, double* a, MKL_INT lda); #define M 6
#define N 4
#define NRHS 2
#define LDA N
#define LDB NRHS int main() {
/* Locals */
MKL_INT m = M, n = N, nrhs = NRHS, lda = LDA, ldb = LDB, info;
/* Local arrays */
double X[LDA * M] = {
1.44, -7.84, -4.39, 4.53,
-9.96, -0.28, -3.24, 3.83,
-7.55, 3.24, 6.27, -6.64,
8.34, 8.09, 5.28, 2.06,
7.08, 2.52, 0.74, -2.47,
-5.45, -5.70, -1.19, 4.70
};
double y[LDB * M] = {
8.58, 9.35,
8.26, -4.43,
8.48, -0.70,
-5.28, -0.26,
5.72, -7.36,
8.93, -2.52
}; printf("LAPACKE_dgels (row-major, high-level) Example Program Results\n");
// 求解最小二乘
info = LAPACKE_dgels(LAPACK_ROW_MAJOR, 'N', m, n, nrhs, X, lda, y, ldb);
// 检查收敛
if (info > 0) {
printf("The diagonal element %i of the triangular factor ", info);
printf("of A is zero, so that A does not have full rank;\n");
printf("the least squares solution could not be computed.\n");
exit(1);
}
// 打印
print_matrix("Least squares solution", n, nrhs, y, ldb); print_vector_norm("Residual sum of squares for the solution", m - n, nrhs,
&y[n * ldb], ldb); print_matrix("Details of QR factorization", m, n, X, lda);
exit(0);
} // 展示矩阵、向量
void print_matrix(const char* desc, MKL_INT m, MKL_INT n, double* a, MKL_INT lda) {
MKL_INT i, j;
printf("\n %s\n", desc);
for (i = 0; i < m; i++) {
for (j = 0; j < n; j++) printf(" %6.2f", a[i * lda + j]);
printf("\n");
}
} void print_vector_norm(const char* desc, MKL_INT m, MKL_INT n, double* a, MKL_INT lda) {
MKL_INT i, j;
double norm;
printf("\n %s\n", desc);
for (j = 0; j < n; j++) {
norm = 0.0;
for (i = 0; i < m; i++) norm += a[i * lda + j] * a[i * lda + j];
printf(" %6.2f", norm);
}
printf("\n");
}

MKL库解线性最小二乘问题(LAPACKE_dgels)的更多相关文章

  1. SLAM中的优化理论(一)—— 线性最小二乘

    最近想写一篇系列博客比较系统的解释一下 SLAM 中运用到的优化理论相关内容,包括线性最小二乘.非线性最小二乘.最小二乘工具的使用.最大似然与最小二 乘的关系以及矩阵的稀疏性等内容.一方面是督促自己对 ...

  2. SVD分解及线性最小二乘问题

    这部分矩阵运算的知识是三维重建的数据基础. 矩阵分解 求解线性方程组:,其解可以表示为. 为了提高运算速度,节约存储空间,通常会采用矩阵分解的方案,常见的矩阵分解有LU分解.QR分解.Cholesky ...

  3. MKL库奇异值分解(LAPACKE_dgesvd)

    对任意一个\(m\times n\)的实矩阵,总可以按照SVD算法对其进行分解.即: \[A = U\Sigma V^T \] 其中\(U.V\)分别为\(m\times m.n\times n\)的 ...

  4. [转]Numpy使用MKL库提升计算性能

    from:http://unifius.wordpress.com.cn/archives/5 系统:Gentoo Linux (64bit, Kernel 3.7.1)配置:Intel(R) Cor ...

  5. 如何在 code blocks中使用 mkl库

    为了安装caffe, 所以安装了mkl, 现在想在codeblock的项目中使用mkl. 设置mkl环境变量: mkl安装好后默认是在/opt/intel/mkl中,其中/opt/intel/mkl/ ...

  6. Poj 1061 青蛙的约会(扩展欧几里得解线性同余式)

    一.Description 两只青蛙在网上相识了,它们聊得很开心,于是觉得很有必要见一面.它们很高兴地发现它们住在同一条纬度线上,于是它们约定各自朝西跳,直到碰面为止.可是它们出发之前忘记了一件很重要 ...

  7. 扩展欧几里得,解线性同余方程 逆元 poj1845

    定理:对于任意整数a,b存在一堆整数x,y,满足ax+by=gcd(a,b) int exgcd(int a,int b,int &x,int &y){ ){x=,y=;return ...

  8. BZOJ 4004: [JLOI2015]装备购买 高斯消元解线性基

    BZOJ严重卡精,要加 $long$  $double$ 才能过. 题意:求权和最小的极大线性无关组. 之前那个方法解的线性基都是基于二进制拆位的,这次不行,现在要求一个适用范围更广的方法. 考虑贪心 ...

  9. 使用python解线性矩阵方程(numpy中的matrix类)

    这学期有一门运筹学,讲的两大块儿:线性优化和非线性优化问题.在非线性优化问题这里涉及到拉格朗日乘子法,经常要算一些非常变态的线性方程,于是我就想用python求解线性方程.查阅资料的过程中找到了一个极 ...

  10. MKL库矩阵乘法

    此示例是利用Intel 的MKL库函数计算矩阵的乘法,目标为:\(C=\alpha*A*B+\beta*C\),由函数cblas_dgemm实现: 其中\(A\)为\(m\times k\)维矩阵,\ ...

随机推荐

  1. Go语言实现1024终端游戏-不到400行代码

    先放源码地址,喜欢看源码翻源码,喜欢看文章的继续继续看文章 https://github.com/taadis/go1024 - go1024 使用 go 语言实现的 1024 终端游戏,不到400行 ...

  2. 深度优先及广度优先在Unity中的应用

    说明: 简单总结一下深度优先算法和广度优先算法在Unity中最直观和最多见的使用.这里我所举的例子是应用到Unity中3D 人物的全部骨骼关键的遍历,推广开就是能够对全部物体的层级关系进行简单的遍历. ...

  3. Condition类的signal()方法底层原理

    一.Condition类的signal()方法底层原理 Condition 接口的 signal 方法是用于唤醒一个在 Condition 上等待的线程.与 Object 的 notify 方法类似, ...

  4. JAVA stream集合List<Map>转二维集合Map<String,Map<String,Object>>

    简介 将一个 List<Map> 转换为一个二维的 Map 结构通常意味着我们需要创建一个 Map<K, Map<K, V>>.这里,外部的 Map 使用某个键(比 ...

  5. nginx禁止IP访问,仅供域名访问(域名访问限制不严格漏洞)

    域名访问限制不严格漏洞解决 nginx添加相关配置 通过default_server,在http中最前面加上该配置 server { listen 80 default_server; server_ ...

  6. 使用PyMuPDF对pdf文件插入文字时 遇到配置本地的字体文件缺仍然使用默认Helvetica字体问题

    背景 昨天收到的新需求,一份文件从其他部门发起,进行一些文字填写后盖章,再到我们部门,我们接收到的是pdf文件,所以需要在pdf文件中进行修改,插入当日日期等文字.但有要求字体必须和原文档字体相同. ...

  7. MySQL 中有哪些锁类型?

    MySQL 中有哪些锁类型? 在 MySQL 中,锁是用于管理并发访问的机制,以保证数据一致性和完整性.MySQL 支持多种类型的锁,按照其粒度和用途可以分为以下几类. 1. 按粒度分类 表锁(Tab ...

  8. VUE——环境搭建

    VUE--环境搭建 npm: Nodejs下的包管理器. webpack: 它主要的用途是通过CommonJS的语法把所有浏览器端需要发布的静态资源做相应的准备,比如资源的合并和打包. vue-cli ...

  9. 【经验】VMware|windows更新20H2版本后VMware虚拟机无法开启(禁用Device guard)

    2021/04/27 针对 Windows 10 的功能更新, 版本 20H2. 出现如下报错. 解决方法参考官网:MSDN-<Manage Windows Defender Credentia ...

  10. ARM终端 KylinOS 容器镜像导入排障

    背景信息 电脑:华为擎云L420 CPU:ARM架构,HUAWEI Kirin 9006C OS:Kylin桌面操作系统V10(SP1) Kernel:5.4.96 Docker: 27.5.1 已准 ...