c++ - 添加自定义稀疏运算(稀疏行列式)
问题描述
我正在尝试让一些稀疏矩阵运算在 Tensorflow 中工作。我要处理的第一个是稀疏行列式,通过稀疏 Cholesky 分解。Eigen 有一个稀疏的 Cholesky,所以我的想法是包装它。
我一直在取得一些进展,但现在有点卡住了。我知道 Tensorflow 中的 SparseTensors 由三部分组成:indices
、values
和shape
。复制类似的操作,我进行了以下REGISTER_OP
声明:
REGISTER_OP("SparseLogDet")
.Input("a_indices: int64")
.Input("a_values: float32")
.Input("a_shape: int64")
.Output("determinant: float32")
.SetShapeFn([](::tensorflow::shape_inference::InferenceContext* c) {
shape_inference::ShapeHandle h;
c->set_output(0, h);
return Status::OK();
});
这编译得很好,但是当我使用一些示例代码运行它时:
import tensorflow as tf
log_det_op = tf.load_op_library('./sparse_log_det_op.so')
with tf.Session(''):
t = tf.SparseTensor(indices=[[0, 0], [1, 2]], values=[1, 2],
dense_shape=[3, 4])
print(log_det_op.sparse_log_det(t).eval().shape)
print(log_det_op.sparse_log_det(t).eval())
它抱怨说:
TypeError: sparse_log_det() missing 2 required positional arguments: 'a_values' and 'a_shape'
这对我来说很有意义,因为它期待其他论点。但是,我真的只想传递稀疏张量,而不是将其分解为组件!有谁知道如何处理其他稀疏操作?
谢谢!
解决方案
如果你想传入稀疏张量,然后确定,indices
从这里,这应该是可能的。只需修改您的 OP 以获取单个输入并产生单个输出。然后通过遍历其元素从 Eigen::Tensor 中提取所需的信息,如下所示:values
shape
Tensor
float
#include "tensorflow/core/framework/op.h"
#include "tensorflow/core/framework/shape_inference.h"
#include "tensorflow/core/framework/op_kernel.h"
#include <Eigen/Dense>
using namespace tensorflow;
REGISTER_OP("SparseDeterminant")
.Input("sparse_tensor: float")
.Output("sparse_determinant: float");
class SparseDeterminantOp : public OpKernel {
public:
explicit SparseDeterminantOp(OpKernelConstruction *context) : OpKernel(context) {}
void Compute(OpKernelContext *context) override {
// get the input tesnorflow tensor
const Tensor& sparse_tensor = context->input(0);
// get shape of input
const TensorShape& sparse_shape = sparse_tensor.shape();
// get Eigen Tensor for input tensor
auto eigen_sparse = sparse_tensor.matrix<float>();
//extract the data you want from the sparse tensor input
auto a_shape = sparse_tensor.shape();
// loop over all elements of the input tensor and add to values and indices
for (int i=0; i<a_shape.dim_size(0); ++i){
for (int j=0; j<a_shape.dim_size(1); ++j){
if(eigen_sparse(i,j) != 0){
/// ***Here add non zero elements to list/tensor of values and their indicies***
std::cout<<eigen_sparse(i,j)<<" at"<<" "<<i<<" "<<j<<" "<<"not zero."<<std::endl;
}
}
}
// create output tensor
Tensor *output_tensor = NULL;
TensorShape output_shape;
OP_REQUIRES_OK(context, context->allocate_output(0, output_shape, &output_tensor));
auto output = output_tensor->scalar<float>();
output(0) = 1.; //**asign return value***;
}
};
REGISTER_KERNEL_BUILDER(Name("SparseDeterminant").Device(DEVICE_CPU), SparseDeterminantOp);
可悲的是,当你传入t
你的 op 时,它会变成 aTensorflow::Tensor
并丢失与 相关的values
andindices
方法tf.sparsetensor
,所以你不能轻易得到它们。
编译后,此代码可以运行:
//run.py
import tensorflow as tf
import numpy as np
my_module = tf.load_op_library('./out.so')
# create sparse matrix
a = np.zeros((10,10))
for i in range(len(a)):
a[i,i] = i
print(a)
a_t = tf.convert_to_tensor(a, dtype= float)
with tf.Session() as sess:
sess.run(my_module.sparse_determinant(a_t))