矩阵特征分解介绍及雅克比(Jacobi)方法实现特征值和特征向量的求解(C++/OpenCV/Eigen)
对角矩阵(diagonal matrix):只在主对角线上含有非零元素,其它位置都是零,对角线上的元素可以为0或其它值。形式上,矩阵D是对角矩阵,当且仅当对于所有的i≠j, Di,j= 0. 单位矩阵就是对角矩阵,对角元素全部是1。我们用diag(v)表示一个对角元素由向量v中元素给定的对角方阵。对角矩阵受到关注的部分原因是对角矩阵的乘法计算很高效。计算乘法diag(v)x,我们只需要将x中的每个元素xi放大vi倍。换言之,diag(v)x = v⊙x。计算对角方阵的逆矩阵也很高效。对角方阵的逆矩阵存在,当且仅当对角元素都是非零值,在这种情况下,diag(v)-1=diag([1/v1, …, 1/vn]T)。在很多情况下,我们可以根据任意矩阵导出一些通用的机器学习算法;但通过将一些矩阵限制为对角矩阵,我们可以得到计算代价较低的(并且简明扼要的)算法。
不是所有的对角矩阵都是方阵。长方形的矩阵也有可能是对角矩阵。非方阵的对角矩阵没有逆矩阵,但我们仍然可以高效地计算它们的乘法。对于一个长方形对角矩阵D而言,乘法Dx会涉及到x中每个元素的缩放,如果D是瘦长型矩阵,那么在缩放后的末尾添加一些零;如果D是胖宽型矩阵,那么在缩放后去掉最后一些元素。
对角矩阵性质:
(1)、对角矩阵都是对称矩阵;
(2)、对角矩阵是上三角矩阵(对角线左下方的系数全部为零)及下三角矩阵(对角线右上方的系数全部为零);
(3)、单位矩阵In及零矩阵(即所有元素皆为0的矩阵)恒为对角矩阵。一维的矩阵也恒为对角矩阵;
(4)、一个对角线上元素皆相等的对角矩阵是数乘矩阵,可表示为单位矩阵及一个系数λ的乘积:λI;
(5)、一对角矩阵diag(a1,…,an)的特征值为a1,…,an。而其特征向量为单位向量e1,…,en;
(6)、一对角矩阵diag(a1,…,an)的行列式为a1,…,an的乘积。
对称(symmetric)矩阵:在线性代数中,对称矩阵是一个方形矩阵,其转置矩阵和自身相等:A=AT。
对称矩阵中的右上至左下方向元素以主对角线(左上至右下)为轴进行对称。若将其写作A=(aij),则:aij=aji.
当某些不依赖参数顺序的双参数函数生成元素时,对称矩阵经常会出现。例如,如果A是一个距离度量矩阵,Ai,j表示i到点j的距离,那么Ai,j=Aj,i,因为距离函数是对称的。
对称矩阵特性:
(1)、对于任何方形矩阵X,X+XT是对称矩阵;
(2)、A为方形矩阵是A为对称矩阵的必要条件;
(3)、对角矩阵都是对称矩阵;
(4)、两个对称矩阵的积是对称矩阵,当且仅当两者的乘法可交换。两个实对称矩阵乘法可交换当且仅当两者的特征空间相同;
(5)、如果X是对称矩阵,那么AXAT也是对称矩阵。
单位向量(unit vector)是具有单位范数(unit norm)的向量:‖x‖2=1.
如果xTy=0,那么向量x和向量y互相正交(orthogonal)。如果两个向量都有非零范数,那么这两个向量之间的夹角是90度。在Rn中,至多有n个范数非零向量互相正交。如果这些向量不仅互相正交,并且范数都为1,那么我们称它们是标准正交(orthogonal)。
正交矩阵(orthogonal matrix)是指行向量和列向量是分别标准正交的方阵:ATA=AAT=I.这意味着A-1=AT.所以正交矩阵受到关注是因为求逆计算代价小。
正交是线性代数的概念,是垂直这一直观概念的推广。作为一个形容词,只有在一个确定的内积空间(内积空间是数学中线性代数里的基本概念,是增添了一个额外的结构的向量空间。这个额外的结构叫做内积或标量积。内积将一对向量与一个标量连接起来,允许我们严格地谈论向量的”夹角”和”长度”,并进一步讨论向量的正交性)中才有意义。若内积空间中两向量的内积为0,则称它们是正交的。如果能够定义向量间的夹角,则正交可以直观的理解为垂直。
标准正交基:在线性代数中,一个内积空间的正交基(orthogonal basis)是元素两两正交的基。称基中的元素为基向量。假若,一个正交基的基向量的模长都是单位长度1,则称这正交基为标准正交基或”规范正交基”(orthogonal basis)。
正交矩阵:在矩阵论中,正交矩阵(orthogonal matrix)是一个方块矩阵Q,其元素为实数,而且行与列皆为正交的单位向量,使得该矩阵的转置矩阵为其逆矩阵:QT=Q-1ó QTQ=QQT=I.其中,I为单位矩阵。正交矩阵的行列式值必定为+1或-1。
旋转矩阵(Rotation matrix):是在乘以一个向量的时候有改变向量的方向但不改变大小的效果并保持了手性的矩阵。旋转可分为主动旋转与被动旋转。主动旋转是指将向量逆时针围绕旋转轴所做出的旋转。被动旋转是对坐标轴本身进行的逆时针旋转,它相当于主动旋转的逆操作。
旋转矩阵性质:设M是任何维的一般旋转矩阵:M∈Rn*n
(1)、两个向量的点积(内积)在它们都被一个旋转矩阵操作之后保持不变:a·b=Ma·Mb;
(2)、从而得出旋转矩阵的逆矩阵是它的转置矩阵:MM-1=MMT=I 这里的I是单位矩阵;
(3)、一个矩阵是旋转矩阵,当且仅当它是正交矩阵并且它的行列式是单位一。正交矩阵的行列式是±1;则它包含了一个反射而不是真旋转矩阵;
(4)、旋转矩阵是正交矩阵,如果它的列向量形成Rn的一个正交基,就是说在任何两个列向量之间的标量积是零(正交性)而每个列向量的大小是单位一(单位向量);
在二维空间中,旋转可以用一个单一的角θ定义。作为约定,正角表示逆时针旋转。把笛卡尔坐标的列向量关于原点逆时针旋转θ的矩阵是:
特征分解(eigen decomposition)是使用最广的矩阵分解之一,即我们将矩阵分解成一组特征向量和特征值。
方阵A的特征向量(eigen vector)是指与A相乘后相当于对该向量进行缩放的非零向量v:Av=λv。标量λ被称为这个特征向量对应的特征值(eigenvalue)。(类似地,我们也可以定义左特征向量(left eigen vector) vTA=λVT,但是通常我们更关注右特征向量(right eigen vector))。
如果v是A的特征向量,那么任何缩放后的向量sv(s∈R,s≠0)也是A的特征向量。此外,sv和v有相同的特征值。基于这个原因,通常我们只考虑单位特征向量。
假设矩阵A有n个线性无关的特征向量{v(1),…,v(n)},对应着特征值{λ1,…,λn}。我们将特征向量连接成一个矩阵,使得每一列是一个特征向量:V=[v(1),…,v(n)].类似地,我们也可以将特征值连接成一个向量λ=[λ1,…,λn]T。因此A的特征分解(eigen decomposition)可以记作:A=Vdiag(λ)V-1。
不是每一个矩阵都可以分解成特征值和特征向量。在某些情况下,特征分解存在,但是会涉及到复数,而非实数。每个实对称矩阵都可以分解成实特征向量和实特征值:A=QΛQT。其中Q是A的特征向量组成的正交矩阵,Λ是对角矩阵。特征值Λi,i对应的特征向量是矩阵Q的第i列,记作Q:,i。因为Q是正交矩阵,我们可以将A看作是沿方向v(i)延展λi倍的空间。
虽然任意一个实对称矩阵A都有特征分解,但是特征分解可能并不唯一。如果两个或多个特征向量拥有相同的特征值,那么在由这些特征向量产生的生成子空间中,任意一组正交向量都是该特征值对应的特征向量。因此,我们可以等价地从这些特征向量中构成Q作为替代。按照惯例,我们通常按降序排列Λ的元素。在该约定下,特征分解唯一当且仅当所有的特征值都是唯一的。
矩阵的特征分解给了我们很多关于矩阵的有用信息。矩阵是奇异的当且仅当含有零特征值。实对称矩阵的特征分解也可以用于优化二次方程f(x)=xTAx,其中限制‖x‖2=1。当x等于A的某个特征向量时,f将返回对应的特征值。在限制条件下,函数f的最大值是最大特征值,最小值是最小特征值。
所有特征值都是正数的矩阵被称为正定(positive definite);所有特征值都是非负数的矩阵被称为半正定(positive semidefinite)。同样地,所有特征值都是负数的矩阵被称为负定(negative definite);所有特征值都是非正数的矩阵被称为半负定(negative semidefinite)。半正定矩阵受到关注是因为它们保证Ⅴx,xTAx≥0。此外,正定矩阵还保证xTAx=0 =>x=0。
特征分解:线性代数中,特征分解(Eigende composition),又称谱分解(Spectral decomposition)是将矩阵分解为由其特征值和特征向量表示的矩阵之积的方法。需要注意只有对可对角化矩阵(如果一个方块矩阵A相似于对角矩阵,也就是说,如果存在一个可逆矩阵P使得P-1AP是对角矩阵,则它就被称为可对角化的)才可以施以特征分解。
特征值和特征向量:在数学上,特别是线性代数中,对于一个给定的线性变换(在数学中,线性映射(有的书上将”线性变换”作为其同义词,有的则不然)是在两个向量空间(包括由函数构成的抽象的向量空间)之间的一种保持向量加法和标量乘法的特殊映射。设V和W是在相同域K上的向量空间。法则f:V→W被称为是线性映射,如果对于V中任何两个向量x和y与K中任何标量a,满足下列两个条件:可加性:f(x+y)=f(x)+f(y);齐次性:f(ax)=af(x);这等价于要求对于任何向量x1,…,xm和标量a1,…,am,方程f(a1x1+…+amxm)=a1f(x1)+…+amf(xm)成立)A,它的特征向量(eigen vector,也译固有向量或本征向量)v经过这个线性变换之后,得到的新向量与原来的v保持在同一条直线上,但其长度或方向也许会改变。即Av=λv,λ为标量,即特征向量的长度在该线性变换下缩放的比例,称λ为其特征值(本征值)。如果特征值为正,则表示v在经过线性变换的作用后方向也不变;如果特征值为负,说明方向会反转;如果特征值为0,则是表示缩回零点。但无论怎样,仍在同一条直线上。在一定条件下(如其矩阵形式为实对称矩阵的线性变换),一个变换可以由其特征值和特征向量完全表述。
以上内容摘自 《深度学习中文版》 和 维基百科
通过雅克比(Jacobi)方法求实对称矩阵的特征值和特征向量操作步骤:S′=GTSG,其中G是旋转矩阵,S′和S均为实对称矩阵,S′和S有相同的Frobenius norm,可以用一个最简单的3维实对称矩阵为例,根据公式进行详细推导(参考 维基百科 ):
通过旋转矩阵将对称矩阵转换为近似对角矩阵,进而求出特征值和特征向量,对角矩阵中主对角元素即为S近似的实特征值。Jacobi是通过迭代方法计算实对称矩阵的特征值和特征向量。
(1)、初始化特征向量V为单位矩阵;
(2)、初始化特征值eigenvalues为矩阵S主对角线元素;
(3)、将二维矩阵S赋值给一维向量A;
(4)、查找矩阵S中,每行除主对角元素外(仅上三角部分)绝对值最大的元素的索引赋给indR;
(5)、查找矩阵S中,第k列,前k个元素中绝对值最大的元素的索引赋给indC;
(6)、查找pivot的索引(k, l),并获取向量A中绝对值最大的元素p;
(7)、如果p的绝对值小于设定的阈值则退出循环;
(8)、计算sinθ(s)和cosθ(c)的值;
(9)、更新(k, l)对应的A和eigenvalues的值;
(10)、旋转A的(k,l);
(11)、旋转特征向量V的(k,l);
(12)、重新计算indR和indC;
(13)、循环执行以上(6)~(12)步,直到达到最大迭代次数,OpenCV中设置迭代次数为n*n*30;
(14)、如果需要对特征向量和特性值进行sort,则执行sort操作。
以下是分别采用C++(参考opencv sources/modules/core/src/lapack.cpp)和OpenCV实现的求取实对称矩阵的特征值和特征向量:
#include "funset.hpp"
#include <math.h>
#include <iostream>
#include <string>
#include <vector>
#include <opencv2/opencv.hpp>
#include "common.hpp"template<typename _Tp>
static inline _Tp hypot(_Tp a, _Tp b)
{a = std::abs(a);b = std::abs(b);if (a > b) {b /= a;return a*std::sqrt(1 + b*b);}if (b > 0) {a /= b;return b*std::sqrt(1 + a*a);}return 0;
}template<typename _Tp>
int eigen(const std::vector<std::vector<_Tp>>& mat, std::vector<_Tp>& eigenvalues, std::vector<std::vector<_Tp>>& eigenvectors, bool sort_ = true)
{auto n = mat.size();for (const auto& m : mat) {if (m.size() != n) {fprintf(stderr, "mat must be square and it should be a real symmetric matrix\n");return -1;}}eigenvalues.resize(n, (_Tp)0);std::vector<_Tp> V(n*n, (_Tp)0);for (int i = 0; i < n; ++i) {V[n * i + i] = (_Tp)1;eigenvalues[i] = mat[i][i];}const _Tp eps = std::numeric_limits<_Tp>::epsilon();int maxIters{ (int)n * (int)n * 30 };_Tp mv{ (_Tp)0 };std::vector<int> indR(n, 0), indC(n, 0);std::vector<_Tp> A;for (int i = 0; i < n; ++i) {A.insert(A.begin() + i * n, mat[i].begin(), mat[i].end());}for (int k = 0; k < n; ++k) {int m, i;if (k < n - 1) {for (m = k + 1, mv = std::abs(A[n*k + m]), i = k + 2; i < n; i++) {_Tp val = std::abs(A[n*k + i]);if (mv < val)mv = val, m = i;}indR[k] = m;}if (k > 0) {for (m = 0, mv = std::abs(A[k]), i = 1; i < k; i++) {_Tp val = std::abs(A[n*i + k]);if (mv < val)mv = val, m = i;}indC[k] = m;}}if (n > 1) for (int iters = 0; iters < maxIters; iters++) {int k, i, m;// find index (k,l) of pivot pfor (k = 0, mv = std::abs(A[indR[0]]), i = 1; i < n - 1; i++) {_Tp val = std::abs(A[n*i + indR[i]]);if (mv < val)mv = val, k = i;}int l = indR[k];for (i = 1; i < n; i++) {_Tp val = std::abs(A[n*indC[i] + i]);if (mv < val)mv = val, k = indC[i], l = i;}_Tp p = A[n*k + l];if (std::abs(p) <= eps)break;_Tp y = (_Tp)((eigenvalues[l] - eigenvalues[k])*0.5);_Tp t = std::abs(y) + hypot(p, y);_Tp s = hypot(p, t);_Tp c = t / s;s = p / s; t = (p / t)*p;if (y < 0)s = -s, t = -t;A[n*k + l] = 0;eigenvalues[k] -= t;eigenvalues[l] += t;_Tp a0, b0;#undef rotate
#define rotate(v0, v1) a0 = v0, b0 = v1, v0 = a0*c - b0*s, v1 = a0*s + b0*c// rotate rows and columns k and lfor (i = 0; i < k; i++)rotate(A[n*i + k], A[n*i + l]);for (i = k + 1; i < l; i++)rotate(A[n*k + i], A[n*i + l]);for (i = l + 1; i < n; i++)rotate(A[n*k + i], A[n*l + i]);// rotate eigenvectorsfor (i = 0; i < n; i++)rotate(V[n*k+i], V[n*l+i]);#undef rotatefor (int j = 0; j < 2; j++) {int idx = j == 0 ? k : l;if (idx < n - 1) {for (m = idx + 1, mv = std::abs(A[n*idx + m]), i = idx + 2; i < n; i++) {_Tp val = std::abs(A[n*idx + i]);if (mv < val)mv = val, m = i;}indR[idx] = m;}if (idx > 0) {for (m = 0, mv = std::abs(A[idx]), i = 1; i < idx; i++) {_Tp val = std::abs(A[n*i + idx]);if (mv < val)mv = val, m = i;}indC[idx] = m;}}}// sort eigenvalues & eigenvectorsif (sort_) {for (int k = 0; k < n - 1; k++) {int m = k;for (int i = k + 1; i < n; i++) {if (eigenvalues[m] < eigenvalues[i])m = i;}if (k != m) {std::swap(eigenvalues[m], eigenvalues[k]);for (int i = 0; i < n; i++)std::swap(V[n*m+i], V[n*k+i]);}}}eigenvectors.resize(n);for (int i = 0; i < n; ++i) {eigenvectors[i].resize(n);eigenvectors[i].assign(V.begin() + i * n, V.begin() + i * n + n);}return 0;
}int test_eigenvalues_eigenvectors()
{std::vector<float> vec{ 1.23f, 2.12f, -4.2f,2.12f, -5.6f, 8.79f,-4.2f, 8.79f, 7.3f };const int N{ 3 };fprintf(stderr, "source matrix:\n");int count{ 0 };for (const auto& value : vec) {if (count++ % N == 0) fprintf(stderr, "\n");fprintf(stderr, " %f ", value);}fprintf(stderr, "\n\n");fprintf(stderr, "c++ compute eigenvalues and eigenvectors, sort:\n");std::vector<std::vector<float>> eigen_vectors1, mat1;std::vector<float> eigen_values1;mat1.resize(N);for (int i = 0; i < N; ++i) {mat1[i].resize(N);for (int j = 0; j < N; ++j) {mat1[i][j] = vec[i * N + j];}}if (eigen(mat1, eigen_values1, eigen_vectors1, true) != 0) {fprintf(stderr, "campute eigenvalues and eigenvector fail\n");return -1;}fprintf(stderr, "eigenvalues:\n");std::vector<std::vector<float>> tmp(N);for (int i = 0; i < N; ++i) {tmp[i].resize(1);tmp[i][0] = eigen_values1[i];}print_matrix(tmp);fprintf(stderr, "eigenvectors:\n");print_matrix(eigen_vectors1);fprintf(stderr, "c++ compute eigenvalues and eigenvectors, no sort:\n");if (eigen(mat1, eigen_values1, eigen_vectors1, false) != 0) {fprintf(stderr, "campute eigenvalues and eigenvector fail\n");return -1;}fprintf(stderr, "eigenvalues:\n");for (int i = 0; i < N; ++i) {tmp[i][0] = eigen_values1[i];}print_matrix(tmp);fprintf(stderr, "eigenvectors:\n");print_matrix(eigen_vectors1);fprintf(stderr, "\nopencv compute eigenvalues and eigenvectors:\n");cv::Mat mat2(N, N, CV_32FC1, vec.data());cv::Mat eigen_values2, eigen_vectors2;bool ret = cv::eigen(mat2, eigen_values2, eigen_vectors2);if (!ret) {fprintf(stderr, "fail to run cv::eigen\n");return -1;}fprintf(stderr, "eigenvalues:\n");print_matrix(eigen_values2);fprintf(stderr, "eigenvectors:\n");print_matrix(eigen_vectors2);return 0;
}
执行结果如下:以下是采用Eigen实现的求取特征值和特征向量的code:
#include "funset.hpp"
#include <math.h>
#include <iostream>
#include <vector>
#include <string>
#include <opencv2/opencv.hpp>
#include <Eigen/Dense>
#include "common.hpp"int test_eigenvalues_eigenvectors()
{std::vector<float> vec{ 1.23f, 2.12f, -4.2f,2.12f, -5.6f, 8.79f,-4.2f, 8.79f, 7.3f };const int N{ 3 };fprintf(stderr, "source matrix:\n");print_matrix(vec.data(), N, N);fprintf(stderr, "\n");Eigen::Map<Eigen::MatrixXf> m(vec.data(), N, N);Eigen::EigenSolver<Eigen::MatrixXf> es(m);Eigen::VectorXf eigen_values = es.eigenvalues().real();fprintf(stderr, "eigen values:\n");print_matrix(eigen_values.data(), N, 1);Eigen::MatrixXf eigen_vectors = es.eigenvectors().real();fprintf(stderr, "eigen vectors:\n");print_matrix(eigen_vectors.data(), N, N);return 0;
}
执行结果如下:GitHub:
https://github.com/fengbingchun/NN_Test
https://github.com/fengbingchun/Eigen_Test
相关文章:
Entity Framework CodeFirst数据迁移
原文:Entity Framework CodeFirst数据迁移前言 紧接着前面一篇博文Entity Framework CodeFirst尝试。 我们知道无论是“Database First”还是“Model First”当模型发生改变了都可以通过Visual Studio设计视图进行更新,那么对于Code First如何更新已有的模型呢&…
限时早鸟票 | 2019 中国大数据技术大会(BDTC)超豪华盛宴抢先看!
2019 年12月5-7 日,由中国计算机学会主办,CCF 大数据专家委员会承办,CSDN、中科天玑数据科技股份有限公司协办的 2019 中国大数据技术大会,将于北京长城饭店隆重举行。届时,超过百位技术专家及行业领袖将齐聚于此&…

Google AI 系统 DeepMind无法通过 高中数学
Google 旗下 DeepMind 团队让 AI 系统接受一项高中程度的数学测试,结果在 40 道题目中只答对了 14 题,甚至连「1111111」也算错了。说来难以置信,Google AI 系统能打败人类世界棋王,却无法通过高中程度的数学考试。上周࿰…

C++11中std::tuple的使用
std::tuple是类似pair的模板。每个pair的成员类型都不相同,但每个pair都恰好有两个成员。不同std::tuple类型的成员类型也不相同,但一个std::tuple可以有任意数量的成员。每个确定的std::tuple类型的成员数目是固定的,但一个std::tuple类型的…

PHP Countable接口
实现该接口可以使用count()方法来获取集合的总数转载于:https://www.cnblogs.com/xiaodo0/p/3611307.html
矩阵奇异值分解简介及C++/OpenCV/Eigen的三种实现
奇异值分解(singular value decomposition, SVD):将矩阵分解为奇异向量(singular vector)和奇异值(singular value)。通过奇异值分解,我们会得到一些与特征分解相同类型的信息。然而,奇异值分解有更广泛的应用。每个实数矩阵都有一个奇异值分…

经典!工业界深度推荐系统与CTR预估必读的论文汇总
(图片付费下载自视觉中国)来源 | 深度传送门(ID: gh_5faae7b50fc5)导读:本文是“深度推荐系统”专栏的第十一篇文章,这个系列将介绍在深度学习的强力驱动下,给推荐系统工业界所带来的最前沿的变…

docker上传自己的镜像
https://blog.csdn.net/boonya/article/details/74906927 需要注意的就是命名规范 docker push 注册用户名/镜像名 tag命令修改为规范的镜像: docker tag boonya/tomcat-allow-remote boonyadocker/tomcat-allow-remote转载于:https://www.cnblogs.com/MC-Curry/p/1…

多个class相同的input标签 获取当前值!方法!
2019独角兽企业重金招聘Python工程师标准>>> var a $(this).prev( ".你的class" ).val(); 转载于:https://my.oschina.net/u/1169079/blog/210082

C++11中std::forward_list单向链表的使用
std::forward_list是在C11中引入的单向链表或叫正向列表。forward_list具有插入、删除表项速度快、消耗内存空间少的特点,但只能向前遍历。与其它序列容器(array、vector、deque)相比,forward_list在容器内任意位置的成员的插入、提取(extracting)、移动…

即学即用的30段Python实用代码
(图片付费下载自视觉中国)原标题 | 30 Helpful Python Snippets That You Can Learn in 30 Seconds or Less作 者 | Fatos Morina翻 译 | Pita & AI开发者Python是目前最流行的语言之一,它在数据科学、机器学习、web开发、脚本编写、自…

如何配置IntelliJ IDEA发布JavaEE项目?
一、以war的形式运行项目 步骤1 新建或者导入项目后,选择File菜单-》Project Structure...,如下图: 步骤2 配置项目类型,名字可以自定义: 说明:这里的Artifact如果没有配置好的话,配置Tomcat时没…

网络分布式软件bonic清除
近期,有一款网格计算软件,在很多服务器上进行了部署,利用cpu进行运算。虽然未构成安全隐患,但是比较消耗资源,影响设备正常运行。今天对设备彻底检查,发现了一个分布式计算软件boinc,他是利用网…

C++/C++11中std::list双向链表的使用
std::list是双向链表,是一个允许在序列中任何一处位置以常量耗时插入或删除元素且可以双向迭代的顺序容器。std::list中的每个元素保存了定位前一个元素及后一个元素的信息,允许在任何一处位置以常量耗时进行插入或删除操作,但不能进行直接随…

React组件设计之边界划分原则
简述 结合SOLID中的单一职责原则来进行组件的设计 Do one thing and do it well javaScript作为一个弱类型并在函数式和面对对象的领域里疯狂试探语言。SOLID原则可能与其他语言例如(java)的表现可能是不同的。不过作为软件开发领域通用的原则࿰…

阿里AI labs发布两大天猫精灵新品,将与平头哥共同定制智能语音芯片
作者 | 夕颜出品 | AI科技大本营(ID:rgznai100)2019 年,去年刮起的一阵智能音箱热浪似乎稍微冷却下来,新产品不再像雨后春笋一样层出不穷,挺过市场洗礼的产品更是凤毛麟角,这些产品的性能、技术支持和体验基…

js 中文匹配正则
为什么80%的码农都做不了架构师?>>> /^[\u4e00-\u9fa5]{2,4}$/gi.test() 匹配中文正则 转载于:https://my.oschina.net/fedde/blog/211852
Caffe中对cifar10执行train操作
参考Caffe source中examples/cifar10目录下内容。cifar10是一个用于普通物体识别的数据集,cifar10被分为10类,分别为airplane、automobile、bird、cat、deer、dog、frog、horse、ship、truck,关于cifar10的详细介绍可以参考: http://blog.csd…

解决掉这些痛点和难点,让知识图谱不再是“噱头”
(图片付费下载自视觉中国)作者| 夕颜出品| AI科技大本营(ID:rgznai100)2012 年,谷歌正式提出知识图谱的概念,当时,研究人员的主要目的是用来优化搜索引擎技术。今年初,谷歌前员工&am…

mongodb使用常用语法,持续更新
设置快捷命令D:\mongodb4.0.8\bin>mongod --config "D:\mongodb4.0.8\mongo.conf" --auth --install --serviceName "MongoDB"mongodb配置文件#数据库路径dbpathD:\mongodb4.0.8\data\db#日志输出文件路径logpathD:\mongodb4.0.8\data\log\MongoDB.log#…
Android之NDK开发的简单实例
NDK全称为Native Development Kit,是本地开发工具集。在Android开发中,有时为了能更好的重用以前的C/C的代码,需要将这些代码编译成相应的so,然后通地JNI以供上层JAVA调用。当然,也有的是为了更高的保护性和安全性。下…

阿里披露AI完整布局,飞天AI平台首次亮相
作者 | 夕颜编辑 | 唐小引出品 | AI 科技大本营(ID:rgznai100)9 月 26 日上午,在云栖大会阿里云飞天智能主论坛上,年轻的阿里巴巴副总裁、阿里云智能计算平台事业部总经理、高级研究员贾扬清与其在 Facebook 的老同事—— Faceboo…
使用Caffe基于cifar10进行物体识别
在http://blog.csdn.net/fengbingchun/article/details/72953284中对cifar10进行train,这里通过train得到的model,对图像进行识别。cifar10数据集共包括10类,按照0到9的顺序依次为airplane(飞机)、automobile(轿车)、bird(鸟)、cat(猫)、deer…

SoJpt Boot 2.3-3.8 发布,Spring Boot 使用 Jfinal 特性极速开发
SoJpt Boot 2.3-3.8 发布了。SoJpt Boot 基于 JFinal 与 Spring Boot制作, 实现了 Spring Boot 与 Jfinal 的混合双打,使 Spring Boot 下的开发者能够体验 Jfinal 的极速开发特性。新版更新内容如下: SoJpt-Boot-2.3-3.8 changelog 1、加入事务注解,Tx(value"c…

PL/SQL程序设计 第七章 包的创建和应用
7.1 引言包是一组相关过程、函数、变量、常量和游标等PL/SQL程序设计元素的组合,它具有面向对象程序设计语言的特点,是对这些PL/SQL 程序设计元素的封装。包类似于C和JAVA语言中的类,其中变量相当于类中的成员变量,过程和函数相当…

C++11中头文件chrono的使用
在C11中,<chrono>是标准模板库中与时间有关的头文件。该头文件中所有函数与类模板均定义在std::chrono命名空间中。 std::chrono是在C11中引入的,是一个模板库,用来处理时间和日期的Time library。要使用chrono库,需要incl…

为什么平头哥做芯片如此迅猛?
作者 | 胡巍巍 发自杭州云栖大会责编 | 唐小引来源 | CSDN(ID:CSDNnews)2018年10月31日,阿里旗下的平头哥半导体有限公司成立。如今,平头哥成立不到一年,就已成绩斐然。2019年9月25日,阿里巴巴旗…

Vue 组件库 heyui@1.18.0 发布,新增地址选择、图片预览组件
开发四年只会写业务代码,分布式高并发都不会还做程序员? 新增 CategoryPicker 新增组件 CategoryPicker,地址级联组件的最佳方案。 <CategoryPicker :option"option" v-model"value"/> 相关文档 ImagePreview 新…

HTML5 Dashboard – 那些让你激动的 Web 技术
HTML5 Dashboard 是一个 Mozilla 推出的项目,里面展示了最前沿的 HTML5,CSS3,JavaScript 技术。每一项技术都有简洁,在线演示以及详细的文档链接。这些技术将成为未来一段时间 Web 开发的顶尖技术,如果不想落伍的话就赶…

计算机解决问题没有奇技淫巧,但动态规划还是有点套路
作者 | labuladong来源 | labuladong(ID:labuladong) 【导读】动态规划算法似乎是一种很高深莫测的算法,你会在一些面试或算法书籍的高级技巧部分看到相关内容,什么状态转移方程,重叠子问题,最优子结构等高…