mirror of
https://github.com/saymrwulf/onnxruntime.git
synced 2026-07-30 20:18:08 +00:00
Add sequence identity for opset 14 & fix sequence insert (#7335)
**Description**: - Fix SequenceInsert with last position, which is equal to the current sequence length. - Implement Identity to support sequence input for opset 14. **Motivation and Context** - Required to export Huggingface/transformers T5 with beam search.
This commit is contained in:
parent
22d7cde725
commit
c584d48283
7 changed files with 104 additions and 40 deletions
|
|
@ -713,11 +713,11 @@ class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 14, Id
|
|||
|
||||
The process is the same for TYPED and untyped kernels - just repeat for each type when updating the typed entries.
|
||||
|
||||
The changes below in the registrations using BuildKernelCreateInfo are essentially the same. Update existing
|
||||
The changes below in the registrations using BuildKernelCreateInfo are essentially the same. Update existing
|
||||
registration to use the VERSIONED_ macro, add end version, add new un-versioned entry in the section for the new
|
||||
opset.
|
||||
|
||||
To double-check what versions an operator should have registrations for see
|
||||
To double-check what versions an operator should have registrations for see
|
||||
https://github.com/onnx/onnx/blob/master/docs/Operators.md
|
||||
*****/
|
||||
|
||||
|
|
|
|||
|
|
@ -209,10 +209,10 @@ Status SequenceInsert::Compute(OpKernelContext* context) const {
|
|||
|
||||
const auto* I = context->Input<Tensor>(2);
|
||||
int64_t num_tensors_input_seq = static_cast<int64_t>(S->Size());
|
||||
int64_t input_seq_idx = num_tensors_input_seq + 1; // default is append
|
||||
if (I) { // position is optional
|
||||
int64_t input_seq_idx = num_tensors_input_seq; // default is append
|
||||
if (I) { // position is optional
|
||||
input_seq_idx = GetSeqIdx(*I);
|
||||
if (!ValidateSeqIdx(input_seq_idx, static_cast<int64_t>(num_tensors_input_seq))) {
|
||||
if (!ValidateSeqIdx(input_seq_idx, num_tensors_input_seq) && input_seq_idx != num_tensors_input_seq) {
|
||||
return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT,
|
||||
"Invalid sequence index (", input_seq_idx, ") specified for sequence of size (", num_tensors_input_seq, ")");
|
||||
}
|
||||
|
|
@ -234,7 +234,7 @@ Status SequenceInsert::Compute(OpKernelContext* context) const {
|
|||
CreateCopyAndAppendCpuTensor(S->Get(i), context, tensors);
|
||||
}
|
||||
}
|
||||
if (input_seq_idx == num_tensors_input_seq + 1) {
|
||||
if (input_seq_idx == num_tensors_input_seq) {
|
||||
CreateCopyAndAppendCpuTensor(*X, context, tensors);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ ONNX_CPU_OPERATOR_VERSIONED_KERNEL(
|
|||
ONNX_CPU_OPERATOR_KERNEL(
|
||||
Identity,
|
||||
14,
|
||||
KernelDefBuilder().TypeConstraint("V", DataTypeImpl::AllTensorTypes()).Alias(0, 0),
|
||||
KernelDefBuilder().TypeConstraint("V", DataTypeImpl::AllTensorAndSequenceTensorTypes()).Alias(0, 0),
|
||||
IdentityOp<false>);
|
||||
|
||||
} // namespace onnxruntime
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
#pragma warning(pop)
|
||||
#endif
|
||||
#include "core/framework/op_kernel.h"
|
||||
#include "core/framework/TensorSeq.h"
|
||||
|
||||
namespace onnxruntime {
|
||||
|
||||
|
|
@ -22,39 +23,62 @@ class IdentityOp final : public OpKernel {
|
|||
}
|
||||
|
||||
Status Compute(OpKernelContext* context) const override {
|
||||
const auto* X = context->Input<Tensor>(0);
|
||||
ORT_ENFORCE(X != nullptr);
|
||||
const TensorShape& shape = X->Shape();
|
||||
Tensor* Y = context->Output(0, shape);
|
||||
auto X_type = X->DataType();
|
||||
auto X_ml_type = context->InputType(0);
|
||||
if (X_ml_type == DataTypeImpl::GetType<Tensor>()) {
|
||||
const auto* X = context->Input<Tensor>(0);
|
||||
ORT_ENFORCE(X != nullptr);
|
||||
const TensorShape& shape = X->Shape();
|
||||
Tensor* Y = context->Output(0, shape);
|
||||
auto X_type = X->DataType();
|
||||
|
||||
const void* source = X->DataRaw(X_type);
|
||||
void* target = Y->MutableDataRaw(X_type);
|
||||
//If source and target pointers are not equal, we need to copy the data.
|
||||
if (target != source) {
|
||||
if (!X->IsDataTypeString()) {
|
||||
memcpy(target, source, shape.Size() * X_type->Size());
|
||||
} else {
|
||||
// handle std::string
|
||||
const auto* src = X->template Data<std::string>();
|
||||
auto* dst = Y->template MutableData<std::string>();
|
||||
std::copy(src, src + shape.Size(), dst);
|
||||
const void* source = X->DataRaw(X_type);
|
||||
void* target = Y->MutableDataRaw(X_type);
|
||||
//If source and target pointers are not equal, we need to copy the data.
|
||||
if (target != source) {
|
||||
if (!X->IsDataTypeString()) {
|
||||
memcpy(target, source, shape.Size() * X_type->Size());
|
||||
} else {
|
||||
// handle std::string
|
||||
const auto* src = X->template Data<std::string>();
|
||||
auto* dst = Y->template MutableData<std::string>();
|
||||
std::copy(src, src + shape.Size(), dst);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (is_dropout) {
|
||||
Tensor* mask = context->Output(1, shape);
|
||||
// a 'nullptr' returned would make it an unused optional output
|
||||
if (mask != nullptr) {
|
||||
// Opset 7 differs with Opset 10 in that the type of the 'mask'
|
||||
// output is tied with the type of the input in Opset 7 whereas
|
||||
// the type of 'mask' in Opset 10 is 'bool' always
|
||||
// so we have a common solution
|
||||
void* mask_data = mask->MutableDataRaw();
|
||||
// In 'test'/'inference' mode, there are no input values dropped out
|
||||
// so fill the buffer with 0/false
|
||||
memset(mask_data, 0, mask->SizeInBytes());
|
||||
if (is_dropout) {
|
||||
Tensor* mask = context->Output(1, shape);
|
||||
// a 'nullptr' returned would make it an unused optional output
|
||||
if (mask != nullptr) {
|
||||
// Opset 7 differs with Opset 10 in that the type of the 'mask'
|
||||
// output is tied with the type of the input in Opset 7 whereas
|
||||
// the type of 'mask' in Opset 10 is 'bool' always
|
||||
// so we have a common solution
|
||||
void* mask_data = mask->MutableDataRaw();
|
||||
// In 'test'/'inference' mode, there are no input values dropped out
|
||||
// so fill the buffer with 0/false
|
||||
memset(mask_data, 0, mask->SizeInBytes());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const auto* X = context->Input<TensorSeq>(0);
|
||||
ORT_ENFORCE(X != nullptr);
|
||||
TensorSeq* output = context->Output<TensorSeq>(0);
|
||||
output->SetType(X->DataType());
|
||||
|
||||
AllocatorPtr alloc;
|
||||
auto status = context->GetTempSpaceAllocator(&alloc);
|
||||
if (!status.IsOK()) {
|
||||
ORT_THROW("Unable to get an allocator");
|
||||
}
|
||||
std::vector<Tensor> tensors;
|
||||
for (auto it = X->begin(), end = X->end(); it != end; ++it) {
|
||||
Tensor tmp(it->DataType(), onnxruntime::TensorShape(it->Shape()), alloc);
|
||||
size_t bytes = it->SizeInBytes();
|
||||
memcpy(tmp.MutableDataRaw(), it->DataRaw(), bytes);
|
||||
tensors.push_back(std::move(tmp));
|
||||
}
|
||||
|
||||
output->SetElements(std::move(tensors));
|
||||
}
|
||||
|
||||
return Status::OK();
|
||||
|
|
|
|||
|
|
@ -129,6 +129,36 @@ TEST(SequenceOpsTest, SequenceInsertPositiveDefault) {
|
|||
test.Run();
|
||||
}
|
||||
|
||||
TEST(SequenceOpsTest, SequenceInsertEmptyLast) {
|
||||
OpTester test("SequenceInsert", 11);
|
||||
SeqTensors<int64_t> input;
|
||||
test.AddSeqInput("S", input);
|
||||
test.AddInput<int64_t>("T", {3, 2}, {10, 20, 30, 40, 50, 60});
|
||||
test.AddInput<int64_t>("I", {1}, {0});
|
||||
|
||||
SeqTensors<int64_t> output;
|
||||
output.AddTensor({3, 2}, {10, 20, 30, 40, 50, 60});
|
||||
test.AddSeqOutput("S2", output);
|
||||
test.Run();
|
||||
}
|
||||
|
||||
TEST(SequenceOpsTest, SequenceInsertLast) {
|
||||
OpTester test("SequenceInsert", 11);
|
||||
SeqTensors<int64_t> input;
|
||||
input.AddTensor({3, 2}, {1, 2, 3, 4, 5, 6});
|
||||
input.AddTensor({3, 3}, {1, 2, 3, 4, 5, 6, 7, 8, 9});
|
||||
test.AddSeqInput("S", input);
|
||||
test.AddInput<int64_t>("T", {3, 2}, {10, 20, 30, 40, 50, 60});
|
||||
test.AddInput<int64_t>("I", {1}, {2});
|
||||
|
||||
SeqTensors<int64_t> output;
|
||||
output.AddTensor({3, 2}, {1, 2, 3, 4, 5, 6});
|
||||
output.AddTensor({3, 3}, {1, 2, 3, 4, 5, 6, 7, 8, 9});
|
||||
output.AddTensor({3, 2}, {10, 20, 30, 40, 50, 60});
|
||||
test.AddSeqOutput("S2", output);
|
||||
test.Run();
|
||||
}
|
||||
|
||||
TEST(SequenceOpsTest, SequenceInsertValidPositiveIdx) {
|
||||
OpTester test("SequenceInsert", 11);
|
||||
SeqTensors<int64_t> input;
|
||||
|
|
|
|||
|
|
@ -23,5 +23,15 @@ TEST(Identity, StringType) {
|
|||
test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider});//TensorRT: unsupported data type
|
||||
}
|
||||
|
||||
TEST(Identity, SequenceType) {
|
||||
OpTester test("Identity", 14, kOnnxDomain);
|
||||
SeqTensors<int64_t> input;
|
||||
input.AddTensor({3, 2}, {1, 2, 3, 4, 5, 6});
|
||||
input.AddTensor({3, 3}, {1, 2, 3, 4, 5, 6, 7, 8, 9});
|
||||
test.AddSeqInput("X", input);
|
||||
test.AddSeqOutput("Y", input);
|
||||
test.Run();
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
} // namespace onnxruntime
|
||||
|
|
|
|||
|
|
@ -891,10 +891,6 @@
|
|||
"HardSigmoid ai.onnx CPUExecutionProvider",
|
||||
8073874088399301792
|
||||
],
|
||||
[
|
||||
"Identity ai.onnx CPUExecutionProvider",
|
||||
13401700334046441640
|
||||
],
|
||||
[
|
||||
"Identity ai.onnx CPUExecutionProvider",
|
||||
16879814636194901248
|
||||
|
|
@ -903,6 +899,10 @@
|
|||
"Identity ai.onnx CPUExecutionProvider",
|
||||
18001636502361632792
|
||||
],
|
||||
[
|
||||
"Identity ai.onnx CPUExecutionProvider",
|
||||
16515685968327103576
|
||||
],
|
||||
[
|
||||
"If ai.onnx CPUExecutionProvider",
|
||||
2236645891232685176
|
||||
|
|
|
|||
Loading…
Reference in a new issue