Wednesday, March 11, 2009
Monday, March 9, 2009
Jittering Data
After my results came out really bad, I decided that my training data was the problem. Both quality and quantity wise. It is difficult to get more training data fast, so Serge recommended using what I have to make more. I used Piotr Dollar's jitterImage function to take a single image and apply transformations to it.
Exaggeration:
Piotr's function applies both rotational and translational rotation to images. Serge recommended playing around with thickness also by raising an image to a power greater than 1, and also a power between 0 and 1.
I did all this, and started out with around 50,000 examples of each character instead of 135. I found out quickly that I run out of memory with this many examples. I eventually had to bring it down to 625, and training took forever.
The first thing I noticed was that the error in the training data was much higher than for when I only had 135 examples. I think that this is because there is a lot more variation in the data now and it's hard to cover all cases in 200 features. When I only had 135 examples, the error eventually went down to 0. This is the error with the 625 examples.
Also, here are the ROC curves plotted on top of each other. When I only have 135 examples, the ROC curve was a right angle.
Here is half of the 625 training examples for 'a':
To cut to the chase, my algorithm still performs poorly, and probably even worse now. D:
Exaggeration:
Piotr's function applies both rotational and translational rotation to images. Serge recommended playing around with thickness also by raising an image to a power greater than 1, and also a power between 0 and 1.
I did all this, and started out with around 50,000 examples of each character instead of 135. I found out quickly that I run out of memory with this many examples. I eventually had to bring it down to 625, and training took forever.
The first thing I noticed was that the error in the training data was much higher than for when I only had 135 examples. I think that this is because there is a lot more variation in the data now and it's hard to cover all cases in 200 features. When I only had 135 examples, the error eventually went down to 0. This is the error with the 625 examples.
Also, here are the ROC curves plotted on top of each other. When I only have 135 examples, the ROC curve was a right angle.
Here is half of the 625 training examples for 'a':
To cut to the chase, my algorithm still performs poorly, and probably even worse now. D:
Wednesday, March 4, 2009
Well, I ran it already
Finally, I got everything together and ran my algorithm. It did horribly. We're talking 0% accuracy horrible. I am using the same hidden markov model (hmm) as last year and I think that the model is just too unforgiving. Once it mispredicts the first letter, we're basically screwed.
I tried abandoning the hmm and for each letter in the test name, find the prediction of that letter, independent of the rest of the letters in the name. I found the prediction by taking the max over all confidences for each of the 26 possibilities. Then, in the end, I find the nearest neighbor of the predicted name with all of the names in the roster. This also did horribly.
I took a look at what was going on under the covers. I found that for each letter, the confidence of that letter being the right letter is pretty high compared to the rest of the confidences, but some other letter always beats it by a little bit. And my algorithm doesn't care about 2nd place. Therefore, I need another way!
I tried abandoning the hmm and for each letter in the test name, find the prediction of that letter, independent of the rest of the letters in the name. I found the prediction by taking the max over all confidences for each of the 26 possibilities. Then, in the end, I find the nearest neighbor of the predicted name with all of the names in the roster. This also did horribly.
I took a look at what was going on under the covers. I found that for each letter, the confidence of that letter being the right letter is pretty high compared to the rest of the confidences, but some other letter always beats it by a little bit. And my algorithm doesn't care about 2nd place. Therefore, I need another way!
Monday, March 2, 2009
Huh. How 'bout dat
Well. My real road block at this point was extracting letters from the test data character boxes because I lost my code from last year. But losing the code wasn't the real bad part - the code wasn't very good in the first place. It had all sorts of hough transforms in it.
Instead, I decided to take a blank sheet and do normalized cross correlation with it against a filled in box. This way, I could find the center of the filled in boxes. I basically figured out how big the boxes are, and can now extract the letter mo' betta. The red circle is where the normalized cross correlation signal was the strongest.
Zample:
To extract the letters, I found that the thickness of the character box lines were about 3 pixels wide so I took this into account.
The result:
Yee-haw. I took the output of this and fed it into my "get rid of white space" function, and resized the letters to 24 by 24 pixels. I also checked if the sum of the pixels of the character image are above a certain threshold, and if so, I assumed there was no letter there. I display these as gray cells with an x through them. This resulted in the following:
Here is another zample.
There is an issue though. SOME people (I'm not going to name any names) cannot write inside character boxes. Here is an example:
Because of that last 'a', my algorithm thinks there's a legitimate character there. See:
However, as far as I can tell, if someone can't keep their characters inside the boxes, they don't deserve to get their quiz graded! They can play games... but so can we! They want to play games, so be it! Let the games begin!
Instead, I decided to take a blank sheet and do normalized cross correlation with it against a filled in box. This way, I could find the center of the filled in boxes. I basically figured out how big the boxes are, and can now extract the letter mo' betta. The red circle is where the normalized cross correlation signal was the strongest.
Zample:
To extract the letters, I found that the thickness of the character box lines were about 3 pixels wide so I took this into account.
The result:
Yee-haw. I took the output of this and fed it into my "get rid of white space" function, and resized the letters to 24 by 24 pixels. I also checked if the sum of the pixels of the character image are above a certain threshold, and if so, I assumed there was no letter there. I display these as gray cells with an x through them. This resulted in the following:
Here is another zample.
There is an issue though. SOME people (I'm not going to name any names) cannot write inside character boxes. Here is an example:
Because of that last 'a', my algorithm thinks there's a legitimate character there. See:
However, as far as I can tell, if someone can't keep their characters inside the boxes, they don't deserve to get their quiz graded! They can play games... but so can we! They want to play games, so be it! Let the games begin!
Testing out the classifiers
I created and saved off 26 different classifiers - 1 for each lower case letter. I started out with 5000 haar-like features and brought it down to 200. So now, the feature vectors will be of length 200. I chose 200 because I found that after 200, there was no improvement in performance. Take a look at the following graph:
As you can see, performance is saturated after 180 iterations. This threshold varies for the different letters, but 200 is always enough from what I've seen.
I spent the majority of my time this weekend dealing with my old code for extracting letters from test data. To remind you, I am given something like:
... and I need to extract all of these letters. I wrote code for this last year but seem to have lost it :) So, I wrote new code to extract the letters which was time consuming. I am not entirely happy with the result of the code either, but I'll deal with it for now.
Given 4 images of 1 type of letter that were automatically extracted with the code I wrote, I ran a number of the 26 different classifiers on them to find the confidences. Confidence ranges from 0 to 1 where 1 indicates that it is 100% confident that the letter is a true instance, and 0 means the classifier is 100% confident that the letter is a false instance.
Here are 4 examples of the letter 'n':
So, the 'n' classifier does the best, which is a relief. However, these numbers can be pretty close, so hopefully the roster information will take care of this.
I wrote another perl script to generate the transition probabilities because I seem to have lost my old one also. Given that the current letter is 'x', I find the probability that the next letter is a 'y' by dividing the number of occurrences of the string 'xy' by the number of occurrences of the letter 'x'.
As you can see, performance is saturated after 180 iterations. This threshold varies for the different letters, but 200 is always enough from what I've seen.
I spent the majority of my time this weekend dealing with my old code for extracting letters from test data. To remind you, I am given something like:
... and I need to extract all of these letters. I wrote code for this last year but seem to have lost it :) So, I wrote new code to extract the letters which was time consuming. I am not entirely happy with the result of the code either, but I'll deal with it for now.
Given 4 images of 1 type of letter that were automatically extracted with the code I wrote, I ran a number of the 26 different classifiers on them to find the confidences. Confidence ranges from 0 to 1 where 1 indicates that it is 100% confident that the letter is a true instance, and 0 means the classifier is 100% confident that the letter is a false instance.
Here are 4 examples of the letter 'n':
Classifier Image 1 Image 2 Image 3 Image 4
n 0.4799 0.4897 0.5225 0.5120
a 0.3878 0.4333 0.3969 0.3969
b 0.4337 0.4499 0.4552 0.4967
c 0.3715 0.3448 0.3443 0.3232
So, the 'n' classifier does the best, which is a relief. However, these numbers can be pretty close, so hopefully the roster information will take care of this.
I wrote another perl script to generate the transition probabilities because I seem to have lost my old one also. Given that the current letter is 'x', I find the probability that the next letter is a 'y' by dividing the number of occurrences of the string 'xy' by the number of occurrences of the letter 'x'.
Subscribe to:
Posts (Atom)