Skip to content

Commit b55b350

Browse files
committed
Switch to CMSIS for optimized kernels, and add documentation
1 parent 0ed4302 commit b55b350

File tree

112 files changed

+37478
-828
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

112 files changed

+37478
-828
lines changed

CMakeLists.txt

Lines changed: 123 additions & 13 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
2+
# TensorFlow Lite Micro
3+
4+
An Open Source Machine Learning Framework for Everyone.
5+
6+
## Introduction
7+
8+
This is a version of the [TensorFlow Lite Micro library](https://www.tensorflow.org/lite/microcontrollers)
9+
for the Raspberry Pi Pico microcontroller. It allows you to run machine learning models to
10+
do things like voice recognition, detect people in images, recognize gestures from an accelerometer,
11+
and other sensor analysis tasks.
12+
13+
## Getting Started
14+
15+
First you'll need to follow the Pico setup instructions to initialize the development
16+
environment on your machine. Once that is done, make sure that the PICO_SDK_PATH
17+
environment variable has been set to the location of the Pico SDK, either in the shell
18+
you're building in, or the CMake configure environment variable setting of the extension
19+
if you're using VS Code.
20+
21+
You should then be able to build the library, tests, and examples. The easiest way to
22+
build is using VS Code's CMake integration, by loading the project and choosing the
23+
build option at the bottom of the window.
24+
25+
## What's Included
26+
27+
There are several example applications included. The simplest one to begin with is the
28+
hello_world project. This demonstrates the fundamentals of deploying an ML model on a
29+
device, driving the Pico's LED in a learned sine-wave pattern.
30+
31+
Other examples include simple speech recognition, a magic wand gesture recognizer,
32+
and spotting people in camera images, but because they require audio, accelerometer or
33+
image inputs you'll need to write some code to hook up your own sensors, since these
34+
are not included with the base microcontroller.
35+
36+
## Contributing
37+
38+
This repository (https://github.com/raspberrypi/pico-tflmicro) is read-only, because
39+
it has been automatically generated from the master TensorFlow repository at
40+
https://github.com/tensorflow/tensorflow. This means that all issues and pull requests
41+
need to be filed there. You can generate a version of this generated project by
42+
running the commands:
43+
44+
```
45+
git clone https://github.com/tensorflow/tensorflow
46+
cd tensorflow
47+
tensorflow/lite/micro/tools/project/generate.py rp2 pico-tflmicro
48+
```
49+
50+
This should create a Pico-compatible project from the latest version of the TensorFlow
51+
repository.
52+
53+
## Learning More
54+
55+
The [TensorFlow website](https://www.tensorflow.org/lite/microcontrollers) has
56+
information on training, tutorials, and other resources.
57+
58+
The [TinyML Book](https://tinymlbook.com) is a guide to using TensorFlow Lite Micro
59+
across a variety of different systems.
60+
61+
[TensorFlowLite Micro: Embedded Machine Learning on TinyML Systems](https://arxiv.org/pdf/2010.08678.pdf)
62+
has more details on the design and implementation of the framework.
63+
64+
## Licensing
65+
66+
The TensorFlow source code is covered by the license described in src/tensorflow/LICENSE,
67+
components from other libraries have the appropriate licenses included in their
68+
third_party folders.
69+
File renamed without changes.

src/tensorflow/lite/micro/benchmarks/keyword_scrambled_model_data.cpp

Lines changed: 2845 additions & 0 deletions
Large diffs are not rendered by default.

src/tensorflow/lite/micro/kernels/add.cpp renamed to src/tensorflow/lite/micro/kernels/cmsis-nn/add.cpp

Lines changed: 40 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ limitations under the License.
1515

1616
#include "tensorflow/lite/kernels/internal/reference/add.h"
1717

18+
#include "CMSIS/NN/Include/arm_nnfunctions.h"
1819
#include "tensorflow/lite/c/builtin_op_data.h"
19-
#include "tensorflow/lite/c/common.h"
2020
#include "tensorflow/lite/kernels/internal/quantization_util.h"
2121
#include "tensorflow/lite/kernels/internal/reference/integer_ops/add.h"
2222
#include "tensorflow/lite/kernels/internal/reference/process_broadcast_shapes.h"
@@ -54,10 +54,6 @@ struct OpData {
5454
int32_t input1_offset;
5555
int32_t input2_offset;
5656
int32_t output_offset;
57-
58-
// Used only for float evals:
59-
float output_activation_min_f32;
60-
float output_activation_max_f32;
6157
};
6258

6359
TfLiteStatus CalculateOpData(TfLiteContext* context, TfLiteAddParams* params,
@@ -95,10 +91,6 @@ TfLiteStatus CalculateOpData(TfLiteContext* context, TfLiteAddParams* params,
9591
TF_LITE_ENSURE_STATUS(CalculateActivationRangeQuantized(
9692
context, params->activation, output, &data->output_activation_min,
9793
&data->output_activation_max));
98-
} else if (output->type == kTfLiteFloat32) {
99-
CalculateActivationRange(params->activation,
100-
&data->output_activation_min_f32,
101-
&data->output_activation_max_f32);
10294
}
10395

10496
return kTfLiteOk;
@@ -107,25 +99,24 @@ TfLiteStatus CalculateOpData(TfLiteContext* context, TfLiteAddParams* params,
10799
void EvalAdd(TfLiteContext* context, TfLiteNode* node, TfLiteAddParams* params,
108100
const OpData* data, const TfLiteEvalTensor* input1,
109101
const TfLiteEvalTensor* input2, TfLiteEvalTensor* output) {
102+
float output_activation_min, output_activation_max;
103+
CalculateActivationRange(params->activation, &output_activation_min,
104+
&output_activation_max);
110105
tflite::ArithmeticParams op_params;
111-
SetActivationParams(data->output_activation_min_f32,
112-
data->output_activation_max_f32, &op_params);
106+
SetActivationParams(output_activation_min, output_activation_max, &op_params);
107+
#define TF_LITE_ADD(opname) \
108+
reference_ops::opname(op_params, tflite::micro::GetTensorShape(input1), \
109+
tflite::micro::GetTensorData<float>(input1), \
110+
tflite::micro::GetTensorShape(input2), \
111+
tflite::micro::GetTensorData<float>(input2), \
112+
tflite::micro::GetTensorShape(output), \
113+
tflite::micro::GetTensorData<float>(output))
113114
if (data->requires_broadcast) {
114-
reference_ops::BroadcastAdd4DSlow(
115-
op_params, tflite::micro::GetTensorShape(input1),
116-
tflite::micro::GetTensorData<float>(input1),
117-
tflite::micro::GetTensorShape(input2),
118-
tflite::micro::GetTensorData<float>(input2),
119-
tflite::micro::GetTensorShape(output),
120-
tflite::micro::GetTensorData<float>(output));
115+
TF_LITE_ADD(BroadcastAdd4DSlow);
121116
} else {
122-
reference_ops::Add(op_params, tflite::micro::GetTensorShape(input1),
123-
tflite::micro::GetTensorData<float>(input1),
124-
tflite::micro::GetTensorShape(input2),
125-
tflite::micro::GetTensorData<float>(input2),
126-
tflite::micro::GetTensorShape(output),
127-
tflite::micro::GetTensorData<float>(output));
117+
TF_LITE_ADD(Add);
128118
}
119+
#undef TF_LITE_ADD
129120
}
130121

131122
TfLiteStatus EvalAddQuantized(TfLiteContext* context, TfLiteNode* node,
@@ -150,42 +141,39 @@ TfLiteStatus EvalAddQuantized(TfLiteContext* context, TfLiteNode* node,
150141
bool need_broadcast = reference_ops::ProcessBroadcastShapes(
151142
tflite::micro::GetTensorShape(input1),
152143
tflite::micro::GetTensorShape(input2), &op_params);
144+
#define TF_LITE_ADD(type, opname, dtype) \
145+
type::opname(op_params, tflite::micro::GetTensorShape(input1), \
146+
tflite::micro::GetTensorData<dtype>(input1), \
147+
tflite::micro::GetTensorShape(input2), \
148+
tflite::micro::GetTensorData<dtype>(input2), \
149+
tflite::micro::GetTensorShape(output), \
150+
tflite::micro::GetTensorData<dtype>(output));
153151
if (output->type == kTfLiteInt8) {
154152
if (need_broadcast) {
155-
reference_integer_ops::BroadcastAdd4DSlow(
156-
op_params, tflite::micro::GetTensorShape(input1),
157-
tflite::micro::GetTensorData<int8_t>(input1),
158-
tflite::micro::GetTensorShape(input2),
159-
tflite::micro::GetTensorData<int8_t>(input2),
160-
tflite::micro::GetTensorShape(output),
161-
tflite::micro::GetTensorData<int8_t>(output));
153+
TF_LITE_ADD(reference_integer_ops, BroadcastAdd4DSlow, int8_t);
162154
} else {
163-
reference_integer_ops::Add(
164-
op_params, tflite::micro::GetTensorShape(input1),
155+
arm_elementwise_add_s8(
165156
tflite::micro::GetTensorData<int8_t>(input1),
166-
tflite::micro::GetTensorShape(input2),
167157
tflite::micro::GetTensorData<int8_t>(input2),
168-
tflite::micro::GetTensorShape(output),
169-
tflite::micro::GetTensorData<int8_t>(output));
158+
op_params.input1_offset, op_params.input1_multiplier,
159+
op_params.input1_shift, op_params.input2_offset,
160+
op_params.input2_multiplier, op_params.input2_shift,
161+
op_params.left_shift, tflite::micro::GetTensorData<int8_t>(output),
162+
op_params.output_offset, op_params.output_multiplier,
163+
op_params.output_shift, op_params.quantized_activation_min,
164+
op_params.quantized_activation_max,
165+
MatchingElementsSize(tflite::micro::GetTensorShape(input1),
166+
tflite::micro::GetTensorShape(input2),
167+
tflite::micro::GetTensorShape(output)));
170168
}
171169
} else {
172170
if (need_broadcast) {
173-
reference_ops::BroadcastAdd4DSlow(
174-
op_params, tflite::micro::GetTensorShape(input1),
175-
tflite::micro::GetTensorData<uint8_t>(input1),
176-
tflite::micro::GetTensorShape(input2),
177-
tflite::micro::GetTensorData<uint8_t>(input2),
178-
tflite::micro::GetTensorShape(output),
179-
tflite::micro::GetTensorData<uint8_t>(output));
171+
TF_LITE_ADD(reference_ops, BroadcastAdd4DSlow, uint8_t);
180172
} else {
181-
reference_ops::Add(op_params, tflite::micro::GetTensorShape(input1),
182-
tflite::micro::GetTensorData<uint8_t>(input1),
183-
tflite::micro::GetTensorShape(input2),
184-
tflite::micro::GetTensorData<uint8_t>(input2),
185-
tflite::micro::GetTensorShape(output),
186-
tflite::micro::GetTensorData<uint8_t>(output));
173+
TF_LITE_ADD(reference_ops, Add, uint8_t);
187174
}
188175
}
176+
#undef TF_LITE_ADD
189177
}
190178

191179
return kTfLiteOk;
@@ -201,11 +189,8 @@ TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) {
201189
TFLITE_DCHECK(node->builtin_data != nullptr);
202190

203191
const TfLiteTensor* input1 = GetInput(context, node, kInputTensor1);
204-
TF_LITE_ENSURE(context, input1 != nullptr);
205192
const TfLiteTensor* input2 = GetInput(context, node, kInputTensor2);
206-
TF_LITE_ENSURE(context, input2 != nullptr);
207193
TfLiteTensor* output = GetOutput(context, node, kOutputTensor);
208-
TF_LITE_ENSURE(context, output != nullptr);
209194

210195
OpData* data = static_cast<OpData*>(node->user_data);
211196
auto* params = reinterpret_cast<TfLiteAddParams*>(node->builtin_data);
@@ -219,16 +204,16 @@ TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) {
219204
TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) {
220205
auto* params = reinterpret_cast<TfLiteAddParams*>(node->builtin_data);
221206

222-
TFLITE_DCHECK(node->user_data != nullptr);
223-
const OpData* data = static_cast<const OpData*>(node->user_data);
224-
225207
const TfLiteEvalTensor* input1 =
226208
tflite::micro::GetEvalInput(context, node, kInputTensor1);
227209
const TfLiteEvalTensor* input2 =
228210
tflite::micro::GetEvalInput(context, node, kInputTensor2);
229211
TfLiteEvalTensor* output =
230212
tflite::micro::GetEvalOutput(context, node, kOutputTensor);
231213

214+
TFLITE_DCHECK(node->user_data != nullptr);
215+
const OpData* data = static_cast<const OpData*>(node->user_data);
216+
232217
if (output->type == kTfLiteFloat32) {
233218
EvalAdd(context, node, params, data, input1, input2, output);
234219
} else if (output->type == kTfLiteUInt8 || output->type == kTfLiteInt8) {

0 commit comments

Comments
 (0)