最近在写ssd里需要用到的cross channel norm。第一次需要在paddlepaddle开发的时候需要用到eigen。过程有点坎坷
不过写过一次就还好了。
主要涉及到这么几点:
- paddle的tensor和eigen的数据类型的转换
- 对行(列)的求和等操作
- 矩阵和向量按照行和列的操作。
- GPU的支持
- eps的数据类型问题
paddlepaddle的Tensor和eigen的矩阵的转化
第一步
template <typename T, int MajorType = Eigen::RowMajor,
typename IndexType = Eigen::DenseIndex>
using EigenVector = framework::EigenVector<T, MajorType, IndexType>;
template <typename T, int MajorType = Eigen::RowMajor,
typename IndexType = Eigen::DenseIndex>
using EigenMatrix = framework::EigenMatrix<T, MajorType, IndexType>;
这里有一个小坑,[1 ,n] 或者[n,1]的tensor,是不能转成Matrix的,只能转成Vector
第二步,开始转化,这里举例了一个求平方的操作
EigenMatrix<T>::From(paddle里的tensor, tensor的dims)
framework::Tensor x_square;
x_square.mutable_data<T>(in_x->dims(), context.GetPlace());
auto x_square_eigen = EigenMatrix<T>::From(
x_square, framework::make_ddim({batch_size, fea_len * channels}));
auto x = EigenMatrix<T>::From(
*in_x, framework::make_ddim({batch_size, fea_len * channels}));
x_square_eigen.device(*place) = x.square();
对行和列的求和操作
比如对列求和
auto dim = Eigen::array<int, 1>({{0}});
xx.sum(dim)
framework::Tensor tmp_tensor;
tmp_tensor.mutable_data<T>(framework::make_ddim({1, fea_len}),
context.GetPlace());
auto tmp = EigenVector<T>::Flatten(tmp_tensor);
auto dim = Eigen::array<int, 1>({{0}});
tmp.device(*place) = x_square_batch_eigen.sum(dim);
矩阵和向量按照行和列的操作
需要用到broadcast
比如一个矩阵按row和一个行向量相乘
Eigen::array<int, 2> broadcast_dim_col;
broadcast_dim_col[1] = 1;
broadcast_dim_col[0] = channels;
out_batch_eigen.device(*place) =
in_x_batch_eigen * (tmp.broadcast(broadcast_dim_col));
GPU的支持
auto* place =
context.template device_context<DeviceContext>().eigen_device();
xxx.device(*place) = ...;
eps的数据类型问题
目前尝试的是这样解决,就可以直接 ++ --了
T epsilon = context.Attr<T>("epsilon");
网友评论