ArmNN
 22.05.01
Fp32NetworkToBf16ConverterTests.cpp
Go to the documentation of this file.
1 //
2 // Copyright © 2020 Arm Ltd. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 
6 #include <TestUtils.hpp>
7 
8 #include <Optimizer.hpp>
9 
10 #include <doctest/doctest.h>
11 
12 TEST_SUITE("Optimizer")
13 {
14 using namespace armnn::optimizations;
15 
16 TEST_CASE("Fp32NetworkToBf16OptimizationNoConversionTest")
17 {
18  armnn::Graph graph;
19 
20  const armnn::TensorInfo infoFP32({ 2, 2, 1, 3 }, armnn::DataType::Float32);
21 
22  // Create the simple test network without Conv2D/FullyConnected.
23  auto input = graph.AddLayer<armnn::InputLayer>(0, "input");
24  input->GetOutputSlot().SetTensorInfo(infoFP32);
25 
26  auto floor = graph.AddLayer<armnn::FloorLayer>("floor");
27  floor->GetOutputSlot().SetTensorInfo(infoFP32);
28 
29  auto output = graph.AddLayer<armnn::OutputLayer>(1, "output");
30 
31  // Connect up the layers
32  input->GetOutputSlot().Connect(floor->GetInputSlot(0));
33  floor->GetOutputSlot().Connect(output->GetInputSlot(0));
34 
35  CHECK(CheckSequence(graph.cbegin(), graph.cend(), &IsLayerOfType<armnn::InputLayer>,
36  &IsLayerOfType<armnn::FloorLayer>, &IsLayerOfType<armnn::OutputLayer>));
37 
38  // Run the optimizer
40 
41  CHECK(CheckSequence(graph.cbegin(), graph.cend(), &IsLayerOfType<armnn::InputLayer>,
42  &IsLayerOfType<armnn::FloorLayer>,
43  &IsLayerOfType<armnn::OutputLayer>));
44 }
45 
46 TEST_CASE("Fp32NetworkToBf16OptimizationConv2DTest")
47 {
48  armnn::Graph graph;
49 
50  const armnn::TensorInfo infoFP32({ 2, 3, 8, 1 }, armnn::DataType::Float32);
51 
52  // Create const tensor fp32 data
53  unsigned int dims[] = { 4, 2, 1, 1 };
54  std::vector<float> floatWeights{ 0.0f, -1.0f,
55  3.8f, // 0x40733333 Round down
56  3.1055E+29f, // 0x707ADC3C Round up
57  9.149516E-10f, // 0x307B7FFF Round down
58  -3.8f, // 0xC0733333 Round down
59  -3.1055E+29f, // 0xF07ADC3C Round up
60  -9.149516E-10f // 0xB07B7FFF Round down
61  };
62  armnn::ConstTensor weights(armnn::TensorInfo(4, dims, armnn::DataType::Float32, 0.0f, 0, true), floatWeights);
63 
64  // Create const bias fp32 data
65  unsigned int biasDims[] {4};
66  std::vector<float> floatBias{ 1.0f, 2.0f, 3.0f, 4.0f };
67  armnn::ConstTensor bias(armnn::TensorInfo(1, biasDims, armnn::DataType::Float32, 0.0f, 0, true), floatBias);
68 
69  // A network with Convolution2d layer
70  auto input = graph.AddLayer<armnn::InputLayer>(0, "input");
71  input->GetOutputSlot().SetTensorInfo(infoFP32);
72 
74 
75  auto conv = graph.AddLayer<armnn::Convolution2dLayer>(descriptor, "conv2d");
76  conv->m_Weight = std::make_unique<armnn::ScopedTensorHandle>(weights);
77  conv->m_Bias = std::make_unique<armnn::ScopedTensorHandle>(bias);
78  conv->GetOutputSlot().SetTensorInfo(infoFP32);
79 
80  auto output = graph.AddLayer<armnn::OutputLayer>(1, "output");
81 
82  // Connect up the layers
83  input->GetOutputSlot().Connect(conv->GetInputSlot(0));
84  conv->GetOutputSlot().Connect(output->GetInputSlot(0));
85 
86  CHECK(CheckSequence(graph.cbegin(), graph.cend(), &IsLayerOfType<armnn::InputLayer>,
87  &IsLayerOfType<armnn::Convolution2dLayer>, &IsLayerOfType<armnn::OutputLayer>));
88 
89  // Run the optimizer
91 
92  CHECK(CheckSequence(graph.cbegin(), graph.cend(), &IsLayerOfType<armnn::InputLayer>,
93  &IsLayerOfType<armnn::ConvertFp32ToBf16Layer>, &IsLayerOfType<armnn::Convolution2dLayer>,
94  &IsLayerOfType<armnn::OutputLayer>));
95 
96  armnn::TensorInfo inputTensor = conv->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo();
97  armnn::TensorInfo outputTensor = conv->GetOutputSlot(0).GetTensorInfo();
98  CHECK((conv->GetDataType() == armnn::DataType::BFloat16));
99  CHECK((conv->m_Weight->GetTensorInfo().GetDataType() == armnn::DataType::BFloat16));
100  CHECK((conv->m_Bias->GetTensorInfo().GetDataType() == armnn::DataType::Float32));
101  CHECK((inputTensor.GetDataType() == armnn::DataType::BFloat16));
102  CHECK((outputTensor.GetDataType() == armnn::DataType::Float32));
103 
104  // Check whether data matches expected Bf16 data
105  const armnn::BFloat16* data = conv->m_Weight->GetConstTensor<armnn::BFloat16>();
106  CHECK(data[0] == armnn::BFloat16(0.0f));
107  CHECK(data[1] == armnn::BFloat16(-1.0f));
108  CHECK(data[2] == armnn::BFloat16(3.796875f)); // 0x4073
109  CHECK(data[3] == armnn::BFloat16(3.1072295E29f)); // 0x707B
110  CHECK(data[4] == armnn::BFloat16(9.131327E-10f)); // 0x307B
111  CHECK(data[5] == armnn::BFloat16(-3.796875f)); // 0xC073
112  CHECK(data[6] == armnn::BFloat16(-3.1072295E29f)); // 0xF07B
113  CHECK(data[7] == armnn::BFloat16(-9.131327E-10f)); // 0xB07B
114 }
115 
116 TEST_CASE("Fp32NetworkToBf16OptimizationFullyConnectedTest")
117 {
118  armnn::Graph graph;
119 
120  const armnn::TensorInfo infoFP32({ 2, 3, 8, 1 }, armnn::DataType::Float32);
121 
122  // Create const tensor fp32 data
123  unsigned int dims[] = { 4, 2, 1, 1 };
124  std::vector<float> floatWeights{ 0.0f, -1.0f,
125  3.8f, // 0x40733333 Round down
126  3.1055E+29f, // 0x707ADC3C Round up
127  9.149516E-10f, // 0x307B7FFF Round down
128  -3.8f, // 0xC0733333 Round down
129  -3.1055E+29f, // 0xF07ADC3C Round up
130  -9.149516E-10f // 0xB07B7FFF Round down
131  };
132  armnn::ConstTensor weights(armnn::TensorInfo(4, dims, armnn::DataType::Float32, 0.0f, 0, true), floatWeights);
133 
134  // Create const bias fp32 data
135  unsigned int biasDims[] {4};
136  std::vector<float> floatBias{ 1.0f, 2.0f, 3.0f, 4.0f };
137  armnn::ConstTensor bias(armnn::TensorInfo(1, biasDims, armnn::DataType::Float32, 0.0f, 0, true), floatBias);
138 
139  // A network with FullyConnected layer
140  auto input = graph.AddLayer<armnn::InputLayer>(0, "input");
141  input->GetOutputSlot().SetTensorInfo(infoFP32);
142 
144 
145  auto fc = graph.AddLayer<armnn::FullyConnectedLayer>(descriptor, "fully");
146  fc->m_Weight = std::make_unique<armnn::ScopedTensorHandle>(weights);
147  fc->m_Bias = std::make_unique<armnn::ScopedTensorHandle>(bias);
148  fc->GetOutputSlot().SetTensorInfo(infoFP32);
149 
150  auto output = graph.AddLayer<armnn::OutputLayer>(1, "output");
151 
152  // Connect up the layers
153  input->GetOutputSlot().Connect(fc->GetInputSlot(0));
154  fc->GetOutputSlot().Connect(output->GetInputSlot(0));
155 
156  CHECK(CheckSequence(graph.cbegin(), graph.cend(), &IsLayerOfType<armnn::InputLayer>,
157  &IsLayerOfType<armnn::FullyConnectedLayer>, &IsLayerOfType<armnn::OutputLayer>));
158 
159  // Run the optimizer
161 
162  CHECK(CheckSequence(graph.cbegin(), graph.cend(), &IsLayerOfType<armnn::InputLayer>,
163  &IsLayerOfType<armnn::ConvertFp32ToBf16Layer>, &IsLayerOfType<armnn::FullyConnectedLayer>,
164  &IsLayerOfType<armnn::OutputLayer>));
165 
166  armnn::TensorInfo inputTensor = fc->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo();
167  armnn::TensorInfo outputTensor = fc->GetOutputSlot(0).GetTensorInfo();
168  CHECK((fc->GetDataType() == armnn::DataType::BFloat16));
169  CHECK((fc->m_Weight->GetTensorInfo().GetDataType() == armnn::DataType::BFloat16));
170  CHECK((fc->m_Bias->GetTensorInfo().GetDataType() == armnn::DataType::Float32));
171  CHECK((inputTensor.GetDataType() == armnn::DataType::BFloat16));
172  CHECK((outputTensor.GetDataType() == armnn::DataType::Float32));
173 
174  // Check whether data matches expected Bf16 data
175  const armnn::BFloat16* data = fc->m_Weight->GetConstTensor<armnn::BFloat16>();
176  CHECK(data[0] == armnn::BFloat16(0.0f));
177  CHECK(data[1] == armnn::BFloat16(-1.0f));
178  CHECK(data[2] == armnn::BFloat16(3.796875f)); // 0x4073
179  CHECK(data[3] == armnn::BFloat16(3.1072295E29f)); // 0x707B
180  CHECK(data[4] == armnn::BFloat16(9.131327E-10f)); // 0x307B
181  CHECK(data[5] == armnn::BFloat16(-3.796875f)); // 0xC073
182  CHECK(data[6] == armnn::BFloat16(-3.1072295E29f)); // 0xF07B
183  CHECK(data[7] == armnn::BFloat16(-9.131327E-10f)); // 0xB07B
184 }
185 
186 
187 }
Optimizer::Optimizations MakeOptimizations(Args &&... args)
Definition: Optimizer.hpp:43
bool CheckSequence(const armnn::Graph::ConstIterator first, const armnn::Graph::ConstIterator last)
Definition: TestUtils.hpp:21
LayerT * AddLayer(Args &&... args)
Adds a new layer, of type LayerType, to the graph constructed with the arguments passed.
Definition: Graph.hpp:425
ConstIterator cbegin() const
Returns const iterator pointing to the beginning of the list. Lowercase for range-based for loops...
Definition: Graph.hpp:179
A Convolution2dDescriptor for the Convolution2dLayer.
int Connect(InputSlot &destination)
Definition: Layer.cpp:112
static void Pass(Graph &graph, const Optimizations &optimizations)
Definition: Optimizer.cpp:16
std::shared_ptr< ConstTensorHandle > m_Weight
A unique pointer to store Weight values.
TEST_SUITE("Optimizer")
A layer user-provided data can be bound to (e.g. inputs, outputs).
Definition: OutputLayer.hpp:13
This layer represents a fully connected operation.
std::shared_ptr< ConstTensorHandle > m_Weight
A unique pointer to store Weight values.
DataType GetDataType() const
Definition: Tensor.hpp:198
A FullyConnectedDescriptor for the FullyConnectedLayer.
A tensor defined by a TensorInfo (shape and data type) and an immutable backing store.
Definition: Tensor.hpp:327
This layer represents a floor operation.
Definition: FloorLayer.hpp:13
A layer user-provided data can be bound to (e.g. inputs, outputs).
Definition: InputLayer.hpp:13
void SetTensorInfo(const TensorInfo &tensorInfo) override
Definition: Layer.cpp:87
const OutputSlot & GetOutputSlot(unsigned int index=0) const override
Get the const output slot handle by slot index.
Definition: Layer.hpp:324
ConstIterator cend() const
Returns const iterator pointing to the end of the list. Lowercase for range-based for loops...
Definition: Graph.hpp:181
This layer represents a convolution 2d operation.
OptimizeForType< Layer, ConvertFp32NetworkToBf16Impl > Fp32NetworkToBf16Converter