Package: classy-classification
Classy ClassificationHave you ever struggled with needing aSpacy TextCategorizerbut didn't have the time to train one from scratch? Classy Classification is the way to go! For few-shot classification usingsentence-transformersorspaCy models, provide a dictionary with labels and examples, or just provide a list of labels for zero shot-classification withHugginface zero-shot classifiers.Installpip install classy-classificationOr, install with faster inference using ONNX.pip install classy-classification[onnx]SetFit supportI got a lot of requests for SetFit support, but I decided to create aseparate packagefor this. Feel free to check it out. ❤️ONNX issuespicklingONNX does show some issues when pickling the data.M1Someinstallation issuesmight occur, which can be fixed by these commands.brew install cmake
brew install protobuf
pip3 install onnx --no-use-pep517QuickstartSpaCy embeddingsimportspacy# or import standalone# from classy_classification import ClassyClassifierdata={"furniture":["This text is about chairs.","Couches, benches and televisions.","I really need to get a new sofa."],"kitchen":["There also exist things like fridges.","I hope to be getting a new stove today.","Do you also have some ovens."]}nlp=spacy.load("en_core_web_trf")nlp.add_pipe("classy_classification",config={"data":data,"model":"spacy"})print(nlp("I am looking for kitchen appliances.")._.cats)# Output:## [{"furniture" : 0.21}, {"kitchen": 0.79}]Sentence level classificationimportspacydata={"furniture":["This text is about chairs.","Couches, benches and televisions.","I really need to get a new sofa."],"kitchen":["There also exist things like fridges.","I hope to be getting a new stove today.","Do you also have some ovens."]}nlp.add_pipe("classy_classification",config={"data":data,"model":"spacy","include_sent":True})print(nlp("I am looking for kitchen appliances. And I love doing so.").sents[0]._.cats)# Output:## [[{"furniture" : 0.21}, {"kitchen": 0.79}]Define random seed and verbositynlp.add_pipe("classy_classification",config={"data":data,"verbose":True,"config":{"seed":42}})Multi-label classificationSometimes multiple labels are necessary to fully describe the contents of a text. In that case, we want to make use of themulti-labelimplementation, here the sum of label scores is not limited to 1. Just pass the same training data to multiple keys.importspacydata={"furniture":["This text is about chairs.","Couches, benches and televisions.","I really need to get a new sofa.","We have a new dinner table.","There also exist things like fridges.","I hope to be getting a new stove today.","Do you also have some ovens.","We have a new dinner table."],"kitchen":["There also exist things like fridges.","I hope to be getting a new stove today.","Do you also have some ovens.","We have a new dinner table.","There also exist things like fridges.","I hope to be getting a new stove today.","Do you also have some ovens.","We have a new dinner table."]}nlp=spacy.load("en_core_web_md")nlp.add_pipe("classy_classification",config={"data":data,"model":"spacy","multi_label":True,})print(nlp("I am looking for furniture and kitchen equipment.")._.cats)# Output:## [{"furniture": 0.92}, {"kitchen": 0.91}]Outlier detectionSometimes it is worth to be able to do outlier detection or binary classification. This can either be approached using
a binary training dataset, however, I have also implemented support for aOneClassSVMforoutlier detection using a single label. Not that this method does not return probabilities, but that the data is formatted like label-score value pair to ensure uniformity.Approach 1:importspacydata_binary={"inlier":["This text is about chairs.","Couches, benches and televisions.","I really need to get a new sofa."],"outlier":["Text about kitchen equipment","This text is about politics","Comments about AI and stuff."]}nlp=spacy.load("en_core_web_md")nlp.add_pipe("classy_classification",config={"data":data_binary,})print(nlp("This text is a random text")._.cats)# Output:## [{'inlier': 0.2926672385488411, 'outlier': 0.707332761451159}]Approach 2:importspacydata_singular={"furniture":["This text is about chairs.","Couches, benches and televisions.","I really need to get a new sofa.","We have a new dinner table."]}nlp=spacy.load("en_core_web_md")nlp.add_pipe("classy_classification",config={"data":data_singular,})print(nlp("This text is a random text")._.cats)# Output:## [{'furniture': 0, 'not_furniture': 1}]Sentence-transfomer embeddingsimportspacydata={"furniture":["This text is about chairs.","Couches, benches and televisions.","I really need to get a new sofa."],"kitchen":["There also exist things like fridges.","I hope to be getting a new stove today.","Do you also have some ovens."]}nlp=spacy.blank("en")nlp.add_pipe("classy_classification",config={"data":data,"model":"sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2","device":"gpu"})print(nlp("I am looking for kitchen appliances.")._.cats)# Output:## [{"furniture": 0.21}, {"kitchen": 0.79}]Hugginface zero-shot classifiersimportspacydata=["furniture","kitchen"]nlp=spacy.blank("en")nlp.add_pipe("classy_classification",config={"data":data,"model":"typeform/distilbert-base-uncased-mnli","cat_type":"zero","device":"gpu"})print(nlp("I am looking for kitchen appliances.")._.cats)# Output:## [{"furniture": 0.21}, {"kitchen": 0.79}]CreditsInspiration Drawn FromHuggingfacedoes offer some nice models for few/zero-shot classification, but these are not tailored to multi-lingual approaches. Rasa NLU hasa nice approachfor this, but its too embedded in their codebase for easy usage outside of Rasa/chatbots. Additionally, it made sense to integratesentence-transformersandHugginface zero-shot, instead of defaultword embeddings. Finally, I decided to integrate with Spacy, since training a customSpacy TextCategorizerseems like a lot of hassle if you want something quick and dirty.Scikit-learnRasa NLUSentence TransformersSpacyOr buy me a coffeeStandalone usage without spaCyfromclassy_classificationimportClassyClassifierdata={"furniture":["This text is about chairs.","Couches, benches and televisions.","I really need to get a new sofa."],"kitchen":["There also exist things like fridges.","I hope to be getting a new stove today.","Do you also have some ovens."]}classifier=ClassyClassifier(data=data)classifier("I am looking for kitchen appliances.")classifier.pipe(["I am looking for kitchen appliances."])# overwrite training dataclassifier.set_training_data(data=data)classifier("I am looking for kitchen appliances.")# overwrite [embedding model](https://www.sbert.net/docs/pretrained_models.html)classifier.set_embedding_model(model="paraphrase-MiniLM-L3-v2")classifier("I am looking for kitchen appliances.")# overwrite SVC configclassifier.set_classification_model(config={"C":[1,2,5,10,20,100],"kernel":["linear"],"max_cross_validation_folds":5})classifier("I am looking for kitchen appliances.")Save and load modelsdata={"furniture":["This text is about chairs.","Couches, benches and televisions.","I really need to get a new sofa."],"kitchen":["There also exist things like fridges.","I hope to be getting a new stove today.","Do you also have some ovens."]}classifier=classyClassifier(data=data)withopen("./classifier.pkl","wb")asf:pickle.dump(classifier,f)f=open("./classifier.pkl","rb")classifier=pickle.load(f)classifier("I am looking for kitchen appliances.")