提交 1bc8de32 编写于 作者: W wanghaoshuang

1. Add sequence_num as edit distance op's output

2. Fix evaluator using 'reduce_sum' op instead of 'mean' op
上级 0b854bdb
......@@ -156,6 +156,7 @@ op_library(parallel_do_op DEPS executor)
# Regist multiple Kernel to pybind
if (WITH_GPU)
op_library(conv_op SRCS conv_op.cc conv_op.cu.cc conv_cudnn_op.cu.cc DEPS vol2col)
op_library(edit_distance_op SRCS edit_distance_op.cc edit_distance_op.cu DEPS math_function)
op_library(pool_op SRCS pool_op.cc pool_op.cu.cc pool_cudnn_op.cu.cc DEPS pooling)
op_library(conv_transpose_op SRCS conv_transpose_op.cc conv_transpose_op.cu.cc
conv_transpose_cudnn_op.cu.cc DEPS vol2col)
......
......@@ -25,6 +25,8 @@ class EditDistanceOp : public framework::OperatorWithKernel {
PADDLE_ENFORCE(ctx->HasInput("Hyps"), "Input(Hyps) shouldn't be null.");
PADDLE_ENFORCE(ctx->HasInput("Refs"), "Input(Refs) shouldn't be null.");
PADDLE_ENFORCE(ctx->HasOutput("Out"), "Output(Out) shouldn't be null.");
PADDLE_ENFORCE(ctx->HasOutput("SequenceNum"),
"Output(SequenceNum) shouldn't be null.");
auto hyp_dims = ctx->GetInputDim("Hyps");
auto ref_dims = ctx->GetInputDim("Refs");
PADDLE_ENFORCE(hyp_dims.size() == 2 && hyp_dims[1] == 1,
......@@ -34,6 +36,7 @@ class EditDistanceOp : public framework::OperatorWithKernel {
"Input(Refs) must be a 2-D LoDTensor with the 2nd dimension "
"equal to 1.");
ctx->SetOutputDim("Out", ctx->GetInputDim("Refs"));
ctx->SetOutputDim("SequenceNum", {1});
}
protected:
......@@ -54,6 +57,7 @@ class EditDistanceOpMaker : public framework::OpProtoAndCheckerMaker {
AddInput("Refs",
"(2-D LoDTensor<int64_t>, 2nd dim. equal to 1) "
"The indices for reference strings.");
AddOutput("SequenceNum", "The sequence count of current batch");
AddAttr<bool>("normalized",
"(bool, default false) Indicated whether to normalize "
"the edit distance by the length of reference string.")
......
......@@ -14,6 +14,7 @@ limitations under the License. */
#include <algorithm>
#include "paddle/framework/op_registry.h"
#include "paddle/operators/math/math_function.h"
#include "paddle/platform/cuda_helper.h"
#include "paddle/platform/gpu_info.h"
......@@ -72,6 +73,8 @@ class EditDistanceGPUKernel : public framework::OpKernel<T> {
auto* x1_t = ctx.Input<framework::LoDTensor>("Hyps");
auto* x2_t = ctx.Input<framework::LoDTensor>("Refs");
auto* sequence_num = ctx.Output<framework::Tensor>("SequenceNum");
sequence_num->mutable_data<int64_t>(ctx.GetPlace());
auto normalized = ctx.Attr<bool>("normalized");
auto stream = reinterpret_cast<const platform::CUDADeviceContext&>(
......@@ -88,7 +91,11 @@ class EditDistanceGPUKernel : public framework::OpKernel<T> {
"Reference string %d is empty.", i);
}
auto num_strs = hyp_lod.size() - 1;
const size_t num_strs = hyp_lod.size() - 1;
math::SetConstant<platform::CUDADeviceContext, int64_t> set_constant;
set_constant(ctx.template device_context<platform::CUDADeviceContext>(),
sequence_num, static_cast<int64_t>(num_strs));
out_t->Resize({static_cast<int64_t>(num_strs), 1});
out_t->mutable_data<T>(ctx.GetPlace());
auto out = out_t->data<T>();
......
......@@ -16,7 +16,6 @@ limitations under the License. */
#include <algorithm>
#include "paddle/framework/eigen.h"
#include "paddle/framework/op_registry.h"
namespace paddle {
namespace operators {
......@@ -28,6 +27,8 @@ class EditDistanceKernel : public framework::OpKernel<T> {
auto* x1_t = ctx.Input<framework::LoDTensor>("Hyps");
auto* x2_t = ctx.Input<framework::LoDTensor>("Refs");
auto* sequence_num = ctx.Output<framework::Tensor>("SequenceNum");
int64_t* seq_num_data = sequence_num->mutable_data<int64_t>(ctx.GetPlace());
auto normalized = ctx.Attr<bool>("normalized");
......@@ -41,6 +42,7 @@ class EditDistanceKernel : public framework::OpKernel<T> {
"Reference string %d is empty.", i);
}
auto num_strs = hyp_lod.size() - 1;
*seq_num_data = static_cast<int64_t>(num_strs);
out_t->Resize({static_cast<int64_t>(num_strs), 1});
out_t->mutable_data<float>(ctx.GetPlace());
......
......@@ -219,15 +219,14 @@ class EditDistance(Evaluator):
self.total_error = self.create_state(
dtype='float32', shape=[1], suffix='total')
self.batch_num = self.create_state(
dtype='float32', shape=[1], suffix='total')
error = layers.edit_distance(input=input, label=label)
error = layers.cast(x=error, dtype='float32')
mean_error = layers.mean(x=error)
layers.sums(input=[self.total_error, mean_error], out=self.total_error)
const1 = layers.fill_constant(shape=[1], value=1.0, dtype="float32")
layers.sums(input=[self.batch_num, const1], out=self.batch_num)
self.metrics.append(mean_error)
self.seq_num = self.create_state(
dtype='int64', shape=[1], suffix='total')
error, seq_num = layers.edit_distance(input=input, label=label)
#error = layers.cast(x=error, dtype='float32')
sum_error = layers.reduce_sum(error)
layers.sums(input=[self.total_error, sum_error], out=self.total_error)
layers.sums(input=[self.seq_num, seq_num], out=self.seq_num)
self.metrics.append(sum_error)
def eval(self, executor, eval_program=None):
if eval_program is None:
......@@ -235,6 +234,7 @@ class EditDistance(Evaluator):
block = eval_program.current_block()
with program_guard(main_program=eval_program):
total_error = _clone_var_(block, self.total_error)
batch_num = _clone_var_(block, self.batch_num)
out = layers.elementwise_div(x=total_error, y=batch_num)
seq_num = _clone_var_(block, self.seq_num)
seq_num = layers.cast(x=seq_num, dtype='float32')
out = layers.elementwise_div(x=total_error, y=seq_num)
return np.array(executor.run(eval_program, fetch_list=[out])[0])
......@@ -1918,14 +1918,16 @@ def edit_distance(input, label, normalized=False, tokens=None, name=None):
# edit distance op
edit_distance_out = helper.create_tmp_variable(dtype="int64")
sequence_num = helper.create_tmp_variable(dtype="int64")
helper.append_op(
type="edit_distance",
inputs={"Hyps": [input],
"Refs": [label]},
outputs={"Out": [edit_distance_out]},
outputs={"Out": [edit_distance_out],
"SequenceNum": [sequence_num]},
attrs={"normalized": normalized})
return edit_distance_out
return edit_distance_out, sequence_num
def ctc_greedy_decoder(input, blank, name=None):
......
......@@ -60,6 +60,7 @@ class TestEditDistanceOp(OpTest):
num_strs = len(x1_lod) - 1
distance = np.zeros((num_strs, 1)).astype("float32")
sequence_num = np.array(2).astype("int64")
for i in range(0, num_strs):
distance[i] = Levenshtein(
hyp=x1[x1_lod[i]:x1_lod[i + 1]],
......@@ -69,7 +70,7 @@ class TestEditDistanceOp(OpTest):
distance[i] = distance[i] / len_ref
self.attrs = {'normalized': normalized}
self.inputs = {'Hyps': (x1, [x1_lod]), 'Refs': (x2, [x2_lod])}
self.outputs = {'Out': distance}
self.outputs = {'Out': distance, 'SequenceNum': sequence_num}
def test_check_output(self):
self.check_output()
......@@ -88,6 +89,7 @@ class TestEditDistanceOpNormalized(OpTest):
num_strs = len(x1_lod) - 1
distance = np.zeros((num_strs, 1)).astype("float32")
sequence_num = np.array(3).astype("int64")
for i in range(0, num_strs):
distance[i] = Levenshtein(
hyp=x1[x1_lod[i]:x1_lod[i + 1]],
......@@ -97,7 +99,7 @@ class TestEditDistanceOpNormalized(OpTest):
distance[i] = distance[i] / len_ref
self.attrs = {'normalized': normalized}
self.inputs = {'Hyps': (x1, [x1_lod]), 'Refs': (x2, [x2_lod])}
self.outputs = {'Out': distance}
self.outputs = {'Out': distance, 'SequenceNum': sequence_num}
def test_check_output(self):
self.check_output()
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册