aboutsummaryrefslogtreecommitdiff
path: root/README.md
blob: 649246de745f7a92f3bef71f3724ccb67c158f6f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
# TOSA Reference Model

## Introduction

The *Tensor Operator Set Architecture (TOSA) Specification
<https://git.mlplatform.org/tosa/specification.git/>* is a set of operators
with defined accuracy and compatibility constraints that Arm expects
to be implemented on its Neural Processing Units (NPUs).  Most
operators from the common ML frameworks (TensorFlow, PyTorch, etc)
should be expressible in TOSA.  TOSA is focused on inference, leaving
training to the original frameworks.

The *TOSA Reference Model* package provides a reference implementation
and testing infrastructure for TOSA.  The reference model consumes a
FlatBuffers serialization of the network subgraph generated by the
TOSA Serialization Library, along with input tensors for placeholder
nodes in NumPy format.  By default, the model validates and evalutes
the network subgraph, and writes out the resulting output tensors in
NumPy format.

## Installation Requirements

The *TOSA Reference Model* and testing suite requires the following
tools:

* CMake version 3.4 or later
* GNU Make 4.1 or later
* GCC (tested with 7.5.0) or Clang C++ compiler (tested with clang-9)
  with C++17 support

The model includes the following git submodules:

* TOSA Serialization Library
* JSON for Modern C++ - 3.8.0
* Eigen 3.3.7
* doctest 2.4.9 (When building unit tests)

The model is written using
C++17 and has been primarily tested on Ubuntu x86_64 18.04 LTS Linux
systems.

The testing infrastructure requires:

* Python 3.6 or later
* FlatBuffers 2.0 or later
* NumPy 1.15 or later

Check out the required git submodules with:

``` bash
git submodule update --init --recursive
```

### Versioning

The *TOSA Reference Model* repository has branches (major.minor) and tags
(major.minor.patch) that correspond to each TOSA version. The `main` branch is
used as the active development branch for the next version.

Perform a check-out of a specific version before compilation or installation of
the test infrastructure by using:

```bash
git checkout --recurse-submodules VERSION
```

Where `VERSION` can be for example: `v0.23` or `v0.23.0`


## Compilation

The *TOSA Reference Model* build can be prepared by creating makefiles using CMake:

``` bash
mkdir -p build
cd build
cmake ..
```

Optionally, `-DCMAKE_BUILD_TYPE=Debug` can be used on the `cmake`
command to create a debug build.  Next compile using `make`:

``` bash
make
```

The resulting executable will be named:
`reference_model/tosa_reference_model`. This executable can be disabled with
`-DBUILD_TOSA_REFERENCE_MODEL_EXECUTABLE=NO`.
A static library will also be generated by default as follows:
`reference_model/libtosa_reference_model_lib.a`.
To make this a shared library (.so) add the following option
`-DBUILD_SHARED_LIBS=YES`.

CMake only needs to be re-run if the build environment changes (e.g., new dependencies or source
files). Code changes that do not affect these build rules can be
rebuilt simply using `make`.

## Executable Usage

The inputs to the *TOSA Reference Model* consist of a FlatBuffers file
containing the serialized subgraph, a JSON test descriptor that describes
a sequence of name, shape and numpy file for each input and output tensor.

The JSON test descriptor must have the following field:
* tosa_file:
    type: string.
    TOSA flatbuffer file location.
* ifm_name:
    type: list(string).
    Input placeholder tensor names.
* ifm_file:
    type: list(string).
    Input numpy array file location.
* ofm_name:
    type: list(string).
    Output placeholder tensor names.
* ofm_file:
    type: list(string).
    Output numpy array file location.
* expected_failure:
    type: boolean.
    Is this test expected to fail in runtime.
* expected_return_code:
    type: int
    The expected return code of the reference model i
    (0 = VALID, 1 = ERROR, 2 = UNPREDICTABLE)

Note by default, all the files specified by "tosa_file", "ifm_file",
"ofm_file" are relative to desc.json. This could be overwritten by
--flatbuffer_dir=, if desired.

An example command is shown below:

``` bash
./build/reference_model/tosa_reference_model \
  --test_desc=examples/test_add_1x4x4x4_f32/flatbuffer-tflite/desc.json
```

Instead of drive model by JSON test descriptor, user can also drive model
with --tosa_file=, --ifm_name=, --ifm_file=, --ofm_name=, --ofm_file=
options directly.

In case where --test_desc= and other options are specified at the same time,
JSON test descriptor will be initialized first. All other options
(--tosa_file=, --ifm_name=, --ifm_file=, --ofm_name=, --ofm_file=) will
overwrite whatever specified by JSON descriptor.

On a successful execution, the output tensors will be written in NumPy
format into output tensors specified by "ofm_file".

For example, you can generate new output .npy by:
``` bash
./build/reference_model/tosa_reference_model \
  --test_desc=examples/test_add_1x4x4x4_f32/flatbuffer-tflite/desc.json \
  --ofm_file=out.npy
```

In this case, the "ofm_file" field in desc.json will be ignored, and the
one specified by --ofm_file= will be picked.

When using JSON-formatted FlatBuffers input (.json extension), the
FlatBuffers schema file from the TOSA Serialization library must be
specified using --operator_fbs=.  When using the binary FlatBuffers
format (.tosa), the schema is not necessary.

### Examples

The TOSA Reference Model distribution contains several example
networks with inputs and reference outputs generated by
TensorFlow or TensorFlow Lite in the examples directory.

These examples can be run through the TOSA Reference model and should
produce the equivalent TOSA-compliant reference output tensors.
Please note that differences in floating-point ordering and rounding
may cause small differences in output for floating-point tests and
differences in quantized scaling between TensorFlow Lite and the TOSA
Specification may cause differences in quantized integer tests.

## ModelRunner API

As an alternative to the executable described above,
the model_runner.h is provided which can be used to invoke the
TOSA Reference Model easily within C++.
A sample of this class and how it can used can be found in
[model_runner_simple_sample.cpp](reference_model/samples/model_runner_simple_sample.cpp).
This sample can be compiled by adding `-DBUILD_MODEL_RUNNER_SAMPLE=YES` to the CMake command
and executed by running `./build/reference_model/model_runner_sample`.

### ModelRunner API Unit Tests
Unit test are generated by default for the ModelRunner.
This executable can be disabled by adding`-DBUILD_TOSA_REFERENCE_MODEL_TESTS=NO` to the CMake command.
This executable can be run using
`./build/reference_model/unit_tests` and requires the submodule doctest.

## Debugging

The debugging facility can be enabled by setting a debug scope and
debug level on the command line.  For most purposes, the following
flags will work: `-dALL -lHIGH`.  Debug output can be directed to a
file using the `-o` switch.

## TOSA Unit Test Infrastructure

The TOSA Unit Test infrastructure builds and runs self-contained tests
for implementations of the *Tensor Operator Set Architecture (TOSA)
Specification*.  These tools directly generate TOSA operators for
verification of the TOSA reference model against existing frameworks
or other operator implementations.

The test builder tool by default generates positive tests with random
arguments and reference inputs for each TOSA operator.  Positive tests
are expected to run without error and usually produce a result (some
control flow operators may not produce a result).
The test builder can also generate negative tests for all the ERROR_IF
conditions within the TOSA Specification by using the `--test-type`
options. Negative tests may contain invalid arguments or inputs and
are expected to run and fail without producing a result. Other errors
or unpredictable results are handled in a system dependent way and
are not tested by the test builder tool.

The unit tests are typically structured as a combination of input
placeholder nodes, const nodes, and attributes feeding into a single
TOSA operator.  The unit tests use a Python copy of the FlatBuffers
schema written by `flatc` to verify tosa.

Each test has a JSON file which provides machine-readable metadata for
the test, including the TOSA flatbuffer file, names, shapes, and
NumPy filenames for each input and output tensor.  There is also a
boolean value for whether a failure is expected because the test is
expected to trigger an invalid set of operands or attributes.

The test runner tool can execute the unit tests on the TOSA Reference
Model to generate reference output tensor values (for positive tests).
The test runner is a modular tool which can be extended to run the same
tests on additional tools or frameworks - such a tool or framework is
called a System Under Test (SUT).
The reference output NumPy files generated by this step can be
programatically compared with output of SUTs to validate them.

### Installation

The test infrastructure needs installing before being used. It is recommended
to create a [python virtual environment](https://docs.python.org/3/library/venv.html)
and then install the TOSA Unit Test infrastructure from the root of the
reference model:

``` bash
pip install .
```

When installing without a python virtual environment, use the pip
option `--user` to install it for the current user only.


### Unit Test Builder
The test builder is invoked by `tosa_verif_build_tests`.  The
builder generates test outputs in `./vtest/<operator_name>/` by
default.  To restrict test generation to particular regular expression
wildcard, use the `--filter ` argument.  The tool can be run with no
arguments to generate all tests.

Inputs and certain attributes are created using a random number
generator, while others are exhaustive (within reasonable bounds)
where the combinatorics allow exhaustive tests.  The test generation
is deterministic for a given random seed, but additional tests can be
generated using `--seed`.  As many corner-case error are often
uncovered using creative tensor shapes, the random seed parameter will
help get coverage of additional shapes.

By default only the positive tests will be produced, use the
argument `--test-type both` to build positive and negative tests.

Additional parameters on some operators can be found in the command
line help.

### Unit Test Runner

The unit test running script takes self-contained unit tests from the
builder and runs them on the reference model or on a System Under
Test.

#### Selecting tests

The `--test` or `-t` option is used to specify a directory containing
a test. Shell wildcards can be used to run more than one test at a time.
Tests will be run sequentially by default, but you may control how
many tests are run in parallel using the `--jobs` or `-j` switch.

For example, to run all of the TOSA add operator tests on the reference
model, eight at a time:

``` bash
tosa_verif_run_tests -t vtest/add/add* -j 8
```

The default location that is used for the reference model is
`reference_model/build/reference_model/tosa_reference_model`, use the option
`--ref-model-path` if you run this from a different location.

You can also supply a list of tests in a file, one per line, using the
`--test-list` or `-T` option.

Finally you can choose the type of test to run - positive, negative or both
(default) -using the `test-type` option. To only run the positive tests:

```bash
tosa_verif_run_tests --test-type positive -t vtest/*/*
```

#### Verbosity

The test runner is reasonably quiet by default, so running a large number of
tests without any obvious errors will show only 1 line of output per test
completion. The `-v` switch will show the commands being run in the
background.

#### Debugging

To enable debugging on the reference model, shortcut commands have
been provided: `--ref-debug=high` and `--ref-intermediates` to
turn on debugging and dump intermediate tensor values.

### Systems Under Test

Additional Systems Under Test (SUTs), such as reference
implementations of operators, full frameworks, and hardware implementations
can be tested by the test runner.

To do this you need to define an SUT module by extending the
`TosaTestRunner` class found in `verif/runner/tosa_test_runner.py`, and
then supplying this to the TOSA Test Runner.

#### SUT inputs and outputs

With each test is a `desc.json` file that contains input and output filename
information which is read and supplied to the `TosaTestRunner` class.

A TOSA System Under Test will need to be able to read the following input files:

* TOSA FlatBuffers (either JSON or binary format) - use the TOSA
  Serialization Library (<https://git.mlplatform.org/tosa/serialization_lib.git>)
  to do this.
* Tensors from python numpy array files - see the
  [numpy documentation](https://numpy.org/doc/stable/reference/generated/numpy.load.html)
  for more information. Use the TOSA Serialization Library to help
  (see the link above).

Utilize the `TosaTestRunner` class to convert these test artifacts
into another format before giving them to your SUT.

For positive tests usually at least one results file should be produced by
your SUT containing the resulting tensor in numpy format. The expected
filenames are supplied in the `desc.json` information.

#### TosaTestRunner class

Your python class extending the `TosaTestRunner` class must contain:

* `__init__(self,...)` function that calls the super() class function.
* `runTestGraph(self)` function that invokes your SUT and then translates the
    return code into a `TosaTestRunner.TosaGraphResult`. It returns this result
    and an optional error message.

Examples of implementations can be found:

* `verif/runner/tosa_refmodel_sut_run.py` - the reference model
* `verif/tests/tosa_mock_sut_run.py` - mock version for testing

There is a helper function `run_sh_command` in `verif/runner/run_command.py`
that provides a robust way of calling shell commands from python that can be used
to invoke your SUT.

#### Testing with the Unit Test Runner

The SUT can then be supplied to the test runner by using the `--sut-module`
flag, the following invokes the reference model as the SUT (default behaviour
when not supplied):

```bash
tosa_verif_run_tests --sut-module runner.tosa_refmodel_sut_run -t TEST
```

You can also pass arguments to your SUT, for example this
will pass an argument called `ARGUMENT` with a value of `VALUE`
to the `mysut.tosa_mysut_sut_run` module:

```bash
tosa_run_tests --sut-module mysut.tosa_mysut_sut_run \
    --sut-module-args mysut.tosa_mysut_sut_run:ARGUMENT=VALUE \
    -t TEST
```

You can repeat this switch multiple times to pass multiple different arguments.

For an example of how to read these arguments in your SUT module, please see the
`tosa_mock_sut_run.py` file.


### TOSA Framework Unit Tests

Included in the TOSA Unit Test infrastructure are scripts to enable the creation
of TOSA unit tests for example frameworks. Included at the moment is support for
TensorFlow and TensorFlow Lite.

#### Setup

Installation (via `pip install`) of the following python package is required to
generate the tests:

* `tensorflow`

A built copy of the tensorflow framework from source is required to compile the
tests to TOSA - see the online documentation <https://www.tensorflow.org/install/source>
on how to do this.
The following tools are used from this build:

* `tensorflow/basel-bin/tensorflow/compiler/mlir/lite/flatbuffer_translate`
* `tensorflow/basel-bin/tensorflow/compiler/mlir/tf-opt`

#### Usage

The command to generate the unit test framework models:

```bash
tosa_verif_framework_generator -o tests
```

Next to convert these models to TOSA and then run them on the reference model:

```bash
tosa_verif_framework_compiler_runner \
  --tf-base-dir tensorflow           \
  --tools-base-dir reference_model   \
  --recursive                        \
  --test tests
```

### TOSA Conformance Generator

This script enables creation of part or all of the *TOSA conformance tests
<https://git.mlplatform.org/tosa/conformance_tests.git/>*, to
enable development of these tests.

Currently only the Base Profile of TOSA is supported by the generator.

#### Setup

To enable selection of the framework tests for conformance, the TOSA Framework
Unit Tests (see above) must have been pre-generated and there is access to the
framework schema from TensorFlow Lite.

#### Usage

These are the main script options for controlling the types of tests produced:

* `--profile` - controls the TOSA profile, only `base` is currently supported.
* `--unit-tests` - choose either `operator`, `framework` or `both` tests.
* `--test-type` - selects `postive`, `negative` or `both` types of test.


An example to create the TOSA operator unit tests for ADD and SUB:

```bash
tosa_verif_conformance_generator        \
  --profile base                        \
  --unit-tests operator                 \
  --ref-model-directory reference_model \
  --operator add sub
```

The above command will create some temporary files in a `conformance_build`
directory, but will output the conformance unit tests into a `conformance`
directory.

This next example will create all the conformance tests, using different
temporary build and output directories:

```bash
tosa_verif_conformance_generator        \
  --profile base                        \
  --unit-tests both                     \
  --ref-model-directory reference_model \
  --build-directory tmp_build           \
  --output-directory conf_tests         \
  --framework-tests-directory tests     \
  --framework-schema tensorflow/lite/schema/schema.fbs
```

## Other tools

Included in this repository are some support utilities used by the test runner:

* `json2numpy` - converts from JSON format to numpy array or the reverse operation.
* `json2fbbin` - converts from JSON flatbuffer format to flatbuffer
    binary format or the reverse operation. This is dependent on the FlatBuffers
    command `flatc` - see the section on the FlatBuffers compiler below.
* `tosa_verif_result_check` - compares two results files.
* `convert2conformance` - converts a unit test into a conformance suitable test.

Please see the respective `--help` of each utility for more information on using
them standalone.

### FlatBuffers compiler

The FlatBuffers compiler tool (`flatc`) is only needed if you want to use
json2fbbin to convert the TOSA flatbuffer binary test files (.tosa) to JSON
or from JSON to binary.
It is best to use the flatbuffer version that comes with the reference model.
After following the reference model compilation instructions, you can build
the FlatBuffers tool using:

``` bash
# After compiling the reference model (in the build directory)
cd thirdparty/serialization_lib/third_party/flatbuffers
make
```


## License

The *TOSA Reference Model* and TOSA Unit Tests are licensed under Apache-2.0.

Copyright (c) 2020-2022 Arm Limited.