Skip to content

Commit b9c0038

Browse files
feat: added max and fist aggregation to token classification
1 parent 5023e58 commit b9c0038

1 file changed

Lines changed: 69 additions & 15 deletions

File tree

pipelines/tokenClassification.go

Lines changed: 69 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,6 @@ func (t *TokenClassificationOutput) GetOutput() []any {
5555

5656
// options
5757

58-
// TODO: need to implement the other types of aggregation (max etc)
59-
6058
// WithSimpleAggregation sets the aggregation strategy for the token labels to simple
6159
// It reproduces simple aggregation from the huggingface implementation.
6260
func WithSimpleAggregation() pipelineBackends.PipelineOption[*TokenClassificationPipeline] {
@@ -65,12 +63,30 @@ func WithSimpleAggregation() pipelineBackends.PipelineOption[*TokenClassificatio
6563
}
6664
}
6765

66+
// WithAverageAggregation sets the aggregation strategy for the token labels to average
67+
// It reproduces simple aggregation from the huggingface implementation.
6868
func WithAverageAggregation() pipelineBackends.PipelineOption[*TokenClassificationPipeline] {
6969
return func(pipeline *TokenClassificationPipeline) {
7070
pipeline.AggregationStrategy = "AVERAGE"
7171
}
7272
}
7373

74+
// WithMaxAggregation sets the aggregation strategy for the token labels to average
75+
// It reproduces average aggregation from the huggingface implementation.
76+
func WithMaxAggregation() pipelineBackends.PipelineOption[*TokenClassificationPipeline] {
77+
return func(pipeline *TokenClassificationPipeline) {
78+
pipeline.AggregationStrategy = "MAX"
79+
}
80+
}
81+
82+
// WithMaxAggregation sets the aggregation strategy for the token labels to average
83+
// It reproduces average aggregation from the huggingface implementation.
84+
func WithFirstAggregation() pipelineBackends.PipelineOption[*TokenClassificationPipeline] {
85+
return func(pipeline *TokenClassificationPipeline) {
86+
pipeline.AggregationStrategy = "FIRST"
87+
}
88+
}
89+
7490
// WithoutAggregation returns the token labels.
7591
func WithoutAggregation() pipelineBackends.PipelineOption[*TokenClassificationPipeline] {
7692
return func(pipeline *TokenClassificationPipeline) {
@@ -86,7 +102,6 @@ func WithIgnoreLabels(ignoreLabels []string) pipelineBackends.PipelineOption[*To
86102

87103
// NewTokenClassificationPipeline Initializes a feature extraction pipeline.
88104
func NewTokenClassificationPipeline(config pipelineBackends.PipelineConfig[*TokenClassificationPipeline], s *options.Options, model *pipelineBackends.Model) (*TokenClassificationPipeline, error) {
89-
90105
defaultPipeline, err := pipelineBackends.NewBasePipeline(config, s, model)
91106
if err != nil {
92107
return nil, err
@@ -286,13 +301,17 @@ func (p *TokenClassificationPipeline) aggregateWord(entities []Entity) (Entity,
286301
for i, e := range entities {
287302
tokens[i] = e.TokenID[0]
288303
}
289-
var newEntity Entity
304+
305+
newEntity := Entity{}
290306

291307
word, err := pipelineBackends.Decode(tokens, p.Model.Tokenizer, true)
292308
if err != nil {
293309
return newEntity, err
294310
}
295311

312+
var score float32
313+
var label string
314+
296315
switch p.AggregationStrategy {
297316
case "AVERAGE":
298317
scores := make([][]float32, len(p.IDLabelMap))
@@ -305,23 +324,58 @@ func (p *TokenClassificationPipeline) aggregateWord(entities []Entity) (Entity,
305324
for i, s := range scores {
306325
averages[i] = util.Mean(s)
307326
}
308-
entityIdx, score, _ := util.ArgMax(averages)
309-
label, ok := p.IDLabelMap[entityIdx]
327+
entityIdx, maxScore, err := util.ArgMax(averages)
328+
if err != nil {
329+
return newEntity, err
330+
}
331+
entityLabel, ok := p.IDLabelMap[entityIdx]
310332
if !ok {
311-
return Entity{}, fmt.Errorf("could not determine entity type for input %s, predicted entity index %d", word, entityIdx)
333+
return newEntity, fmt.Errorf("could not determine entity type for input %s, predicted entity index %d", word, entityIdx)
334+
}
335+
score = maxScore
336+
label = entityLabel
337+
case "MAX":
338+
var maxScore float32
339+
var maxIdx int
340+
for _, e := range entities {
341+
idx, score, err := util.ArgMax(e.Scores)
342+
if err != nil {
343+
return newEntity, err
344+
}
345+
if score >= maxScore {
346+
maxScore = score
347+
maxIdx = idx
348+
}
312349
}
313-
newEntity = Entity{
314-
Entity: label,
315-
Score: score,
316-
Word: word,
317-
TokenID: tokens,
318-
Start: entities[0].Start,
319-
End: entities[len(entities)-1].End,
350+
entityLabel, ok := p.IDLabelMap[maxIdx]
351+
if !ok {
352+
return Entity{}, fmt.Errorf("could not determine entity type for input %s, predicted entity index %d", word, maxIdx)
320353
}
354+
score = maxScore
355+
label = entityLabel
356+
case "FIRST":
357+
entityIdx, maxScore, err := util.ArgMax(entities[0].Scores)
358+
if err != nil {
359+
return newEntity, err
360+
}
361+
entityLabel, ok := p.IDLabelMap[entityIdx]
362+
if !ok {
363+
return Entity{}, fmt.Errorf("could not determine entity type for input %s, predicted entity index %d", word, entityIdx)
364+
}
365+
score = maxScore
366+
label = entityLabel
321367
default:
322368
return Entity{}, fmt.Errorf("aggregation strategy %s not recognized", p.AggregationStrategy)
323369
}
324-
return newEntity, nil
370+
371+
return Entity{
372+
Entity: label,
373+
Score: score,
374+
Word: word,
375+
TokenID: tokens,
376+
Start: entities[0].Start,
377+
End: entities[len(entities)-1].End,
378+
}, nil
325379
}
326380

327381
func (p *TokenClassificationPipeline) aggregateWords(entities []Entity) ([]Entity, error) {

0 commit comments

Comments
 (0)