aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar A. Unique TensorFlower <gardener@tensorflow.org>2017-11-09 17:55:08 -0800
committerGravatar Andrew Selle <aselle@andyselle.com>2017-11-10 16:14:41 -0800
commit8392a4b8e9d6d7ccbfde15dcdda0477c2791b6dc (patch)
tree2f4ccc8b42f2cbba82ebc2365d2e7a1556d24435
parentf9c7db10e294a011baf4d168e80c8209efb57f72 (diff)
Hlo parser: support padding.
Also, give PaddingConfig its own ToString format. PiperOrigin-RevId: 175239832
-rw-r--r--tensorflow/compiler/xla/service/hlo_instruction.cc18
-rw-r--r--tensorflow/compiler/xla/service/hlo_instruction.h2
-rw-r--r--tensorflow/compiler/xla/tools/parser/README.md6
-rw-r--r--tensorflow/compiler/xla/tools/parser/hlo_lexer.cc13
-rw-r--r--tensorflow/compiler/xla/tools/parser/hlo_lexer.h2
-rw-r--r--tensorflow/compiler/xla/tools/parser/hlo_parser.cc51
-rw-r--r--tensorflow/compiler/xla/tools/parser/hlo_parser_test.cc52
-rw-r--r--tensorflow/compiler/xla/tools/parser/hlo_token.h2
8 files changed, 130 insertions, 16 deletions
diff --git a/tensorflow/compiler/xla/service/hlo_instruction.cc b/tensorflow/compiler/xla/service/hlo_instruction.cc
index 1b2161fc2e..674d3e3836 100644
--- a/tensorflow/compiler/xla/service/hlo_instruction.cc
+++ b/tensorflow/compiler/xla/service/hlo_instruction.cc
@@ -1889,7 +1889,8 @@ std::vector<string> HloInstruction::ExtraAttributesToString() const {
extra.push_back(StrCat("window={", window_util::ToString(*window_), "}"));
}
if (padding_config_ != nullptr) {
- extra.push_back(StrCat("padding=", padding_config_->ShortDebugString()));
+ extra.push_back(
+ StrCat("padding=", xla::PaddingConfigToString(*padding_config_)));
}
if (opcode() == HloOpcode::kSlice) {
std::vector<string> bounds;
@@ -2894,6 +2895,21 @@ StatusOr<HloInstruction::FusionKind> StringToFusionKind(
return InvalidArgument("Unknown fusion kind: %s", kind_name.c_str());
}
+string PaddingConfigToString(const PaddingConfig& padding) {
+ bool has_interior_padding =
+ std::any_of(padding.dimensions().begin(), padding.dimensions().end(),
+ [](const PaddingConfig::PaddingConfigDimension& dim) {
+ return dim.interior_padding() != 0;
+ });
+ return Join(
+ padding.dimensions(), "x",
+ [&](string* out, const PaddingConfig::PaddingConfigDimension& dim) {
+ StrAppend(
+ out, dim.edge_padding_low(), "_", dim.edge_padding_high(),
+ has_interior_padding ? StrCat("_", dim.interior_padding()) : "");
+ });
+}
+
std::ostream& operator<<(std::ostream& os, HloInstruction::FusionKind kind) {
return os << ToString(kind);
}
diff --git a/tensorflow/compiler/xla/service/hlo_instruction.h b/tensorflow/compiler/xla/service/hlo_instruction.h
index 974d43d89e..64a88164a7 100644
--- a/tensorflow/compiler/xla/service/hlo_instruction.h
+++ b/tensorflow/compiler/xla/service/hlo_instruction.h
@@ -1234,6 +1234,8 @@ string ToString(HloInstruction::FusionKind kind);
StatusOr<HloInstruction::FusionKind> StringToFusionKind(
const string& kind_name);
+string PaddingConfigToString(const PaddingConfig& padding);
+
std::ostream& operator<<(std::ostream& os, HloInstruction::FusionKind kind);
// Map classes that guarantee a deterministic iteration order when the key is
diff --git a/tensorflow/compiler/xla/tools/parser/README.md b/tensorflow/compiler/xla/tools/parser/README.md
index 986041caf6..b768b94e77 100644
--- a/tensorflow/compiler/xla/tools/parser/README.md
+++ b/tensorflow/compiler/xla/tools/parser/README.md
@@ -54,9 +54,9 @@ attribute
attribute_value
: kInt
| kName
- | [0-9bf]{3,}_[0-9io]{3,}->[0-9bf]{3,} /*dim_labels_pattern*/
- | [0-9]+(x[0-9]+)+ /*dxd_pattern*/
- | [0-9]+_[0-9]+(x[0-9]+_[0-9]+)* /*window_pad_pattern*/
+ | [0-9bf]{3,}_[0-9io]{3,}->[0-9bf]{3,} /*dim_labels_pattern*/
+ | [0-9]+(x[0-9]+)+ /*dxd_pattern*/
+ | [0-9]+_[0-9]+(_[0-9]+)?(x[0-9]+_[0-9]+(_[0-9]+)?)* /*pad_pattern*/
| '{' sub_attributes '}'
;
diff --git a/tensorflow/compiler/xla/tools/parser/hlo_lexer.cc b/tensorflow/compiler/xla/tools/parser/hlo_lexer.cc
index f70386411c..b5befbf58b 100644
--- a/tensorflow/compiler/xla/tools/parser/hlo_lexer.cc
+++ b/tensorflow/compiler/xla/tools/parser/hlo_lexer.cc
@@ -254,13 +254,13 @@ TokKind HloLexer::LexPercent() {
}
// Lex integer and floating-point values, -inf, and patterns for dim labels,
-// dxd (e.g. 1x2x3), and window pad.
+// dxd (e.g. 1x2x3), and pad.
//
// fp with exp ::= [-]?([0-9]+|[0-9]+[.][0-9]*|[0-9]*[.][0-9]+)([eE][+-]?[0-9]+)
// fp without exp ::= [-]?([0-9]+[.][0-9]*|[0-9]*[.][0-9]+)
// dim_labels_pattern ::= [0-9bf]{3,}_[0-9io]{3,}->[0-9bf]{3,}
// dxd_pattern ::= [0-9]+(x[0-9]+)+
-// window_pad_pattern ::= [0-9]+_[0-9]+(x[0-9]+_[0-9]+)*
+// pad_pattern ::= [0-9]+_[0-9]+(_[0-9]+)?(x[0-9]+_[0-9]+(_[0-9]+)?)*
// int ::= [-]?[0-9]+
// negative inf ::= '-inf'
TokKind HloLexer::LexNumberOrPattern() {
@@ -277,7 +277,8 @@ TokKind HloLexer::LexNumberOrPattern() {
static LazyRE2 dim_labels_pattern = {
R"([0-9bf]{3,}_[0-9io]{3,}->[0-9bf]{3,})"};
static LazyRE2 dxd_pattern = {R"([0-9]+(x[0-9]+)+)"};
- static LazyRE2 pad_pattern = {R"([0-9]+_[0-9]+(x[0-9]+_[0-9]+)*)"};
+ static LazyRE2 pad_pattern = {
+ R"([0-9]+_[0-9]+(_[0-9]+)?(x[0-9]+_[0-9]+(_[0-9]+)?)*)"};
if (RE2::Consume(&consumable, *dim_labels_pattern)) {
current_ptr_ = consumable.begin();
@@ -294,7 +295,7 @@ TokKind HloLexer::LexNumberOrPattern() {
if (RE2::Consume(&consumable, *pad_pattern)) {
current_ptr_ = consumable.begin();
str_val_.assign(token_start_, current_ptr_);
- return TokKind::kWindowPad;
+ return TokKind::kPad;
}
static LazyRE2 int_pattern = {R"([-]?\d+)"};
@@ -395,8 +396,8 @@ string TokKindToString(TokKind kind) {
return "kDimLabels";
case TokKind::kDxD:
return "kDxD";
- case TokKind::kWindowPad:
- return "kWindowPad";
+ case TokKind::kPad:
+ return "kPad";
case TokKind::kShape:
return "kShape";
case TokKind::kOpcode:
diff --git a/tensorflow/compiler/xla/tools/parser/hlo_lexer.h b/tensorflow/compiler/xla/tools/parser/hlo_lexer.h
index 74e6829180..79c4f271a1 100644
--- a/tensorflow/compiler/xla/tools/parser/hlo_lexer.h
+++ b/tensorflow/compiler/xla/tools/parser/hlo_lexer.h
@@ -45,7 +45,7 @@ class HloLexer {
case TokKind::kAttributeName:
case TokKind::kDimLabels:
case TokKind::kDxD:
- case TokKind::kWindowPad:
+ case TokKind::kPad:
return str_val_;
default:
LOG(FATAL) << "This token does not have string value";
diff --git a/tensorflow/compiler/xla/tools/parser/hlo_parser.cc b/tensorflow/compiler/xla/tools/parser/hlo_parser.cc
index 710877b4e0..fed0492a54 100644
--- a/tensorflow/compiler/xla/tools/parser/hlo_parser.cc
+++ b/tensorflow/compiler/xla/tools/parser/hlo_parser.cc
@@ -99,6 +99,7 @@ class HloParser {
kSharding,
kInstructionList,
kSliceRanges,
+ kPaddingConfig,
};
struct AttrConfig {
@@ -134,6 +135,7 @@ class HloParser {
bool ParseInstructionNames(std::vector<HloInstruction*>* instructions);
bool ParseWindow(Window* window);
bool ParseConvolutionDimensionNumbers(ConvolutionDimensionNumbers* dnums);
+ bool ParsePaddingConfig(PaddingConfig* padding);
bool ParseSharding(OpSharding* sharding);
bool ParseSingleSharding(OpSharding* sharding, bool lbrace_pre_lexed);
@@ -727,9 +729,19 @@ bool HloParser::ParseInstruction(HloComputation::Builder* builder,
/*grad_output=*/operands[4], *epsilon, *feature_index));
break;
}
+ case HloOpcode::kPad: {
+ optional<PaddingConfig> padding;
+ attrs["padding"] = {/*required=*/true, AttrTy::kPaddingConfig, &padding};
+ if (!ParseOperands(&operands, /*expected_size=*/2) ||
+ !ParseAttributes(attrs)) {
+ return false;
+ }
+ instruction = builder->AddInstruction(HloInstruction::CreatePad(
+ shape, operands[0], /*padding_value=*/operands[1], *padding));
+ break;
+ }
case HloOpcode::kCustomCall:
case HloOpcode::kReducePrecision:
- case HloOpcode::kPad:
case HloOpcode::kRng:
case HloOpcode::kFusion:
case HloOpcode::kInfeed:
@@ -1374,6 +1386,14 @@ bool HloParser::ParseAttributes(
static_cast<optional<SliceRanges>*>(attr_out_ptr)->emplace(result);
return true;
}
+ case AttrTy::kPaddingConfig: {
+ PaddingConfig result;
+ if (!ParsePaddingConfig(&result)) {
+ return false;
+ }
+ static_cast<optional<PaddingConfig>*>(attr_out_ptr)->emplace(result);
+ return true;
+ }
}
}();
if (!success) {
@@ -1774,7 +1794,7 @@ bool HloParser::ParseWindowPad(std::vector<std::vector<int64>>* pad) {
if (!pad->empty()) {
return TokenError("sub-attribute 'pad=' already exists");
}
- if (lexer_.GetKind() != TokKind::kWindowPad) {
+ if (lexer_.GetKind() != TokKind::kPad) {
return TokenError("expects window pad pattern, e.g., '0_0x3_3'");
}
string str = lexer_.GetStrVal();
@@ -1792,6 +1812,33 @@ bool HloParser::ParseWindowPad(std::vector<std::vector<int64>>* pad) {
return true;
}
+// This is the inverse xla::ToString(PaddingConfig). The padding config string
+// looks like "0_0_0x3_3_1". The string is first separated by 'x', each
+// substring represents one PaddingConfigDimension. The substring is 3 (or 2)
+// numbers joined by '_'.
+bool HloParser::ParsePaddingConfig(PaddingConfig* padding) {
+ if (lexer_.GetKind() != TokKind::kPad) {
+ return TokenError("expects padding config, e.g., '0_0_0x3_3_1'");
+ }
+ string str = lexer_.GetStrVal();
+ std::vector<string> padding_str = Split(str, 'x');
+ for (const auto& padding_dim_str : padding_str) {
+ std::vector<int64> padding_dim;
+ if (!SplitAndParseAsInts(padding_dim_str, '_', &padding_dim) ||
+ (padding_dim.size() != 2 && padding_dim.size() != 3)) {
+ return TokenError(
+ "expects padding config pattern like 'low_high_interior' or "
+ "'low_high'");
+ }
+ auto* dim = padding->add_dimensions();
+ dim->set_edge_padding_low(padding_dim[0]);
+ dim->set_edge_padding_high(padding_dim[1]);
+ dim->set_interior_padding(padding_dim.size() == 3 ? padding_dim[2] : 0);
+ }
+ lexer_.Lex();
+ return true;
+}
+
bool HloParser::ParseOpcode(HloOpcode* result) {
VLOG(1) << "ParseOpcode";
if (lexer_.GetKind() != TokKind::kOpcode) {
diff --git a/tensorflow/compiler/xla/tools/parser/hlo_parser_test.cc b/tensorflow/compiler/xla/tools/parser/hlo_parser_test.cc
index fbe0409e3d..d19c6e1877 100644
--- a/tensorflow/compiler/xla/tools/parser/hlo_parser_test.cc
+++ b/tensorflow/compiler/xla/tools/parser/hlo_parser_test.cc
@@ -36,6 +36,10 @@ string TestDataToString(const ::testing::TestParamInfo<TestData>& data) {
return data.param.test_name;
}
+// For each string below, we check that:
+// - we parse it to an HloModule successfully, and
+// - the stringification of the resulting HloModule is equal to our original
+// string.
std::vector<TestData> CreateTestCases() {
// clang-format off
return std::vector<TestData>({
@@ -510,6 +514,32 @@ ENTRY %BatchNormGrad.v4 (input: f32[2,2,2,2], scale: f32[2], mean: f32[2], varia
}
)"
+},
+// pad
+{
+"Pad",
+R"(HloModule Pad1DS3Array_module:
+
+ENTRY %Pad1DS3Array.v3 () -> f32[8] {
+ %constant = f32[3]{0} constant({1, 2, 3})
+ %constant.1 = f32[] constant(0.1)
+ ROOT %pad = f32[8]{0} pad(f32[3]{0} %constant, f32[] %constant.1), padding=3_1
+}
+
+)"
+},
+// pad has interior
+{
+"PadHasInterior",
+R"(HloModule PadHasInterior_module:
+
+ENTRY %PadHasInterior.v3 (input: f32[1,25,7,7]) -> f32[1,25,17,11] {
+ %input = f32[1,25,7,7]{3,2,1,0} parameter(0)
+ %constant = f32[] constant(-5.123)
+ ROOT %pad = f32[1,25,17,11]{3,2,1,0} pad(f32[1,25,7,7]{3,2,1,0} %input, f32[] %constant), padding=0_0_0x0_0_0x2_2_1x2_2_0
+}
+
+)"
}
});
// clang-format on
@@ -523,7 +553,10 @@ class HloParserTest : public ::testing::Test,
<< "'" << s << "' does not contain '" << expected << "'";
}
- void ExpectSuccess() {
+ // Expects "ToString(Parse(string)) == string", that is, parses the string,
+ // asserts that it succeeded, stringifies the parsed module, and checks that
+ // the it equals the original string.
+ void ExpectEqual() {
const string& original = GetParam().module_string;
auto result = Parse(original);
TF_EXPECT_OK(result.status());
@@ -532,7 +565,7 @@ class HloParserTest : public ::testing::Test,
}
};
-TEST_P(HloParserTest, Run) { ExpectSuccess(); }
+TEST_P(HloParserTest, Run) { ExpectEqual(); }
INSTANTIATE_TEST_CASE_P(HloParserTestSuccessInstantiation, HloParserTest,
::testing::ValuesIn(CreateTestCases()),
@@ -793,6 +826,21 @@ ENTRY %slice.v2 (p0: f32[3,3,4,4]) -> f32[3,3,2,4] {
TF_EXPECT_OK(Parse(original).status());
}
+TEST_F(HloParserTest, PaddingConfigIsNotWindowPad) {
+ const string original = R"(HloModule window_pad_module:
+
+ENTRY %Convolve1D1Window_0.v3 (input: f32[1,2,1], filter: f32[1,1,1]) -> f32[1,2,1] {
+ %input = f32[1,2,1]{2,1,0} parameter(0)
+ %copy = f32[1,2,1]{2,0,1} copy(f32[1,2,1]{2,1,0} %input)
+ %filter = f32[1,1,1]{2,1,0} parameter(1)
+ ROOT %convolution = f32[1,2,1]{2,0,1} convolution(f32[1,2,1]{2,0,1} %copy, f32[1,1,1]{2,1,0} %filter), dim_labels=b0f_0io->b0f, window={pad=1_1_0 size=1}
+}
+
+)";
+ ExpectHasSubstr(Parse(original).status().error_message(),
+ "expects padding_low and padding_high separated by '_'");
+}
+
} // namespace
} // namespace tools
} // namespace xla
diff --git a/tensorflow/compiler/xla/tools/parser/hlo_token.h b/tensorflow/compiler/xla/tools/parser/hlo_token.h
index 15ab8b1ccc..9afd2fac23 100644
--- a/tensorflow/compiler/xla/tools/parser/hlo_token.h
+++ b/tensorflow/compiler/xla/tools/parser/hlo_token.h
@@ -59,7 +59,7 @@ enum class TokKind {
kAttributeName, // dimensions=
kDimLabels, // [0-9bf]+_[0-9io]+->[0-9bf]+
kDxD, // [0-9]+(x[0-9]+)+
- kWindowPad, // [0-9]+_[0-9]+(x[0-9]+_[0-9]+)*
+ kPad, // [0-9]+_[0-9]+(_[0-9]+)?(x[0-9]+_[0-9]+(_[0-9]+)?)*
kShape, // f32[2,3]{1,0}
kOpcode, // add
kInt, // 42