Skip to content

Commit 4304801

Browse files
craiglabenzPiinks
andauthored
Text Embedding task (#21)
* updated and re-ran generators * added embedding concepts to mediapipe-core * fixed embedding header file and bindings * adds text embedding classes to text pkg * updates example with text embedding * removed dead file * added more embedding tests * added embedding model download to CI script * touch ups * Update packages/mediapipe-core/lib/src/io/containers.dart Co-authored-by: Kate Lovett <[email protected]> * Update packages/mediapipe-task-text/example/.gitignore Co-authored-by: Kate Lovett <[email protected]> * Update packages/mediapipe-task-text/example/lib/text_embedding_demo.dart Co-authored-by: Kate Lovett <[email protected]> * moved worker dispose method to base class * docstring & comment improvements * throw exceptions in impossible code paths instead of returning null * class hierarchy improvements * fixed outdates tests * cleaned up dispose methods * various tidying * fixed deprecation warning * moves repeated widgets into helper method --------- Co-authored-by: Kate Lovett <[email protected]>
1 parent 4c159a7 commit 4304801

File tree

56 files changed

+2368
-189
lines changed

Some content is hidden

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

56 files changed

+2368
-189
lines changed

Makefile

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22
headers:
33
cd tool/builder && dart bin/main.dart headers
44

5+
# Downloads all necessary task models
6+
models:
7+
cd tool/builder && dart bin/main.dart model -m textclassification
8+
cd tool/builder && dart bin/main.dart model -m textembedding
9+
10+
511
# Runs `ffigen` for all packages
612
generate: generate_core generate_text
713

packages/mediapipe-core/lib/generated/core_symbols.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@ files:
1616
name: Classifications
1717
c:@S@ClassifierOptions:
1818
name: ClassifierOptions
19+
c:@S@EmbedderOptions:
20+
name: EmbedderOptions
21+
c:@S@Embedding:
22+
name: Embedding
23+
c:@S@EmbeddingResult:
24+
name: EmbeddingResult
1925
c:@S@__darwin_pthread_handler_rec:
2026
name: __darwin_pthread_handler_rec
2127
c:@S@_opaque_pthread_attr_t:

packages/mediapipe-core/lib/io.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5+
export 'src/interface/containers.dart' show EmbeddingType;
56
export 'src/io/mediapipe_core.dart';

packages/mediapipe-core/lib/mediapipe_core.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
library mediapipe_core;
88

99
export 'src/extensions.dart';
10+
export 'src/interface/containers.dart' show EmbeddingType;
1011
export 'universal_mediapipe_core.dart'
1112
if (dart.library.html) 'src/web/mediapipe_core.dart'
1213
if (dart.library.io) 'src/io/mediapipe_core.dart';

packages/mediapipe-core/lib/src/interface/containers.dart

Lines changed: 75 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,16 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5+
import 'dart:typed_data';
6+
57
import 'package:equatable/equatable.dart';
68

79
/// {@template Category}
810
/// Dart representation of MediaPipe's "Category" concept.
911
///
1012
/// Category is a util class that contains a [categoryName], its [displayName],
1113
/// a float value as [score], and the [index] of the label in the corresponding
12-
/// label file. It is Typically used as result of classification or detection
14+
/// label file. It is typically used as result of classification or detection
1315
/// tasks.
1416
///
1517
/// See more:
@@ -45,7 +47,7 @@ abstract class BaseCategory extends Equatable {
4547
/// See also:
4648
/// * [MediaPipe's Classifications documentation](https://developers.google.com/mediapipe/api/solutions/java/com/google/mediapipe/tasks/components/containers/Classifications)
4749
/// {@endtemplate}
48-
abstract base class BaseClassifications extends Equatable {
50+
abstract class BaseClassifications extends Equatable {
4951
/// A list of [Category] objects which contain the actual classification
5052
/// information, including human-readable labels and probability scores.
5153
Iterable<BaseCategory> get categories;
@@ -71,3 +73,74 @@ abstract base class BaseClassifications extends Equatable {
7173
@override
7274
List<Object?> get props => [categories, headIndex, headName];
7375
}
76+
77+
/// Marker for which flavor of analysis was performed for a specific
78+
/// [Embedding] instance.
79+
enum EmbeddingType {
80+
/// Indicates an [Embedding] object has a non-null value for
81+
/// [Embedding.floatEmbedding].
82+
float,
83+
84+
/// Indicates an [Embedding] object has a non-null value for
85+
/// [Embedding.quantizedEmbedding].
86+
quantized;
87+
88+
/// Returns the opposite type.
89+
EmbeddingType get opposite => switch (this) {
90+
EmbeddingType.float => EmbeddingType.quantized,
91+
EmbeddingType.quantized => EmbeddingType.float,
92+
};
93+
}
94+
95+
/// {@template Embedding}
96+
/// Represents the embedding for a given embedder head. Typically used in
97+
/// embedding tasks.
98+
///
99+
/// One and only one of 'floatEmbedding' and 'quantizedEmbedding' will contain
100+
/// data, based on whether or not the embedder was configured to perform scala
101+
/// quantization.
102+
/// {@endtemplate}
103+
abstract class BaseEmbedding extends Equatable {
104+
/// Length of this embedding.
105+
int get length;
106+
107+
/// The index of the embedder head to which these entries refer.
108+
int get headIndex;
109+
110+
/// The optional name of the embedder head, which is the corresponding tensor
111+
/// metadata name.
112+
String? get headName;
113+
114+
/// Floating-point embedding. [null] if the embedder was configured to perform
115+
/// scalar-quantization.
116+
Float32List? get floatEmbedding;
117+
118+
/// Scalar-quantized embedding. [null] if the embedder was not configured to
119+
/// perform scalar quantization.
120+
Uint8List? get quantizedEmbedding;
121+
122+
/// [True] if this embedding came from an embedder configured to perform
123+
/// scalar quantization.
124+
bool get isQuantized => type == EmbeddingType.quantized;
125+
126+
/// [True] if this embedding came from an embedder that was not configured to
127+
/// perform scalar quantization.
128+
bool get isFloat => type == EmbeddingType.float;
129+
130+
/// Indicator for the type of results in this embedding.
131+
EmbeddingType get type;
132+
133+
@override
134+
String toString() {
135+
return 'Embedding(quantizedEmbedding=$quantizedEmbedding, floatEmbedding='
136+
'$floatEmbedding, headIndex=$headIndex, headName=$headName)';
137+
}
138+
139+
@override
140+
List<Object?> get props => [
141+
quantizedEmbedding,
142+
floatEmbedding,
143+
headIndex,
144+
headName,
145+
];
146+
}

packages/mediapipe-core/lib/src/interface/task_options.dart

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,13 @@ import 'package:equatable/equatable.dart';
1313
/// including a descendent of the universal options struct, [BaseBaseOptions].
1414
/// The second field will be task-specific.
1515
/// {@endtemplate}
16+
///
17+
/// This implementation is not immutable to track whether `dispose` has been
18+
/// called. All values used by pkg:equatable are in fact immutable.
19+
// ignore: must_be_immutable
1620
abstract class BaseTaskOptions extends Equatable {
1721
/// {@macro TaskOptions}
18-
const BaseTaskOptions();
22+
BaseTaskOptions();
1923

2024
/// {@template TaskOptions.baseOptions}
2125
/// Options class shared by all MediaPipe tasks - namely, how to find and load
@@ -125,3 +129,39 @@ abstract class BaseClassifierOptions extends BaseInnerTaskOptions {
125129
...(categoryDenylist ?? []),
126130
];
127131
}
132+
133+
/// {@template EmbedderOptions}
134+
/// Dart representation of MediaPipe's "EmbedderOptions" concept.
135+
///
136+
/// Embedder options shared across MediaPipe embedding tasks.
137+
///
138+
/// See also:
139+
/// * [MediaPipe's EmbedderOptions documentation](https://developers.google.com/mediapipe/api/solutions/java/com/google/mediapipe/tasks/text/textembedder/TextEmbedder.TextEmbedderOptions)
140+
/// * [BaseOptions], which is often used in conjunction to specify a
141+
/// embedder's desired behavior.
142+
/// {@endtemplate}
143+
abstract class BaseEmbedderOptions extends BaseInnerTaskOptions {
144+
/// {@macro EmbedderOptions}
145+
const BaseEmbedderOptions();
146+
147+
/// Whether to normalize the returned feature vector with L2 norm. Use this
148+
/// option only if the model does not already contain a native L2_NORMALIZATION
149+
/// TF Lite Op. In most cases, this is already the case and L2 norm is thus
150+
/// achieved through TF Lite inference.
151+
///
152+
/// See also:
153+
/// * [TutorialsPoint guide on L2 normalization](https://www.tutorialspoint.com/machine_learning_with_python/machine_learning_with_python_ltwo_normalization.htm)
154+
bool get l2Normalize;
155+
156+
/// Whether the returned embedding should be quantized to bytes via scalar
157+
/// quantization. Embeddings are implicitly assumed to be unit-norm and
158+
/// therefore any dimension is guaranteed to have a value in [-1.0, 1.0]. Use
159+
/// the l2_normalize option if this is not the case.
160+
///
161+
/// See also:
162+
/// * [l2Normalize]
163+
bool get quantize;
164+
165+
@override
166+
List<Object?> get props => [l2Normalize, quantize];
167+
}

packages/mediapipe-core/lib/src/interface/task_result.dart

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,31 @@
33
// found in the LICENSE file.
44

55
import 'package:mediapipe_core/interface.dart';
6+
import 'package:meta/meta.dart';
67

78
/// Anchor class for all result objects from MediaPipe tasks.
89
abstract class TaskResult {
910
/// {@template TaskResult.dispose}
10-
/// Releases platform memory if any is held.
11+
/// Releases all resources for this object.
12+
///
13+
/// See also:
14+
/// * [isClosed] which tracks whether this method has been called.
15+
/// {@endtemplate}
16+
@mustCallSuper
17+
void dispose() {
18+
_isClosed = true;
19+
}
20+
21+
/// {@template TaskResult.isClosed}
22+
/// Tracks whether this object has been properly released via `dispose`.
23+
///
24+
/// See also:
25+
/// * [dispose], whose calling should set this to `true`.
1126
/// {@endtemplate}
12-
void dispose();
27+
bool get isClosed => _isClosed;
28+
29+
/// Inner tracker for whether [dispose] has been called;
30+
bool _isClosed = false;
1331
}
1432

1533
/// {@template ClassifierResult}
@@ -37,7 +55,7 @@ abstract class BaseClassifierResult extends TaskResult {
3755
/// Container for classification results that may describe a slice of time
3856
/// within a larger, streaming data source (.e.g, a video or audio file).
3957
/// {@endtemplate}
40-
mixin TimestampedResult {
58+
mixin TimestampedResult on TaskResult {
4159
/// The optional timestamp (as a [Duration]) of the start of the chunk of data
4260
/// corresponding to these results.
4361
///
@@ -47,3 +65,34 @@ mixin TimestampedResult {
4765
/// input data is split into multiple chunks starting at different timestamps.
4866
Duration? get timestamp;
4967
}
68+
69+
/// {@template EmbeddingResult}
70+
/// Represents the embedding results of a model. Typically used as a result for
71+
/// embedding tasks.
72+
///
73+
/// This flavor of embedding result will never have a timestamp.
74+
///
75+
/// See also:
76+
/// * [TimestampedEmbeddingResult] for data which may have a timestamp.
77+
///
78+
/// {@endtemplate}
79+
abstract class BaseEmbedderResult extends TaskResult {
80+
/// {@macro EmbeddingResult}
81+
BaseEmbedderResult();
82+
83+
/// The embedding results for each head of the model.
84+
Iterable<BaseEmbedding> get embeddings;
85+
86+
@override
87+
String toString() {
88+
return '$runtimeType(embeddings=[...${embeddings.length} items])';
89+
}
90+
91+
/// A [toString] variant that calls the full [toString] on each child
92+
/// embedding. Use with caution - this can produce a long value.
93+
String toStringVerbose() {
94+
final embeddingStrings =
95+
embeddings.map<String>((emb) => emb.toString()).toList().join(', ');
96+
return '$runtimeType(embeddings=[$embeddingStrings])';
97+
}
98+
}

0 commit comments

Comments
 (0)