Skip to content

Commit 383efc4

Browse files
Merge pull request #6 from knights-analytics/interface-test
Add RunPipeline function for concrete return types
2 parents 3fdcab5 + 3781ebb commit 383efc4

5 files changed

Lines changed: 37 additions & 48 deletions

File tree

README.md

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,11 @@ import (
8585
"github.com/knights-analytics/hugot/pipelines"
8686
)
8787

88+
func check(err error) {
89+
if err != nil {
90+
panic(err.Error())
91+
}
92+
}
8893
// start a new session. This looks for the onnxruntime.so library in its default path, e.g. /usr/lib/onnxruntime.so
8994
session, err := hugot.NewSession()
9095
// if your onnxruntime.so is somewhere else, you can explicitly set it by using WithOnnxLibraryPath
@@ -97,17 +102,14 @@ defer func(session *hugot.Session) {
97102
}(session)
98103
// we now create a text classification pipeline. It requires the path to the onnx model folder,
99104
// and a pipeline name
100-
sentimentPipeline, err := session.NewTextClassificationPipeline(modelPath, "testPipeline")
105+
sentimentPipeline, err := session.NewTextClassificationPipeline("/path/to/model/", "testPipeline")
101106
check(err)
102107
// we can now use the pipeline for prediction on a batch of strings
103108
batch := []string{"This movie is disgustingly good !", "The director tried too much"}
104-
batchResult, err := sentimentPipeline.Run(batch)
109+
batchResult, err := sentimentPipeline.RunPipeline(batch)
105110
check(err)
106-
// batchResult is an interface so that we can treat pipelines uniformly.
107-
// we can cast it to the concrete result type of this pipeline
108-
result, ok := batchResult.(*pipelines.TextClassificationOutput)
109111
// and do whatever we want with it :)
110-
s, err := json.Marshal(result)
112+
s, err := json.Marshal(batchResult)
111113
check(err)
112114
fmt.Println(string(s))
113115
// {"ClassificationOutputs":[[{"Label":"POSITIVE","Score":0.9998536}],[{"Label":"NEGATIVE","Score":0.99752176}]]}
@@ -208,4 +210,4 @@ This will build a test image and run all tests in a container. A testTarget fold
208210
3. add tests and make sure the full test suite passes and test coverage does not dip below 80%
209211
4. create a MR linking to the relevant issue
210212

211-
Thank you for contributing to hugot!
213+
Thank you for contributing to hugot!

hugot_test.go

Lines changed: 13 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -73,14 +73,10 @@ func TestTextClassificationPipeline(t *testing.T) {
7373

7474
for _, tt := range tests {
7575
t.Run(tt.name, func(t *testing.T) {
76-
batchResult, err := tt.pipeline.Run(tt.strings)
77-
result, ok := batchResult.(*pipelines.TextClassificationOutput)
78-
if !ok {
79-
t.FailNow()
80-
}
76+
batchResult, err := tt.pipeline.RunPipeline(tt.strings)
8177
check(t, err)
8278
for i, expected := range tt.expected.ClassificationOutputs {
83-
checkClassificationOutput(t, expected, result.ClassificationOutputs[i])
79+
checkClassificationOutput(t, expected, batchResult.ClassificationOutputs[i])
8480
}
8581
})
8682
}
@@ -176,15 +172,10 @@ func TestTokenClassificationPipeline(t *testing.T) {
176172

177173
for _, tt := range tests {
178174
t.Run(tt.name, func(t *testing.T) {
179-
batchResult, err := tt.pipeline.Run(tt.strings)
175+
batchResult, err := tt.pipeline.RunPipeline(tt.strings)
180176
check(t, err)
181-
result, ok := batchResult.(*pipelines.TokenClassificationOutput)
182-
if !ok {
183-
t.FailNow()
184-
}
185-
186-
printTokenEntities(result)
187-
for i, predictedEntities := range result.Entities {
177+
printTokenEntities(batchResult)
178+
for i, predictedEntities := range batchResult.Entities {
188179
assert.Equal(t, len(tt.expected.Entities[i]), len(predictedEntities))
189180
for j, entity := range predictedEntities {
190181
expectedEntity := tt.expected.Entities[i][j]
@@ -254,13 +245,9 @@ func TestFeatureExtractionPipeline(t *testing.T) {
254245
// test 'robert smith'
255246
testResults = expectedResults["test1output"]
256247
for i := 1; i <= 10; i++ {
257-
batchResult, err := pipeline.Run([]string{"robert smith"})
248+
batchResult, err := pipeline.RunPipeline([]string{"robert smith"})
258249
check(t, err)
259-
result, ok := batchResult.(*pipelines.FeatureExtractionOutput)
260-
if !ok {
261-
t.FailNow()
262-
}
263-
e := floatsEqual(result.Embeddings[0], testResults[0])
250+
e := floatsEqual(batchResult.Embeddings[0], testResults[0])
264251
if e != nil {
265252
t.Logf("Test 1: The neural network didn't produce the correct result on loop %d: %s\n", i, e)
266253
t.FailNow()
@@ -270,13 +257,9 @@ func TestFeatureExtractionPipeline(t *testing.T) {
270257
// test ['robert smith junior', 'francis ford coppola']
271258
testResults = expectedResults["test2output"]
272259
for i := 1; i <= 10; i++ {
273-
batchResult, err := pipeline.Run([]string{"robert smith junior", "francis ford coppola"})
260+
batchResult, err := pipeline.RunPipeline([]string{"robert smith junior", "francis ford coppola"})
274261
check(t, err)
275-
result, ok := batchResult.(*pipelines.FeatureExtractionOutput)
276-
if !ok {
277-
t.FailNow()
278-
}
279-
for j, res := range result.Embeddings {
262+
for j, res := range batchResult.Embeddings {
280263
e := floatsEqual(res, testResults[j])
281264
if e != nil {
282265
t.Logf("Test 2: The neural network didn't produce the correct result on loop %d: %s\n", i, e)
@@ -293,21 +276,13 @@ func TestFeatureExtractionPipeline(t *testing.T) {
293276

294277
for k, sentencePair := range testPairs {
295278
// these vectors should be the same
296-
firstBatchResult, err2 := pipeline.Run(sentencePair[0])
279+
firstBatchResult, err2 := pipeline.RunPipeline(sentencePair[0])
297280
check(t, err2)
298-
firstResult, ok := firstBatchResult.(*pipelines.FeatureExtractionOutput)
299-
if !ok {
300-
t.FailNow()
301-
}
302-
firstEmbedding := firstResult.Embeddings[0]
281+
firstEmbedding := firstBatchResult.Embeddings[0]
303282

304-
secondBatchResult, err3 := pipeline.Run(sentencePair[1])
283+
secondBatchResult, err3 := pipeline.RunPipeline(sentencePair[1])
305284
check(t, err3)
306-
secondResult, ok := secondBatchResult.(*pipelines.FeatureExtractionOutput)
307-
if !ok {
308-
t.FailNow()
309-
}
310-
secondEmbedding := secondResult.Embeddings[0]
285+
secondEmbedding := secondBatchResult.Embeddings[0]
311286
e := floatsEqual(firstEmbedding, secondEmbedding)
312287
if e != nil {
313288
t.Logf("Equality failed for determinism test %s test with pairs %s and %s", k, strings.Join(sentencePair[0], ","), strings.Join(sentencePair[1], ","))

pipelines/featureExtraction.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ func (p *FeatureExtractionPipeline) Validate() error {
6666
}
6767

6868
// Postprocess Parse the results of the forward pass into the output. Token embeddings are mean pooled.
69-
func (p *FeatureExtractionPipeline) Postprocess(batch PipelineBatch) (PipelineBatchOutput, error) {
69+
func (p *FeatureExtractionPipeline) Postprocess(batch PipelineBatch) (*FeatureExtractionOutput, error) {
7070

7171
maxSequence := batch.MaxSequence
7272
vectorCounter := 0
@@ -119,6 +119,10 @@ func meanPooling(tokens [][]float32, input TokenizedInput, maxSequence int, dime
119119

120120
// Run the pipeline on a string batch
121121
func (p *FeatureExtractionPipeline) Run(inputs []string) (PipelineBatchOutput, error) {
122+
return p.RunPipeline(inputs)
123+
}
124+
125+
func (p *FeatureExtractionPipeline) RunPipeline(inputs []string) (*FeatureExtractionOutput, error) {
122126
batch := p.Preprocess(inputs)
123127
batch, forwardError := p.Forward(batch)
124128
if forwardError != nil {

pipelines/textClassification.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ func (p *TextClassificationPipeline) Forward(batch PipelineBatch) (PipelineBatch
159159
return batch, err
160160
}
161161

162-
func (p *TextClassificationPipeline) Postprocess(batch PipelineBatch) (PipelineBatchOutput, error) {
162+
func (p *TextClassificationPipeline) Postprocess(batch PipelineBatch) (*TextClassificationOutput, error) {
163163

164164
outputTensor := batch.OutputTensor
165165
output := make([][]float32, len(batch.Input))
@@ -210,6 +210,10 @@ func (p *TextClassificationPipeline) Postprocess(batch PipelineBatch) (PipelineB
210210

211211
// Run the pipeline on a string batch
212212
func (p *TextClassificationPipeline) Run(inputs []string) (PipelineBatchOutput, error) {
213+
return p.RunPipeline(inputs)
214+
}
215+
216+
func (p *TextClassificationPipeline) RunPipeline(inputs []string) (*TextClassificationOutput, error) {
213217
batch := p.Preprocess(inputs)
214218
batch, err := p.Forward(batch)
215219
if err != nil {

pipelines/tokenClassification.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ func (p *TokenClassificationPipeline) Validate() error {
149149
}
150150

151151
// Postprocess function for a token classification pipeline
152-
func (p *TokenClassificationPipeline) Postprocess(batch PipelineBatch) (PipelineBatchOutput, error) {
152+
func (p *TokenClassificationPipeline) Postprocess(batch PipelineBatch) (*TokenClassificationOutput, error) {
153153

154154
outputs := make([][][]float32, len(batch.Input)) // holds the final output
155155
inputVectors := make([][]float32, 0, batch.MaxSequence) // holds the embeddings of each original token (no padding) for an input
@@ -355,6 +355,10 @@ func (p *TokenClassificationPipeline) GroupEntities(entities []Entity) ([]Entity
355355

356356
// Run the pipeline on a string batch
357357
func (p *TokenClassificationPipeline) Run(inputs []string) (PipelineBatchOutput, error) {
358+
return p.RunPipeline(inputs)
359+
}
360+
361+
func (p *TokenClassificationPipeline) RunPipeline(inputs []string) (*TokenClassificationOutput, error) {
358362
batch := p.Preprocess(inputs)
359363
batch, errForward := p.Forward(batch)
360364
if errForward != nil {

0 commit comments

Comments
 (0)