How do we use our model against a specific image?

multi_preds, y = learn.TTA(),
preds = np.mean(multi_preds, 0)

Is this what you man?
Just have a look at lesson 2 NB…

No. The result coming back from the individual predictions just don’t match the ones from the TTA, even after I post process them to turn them back into what I think should be the actual pred. So for this project I am just going to use the TTA method.

I put together a first cut at a UI for the classifier and came up with something like this. You can drag images into the top zone and it will load below, passing the image through the classifier and getting the predictions.

Not using the TTA method btw, just the plain predict(isTest=True)

1 Like

Can you share how did you create the app/on web hosted or something?

I also want to create one but need a bit help from the community…

1 Like

I will clean things up a bit and post some code.

I used flask for my little API. I needed to handle a file (Image) upload, and after trying and failing with django, I found flask to be trivial.

Please see the code below.

Some notes. This is for a hackahon, and I have definitely done a hack to predict the images one at a time. I wanted to use 'learner.predict_array() to predict a single image, but the results were never clear to me. What I ended up doing is this. I trained the model in a separate process, similar to what was done in class and in the notebooks. Before I start the flask api, I ensure a single image is in the test directory called ‘placeholder.jpg’. When the api starts up, it creates the pre-trained model and loads the saved trained model.

One endpoint is exposed ‘/upload’ which takes a multi-part form request (typical file upload), extracts the image, saves it in place of the placeholder.jpg image. It then asks the model to predict in test mode. I get the predictions back, do a bit of post-processing, and return a JSON map back to the client. Again, this will work fine for the hackathon, but is def not the ideal way to do single image classification. But then again, I understand that is not necessarily the point of the library. This is just what I am doing to shoehorn that functionality in.

Here is the flask code.

        import os
        import time
        import json
        from flask import Flask, render_template, request
        from fastai.conv_learner import *

        app = Flask(__name__, static_url_path='/static')
        print("Starting flask app...")

        PATH = 'data/shopstyle/'
        f_model = resnet34
        label_csv = f'{PATH}prod_train.csv'
        n = len(list(open(label_csv)))-1
        val_idxs = get_cv_idxs(n)
        sz = 128

        def get_data(sz):
            tfms = tfms_from_model(f_model, sz, aug_tfms=transforms_side_on, max_zoom=1.05)
            return ImageClassifierData.from_csv(PATH, 'train', label_csv, tfms=tfms, suffix='.jpg', val_idxs=val_idxs, test_name='test')

        data = get_data(sz)
        learn = ConvLearner.pretrained(f_model, data)

        def load_model():
            print("Loading model...")
            learn.load(f'{sz}')
            learn.precompute=False

        load_model()

        @app.route('/upload', methods=['POST'])
        def upload_file():
            print("cleaning test dir")
            for root, dirs, files in os.walk(PATH+'/test'):
                for f in files:
                    os.unlink(os.path.join(root, f))
            file = request.files['file']
            f = os.path.join(PATH+"/test", 'placeholder.jpg')
            file.save(f)


            start_time = time.process_time()
            load_model();
            test_preds = learn.predict(is_test=True)
            end_time = time.process_time()
            print("Elapsed time: %.9f" % (end_time-start_time))
            tuples = list(zip(data.classes, test_preds[0]))
            #convert to a float
            tuples = list(map(lambda x: (x[0], float(x[1])), tuples))
            #throw away anything less than 0.1
            result = [item for item in tuples if item[1] > 0.1]
            #return up to 5 categories
            return json.dumps(dict(result[:5])
12 Likes

Thanks a lot…
I will try it today itself and will ping you if I ran into some issues…

Legal issues with the dataset?

1 Like

There is nothing proprietary in this dataset, but since I built it with company data I have to get permission first. Still working on that

Hi @binarypoet This is what worked for me for testing against a single image.

im = val_tfms(open_image(f’{PATH}’+fn)) – Load Image using fastai open_image in dataset.py
learn.precompute=False # We’ll pass in a raw image, not activations
log_preds_single = learn.predict_array(im[None]) – Predict Image
maxP = np.argmax(log_preds_single,axis=1) – Pick the index with highest log probability
probs_single = np.exp(log_preds_single) – If you want the probabilities of the classes
actualclass = data.classes[maxP[0]]

I think the key observation from the above line / code is that the actual classes that you have are one hot encoded and the mapping is in data.classes so you have to look up the actual class from data.classes. Hope this helps

2 Likes

Can you just wrap your code With Three `(top and bottom)

It will make it easier for anyone in future…

Thanks

@ecdrid Wrap your code with Three ?

If the intention is to wrap the code in a function, here it is.

def predictSingleImage(fn):
    im = val_tfms(open_image(f'{PATH}'+fn)) # Load Image using fastai open_image in dataset.py
    learn.precompute=False # We’ll pass in a raw image, not activations
    log_preds_single = learn.predict_array(im[None]) # Predict Image
    maxP = np.argmax(log_preds_single,axis=1) # Pick the index with highest log probability
    probs_single = np.exp(log_preds_single) # If you want the probabilities of the classes
    actualclass = data.classes[maxP[0]] # Look up tactualPT   return actualclass
    return actualclass
4 Likes

I just did that - hope that’s OK @binarypoet

Hello, I am getting this error using this code…

AttributeError Traceback (most recent call last)
in ()
1 trn_tfms, val_tfrms = tfms_from_model(arch, 224)
----> 2 im = val_tfrms(PIL.Image.open(’/home/ubuntu/data/sleevelength/sleeve_length_validation/valid/sleeveless/11459845282725-Vishudh-Black–Red-Printed-Kurta-9521459845282239-1.jpg’))
3


AttributeError: ‘JpegImageFile’ object has no attribute ‘shape’

What am i missing here?

See above here: How do we use our model against a specific image?

There was another user getting same error and the remedy (hopefully) lies in the comment right below the post I linked too.

thanks WG, yes i did find it after commenting :stuck_out_tongue:

Hi,
I’m learning with Cats & Dogs classification.
I’m trying to predict a specific image as follow:

trn_tfms, val_tfms = tfms_from_model(resnet34, sz, aug_tfms = transforms_side_on, max_zoom = 1.1)
im = val_tfms(np.array(Image.open(fname)))

pred1 = learn.predict_array(im[None])
prob = np.argmax(np.exp(pred1))

However, the results of prob is always 0
I found out the pred1 always the following results:
array([[ 0. ,negative_number]], dtype=float32)

Example:
array([[ 0. , -106.45783]], dtype=float32)

It doesn’t matter if the image is dog or cat, the first element of pred1 is always 0.

My learn model has accuracy of 99.3% and the confusion matrix was pretty good.
I’ve checked my learn.data.classes it is ['cats', 'dogs']

Does anybody have similar issue?

I am trying to predict the label for a specific image using code sharing on this thread. I also seeing the different result between predict(isTest=true) and the predict_array() function. I try scaling img/255 before converting it to numpy and now it works. The two results are identical !

1 Like

Try np.array(Image.open(fname))/255. I have a similar issue when working on my dataset. Scaling 1/255 works for me.

2 Likes

Thank you @quangduong! I’ll give it a try as soon as I can.

Thank you @quangduong it works.
What is the reason behind it, why do we need to scale it ?
I don’t see that during the training, so why do we have to divide by 255 during the prediction.