TensorFlow - 使用Eigen进行矩阵计算
flyfish
假设不使用Eigen,是怎样的方式
首先include一些头文件
#include <utility>
#include <vector>
#include <cmath>
#include <limits>
#include <random>
#include "boost\align\aligned_allocator.hpp"
typedef std::vector<double_t, boost::alignment::aligned_allocator<double_t, 128>> Tensor1D;`这里写代码片`
typedef std::vector<Tensor1D> Tensor2D;
//按照128位进行对齐
//根据硬件平台double_t是double 还是long double
//double_t 在corecrt_math.h头文件里
SE或者AltiVec指令集,向量化必须要求向量是以16字节即128bit对齐的方式分配内存空间
声明函数
void Randn(Tensor2D& t);//
void InitData(Tensor2D& t, int row, int col);
void Concatenate(Tensor2D& result, Tensor2D& a, Tensor2D& b);//列相等 两个矩阵的.连结
void MatirxDot(Tensor2D& result, Tensor2D& a, Tensor2D& b); //矩阵乘法
void MatirxAddBias(Tensor2D& result, Tensor2D& a, Tensor2D& b);//矩阵+1维偏置
void ElementWise(Tensor2D& result, Tensor2D& a, Tensor2D& b);//element-wise乘积
实现函数
void Randn(Tensor2D& t)
{
std::random_device rd; //Will be used to obtain a seed for the random number engine
std::mt19937 gen(rd());
std::normal_distribution<double> dis(0.0f, 1.0f);//使用正太分布生成数据
for (auto& v : t)
{
for (auto& i = v.begin(); i != v.end(); ++i)
{
(*i) = dis(gen);
}
}
}
void InitData(Tensor2D& t, int row, int col)
{
t.resize(row);//行大小
for (int j = 0; j < row; ++j)
t[j].resize(col);//列大小
Randn(t);
}
void Concatenate(Tensor2D& result, Tensor2D& a, Tensor2D& b)
{
result.insert(result.end(), a.begin(), a.end());
result.insert(result.end(), b.begin(), b.end());
}
void MatirxDot(Tensor2D& result, Tensor2D& a, Tensor2D& b)
{
//第一个矩阵第一行的每个数字,各自乘以第二个矩阵第一列对应位置的数字,然后将乘积相加
//只有在第一个矩阵的列数(column)和第二个矩阵的行数(row)相同时才有意义
//举例
//wf 5行8列
//cancate 8行 10列 第一个矩阵的列数(column)和第二个矩阵的行数(row
//
//结果是a的行数,b的列数
int row = a.size();
int col = b.size();
//假设不为空
Tensor2D r(row, Tensor1D(col, 0));
//a[m][x]
//b[x][n]
int m= row;
int n=a[0].size();
int x = col;;
for (int i = 0; i<m; i++)
for (int j = 0; j<n; j++)
{
for (int k = 0; k<x; k++) //k运行3次
r[i][j] =r[i][j] + a[i][k] * b[k][j]; //a的第i行与b的第j列相乘
}
result.insert(result.end(), r.begin(), r.end());
}
void MatirxAddBias(Tensor2D& result, Tensor2D& matrix, Tensor2D& bias)
{
//行数相等,列不同的情况
//import numpy as np
// A = np.array([[1, 1, 2], [3, 4, 5]])
// X = np.array([[5], [3]])
// print(A.shape)
// print(X.shape)
// print(A + X)
// (2, 3)
// (2, 1)
// [[6 6 7]
// [6 7 8]]
//bias 默认情况下只有一列
int n = 0;
for (auto& v : matrix)
{
for (size_t i=0;i<v.size(); i++)
{
v[i] = v[i] + bias[n][0];
}
n++;
}
result.insert(result.end(), matrix.begin(), matrix.end());
}
void ElementWise(Tensor2D& result, Tensor2D& a, Tensor2D& b)
{
//a==b 还需要处理a和b的大小
int m = a.size();
int n = a[0].size();
for (int i=0;i<m;i++)
for (int j = 0; j < n; j++)
{
result[i][j] = a[i][j] * b[i][j];
}
}
数学函数例如
void tanh_forward(Tensor2D &y,const Tensor2D &x) {
for (auto& i : x)
{
Tensor1D y1;
tanh_forward(y1, i);
y.push_back(y1);
}
}
void tanh_forward(Tensor1D &y,const Tensor1D &x)
{
for (size_t j = 0; j < x.size(); j++)
{
y.push_back(std::tanh(x[j]));
}
}
void tanh_backward(const Tensor1D &x,const Tensor1D &y,Tensor1D &dx,const Tensor1D &dy)
{
for (size_t j = 0; j < x.size(); j++) {
// dx = dy * (gradient of tanh)
dx[j] = dy[j] * (double(1) - std::pow(y[j], 2));
}
}
void sigmond_forward(Tensor2D &y,const Tensor2D &x )
{ //y是返回值
for (auto& i : x)
{
Tensor1D y1;
sigmond_forward(y1, i);
y.push_back(y1);
}
}
void sigmond_forward(Tensor1D &y,const Tensor1D &x)
{
for (size_t j = 0; j < x.size(); j++)
{
y.push_back(float_t(1) / (float_t(1) + std::exp(-x[j])));
}
}
void sigmond_backward(const Tensor1D &x,const Tensor1D &y,Tensor1D &dx,const Tensor1D &dy) {
for (size_t j = 0; j < x.size(); j++) {
// dx = dy * (gradient of sigmoid)
dx[j] = dy[j] * y[j] * (float_t(1) - y[j]);
}
}
使用方法
int row = 3;
int col = 4;
Tensor2D test(row, Tensor1D(col, 0));//初始3行4列数据 ,数值全部为0
Tensor2D xt;//(3, 10)
Tensor2D a_prev;//(5, 10)
Tensor2D c_prev;//(5, 10)
Tensor2D Wf;//(5, 5 + 3)
Tensor2D bf;//(5, 1)
Tensor2D Wi;//(5, 5 + 3)
Tensor2D bi;//(5, 1)
Tensor2D Wo;//(5, 5 + 3)
Tensor2D bo;//(5, 1)
Tensor2D Wc;//(5, 5 + 3)
Tensor2D bc;//(5, 1)
Tensor2D Wy;//(2, 5)
Tensor2D by;//(2, 1)
//Concatenate a_prev and xt
InitData(xt, 3, 10);
InitData(a_prev, 5, 10);
InitData(c_prev, 5, 10);
InitData(Wf, 5, 5 + 3);
InitData(bf, 5, 1);
InitData(Wi, 5, 5 + 3);
InitData(bi, 5, 1);
InitData(Wo, 5, 5 + 3);
InitData(bo, 5, 1);
InitData(Wc, 5, 5 + 3);
InitData(bc, 5, 1);
InitData(Wy, 2, 5);
InitData(by, 2, 1);
Tensor2D concate;
Concatenate(concate, a_prev, xt);
//
Tensor2D m11;//5行 8列
MatirxDot(m11, Wf, concate);
Tensor2D m21;//5行 8列
MatirxAddBias(m21, m11, bf);
Tensor2D ft;//5行 8列
sigmond_forward(ft, m21);
//
Tensor2D m12;//5行 8列
MatirxDot(m12, Wi, concate);
Tensor2D m22;//5行 8列
MatirxAddBias(m22, m12, bi);
Tensor2D it;//5行 8列
sigmond_forward(it, m22);
//
Tensor2D m13;//5行 8列
MatirxDot(m13, Wc, concate);
Tensor2D m23;//5行 8列
MatirxAddBias(m23, m13, bc);
Tensor2D cct;//5行 8列
tanh_forward(cct,m23);
使用vs2017 C++17的时候
在eigen文件中增加,C++17有些stl函数是不推荐使用的
//error C4996: 'std::unary_negate<_Fn>':
//warning STL4008: std::not1(), std::not2(), std::unary_negate, and std::binary_negate are deprecated in C++17.
//They are superseded by std::not_fn(). You can define _SILENCE_CXX17_NEGATORS_DEPRECATION_WARNING or
//_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS to acknowledge that you have received this warning.
#if defined(_MSC_VER)
# pragma warning(push)
# pragma warning(disable: 4996) // error C4996: std::not1(), std::not2(), std::unary_negate, and std::binary_negate are deprecated in C++17
#endif
如果使用Eigen,转换函数是这样的
void std_vector2eigen_matrix(Eigen::MatrixXd& r, Tensor2D& a)
{
for (size_t i = 0; i < a.size(); i++)
r.row(i) = Eigen::VectorXd::Map(&a[i][0], a[i].size());
}
使用转换函数
Tensor2D test1;
InitData(test1, 3, 4);
Eigen::MatrixXd r(3,4);
std_vector2eigen_matrix(r, test1);
下面是使用Eigen
#include "stdafx.h"
#include <iostream>
#include <vector>
#include "Eigen\Dense"
int _tmain(int argc, _TCHAR* argv[])
{
std::vector<float> v{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
//同样是3行4列
Eigen::Map<Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>> m1(v.data(), 3, 4);
std::cout << "行优先" << '\n' << m1 << std::endl;
Eigen::Map<Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::ColMajor>> m2(v.data(), 3, 4);
std::cout << "列优先" << '\n' << m2 << std::endl;
Eigen::MatrixXd matrixXd1(3, 3);
matrixXd1 << 1, 2, 3,
4, 5, 6,
7, 8, 9;
std::cout << "原始矩阵" << '\n' << matrixXd1 << '\n' << std::endl;
std::cout << " 转置矩阵" << '\n' << matrixXd1.transpose() << '\n' << std::endl;
std::cout << "共轭矩阵 Hermite阵" << '\n' << matrixXd1.conjugate() << '\n' << std::endl;
std::cout << "伴随矩阵" << '\n' << matrixXd1.adjoint() << '\n' << std::endl;
std::cout << "矩阵的行列式 " << '\n' << matrixXd1.determinant() << '\n' << std::endl;
std::cout << "矩阵的迹" << '\n' << matrixXd1.trace() << '\n' << std::endl;
std::cout << " 逆矩阵" << '\n' << matrixXd1.inverse() << '\n' << std::endl;
system("pause");
return 0;
}
行优先
1 2 3 4
5 6 7 8
9 10 11 12
列优先
1 4 7 10
2 5 8 11
3 6 9 12
原始矩阵
1 2 3
4 5 6
7 8 9
转置矩阵
1 4 7
2 5 8
3 6 9
共轭矩阵 Hermite阵
1 2 3
4 5 6
7 8 9
伴随矩阵
1 4 7
2 5 8
3 6 9
矩阵的行列式
6.66134e-016
矩阵的迹
15
逆矩阵
- 4.5036e+015 9.0072e+015 - 4.5036e+015
9.0072e+015 - 1.80144e+016 9.0072e+015
- 4.5036e+015 9.0072e+015 - 4.5036e+015