@@ -35,7 +35,7 @@ type Entity struct {
3535 Scores []float32
3636 Index int
3737 Word string
38- TokenID uint32
38+ TokenID [] uint32
3939 Start uint
4040 End uint
4141 IsSubword bool
@@ -65,6 +65,12 @@ func WithSimpleAggregation() pipelineBackends.PipelineOption[*TokenClassificatio
6565 }
6666}
6767
68+ func WithAverageAggregation () pipelineBackends.PipelineOption [* TokenClassificationPipeline ] {
69+ return func (pipeline * TokenClassificationPipeline ) {
70+ pipeline .AggregationStrategy = "AVERAGE"
71+ }
72+ }
73+
6874// WithoutAggregation returns the token labels.
6975func WithoutAggregation () pipelineBackends.PipelineOption [* TokenClassificationPipeline ] {
7076 return func (pipeline * TokenClassificationPipeline ) {
@@ -264,7 +270,7 @@ func (p *TokenClassificationPipeline) GatherPreEntities(input pipelineBackends.T
264270 // in that case set the subword as in the python code
265271 preEntities = append (preEntities , Entity {
266272 Word : word ,
267- TokenID : tokenID ,
273+ TokenID : [] uint32 { tokenID } ,
268274 Scores : tokenScores ,
269275 Start : startInd ,
270276 End : endInd ,
@@ -275,8 +281,82 @@ func (p *TokenClassificationPipeline) GatherPreEntities(input pipelineBackends.T
275281 return preEntities
276282}
277283
284+ func (p * TokenClassificationPipeline ) aggregateWord (entities []Entity ) (Entity , error ) {
285+ tokens := make ([]uint32 , len (entities ))
286+ for i , e := range entities {
287+ tokens [i ] = e .TokenID [0 ]
288+ }
289+ var newEntity Entity
290+
291+ word , err := pipelineBackends .Decode (tokens , p .Model .Tokenizer , true )
292+ if err != nil {
293+ return newEntity , err
294+ }
295+
296+ switch p .AggregationStrategy {
297+ case "AVERAGE" :
298+ scores := make ([][]float32 , len (p .IDLabelMap ))
299+ for _ , e := range entities {
300+ for i , score := range e .Scores {
301+ scores [i ] = append (scores [i ], score )
302+ }
303+ }
304+ averages := make ([]float32 , len (p .IDLabelMap ))
305+ for i , s := range scores {
306+ averages [i ] = util .Mean (s )
307+ }
308+ entityIdx , score , _ := util .ArgMax (averages )
309+ label , ok := p .IDLabelMap [entityIdx ]
310+ if ! ok {
311+ return Entity {}, fmt .Errorf ("could not determine entity type for input %s, predicted entity index %d" , word , entityIdx )
312+ }
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 ,
320+ }
321+ default :
322+ return Entity {}, fmt .Errorf ("aggregation strategy %s not recognized" , p .AggregationStrategy )
323+ }
324+ return newEntity , nil
325+ }
326+
327+ func (p * TokenClassificationPipeline ) aggregateWords (entities []Entity ) ([]Entity , error ) {
328+ var wordGroup []Entity
329+ var wordEntities []Entity
330+
331+ for _ , entity := range entities {
332+ if len (wordGroup ) == 0 {
333+ wordGroup = []Entity {entity }
334+ } else if entity .IsSubword {
335+ wordGroup = append (wordGroup , entity )
336+ } else {
337+ aggregated , err := p .aggregateWord (wordGroup )
338+ if err != nil {
339+ return nil , err
340+ }
341+ wordEntities = append (wordEntities , aggregated )
342+ wordGroup = []Entity {entity }
343+ }
344+ }
345+
346+ if len (wordGroup ) > 0 {
347+ aggregated , err := p .aggregateWord (wordGroup )
348+ if err != nil {
349+ return nil , err
350+ }
351+ wordEntities = append (wordEntities , aggregated )
352+ }
353+ return wordEntities , nil
354+ }
355+
278356func (p * TokenClassificationPipeline ) Aggregate (input pipelineBackends.TokenizedInput , preEntities []Entity ) ([]Entity , error ) {
279357 entities := make ([]Entity , len (preEntities ))
358+ var aggregationError error
359+
280360 if p .AggregationStrategy == "SIMPLE" || p .AggregationStrategy == "NONE" {
281361 for i , preEntity := range preEntities {
282362 entityIdx , score , argMaxErr := util .ArgMax (preEntity .Scores )
@@ -298,8 +378,12 @@ func (p *TokenClassificationPipeline) Aggregate(input pipelineBackends.Tokenized
298378 }
299379 }
300380 } else {
301- return nil , errors .New ("aggregation strategies other than SIMPLE and NONE are not implemented" )
381+ entities , aggregationError = p .aggregateWords (preEntities )
382+ if aggregationError != nil {
383+ return nil , aggregationError
384+ }
302385 }
386+
303387 if p .AggregationStrategy == "NONE" {
304388 return entities , nil
305389 }
@@ -323,7 +407,7 @@ func (p *TokenClassificationPipeline) getTag(entityName string) (string, string)
323407 return bi , tag
324408}
325409
326- func (p * TokenClassificationPipeline ) groupSubEntities (entities []Entity ) Entity {
410+ func (p * TokenClassificationPipeline ) groupSubEntities (entities []Entity ) ( Entity , error ) {
327411 splits := strings .Split (entities [0 ].Entity , "-" )
328412 var entityType string
329413 if len (splits ) == 1 {
@@ -335,20 +419,23 @@ func (p *TokenClassificationPipeline) groupSubEntities(entities []Entity) Entity
335419 tokens := make ([]uint32 , len (entities ))
336420 for i , s := range entities {
337421 scores [i ] = s .Score
338- tokens [ i ] = s .TokenID
422+ tokens = slices . Concat ( tokens , s .TokenID )
339423 }
340424 score := util .Mean (scores )
341425 // note: here we directly appeal to the tokenizer decoder with the tokenIds
342426 // in the python code they pass the words to a token_to_string_method
343- word := pipelineBackends .Decode (tokens , p .Model .Tokenizer )
427+ word , err := pipelineBackends .Decode (tokens , p .Model .Tokenizer , true )
428+ if err != nil {
429+ return Entity {}, err
430+ }
344431
345432 return Entity {
346433 Entity : entityType ,
347434 Score : score ,
348435 Word : word ,
349436 Start : entities [0 ].Start ,
350437 End : entities [len (entities )- 1 ].End ,
351- }
438+ }, nil
352439}
353440
354441// GroupEntities group together adjacent tokens with the same entity predicted.
@@ -368,14 +455,22 @@ func (p *TokenClassificationPipeline) GroupEntities(entities []Entity) ([]Entity
368455 currentGroupDisagg = append (currentGroupDisagg , e )
369456 } else {
370457 // create the grouped entity
371- entityGroups = append (entityGroups , p .groupSubEntities (currentGroupDisagg ))
458+ groupedEntity , err := p .groupSubEntities (currentGroupDisagg )
459+ if err != nil {
460+ return nil , err
461+ }
462+ entityGroups = append (entityGroups , groupedEntity )
372463 currentGroupDisagg = []Entity {e }
373464 }
374465 }
375466
376467 if len (currentGroupDisagg ) > 0 {
377468 // last entity remaining
378- entityGroups = append (entityGroups , p .groupSubEntities (currentGroupDisagg ))
469+ groupedEntity , err := p .groupSubEntities (currentGroupDisagg )
470+ if err != nil {
471+ return nil , err
472+ }
473+ entityGroups = append (entityGroups , groupedEntity )
379474 }
380475 return entityGroups , nil
381476}
0 commit comments