Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"Classifier with Feature Extractor" might not work with 3+ classes. #164

Closed
honnet opened this issue Jun 19, 2018 · 18 comments
Closed

"Classifier with Feature Extractor" might not work with 3+ classes. #164

honnet opened this issue Jun 19, 2018 · 18 comments

Comments

@honnet
Copy link

honnet commented Jun 19, 2018

The given example works smoothly with 2 classes:
https://ml5js.org/docs/custom-classifier

...but adding a 3rd prediction class doesn't seem to be working yet.
Reproduction sketch:
https://alpha.editor.p5js.org/CedHon/sketches/S1yCjnr-7

Let me know if I can add any detail ;)

@cvalenzuela
Copy link
Member

I'll look into this. But changing the hyperparameters might help: https://ml5js.org/docs/FeatureExtractor#parameters

@honnet
Copy link
Author

honnet commented Jun 23, 2018

Thanks for the answer!
You suggested it during the workshop and we tried it (see lines 18-19), but it seems that something else is missing...

@cezary69
Copy link

For some reason numClasses is always = 2 whatever I put into hyperparameters object
just console.log(classifier) to see it
that's why we can't have more than 2 classes with actual ml5

@gick
Copy link

gick commented Jul 3, 2018

I experienced the same issue, a quick fix that's working for me is to set numClasses explicitely

featureExtractor = ml5.featureExtractor('MobileNet', modelReady);
featureExtractor.numClasses=3

Then by putting a breakpoint in

function classify() {
  classifier.classify(gotResults);
}

And inspecting classifier properties, numClasses is at 3.

I changed a bit the code with a "Add bird image" button, using similar pattern than "Add dog" and "Add cat" and it works correctly, distinguishing 3 classes.
image

I put the working example on p5.js :
https://alpha.editor.p5js.org/gick/sketches/rJFlNNKGX

@lenny76
Copy link

lenny76 commented Jul 23, 2018

@gick great solutions!
it works for me too.
thanks!

@artismarti
Copy link

<3 thank you for this!!!!

@shiffman
Copy link
Member

shiffman commented Jan 5, 2019

I investigated this a bit more and another way to do this is the following:

featureExtractor = ml5.featureExtractor('MobileNet', { numClasses: 3 }, modelReady);

The number of classes has to be set in advance b/c when examples are added they are "one-hot encoded" according to the total number of classes. This is distinctly different than the KNNClassifier examples which builds up the examples and labels on the fly.

In light of this...

  1. Specifying the number of classes should probably be required. I suppose a default of 2 is reasonable for some very basic demos, but it's probably a good idea for the user to think about and specify the number.
  2. The number of classes is only relevant when the feature extractor is turned into a classifier. Therefore the number of classes should probably be specified. What about the following:
featureExtractor = ml5.featureExtractor('MobileNet', modelReady);
classifier = featureExtractor.classification(3, video, videoReady);

or in the case of not working with video

featureExtractor = ml5.featureExtractor('MobileNet', modelReady);
classifier = featureExtractor.classification(3);

@cvalenzuela
Copy link
Member

Yes, that's the default behavior (see docs) and I believe we fix this in a PR a few months ago. Perhaps adding an example with more classes will help

@shiffman
Copy link
Member

Thanks @cvalenzuela. Thinking about this a bit more it feels like the number of classes should be set when calling classification() since it's not relevant to the featureExtractor until that point? We can discuss next week!

classifier = featureExtractor.classification({ numClasses: 3 });

Also, probably worth discussing if we make the terminology more consistent with KNNClassifier and use "labels".

@OmarTahoun
Copy link

Thanks for this!! i've been stuck for a minute here trying to figure out why it never classifies the last class added.

@shiffman Don't you think the function classifier.addImage('Cat') should return a warning or an error if the number of labels added to the classifier is already more than the number specified in the classifier object?
This would make it easier to debug.
I would love to work on that!!

@OmarTahoun
Copy link

I imagine it to be something like this inside the addImage() function.

if (this.mapStringToIndex.length <= this.numClasses)
// Can add image
else
// Raise Warning("More labels than specified")

@aaaven
Copy link

aaaven commented Apr 2, 2019

Thanks for this! Tested both methods, worked for me.

featureExtractor = ml5.featureExtractor('MobileNet',{numClasses:4},function(){
    console.log("model is loaded...");
  });

and

  featureExtractor = ml5.featureExtractor('MobileNet',function(){
    console.log("model is loaded...");
  });
  featureExtractor.numClasses = 4;

@joeyklee
Copy link
Contributor

Hi All! This is now resolved with ml5js/ml5-examples#142. Closing up this issue for now. Thanks for this nice discussion! 🙏

@rokkoo
Copy link

rokkoo commented Jul 17, 2019

In last update they change name to numClasses to numLabels

@redet-G
Copy link

redet-G commented Jul 22, 2019

In last update they change name to numClasses to numLabels
thanks man!

@snkyogi
Copy link

snkyogi commented Aug 18, 2020

For people using 0.4.1 or above, numClasses has been changed to numLabels.

featureExtractor = ml5.featureExtractor('MobileNet', { numLabels: 3 }, modelReady);

@Kimbotoski
Copy link

Thanks for this! Tested both methods, worked for me.

featureExtractor = ml5.featureExtractor('MobileNet',{numClasses:4},function(){
    console.log("model is loaded...");
  });

and

  featureExtractor = ml5.featureExtractor('MobileNet',function(){
    console.log("model is loaded...");
  });
  featureExtractor.numClasses = 4;

Thanks for this! Tested both methods, worked for me.

featureExtractor = ml5.featureExtractor('MobileNet',{numClasses:4},function(){
    console.log("model is loaded...");
  });

and

  featureExtractor = ml5.featureExtractor('MobileNet',function(){
    console.log("model is loaded...");
  });
  featureExtractor.numClasses = 4;

can u show ur all code i still dont get which line to add ur code to make my model can predict more that 2 class

@corpr8
Copy link

corpr8 commented Sep 1, 2022

I create and train a featureExtractor with 10 classes and I save that onto a server. When I load this in a classifier. When I examine the JSON, I can see a key ml5Specs.mapStringToIndex which contains the 10 classes. However, I cannot get it to classify more than the first 2 classes.

I have tried the fixes above with no luck.

Heres my classifier code:

let classifier

//just a way to get the image location from a url parameter:
let getUrlVars = () =>{
    let vars = [], hash;
    let hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');
    for(var i = 0; i < hashes.length; i++)
    {
        hash = hashes[i].split('=');
        vars.push(hash[0]);
        vars[hash[0]] = hash[1];
    }
    return vars;
}

const url_vars = getUrlVars()

function setup() {
    console.log(`image src: ${url_vars.image}`)
    document.getElementById('img_1').src = `img?src=${url_vars.image}`
}

function modelLoaded() {
    // Create a new classifier using those features
    classifier = featureExtractor.classification();
    
    classifier.load('./generated_models/32b32ea7-c7dc-40dc-b018-66b3af18da61.json', () => {
        console.log("Model loaded!");
        classifier.classify(document.getElementById('img_1'), gotResults)
    })
  }

  // Show the results
function gotResults(err, results) {
    // Display any error
    if (err) {
      console.error(err);
    }
    if (results && results[0]) {
      console.log(results)
    }
  }

// Extract the already learned features from MobileNet
const featureExtractor = ml5.featureExtractor("MobileNet", { numLabels: 10 }, modelLoaded);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests