Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
ModelZoo
ResNet50_tensorflow
Commits
edea2b67
Commit
edea2b67
authored
May 11, 2018
by
Terry Koo
Browse files
Remove runtime because reasons.
parent
a4bb31d0
Changes
291
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
0 additions
and
3846 deletions
+0
-3846
research/syntaxnet/dragnn/runtime/math/sgemvv_test.cc
research/syntaxnet/dragnn/runtime/math/sgemvv_test.cc
+0
-409
research/syntaxnet/dragnn/runtime/math/transformations.h
research/syntaxnet/dragnn/runtime/math/transformations.h
+0
-140
research/syntaxnet/dragnn/runtime/math/transformations_test.cc
...rch/syntaxnet/dragnn/runtime/math/transformations_test.cc
+0
-101
research/syntaxnet/dragnn/runtime/math/types.h
research/syntaxnet/dragnn/runtime/math/types.h
+0
-455
research/syntaxnet/dragnn/runtime/math/types_test.cc
research/syntaxnet/dragnn/runtime/math/types_test.cc
+0
-482
research/syntaxnet/dragnn/runtime/mmap.cc
research/syntaxnet/dragnn/runtime/mmap.cc
+0
-138
research/syntaxnet/dragnn/runtime/mmap.h
research/syntaxnet/dragnn/runtime/mmap.h
+0
-93
research/syntaxnet/dragnn/runtime/mmap_array_variable_store.cc
...rch/syntaxnet/dragnn/runtime/mmap_array_variable_store.cc
+0
-39
research/syntaxnet/dragnn/runtime/mmap_array_variable_store.h
...arch/syntaxnet/dragnn/runtime/mmap_array_variable_store.h
+0
-51
research/syntaxnet/dragnn/runtime/mmap_test.cc
research/syntaxnet/dragnn/runtime/mmap_test.cc
+0
-176
research/syntaxnet/dragnn/runtime/mst_solver_component_base.cc
...rch/syntaxnet/dragnn/runtime/mst_solver_component_base.cc
+0
-115
research/syntaxnet/dragnn/runtime/mst_solver_component_base.h
...arch/syntaxnet/dragnn/runtime/mst_solver_component_base.h
+0
-91
research/syntaxnet/dragnn/runtime/mst_solver_component_base_test.cc
...yntaxnet/dragnn/runtime/mst_solver_component_base_test.cc
+0
-189
research/syntaxnet/dragnn/runtime/multiarch.bzl
research/syntaxnet/dragnn/runtime/multiarch.bzl
+0
-203
research/syntaxnet/dragnn/runtime/myelin/BUILD
research/syntaxnet/dragnn/runtime/myelin/BUILD
+0
-331
research/syntaxnet/dragnn/runtime/myelin/attr_value_utils.cc
research/syntaxnet/dragnn/runtime/myelin/attr_value_utils.cc
+0
-150
research/syntaxnet/dragnn/runtime/myelin/attr_value_utils.h
research/syntaxnet/dragnn/runtime/myelin/attr_value_utils.h
+0
-38
research/syntaxnet/dragnn/runtime/myelin/attr_value_utils_test.cc
.../syntaxnet/dragnn/runtime/myelin/attr_value_utils_test.cc
+0
-105
research/syntaxnet/dragnn/runtime/myelin/build_defs.bzl
research/syntaxnet/dragnn/runtime/myelin/build_defs.bzl
+0
-78
research/syntaxnet/dragnn/runtime/myelin/myelin_cell_converter.cc
.../syntaxnet/dragnn/runtime/myelin/myelin_cell_converter.cc
+0
-462
No files found.
Too many changes to show.
To preserve performance only
291 of 291+
files are displayed.
Plain diff
Email patch
research/syntaxnet/dragnn/runtime/math/sgemvv_test.cc
deleted
100644 → 0
View file @
a4bb31d0
// Copyright 2017 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// =============================================================================
#include "dragnn/runtime/math/sgemvv.h"
#include <chrono>
#include <random>
#include "dragnn/core/test/generic.h"
#include "dragnn/runtime/math/arithmetic.h"
#include "dragnn/runtime/math/transformations.h"
#include "dragnn/runtime/math/types.h"
#include "dragnn/runtime/test/helpers.h"
#include "tensorflow/core/lib/core/status_test_util.h"
#include "tensorflow/core/lib/strings/strcat.h"
#include "tensorflow/core/platform/test.h"
namespace
syntaxnet
{
namespace
dragnn
{
namespace
runtime
{
void
naive_sgemv
(
const
MutableMatrix
<
float
>
&
matrix
,
const
float
*
v
,
const
float
*
b
,
float
*
y
)
{
for
(
int
row
=
0
;
row
<
matrix
.
num_rows
();
row
++
)
{
y
[
row
]
=
b
[
row
];
for
(
int
col
=
0
;
col
<
matrix
.
num_columns
();
col
++
)
{
y
[
row
]
+=
matrix
.
row
(
row
)[
col
]
*
v
[
col
];
}
}
}
// Everything except floats require copying.
template
<
class
ElementType
>
constexpr
bool
RequiresCopy
();
template
<
>
constexpr
bool
RequiresCopy
<
TruncatedFloat16
>
()
{
return
true
;
}
#if defined(__F16C__)
template
<
>
constexpr
bool
RequiresCopy
<
IeeeFloat16
>
()
{
return
true
;
}
#endif
template
<
>
constexpr
bool
RequiresCopy
<
float
>
()
{
return
false
;
}
template
<
class
ElementType
>
void
ConvertRow
(
Vector
<
float
>
input
,
MutableVector
<
ElementType
>
output
);
template
<
>
void
ConvertRow
<
float
>
(
Vector
<
float
>
input
,
MutableVector
<
float
>
output
)
{}
template
<
>
void
ConvertRow
<
TruncatedFloat16
>
(
Vector
<
float
>
input
,
MutableVector
<
TruncatedFloat16
>
output
)
{
CHECK_EQ
(
input
.
size
()
%
16
,
0
);
CHECK_EQ
(
input
.
size
(),
output
.
size
());
for
(
int
i
=
0
;
i
<
input
.
size
();
++
i
)
{
int
i_permuted
=
(
i
/
16
)
*
16
+
FastUnpackPermutation
(
i
%
16
);
output
[
i
]
=
TruncatedFloat16
::
DebugFromFloat
(
input
[
i_permuted
]);
}
}
#if defined(__F16C__)
template
<
>
void
ConvertRow
<
IeeeFloat16
>
(
Vector
<
float
>
input
,
MutableVector
<
IeeeFloat16
>
output
)
{
CHECK_EQ
(
input
.
size
()
%
16
,
0
);
CHECK_EQ
(
input
.
size
(),
output
.
size
());
for
(
int
i
=
0
;
i
<
input
.
size
();
++
i
)
{
output
[
i
]
=
IeeeFloat16
::
DebugFromFloat
(
input
[
i
]);
}
}
#endif
// Converts a matrix to SGEMV. If the element type is not float, copies the
// matrix and then converts it.
template
<
int
sse_batch_size
,
typename
ElementType
=
float
>
SgemvMatrix
<
sse_batch_size
,
ElementType
>
ConvertToSgemv
(
const
Matrix
<
float
>
&
matrix
,
UniqueMatrix
<
ElementType
>
*
sgemv_storage
)
{
MutableBlockedMatrix
<
ElementType
,
BlockedMatrixFormat
::
kRowBlockedColumnMajor
>
blocked
;
TF_EXPECT_OK
(
blocked
.
Reset
(
sgemv_storage
->
area
(),
matrix
.
num_rows
(),
matrix
.
num_columns
()));
// TODO(googleuser): Clean this up when we can use C++17's `if constexpr`
// ... then we will not have to introduce this raw pointer, which is either
// an actual new variable or alias to `sgemv_storage`.
UniqueMatrix
<
float
>
*
uncompressed
;
if
(
RequiresCopy
<
ElementType
>
())
{
uncompressed
=
new
UniqueMatrix
<
float
>
((
*
sgemv_storage
)
->
num_rows
(),
(
*
sgemv_storage
)
->
num_columns
());
}
else
{
// NOTE: Because we don't have C++17's `if constexpr`, we need to add a
// reinterpret_cast, so this code can compile when ElementType != float.
uncompressed
=
reinterpret_cast
<
UniqueMatrix
<
float
>
*>
(
sgemv_storage
);
}
// Copy to the uncompressed matrix. If ElementType == float, this is just
// the output, otherwise it's the temporary array.
MutableBlockedMatrix
<
float
,
BlockedMatrixFormat
::
kRowBlockedColumnMajor
>
uncompressed_matrix
;
TF_EXPECT_OK
(
uncompressed_matrix
.
Reset
(
uncompressed
->
area
(),
matrix
.
num_rows
(),
matrix
.
num_columns
()));
TF_EXPECT_OK
(
CopyMatrix
(
matrix
,
&
uncompressed_matrix
));
if
(
RequiresCopy
<
ElementType
>
())
{
for
(
int
i
=
0
;
i
<
blocked
.
num_vectors
();
++
i
)
{
ConvertRow
<
ElementType
>
(
Vector
<
float
>
(
uncompressed_matrix
.
vector
(
i
)),
blocked
.
vector
(
i
));
}
delete
uncompressed
;
}
SgemvMatrix
<
sse_batch_size
,
ElementType
>
sgemv_matrix
;
TF_EXPECT_OK
(
sgemv_matrix
.
Initialize
(
blocked
.
AsConst
()));
return
sgemv_matrix
;
}
void
InitRandomVector
(
MutableVector
<
float
>
vector
)
{
// clock() is updated less frequently than a cycle counter, so keep around the
// RNG just in case we initialize some vectors in less than a clock tick.
static
std
::
mt19937
*
rng
=
new
std
::
mt19937
(
clock
());
std
::
normal_distribution
<
float
>
distribution
(
0
,
1
);
for
(
int
i
=
0
;
i
<
vector
.
size
();
i
++
)
{
vector
[
i
]
=
distribution
(
*
rng
);
}
}
void
InitRandomMatrix
(
MutableMatrix
<
float
>
matrix
)
{
// See InitRandomVector comment.
static
std
::
mt19937
*
rng
=
new
std
::
mt19937
(
clock
());
std
::
normal_distribution
<
float
>
distribution
(
0
,
1
);
GenerateMatrix
(
matrix
.
num_rows
(),
matrix
.
num_columns
(),
[
&
distribution
](
int
row
,
int
col
)
{
return
distribution
(
*
rng
);
},
&
matrix
);
}
TEST
(
SgemvvTest
,
MatmulNoBias
)
{
constexpr
int
sse_batch_size
=
32
;
constexpr
int
num_rows
=
32
;
constexpr
int
num_columns
=
15
;
constexpr
int
output_size
=
8
;
constexpr
int
sgemv_views
=
num_rows
*
num_columns
/
sse_batch_size
;
static_assert
(
num_rows
*
num_columns
%
sse_batch_size
==
0
,
"Bad matrix size"
);
ASSERT_EQ
(
output_size
%
8
,
0
)
<<
"Output size must still be 32-byte aligned."
;
UniqueMatrix
<
float
>
matrix
(
num_rows
,
num_columns
);
UniqueMatrix
<
float
>
sgemv_storage
(
sgemv_views
,
sse_batch_size
);
UniqueVector
<
float
>
input_vector
(
num_columns
);
UniqueVector
<
float
>
output
(
num_rows
);
UniqueVector
<
float
>
expected
(
num_rows
);
// Random initialization for all variables/values.
InitRandomMatrix
(
*
matrix
);
InitRandomVector
(
*
output
);
InitRandomVector
(
*
expected
);
InitRandomVector
(
*
input_vector
);
// Layout SGEMV matrix.
SgemvMatrix
<
sse_batch_size
>
sgemv_matrix
=
ConvertToSgemv
<
sse_batch_size
>
(
Matrix
<
float
>
(
*
matrix
),
&
sgemv_storage
);
// SGEMV multiplication.
SgemvInputBatch
<
1
>
inputs
=
{{
input_vector
->
data
()},
{
nullptr
}};
SgemvOutputBatch
<
1
>
outputs
=
{{
output
->
data
()}};
sgemv_matrix
.
MaskedMatrixMultiVectorProductNoInitial
(
inputs
,
output_size
,
&
outputs
);
// Naive algorithm.
MultiplyMatrixAndVector
<
float
>
(
Matrix
<
float
>
(
*
matrix
),
Vector
<
float
>
(
*
input_vector
),
*
expected
);
// Check that results are equal.
for
(
int
i
=
0
;
i
<
output_size
;
i
++
)
{
EXPECT_NEAR
(
output
->
data
()[
i
],
expected
->
data
()[
i
],
1e-5
);
}
}
TEST
(
SgemvvTest
,
ErrorsWithBadMultiple
)
{
// Pick num_rows which is (32-byte) alignable, but not a multiple of
// sse_batch_size (32 floats). These should return errors.
for
(
int
num_rows
=
8
;
num_rows
<
32
;
num_rows
+=
8
)
{
// Layout blocked matrix.
UniqueMatrix
<
float
>
sgemv_storage
(
1
,
num_rows
);
MutableBlockedMatrix
<
float
,
BlockedMatrixFormat
::
kRowBlockedColumnMajor
>
blocked
;
TF_EXPECT_OK
(
blocked
.
Reset
(
sgemv_storage
.
area
(),
num_rows
,
1
));
// Initialize SgemvvMatrix.
SgemvMatrix
<
32
>
matrix
;
EXPECT_THAT
(
matrix
.
Initialize
(
blocked
.
AsConst
()),
test
::
IsErrorWithSubstr
(
"must be equal to sse_batch_size"
));
}
}
template
<
typename
ElementType
>
string
TypenameString
();
template
<
>
string
TypenameString
<
float
>
()
{
return
"float32"
;
}
template
<
>
string
TypenameString
<
TruncatedFloat16
>
()
{
return
"bfloat16"
;
}
#if defined(__F16C__)
template
<
>
string
TypenameString
<
IeeeFloat16
>
()
{
return
"float16"
;
}
#endif
template
<
typename
ElementType
>
float
ToleranceAt128
();
template
<
>
float
ToleranceAt128
<
float
>
()
{
return
1e-5
;
}
template
<
>
float
ToleranceAt128
<
TruncatedFloat16
>
()
{
return
1
;
}
#if defined(__F16C__)
template
<
>
float
ToleranceAt128
<
IeeeFloat16
>
()
{
return
1e-1
;
}
#endif
template
<
int
sse_batch_size
,
int
num_rows
,
int
num_cols
,
typename
ElementType
>
void
RunPerformanceTest
(
int
output_size
)
{
constexpr
int
sgemv_views
=
num_rows
*
num_cols
/
sse_batch_size
;
static_assert
(
num_rows
*
num_cols
%
sse_batch_size
==
0
,
"Bad matrix size"
);
ASSERT_EQ
(
output_size
%
8
,
0
)
<<
"Output size must still be 32-byte aligned."
;
UniqueMatrix
<
float
>
matrix
(
num_rows
,
num_cols
);
UniqueMatrix
<
ElementType
>
sgemv_storage
(
sgemv_views
,
sse_batch_size
);
UniqueVector
<
float
>
initial_1
(
num_rows
);
UniqueVector
<
float
>
initial_2
(
num_rows
);
UniqueVector
<
float
>
vector_1
(
num_cols
);
UniqueVector
<
float
>
vector_2
(
num_cols
);
UniqueVector
<
float
>
output_1
(
num_rows
);
UniqueVector
<
float
>
output_2
(
num_rows
);
UniqueVector
<
float
>
expected_output_1
(
num_rows
);
UniqueVector
<
float
>
expected_output_2
(
num_rows
);
UniqueVector
<
float
>
untouched_output_1
(
num_rows
);
UniqueVector
<
float
>
untouched_output_2
(
num_rows
);
// Random initialization for all variables/values.
InitRandomMatrix
(
*
matrix
);
InitRandomVector
(
*
initial_1
);
InitRandomVector
(
*
initial_2
);
InitRandomVector
(
*
output_1
);
InitRandomVector
(
*
output_2
);
InitRandomVector
(
*
expected_output_1
);
InitRandomVector
(
*
expected_output_2
);
InitRandomVector
(
*
vector_1
);
InitRandomVector
(
*
vector_2
);
for
(
int
i
=
0
;
i
<
num_rows
;
i
++
)
{
(
*
untouched_output_1
)[
i
]
=
(
*
output_1
)[
i
];
(
*
untouched_output_2
)[
i
]
=
(
*
output_2
)[
i
];
}
// Layout SGEMV matrix.
SgemvMatrix
<
sse_batch_size
,
ElementType
>
sgemv_matrix
=
ConvertToSgemv
<
sse_batch_size
,
ElementType
>
(
Matrix
<
float
>
(
*
matrix
),
&
sgemv_storage
);
naive_sgemv
(
*
matrix
,
vector_1
->
data
(),
initial_1
->
data
(),
expected_output_1
->
data
());
naive_sgemv
(
*
matrix
,
vector_2
->
data
(),
initial_2
->
data
(),
expected_output_2
->
data
());
double
raw_flops_per_iteration
=
2.0
*
2.0
*
num_rows
*
num_cols
;
const
uint64
iterations
=
static_cast
<
uint64
>
(
std
::
round
(
4e9
/
raw_flops_per_iteration
));
auto
start_time
=
std
::
chrono
::
system_clock
::
now
();
SgemvInputBatch
<
2
>
inputs
=
{
{
vector_1
->
data
(),
vector_2
->
data
()},
{
initial_1
->
data
(),
initial_2
->
data
()},
};
SgemvOutputBatch
<
2
>
outputs
=
{{
output_1
->
data
(),
output_2
->
data
()}};
if
(
num_rows
==
output_size
)
{
for
(
int
iter
=
0
;
iter
<
iterations
;
iter
++
)
{
sgemv_matrix
.
template
MatrixMultiVectorProduct
<
2
,
0
,
0
>(
inputs
,
&
outputs
);
}
}
else
{
for
(
int
iter
=
0
;
iter
<
iterations
;
iter
++
)
{
sgemv_matrix
.
template
MaskedMatrixMultiVectorProduct
<
2
>(
inputs
,
output_size
,
&
outputs
);
}
}
auto
end_time
=
std
::
chrono
::
system_clock
::
now
();
std
::
chrono
::
duration
<
double
>
elapsed_seconds
=
end_time
-
start_time
;
double
elapsed
=
elapsed_seconds
.
count
();
// Each MatrixVectorVectorProduct does 2 Matrix-vector ops, and each op does a
// multiply and an add (2 floating-point operations) for each entry in the
// matrix.
string
raw_gflops
=
""
;
if
(
num_rows
!=
output_size
)
{
raw_gflops
=
::
tensorflow
::
strings
::
StrCat
(
", "
,
raw_flops_per_iteration
*
iterations
/
1e9
/
elapsed
,
" raw"
);
}
VLOG
(
0
)
<<
" ElementType "
<<
TypenameString
<
ElementType
>
()
<<
" GFLOPS: "
<<
(
2.0
*
2.0
*
output_size
*
num_cols
*
iterations
)
/
1e9
/
elapsed
<<
" effective"
<<
raw_gflops
;
const
float
tolerance
=
ToleranceAt128
<
ElementType
>
()
*
(
num_rows
/
128.0
)
+
1e-5
;
for
(
int
i
=
0
;
i
<
output_size
;
i
++
)
{
EXPECT_NEAR
(
output_1
->
data
()[
i
],
expected_output_1
->
data
()[
i
],
tolerance
);
EXPECT_NEAR
(
output_2
->
data
()[
i
],
expected_output_2
->
data
()[
i
],
tolerance
);
}
// Check that any non-output items are untouched.
for
(
int
i
=
output_size
;
i
<
num_rows
;
i
++
)
{
EXPECT_EQ
((
*
output_1
)[
i
],
(
*
untouched_output_1
)[
i
]);
EXPECT_EQ
((
*
output_2
)[
i
],
(
*
untouched_output_2
)[
i
]);
}
}
TEST
(
SgemvvTest
,
PerformanceAndAccuracyTest
)
{
// Benchmarking is hard. Sometimes results vary between test runs, or are just
// unreliable. This could be in part from CPU frequency scaling, and also how
// favorably the memory allocator places data (coherence, etc.).
constexpr
int
kNumBatches
=
3
;
VLOG
(
0
)
<<
"64x64 32-batch-size test"
;
for
(
int
batch
=
0
;
batch
<
kNumBatches
;
++
batch
)
{
RunPerformanceTest
<
32
,
64
,
64
,
float
>
(
64
);
#if defined(__F16C__)
RunPerformanceTest
<
32
,
64
,
64
,
IeeeFloat16
>
(
64
);
#endif
}
VLOG
(
0
)
<<
"128x128 32-batch-size test"
;
for
(
int
batch
=
0
;
batch
<
kNumBatches
;
++
batch
)
{
RunPerformanceTest
<
32
,
128
,
128
,
float
>
(
128
);
}
VLOG
(
0
)
<<
"256x256 32-batch-size test"
;
for
(
int
batch
=
0
;
batch
<
kNumBatches
;
++
batch
)
{
RunPerformanceTest
<
32
,
256
,
256
,
float
>
(
256
);
#if defined(__F16C__)
RunPerformanceTest
<
32
,
256
,
256
,
IeeeFloat16
>
(
256
);
#endif
RunPerformanceTest
<
32
,
256
,
256
,
TruncatedFloat16
>
(
256
);
}
VLOG
(
0
)
<<
"96x96 48-batch-size test"
;
for
(
int
batch
=
0
;
batch
<
kNumBatches
;
++
batch
)
{
RunPerformanceTest
<
48
,
96
,
96
,
float
>
(
96
);
}
VLOG
(
0
)
<<
"48x96 48-batch-size test"
;
for
(
int
batch
=
0
;
batch
<
kNumBatches
;
++
batch
)
{
RunPerformanceTest
<
48
,
48
,
96
,
float
>
(
48
);
}
VLOG
(
0
)
<<
"40x96 48-batch-size test"
;
for
(
int
batch
=
0
;
batch
<
kNumBatches
;
++
batch
)
{
RunPerformanceTest
<
48
,
48
,
96
,
float
>
(
40
);
}
// These larger matrices are about the same amount of computation as one
// 96-dimensional LSTM cell (without output softmax).
VLOG
(
0
)
<<
"480x96 48-batch-size test"
;
for
(
int
batch
=
0
;
batch
<
kNumBatches
;
++
batch
)
{
RunPerformanceTest
<
48
,
480
,
96
,
float
>
(
480
);
#if defined(__F16C__)
RunPerformanceTest
<
48
,
480
,
96
,
IeeeFloat16
>
(
480
);
#endif
RunPerformanceTest
<
48
,
480
,
96
,
TruncatedFloat16
>
(
480
);
}
VLOG
(
0
)
<<
"472x96 48-batch-size test"
;
for
(
int
batch
=
0
;
batch
<
kNumBatches
;
++
batch
)
{
RunPerformanceTest
<
48
,
480
,
96
,
float
>
(
472
);
#if defined(__F16C__)
RunPerformanceTest
<
48
,
480
,
96
,
IeeeFloat16
>
(
472
);
#endif
RunPerformanceTest
<
48
,
480
,
96
,
TruncatedFloat16
>
(
472
);
}
}
}
// namespace runtime
}
// namespace dragnn
}
// namespace syntaxnet
research/syntaxnet/dragnn/runtime/math/transformations.h
deleted
100644 → 0
View file @
a4bb31d0
// Copyright 2017 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// =============================================================================
// Utility functions that can transform different matrix types. This includes
// non-trivial transposes, and converting vectors/etc. to the matrix types. This
// library should NOT be used for any performance-critical work, and should NOT
// be included at all in the mobile runtime.
#ifndef DRAGNN_RUNTIME_MATH_TRANSFORMATIONS_H_
#define DRAGNN_RUNTIME_MATH_TRANSFORMATIONS_H_
#include "dragnn/runtime/math/types.h"
#include "tensorflow/core/lib/core/errors.h"
#include "tensorflow/core/lib/core/status.h"
namespace
syntaxnet
{
namespace
dragnn
{
namespace
runtime
{
namespace
internal
{
// Puts a format-agnostic API on matrix-like data types. This is convenient, but
// has the downside of potential confusing compiler errors (when a
// specialization does not exist), and isn't suitable for optimizations like
// blocked transformations.
template
<
class
T
>
T
*
GetMatrixElement
(
int
row
,
int
col
,
MatrixImpl
<
T
>
*
matrix
)
{
return
&
matrix
->
row
(
row
)[
col
];
}
template
<
class
T
>
const
T
&
GetMatrixElement
(
int
row
,
int
col
,
const
MatrixImpl
<
T
>
&
matrix
)
{
return
matrix
.
row
(
row
)[
col
];
}
template
<
class
T
>
T
*
GetMatrixElement
(
int
row
,
int
col
,
BlockedMatrixImpl
<
T
,
BlockedMatrixFormat
::
kRowBlockedColumnMajor
>
*
matrix
)
{
int
sub_matrix_idx
=
row
/
matrix
->
block_size
();
int
vector_idx
=
sub_matrix_idx
*
matrix
->
num_columns
()
+
col
;
int
element_idx
=
row
%
matrix
->
block_size
();
return
&
matrix
->
vector
(
vector_idx
)[
element_idx
];
}
template
<
class
T
>
const
T
&
GetMatrixElement
(
int
row
,
int
col
,
const
BlockedMatrixImpl
<
T
,
BlockedMatrixFormat
::
kRowBlockedColumnMajor
>
&
matrix
)
{
int
sub_matrix_idx
=
row
/
matrix
.
block_size
();
int
vector_idx
=
sub_matrix_idx
*
matrix
.
num_columns
()
+
col
;
int
element_idx
=
row
%
matrix
.
block_size
();
return
matrix
.
vector
(
vector_idx
)[
element_idx
];
}
template
<
class
T
>
T
*
GetMatrixElement
(
int
row
,
int
col
,
BlockedMatrixImpl
<
T
,
BlockedMatrixFormat
::
kColumnBlockedRowMajor
>
*
matrix
)
{
int
sub_matrix_idx
=
col
/
matrix
->
block_size
();
int
vector_idx
=
sub_matrix_idx
*
matrix
->
num_rows
()
+
row
;
int
element_idx
=
col
%
matrix
->
block_size
();
return
&
matrix
->
vector
(
vector_idx
)[
element_idx
];
}
template
<
class
T
>
const
T
&
GetMatrixElement
(
int
row
,
int
col
,
const
BlockedMatrixImpl
<
T
,
BlockedMatrixFormat
::
kColumnBlockedRowMajor
>
&
matrix
)
{
int
sub_matrix_idx
=
col
/
matrix
.
block_size
();
int
vector_idx
=
sub_matrix_idx
*
matrix
.
num_rows
()
+
row
;
int
element_idx
=
col
%
matrix
.
block_size
();
return
matrix
.
vector
(
vector_idx
)[
element_idx
];
}
}
// namespace internal
// Generates values for a matrix, by calling a provided function on each
// row/column index. Thanks to the magic of templating, the function call should
// be inlined and not cause too much overhead being "called" on each index.
template
<
class
Function
,
class
OutputMatrix
>
void
GenerateMatrix
(
int
num_rows
,
int
num_columns
,
const
Function
&
get_value
,
OutputMatrix
*
output_matrix
)
{
for
(
size_t
row
=
0
;
row
<
num_rows
;
++
row
)
{
for
(
size_t
column
=
0
;
column
<
num_columns
;
++
column
)
{
*
(
GetMatrixElement
(
row
,
column
,
output_matrix
))
=
get_value
(
row
,
column
);
}
}
}
// Copies the first |num_rows| rows and |num_columns| columns of input_matrix to
// output_matrix.
template
<
class
InputMatrix
,
class
OutputMatrix
>
void
CopyMatrixPrefix
(
const
InputMatrix
&
input_matrix
,
int
num_rows
,
int
num_columns
,
OutputMatrix
*
output_matrix
)
{
const
auto
&
get_value
=
[
input_matrix
](
int
row
,
int
column
)
{
return
GetMatrixElement
(
row
,
column
,
input_matrix
);
};
GenerateMatrix
(
num_rows
,
num_columns
,
get_value
,
output_matrix
);
}
// Copies matrices. The matrices can be of different types, but must have the
// same dimensions.
template
<
class
InputMatrix
,
class
OutputMatrix
>
tensorflow
::
Status
CopyMatrix
(
const
InputMatrix
&
input_matrix
,
OutputMatrix
*
output_matrix
)
{
if
(
input_matrix
.
num_rows
()
!=
output_matrix
->
num_rows
())
{
return
tensorflow
::
errors
::
InvalidArgument
(
"Input matrix num_rows ("
,
input_matrix
.
num_rows
(),
") != output matrix num_rows ("
,
output_matrix
->
num_rows
(),
")"
);
}
if
(
input_matrix
.
num_columns
()
!=
output_matrix
->
num_columns
())
{
return
tensorflow
::
errors
::
InvalidArgument
(
"Input matrix num_columns ("
,
input_matrix
.
num_columns
(),
") != output matrix num_columns ("
,
output_matrix
->
num_columns
(),
")"
);
}
CopyMatrixPrefix
(
input_matrix
,
input_matrix
.
num_rows
(),
input_matrix
.
num_columns
(),
output_matrix
);
return
tensorflow
::
Status
::
OK
();
}
}
// namespace runtime
}
// namespace dragnn
}
// namespace syntaxnet
#endif // DRAGNN_RUNTIME_MATH_TRANSFORMATIONS_H_
research/syntaxnet/dragnn/runtime/math/transformations_test.cc
deleted
100644 → 0
View file @
a4bb31d0
// Copyright 2017 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// =============================================================================
#include "dragnn/runtime/math/transformations.h"
#include "dragnn/runtime/test/helpers.h"
#include <gmock/gmock.h>
#include "tensorflow/core/lib/core/status.h"
#include "tensorflow/core/lib/core/status_test_util.h"
#include "tensorflow/core/platform/test.h"
namespace
syntaxnet
{
namespace
dragnn
{
namespace
runtime
{
namespace
{
// Generates a matrix where each value is of the form `aa.bb`, where `aa` is the
// column index and `bb` is the row index.
TEST
(
TransformationsTest
,
GenerateRowColIdxMatrix
)
{
UniqueMatrix
<
float
>
row_col_matrix
(
5
,
5
);
GenerateMatrix
(
5
,
5
,
[](
int
row
,
int
col
)
{
return
static_cast
<
float
>
(
row
)
+
(
col
/
100.0
f
);
},
row_col_matrix
.
get
());
ExpectMatrix
(
Matrix
<
float
>
(
*
row_col_matrix
),
{{
0.0
f
,
0.01
f
,
0.02
f
,
0.03
f
,
0.04
f
},
{
1.0
f
,
1.01
f
,
1.02
f
,
1.03
f
,
1.04
f
},
{
2.0
f
,
2.01
f
,
2.02
f
,
2.03
f
,
2.04
f
},
{
3.0
f
,
3.01
f
,
3.02
f
,
3.03
f
,
3.04
f
},
{
4.0
f
,
4.01
f
,
4.02
f
,
4.03
f
,
4.04
f
}});
}
TEST
(
TransformationsTest
,
CopiesMatrix
)
{
UniqueMatrix
<
float
>
a
({{
1
,
2
}}),
b
({{
3
,
4
}});
TF_EXPECT_OK
(
CopyMatrix
(
*
a
,
b
.
get
()));
EXPECT_EQ
(
b
->
row
(
0
)[
0
],
1
);
EXPECT_EQ
(
b
->
row
(
0
)[
1
],
2
);
}
TEST
(
TransformationsTest
,
CopiesRowBlockedMatrix
)
{
UniqueMatrix
<
double
>
source
({{
1
,
2
,
3
},
//
{
4
,
5
,
6
},
//
{
7
,
8
,
9
},
//
{
10
,
11
,
12
},
//
{
13
,
14
,
15
},
//
{
16
,
17
,
18
},
//
{
19
,
20
,
21
},
//
{
22
,
23
,
24
}});
UniqueMatrix
<
double
>
dst_mem
(
6
,
4
);
MutableBlockedMatrix
<
double
,
BlockedMatrixFormat
::
kRowBlockedColumnMajor
>
blocked
;
TF_EXPECT_OK
(
blocked
.
Reset
(
dst_mem
.
area
(),
8
,
3
));
TF_EXPECT_OK
(
CopyMatrix
(
*
source
,
&
blocked
));
ExpectMatrix
(
Matrix
<
double
>
(
*
dst_mem
),
{{
1
,
4
,
7
,
10
},
//
{
2
,
5
,
8
,
11
},
//
{
3
,
6
,
9
,
12
},
//
{
13
,
16
,
19
,
22
},
//
{
14
,
17
,
20
,
23
},
//
{
15
,
18
,
21
,
24
}});
}
// This test is the same as the above, except everything is transposed.
TEST
(
TransformationsTest
,
CopiesColumnBlockedMatrix
)
{
UniqueMatrix
<
double
>
source
(
//
{{
1
,
4
,
7
,
10
,
13
,
16
,
19
,
22
},
//
{
2
,
5
,
8
,
11
,
14
,
17
,
20
,
23
},
//
{
3
,
6
,
9
,
12
,
15
,
18
,
21
,
24
}});
UniqueMatrix
<
double
>
dst_mem
(
6
,
4
);
MutableBlockedMatrix
<
double
>
blocked
;
TF_EXPECT_OK
(
blocked
.
Reset
(
dst_mem
.
area
(),
3
,
8
));
TF_EXPECT_OK
(
CopyMatrix
(
*
source
,
&
blocked
));
ExpectMatrix
(
Matrix
<
double
>
(
*
dst_mem
),
{{
1
,
4
,
7
,
10
},
//
{
2
,
5
,
8
,
11
},
//
{
3
,
6
,
9
,
12
},
//
{
13
,
16
,
19
,
22
},
//
{
14
,
17
,
20
,
23
},
//
{
15
,
18
,
21
,
24
}});
}
}
// namespace
}
// namespace runtime
}
// namespace dragnn
}
// namespace syntaxnet
research/syntaxnet/dragnn/runtime/math/types.h
deleted
100644 → 0
View file @
a4bb31d0
// Copyright 2017 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// =============================================================================
// Mathematical types.
#ifndef DRAGNN_RUNTIME_MATH_TYPES_H_
#define DRAGNN_RUNTIME_MATH_TYPES_H_
#include <stddef.h>
#include <limits>
#include "dragnn/runtime/alignment.h"
#include "tensorflow/core/lib/core/errors.h"
#include "tensorflow/core/lib/core/status.h"
#include "tensorflow/core/platform/logging.h"
namespace
syntaxnet
{
namespace
dragnn
{
namespace
runtime
{
// Blocked matrix formats, for fast inference routines.
enum
class
BlockedMatrixFormat
{
// Represents a row-blocked block-column-major matrix. In other words, first
// split a matrix M into
//
// [ M_1
// ...
// M_m ]
//
// sub-matrices, where each M_i is a `block_size x n` sub-matrix. Then each
// M_i is formatted in column-major order, and the sub-matrices' data is
// concatenated together.
kRowBlockedColumnMajor
,
// Represents a column-blocked block-row-major matrix. This is the
// transpose of the above. A matrix M is split into
//
// [ M_1 ... M_n ]
//
// sub-matrices, where each M_i is a `m x block_size` sub-matrix. Then each
// M_i is formatted in row-major order, and the sub-matrices' data is
// concatenated together.
kColumnBlockedRowMajor
,
};
namespace
internal
{
// An aligned vector of values. Do not use this class directly, instead use
// (Mutable)Vector below.
template
<
class
T
>
class
VectorImpl
{
public:
static_assert
(
IsAlignable
<
T
>
(),
"T must be alignable"
);
// Creates an empty vector.
VectorImpl
()
=
default
;
// Points this at the |view|, which must be evenly divisible into Ts.
template
<
class
Byte
>
explicit
VectorImpl
(
AlignedViewImpl
<
Byte
>
view
);
// Points this at a prefix of the |view| containing |size| Ts. The |view|
// must span at least |size| * sizeof(T) bytes.
template
<
class
Byte
>
VectorImpl
(
AlignedViewImpl
<
Byte
>
view
,
size_t
size
);
// Points this at the same values as |that|, possibly reinterpreting type.
template
<
class
U
>
explicit
VectorImpl
(
VectorImpl
<
U
>
that
);
template
<
class
U
>
VectorImpl
&
operator
=
(
VectorImpl
<
U
>
that
);
// Enables range-based for loops.
T
*
begin
()
const
{
return
data
();
}
T
*
end
()
const
{
return
begin
()
+
size
();
}
// Accessors.
T
*
data
()
const
{
return
data_
;
}
size_t
size
()
const
{
return
size_
;
}
bool
empty
()
const
{
return
size
()
==
0
;
}
T
&
operator
[](
size_t
index
)
const
;
// Gets a sub-vector starting at |start| with |size| elements.
VectorImpl
<
T
>
Subsequence
(
size_t
start
,
size_t
size
)
const
;
private:
template
<
class
U
>
friend
class
MatrixImpl
;
template
<
class
U
,
BlockedMatrixFormat
format
>
friend
class
BlockedMatrixImpl
;
// Points this at [|data|,|data|+|size|), bypassing alignment checks.
VectorImpl
(
T
*
data
,
size_t
size
);
// Pointer to the start of the vector.
T
*
data_
=
nullptr
;
// Number of values in the vector.
size_t
size_
=
0
;
};
// Returns the format corresponding to the transpose of the |format|.
constexpr
BlockedMatrixFormat
TransposeBlockedMatrixFormat
(
BlockedMatrixFormat
format
);
// A row-major matrix where each row or column is aligned. Do not use this
// class directly, instead use (Mutable)Matrix below.
template
<
class
T
>
class
MatrixImpl
{
public:
static_assert
(
IsAlignable
<
T
>
(),
"T must be alignable"
);
// Creates an empty matrix.
MatrixImpl
()
=
default
;
// Points each row of this matrix at the corresponding sub-view of the |area|.
// Each view in the |area| must be evenly divisible into Ts.
template
<
class
Byte
>
explicit
MatrixImpl
(
AlignedAreaImpl
<
Byte
>
area
);
// Creates a matrix from a single vector. Assumes that the vector's stride is
// the minimum alignment padding.
explicit
MatrixImpl
(
VectorImpl
<
T
>
single_vector
);
// Points this at the same values as |that|.
template
<
class
U
>
explicit
MatrixImpl
(
MatrixImpl
<
U
>
that
);
template
<
class
U
>
MatrixImpl
&
operator
=
(
MatrixImpl
<
U
>
that
);
// Accessors.
T
*
data
()
const
{
return
data_
;
}
size_t
num_rows
()
const
{
return
num_rows_
;
}
size_t
num_columns
()
const
{
return
num_columns_
;
}
size_t
row_stride
()
const
{
return
row_stride_
;
}
VectorImpl
<
T
>
row
(
size_t
index
)
const
;
private:
template
<
class
U
>
friend
class
MatrixImpl
;
// Pointer to the start of the matrix.
T
*
data_
=
nullptr
;
// Number of rows and columns in the matrix.
size_t
num_rows_
=
0
;
size_t
num_columns_
=
0
;
// Distance between the starts of consecutive rows.
size_t
row_stride_
=
0
;
};
// Blocked matrix representation. See BlockedMatrixFormat for details.
template
<
class
T
,
BlockedMatrixFormat
format
>
class
BlockedMatrixImpl
{
public:
static_assert
(
IsAlignable
<
T
>
(),
"T must be alignable"
);
// These aliases allow templated code to reach back in and get template
// parameters, like std::vector<T>::iterator::value aliases.
using
ElementType
=
T
;
static
constexpr
bool
IsRowBlocked
()
{
return
format
==
BlockedMatrixFormat
::
kRowBlockedColumnMajor
;
}
// Creates an empty matrix.
BlockedMatrixImpl
()
=
default
;
// Creates a copy of this matrix, using the same values (underlying area), but
// possibly re-interpreting the type. The new type U must be the same size,
// and `T *` must be implictly convertible to `U *` (usually just adding
// "const" qualifiers, but theoretically it could be a superclass).
template
<
class
U
>
explicit
BlockedMatrixImpl
(
BlockedMatrixImpl
<
U
,
format
>
that
);
template
<
class
U
>
BlockedMatrixImpl
&
operator
=
(
BlockedMatrixImpl
<
U
,
format
>
that
);
// Creates a new view that's const-qualified, in particular converting
// MutableBlockedMatrix to BlockedMatrix.
BlockedMatrixImpl
<
const
T
,
format
>
AsConst
()
const
{
return
BlockedMatrixImpl
<
const
T
,
format
>
(
*
this
);
}
// Initializes the matrix. Raises errors if the matrix dimensions are
// incompatible with the underlying area, namely if the number of views in
// `area` do not cover the whole matrix, and also if the matrix cannot be
// blocked according to (template parameter) `format`.
//
// Further, because this class is used for (delicate / specialized) optimized
// inference routines, it is also required that no padding is present, i.e.
// that the block size is divisible by kAlignmentBytes (currently 32).
template
<
class
Byte
>
tensorflow
::
Status
Reset
(
AlignedAreaImpl
<
Byte
>
area
,
size_t
num_rows
,
size_t
num_columns
);
// Returns the transpose of this.
BlockedMatrixImpl
<
T
,
TransposeBlockedMatrixFormat
(
format
)
>
Transpose
()
const
;
// Accessors.
size_t
num_rows
()
const
{
return
num_rows_
;
}
size_t
num_columns
()
const
{
return
num_columns_
;
}
size_t
block_size
()
const
{
return
block_size_
;
}
size_t
num_vectors
()
const
{
return
num_vectors_
;
}
VectorImpl
<
T
>
vector
(
size_t
index
)
const
;
private:
template
<
class
U
,
BlockedMatrixFormat
other_format
>
friend
class
BlockedMatrixImpl
;
// This is the same as calling Reset(), except the area is not checked.
template
<
class
Byte
>
explicit
BlockedMatrixImpl
(
AlignedAreaImpl
<
Byte
>
area
,
int
num_rows
,
int
num_columns
);
// Pointer to the start of the matrix.
T
*
data_
=
nullptr
;
// Number of rows and columns in the matrix. Unlike MatrixImpl, there is no
// API for directly accessing rows and columns, but it's necessary for any
// algorithm (e.g. matrix-vector multiplication) to know the logical shape.
size_t
num_rows_
=
0
;
size_t
num_columns_
=
0
;
size_t
block_size_
=
0
;
// in T's
size_t
num_vectors_
=
0
;
// = num_rows * num_columns / block_size
};
}
// namespace internal
// Public aliases; use these.
template
<
class
T
>
using
Vector
=
internal
::
VectorImpl
<
const
T
>
;
template
<
class
T
>
using
Matrix
=
internal
::
MatrixImpl
<
const
T
>
;
template
<
class
T
,
BlockedMatrixFormat
format
=
BlockedMatrixFormat
::
kColumnBlockedRowMajor
>
using
BlockedMatrix
=
internal
::
BlockedMatrixImpl
<
const
T
,
format
>
;
template
<
class
T
>
using
MutableVector
=
internal
::
VectorImpl
<
T
>
;
template
<
class
T
>
using
MutableMatrix
=
internal
::
MatrixImpl
<
T
>
;
template
<
class
T
,
BlockedMatrixFormat
format
=
BlockedMatrixFormat
::
kColumnBlockedRowMajor
>
using
MutableBlockedMatrix
=
internal
::
BlockedMatrixImpl
<
T
,
format
>
;
// Implementation details below.
namespace
internal
{
template
<
class
T
>
template
<
class
Byte
>
VectorImpl
<
T
>::
VectorImpl
(
AlignedViewImpl
<
Byte
>
view
)
:
data_
(
reinterpret_cast
<
T
*>
(
view
.
data
())),
size_
(
view
.
size
()
/
sizeof
(
T
))
{
DCHECK_EQ
(
view
.
size
()
%
sizeof
(
T
),
0
);
}
template
<
class
T
>
template
<
class
Byte
>
VectorImpl
<
T
>::
VectorImpl
(
AlignedViewImpl
<
Byte
>
view
,
size_t
size
)
:
data_
(
reinterpret_cast
<
T
*>
(
view
.
data
())),
size_
(
size
)
{
DCHECK_LE
(
size
*
sizeof
(
T
),
view
.
size
());
}
template
<
class
T
>
template
<
class
U
>
VectorImpl
<
T
>::
VectorImpl
(
VectorImpl
<
U
>
that
)
:
data_
(
that
.
data
()),
size_
(
that
.
size
())
{
static_assert
(
sizeof
(
T
)
==
sizeof
(
U
),
"T and U must be the same size"
);
}
template
<
class
T
>
template
<
class
U
>
VectorImpl
<
T
>
&
VectorImpl
<
T
>::
operator
=
(
VectorImpl
<
U
>
that
)
{
static_assert
(
sizeof
(
T
)
==
sizeof
(
U
),
"T and U must be the same size"
);
data_
=
that
.
data
();
size_
=
that
.
size
();
return
*
this
;
}
template
<
class
T
>
T
&
VectorImpl
<
T
>::
operator
[](
size_t
index
)
const
{
DCHECK_LT
(
index
,
size
());
return
data_
[
index
];
}
template
<
class
T
>
VectorImpl
<
T
>::
VectorImpl
(
T
*
data
,
size_t
size
)
:
data_
(
data
),
size_
(
size
)
{
TF_DCHECK_OK
(
OkIfAligned
(
data
));
}
template
<
class
T
>
VectorImpl
<
T
>
VectorImpl
<
T
>::
Subsequence
(
size_t
start
,
size_t
size
)
const
{
DCHECK_LE
(
start
+
size
,
size_
);
return
VectorImpl
<
T
>
(
&
data_
[
start
],
size
);
}
constexpr
BlockedMatrixFormat
TransposeBlockedMatrixFormat
(
BlockedMatrixFormat
format
)
{
return
format
==
BlockedMatrixFormat
::
kRowBlockedColumnMajor
?
BlockedMatrixFormat
::
kColumnBlockedRowMajor
:
BlockedMatrixFormat
::
kRowBlockedColumnMajor
;
}
template
<
class
T
>
MatrixImpl
<
T
>::
MatrixImpl
(
VectorImpl
<
T
>
single_vector
)
:
data_
(
single_vector
.
data
()),
num_rows_
(
1
),
num_columns_
(
single_vector
.
size
()),
row_stride_
(
PadToAlignment
(
single_vector
.
size
()
*
sizeof
(
T
))
/
sizeof
(
T
))
{}
template
<
class
T
>
template
<
class
Byte
>
MatrixImpl
<
T
>::
MatrixImpl
(
AlignedAreaImpl
<
Byte
>
area
)
:
data_
(
reinterpret_cast
<
T
*>
(
area
.
data
())),
num_rows_
(
area
.
num_views
()),
num_columns_
(
area
.
view_size
()
/
sizeof
(
T
)),
row_stride_
(
area
.
view_stride
()
/
sizeof
(
T
))
{
DCHECK_EQ
(
area
.
view_size
()
%
sizeof
(
T
),
0
);
DCHECK_EQ
(
area
.
view_stride
()
%
sizeof
(
T
),
0
);
}
template
<
class
T
>
template
<
class
U
>
MatrixImpl
<
T
>::
MatrixImpl
(
MatrixImpl
<
U
>
that
)
:
data_
(
that
.
data_
),
num_rows_
(
that
.
num_rows
()),
num_columns_
(
that
.
num_columns
()),
row_stride_
(
that
.
row_stride_
)
{
static_assert
(
sizeof
(
T
)
==
sizeof
(
U
),
"T and U must be the same size"
);
}
template
<
class
T
>
template
<
class
U
>
MatrixImpl
<
T
>
&
MatrixImpl
<
T
>::
operator
=
(
MatrixImpl
<
U
>
that
)
{
static_assert
(
sizeof
(
T
)
==
sizeof
(
U
),
"T and U must be the same size"
);
data_
=
that
.
data_
;
num_rows_
=
that
.
num_rows
();
num_columns_
=
that
.
num_columns
();
row_stride_
=
that
.
row_stride_
;
return
*
this
;
}
template
<
class
T
>
VectorImpl
<
T
>
MatrixImpl
<
T
>::
row
(
size_t
index
)
const
{
DCHECK_LT
(
index
,
num_rows
());
// Note that |row_stride_|, not |num_columns_|, determines the start of the
// row. The former is aligned and may stride over a wider span than normal
// when this is a "slice" of a larger matrix.
return
VectorImpl
<
T
>
(
data_
+
row_stride_
*
index
,
num_columns
());
}
template
<
class
T
,
BlockedMatrixFormat
format
>
template
<
class
U
>
BlockedMatrixImpl
<
T
,
format
>::
BlockedMatrixImpl
(
BlockedMatrixImpl
<
U
,
format
>
that
)
:
data_
(
that
.
data_
),
num_rows_
(
that
.
num_rows
()),
num_columns_
(
that
.
num_columns
()),
block_size_
(
that
.
block_size
()),
num_vectors_
(
that
.
num_vectors
())
{
static_assert
(
sizeof
(
T
)
==
sizeof
(
U
),
"T and U must be the same size"
);
}
template
<
class
T
,
BlockedMatrixFormat
format
>
template
<
class
U
>
BlockedMatrixImpl
<
T
,
format
>
&
BlockedMatrixImpl
<
T
,
format
>::
operator
=
(
BlockedMatrixImpl
<
U
,
format
>
that
)
{
static_assert
(
sizeof
(
T
)
==
sizeof
(
U
),
"T and U must be the same size"
);
data_
=
that
.
data_
;
num_rows_
=
that
.
num_rows
();
num_columns_
=
that
.
num_columns
();
block_size_
=
that
.
block_size
();
num_vectors_
=
that
.
num_vectors
();
return
*
this
;
}
template
<
class
T
,
BlockedMatrixFormat
format
>
template
<
class
Byte
>
tensorflow
::
Status
BlockedMatrixImpl
<
T
,
format
>::
Reset
(
AlignedAreaImpl
<
Byte
>
area
,
size_t
num_rows
,
size_t
num_columns
)
{
data_
=
reinterpret_cast
<
T
*>
(
area
.
view
(
0
).
data
());
num_rows_
=
num_rows
;
num_columns_
=
num_columns
;
block_size_
=
area
.
view_size
()
/
sizeof
(
T
);
num_vectors_
=
num_rows
*
num_columns
/
block_size_
;
if
(
area
.
view_stride
()
!=
area
.
view_size
())
{
return
tensorflow
::
errors
::
InvalidArgument
(
"Padding is not supported for blocked matrix formats. Underlying area "
"has size "
,
area
.
view_size
(),
" which is padded to stride "
,
area
.
view_stride
(),
"."
);
}
if
(
area
.
view_size
()
%
sizeof
(
T
)
!=
0
)
{
return
tensorflow
::
errors
::
InvalidArgument
(
"View size "
,
area
.
view_size
(),
" is not a multiple of the templated type's size, "
,
sizeof
(
T
));
}
if
(
num_vectors_
!=
area
.
num_views
())
{
return
tensorflow
::
errors
::
InvalidArgument
(
"Area has "
,
area
.
num_views
(),
" views, but should have "
,
num_vectors_
);
}
// The block dimension must divide rows or columns evenly.
size_t
divided_dimension
=
IsRowBlocked
()
?
num_rows
:
num_columns
;
if
(
divided_dimension
%
block_size_
!=
0
)
{
return
tensorflow
::
errors
::
InvalidArgument
(
IsRowBlocked
()
?
"row"
:
"column"
,
"-blocked matrix has major dimension "
,
divided_dimension
,
" which is not divisible by the block size, "
,
block_size_
);
}
return
tensorflow
::
Status
::
OK
();
}
template
<
class
T
,
BlockedMatrixFormat
format
>
VectorImpl
<
T
>
BlockedMatrixImpl
<
T
,
format
>::
vector
(
size_t
index
)
const
{
DCHECK_LT
(
index
,
num_vectors_
);
return
VectorImpl
<
T
>
(
data_
+
block_size_
*
index
,
block_size_
);
}
template
<
class
T
,
BlockedMatrixFormat
format
>
BlockedMatrixImpl
<
T
,
TransposeBlockedMatrixFormat
(
format
)
>
BlockedMatrixImpl
<
T
,
format
>::
Transpose
()
const
{
BlockedMatrixImpl
<
T
,
TransposeBlockedMatrixFormat
(
format
)
>
result
;
result
.
data_
=
data_
;
result
.
num_columns_
=
num_rows_
;
result
.
num_rows_
=
num_columns_
;
result
.
block_size_
=
block_size_
;
result
.
num_vectors_
=
num_vectors_
;
return
result
;
}
}
// namespace internal
}
// namespace runtime
}
// namespace dragnn
}
// namespace syntaxnet
#endif // DRAGNN_RUNTIME_MATH_TYPES_H_
research/syntaxnet/dragnn/runtime/math/types_test.cc
deleted
100644 → 0
View file @
a4bb31d0
// Copyright 2017 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// =============================================================================
#include "dragnn/runtime/math/types.h"
#include <stddef.h>
#include <string.h>
#include <set>
#include "dragnn/core/test/generic.h"
#include "dragnn/runtime/alignment.h"
#include "tensorflow/core/lib/core/status.h"
#include "tensorflow/core/lib/core/status_test_util.h"
#include "tensorflow/core/platform/test.h"
namespace
syntaxnet
{
namespace
dragnn
{
namespace
runtime
{
namespace
{
// Creates a pointer that is be invalid. This is useful for creating proxy areas
// for testing, whose real data should never be accessed. We manually tested
// that if this pointer is dereferenced, a segmentation fault will be thrown.
char
*
InvalidAlignedPointer
()
{
return
reinterpret_cast
<
char
*>
(
3
*
internal
::
kAlignmentBytes
);
}
// Expects that two pointers point to the same address.
void
ExpectSameAddress
(
const
void
*
ptr1
,
const
void
*
ptr2
)
{
EXPECT_EQ
(
ptr1
,
ptr2
);
}
template
<
class
A
,
class
B
>
bool
StructsEqual
(
const
A
&
a
,
const
B
&
b
)
{
static_assert
(
sizeof
(
A
)
==
sizeof
(
B
),
"StructsEqual must be given structs of the same size."
);
return
memcmp
(
&
a
,
&
b
,
sizeof
(
A
))
==
0
;
}
// Tests that (Mutable)Vector is empty by default.
TEST
(
VectorTest
,
EmptyByDefault
)
{
const
Vector
<
int
>
vector1
;
EXPECT_EQ
(
vector1
.
size
(),
0
);
EXPECT_TRUE
(
vector1
.
empty
());
const
MutableVector
<
int
>
vector2
;
EXPECT_EQ
(
vector2
.
size
(),
0
);
EXPECT_TRUE
(
vector2
.
empty
());
}
// Tests that (Mutable)Vector can be initialized from a view.
TEST
(
VectorTest
,
ConstructFromView
)
{
MutableAlignedView
view
;
char
*
ptr
=
InvalidAlignedPointer
();
TF_ASSERT_OK
(
view
.
Reset
(
ptr
,
10
*
sizeof
(
int
)));
const
Vector
<
int
>
vector1
(
view
);
ExpectSameAddress
(
vector1
.
data
(),
ptr
);
EXPECT_EQ
(
vector1
.
size
(),
10
);
EXPECT_FALSE
(
vector1
.
empty
());
const
MutableVector
<
int
>
vector2
(
view
);
ExpectSameAddress
(
vector2
.
data
(),
ptr
);
EXPECT_EQ
(
vector2
.
size
(),
10
);
EXPECT_FALSE
(
vector2
.
empty
());
}
// Tests that (Mutable)Vector can be initialized from a prefix of a view.
TEST
(
VectorTest
,
ConstructFromViewPrefix
)
{
MutableAlignedView
view
;
char
*
ptr
=
InvalidAlignedPointer
();
TF_ASSERT_OK
(
view
.
Reset
(
ptr
,
10
*
sizeof
(
int
)));
// Use a prefix of 3 of the 10 available ints in the |view|.
const
Vector
<
int
>
vector1
(
view
,
3
);
ExpectSameAddress
(
vector1
.
data
(),
ptr
);
EXPECT_EQ
(
vector1
.
size
(),
3
);
EXPECT_FALSE
(
vector1
.
empty
());
// Use a prefix of 5 of the 10 available ints in the |view|.
const
MutableVector
<
int
>
vector2
(
view
,
5
);
ExpectSameAddress
(
vector2
.
data
(),
ptr
);
EXPECT_EQ
(
vector2
.
size
(),
5
);
EXPECT_FALSE
(
vector2
.
empty
());
}
// Tests that (Mutable)Vector supports copy-construction and assignment with
// shallow-copy semantics, and reinterprets from T* to const T*.
TEST
(
VectorTest
,
CopyAndAssign
)
{
MutableAlignedView
view
;
char
*
ptr
=
InvalidAlignedPointer
();
TF_ASSERT_OK
(
view
.
Reset
(
ptr
,
10
*
sizeof
(
int
)));
const
MutableVector
<
int
>
vector1
(
view
);
// Copy-construct from another vector.
MutableVector
<
int
>
vector2
(
vector1
);
ExpectSameAddress
(
vector2
.
data
(),
ptr
);
EXPECT_EQ
(
vector2
.
size
(),
10
);
EXPECT_FALSE
(
vector2
.
empty
());
// Assign from an empty vector, effectively clearing it.
vector2
=
MutableVector
<
int
>
();
EXPECT_EQ
(
vector2
.
size
(),
0
);
EXPECT_TRUE
(
vector2
.
empty
());
// Assign from the original vector.
vector2
=
vector1
;
ExpectSameAddress
(
vector2
.
data
(),
ptr
);
EXPECT_EQ
(
vector2
.
size
(),
10
);
EXPECT_FALSE
(
vector2
.
empty
());
// Copy-construct from another vector. Note that this reinterprets type.
Vector
<
int
>
vector3
(
vector1
);
ExpectSameAddress
(
vector3
.
data
(),
ptr
);
EXPECT_EQ
(
vector3
.
size
(),
10
);
EXPECT_FALSE
(
vector3
.
empty
());
// Assign from an empty vector, effectively clearing it.
vector3
=
Vector
<
int
>
();
EXPECT_EQ
(
vector3
.
size
(),
0
);
EXPECT_TRUE
(
vector3
.
empty
());
// Assign from another vector. Note that this reinterprets type.
vector3
=
vector2
;
ExpectSameAddress
(
vector3
.
data
(),
ptr
);
EXPECT_EQ
(
vector3
.
size
(),
10
);
EXPECT_FALSE
(
vector3
.
empty
());
}
// Tests that (Mutable)Vector supports access via operator[].
TEST
(
VectorTest
,
Subscript
)
{
UniqueAlignedArray
array
;
array
.
Reset
(
10
*
sizeof
(
float
));
// Write into a mutable vector.
const
MutableVector
<
float
>
mutable_vector
(
array
.
view
());
ASSERT_EQ
(
mutable_vector
.
size
(),
10
);
for
(
int
i
=
0
;
i
<
10
;
++
i
)
mutable_vector
[
i
]
=
i
;
// Read from a const vector that points at the same values.
const
Vector
<
float
>
const_vector
(
array
.
view
());
ASSERT_EQ
(
const_vector
.
size
(),
10
);
for
(
int
i
=
0
;
i
<
10
;
++
i
)
EXPECT_EQ
(
const_vector
[
i
],
i
);
}
// Tests the subsequence operator.
TEST
(
VectorTest
,
Subsequence
)
{
// Debug checks will fail if either of the constructed vectors is not aligned.
constexpr
int
numAlignedFloats
=
internal
::
kAlignmentBytes
/
sizeof
(
float
);
UniqueAlignedArray
array
;
array
.
Reset
(
2
*
numAlignedFloats
*
sizeof
(
float
));
// Write into a mutable vector.
const
MutableVector
<
float
>
mutable_vector
(
array
.
view
());
for
(
int
i
=
0
;
i
<
2
*
numAlignedFloats
;
++
i
)
mutable_vector
[
i
]
=
i
;
// Subscript beginning.
Vector
<
float
>
first_half
(
mutable_vector
.
Subsequence
(
0
,
numAlignedFloats
));
ASSERT_EQ
(
first_half
.
size
(),
numAlignedFloats
);
for
(
int
i
=
0
;
i
<
numAlignedFloats
;
++
i
)
{
EXPECT_EQ
(
first_half
[
i
],
i
);
}
// Subscript end.
Vector
<
float
>
second_half
(
mutable_vector
.
Subsequence
(
numAlignedFloats
,
numAlignedFloats
));
ASSERT_EQ
(
second_half
.
size
(),
numAlignedFloats
);
for
(
int
i
=
0
;
i
<
numAlignedFloats
;
++
i
)
{
EXPECT_EQ
(
second_half
[
i
],
i
+
numAlignedFloats
);
}
}
// Tests that (Mutable)Vector supports access via range-based for loops.
TEST
(
VectorTest
,
RangeBasedFor
)
{
UniqueAlignedArray
array
;
array
.
Reset
(
10
*
sizeof
(
float
));
// Write into a mutable vector.
const
MutableVector
<
float
>
mutable_vector
(
array
.
view
());
ASSERT_EQ
(
mutable_vector
.
size
(),
10
);
float
counter
=
0.0
;
for
(
float
&
value
:
mutable_vector
)
value
=
counter
++
;
// Read from a const vector that points at the same values.
const
Vector
<
float
>
const_vector
(
array
.
view
());
ASSERT_EQ
(
const_vector
.
size
(),
10
);
counter
=
0.0
;
for
(
const
float
&
value
:
const_vector
)
EXPECT_EQ
(
value
,
counter
++
);
}
// Tests that (Mutable)Matrix is empty by default.
TEST
(
MatrixTest
,
EmptyByDefault
)
{
const
Matrix
<
int
>
matrix1
;
EXPECT_EQ
(
matrix1
.
num_rows
(),
0
);
EXPECT_EQ
(
matrix1
.
num_columns
(),
0
);
EXPECT_EQ
(
matrix1
.
row_stride
(),
0
);
const
MutableMatrix
<
int
>
matrix2
;
EXPECT_EQ
(
matrix2
.
num_rows
(),
0
);
EXPECT_EQ
(
matrix2
.
num_columns
(),
0
);
EXPECT_EQ
(
matrix2
.
row_stride
(),
0
);
}
// Tests that (Mutable)Matrix can be constructed from an area.
TEST
(
MatrixTest
,
ConstructFromArea
)
{
MutableAlignedView
view
;
char
*
ptr
=
InvalidAlignedPointer
();
const
size_t
kNumRows
=
11
;
const
size_t
kNumColumns
=
13
;
const
size_t
kRowBytes
=
kNumColumns
*
sizeof
(
int
);
const
size_t
kRowStride
=
PadToAlignment
(
kRowBytes
)
/
sizeof
(
int
);
const
size_t
bytes
=
ComputeAlignedAreaSize
(
kNumRows
,
kRowBytes
);
TF_ASSERT_OK
(
view
.
Reset
(
ptr
,
bytes
));
MutableAlignedArea
area
;
TF_ASSERT_OK
(
area
.
Reset
(
view
,
kNumRows
,
kRowBytes
));
const
Matrix
<
int
>
matrix1
(
area
);
EXPECT_EQ
(
matrix1
.
num_rows
(),
kNumRows
);
EXPECT_EQ
(
matrix1
.
num_columns
(),
kNumColumns
);
EXPECT_EQ
(
matrix1
.
row_stride
(),
kRowStride
);
ExpectSameAddress
(
matrix1
.
row
(
0
).
data
(),
ptr
);
ExpectSameAddress
(
matrix1
.
data
(),
ptr
);
const
MutableMatrix
<
int
>
matrix2
(
area
);
EXPECT_EQ
(
matrix2
.
num_rows
(),
kNumRows
);
EXPECT_EQ
(
matrix2
.
num_columns
(),
kNumColumns
);
EXPECT_EQ
(
matrix2
.
row_stride
(),
kRowStride
);
ExpectSameAddress
(
matrix2
.
row
(
0
).
data
(),
ptr
);
ExpectSameAddress
(
matrix2
.
data
(),
ptr
);
}
// Tests that (Mutable)Matrix supports copy-construction and assignment with
// shallow-copy semantics, and reinterprets from T* to const T*.
TEST
(
MatrixTest
,
CopyAndAssign
)
{
MutableAlignedView
view
;
char
*
ptr
=
InvalidAlignedPointer
();
const
size_t
kNumRows
=
11
;
const
size_t
kNumColumns
=
13
;
const
size_t
kRowBytes
=
kNumColumns
*
sizeof
(
int
);
const
size_t
kRowStride
=
PadToAlignment
(
kRowBytes
)
/
sizeof
(
int
);
const
size_t
bytes
=
ComputeAlignedAreaSize
(
kNumRows
,
kRowBytes
);
TF_ASSERT_OK
(
view
.
Reset
(
ptr
,
bytes
));
MutableAlignedArea
area
;
TF_ASSERT_OK
(
area
.
Reset
(
view
,
kNumRows
,
kRowBytes
));
const
MutableMatrix
<
int
>
matrix1
(
area
);
EXPECT_EQ
(
matrix1
.
num_rows
(),
kNumRows
);
EXPECT_EQ
(
matrix1
.
num_columns
(),
kNumColumns
);
EXPECT_EQ
(
matrix1
.
row_stride
(),
kRowStride
);
ExpectSameAddress
(
matrix1
.
row
(
0
).
data
(),
ptr
);
ExpectSameAddress
(
matrix1
.
data
(),
ptr
);
// Copy-construct from another matrix.
MutableMatrix
<
int
>
matrix2
(
matrix1
);
EXPECT_EQ
(
matrix2
.
num_rows
(),
kNumRows
);
EXPECT_EQ
(
matrix2
.
num_columns
(),
kNumColumns
);
EXPECT_EQ
(
matrix2
.
row_stride
(),
kRowStride
);
ExpectSameAddress
(
matrix2
.
row
(
0
).
data
(),
ptr
);
ExpectSameAddress
(
matrix2
.
data
(),
ptr
);
// Assign from an empty matrix, effectively clearing it.
matrix2
=
MutableMatrix
<
int
>
();
EXPECT_EQ
(
matrix2
.
num_rows
(),
0
);
EXPECT_EQ
(
matrix2
.
num_columns
(),
0
);
EXPECT_EQ
(
matrix2
.
row_stride
(),
0
);
// Assign from the original matrix.
matrix2
=
matrix1
;
EXPECT_EQ
(
matrix2
.
num_rows
(),
kNumRows
);
EXPECT_EQ
(
matrix2
.
num_columns
(),
kNumColumns
);
EXPECT_EQ
(
matrix2
.
row_stride
(),
kRowStride
);
ExpectSameAddress
(
matrix2
.
row
(
0
).
data
(),
ptr
);
ExpectSameAddress
(
matrix2
.
data
(),
ptr
);
// Copy-construct from another matrix. Note that this reinterprets type.
Matrix
<
int
>
matrix3
(
matrix2
);
EXPECT_EQ
(
matrix3
.
num_rows
(),
kNumRows
);
EXPECT_EQ
(
matrix3
.
num_columns
(),
kNumColumns
);
EXPECT_EQ
(
matrix3
.
row_stride
(),
kRowStride
);
ExpectSameAddress
(
matrix3
.
row
(
0
).
data
(),
ptr
);
ExpectSameAddress
(
matrix3
.
data
(),
ptr
);
// Assign from an empty matrix, effectively clearing it.
matrix3
=
Matrix
<
int
>
();
EXPECT_EQ
(
matrix3
.
num_rows
(),
0
);
EXPECT_EQ
(
matrix3
.
num_columns
(),
0
);
EXPECT_EQ
(
matrix3
.
row_stride
(),
0
);
// Assign from the original matrix. Note that this reinterprets type.
matrix3
=
matrix1
;
EXPECT_EQ
(
matrix3
.
num_rows
(),
kNumRows
);
EXPECT_EQ
(
matrix3
.
num_columns
(),
kNumColumns
);
EXPECT_EQ
(
matrix3
.
row_stride
(),
kRowStride
);
ExpectSameAddress
(
matrix3
.
row
(
0
).
data
(),
ptr
);
ExpectSameAddress
(
matrix3
.
data
(),
ptr
);
}
// Tests that (Mutable)Matrix supports row access.
TEST
(
MatrixTest
,
Rows
)
{
const
size_t
kNumRows
=
11
;
const
size_t
kNumColumns
=
13
;
const
size_t
bytes
=
ComputeAlignedAreaSize
(
kNumRows
,
kNumColumns
*
sizeof
(
float
));
UniqueAlignedArray
array
;
array
.
Reset
(
bytes
);
MutableAlignedArea
area
;
TF_ASSERT_OK
(
area
.
Reset
(
array
.
view
(),
kNumRows
,
kNumColumns
*
sizeof
(
float
)));
// Write to a mutable matrix.
const
MutableMatrix
<
float
>
mutable_matrix
(
area
);
ASSERT_EQ
(
mutable_matrix
.
num_rows
(),
kNumRows
);
ASSERT_EQ
(
mutable_matrix
.
num_columns
(),
kNumColumns
);
for
(
size_t
row
=
0
;
row
<
kNumRows
;
++
row
)
{
for
(
size_t
column
=
0
;
column
<
kNumColumns
;
++
column
)
{
mutable_matrix
.
row
(
row
)[
column
]
=
row
*
1000.0
+
column
;
}
}
// Read from a const matrix that points at the same values.
const
Matrix
<
float
>
const_matrix
(
area
);
ASSERT_EQ
(
const_matrix
.
num_rows
(),
kNumRows
);
ASSERT_EQ
(
const_matrix
.
num_columns
(),
kNumColumns
);
for
(
size_t
row
=
0
;
row
<
kNumRows
;
++
row
)
{
for
(
size_t
column
=
0
;
column
<
kNumColumns
;
++
column
)
{
EXPECT_EQ
(
const_matrix
.
row
(
row
)[
column
],
row
*
1000.0
+
column
);
}
}
}
TEST
(
MatrixTest
,
MatrixFromVector
)
{
for
(
int
cols
=
0
;
cols
<
100
;
++
cols
)
{
MutableAlignedView
view
;
char
*
ptr
=
InvalidAlignedPointer
();
TF_ASSERT_OK
(
view
.
Reset
(
ptr
,
cols
*
sizeof
(
int
)));
const
MutableVector
<
int
>
vector
(
view
);
const
MutableMatrix
<
int
>
matrix
(
vector
);
ASSERT_EQ
(
matrix
.
row
(
0
).
data
(),
vector
.
data
());
ExpectSameAddress
(
matrix
.
data
(),
vector
.
data
());
ASSERT_EQ
(
matrix
.
num_rows
(),
1
);
ASSERT_EQ
(
matrix
.
num_columns
(),
vector
.
size
());
}
}
template
<
class
MatrixType
>
class
BlockedMatrixTest
:
public
::
testing
::
Test
{};
typedef
::
testing
::
Types
<
BlockedMatrix
<
float
,
BlockedMatrixFormat
::
kRowBlockedColumnMajor
>
,
BlockedMatrix
<
float
,
BlockedMatrixFormat
::
kColumnBlockedRowMajor
>
,
BlockedMatrix
<
int64
,
BlockedMatrixFormat
::
kRowBlockedColumnMajor
>
,
BlockedMatrix
<
int64
,
BlockedMatrixFormat
::
kColumnBlockedRowMajor
>>
BlockedRowAndColumnTypes
;
TYPED_TEST_CASE
(
BlockedMatrixTest
,
BlockedRowAndColumnTypes
);
TYPED_TEST
(
BlockedMatrixTest
,
PaddingNotAllowed
)
{
MutableAlignedView
view
;
MutableAlignedArea
area
;
constexpr
size_t
kNumRows
=
10
;
constexpr
size_t
kNumColumns
=
10
;
constexpr
size_t
kBlockSize
=
5
;
constexpr
size_t
kNumViews
=
(
kNumRows
*
kNumColumns
)
/
kBlockSize
;
constexpr
size_t
kBlockSizeBytes
=
kBlockSize
*
sizeof
(
typename
TypeParam
::
ElementType
);
const
size_t
bytes
=
ComputeAlignedAreaSize
(
kNumViews
,
kBlockSizeBytes
);
TF_ASSERT_OK
(
view
.
Reset
(
InvalidAlignedPointer
(),
bytes
));
TF_ASSERT_OK
(
area
.
Reset
(
view
,
kNumViews
,
kBlockSizeBytes
));
// 5 is usually relatively prime to the alignment size, but you may have to
// update this test if kAlignmentBytes changes.
ASSERT_NE
(
PadToAlignment
(
kBlockSizeBytes
),
kBlockSizeBytes
);
TypeParam
matrix
;
EXPECT_THAT
(
matrix
.
Reset
(
area
,
kNumRows
,
kNumColumns
),
test
::
IsErrorWithSubstr
(
"Padding is not supported for blocked matrix formats."
));
}
// Tests accessors, and the size of matrices after allocation.
TYPED_TEST
(
BlockedMatrixTest
,
Accessors
)
{
MutableAlignedView
view
;
MutableAlignedArea
area
;
char
*
ptr
=
InvalidAlignedPointer
();
constexpr
size_t
kNumRows
=
48
;
constexpr
size_t
kNumColumns
=
24
;
constexpr
size_t
kBlockSize
=
8
;
constexpr
size_t
kNumViews
=
(
kNumRows
*
kNumColumns
)
/
kBlockSize
;
constexpr
size_t
kBlockSizeBytes
=
kBlockSize
*
sizeof
(
typename
TypeParam
::
ElementType
);
const
size_t
bytes
=
ComputeAlignedAreaSize
(
kNumViews
,
kBlockSizeBytes
);
TF_ASSERT_OK
(
view
.
Reset
(
ptr
,
bytes
));
TF_ASSERT_OK
(
area
.
Reset
(
view
,
kNumViews
,
kBlockSizeBytes
));
TypeParam
matrix
;
// If the view size is wrong, it should fail.
EXPECT_THAT
(
matrix
.
Reset
(
area
,
kNumRows
+
1
,
kNumColumns
),
test
::
IsErrorWithSubstr
(
"Area has 144 views, but should have 147"
));
// If the blocking scheme cannot divide the matrix evenly, an error should
// be raised. The choice of 12 and 96 is a bit non-trivial: they are numbers
// that conveniently result in the correct area (so other errors won't be
// raised), but an incompatible division of the vectors.
if
(
TypeParam
::
IsRowBlocked
())
{
EXPECT_THAT
(
matrix
.
Reset
(
area
,
12
,
96
),
test
::
IsErrorWithSubstr
(
"row-blocked matrix has major dimension 12 "
"which is not divisible by the block "
"size, 8"
));
}
else
{
EXPECT_THAT
(
matrix
.
Reset
(
area
,
96
,
12
),
test
::
IsErrorWithSubstr
(
"column-blocked matrix has major dimension "
"12 which is not divisible by the block "
"size, 8"
));
}
TF_EXPECT_OK
(
matrix
.
Reset
(
area
,
kNumRows
,
kNumColumns
));
EXPECT_EQ
(
matrix
.
vector
(
0
).
data
(),
reinterpret_cast
<
typename
TypeParam
::
ElementType
*>
(
ptr
));
EXPECT_EQ
(
matrix
.
num_rows
(),
kNumRows
);
EXPECT_EQ
(
matrix
.
num_columns
(),
kNumColumns
);
EXPECT_EQ
(
matrix
.
block_size
(),
kBlockSize
);
EXPECT_EQ
(
matrix
.
num_vectors
(),
kNumViews
);
}
TYPED_TEST
(
BlockedMatrixTest
,
CopyCastTranspose
)
{
MutableAlignedView
view
;
MutableAlignedArea
area
;
constexpr
size_t
kNumRows
=
48
;
constexpr
size_t
kNumColumns
=
24
;
constexpr
size_t
kBlockSize
=
8
;
constexpr
size_t
kNumViews
=
(
kNumRows
*
kNumColumns
)
/
kBlockSize
;
constexpr
size_t
kBlockSizeBytes
=
kBlockSize
*
sizeof
(
typename
TypeParam
::
ElementType
);
const
size_t
bytes
=
ComputeAlignedAreaSize
(
kNumViews
,
kBlockSizeBytes
);
TF_ASSERT_OK
(
view
.
Reset
(
InvalidAlignedPointer
(),
bytes
));
TF_ASSERT_OK
(
area
.
Reset
(
view
,
kNumViews
,
kBlockSizeBytes
));
TypeParam
matrix
;
TF_EXPECT_OK
(
matrix
.
Reset
(
area
,
kNumRows
,
kNumColumns
));
// Test both copying and casting to const.
TypeParam
matrix_copy
=
matrix
;
auto
readonly
=
matrix
.
AsConst
();
EXPECT_TRUE
(
StructsEqual
(
matrix
,
matrix_copy
));
EXPECT_TRUE
(
StructsEqual
(
matrix
,
readonly
));
for
(
int
i
=
0
;
i
<
kNumViews
;
++
i
)
{
EXPECT_EQ
(
matrix
.
vector
(
i
).
data
(),
matrix_copy
.
vector
(
i
).
data
());
EXPECT_EQ
(
matrix
.
vector
(
i
).
data
(),
readonly
.
vector
(
i
).
data
());
}
// Transpose matrix.
auto
transposed
=
matrix
.
Transpose
();
auto
readonly_transposed
=
readonly
.
Transpose
();
EXPECT_FALSE
(
StructsEqual
(
matrix
,
transposed
));
EXPECT_FALSE
(
StructsEqual
(
readonly
,
readonly_transposed
));
EXPECT_TRUE
(
StructsEqual
(
transposed
,
readonly_transposed
));
}
}
// namespace
}
// namespace runtime
}
// namespace dragnn
}
// namespace syntaxnet
research/syntaxnet/dragnn/runtime/mmap.cc
deleted
100644 → 0
View file @
a4bb31d0
// Copyright 2017 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// =============================================================================
#include "dragnn/runtime/mmap.h"
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <utility>
#include "tensorflow/core/lib/core/errors.h"
#include "tensorflow/core/lib/gtl/cleanup.h"
#include "tensorflow/core/platform/env.h"
#include "tensorflow/core/platform/logging.h"
namespace
syntaxnet
{
namespace
dragnn
{
namespace
runtime
{
int
UniqueAlignedMmap
::
Syscalls
::
Open
(
const
string
&
path
)
const
{
return
open
(
path
.
c_str
(),
O_RDONLY
);
}
int
UniqueAlignedMmap
::
Syscalls
::
Close
(
int
file_descriptor
)
const
{
return
close
(
file_descriptor
);
}
void
*
UniqueAlignedMmap
::
Syscalls
::
Mmap
(
int
file_descriptor
,
size_t
size
)
const
{
return
mmap
(
nullptr
,
size
,
PROT_READ
,
MAP_SHARED
,
file_descriptor
,
0
);
}
int
UniqueAlignedMmap
::
Syscalls
::
Munmap
(
void
*
data
,
size_t
size
)
const
{
return
munmap
(
data
,
size
);
}
UniqueAlignedMmap
::
UniqueAlignedMmap
(
std
::
unique_ptr
<
Syscalls
>
syscalls
)
:
syscalls_
(
std
::
move
(
syscalls
))
{}
UniqueAlignedMmap
::
UniqueAlignedMmap
(
UniqueAlignedMmap
&&
that
)
:
syscalls_
(
std
::
move
(
that
.
syscalls_
))
{
view_
=
that
.
view_
;
path_
=
that
.
path_
;
that
.
view_
=
MutableAlignedView
();
that
.
path_
.
clear
();
}
UniqueAlignedMmap
&
UniqueAlignedMmap
::
operator
=
(
UniqueAlignedMmap
&&
that
)
{
syscalls_
=
std
::
move
(
that
.
syscalls_
);
view_
=
that
.
view_
;
path_
=
that
.
path_
;
that
.
view_
=
MutableAlignedView
();
that
.
path_
.
clear
();
return
*
this
;
}
UniqueAlignedMmap
::~
UniqueAlignedMmap
()
{
UnmapIfNonEmpty
(
view_
.
data
(),
view_
.
size
(),
path_
);
}
tensorflow
::
Status
UniqueAlignedMmap
::
Reset
(
const
string
&
path
)
{
uint64
size
=
0
;
TF_RETURN_IF_ERROR
(
tensorflow
::
Env
::
Default
()
->
GetFileSize
(
path
,
&
size
));
// Since mmap() cannot map 0 bytes, we skip the call on empty files. This is
// OK because UnmapIfNonEmpty() also skips munmap() on an empty region.
if
(
size
==
0
)
{
view_
=
MutableAlignedView
();
path_
=
path
;
return
tensorflow
::
Status
::
OK
();
}
const
int
file_descriptor
=
syscalls_
->
Open
(
path
);
if
(
file_descriptor
==
-
1
)
{
// TODO(googleuser): Use strerror_r() to export the system error message.
return
tensorflow
::
errors
::
Unknown
(
"Failed to open '"
,
path
,
"'"
);
}
// In case we error out.
auto
ensure_closed
=
tensorflow
::
gtl
::
MakeCleanup
([
&
]
{
if
(
syscalls_
->
Close
(
file_descriptor
)
!=
0
)
{
LOG
(
ERROR
)
<<
"Failed to close '"
<<
path
<<
"'"
;
}
});
void
*
mmap_result
=
syscalls_
->
Mmap
(
file_descriptor
,
size
);
if
(
mmap_result
==
MAP_FAILED
)
{
return
tensorflow
::
errors
::
Unknown
(
"Failed to mmap '"
,
path
,
"'"
);
}
// In case we error out.
auto
ensure_unmapped
=
tensorflow
::
gtl
::
MakeCleanup
(
[
&
]
{
UnmapIfNonEmpty
(
mmap_result
,
size
,
path
);
});
// Since mmap() increments the refcount of the |file_descriptor|, it must be
// closed to prevent a leak.
ensure_closed
.
release
();
// going to close it manually
if
(
syscalls_
->
Close
(
file_descriptor
)
!=
0
)
{
return
tensorflow
::
errors
::
Unknown
(
"Failed to close '"
,
path
,
"'"
);
}
// Most implementations of mmap() place the mapped region on a page boundary,
// which is plenty of alignment. Since this is so unlikely to fail, we don't
// try to recover if the address is misaligned. A potential recovery method
// is to allocate a UniqueAlignedArray and read the file normally.
MutableAlignedView
data
;
TF_RETURN_IF_ERROR
(
data
.
Reset
(
reinterpret_cast
<
char
*>
(
mmap_result
),
size
));
// Success; make modifications.
view_
=
data
;
path_
=
path
;
ensure_unmapped
.
release
();
// this has taken ownership of the mapped file
return
tensorflow
::
Status
::
OK
();
}
void
UniqueAlignedMmap
::
UnmapIfNonEmpty
(
void
*
data
,
size_t
size
,
const
string
&
path
)
const
{
if
(
size
==
0
)
return
;
if
(
syscalls_
->
Munmap
(
data
,
size
)
!=
0
)
{
LOG
(
ERROR
)
<<
"Failed to munmap() file '"
<<
path
<<
"'"
;
}
}
}
// namespace runtime
}
// namespace dragnn
}
// namespace syntaxnet
research/syntaxnet/dragnn/runtime/mmap.h
deleted
100644 → 0
View file @
a4bb31d0
// Copyright 2017 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// =============================================================================
// Utils for establishing and managing memory-mapped files.
#ifndef DRAGNN_RUNTIME_MMAP_H_
#define DRAGNN_RUNTIME_MMAP_H_
#include <stddef.h>
#include <memory>
#include <string>
#include "dragnn/runtime/alignment.h"
#include "syntaxnet/base.h"
#include "tensorflow/core/lib/core/status.h"
namespace
syntaxnet
{
namespace
dragnn
{
namespace
runtime
{
// A uniquely-owned aligned memory-mapped file. This has virtual methods only
// for mocking in tests; do not derive from class.
class
UniqueAlignedMmap
{
public:
// A mockable wrapper around the system calls used by this class.
class
Syscalls
{
public:
virtual
~
Syscalls
()
=
default
;
// Each method below forwards to the similarly-named syscall. Some methods
// have been simplified by omitting arguments that are never varied.
virtual
int
Open
(
const
string
&
path
)
const
;
virtual
int
Close
(
int
file_descriptor
)
const
;
virtual
void
*
Mmap
(
int
file_descriptor
,
size_t
size
)
const
;
virtual
int
Munmap
(
void
*
data
,
size_t
size
)
const
;
};
// Creates an empty, unmapped memory region.
UniqueAlignedMmap
()
=
default
;
// FOR TESTS ONLY. As above, but injects the |syscalls|.
explicit
UniqueAlignedMmap
(
std
::
unique_ptr
<
Syscalls
>
syscalls
);
// Supports movement only.
UniqueAlignedMmap
(
UniqueAlignedMmap
&&
that
);
UniqueAlignedMmap
&
operator
=
(
UniqueAlignedMmap
&&
that
);
UniqueAlignedMmap
(
const
UniqueAlignedMmap
&
that
)
=
delete
;
UniqueAlignedMmap
&
operator
=
(
const
UniqueAlignedMmap
&
that
)
=
delete
;
// Unmaps the current memory-mapped file, if any.
~
UniqueAlignedMmap
();
// Resets this to a memory-mapping of the |path|. On error, returns non-OK
// and modifies nothing.
tensorflow
::
Status
Reset
(
const
string
&
path
);
// Returns the mapped memory region.
AlignedView
view
()
const
{
return
AlignedView
(
view_
);
}
private:
// Unmaps [|data|,|data|+|size|), if non-empty. Uses the |path| for error
// logging. Does not return a status because none of the call sites could
// pass it along; they'd log it anyways.
void
UnmapIfNonEmpty
(
void
*
data
,
size_t
size
,
const
string
&
path
)
const
;
// The system calls used to perform the memory-mapping.
std
::
unique_ptr
<
Syscalls
>
syscalls_
{
new
Syscalls
()};
// The current memory-mapped file, or empty if unmapped. Mutable to satisfy
// munmap(), which requires a non-const pointer---contents are not modified.
MutableAlignedView
view_
;
// The path to the current memory-mapped file, if any, for debug logging.
string
path_
;
};
}
// namespace runtime
}
// namespace dragnn
}
// namespace syntaxnet
#endif // DRAGNN_RUNTIME_MMAP_H_
research/syntaxnet/dragnn/runtime/mmap_array_variable_store.cc
deleted
100644 → 0
View file @
a4bb31d0
// Copyright 2017 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// =============================================================================
#include "dragnn/runtime/mmap_array_variable_store.h"
#include <utility>
#include "tensorflow/core/lib/core/errors.h"
namespace
syntaxnet
{
namespace
dragnn
{
namespace
runtime
{
tensorflow
::
Status
MmapArrayVariableStore
::
Reset
(
const
ArrayVariableStoreSpec
&
spec
,
const
string
&
path
)
{
UniqueAlignedMmap
data
;
TF_RETURN_IF_ERROR
(
data
.
Reset
(
path
));
TF_RETURN_IF_ERROR
(
ArrayVariableStore
::
Reset
(
spec
,
data
.
view
()));
// Success; make modifications.
data_
=
std
::
move
(
data
);
return
tensorflow
::
Status
::
OK
();
}
}
// namespace runtime
}
// namespace dragnn
}
// namespace syntaxnet
research/syntaxnet/dragnn/runtime/mmap_array_variable_store.h
deleted
100644 → 0
View file @
a4bb31d0
// Copyright 2017 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// =============================================================================
#ifndef DRAGNN_RUNTIME_MMAP_ARRAY_VARIABLE_STORE_H_
#define DRAGNN_RUNTIME_MMAP_ARRAY_VARIABLE_STORE_H_
#include <string>
#include "dragnn/protos/runtime.pb.h"
#include "dragnn/runtime/array_variable_store.h"
#include "dragnn/runtime/mmap.h"
#include "syntaxnet/base.h"
#include "tensorflow/core/lib/core/status.h"
namespace
syntaxnet
{
namespace
dragnn
{
namespace
runtime
{
// An ArrayVariableStore subclass that maps file content into memory.
class
MmapArrayVariableStore
:
public
ArrayVariableStore
{
public:
// Creates an uninitialized store.
MmapArrayVariableStore
()
=
default
;
// Resets this to represent the variables defined by the |spec|, mapping the
// byte array from the |path|. On error, returns non-OK and modifies nothing.
tensorflow
::
Status
Reset
(
const
ArrayVariableStoreSpec
&
spec
,
const
string
&
path
);
private:
// The memory-mapped file containing the variables.
UniqueAlignedMmap
data_
;
};
}
// namespace runtime
}
// namespace dragnn
}
// namespace syntaxnet
#endif // DRAGNN_RUNTIME_MMAP_ARRAY_VARIABLE_STORE_H_
research/syntaxnet/dragnn/runtime/mmap_test.cc
deleted
100644 → 0
View file @
a4bb31d0
// Copyright 2017 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// =============================================================================
#include "dragnn/runtime/mmap.h"
#include <stddef.h>
#include <sys/mman.h>
#include <string>
#include <utility>
#include "dragnn/core/test/generic.h"
#include "syntaxnet/base.h"
#include <gmock/gmock.h>
#include "tensorflow/core/lib/core/status.h"
#include "tensorflow/core/lib/core/status_test_util.h"
#include "tensorflow/core/lib/io/path.h"
#include "tensorflow/core/platform/test.h"
namespace
syntaxnet
{
namespace
dragnn
{
namespace
runtime
{
namespace
{
using
::
testing
::
Return
;
// A mockable set of system calls.
class
MockSyscalls
:
public
UniqueAlignedMmap
::
Syscalls
{
public:
MOCK_CONST_METHOD1
(
Open
,
int
(
const
string
&
path
));
MOCK_CONST_METHOD1
(
Close
,
int
(
int
file_descriptor
));
MOCK_CONST_METHOD2
(
Mmap
,
void
*
(
int
file_descriptor
,
size_t
size
));
MOCK_CONST_METHOD2
(
Munmap
,
int
(
void
*
,
size_t
size
));
};
class
UniqueAlignedMmapTest
:
public
::
testing
::
Test
{
protected:
const
string
kInvalidFile
=
"/some/invalid/path"
;
const
string
kEmptyFile
=
tensorflow
::
io
::
JoinPath
(
test
::
GetTestDataPrefix
(),
"dragnn/runtime/testdata/empty_file"
);
const
string
kTenBytes
=
tensorflow
::
io
::
JoinPath
(
test
::
GetTestDataPrefix
(),
"dragnn/runtime/testdata/ten_bytes"
);
std
::
unique_ptr
<
MockSyscalls
>
syscalls_
{
new
MockSyscalls
()};
};
// Tests that the mapped region is empty by default.
TEST_F
(
UniqueAlignedMmapTest
,
EmptyByDefault
)
{
UniqueAlignedMmap
data
;
EXPECT_TRUE
(
data
.
view
().
empty
());
}
// Tests that an empty file can be mapped.
TEST_F
(
UniqueAlignedMmapTest
,
EmptyFile
)
{
UniqueAlignedMmap
data
;
TF_ASSERT_OK
(
data
.
Reset
(
kEmptyFile
));
EXPECT_TRUE
(
data
.
view
().
empty
());
}
// Tests that a non-empty file can be mapped.
TEST_F
(
UniqueAlignedMmapTest
,
TenBytes
)
{
UniqueAlignedMmap
data
;
TF_ASSERT_OK
(
data
.
Reset
(
kTenBytes
));
ASSERT_EQ
(
data
.
view
().
size
(),
10
);
EXPECT_STREQ
(
data
.
view
().
data
(),
"0123456789"
);
}
// Tests that the mapped files can be move-constructed and move-assigned.
TEST_F
(
UniqueAlignedMmapTest
,
Movement
)
{
UniqueAlignedMmap
data1
;
TF_ASSERT_OK
(
data1
.
Reset
(
kTenBytes
));
UniqueAlignedMmap
data2
(
std
::
move
(
data1
));
ASSERT_EQ
(
data2
.
view
().
size
(),
10
);
EXPECT_STREQ
(
data2
.
view
().
data
(),
"0123456789"
);
UniqueAlignedMmap
data3
;
data3
=
std
::
move
(
data2
);
ASSERT_EQ
(
data3
.
view
().
size
(),
10
);
EXPECT_STREQ
(
data3
.
view
().
data
(),
"0123456789"
);
}
// Tests that the mapping fails if the file is invalid.
TEST_F
(
UniqueAlignedMmapTest
,
InvalidFile
)
{
UniqueAlignedMmap
data
;
EXPECT_FALSE
(
data
.
Reset
(
kInvalidFile
).
ok
());
}
// Tests that the mapping fails if the file cannot be open()ed.
TEST_F
(
UniqueAlignedMmapTest
,
FailToOpen
)
{
EXPECT_CALL
(
*
syscalls_
,
Open
(
kTenBytes
)).
WillOnce
(
Return
(
-
1
));
UniqueAlignedMmap
data
(
std
::
move
(
syscalls_
));
EXPECT_THAT
(
data
.
Reset
(
kTenBytes
),
test
::
IsErrorWithSubstr
(
"Failed to open"
));
}
// Tests that the mapping fails if the file cannot be mmap()ed.
TEST_F
(
UniqueAlignedMmapTest
,
FailToMmap
)
{
const
int
kFileDescriptor
=
5
;
EXPECT_CALL
(
*
syscalls_
,
Open
(
kTenBytes
)).
WillOnce
(
Return
(
kFileDescriptor
));
EXPECT_CALL
(
*
syscalls_
,
Mmap
(
kFileDescriptor
,
10
))
.
WillOnce
(
Return
(
MAP_FAILED
));
EXPECT_CALL
(
*
syscalls_
,
Close
(
kFileDescriptor
)).
WillOnce
(
Return
(
0
));
UniqueAlignedMmap
data
(
std
::
move
(
syscalls_
));
EXPECT_THAT
(
data
.
Reset
(
kTenBytes
),
test
::
IsErrorWithSubstr
(
"Failed to mmap"
));
}
// As above, but also fails to close.
TEST_F
(
UniqueAlignedMmapTest
,
FailToMmapAndClose
)
{
const
int
kFileDescriptor
=
5
;
EXPECT_CALL
(
*
syscalls_
,
Open
(
kTenBytes
)).
WillOnce
(
Return
(
kFileDescriptor
));
EXPECT_CALL
(
*
syscalls_
,
Mmap
(
kFileDescriptor
,
10
))
.
WillOnce
(
Return
(
MAP_FAILED
));
EXPECT_CALL
(
*
syscalls_
,
Close
(
kFileDescriptor
)).
WillOnce
(
Return
(
-
1
));
UniqueAlignedMmap
data
(
std
::
move
(
syscalls_
));
EXPECT_THAT
(
data
.
Reset
(
kTenBytes
),
test
::
IsErrorWithSubstr
(
"Failed to mmap"
));
}
// Tests that the mapping fails if the file cannot be close()ed.
TEST_F
(
UniqueAlignedMmapTest
,
FailToClose
)
{
const
int
kFileDescriptor
=
5
;
EXPECT_CALL
(
*
syscalls_
,
Open
(
kTenBytes
)).
WillOnce
(
Return
(
kFileDescriptor
));
EXPECT_CALL
(
*
syscalls_
,
Mmap
(
kFileDescriptor
,
10
)).
WillOnce
(
Return
(
nullptr
));
EXPECT_CALL
(
*
syscalls_
,
Close
(
kFileDescriptor
)).
WillOnce
(
Return
(
-
1
));
EXPECT_CALL
(
*
syscalls_
,
Munmap
(
nullptr
,
10
)).
WillOnce
(
Return
(
0
));
UniqueAlignedMmap
data
(
std
::
move
(
syscalls_
));
EXPECT_THAT
(
data
.
Reset
(
kTenBytes
),
test
::
IsErrorWithSubstr
(
"Failed to close"
));
}
// As above, but also fails to munmap().
TEST_F
(
UniqueAlignedMmapTest
,
FailToCloseAndMunmap
)
{
const
int
kFileDescriptor
=
5
;
EXPECT_CALL
(
*
syscalls_
,
Open
(
kTenBytes
)).
WillOnce
(
Return
(
kFileDescriptor
));
EXPECT_CALL
(
*
syscalls_
,
Mmap
(
kFileDescriptor
,
10
)).
WillOnce
(
Return
(
nullptr
));
EXPECT_CALL
(
*
syscalls_
,
Close
(
kFileDescriptor
)).
WillOnce
(
Return
(
-
1
));
EXPECT_CALL
(
*
syscalls_
,
Munmap
(
nullptr
,
10
)).
WillOnce
(
Return
(
-
1
));
UniqueAlignedMmap
data
(
std
::
move
(
syscalls_
));
EXPECT_THAT
(
data
.
Reset
(
kTenBytes
),
test
::
IsErrorWithSubstr
(
"Failed to close"
));
}
// Tests that the mapping fails if the mapped region is misaligned.
TEST_F
(
UniqueAlignedMmapTest
,
Misaligned
)
{
char
*
ptr
=
nullptr
;
++
ptr
;
const
int
kFileDescriptor
=
5
;
EXPECT_CALL
(
*
syscalls_
,
Open
(
kTenBytes
)).
WillOnce
(
Return
(
kFileDescriptor
));
EXPECT_CALL
(
*
syscalls_
,
Mmap
(
kFileDescriptor
,
10
)).
WillOnce
(
Return
(
ptr
));
EXPECT_CALL
(
*
syscalls_
,
Close
(
kFileDescriptor
)).
WillOnce
(
Return
(
0
));
EXPECT_CALL
(
*
syscalls_
,
Munmap
(
ptr
,
10
)).
WillOnce
(
Return
(
0
));
UniqueAlignedMmap
data
(
std
::
move
(
syscalls_
));
EXPECT_THAT
(
data
.
Reset
(
kTenBytes
),
test
::
IsErrorWithSubstr
(
"Pointer fails alignment requirement"
));
}
}
// namespace
}
// namespace runtime
}
// namespace dragnn
}
// namespace syntaxnet
research/syntaxnet/dragnn/runtime/mst_solver_component_base.cc
deleted
100644 → 0
View file @
a4bb31d0
// Copyright 2018 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// =============================================================================
#include "dragnn/runtime/mst_solver_component_base.h"
#include <stddef.h>
#include "dragnn/runtime/attributes.h"
#include "dragnn/runtime/math/types.h"
#include "dragnn/runtime/network_unit.h"
#include "tensorflow/core/lib/core/errors.h"
namespace
syntaxnet
{
namespace
dragnn
{
namespace
runtime
{
namespace
{
// Attributes used by the MST solver.
struct
MstSolverAttributes
:
public
Attributes
{
// Whether to solve for a spanning forest instead of a spanning tree.
Optional
<
bool
>
forest
{
"forest"
,
false
,
this
};
// Training-only attributes, ignored in the runtime.
Ignored
loss
{
"loss"
,
this
};
};
}
// namespace
MstSolverComponentBase
::
MstSolverComponentBase
(
const
string
&
builder_name
,
const
string
&
backend_name
)
:
builder_name_
(
builder_name
),
backend_name_
(
backend_name
)
{}
bool
MstSolverComponentBase
::
Supports
(
const
ComponentSpec
&
component_spec
,
const
string
&
normalized_builder_name
)
const
{
const
string
network_unit
=
NetworkUnit
::
GetClassName
(
component_spec
);
return
(
normalized_builder_name
==
"BulkAnnotatorComponent"
||
normalized_builder_name
==
builder_name_
)
&&
(
component_spec
.
backend
().
registered_name
()
==
"StatelessComponent"
||
component_spec
.
backend
().
registered_name
()
==
backend_name_
)
&&
component_spec
.
transition_system
().
registered_name
()
==
"heads"
&&
network_unit
==
"MstSolverNetwork"
&&
component_spec
.
fixed_feature_size
()
==
0
&&
component_spec
.
linked_feature_size
()
==
1
;
}
tensorflow
::
Status
MstSolverComponentBase
::
Initialize
(
const
ComponentSpec
&
component_spec
,
VariableStore
*
variable_store
,
NetworkStateManager
*
network_state_manager
,
ExtensionManager
*
extension_manager
)
{
MstSolverAttributes
attributes
;
TF_RETURN_IF_ERROR
(
attributes
.
Reset
(
component_spec
.
network_unit
().
parameters
()));
forest_
=
attributes
.
forest
();
const
LinkedFeatureChannel
&
link
=
component_spec
.
linked_feature
(
0
);
size_t
dimension
=
0
;
TF_RETURN_IF_ERROR
(
network_state_manager
->
LookupLayer
(
link
.
source_component
(),
link
.
source_layer
(),
&
dimension
,
&
adjacency_handle_
));
if
(
dimension
!=
1
)
{
return
tensorflow
::
errors
::
InvalidArgument
(
"Adjacency matrix has dimension "
,
dimension
,
" but expected 1"
);
}
extension_manager
->
GetShared
(
&
heads_handle_
);
extension_manager
->
GetShared
(
&
solver_handle_
);
return
tensorflow
::
Status
::
OK
();
}
tensorflow
::
Status
MstSolverComponentBase
::
ComputeHeads
(
SessionState
*
session_state
,
tensorflow
::
gtl
::
ArraySlice
<
Index
>
*
heads
)
const
{
Matrix
<
float
>
adjacency
(
session_state
->
network_states
.
GetLayer
(
adjacency_handle_
));
const
size_t
num_nodes
=
adjacency
.
num_rows
();
Solver
&
solver
=
session_state
->
extensions
.
Get
(
solver_handle_
);
TF_RETURN_IF_ERROR
(
solver
.
Init
(
forest_
,
num_nodes
));
for
(
size_t
target
=
0
;
target
<
num_nodes
;
++
target
)
{
Vector
<
float
>
source_scores
=
adjacency
.
row
(
target
);
for
(
size_t
source
=
0
;
source
<
num_nodes
;
++
source
)
{
if
(
source
==
target
)
{
solver
.
AddRoot
(
source
,
source_scores
[
source
]);
}
else
{
solver
.
AddArc
(
source
,
target
,
source_scores
[
source
]);
}
}
}
std
::
vector
<
Index
>
&
argmax
=
session_state
->
extensions
.
Get
(
heads_handle_
);
argmax
.
resize
(
num_nodes
);
TF_RETURN_IF_ERROR
(
solver
.
Solve
(
&
argmax
));
*
heads
=
argmax
;
return
tensorflow
::
Status
::
OK
();
}
}
// namespace runtime
}
// namespace dragnn
}
// namespace syntaxnet
research/syntaxnet/dragnn/runtime/mst_solver_component_base.h
deleted
100644 → 0
View file @
a4bb31d0
// Copyright 2018 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// =============================================================================
#ifndef DRAGNN_RUNTIME_MST_SOLVER_COMPONENT_BASE_H_
#define DRAGNN_RUNTIME_MST_SOLVER_COMPONENT_BASE_H_
#include <vector>
#include "dragnn/core/compute_session.h"
#include "dragnn/mst/mst_solver.h"
#include "dragnn/protos/spec.pb.h"
#include "dragnn/runtime/component.h"
#include "dragnn/runtime/extensions.h"
#include "dragnn/runtime/network_states.h"
#include "dragnn/runtime/session_state.h"
#include "dragnn/runtime/variable_store.h"
#include "syntaxnet/base.h"
#include "tensorflow/core/lib/core/status.h"
#include "tensorflow/core/lib/gtl/array_slice.h"
namespace
syntaxnet
{
namespace
dragnn
{
namespace
runtime
{
// Base class for MST parsing components, which select heads jointly by finding
// the maximum spanning tree of the input tokens.
//
// This base class only computes the selected heads, while subclasses apply the
// heads to the annotations in the ComputeSession.
class
MstSolverComponentBase
:
public
Component
{
public:
// NB: This definition of Index should match the MstSolver TF op wrappers.
using
Index
=
uint16
;
// Partially implements Component.
bool
Supports
(
const
ComponentSpec
&
component_spec
,
const
string
&
normalized_builder_name
)
const
override
;
tensorflow
::
Status
Initialize
(
const
ComponentSpec
&
component_spec
,
VariableStore
*
variable_store
,
NetworkStateManager
*
network_state_manager
,
ExtensionManager
*
extension_manager
)
override
;
bool
PreferredTo
(
const
Component
&
other
)
const
override
{
return
false
;
}
protected:
// Creates a component that supports the |builder_name| and |backend_name|.
MstSolverComponentBase
(
const
string
&
builder_name
,
const
string
&
backend_name
);
// Points |heads| at the list of heads computed from the |session_state|,
// where a self-loop indicates a root. Returns non-OK on error.
tensorflow
::
Status
ComputeHeads
(
SessionState
*
session_state
,
tensorflow
::
gtl
::
ArraySlice
<
Index
>
*
heads
)
const
;
private:
using
Solver
=
MstSolver
<
Index
,
float
>
;
// Names of the supported component builder and backend.
const
string
builder_name_
;
const
string
backend_name_
;
// Whether to solve for a spanning forest instead of a spanning tree.
bool
forest_
=
false
;
// Directed adjacency matrix input.
PairwiseLayerHandle
<
float
>
adjacency_handle_
;
// List of selected head indices.
SharedExtensionHandle
<
std
::
vector
<
Index
>>
heads_handle_
;
// Reusable MST solver.
SharedExtensionHandle
<
Solver
>
solver_handle_
;
};
}
// namespace runtime
}
// namespace dragnn
}
// namespace syntaxnet
#endif // DRAGNN_RUNTIME_MST_SOLVER_COMPONENT_BASE_H_
research/syntaxnet/dragnn/runtime/mst_solver_component_base_test.cc
deleted
100644 → 0
View file @
a4bb31d0
// Copyright 2018 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// =============================================================================
#include "dragnn/runtime/mst_solver_component_base.h"
#include <stddef.h>
#include <string>
#include <vector>
#include "dragnn/core/compute_session.h"
#include "dragnn/core/input_batch_cache.h"
#include "dragnn/core/test/generic.h"
#include "dragnn/protos/spec.pb.h"
#include "dragnn/protos/trace.pb.h"
#include "dragnn/runtime/network_states.h"
#include "dragnn/runtime/session_state.h"
#include "dragnn/runtime/test/network_test_base.h"
#include "dragnn/runtime/variable_store.h"
#include "syntaxnet/base.h"
#include "tensorflow/core/lib/core/status.h"
#include "tensorflow/core/lib/core/status_test_util.h"
#include "tensorflow/core/lib/gtl/array_slice.h"
#include "tensorflow/core/platform/test.h"
namespace
syntaxnet
{
namespace
dragnn
{
namespace
runtime
{
namespace
{
constexpr
size_t
kNumSteps
=
12
;
constexpr
size_t
kRootIndex
=
7
;
// the root and head of all other tokens
constexpr
char
kTestBuilder
[]
=
"TestBuilder"
;
constexpr
char
kTestBackend
[]
=
"TestBackend"
;
constexpr
char
kPreviousComponentName
[]
=
"previous_component"
;
constexpr
char
kAdjacencyLayerName
[]
=
"adjacency_layer"
;
constexpr
char
kBadDimLayerName
[]
=
"bad_layer"
;
// A subclass for tests.
class
BasicMstSolverComponent
:
public
MstSolverComponentBase
{
public:
BasicMstSolverComponent
()
:
MstSolverComponentBase
(
kTestBuilder
,
kTestBackend
)
{}
// Implements Component. These methods are never called, but must be defined
// so the class is not abstract.
tensorflow
::
Status
Evaluate
(
SessionState
*
session_state
,
ComputeSession
*
compute_session
,
ComponentTrace
*
component_trace
)
const
override
{
return
tensorflow
::
Status
::
OK
();
}
// Publicizes the base class's method.
using
MstSolverComponentBase
::
ComputeHeads
;
};
// Returns a ComponentSpec that works with the head selection component.
ComponentSpec
MakeGoodSpec
()
{
ComponentSpec
component_spec
;
component_spec
.
mutable_component_builder
()
->
set_registered_name
(
kTestBuilder
);
component_spec
.
mutable_backend
()
->
set_registered_name
(
kTestBackend
);
component_spec
.
mutable_transition_system
()
->
set_registered_name
(
"heads"
);
component_spec
.
mutable_network_unit
()
->
set_registered_name
(
"some.path.to.MstSolverNetwork"
);
LinkedFeatureChannel
*
link
=
component_spec
.
add_linked_feature
();
link
->
set_source_component
(
kPreviousComponentName
);
link
->
set_source_layer
(
kAdjacencyLayerName
);
return
component_spec
;
}
class
MstSolverComponentBaseTest
:
public
NetworkTestBase
{
protected:
// Initializes a head selection component from the |component_spec| and sets
// |heads| to the extracted head indices. Returs non-OK on error.
tensorflow
::
Status
Run
(
const
ComponentSpec
&
component_spec
,
std
::
vector
<
int
>
*
heads
)
{
AddComponent
(
kPreviousComponentName
);
AddPairwiseLayer
(
kAdjacencyLayerName
,
1
);
AddPairwiseLayer
(
kBadDimLayerName
,
2
);
BasicMstSolverComponent
component
;
TF_RETURN_IF_ERROR
(
component
.
Initialize
(
component_spec
,
&
variable_store_
,
&
network_state_manager_
,
&
extension_manager_
));
network_states_
.
Reset
(
&
network_state_manager_
);
StartComponent
(
kNumSteps
);
// Fill the |kRootIndex|'th column of the adjacency matrix with higher
// scores, so all tokens select it as head. The |kRootIndex|'th token
// itself is a self-loop, so it becomes a root.
MutableMatrix
<
float
>
adjacency
=
GetPairwiseLayer
(
kPreviousComponentName
,
kAdjacencyLayerName
);
for
(
size_t
target
=
0
;
target
<
kNumSteps
;
++
target
)
{
for
(
size_t
source
=
0
;
source
<
kNumSteps
;
++
source
)
{
adjacency
.
row
(
target
)[
source
]
=
source
==
kRootIndex
?
1.0
:
0.0
;
}
}
session_state_
.
extensions
.
Reset
(
&
extension_manager_
);
tensorflow
::
gtl
::
ArraySlice
<
MstSolverComponentBase
::
Index
>
argmax
;
TF_RETURN_IF_ERROR
(
component
.
ComputeHeads
(
&
session_state_
,
&
argmax
));
heads
->
assign
(
argmax
.
begin
(),
argmax
.
end
());
return
tensorflow
::
Status
::
OK
();
}
};
// Tests that the expected heads are produced for a good spec.
TEST_F
(
MstSolverComponentBaseTest
,
RunsGoodSpec
)
{
std
::
vector
<
int
>
heads
;
TF_ASSERT_OK
(
Run
(
MakeGoodSpec
(),
&
heads
));
const
std
::
vector
<
int
>
expected_heads
(
kNumSteps
,
kRootIndex
);
EXPECT_EQ
(
heads
,
expected_heads
);
}
// Tests that a layer with the wrong dimension is rejected
TEST_F
(
MstSolverComponentBaseTest
,
WrongDimension
)
{
ComponentSpec
component_spec
=
MakeGoodSpec
();
component_spec
.
mutable_linked_feature
(
0
)
->
set_source_layer
(
kBadDimLayerName
);
std
::
vector
<
int
>
heads
;
EXPECT_THAT
(
Run
(
component_spec
,
&
heads
),
test
::
IsErrorWithSubstr
(
"Adjacency matrix has dimension 2 but expected 1"
));
}
// Tests that the component is always dis-preferred.
TEST_F
(
MstSolverComponentBaseTest
,
NotPreferred
)
{
BasicMstSolverComponent
component
;
EXPECT_FALSE
(
component
.
PreferredTo
(
component
));
}
// Tests that the good spec is supported.
TEST_F
(
MstSolverComponentBaseTest
,
SupportsGoodSpec
)
{
ComponentSpec
component_spec
=
MakeGoodSpec
();
BasicMstSolverComponent
component
;
EXPECT_TRUE
(
component
.
Supports
(
component_spec
,
kTestBuilder
));
}
// Tests that various bad specs are rejected.
TEST_F
(
MstSolverComponentBaseTest
,
RejectsBadSpecs
)
{
ComponentSpec
component_spec
=
MakeGoodSpec
();
BasicMstSolverComponent
component
;
EXPECT_FALSE
(
component
.
Supports
(
component_spec
,
"bad"
));
component_spec
=
MakeGoodSpec
();
component_spec
.
mutable_backend
()
->
set_registered_name
(
"bad"
);
EXPECT_FALSE
(
component
.
Supports
(
component_spec
,
kTestBuilder
));
component_spec
=
MakeGoodSpec
();
component_spec
.
mutable_transition_system
()
->
set_registered_name
(
"bad"
);
EXPECT_FALSE
(
component
.
Supports
(
component_spec
,
kTestBuilder
));
component_spec
=
MakeGoodSpec
();
component_spec
.
mutable_network_unit
()
->
set_registered_name
(
"bad"
);
EXPECT_FALSE
(
component
.
Supports
(
component_spec
,
kTestBuilder
));
component_spec
=
MakeGoodSpec
();
component_spec
.
add_fixed_feature
();
EXPECT_FALSE
(
component
.
Supports
(
component_spec
,
kTestBuilder
));
component_spec
=
MakeGoodSpec
();
component_spec
.
add_linked_feature
();
EXPECT_FALSE
(
component
.
Supports
(
component_spec
,
kTestBuilder
));
component_spec
=
MakeGoodSpec
();
component_spec
.
clear_linked_feature
();
EXPECT_FALSE
(
component
.
Supports
(
component_spec
,
kTestBuilder
));
}
}
// namespace
}
// namespace runtime
}
// namespace dragnn
}
// namespace syntaxnet
research/syntaxnet/dragnn/runtime/multiarch.bzl
deleted
100644 → 0
View file @
a4bb31d0
# Copyright 2017 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# =============================================================================
"""Build extension rules for handling multiple target architectures."""
# Build configs for specific CPU architectures. Each entry specified
# additional copts and tags.
# TODO(googleuser): Figure out a workaround for the shift
# instructions, and look for any other unsupported instructions.
MULTIARCH_CONFIGS
=
{
"generic"
:
{
"copts"
:
[],
"tags"
:
[],
},
"avx"
:
{
"copts"
:
[
"-msse4.2"
,
],
"tags"
:
[],
},
"avx2fma"
:
{
"copts"
:
[
"-msse4.2"
,
"-mavx"
,
"-mavx2"
,
"-mfma"
,
],
"tags"
:
[
"local"
,
"manual"
,
],
},
}
# List of targets which are built for multiple architectures. These
# dependencies in dragnn_cc_* build rules are replaced with one with the
# appropriate suffix, e.g. _multiarch_generic
MULTIARCH_TARGETS
=
[
"//dragnn/runtime:biaffine_digraph_component"
,
"//dragnn/runtime:bulk_dynamic_component"
,
"//dragnn/runtime:bulk_feed_forward_network"
,
"//dragnn/runtime:bulk_lstm_network"
,
"//dragnn/runtime:feed_forward_network"
,
"//dragnn/runtime:feed_forward_network_kernel"
,
"//dragnn/runtime:feed_forward_network_layer"
,
"//dragnn/runtime:fixed_embeddings"
,
"//dragnn/runtime:linked_embeddings"
,
"//dragnn/runtime:lstm_network"
,
"//dragnn/runtime:lstm_network_kernel"
,
"//dragnn/runtime:network_unit_base"
,
"//dragnn/runtime:sequence_bulk_dynamic_component"
,
"//dragnn/runtime:sequence_features"
,
"//dragnn/runtime:sequence_links"
,
"//dragnn/runtime:sequence_model"
,
"//dragnn/runtime/lstm_cell:cell_function"
,
"//dragnn/runtime/lstm_cell:test_helpers"
,
"//dragnn/runtime/myelin:myelin_dynamic_component"
,
"//dragnn/runtime/myelin:myelin_dynamic_component_base"
,
"//dragnn/runtime/myelin:sequence_myelin_dynamic_component"
,
"//dragnn/runtime/xla:sequence_xla_dynamic_component_mixin"
,
"//dragnn/runtime/xla:testdata_simple_component_library"
,
"//dragnn/runtime/xla:xla_aot_dynamic_component"
,
"//dragnn/runtime/xla:xla_dynamic_component"
,
"//dragnn/runtime/xla:xla_dynamic_component_base"
,
]
def
multiarch_name
(
target_name
,
arch_name
):
"""Generates the multiarch version of |target_name| given |arch_name|."""
return
target_name
+
'_multiarch_'
+
arch_name
def
_is_multiarch
(
target
):
"""Returns true if |target| is designated as a multiarch target."""
return
(
target
in
MULTIARCH_TARGETS
or
(
'//'
+
native
.
package_name
()
+
target
)
in
MULTIARCH_TARGETS
)
def
_dragnn_cc_multiarch_target
(
native_rule
=
None
,
name
=
''
,
target_arch
=
None
,
target_suffix
=
''
,
copts
=
[],
deps
=
[],
tags
=
[],
opts_self
=
False
,
deps_transformer
=
None
,
**
kwargs
):
"""Generates a target for multiple architectures.
Using the |native_rule| (e.g. cc_library) to create a set of targets for
all CPU architectures listed in MULTIARCH_CONFIGS, with added suffixes
that designate the architecture.
When |target_arch| is set, then only that single target is generated,
and the name of the target is unchanged (no suffix is added).
When |opts_self| is true, then the 'copts' entry in MULTIARCH_CONFIGS
is additionally used to build this target.
The 'tags' entry in MULTIARCH_CONFIGS are included in the build tags.
Args:
native_rule: The build rule used for all generated targets
name: The original name of the build rule (without any suffix).
target_arch: When set, only this architecture is targeted.
target_suffix: Additional suffix to add after the architecture.
copts: The original compilation options for this target.
deps: The original dependencies for this target.
tags: The original build tags for this target.
opts_self: When true, additional copts are included.
deps_transformer: When set, a function to apply to the multiarch deps.
**kwargs: Additional args passed along to the build rule.
"""
# Determine set of target architectures based on |target_arch|.
if
target_arch
:
if
target_arch
in
MULTIARCH_CONFIGS
:
arch_items
=
[(
target_arch
,
MULTIARCH_CONFIGS
[
target_arch
])]
else
:
fail
(
'Unknown target_arch value: '
+
target_arch
)
else
:
arch_items
=
MULTIARCH_CONFIGS
.
items
()
# There is one target for each architecture in |arch_items|.
for
arch
,
arch_config
in
arch_items
:
# Transform the multi-arch deps.
multiarch_deps
=
[
multiarch_name
(
dep
,
arch
)
if
_is_multiarch
(
dep
)
else
dep
for
dep
in
deps
]
if
deps_transformer
:
multiarch_deps
=
deps_transformer
(
multiarch_deps
)
native_rule
(
name
=
(
name
if
target_arch
else
multiarch_name
(
name
,
arch
))
+
target_suffix
,
copts
=
copts
+
arch_config
[
'copts'
]
if
opts_self
else
copts
,
deps
=
multiarch_deps
,
tags
=
tags
+
arch_config
[
'tags'
],
**
kwargs
)
def
_dragnn_cc_multiarch_test_target
(
name
=
None
,
target_arch
=
None
,
**
kwargs
):
"""Test target wrapper which puts arch name before '_test'."""
test_suffix
=
'_test'
has_test_suffix
=
name
.
endswith
(
test_suffix
)
# Keeps _test at the end of the target name.
test_name
=
name
[:
-
len
(
test_suffix
)]
if
has_test_suffix
else
name
target_suffix
=
test_suffix
if
has_test_suffix
else
''
_dragnn_cc_multiarch_target
(
native_rule
=
native
.
cc_test
,
name
=
test_name
,
target_arch
=
target_arch
,
target_suffix
=
target_suffix
,
**
kwargs
)
# When |target_arch| is set, the resulting test is named |name|. Otherwise,
# tests with arch-specific names are generated, and for convenience we add a
# test_suite named |name| that runs the generic version of the test.
if
not
target_arch
:
native
.
test_suite
(
name
=
name
,
tests
=
[
multiarch_name
(
test_name
,
'generic'
)
+
target_suffix
])
def
dragnn_cc_multiarch_library
(
**
kwargs
):
"""Similar to cc_library, but creates multiple architecture targets."""
_dragnn_cc_multiarch_target
(
native_rule
=
native
.
cc_library
,
**
kwargs
)
def
dragnn_cc_multiarch_test
(
**
kwargs
):
"""Similar to cc_test, but creates multiple architecture targets."""
_dragnn_cc_multiarch_test_target
(
**
kwargs
)
def
dragnn_cc_multiarch_binary
(
**
kwargs
):
"""Similar to cc_binary, but creates multiple architecture targets."""
_dragnn_cc_multiarch_target
(
native_rule
=
native
.
cc_binary
,
**
kwargs
)
def
dragnn_cc_library
(
target_arch
=
'generic'
,
**
kwargs
):
"""Similar to cc_library, but targets one specific architecture."""
_dragnn_cc_multiarch_target
(
native_rule
=
native
.
cc_library
,
target_arch
=
target_arch
,
**
kwargs
)
def
dragnn_cc_test
(
target_arch
=
'generic'
,
**
kwargs
):
"""Similar to cc_test, but targets one specific architecture."""
_dragnn_cc_multiarch_test_target
(
target_arch
=
target_arch
,
**
kwargs
)
def
dragnn_cc_binary
(
target_arch
=
'generic'
,
**
kwargs
):
"""Similar to cc_binary, but targets one specific architecture."""
_dragnn_cc_multiarch_target
(
native_rule
=
native
.
cc_binary
,
target_arch
=
target_arch
,
**
kwargs
)
research/syntaxnet/dragnn/runtime/myelin/BUILD
deleted
100644 → 0
View file @
a4bb31d0
package
(
default_visibility
=
[
"//visibility:public"
])
load
(
":build_defs.bzl"
,
"dragnn_myelin_cc_library"
,
"dragnn_myelin_cc_test"
,
"dragnn_myelin_cc_multiarch_library"
,
"dragnn_myelin_cc_multiarch_test"
,
)
test_suite
(
name
=
"all_tests"
)
filegroup
(
name
=
"test_myelination_output"
,
srcs
=
glob
([
"testdata/myelination_output/**"
]),
)
cc_library
(
name
=
"attr_value_utils"
,
srcs
=
[
"attr_value_utils.cc"
],
hdrs
=
[
"attr_value_utils.h"
],
deps
=
[
"//syntaxnet:base"
,
"@org_tensorflow//tensorflow/core:framework_headers_lib"
,
"@org_tensorflow//tensorflow/core:lib"
,
"@org_tensorflow//tensorflow/core:protos_all_cc"
,
],
)
cc_test
(
name
=
"attr_value_utils_test"
,
size
=
"small"
,
srcs
=
[
"attr_value_utils_test.cc"
],
deps
=
[
":attr_value_utils"
,
"//dragnn/core/test:generic"
,
"//syntaxnet:base"
,
"@org_tensorflow//tensorflow/core:lib"
,
"@org_tensorflow//tensorflow/core:test"
,
],
)
dragnn_myelin_cc_library
(
name
=
"myelin_cell_converter"
,
srcs
=
[
"myelin_cell_converter.cc"
],
hdrs
=
[
"myelin_cell_converter.h"
],
deps
=
[
":attr_value_utils"
,
"//dragnn/protos:export_proto_cc"
,
"//dragnn/runtime:trained_model"
,
"//syntaxnet:base"
,
"@org_tensorflow//tensorflow/core:framework_headers_lib"
,
"@org_tensorflow//tensorflow/core:lib"
,
"@org_tensorflow//tensorflow/core:protos_all_cc"
,
],
)
dragnn_myelin_cc_test
(
name
=
"myelin_cell_converter_test"
,
size
=
"small"
,
timeout
=
"moderate"
,
srcs
=
[
"myelin_cell_converter_test.cc"
],
data
=
[
"//dragnn/runtime:test_rnn_tagger"
],
deps
=
[
":myelin_cell_converter"
,
":myelin_spec_utils"
,
"//dragnn/components/syntaxnet:syntaxnet_component"
,
"//dragnn/core/test:generic"
,
"//dragnn/runtime:alignment"
,
"//dragnn/runtime:trained_model"
,
"//syntaxnet:base"
,
"@org_tensorflow//tensorflow/core:lib"
,
"@org_tensorflow//tensorflow/core:test"
,
"@sling//sling/myelin:compute"
,
"@sling//sling/myelin:flow"
,
"@sling//sling/myelin:graph"
,
],
)
dragnn_myelin_cc_library
(
name
=
"myelin_library"
,
srcs
=
[
"myelin_library.cc"
],
hdrs
=
[
"myelin_library.h"
],
deps
=
[
"//syntaxnet:base"
,
"@org_tensorflow//tensorflow/core:lib"
,
"@sling//sling/myelin:flow"
,
],
)
dragnn_myelin_cc_test
(
name
=
"myelin_library_test"
,
size
=
"small"
,
srcs
=
[
"myelin_library_test.cc"
],
deps
=
[
":myelin_library"
,
"//syntaxnet:test_main"
,
"@org_tensorflow//tensorflow/core:test"
,
],
)
dragnn_myelin_cc_library
(
name
=
"myelin_spec_utils"
,
srcs
=
[
"myelin_spec_utils.cc"
],
hdrs
=
[
"myelin_spec_utils.h"
],
deps
=
[
":myelin_library"
,
"//dragnn/protos:spec_proto_cc"
,
"//syntaxnet:base"
,
"@org_tensorflow//tensorflow/core:lib"
,
"@sling//sling/base"
,
"@sling//sling/file"
,
"@sling//sling/myelin:compute"
,
"@sling//sling/myelin:flow"
,
"@sling//sling/myelin/kernel:tensorflow"
,
],
)
dragnn_myelin_cc_test
(
name
=
"myelin_spec_utils_test"
,
size
=
"small"
,
srcs
=
[
"myelin_spec_utils_test.cc"
],
deps
=
[
":myelin_spec_utils"
,
"//dragnn/core/test:generic"
,
"//dragnn/protos:spec_proto_cc"
,
"//syntaxnet:base"
,
"//syntaxnet:test_main"
,
"@org_tensorflow//tensorflow/core:lib"
,
"@org_tensorflow//tensorflow/core:test"
,
"@sling//sling/file"
,
"@sling//sling/file:posix"
,
"@sling//sling/myelin:compute"
,
"@sling//sling/myelin:flow"
,
],
)
dragnn_myelin_cc_library
(
name
=
"myelin_tracing"
,
srcs
=
[
"myelin_tracing.cc"
],
hdrs
=
[
"myelin_tracing.h"
],
deps
=
[
"//dragnn/protos:cell_trace_proto_cc"
,
"//syntaxnet:base"
,
"@org_tensorflow//tensorflow/core:lib"
,
"@sling//sling/myelin:compute"
,
],
)
dragnn_myelin_cc_test
(
name
=
"myelin_tracing_test"
,
size
=
"small"
,
srcs
=
[
"myelin_tracing_test.cc"
],
deps
=
[
":myelin_spec_utils"
,
":myelin_tracing"
,
"//dragnn/core/test:generic"
,
"//dragnn/protos:cell_trace_proto_cc"
,
"//dragnn/runtime/test:helpers"
,
"//syntaxnet:base"
,
"//syntaxnet:test_main"
,
"@org_tensorflow//tensorflow/core:lib"
,
"@org_tensorflow//tensorflow/core:test"
,
"@sling//sling/myelin:compute"
,
"@sling//sling/myelin:flow"
,
],
)
dragnn_myelin_cc_multiarch_library
(
name
=
"myelin_dynamic_component_base"
,
srcs
=
[
"myelin_dynamic_component_base.cc"
],
hdrs
=
[
"myelin_dynamic_component_base.h"
],
deps
=
[
":myelin_spec_utils"
,
":myelin_tracing"
,
"//dragnn/protos:cell_trace_proto_cc"
,
"//dragnn/protos:spec_proto_cc"
,
"//dragnn/protos:trace_proto_cc"
,
"//dragnn/runtime:alignment"
,
"//dragnn/runtime:component"
,
"//dragnn/runtime:extensions"
,
"//dragnn/runtime:fixed_embeddings"
,
"//dragnn/runtime:linked_embeddings"
,
"//dragnn/runtime:network_states"
,
"//dragnn/runtime:session_state"
,
"//dragnn/runtime:transition_system_traits"
,
"//dragnn/runtime:variable_store"
,
"//dragnn/runtime/math:types"
,
"//syntaxnet:base"
,
"@org_tensorflow//tensorflow/core:lib"
,
"@sling//sling/myelin:compute"
,
"@sling//sling/myelin:flow"
,
],
)
dragnn_myelin_cc_multiarch_library
(
name
=
"myelin_dynamic_component"
,
srcs
=
[
"myelin_dynamic_component.cc"
],
deps
=
[
":myelin_dynamic_component_base"
,
"//dragnn/core:compute_session"
,
"//dragnn/protos:spec_proto_cc"
,
"//dragnn/protos:trace_proto_cc"
,
"//dragnn/runtime:component"
,
"//dragnn/runtime:fixed_embeddings"
,
"//dragnn/runtime:linked_embeddings"
,
"//dragnn/runtime:network_states"
,
"//dragnn/runtime:session_state"
,
"//dragnn/runtime/math:types"
,
"//syntaxnet:base"
,
"@org_tensorflow//tensorflow/core:lib"
,
"@sling//sling/myelin:compute"
,
],
alwayslink
=
1
,
)
dragnn_myelin_cc_multiarch_test
(
name
=
"myelin_dynamic_component_test"
,
size
=
"small"
,
srcs
=
[
"myelin_dynamic_component_test.cc"
],
deps
=
[
":myelin_dynamic_component"
,
":myelin_spec_utils"
,
"//dragnn/core/test:generic"
,
"//dragnn/protos:cell_trace_proto_cc"
,
"//dragnn/protos:spec_proto_cc"
,
"//dragnn/protos:trace_proto_cc"
,
"//dragnn/runtime:component"
,
"//dragnn/runtime:extensions"
,
"//dragnn/runtime/test:network_test_base"
,
"//syntaxnet:base"
,
"@org_tensorflow//tensorflow/core:lib"
,
"@org_tensorflow//tensorflow/core:test"
,
"@sling//sling/file"
,
"@sling//sling/file:posix"
,
"@sling//sling/myelin:flow"
,
],
)
dragnn_myelin_cc_library
(
name
=
"myelination"
,
srcs
=
[
"myelination.cc"
],
hdrs
=
[
"myelination.h"
],
deps
=
[
":myelin_cell_converter"
,
":myelin_spec_utils"
,
"//dragnn/protos:spec_proto_cc"
,
"//dragnn/runtime:component"
,
"//dragnn/runtime:trained_model"
,
"//syntaxnet:base"
,
"//syntaxnet:registry"
,
"@org_tensorflow//tensorflow/core:lib"
,
],
)
dragnn_myelin_cc_test
(
name
=
"myelination_test"
,
size
=
"small"
,
timeout
=
"moderate"
,
srcs
=
[
"myelination_test.cc"
],
data
=
[
":test_myelination_output"
,
"//dragnn/runtime:test_rnn_tagger"
,
],
deps
=
[
":myelin_spec_utils"
,
":myelination"
,
"//dragnn/components/syntaxnet:syntaxnet_component"
,
"//dragnn/core/test:generic"
,
"//dragnn/protos:spec_proto_cc"
,
"//syntaxnet:base"
,
"@org_tensorflow//tensorflow/core:lib"
,
"@org_tensorflow//tensorflow/core:test"
,
],
)
dragnn_myelin_cc_multiarch_library
(
name
=
"sequence_myelin_dynamic_component"
,
srcs
=
[
"sequence_myelin_dynamic_component.cc"
],
deps
=
[
":myelin_dynamic_component_base"
,
"//dragnn/core:compute_session"
,
"//dragnn/protos:spec_proto_cc"
,
"//dragnn/protos:trace_proto_cc"
,
"//dragnn/runtime:component"
,
"//dragnn/runtime:extensions"
,
"//dragnn/runtime:network_states"
,
"//dragnn/runtime:sequence_features"
,
"//dragnn/runtime:sequence_links"
,
"//dragnn/runtime:sequence_model"
,
"//dragnn/runtime:session_state"
,
"//dragnn/runtime:variable_store"
,
"//dragnn/runtime/math:types"
,
"//syntaxnet:base"
,
"@org_tensorflow//tensorflow/core:lib"
,
"@sling//sling/myelin:compute"
,
],
alwayslink
=
1
,
)
dragnn_myelin_cc_multiarch_test
(
name
=
"sequence_myelin_dynamic_component_test"
,
size
=
"small"
,
srcs
=
[
"sequence_myelin_dynamic_component_test.cc"
],
deps
=
[
":myelin_spec_utils"
,
":sequence_myelin_dynamic_component"
,
"//dragnn/core:compute_session"
,
"//dragnn/core:input_batch_cache"
,
"//dragnn/core/test:generic"
,
"//dragnn/protos:spec_proto_cc"
,
"//dragnn/protos:trace_proto_cc"
,
"//dragnn/runtime:component"
,
"//dragnn/runtime:extensions"
,
"//dragnn/runtime:network_states"
,
"//dragnn/runtime:sequence_backend"
,
"//dragnn/runtime:sequence_extractor"
,
"//dragnn/runtime:sequence_linker"
,
"//dragnn/runtime:sequence_predictor"
,
"//dragnn/runtime:session_state"
,
"//dragnn/runtime:variable_store"
,
"//dragnn/runtime/math:types"
,
"//dragnn/runtime/test:network_test_base"
,
"//syntaxnet:base"
,
"@org_tensorflow//tensorflow/core:lib"
,
"@org_tensorflow//tensorflow/core:test"
,
"@sling//sling/file"
,
"@sling//sling/file:posix"
,
"@sling//sling/myelin:flow"
,
],
)
research/syntaxnet/dragnn/runtime/myelin/attr_value_utils.cc
deleted
100644 → 0
View file @
a4bb31d0
// Copyright 2017 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// =============================================================================
// Implementation note: This file contains branched versions of functions from
// tensorflow/core/framework/attr_value_util.cc. These functions are branched
// to prevent changes in their behavior from impacting the Myelin conversion.
#include "dragnn/runtime/myelin/attr_value_utils.h"
#include <algorithm>
#include <vector>
#include "tensorflow/core/framework/tensor.h"
#include "tensorflow/core/framework/tensor_shape.h"
#include "tensorflow/core/framework/tensor_shape.pb.h"
#include "tensorflow/core/framework/types.h"
#include "tensorflow/core/lib/core/errors.h"
#include "tensorflow/core/lib/core/stringpiece.h"
#include "tensorflow/core/lib/strings/str_util.h"
#include "tensorflow/core/platform/protobuf.h"
namespace
syntaxnet
{
namespace
dragnn
{
namespace
runtime
{
namespace
{
using
::
tensorflow
::
AttrValue
;
using
::
tensorflow
::
NameAttrList
;
using
::
tensorflow
::
PartialTensorShape
;
using
::
tensorflow
::
StringPiece
;
using
::
tensorflow
::
Tensor
;
using
::
tensorflow
::
TensorProto
;
using
::
tensorflow
::
TensorShape
;
namespace
strings
=
::
tensorflow
::
strings
;
namespace
str_util
=
::
tensorflow
::
str_util
;
string
SummarizeString
(
const
string
&
str
)
{
string
escaped
=
str_util
::
CEscape
(
str
);
// If the string is long, replace the middle with ellipses.
constexpr
int
kMaxStringSummarySize
=
80
;
if
(
escaped
.
size
()
>=
kMaxStringSummarySize
)
{
StringPiece
prefix
(
escaped
);
StringPiece
suffix
=
prefix
;
prefix
.
remove_suffix
(
escaped
.
size
()
-
10
);
suffix
.
remove_prefix
(
escaped
.
size
()
-
10
);
return
strings
::
StrCat
(
"
\"
"
,
prefix
,
"..."
,
suffix
,
"
\"
"
);
}
else
{
return
strings
::
StrCat
(
"
\"
"
,
escaped
,
"
\"
"
);
}
}
string
SummarizeTensor
(
const
TensorProto
&
tensor_proto
)
{
Tensor
t
;
if
(
!
t
.
FromProto
(
tensor_proto
))
return
"<Invalid TensorProto>"
;
return
t
.
DebugString
();
}
string
SummarizeFunc
(
const
NameAttrList
&
func
)
{
std
::
vector
<
string
>
entries
;
for
(
auto
p
:
func
.
attr
())
{
entries
.
push_back
(
strings
::
StrCat
(
p
.
first
,
"="
,
AttrValueToString
(
p
.
second
)));
}
std
::
sort
(
entries
.
begin
(),
entries
.
end
());
return
strings
::
StrCat
(
func
.
name
(),
"["
,
str_util
::
Join
(
entries
,
", "
),
"]"
);
}
}
// namespace
string
AttrValueToString
(
const
AttrValue
&
attr_value
)
{
switch
(
attr_value
.
value_case
())
{
case
AttrValue
::
kS
:
return
SummarizeString
(
attr_value
.
s
());
case
AttrValue
::
kI
:
return
strings
::
StrCat
(
attr_value
.
i
());
case
AttrValue
::
kF
:
return
strings
::
StrCat
(
attr_value
.
f
());
case
AttrValue
::
kB
:
return
attr_value
.
b
()
?
"true"
:
"false"
;
case
AttrValue
::
kType
:
return
DataType_Name
(
attr_value
.
type
());
case
AttrValue
::
kShape
:
return
PartialTensorShape
::
DebugString
(
attr_value
.
shape
());
case
AttrValue
::
kTensor
:
return
SummarizeTensor
(
attr_value
.
tensor
());
case
AttrValue
::
kList
:
{
std
::
vector
<
string
>
pieces
;
if
(
attr_value
.
list
().
s_size
()
>
0
)
{
for
(
int
i
=
0
;
i
<
attr_value
.
list
().
s_size
();
++
i
)
{
pieces
.
push_back
(
SummarizeString
(
attr_value
.
list
().
s
(
i
)));
}
}
else
if
(
attr_value
.
list
().
i_size
()
>
0
)
{
for
(
int
i
=
0
;
i
<
attr_value
.
list
().
i_size
();
++
i
)
{
pieces
.
push_back
(
strings
::
StrCat
(
attr_value
.
list
().
i
(
i
)));
}
}
else
if
(
attr_value
.
list
().
f_size
()
>
0
)
{
for
(
int
i
=
0
;
i
<
attr_value
.
list
().
f_size
();
++
i
)
{
pieces
.
push_back
(
strings
::
StrCat
(
attr_value
.
list
().
f
(
i
)));
}
}
else
if
(
attr_value
.
list
().
b_size
()
>
0
)
{
for
(
int
i
=
0
;
i
<
attr_value
.
list
().
b_size
();
++
i
)
{
pieces
.
push_back
(
attr_value
.
list
().
b
(
i
)
?
"true"
:
"false"
);
}
}
else
if
(
attr_value
.
list
().
type_size
()
>
0
)
{
for
(
int
i
=
0
;
i
<
attr_value
.
list
().
type_size
();
++
i
)
{
pieces
.
push_back
(
DataType_Name
(
attr_value
.
list
().
type
(
i
)));
}
}
else
if
(
attr_value
.
list
().
shape_size
()
>
0
)
{
for
(
int
i
=
0
;
i
<
attr_value
.
list
().
shape_size
();
++
i
)
{
pieces
.
push_back
(
TensorShape
::
DebugString
(
attr_value
.
list
().
shape
(
i
)));
}
}
else
if
(
attr_value
.
list
().
tensor_size
()
>
0
)
{
for
(
int
i
=
0
;
i
<
attr_value
.
list
().
tensor_size
();
++
i
)
{
pieces
.
push_back
(
SummarizeTensor
(
attr_value
.
list
().
tensor
(
i
)));
}
}
else
if
(
attr_value
.
list
().
func_size
()
>
0
)
{
for
(
int
i
=
0
;
i
<
attr_value
.
list
().
func_size
();
++
i
)
{
pieces
.
push_back
(
SummarizeFunc
(
attr_value
.
list
().
func
(
i
)));
}
}
return
strings
::
StrCat
(
"["
,
str_util
::
Join
(
pieces
,
", "
),
"]"
);
}
case
AttrValue
::
kFunc
:
{
return
SummarizeFunc
(
attr_value
.
func
());
}
case
AttrValue
::
kPlaceholder
:
return
strings
::
StrCat
(
"$"
,
attr_value
.
placeholder
());
case
AttrValue
::
VALUE_NOT_SET
:
return
"<Unknown AttrValue type>"
;
}
return
"<Unknown AttrValue type>"
;
// Prevent missing return warning
}
}
// namespace runtime
}
// namespace dragnn
}
// namespace syntaxnet
research/syntaxnet/dragnn/runtime/myelin/attr_value_utils.h
deleted
100644 → 0
View file @
a4bb31d0
// Copyright 2017 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// =============================================================================
// Utils for working with tensorflow.AttrValue protos.
#ifndef DRAGNN_RUNTIME_MYELIN_ATTR_VALUE_UTILS_H_
#define DRAGNN_RUNTIME_MYELIN_ATTR_VALUE_UTILS_H_
#include <string>
#include "syntaxnet/base.h"
#include "tensorflow/core/framework/attr_value.pb.h"
namespace
syntaxnet
{
namespace
dragnn
{
namespace
runtime
{
// Returns a string representation of the |attr_value|. This is similar to
// tensorflow::SummarizeAttrValue(), but never elides or abbreviates.
string
AttrValueToString
(
const
tensorflow
::
AttrValue
&
attr_value
);
}
// namespace runtime
}
// namespace dragnn
}
// namespace syntaxnet
#endif // DRAGNN_RUNTIME_MYELIN_ATTR_VALUE_UTILS_H_
research/syntaxnet/dragnn/runtime/myelin/attr_value_utils_test.cc
deleted
100644 → 0
View file @
a4bb31d0
// Copyright 2017 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// =============================================================================
// NB: These tests don't assert on dtypes, shapes, or tensors, because those are
// just calls to TF library functions. (I.e., don't test someone else's API).
#include "dragnn/runtime/myelin/attr_value_utils.h"
#include <string>
#include "dragnn/core/test/generic.h"
#include "syntaxnet/base.h"
#include "tensorflow/core/lib/core/status_test_util.h"
#include "tensorflow/core/lib/core/stringpiece.h"
#include "tensorflow/core/lib/io/path.h"
#include "tensorflow/core/lib/strings/numbers.h"
#include "tensorflow/core/lib/strings/str_util.h"
#include "tensorflow/core/lib/strings/strcat.h"
#include "tensorflow/core/platform/test.h"
namespace
syntaxnet
{
namespace
dragnn
{
namespace
runtime
{
namespace
{
// Tests that singular attributes are stringified correctly.
TEST
(
AttrValueToStringTest
,
Singular
)
{
{
tensorflow
::
AttrValue
attr_value
;
attr_value
.
set_s
(
"foo"
);
EXPECT_EQ
(
AttrValueToString
(
attr_value
),
"
\"
foo
\"
"
);
}
{
tensorflow
::
AttrValue
attr_value
;
attr_value
.
set_i
(
123
);
EXPECT_EQ
(
AttrValueToString
(
attr_value
),
"123"
);
}
{
tensorflow
::
AttrValue
attr_value
;
attr_value
.
set_f
(
-
1.5
);
EXPECT_EQ
(
AttrValueToString
(
attr_value
),
"-1.5"
);
}
{
tensorflow
::
AttrValue
attr_value
;
attr_value
.
set_b
(
false
);
EXPECT_EQ
(
AttrValueToString
(
attr_value
),
"false"
);
attr_value
.
set_b
(
true
);
EXPECT_EQ
(
AttrValueToString
(
attr_value
),
"true"
);
}
}
// Tests that list attributes are stringified correctly.
TEST
(
AttrValueToStringTest
,
List
)
{
{
tensorflow
::
AttrValue
attr_value
;
attr_value
.
mutable_list
()
->
add_s
(
"foo"
);
attr_value
.
mutable_list
()
->
add_s
(
"bar"
);
attr_value
.
mutable_list
()
->
add_s
(
"baz"
);
EXPECT_EQ
(
AttrValueToString
(
attr_value
),
"[
\"
foo
\"
,
\"
bar
\"
,
\"
baz
\"
]"
);
}
{
tensorflow
::
AttrValue
attr_value
;
attr_value
.
mutable_list
()
->
add_i
(
123
);
attr_value
.
mutable_list
()
->
add_i
(
-
45
);
attr_value
.
mutable_list
()
->
add_i
(
6789
);
EXPECT_EQ
(
AttrValueToString
(
attr_value
),
"[123, -45, 6789]"
);
}
{
tensorflow
::
AttrValue
attr_value
;
attr_value
.
mutable_list
()
->
add_f
(
-
1.5
);
attr_value
.
mutable_list
()
->
add_f
(
0.25
);
attr_value
.
mutable_list
()
->
add_f
(
3.5
);
EXPECT_EQ
(
AttrValueToString
(
attr_value
),
"[-1.5, 0.25, 3.5]"
);
}
{
tensorflow
::
AttrValue
attr_value
;
attr_value
.
mutable_list
()
->
add_b
(
false
);
attr_value
.
mutable_list
()
->
add_b
(
true
);
attr_value
.
mutable_list
()
->
add_b
(
false
);
EXPECT_EQ
(
AttrValueToString
(
attr_value
),
"[false, true, false]"
);
}
}
}
// namespace
}
// namespace runtime
}
// namespace dragnn
}
// namespace syntaxnet
research/syntaxnet/dragnn/runtime/myelin/build_defs.bzl
deleted
100644 → 0
View file @
a4bb31d0
# Copyright 2017 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# =============================================================================
"""Build rules that restrict Myelin to supported environments.
As of this writing, SLING requires Linux and x86-64:
https://github.com/google/sling/blob/master/README.md#building
The technique used here is to replace the hdrs, srcs, and deps with appropriate
empty content when building in an unsupported environment.
"""
load
(
"//dragnn/runtime:multiarch.bzl"
,
"dragnn_cc_multiarch_library"
,
"dragnn_cc_multiarch_test"
,
)
def
_if_supported
(
consequent
,
alternative
=
[]):
"""Returns the |consequent| iff the build environment supports Myelin."""
return
select
({
"@org_tensorflow//tensorflow:linux_x86_64"
:
consequent
,
"//conditions:default"
:
alternative
,
})
def
_if_supported_test_deps
(
deps
):
"""Like _if_supported, but returns appropriate fallback deps for a test."""
return
_if_supported
(
deps
,
[
"//syntaxnet:test_main"
])
def
dragnn_myelin_cc_library
(
hdrs
=
[],
srcs
=
[],
deps
=
[],
**
kwargs
):
"""Like cc_library, but reduces to a NOP in unsupported environments."""
native
.
cc_library
(
hdrs
=
_if_supported
(
hdrs
),
srcs
=
_if_supported
(
srcs
),
deps
=
_if_supported
(
deps
),
**
kwargs
)
def
dragnn_myelin_cc_test
(
srcs
=
[],
deps
=
[],
**
kwargs
):
"""Like cc_test, but reduces to a NOP in unsupported environments."""
native
.
cc_test
(
srcs
=
_if_supported
(
srcs
),
deps
=
_if_supported_test_deps
(
deps
),
**
kwargs
)
# Implementation note: Bazel select()s are not resolved at the time that build
# rules are evaluated. If we pass _if_supported(deps) into the multi-arch build
# rules (like we do for the native rules above), then the multi-arch rules break
# when they attempt to iterate over the deps---at that point, the deps are an
# unresolved select() that can't be iterated. To get around this, we delay the
# select() by passing _if_supported into the multi-arch rule, which will apply
# it just before passing the deps to the native rule.
def
dragnn_myelin_cc_multiarch_library
(
hdrs
=
[],
srcs
=
[],
**
kwargs
):
"""Multi-arch version of dragnn_myelin_cc_library."""
dragnn_cc_multiarch_library
(
hdrs
=
_if_supported
(
hdrs
),
srcs
=
_if_supported
(
srcs
),
deps_transformer
=
_if_supported
,
**
kwargs
)
def
dragnn_myelin_cc_multiarch_test
(
srcs
=
[],
**
kwargs
):
"""Multi-arch version of dragnn_myelin_cc_test."""
dragnn_cc_multiarch_test
(
srcs
=
_if_supported
(
srcs
,
[]),
deps_transformer
=
_if_supported_test_deps
,
**
kwargs
)
research/syntaxnet/dragnn/runtime/myelin/myelin_cell_converter.cc
deleted
100644 → 0
View file @
a4bb31d0
// Copyright 2017 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// =============================================================================
#include "dragnn/runtime/myelin/myelin_cell_converter.h"
#include <stddef.h>
#include <algorithm>
#include <limits>
#include "dragnn/runtime/myelin/attr_value_utils.h"
#include "tensorflow/core/framework/attr_value.pb.h"
#include "tensorflow/core/framework/node_def_util.h"
#include "tensorflow/core/framework/tensor.h"
#include "tensorflow/core/framework/tensor.pb.h"
#include "tensorflow/core/framework/tensor_shape.h"
#include "tensorflow/core/framework/tensor_shape.pb.h"
#include "tensorflow/core/framework/types.h"
#include "tensorflow/core/framework/types.pb.h"
#include "tensorflow/core/lib/core/errors.h"
#include "tensorflow/core/lib/core/stringpiece.h"
#include "tensorflow/core/lib/strings/numbers.h"
#include "tensorflow/core/lib/strings/strcat.h"
#include "tensorflow/core/platform/cpu_info.h"
#include "tensorflow/core/platform/logging.h"
namespace
syntaxnet
{
namespace
dragnn
{
namespace
runtime
{
namespace
{
// Returns true if the |tensor_name| denotes a control dependency.
bool
IsControlDependency
(
const
string
&
tensor_name
)
{
return
tensor_name
[
0
]
==
'^'
;
}
// Returns true if the |node| is a TF variable.
bool
IsVariableNode
(
const
tensorflow
::
NodeDef
&
node
)
{
return
node
.
op
()
==
"VariableV2"
;
}
// Returns true if the |node| is a tf.constant().
bool
IsConstantNode
(
const
tensorflow
::
NodeDef
&
node
)
{
return
node
.
op
()
==
"Const"
;
}
// Returns true if the |node| is a tf.placeholder().
bool
IsPlaceholderNode
(
const
tensorflow
::
NodeDef
&
node
)
{
return
node
.
op
()
==
"Placeholder"
;
}
// Sets |max_value| to |value| if it is lesser.
void
UpdateMax
(
uint32
value
,
uint32
*
max_value
)
{
*
max_value
=
std
::
max
(
*
max_value
,
value
);
}
// Loads the |tensor| from the constant |node|. On error, returns non-OK.
tensorflow
::
Status
GetConstantTensor
(
const
tensorflow
::
NodeDef
&
node
,
tensorflow
::
Tensor
*
tensor
)
{
DCHECK
(
IsConstantNode
(
node
));
return
tensorflow
::
GetNodeAttr
(
node
,
"value"
,
tensor
);
}
// Loads the |shape| from the placeholder |node|. On error, returns non-OK.
tensorflow
::
Status
GetPlaceholderShape
(
const
tensorflow
::
NodeDef
&
node
,
tensorflow
::
TensorShape
*
shape
)
{
DCHECK
(
IsPlaceholderNode
(
node
));
return
tensorflow
::
GetNodeAttr
(
node
,
"shape"
,
shape
);
}
// Returns the dtype string associated with the |node|, or an empty string if it
// cannot be inferred.
string
GetDType
(
const
tensorflow
::
NodeDef
&
node
)
{
tensorflow
::
DataType
dtype
;
tensorflow
::
Status
status
=
tensorflow
::
GetNodeAttr
(
node
,
"T"
,
&
dtype
);
if
(
!
status
.
ok
())
status
=
tensorflow
::
GetNodeAttr
(
node
,
"dtype"
,
&
dtype
);
if
(
status
.
ok
())
return
tensorflow
::
DataTypeString
(
dtype
);
return
string
();
}
// Modifies the |dtype| into a reference type.
void
MarkAsReferenceDType
(
string
*
dtype
)
{
DCHECK_NE
((
*
dtype
)[
0
],
'&'
);
*
dtype
=
tensorflow
::
strings
::
StrCat
(
"&"
,
*
dtype
);
}
// Loads the CellSubgraphSpec for the component named |component_name| from the
// |trained_model| into the |spec|. On error, returns non-OK.
tensorflow
::
Status
LoadCellSubgraphSpec
(
const
string
&
component_name
,
const
TrainedModel
&
trained_model
,
CellSubgraphSpec
*
spec
)
{
const
string
tensor_name
=
tensorflow
::
strings
::
StrCat
(
component_name
,
"/EXPORT/CellSubgraphSpec"
);
tensorflow
::
Tensor
tensor
;
TF_RETURN_IF_ERROR
(
trained_model
.
EvaluateTensor
(
tensor_name
,
&
tensor
));
if
(
!
spec
->
ParseFromString
(
tensor
.
scalar
<
string
>
()()))
{
return
tensorflow
::
errors
::
InvalidArgument
(
"Failed to parse CellSubgraphSpec for component "
,
component_name
);
}
VLOG
(
1
)
<<
tensor_name
<<
" =
\n
"
<<
spec
->
DebugString
();
return
tensorflow
::
Status
::
OK
();
}
}
// namespace
// Writer for incrementally building a Flow file.
// https://github.com/google/sling/tree/master/myelin#flow-file-format
class
MyelinCellConverter
::
Writer
{
public:
// TODO(googleuser): Add templated Write() methods and coerce typed data into
// little-endian format, so this doesn't need to run on a little-endian CPU.
static_assert
(
tensorflow
::
port
::
kLittleEndian
,
"Flow files must be written in little-endian format"
);
// Creates a writer that overwrites |flow|.
explicit
Writer
(
string
*
flow
)
:
flow_
(
CHECK_NOTNULL
(
flow
))
{
flow_
->
clear
();
Write
(
"flow"
,
4
);
// magic number
WriteInt32
(
4
);
// version
}
// Appends [|data|,|data|+|size|) to the Flow file.
void
Write
(
const
void
*
data
,
size_t
size
)
{
flow_
->
append
(
reinterpret_cast
<
const
char
*>
(
data
),
size
);
}
// Appends the |value| to the Flow file.
void
WriteInt32
(
int32
value
)
{
Write
(
&
value
,
sizeof
(
int32
));
}
void
WriteUint64
(
uint64
value
)
{
Write
(
&
value
,
sizeof
(
uint64
));
}
// Writes the |str| to the Flow file as a length-prefixed string.
void
WriteString
(
const
string
&
str
)
{
DCHECK_LE
(
str
.
size
(),
std
::
numeric_limits
<
int32
>::
max
());
WriteInt32
(
str
.
size
());
Write
(
str
.
data
(),
str
.
size
());
}
private:
// Flow file content.
string
*
const
flow_
;
};
tensorflow
::
Status
MyelinCellConverter
::
Convert
(
const
string
&
component_name
,
const
TrainedModel
&
trained_model
,
string
*
flow
)
{
return
MyelinCellConverter
().
ConvertImpl
(
component_name
,
trained_model
,
flow
);
}
tensorflow
::
Status
MyelinCellConverter
::
ConvertImpl
(
const
string
&
component_name
,
const
TrainedModel
&
trained_model
,
string
*
flow
)
{
component_name_
=
component_name
;
trained_model_
=
&
trained_model
;
CellSubgraphSpec
spec
;
TF_RETURN_IF_ERROR
(
LoadCellSubgraphSpec
(
component_name_
,
*
trained_model_
,
&
spec
));
TF_RETURN_IF_ERROR
(
BuildInputsAndOutputs
(
spec
));
TF_RETURN_IF_ERROR
(
BuildOperations
());
Writer
writer
(
flow
);
TF_RETURN_IF_ERROR
(
WriteVariables
(
&
writer
));
WriteOperations
(
&
writer
);
WriteFunctions
(
&
writer
);
WriteConnectors
(
&
writer
);
WriteBlobs
(
&
writer
);
return
tensorflow
::
Status
::
OK
();
}
tensorflow
::
Status
MyelinCellConverter
::
BuildInputsAndOutputs
(
const
CellSubgraphSpec
&
spec
)
{
std
::
set
<
string
>
unique_input_names
;
for
(
const
CellSubgraphSpec
::
Input
&
input
:
spec
.
input
())
{
if
(
!
unique_input_names
.
insert
(
input
.
name
()).
second
)
{
return
tensorflow
::
errors
::
InvalidArgument
(
"Duplicate input name { "
,
input
.
ShortDebugString
(),
" }"
);
}
TensorId
tensor_id
;
TF_RETURN_IF_ERROR
(
ParseTensorId
(
input
.
tensor
(),
&
tensor_id
));
if
(
inputs_
.
find
(
tensor_id
)
!=
inputs_
.
end
())
{
return
tensorflow
::
errors
::
InvalidArgument
(
"Duplicate input variable { "
,
input
.
ShortDebugString
(),
" }; currently has name '"
,
inputs_
[
tensor_id
],
"'"
);
}
inputs_
[
tensor_id
]
=
input
.
name
();
}
std
::
set
<
string
>
unique_output_names
;
for
(
const
CellSubgraphSpec
::
Output
&
output
:
spec
.
output
())
{
if
(
!
unique_output_names
.
insert
(
output
.
name
()).
second
)
{
return
tensorflow
::
errors
::
InvalidArgument
(
"Duplicate output name { "
,
output
.
ShortDebugString
(),
" }"
);
}
TensorId
tensor_id
;
TF_RETURN_IF_ERROR
(
ParseTensorId
(
output
.
tensor
(),
&
tensor_id
));
outputs_
[
tensor_id
].
insert
(
output
.
name
());
}
// Check that recurrent inputs match the name of an output.
for
(
const
CellSubgraphSpec
::
Input
&
input
:
spec
.
input
())
{
if
(
input
.
type
()
!=
CellSubgraphSpec
::
Input
::
TYPE_RECURRENT
)
continue
;
if
(
unique_output_names
.
find
(
input
.
name
())
==
unique_output_names
.
end
())
{
return
tensorflow
::
errors
::
InvalidArgument
(
"Recurrent input does not match any output { "
,
input
.
ShortDebugString
(),
" }"
);
}
}
return
tensorflow
::
Status
::
OK
();
}
tensorflow
::
Status
MyelinCellConverter
::
BuildOperations
()
{
// Extract sets of input and output node names.
std
::
set
<
string
>
input_node_names
;
std
::
set
<
string
>
output_node_names
;
for
(
const
auto
&
it
:
inputs_
)
input_node_names
.
insert
(
it
.
first
.
first
);
for
(
const
auto
&
it
:
outputs_
)
output_node_names
.
insert
(
it
.
first
.
first
);
// Set of nodes that have already been visited by the DFS.
std
::
set
<
string
>
visited
;
// DFS backwards from output nodes to input nodes and collect operations.
std
::
vector
<
string
>
stack
(
output_node_names
.
begin
(),
output_node_names
.
end
());
while
(
!
stack
.
empty
())
{
const
string
name
=
stack
.
back
();
stack
.
pop_back
();
if
(
!
visited
.
insert
(
name
).
second
)
continue
;
// already visited; skip
const
tensorflow
::
NodeDef
*
node
=
nullptr
;
TF_RETURN_IF_ERROR
(
trained_model_
->
LookupNode
(
name
,
&
node
));
Operation
&
operation
=
operations_
[
name
];
if
(
operation
.
node
!=
nullptr
&&
operation
.
node
!=
node
)
{
return
tensorflow
::
errors
::
Internal
(
"Inconsistent nodes for operation "
,
name
,
" ("
,
operation
.
node
->
name
(),
" vs "
,
node
->
name
());
}
operation
.
node
=
node
;
// Function inputs bound the search; don't expand them.
if
(
input_node_names
.
find
(
name
)
!=
input_node_names
.
end
())
continue
;
// Expand (non-control) inputs.
for
(
const
string
&
input_name
:
node
->
input
())
{
if
(
IsControlDependency
(
input_name
))
continue
;
VLOG
(
1
)
<<
name
<<
" has input "
<<
input_name
;
TensorId
tensor_id
;
TF_RETURN_IF_ERROR
(
ParseTensorId
(
input_name
,
&
tensor_id
));
stack
.
push_back
(
tensor_id
.
first
);
// Add the input tensor and register the output index on the input op.
operation
.
inputs
.
push_back
(
AsVariableName
(
tensor_id
));
UpdateMax
(
tensor_id
.
second
+
1
,
&
operations_
[
tensor_id
.
first
].
num_outputs
);
}
}
// Register output indices for the |outputs_|; the DFS does not cover these.
for
(
const
auto
&
it
:
outputs_
)
{
const
TensorId
&
tensor_id
=
it
.
first
;
UpdateMax
(
tensor_id
.
second
+
1
,
&
operations_
[
tensor_id
.
first
].
num_outputs
);
}
// Sanity check: All operations must have nodes and outputs.
for
(
const
auto
&
it
:
operations_
)
{
const
Operation
&
operation
=
it
.
second
;
DCHECK
(
operation
.
node
!=
nullptr
);
DCHECK_GT
(
operation
.
num_outputs
,
0
);
}
return
tensorflow
::
Status
::
OK
();
}
tensorflow
::
Status
MyelinCellConverter
::
WriteVariables
(
Writer
*
writer
)
const
{
int
num_variables
=
0
;
for
(
const
auto
&
it
:
operations_
)
num_variables
+=
it
.
second
.
num_outputs
;
writer
->
WriteInt32
(
num_variables
);
for
(
const
auto
&
it
:
operations_
)
{
const
Operation
&
operation
=
it
.
second
;
for
(
uint32
output
=
0
;
output
<
operation
.
num_outputs
;
++
output
)
{
TF_RETURN_IF_ERROR
(
WriteVariable
(
*
operation
.
node
,
output
,
writer
));
}
}
return
tensorflow
::
Status
::
OK
();
}
tensorflow
::
Status
MyelinCellConverter
::
WriteVariable
(
const
tensorflow
::
NodeDef
&
node
,
uint32
output_index
,
Writer
*
writer
)
const
{
const
TensorId
tensor_id
(
node
.
name
(),
output_index
);
const
string
name
=
AsVariableName
(
tensor_id
);
const
std
::
set
<
string
>
aliases
=
GetAliases
(
tensor_id
);
// Only cell inputs and outputs have aliases.
const
bool
is_cell_input_or_output
=
!
aliases
.
empty
();
// Treat cell inputs and outputs as references, so they can be pointed at
// pieces of memory managed by the DRAGNN runtime.
string
dtype
=
GetDType
(
node
);
if
(
is_cell_input_or_output
)
MarkAsReferenceDType
(
&
dtype
);
// Extract variable data and shape, if available. Myelin treats a 0-element
// shape (e.g., [0], [1, 0, 2]) as undefined and will infer shapes for such
// variables, so we ensure that the shape is undefined unless explicitly set.
tensorflow
::
Tensor
tensor
;
tensorflow
::
TensorShape
shape
({
0
});
// undefined by default
if
(
IsConstantNode
(
node
))
{
TF_RETURN_IF_ERROR
(
GetConstantTensor
(
node
,
&
tensor
));
shape
=
tensor
.
shape
();
}
else
if
(
IsVariableNode
(
node
))
{
TF_RETURN_IF_ERROR
(
trained_model_
->
EvaluateTensor
(
name
,
&
tensor
));
shape
=
tensor
.
shape
();
}
else
if
(
IsPlaceholderNode
(
node
))
{
TF_RETURN_IF_ERROR
(
GetPlaceholderShape
(
node
,
&
shape
));
}
const
tensorflow
::
StringPiece
data
=
tensor
.
tensor_data
();
writer
->
WriteString
(
name
);
writer
->
WriteInt32
(
aliases
.
size
());
for
(
const
string
&
alias
:
aliases
)
writer
->
WriteString
(
alias
);
writer
->
WriteString
(
dtype
);
writer
->
WriteInt32
(
shape
.
dims
());
for
(
int
i
=
0
;
i
<
shape
.
dims
();
++
i
)
writer
->
WriteInt32
(
shape
.
dim_size
(
i
));
writer
->
WriteUint64
(
data
.
size
());
writer
->
Write
(
data
.
data
(),
data
.
size
());
return
tensorflow
::
Status
::
OK
();
}
std
::
set
<
string
>
MyelinCellConverter
::
GetAliases
(
const
TensorId
&
tensor_id
)
const
{
std
::
set
<
string
>
aliases
;
const
auto
input_it
=
inputs_
.
find
(
tensor_id
);
if
(
input_it
!=
inputs_
.
end
())
{
const
string
&
name
=
input_it
->
second
;
aliases
.
insert
(
tensorflow
::
strings
::
StrCat
(
"INPUT/"
,
name
));
}
const
auto
output_it
=
outputs_
.
find
(
tensor_id
);
if
(
output_it
!=
outputs_
.
end
())
{
for
(
const
string
&
name
:
output_it
->
second
)
{
aliases
.
insert
(
tensorflow
::
strings
::
StrCat
(
"OUTPUT/"
,
name
));
}
}
return
aliases
;
}
void
MyelinCellConverter
::
WriteOperations
(
Writer
*
writer
)
const
{
writer
->
WriteInt32
(
operations_
.
size
());
for
(
const
auto
&
it
:
operations_
)
{
const
Operation
&
operation
=
it
.
second
;
WriteOperation
(
operation
,
writer
);
}
}
void
MyelinCellConverter
::
WriteOperation
(
const
Operation
&
operation
,
Writer
*
writer
)
const
{
const
string
&
name
=
operation
.
node
->
name
();
const
string
&
type
=
operation
.
node
->
op
();
// Create one output per possible output index, in order.
std
::
vector
<
string
>
outputs
;
for
(
uint32
output
=
0
;
output
<
operation
.
num_outputs
;
++
output
)
{
outputs
.
push_back
(
AsVariableName
(
TensorId
(
name
,
output
)));
}
// Copy the attrs to a sorted map for deterministic ordering.
std
::
map
<
string
,
tensorflow
::
AttrValue
>
attrs
(
operation
.
node
->
attr
().
begin
(),
operation
.
node
->
attr
().
end
());
writer
->
WriteString
(
name
);
writer
->
WriteString
(
type
);
writer
->
WriteInt32
(
operation
.
inputs
.
size
());
for
(
const
string
&
input
:
operation
.
inputs
)
writer
->
WriteString
(
input
);
writer
->
WriteInt32
(
outputs
.
size
());
for
(
const
string
&
output
:
outputs
)
writer
->
WriteString
(
output
);
writer
->
WriteInt32
(
attrs
.
size
());
for
(
const
auto
&
it
:
attrs
)
{
writer
->
WriteString
(
it
.
first
);
writer
->
WriteString
(
AttrValueToString
(
it
.
second
));
}
}
void
MyelinCellConverter
::
WriteFunctions
(
Writer
*
writer
)
const
{
writer
->
WriteInt32
(
1
);
writer
->
WriteString
(
component_name_
);
writer
->
WriteInt32
(
operations_
.
size
());
for
(
const
auto
&
it
:
operations_
)
writer
->
WriteString
(
it
.
first
);
}
void
MyelinCellConverter
::
WriteConnectors
(
Writer
*
writer
)
const
{
writer
->
WriteInt32
(
0
);
}
void
MyelinCellConverter
::
WriteBlobs
(
Writer
*
writer
)
const
{
writer
->
WriteInt32
(
0
);
}
tensorflow
::
Status
MyelinCellConverter
::
ParseTensorId
(
const
string
&
tensor_name
,
TensorId
*
tensor_id
)
{
if
(
IsControlDependency
(
tensor_name
))
{
return
tensorflow
::
errors
::
InvalidArgument
(
"Cannot parse tensor ID from control dependency '"
,
tensor_name
,
"'"
);
}
const
auto
colon_index
=
tensor_name
.
rfind
(
':'
);
// NB: If |colon_index| is string::npos, takes the whole string as desired.
tensor_id
->
first
=
tensor_name
.
substr
(
0
,
colon_index
);
if
(
colon_index
==
string
::
npos
)
{
// no colon; assume 0
tensor_id
->
second
=
0
;
}
else
{
const
string
output_str
=
tensor_name
.
substr
(
colon_index
+
1
);
if
(
!
tensorflow
::
strings
::
safe_strtou32
(
output_str
,
&
tensor_id
->
second
))
{
return
tensorflow
::
errors
::
InvalidArgument
(
"Malformed tensor name "
,
tensor_name
);
}
}
return
tensorflow
::
Status
::
OK
();
}
string
MyelinCellConverter
::
AsVariableName
(
const
TensorId
&
tensor_id
)
{
if
(
tensor_id
.
second
==
0
)
return
tensor_id
.
first
;
return
tensorflow
::
strings
::
StrCat
(
tensor_id
.
first
,
":"
,
tensor_id
.
second
);
}
}
// namespace runtime
}
// namespace dragnn
}
// namespace syntaxnet
Prev
1
2
3
4
5
6
7
8
9
10
…
15
Next
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment