You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
162 lines
5.9 KiB
162 lines
5.9 KiB
7 months ago
|
// Copyright 2020 Google LLC
|
||
|
//
|
||
|
// This source code is licensed under the BSD-style license found in the
|
||
|
// LICENSE file in the root directory of this source tree.
|
||
|
|
||
|
#pragma once
|
||
|
|
||
|
#include <xnnpack.h>
|
||
|
#include <xnnpack/subgraph.h>
|
||
|
|
||
|
#include <algorithm>
|
||
|
#include <cassert>
|
||
|
#include <cmath>
|
||
|
#include <cstddef>
|
||
|
#include <cstdlib>
|
||
|
#include <functional>
|
||
|
#include <random>
|
||
|
#include <vector>
|
||
|
|
||
|
#include <gtest/gtest.h>
|
||
|
|
||
|
enum xnn_tensor_type {
|
||
|
kStaticDense,
|
||
|
kStaticSparse,
|
||
|
kDynamic,
|
||
|
};
|
||
|
|
||
|
class SubgraphTester {
|
||
|
public:
|
||
|
explicit SubgraphTester(uint32_t external_value_ids) {
|
||
|
xnn_status status = xnn_initialize(nullptr);
|
||
|
EXPECT_EQ(status, xnn_status_success);
|
||
|
|
||
|
xnn_subgraph_t subgraph_ptr = nullptr;
|
||
|
status = xnn_create_subgraph(external_value_ids, 0 /* flags */, &subgraph_ptr);
|
||
|
EXPECT_EQ(status, xnn_status_success);
|
||
|
subgraph_.reset(subgraph_ptr);
|
||
|
|
||
|
std::random_device random_device;
|
||
|
rng_ = std::mt19937(random_device());
|
||
|
}
|
||
|
|
||
|
inline SubgraphTester& add_tensor(const std::vector<size_t>& dims,
|
||
|
xnn_tensor_type tensor_type,
|
||
|
uint32_t external_id) {
|
||
|
void* data = nullptr;
|
||
|
if (tensor_type == kStaticDense || tensor_type == kStaticSparse) {
|
||
|
const size_t num_elements = std::accumulate(std::begin(dims), std::end(dims), 1, std::multiplies<size_t>());
|
||
|
static_data_.emplace_back(num_elements);
|
||
|
std::vector<float>& weights = static_data_.back();
|
||
|
auto f32rng = std::bind(std::uniform_real_distribution<float>(-1.0f, +1.0f), std::ref(rng_));
|
||
|
if (tensor_type == kStaticDense) {
|
||
|
std::generate(weights.begin(), weights.end(), std::ref(f32rng));
|
||
|
} else {
|
||
|
// Create tensor with 90% sparsity in two steps:
|
||
|
// 1. Generate non-zero elements in the beginning of the vector
|
||
|
// 2. Randomize positions of non-zero elements
|
||
|
const size_t num_nonzero_elements = num_elements / 10;
|
||
|
std::generate(weights.begin(), weights.begin() + num_nonzero_elements, std::ref(f32rng));
|
||
|
std::shuffle(weights.begin(), weights.end(), rng_);
|
||
|
}
|
||
|
data = weights.data();
|
||
|
}
|
||
|
uint32_t id_out = 0;
|
||
|
const xnn_status status =
|
||
|
xnn_define_tensor_value(subgraph_.get(), xnn_datatype_fp32, dims.size(),
|
||
|
dims.data(), data, external_id, 0 /* flags */, &id_out);
|
||
|
EXPECT_EQ(status, xnn_status_success);
|
||
|
EXPECT_EQ(id_out, external_id);
|
||
|
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
inline SubgraphTester& add_conv(
|
||
|
uint32_t input_padding_top, uint32_t input_padding_right,
|
||
|
uint32_t input_padding_bottom, uint32_t input_padding_left,
|
||
|
uint32_t kernel_height, uint32_t kernel_width,
|
||
|
uint32_t subsampling_height, uint32_t subsampling_width,
|
||
|
uint32_t dilation_height, uint32_t dilation_width, uint32_t groups,
|
||
|
size_t group_input_channels, size_t group_output_channels,
|
||
|
uint32_t input_id, uint32_t filter_id, uint32_t bias_id,
|
||
|
uint32_t output_id)
|
||
|
{
|
||
|
const xnn_status status = xnn_define_convolution_2d(
|
||
|
subgraph_.get(), input_padding_top, input_padding_right,
|
||
|
input_padding_bottom, input_padding_left, kernel_height, kernel_width,
|
||
|
subsampling_height, subsampling_width, dilation_height, dilation_width,
|
||
|
groups, group_input_channels, group_output_channels,
|
||
|
-std::numeric_limits<float>::infinity(),
|
||
|
std::numeric_limits<float>::infinity(), input_id, filter_id, bias_id,
|
||
|
output_id, 0 /* flags */);
|
||
|
EXPECT_EQ(status, xnn_status_success);
|
||
|
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
inline SubgraphTester& add_depthwise_conv(
|
||
|
uint32_t input_padding_top, uint32_t input_padding_right,
|
||
|
uint32_t input_padding_bottom, uint32_t input_padding_left,
|
||
|
uint32_t kernel_height, uint32_t kernel_width,
|
||
|
uint32_t subsampling_height, uint32_t subsampling_width,
|
||
|
uint32_t dilation_height, uint32_t dilation_width,
|
||
|
uint32_t depth_multiplier, size_t input_channels, uint32_t input_id,
|
||
|
uint32_t filter_id, uint32_t bias_id, uint32_t output_id)
|
||
|
{
|
||
|
const xnn_status status = xnn_define_depthwise_convolution_2d(
|
||
|
subgraph_.get(), input_padding_top, input_padding_right,
|
||
|
input_padding_bottom, input_padding_left, kernel_height, kernel_width,
|
||
|
subsampling_height, subsampling_width, dilation_height, dilation_width,
|
||
|
depth_multiplier, input_channels,
|
||
|
-std::numeric_limits<float>::infinity(),
|
||
|
std::numeric_limits<float>::infinity(), input_id, filter_id, bias_id,
|
||
|
output_id, 0 /* flags */);
|
||
|
EXPECT_EQ(status, xnn_status_success);
|
||
|
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
inline SubgraphTester& add_addition(uint32_t input_id1, uint32_t input_id2, uint32_t output_id)
|
||
|
{
|
||
|
const xnn_status status =
|
||
|
xnn_define_add2(subgraph_.get(), -std::numeric_limits<float>::infinity(),
|
||
|
std::numeric_limits<float>::infinity(), input_id1,
|
||
|
input_id2, output_id, 0 /* flags */);
|
||
|
EXPECT_EQ(status, xnn_status_success);
|
||
|
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
inline SubgraphTester& add_global_average_pooling(uint32_t input_id, uint32_t output_id)
|
||
|
{
|
||
|
const xnn_status status = xnn_define_global_average_pooling_2d(
|
||
|
subgraph_.get(), -std::numeric_limits<float>::infinity(),
|
||
|
std::numeric_limits<float>::infinity(), input_id, output_id, 0 /* flags */);
|
||
|
EXPECT_EQ(status, xnn_status_success);
|
||
|
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
inline SubgraphTester& optimize() {
|
||
|
const xnn_status status = xnn_subgraph_optimize(subgraph_.get(), 0 /* flags */);
|
||
|
EXPECT_EQ(status, xnn_status_success);
|
||
|
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
inline SubgraphTester& rewrite() {
|
||
|
xnn_subgraph_rewrite_for_nchw(subgraph_.get());
|
||
|
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
inline xnn_layout_type get_layout(uint32_t value_id) const {
|
||
|
return subgraph_->values[value_id].layout;
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
std::vector<std::vector<float>> static_data_;
|
||
|
std::unique_ptr<xnn_subgraph, decltype(&xnn_delete_subgraph)> subgraph_{nullptr, xnn_delete_subgraph};
|
||
|
std::mt19937 rng_;
|
||
|
};
|