未验证 提交 f521a30d 编写于 作者: X xiongkun 提交者: GitHub

refine svd; unexpose tensor.svd; fix english document; set timeout=40 (#35635)

上级 86a6be1a
...@@ -20,6 +20,9 @@ ...@@ -20,6 +20,9 @@
#include "paddle/fluid/framework/ddim.h" #include "paddle/fluid/framework/ddim.h"
#include "paddle/fluid/framework/operator.h" #include "paddle/fluid/framework/operator.h"
#include "paddle/fluid/framework/tensor.h" #include "paddle/fluid/framework/tensor.h"
#include "paddle/fluid/operators/diag_op.h"
#include "paddle/fluid/operators/eigen/eigen_function.h"
#include "paddle/fluid/operators/elementwise/elementwise_op_function.h"
#include "paddle/fluid/operators/math/blas.h" #include "paddle/fluid/operators/math/blas.h"
#include "paddle/fluid/operators/math/functors.h" #include "paddle/fluid/operators/math/functors.h"
#include "paddle/fluid/operators/math/math_function.h" #include "paddle/fluid/operators/math/math_function.h"
...@@ -89,7 +92,6 @@ struct PowFunctor { ...@@ -89,7 +92,6 @@ struct PowFunctor {
}; };
static std::vector<int> GetBroadcastShape(InTensors ins) { static std::vector<int> GetBroadcastShape(InTensors ins) {
// TODO(xiongkun03) check the operators and output
PADDLE_ENFORCE_EQ(ins.size(), 2, platform::errors::InvalidArgument( PADDLE_ENFORCE_EQ(ins.size(), 2, platform::errors::InvalidArgument(
"GetBroadcastShape Receive 2 tensors" "GetBroadcastShape Receive 2 tensors"
"but got [%d]", "but got [%d]",
...@@ -125,6 +127,19 @@ static std::vector<int> GetBroadcastShape(InTensors ins) { ...@@ -125,6 +127,19 @@ static std::vector<int> GetBroadcastShape(InTensors ins) {
return broadcast_shape; return broadcast_shape;
} }
#define DITO_TRANSPOSE_RANK_CASE(N) \
case N: { \
math::Transpose<DeviceContext, T, N> trans; \
trans(dev_ctx, x, &ret, axis); \
break; \
}
#define DITO_SLICE_RANK_CASE(N) \
case N: { \
EigenSliceWrapper<N>(&x, offset, extends, &ret); \
break; \
}
template <typename DeviceContext, typename T> template <typename DeviceContext, typename T>
struct DeviceIndependenceTensorOperations { struct DeviceIndependenceTensorOperations {
// 1. Device indenpendence, for kernel reuse. // 1. Device indenpendence, for kernel reuse.
...@@ -153,20 +168,25 @@ struct DeviceIndependenceTensorOperations { ...@@ -153,20 +168,25 @@ struct DeviceIndependenceTensorOperations {
framework::Tensor Matmul(const framework::Tensor& mat_a, framework::Tensor Matmul(const framework::Tensor& mat_a,
const framework::Tensor& mat_b, bool trans_a = false, const framework::Tensor& mat_b, bool trans_a = false,
bool trans_b = false) { bool trans_b = false) {
framework::AttributeMap attrs; framework::Tensor ret;
attrs["trans_x"] = trans_a;
attrs["trans_y"] = trans_b;
NameInTensorMap inputs({{"X", {&mat_a}}, {"Y", {&mat_b}}});
auto a_dim = mat_a.dims(); auto a_dim = mat_a.dims();
auto b_dim = mat_b.dims(); auto b_dim = mat_b.dims();
std::vector<int> x_vec = framework::vectorize<int>(a_dim); std::vector<int> x_vec = framework::vectorize<int>(a_dim);
x_vec[x_vec.size() - 2] = a_dim[a_dim.size() - (trans_a ? 1 : 2)]; x_vec[x_vec.size() - 2] = a_dim[a_dim.size() - (trans_a ? 1 : 2)];
x_vec[x_vec.size() - 1] = b_dim[b_dim.size() - (trans_b ? 2 : 1)]; x_vec[x_vec.size() - 1] = b_dim[b_dim.size() - (trans_b ? 2 : 1)];
return CreateOpRunAndReturnTensor("matmul_v2", inputs, attrs, x_vec); ret.Resize(framework::make_ddim(x_vec));
ret.mutable_data<T>(context.GetPlace());
auto blas = GetBlas();
auto mat_a_discrib = math::CreateMatrixDescriptor(a_dim, 0, trans_a);
auto mat_b_discrib = math::CreateMatrixDescriptor(b_dim, 0, trans_b);
blas.MatMul(mat_a, mat_a_discrib, mat_b, mat_b_discrib, T(1.0), &ret,
T(0.0));
return ret;
} }
// transpose the last two dimision
framework::Tensor Transpose(const framework::Tensor& x) { framework::Tensor Transpose(const framework::Tensor& x) {
framework::Tensor out; // transpose the last two dimision
framework::Tensor ret;
auto x_dim = x.dims(); auto x_dim = x.dims();
auto x_vec = framework::vectorize<int>(x_dim); auto x_vec = framework::vectorize<int>(x_dim);
int rank = x_vec.size(); int rank = x_vec.size();
...@@ -177,26 +197,42 @@ struct DeviceIndependenceTensorOperations { ...@@ -177,26 +197,42 @@ struct DeviceIndependenceTensorOperations {
axis[i] = i; axis[i] = i;
} }
std::swap(axis[rank - 1], axis[rank - 2]); std::swap(axis[rank - 1], axis[rank - 2]);
framework::AttributeMap attrs; auto& dev_ctx = context.template device_context<DeviceContext>();
attrs["axis"] = axis; ret.Resize(framework::make_ddim(x_vec));
NameInTensorMap inputs({{"X", {&x}}}); ret.mutable_data<T>(context.GetPlace());
return CreateOpRunAndReturnTensor("transpose2", inputs, attrs, out_shape, switch (rank) {
{"Out", "XShape"}); DITO_TRANSPOSE_RANK_CASE(2);
DITO_TRANSPOSE_RANK_CASE(3);
DITO_TRANSPOSE_RANK_CASE(4);
DITO_TRANSPOSE_RANK_CASE(5);
DITO_TRANSPOSE_RANK_CASE(6);
default: {
PADDLE_THROW(platform::errors::InvalidArgument(
"Invalid Rank number, "
"currently only support rank between 2~6"));
}
}
return ret;
} }
framework::Tensor Diag(const framework::Tensor& x, int offset = 0, framework::Tensor Diag(const framework::Tensor& x, int offset = 0,
// FIXME link error
int padding_value = 0) { int padding_value = 0) {
framework::AttributeMap attrs; PADDLE_ENFORCE_EQ(padding_value, 0,
attrs["offset"] = offset; platform::errors::InvalidArgument(
attrs["padding_value"] = padding_value; "Current diag only support padding_value = 0"));
NameInTensorMap inputs({{"X", {&x}}}); PADDLE_ENFORCE_EQ(offset, 0,
platform::errors::InvalidArgument(
"Current diag only support offset = 0,"
"you can use DiagOp instead(not recommend)"));
framework::Tensor ret;
int x_rank = x.dims().size(); int x_rank = x.dims().size();
std::vector<int> out_shape; std::vector<int> out_shape;
if (x_rank == 2) { if (x_rank == 2) {
PADDLE_ENFORCE_EQ(x.dims()[0], x.dims()[1], PADDLE_THROW(platform::errors::InvalidArgument(
platform::errors::InvalidArgument( "Current diag only support vector"
"if X is a Matrix, then X must be square")); "-> diagonalized matrix, not support matrix -> vector,"
out_shape.push_back(x.dims()[0]); " Use DiagOp instead."));
} else if (x_rank == 1) { } else if (x_rank == 1) {
out_shape.push_back(x.dims()[0]); out_shape.push_back(x.dims()[0]);
out_shape.push_back(x.dims()[0]); out_shape.push_back(x.dims()[0]);
...@@ -204,42 +240,73 @@ struct DeviceIndependenceTensorOperations { ...@@ -204,42 +240,73 @@ struct DeviceIndependenceTensorOperations {
PADDLE_THROW( PADDLE_THROW(
platform::errors::InvalidArgument("Rank must less or equal than 2")); platform::errors::InvalidArgument("Rank must less or equal than 2"));
} }
return CreateOpRunAndReturnTensor("diag_v2", inputs, attrs, out_shape); ret = Fill({out_shape[0], out_shape[0]}, 0.0);
T* output = ret.mutable_data<T>(context.GetPlace());
auto for_range = GetForRange(x.numel());
for_range(DiagFunctor<T>(x.data<T>(), x.numel(), output));
return ret;
}
framework::Tensor Div(const framework::Tensor& x,
const framework::Tensor& y) {
framework::Tensor ret;
std::vector<int> out_shape = GetBroadcastShape({&x, &y});
ret.Resize(framework::make_ddim(out_shape));
ElementwiseComputeEx<DivFunctor<T>, DeviceContext, T>(
context, &x, &y, -1, DivFunctor<T>(), &ret);
return ret;
} }
framework::Tensor Add(const framework::Tensor& x, framework::Tensor Add(const framework::Tensor& x,
const framework::Tensor& y) { const framework::Tensor& y) {
InTensors ins({&x, &y}); // element wise add, support numpy broadcast.
framework::AttributeMap attrs; framework::Tensor ret;
attrs["axis"] = -1;
std::vector<int> out_shape = GetBroadcastShape({&x, &y}); std::vector<int> out_shape = GetBroadcastShape({&x, &y});
NameInTensorMap inputs({{"X", {&x}}, {"Y", {&y}}}); ret.Resize(framework::make_ddim(out_shape));
return CreateOpRunAndReturnTensor("elementwise_add", inputs, attrs, ElementwiseComputeEx<AddFunctor<T>, DeviceContext, T>(
out_shape); context, &x, &y, -1, AddFunctor<T>(), &ret);
return ret;
} }
framework::Tensor Mul(const framework::Tensor& x, framework::Tensor Mul(const framework::Tensor& x,
const framework::Tensor& y) { const framework::Tensor& y) {
InTensors ins({&x, &y}); framework::Tensor ret;
framework::AttributeMap attrs;
attrs["axis"] = -1;
std::vector<int> out_shape = GetBroadcastShape({&x, &y}); std::vector<int> out_shape = GetBroadcastShape({&x, &y});
NameInTensorMap inputs({{"X", {&x}}, {"Y", {&y}}}); ret.Resize(framework::make_ddim(out_shape));
return CreateOpRunAndReturnTensor("elementwise_mul", inputs, attrs, ElementwiseComputeEx<MulFunctor<T>, DeviceContext, T>(
out_shape); context, &x, &y, -1, MulFunctor<T>(), &ret);
return ret;
}
framework::Tensor ReduceSum(const framework::Tensor& x,
std::vector<int> out_dim) {
framework::AttributeMap attrs;
attrs["dim"] = std::vector<int>{-1};
NameInTensorMap inputs({{"X", {&x}}});
return CreateOpRunAndReturnTensor("reduce_sum", inputs, attrs, out_dim);
}
framework::Tensor ReduceMax(const framework::Tensor& x,
std::vector<int> out_dim) {
framework::AttributeMap attrs;
attrs["dim"] = std::vector<int>{-1};
NameInTensorMap inputs({{"X", {&x}}});
return CreateOpRunAndReturnTensor("reduce_max", inputs, attrs, out_dim);
} }
framework::Tensor Sub(const framework::Tensor& x, framework::Tensor Sub(const framework::Tensor& x,
const framework::Tensor& y) { const framework::Tensor& y) {
InTensors ins({&x, &y}); framework::Tensor ret;
framework::AttributeMap attrs;
attrs["axis"] = -1;
std::vector<int> out_shape = GetBroadcastShape({&x, &y}); std::vector<int> out_shape = GetBroadcastShape({&x, &y});
NameInTensorMap inputs({{"X", {&x}}, {"Y", {&y}}}); ret.Resize(framework::make_ddim(out_shape));
return CreateOpRunAndReturnTensor("elementwise_sub", inputs, attrs, if (x.dims().size() >= y.dims().size()) {
out_shape); ElementwiseComputeEx<SubFunctor<T>, DeviceContext, T>(
context, &x, &y, -1, SubFunctor<T>(), &ret);
} else {
ElementwiseComputeEx<InverseSubFunctor<T>, DeviceContext, T>(
// This is copyed from elementwise_sub, which means we
// need reverse will xrank < yrank
context, &x, &y, -1, InverseSubFunctor<T>(), &ret);
}
return ret;
} }
const framework::Tensor Unsqueeze(const framework::Tensor& x, int axis = 0) { const framework::Tensor Unsqueeze(const framework::Tensor& x, int axis = 0) {
// don't copy data, only change the dims // don't copy data, only change the dims
framework::Tensor out; framework::Tensor out;
...@@ -255,40 +322,29 @@ struct DeviceIndependenceTensorOperations { ...@@ -255,40 +322,29 @@ struct DeviceIndependenceTensorOperations {
out.Resize(framework::make_ddim(out_shape)); out.Resize(framework::make_ddim(out_shape));
return out; return out;
} }
framework::Tensor Fill(std::vector<int> shape, float fill_value) {
framework::Tensor Zeros(std::vector<int> shape, framework::Tensor ret;
framework::proto::VarType::Type dtype, ret.Resize(framework::make_ddim(shape));
float fill_value) { ret.mutable_data<T>(context.GetPlace());
framework::AttributeMap attrs; auto& dev_ctx = context.template device_context<DeviceContext>();
attrs["dtype"] = dtype; SetConstant<DeviceContext, T>()(dev_ctx, &ret, T(fill_value));
attrs["shape"] = shape; return ret;
attrs["value"] = fill_value;
NameInTensorMap inputs({});
return CreateOpRunAndReturnTensor("fill_constant", inputs, attrs, shape);
} }
framework::Tensor Infinits(std::vector<int> shape) {
framework::Tensor Infinits(std::vector<int> shape, auto value = static_cast<T>(std::numeric_limits<double>::infinity());
framework::proto::VarType::Type dtype) { return Fill(shape, value);
framework::AttributeMap attrs;
attrs["dtype"] = dtype;
attrs["shape"] = shape;
attrs["str_value"] = std::string("inf");
NameInTensorMap inputs({});
return CreateOpRunAndReturnTensor("fill_constant", inputs, attrs, shape);
} }
framework::Tensor Eye(int n) {
framework::Tensor Eye(int n, framework::proto::VarType::Type dtype) { auto output = Fill({n}, 1);
auto output = Zeros({n}, dtype, 1);
auto ret = Diag(output); auto ret = Diag(output);
return ret; return ret;
} }
framework::Tensor Slice(const framework::Tensor& x, std::vector<int> axes, framework::Tensor Slice(const framework::Tensor& x, std::vector<int> axes,
std::vector<int> starts, std::vector<int> ends) { std::vector<int> starts, std::vector<int> ends) {
framework::Tensor ret;
std::vector<int> new_axes = axes; std::vector<int> new_axes = axes;
NameInTensorMap inputs({{"Input", {&x}}});
std::vector<int> out_shape = framework::vectorize<int>(x.dims()); std::vector<int> out_shape = framework::vectorize<int>(x.dims());
int rank = out_shape.size(); size_t rank = out_shape.size();
PADDLE_ENFORCE_EQ( PADDLE_ENFORCE_EQ(
axes.size(), starts.size(), axes.size(), starts.size(),
platform::errors::InvalidArgument("Slice Operator Argument Invalided")); platform::errors::InvalidArgument("Slice Operator Argument Invalided"));
...@@ -306,27 +362,31 @@ struct DeviceIndependenceTensorOperations { ...@@ -306,27 +362,31 @@ struct DeviceIndependenceTensorOperations {
"C++ Slice Operation Not Support End < Start")); "C++ Slice Operation Not Support End < Start"));
out_shape[axis] = ed - st; out_shape[axis] = ed - st;
} }
framework::AttributeMap attrs; std::vector<int> offset(rank), extends(rank);
attrs["axes"] = new_axes; for (size_t i = 0; i < rank; ++i) {
attrs["starts"] = starts; offset[i] = 0;
attrs["ends"] = ends; extends[i] = x.dims()[i];
return CreateOpRunAndReturnTensor("slice", inputs, attrs, out_shape); }
} for (size_t i = 0; i < new_axes.size(); ++i) {
offset[new_axes[i]] = starts[i];
framework::Tensor ReduceSum(const framework::Tensor& x, extends[new_axes[i]] = ends[i] - starts[i];
std::vector<int> out_dim) { }
framework::AttributeMap attrs; ret.Resize(framework::make_ddim(out_shape));
attrs["dim"] = std::vector<int>{-1}; ret.mutable_data<T>(context.GetPlace());
NameInTensorMap inputs({{"X", {&x}}}); switch (rank) {
return CreateOpRunAndReturnTensor("reduce_sum", inputs, attrs, out_dim); DITO_SLICE_RANK_CASE(1);
} DITO_SLICE_RANK_CASE(2);
DITO_SLICE_RANK_CASE(3);
framework::Tensor ReduceMax(const framework::Tensor& x, DITO_SLICE_RANK_CASE(4);
std::vector<int> out_dim) { DITO_SLICE_RANK_CASE(5);
framework::AttributeMap attrs; DITO_SLICE_RANK_CASE(6);
attrs["dim"] = std::vector<int>{-1}; default: {
NameInTensorMap inputs({{"X", {&x}}}); PADDLE_THROW(platform::errors::InvalidArgument(
return CreateOpRunAndReturnTensor("reduce_max", inputs, attrs, out_dim); "Invalid Rank number, "
"currently only support rank between 2~6"));
}
}
return ret;
} }
private: private:
...@@ -338,14 +398,40 @@ struct DeviceIndependenceTensorOperations { ...@@ -338,14 +398,40 @@ struct DeviceIndependenceTensorOperations {
auto& dev_ctx = context.template device_context<DeviceContext>(); auto& dev_ctx = context.template device_context<DeviceContext>();
return platform::ForRange<DeviceContext>(dev_ctx, numel); return platform::ForRange<DeviceContext>(dev_ctx, numel);
} }
template <size_t D>
void EigenSliceWrapper(const framework::Tensor* in,
const std::vector<int>& start,
const std::vector<int>& end, framework::Tensor* out) {
// Slice by call Eigen Tensor Function `.slice()`
size_t rank = in->dims().size();
PADDLE_ENFORCE_EQ(start.size(), rank,
platform::errors::InvalidArgument(
"EigenSliceWrapper function start "
"argument must have the same length as input rank."));
PADDLE_ENFORCE_EQ(end.size(), rank,
platform::errors::InvalidArgument(
"EigenSliceWrapper function end "
"argument must have the same length as input rank."));
auto eigen_place_ptr =
context.template device_context<DeviceContext>().eigen_device();
auto eigen_place = *eigen_place_ptr;
auto out_t = framework::EigenTensor<T, D>::From(*out, out->dims());
auto in_t = framework::EigenTensor<T, D>::From(*in, in->dims());
Eigen::DSizes<int, D> offsets_32bit, extents_32bit;
for (size_t i = 0; i < D; i++) {
offsets_32bit[i] = start[i];
extents_32bit[i] = end[i];
}
EigenSlice<std::decay_t<decltype(eigen_place)>, T, D>::Eval(
eigen_place, framework::To32BitIndex(out_t),
framework::To32BitIndex(in_t), offsets_32bit, extents_32bit);
}
framework::Tensor CreateOpRunAndReturnTensor( framework::Tensor CreateOpRunAndReturnTensor(
const std::string& type, const NameInTensorMap& inputs, const std::string& type, const NameInTensorMap& inputs,
const framework::AttributeMap& attrs, std::vector<int> out_shape, const framework::AttributeMap& attrs, std::vector<int> out_shape,
NameOutTensor out_str = {"Out"}) { NameOutTensor out_str = {"Out"}) {
// varialble set dims must be LoDTensor / SelectedRowTensor // varialble set dims must be LoDTensor / SelectedRowTensor
framework::Scope& local_scope = context.scope().NewScope(); framework::Scope& local_scope = context.scope().NewScope();
framework::VariableNameMap op_outputs; framework::VariableNameMap op_outputs;
for (auto out_name : out_str) { for (auto out_name : out_str) {
local_scope.Var("tmp_" + out_name)->GetMutable<framework::LoDTensor>(); local_scope.Var("tmp_" + out_name)->GetMutable<framework::LoDTensor>();
...@@ -373,6 +459,7 @@ struct DeviceIndependenceTensorOperations { ...@@ -373,6 +459,7 @@ struct DeviceIndependenceTensorOperations {
} }
op_inputs[item.first] = name_vector; op_inputs[item.first] = name_vector;
} }
auto op = auto op =
framework::OpRegistry::CreateOp(type, op_inputs, op_outputs, attrs); framework::OpRegistry::CreateOp(type, op_inputs, op_outputs, attrs);
op->Run(local_scope, context.GetPlace()); op->Run(local_scope, context.GetPlace());
......
...@@ -54,7 +54,6 @@ class SvdCPUKernel : public framework::OpKernel<T> { ...@@ -54,7 +54,6 @@ class SvdCPUKernel : public framework::OpKernel<T> {
size_t(batches * col_v * cols * sizeof(math::Real<T>))); size_t(batches * col_v * cols * sizeof(math::Real<T>)));
auto* S_out = S->mutable_data<math::Real<T>>( auto* S_out = S->mutable_data<math::Real<T>>(
context.GetPlace(), size_t(batches * k * sizeof(math::Real<T>))); context.GetPlace(), size_t(batches * k * sizeof(math::Real<T>)));
/*SVD Use the Eigen Library*/ /*SVD Use the Eigen Library*/
math::BatchSvd<T>(x_data, U_out, VH_out, S_out, rows, cols, batches, full); math::BatchSvd<T>(x_data, U_out, VH_out, S_out, rows, cols, batches, full);
} }
...@@ -96,7 +95,7 @@ class SvdGradKernel : public framework::OpKernel<T> { ...@@ -96,7 +95,7 @@ class SvdGradKernel : public framework::OpKernel<T> {
auto s_square = dito.Pow(S, 2); auto s_square = dito.Pow(S, 2);
auto F = auto F =
dito.Sub(dito.Unsqueeze(s_square, -2), dito.Unsqueeze(s_square, -1)); dito.Sub(dito.Unsqueeze(s_square, -2), dito.Unsqueeze(s_square, -1));
F = dito.Add(F, dito.Diag(dito.Infinits({k}, U.type()))); F = dito.Add(F, dito.Diag(dito.Infinits({k})));
F = dito.Pow(F, -1); F = dito.Pow(F, -1);
Tensor sigma_term; Tensor sigma_term;
Tensor u_term; Tensor u_term;
...@@ -115,8 +114,7 @@ class SvdGradKernel : public framework::OpKernel<T> { ...@@ -115,8 +114,7 @@ class SvdGradKernel : public framework::OpKernel<T> {
u_term = dito.Mul(dito.Mul(dito.Sub(UTG, GTU), F), dito.Unsqueeze(S, -2)); u_term = dito.Mul(dito.Mul(dito.Sub(UTG, GTU), F), dito.Unsqueeze(S, -2));
u_term = dito.Matmul(U, u_term); u_term = dito.Matmul(U, u_term);
if (m > k) { if (m > k) {
auto project = auto project = dito.Sub(dito.Eye(m), dito.Matmul(U, U, false, true));
dito.Sub(dito.Eye(m, U.type()), dito.Matmul(U, U, false, true));
u_term = dito.Add(u_term, dito.Mul(dito.Matmul(project, dU), u_term = dito.Add(u_term, dito.Mul(dito.Matmul(project, dU),
dito.Unsqueeze(s_inverse, -2))); dito.Unsqueeze(s_inverse, -2)));
} }
...@@ -129,8 +127,7 @@ class SvdGradKernel : public framework::OpKernel<T> { ...@@ -129,8 +127,7 @@ class SvdGradKernel : public framework::OpKernel<T> {
v_term = dito.Mul(dito.Matmul(dito.Mul(dito.Sub(UTG, GTU), F), VH), v_term = dito.Mul(dito.Matmul(dito.Mul(dito.Sub(UTG, GTU), F), VH),
dito.Unsqueeze(S, -1)); dito.Unsqueeze(S, -1));
if (n > k) { if (n > k) {
auto project = auto project = dito.Sub(dito.Eye(n), dito.Matmul(VH, VH, true, false));
dito.Sub(dito.Eye(n, U.type()), dito.Matmul(VH, VH, true, false));
v_term = dito.Add(v_term, dito.Mul(dito.Matmul(dVH, project), v_term = dito.Add(v_term, dito.Mul(dito.Matmul(dVH, project),
dito.Unsqueeze(s_inverse, -1))); dito.Unsqueeze(s_inverse, -1)));
} }
......
...@@ -100,7 +100,6 @@ from .tensor.linalg import bmm # noqa: F401 ...@@ -100,7 +100,6 @@ from .tensor.linalg import bmm # noqa: F401
from .tensor.linalg import histogram # noqa: F401 from .tensor.linalg import histogram # noqa: F401
from .tensor.linalg import mv # noqa: F401 from .tensor.linalg import mv # noqa: F401
from .tensor.linalg import matrix_power # noqa: F401 from .tensor.linalg import matrix_power # noqa: F401
from .tensor.linalg import svd # noqa: F401
from .tensor.logic import equal # noqa: F401 from .tensor.logic import equal # noqa: F401
from .tensor.logic import greater_equal # noqa: F401 from .tensor.logic import greater_equal # noqa: F401
from .tensor.logic import greater_than # noqa: F401 from .tensor.logic import greater_than # noqa: F401
...@@ -498,7 +497,6 @@ __all__ = [ # noqa ...@@ -498,7 +497,6 @@ __all__ = [ # noqa
'sqrt', 'sqrt',
'cholesky', 'cholesky',
'matrix_power', 'matrix_power',
'svd',
'randperm', 'randperm',
'linspace', 'linspace',
'reshape', 'reshape',
......
...@@ -889,7 +889,7 @@ set_tests_properties(test_multiprocess_dataloader_iterable_dataset_static PROPER ...@@ -889,7 +889,7 @@ set_tests_properties(test_multiprocess_dataloader_iterable_dataset_static PROPER
set_tests_properties(test_lstm_cudnn_op PROPERTIES TIMEOUT 120) set_tests_properties(test_lstm_cudnn_op PROPERTIES TIMEOUT 120)
set_tests_properties(test_stack_op PROPERTIES TIMEOUT 120) set_tests_properties(test_stack_op PROPERTIES TIMEOUT 120)
set_tests_properties(test_bilinear_interp_v2_op PROPERTIES TIMEOUT 120) set_tests_properties(test_bilinear_interp_v2_op PROPERTIES TIMEOUT 120)
set_tests_properties(test_svd_op PROPERTIES TIMEOUT 120) set_tests_properties(test_svd_op PROPERTIES TIMEOUT 40)
set_tests_properties(test_deformable_psroi_pooling PROPERTIES TIMEOUT 120) set_tests_properties(test_deformable_psroi_pooling PROPERTIES TIMEOUT 120)
set_tests_properties(test_trilinear_interp_v2_op PROPERTIES TIMEOUT 120) set_tests_properties(test_trilinear_interp_v2_op PROPERTIES TIMEOUT 120)
set_tests_properties(test_imperative_static_runner_mnist PROPERTIES TIMEOUT 120) set_tests_properties(test_imperative_static_runner_mnist PROPERTIES TIMEOUT 120)
......
...@@ -45,7 +45,6 @@ from .linalg import bmm # noqa: F401 ...@@ -45,7 +45,6 @@ from .linalg import bmm # noqa: F401
from .linalg import histogram # noqa: F401 from .linalg import histogram # noqa: F401
from .linalg import mv # noqa: F401 from .linalg import mv # noqa: F401
from .linalg import matrix_power # noqa: F401 from .linalg import matrix_power # noqa: F401
from .linalg import svd # noqa: F401
from .logic import equal # noqa: F401 from .logic import equal # noqa: F401
from .logic import greater_equal # noqa: F401 from .logic import greater_equal # noqa: F401
from .logic import greater_than # noqa: F401 from .logic import greater_than # noqa: F401
...@@ -226,7 +225,6 @@ tensor_method_func = [ #noqa ...@@ -226,7 +225,6 @@ tensor_method_func = [ #noqa
'histogram', 'histogram',
'mv', 'mv',
'matrix_power', 'matrix_power',
'svd',
'abs', 'abs',
'acos', 'acos',
'all', 'all',
......
...@@ -1036,46 +1036,51 @@ def mv(x, vec, name=None): ...@@ -1036,46 +1036,51 @@ def mv(x, vec, name=None):
def svd(x, full_matrices=False, name=None): def svd(x, full_matrices=False, name=None):
r""" r"""
Computes the singular value decomposition of one Computes the singular value decomposition of one matrix or a batch of regular matrices.
matrix or batches of regular matrice.
Let :math:`X` be the input matrix or a batch of input matrices, the output should satisfies:
.. math::
X = U * diag(S) * VT
Args: Args:
x (Tensor): The input tensor. Its shape should be `[..., N, M]`, x (Tensor): The input tensor. Its shape should be `[..., N, M]`,
where ... is zero or more batch dimensions. N and M can be arbitraty where `...` is zero or more batch dimensions. N and M can be arbitraty
positive number. Note that if x is sigular matrices, the grad is numerical positive number. Note that if x is sigular matrices, the grad is numerical
instability. The data type of x should be float32 or float64. instable. The data type of x should be float32 or float64.
full_matrices (bool): A flag to control the behavor of svd.
full_matrices(bool): A flag to control the behavor of svd.
If full_matrices = True, svd op will compute full U and V matrics, If full_matrices = True, svd op will compute full U and V matrics,
which means shape of U is `[..., N, N]`, shape of V is `[..., M, M]`. which means shape of U is `[..., N, N]`, shape of V is `[..., M, M]`. K = min(M, N).
If full_matrices = False, svd op will use a economic method to store U and V. If full_matrices = False, svd op will use a economic method to store U and V.
which means shape of U is `[..., N, K]`, shape of V is `[..., M, K]` which means shape of U is `[..., N, K]`, shape of V is `[..., M, K]`. K = min(M, N).
name (str, optional): Name for the operation (optional, default is None).
For more information, please refer to :ref:`api_guide_Name`.
Returns: Returns:
Tensor: Tensor U, the shape of U is controlled by full_matrices flag. Tuple of 3 tensors: (U, S, VH). VH is the conjugate transpose of V. S is the singlar value vectors of matrics with shape `[..., K]`
Tensor: Tensor S, the singular value of X. the shape of S is [..., K]
Tensor: Tensor VH, the conjugate transpose of V. the shape of V is controlled by full_matrices flag.
import numpy as np Examples:
.. code-block:: python
import paddle
x = paddle.to_tensor([[1.0, 2.0], [1.0, 3.0], [4.0, 6.0]]).astype('float64') x = paddle.to_tensor([[1.0, 2.0], [1.0, 3.0], [4.0, 6.0]]).astype('float64')
x = x.reshape([3, 2]) x = x.reshape([3, 2])
u, s, vt = paddle.linalg.svd(x) u, s, vh = paddle.linalg.svd(x)
print (u) print (u)
print (s)
print (vt)
#U = [[ 0.27364809, -0.21695147 ], #U = [[ 0.27364809, -0.21695147 ],
# [ 0.37892198, -0.87112408 ], # [ 0.37892198, -0.87112408 ],
# [ 0.8840446 , 0.44053933 ]] # [ 0.8840446 , 0.44053933 ]]
print (s)
#S = [8.14753743, 0.78589688] #S = [8.14753743, 0.78589688]
print (vh)
#VT= [[ 0.51411221, 0.85772294], #VT= [[ 0.51411221, 0.85772294],
# [ 0.85772294, -0.51411221]] # [ 0.85772294, -0.51411221]]
# one can verify : U * S * VT = X ; # one can verify : U * S * VT == X
# U * UH = I ; # U * UH == I
# V * VH = I # V * VH == I
""" """
if in_dygraph_mode(): if in_dygraph_mode():
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册