/ test / python / testpipeline / testtrain / testonnx.py
testonnx.py
  1  """
  2  ONNX module tests
  3  """
  4  
  5  import os
  6  import tempfile
  7  import unittest
  8  
  9  from unittest.mock import patch
 10  
 11  from sklearn.feature_extraction.text import TfidfVectorizer
 12  from sklearn.linear_model import LogisticRegression
 13  from sklearn.pipeline import Pipeline
 14  
 15  from txtai.embeddings import Embeddings
 16  from txtai.models import OnnxModel
 17  from txtai.pipeline import HFOnnx, HFTrainer, Labels, MLOnnx, Questions
 18  
 19  
 20  class TestOnnx(unittest.TestCase):
 21      """
 22      ONNX tests.
 23      """
 24  
 25      @classmethod
 26      def setUpClass(cls):
 27          """
 28          Create default datasets.
 29          """
 30  
 31          cls.data = [{"text": "Dogs", "label": 0}, {"text": "dog", "label": 0}, {"text": "Cats", "label": 1}, {"text": "cat", "label": 1}] * 100
 32  
 33      def testDefault(self):
 34          """
 35          Test exporting an ONNX model with default parameters
 36          """
 37  
 38          # Export model to ONNX, use default parameters
 39          onnx = HFOnnx()
 40          model = onnx("google/bert_uncased_L-2_H-128_A-2")
 41  
 42          # Validate model has data
 43          self.assertGreater(len(model), 0)
 44  
 45          # Validate model device properly works
 46          self.assertEqual(OnnxModel(model).device, -1)
 47  
 48      def testClassification(self):
 49          """
 50          Test exporting a classification model to ONNX and running inference
 51          """
 52  
 53          path = "google/bert_uncased_L-2_H-128_A-2"
 54  
 55          trainer = HFTrainer()
 56          model, tokenizer = trainer(path, self.data)
 57  
 58          # Output file path
 59          output = os.path.join(tempfile.gettempdir(), "onnx")
 60  
 61          # Export model to ONNX
 62          onnx = HFOnnx()
 63          model = onnx((model, tokenizer), "text-classification", output, True)
 64  
 65          # Test classification
 66          labels = Labels((model, path), dynamic=False)
 67          self.assertEqual(labels("cat")[0][0], 1)
 68  
 69      @patch("onnxruntime.get_available_providers")
 70      @patch("torch.cuda.is_available")
 71      def testPooling(self, cuda, providers):
 72          """
 73          Test exporting a pooling model to ONNX and running inference
 74          """
 75  
 76          path = "sentence-transformers/paraphrase-MiniLM-L3-v2"
 77  
 78          # Export model to ONNX
 79          onnx = HFOnnx()
 80          model = onnx(path, "pooling", quantize=True)
 81  
 82          # Test no CUDA and onnxruntime installed
 83          cuda.return_value = False
 84          providers.return_value = ["CPUExecutionProvider"]
 85  
 86          embeddings = Embeddings({"path": model, "tokenizer": path})
 87          self.assertEqual(embeddings.similarity("animal", ["dog", "book", "rug"])[0][0], 0)
 88  
 89          # Test no CUDA and onnxruntime-gpu installed
 90          cuda.return_value = False
 91          providers.return_value = ["CUDAExecutionProvider", "CPUExecutionProvider"]
 92  
 93          embeddings = Embeddings({"path": model, "tokenizer": path})
 94          self.assertIsNotNone(embeddings)
 95  
 96          # Test CUDA and only onnxruntime installed
 97          cuda.return_value = True
 98          providers.return_value = ["CPUExecutionProvider"]
 99  
100          embeddings = Embeddings({"path": model, "tokenizer": path})
101          self.assertIsNotNone(embeddings)
102  
103          # Test CUDA and onnxruntime-gpu installed
104          cuda.return_value = True
105          providers.return_value = ["CUDAExecutionProvider", "CPUExecutionProvider"]
106  
107          embeddings = Embeddings({"path": model, "tokenizer": path})
108          self.assertIsNotNone(embeddings)
109  
110      def testQA(self):
111          """
112          Test exporting a QA model to ONNX and running inference
113          """
114  
115          path = "distilbert-base-cased-distilled-squad"
116  
117          # Export model to ONNX
118          onnx = HFOnnx()
119          model = onnx(path, "question-answering")
120  
121          questions = Questions((model, path))
122          self.assertEqual(questions(["What is the price?"], ["The price is $30"])[0], "$30")
123  
124      def testScikit(self):
125          """
126          Test exporting a scikit-learn model to ONNX and running inference
127          """
128  
129          # pylint: disable=W0613
130          def tokenizer(inputs, **kwargs):
131              if isinstance(inputs, str):
132                  inputs = [inputs]
133  
134              return {"input_ids": [[x] for x in inputs]}
135  
136          # Train a scikit-learn model
137          model = Pipeline([("tfidf", TfidfVectorizer()), ("lr", LogisticRegression())])
138          model.fit([x["text"] for x in self.data], [x["label"] for x in self.data])
139  
140          # Export model to ONNX
141          onnx = MLOnnx()
142          model = onnx(model)
143  
144          # Test classification
145          labels = Labels((model, tokenizer), dynamic=False)
146          self.assertEqual(labels("cat")[0][0], 1)
147  
148      def testZeroShot(self):
149          """
150          Test exporting a zero shot classification model to ONNX and running inference
151          """
152  
153          path = "prajjwal1/bert-medium-mnli"
154  
155          # Export model to ONNX
156          onnx = HFOnnx()
157          model = onnx(path, "zero-shot-classification", quantize=True)
158  
159          # Test zero shot classification
160          labels = Labels((model, path))
161          self.assertEqual(labels("That is great news", ["negative", "positive"])[0][0], 1)