onnx / onnx/models

Help tiny yolo v2

Open
#234 11 comments 0 reactions 1 assignee View on GitHub

@EmmaNingMS is already working on this.

Since Nov 6, 2019.

Dominant language
Jupyter Notebook
Stars
9.8k
Forks
1.6k
PR merge metrics
No merged PRs in 30d

Description

Hello

I want to use the onnx tiny yolo v2 in Android https://github.com/onnx/models/tree/master/vision/object_detection_segmentation/tiny_yolov2

My implementation is based on this one: https://github.com/tensorflow/tensorflow/blob/master/tensorflow/examples/android/src/org/tensorflow/demo/TensorFlowYoloDetector.java

I made it work but I always get (almost) the same output with different inputs (I use the VOC dataset):

[20975] tvmonitor (24.3%) RectF(0.0, 0.0, 415.0, 415.0)
[6600] horse (23.7%) RectF(0.0, 0.0, 401.00543, 399.01813)
[21075] bicycle (22.9%) RectF(0.0, 0.0, 415.0, 415.0)
[14550] aeroplane (21.4%) RectF(0.0, 0.0, 415.0, 415.0)

That's the output of this picture:
009667

I am not sure where is the problem, if I do the pre/post-processing wrong or the model is not correct. Because I tried to use the model from the original website with the same images and it works nice.

This is my preprocessing:

public float[] getFloatArrayFromResizedImage(Bitmap bm,int reqCH, int reqW, int reqH ) {
        int w = bm.getWidth();
        int h = bm.getHeight();
        if (reqW != w || reqH != h  ){
            
            bm = resizeImage(bm, reqW, reqH);
       
            w = bm.getWidth();
            h = bm.getHeight();
        }
    
      
        float[] data =  new float[reqCH * w * h];
        int[] intValues =  new int[w * h];
        bm.getPixels(intValues, 0, bm.getWidth(), 0, 0, bm.getWidth(), bm.getHeight());

        for (int i = 0; i < intValues.length; ++i) {
            float r = ((intValues[i] >> 16) & 0xFF) / 255.0f;
            float g = ((intValues[i] >> 8) & 0xFF) / 255.0f;
            float b =  (intValues[i] & 0xFF) / 255.0f;


            if(reqCH == 1){
                int gray = (int) (r * 0.3 + g * 0.59 + b * 0.11);

                    data[i] = gray;

                } else {
                    data[i * 3 + 0] = r;
                    data[i * 3 + 1] = g;
                    data[i * 3 + 2] = b;
                }
        }
return data;
    }

I know that the input format is NCHW, in this case, 1x3x416x416, I just wonder what it means, should I feed the model with an 1D array of size 3x416x416 in this format [R,G,B,R,G,B,R,G,B....] (I use this right now) or this one: [R,R,R......, G,G,G.....B,B,B]??

Post-processing:

public List<Classifier.Recognition> postProcess(float[] output1) {


        int MAX_RESULTS = 5;

         int NUM_CLASSES = 20;

         int NUM_BOXES_PER_BLOCK = 5;
        final float[] output = output1;
               
           double[] ANCHORS = {
                1.08, 1.19,
                3.42, 4.41,
                6.63, 11.38,
                9.42, 5.11,
                16.62, 10.52
        };

           String[] LABELS = {
                "aeroplane",
                "bicycle",
                "bird",
                "boat",
                "bottle",
                "bus",
                "car",
                "cat",
                "chair",
                "cow",
                "diningtable",
                "dog",
                "horse",
                "motorbike",
                "person",
                "pottedplant",
                "sheep",
                "sofa",
                "train",
                "tvmonitor"
        };

             int blockSize = 32;

    
        final int gridWidth = 416 / blockSize;
        final int gridHeight = 416 / blockSize;
        

       //https://github.com/tensorflow/tensorflow/blob/master/tensorflow/examples/android/src/org/tensorflow/demo/Classifier.java
        final PriorityQueue<Classifier.Recognition> pq =
                new PriorityQueue<Classifier.Recognition>(
                        1,
                        new Comparator<Classifier.Recognition>() {
                            @Override
                            public int compare(final Classifier.Recognition lhs, final Classifier.Recognition rhs) {
                                // Intentionally reversed to put high confidence at the head of the queue.
                                return Float.compare(rhs.getConfidence(), lhs.getConfidence());
                            }
                        });

        for (int y = 0; y < gridHeight; ++y) {
            for (int x = 0; x < gridWidth; ++x) {
                for (int b = 0; b < NUM_BOXES_PER_BLOCK; ++b) {
                    final int offset =
                            (gridWidth * (NUM_BOXES_PER_BLOCK * (NUM_CLASSES + 5))) * y
                                    + (NUM_BOXES_PER_BLOCK * (NUM_CLASSES + 5)) * x
                                    + (NUM_CLASSES + 5) * b;

                    final float xPos = (x + expit(output[offset + 0])) * blockSize;
                    final float yPos = (y + expit(output[offset + 1])) * blockSize;

                    final float w = (float) (Math.exp(output[offset + 2]) * ANCHORS[2 * b + 0]) * blockSize;
                    final float h = (float) (Math.exp(output[offset + 3]) * ANCHORS[2 * b + 1]) * blockSize;

                    final float confidence = expit(output[offset + 4]);

                    int detectedClass = -1;
                    float maxClass = 0;

                    final float[] classes = new float[NUM_CLASSES];
                    for (int c = 0; c < NUM_CLASSES; ++c) {
                        classes[c] = output[offset + 5 + c];
                    }
                    softmax(classes);

                    for (int c = 0; c < NUM_CLASSES; ++c) {
                        if (classes[c] > maxClass) {
                            detectedClass = c;
                            maxClass = classes[c];
                        }
                    }

                    final float confidenceInClass = maxClass * confidence;
                    if (confidenceInClass > 0.2) {
                        final RectF rect =
                                new RectF(
                                        Math.max(0, xPos - w / 2),
                                        Math.max(0, yPos - h / 2),
                                        Math.min(416 - 1, xPos + w / 2),
                                        Math.min(416 - 1, yPos + h / 2));
                        System.out.println(LABELS[detectedClass] +", "+ detectedClass +", "+  confidenceInClass+", "+ rect);

                        pq.add(new Classifier.Recognition("" + offset, LABELS[detectedClass], confidenceInClass, rect));
                    }
                }
            }
        }
       
        final ArrayList<Classifier.Recognition> recognitions = new ArrayList<Classifier.Recognition>();
        for (int i = 0; i < Math.min(pq.size(), MAX_RESULTS); ++i) {
            recognitions.add(pq.poll());
        }
             
        return recognitions;
    }

void softmax(final float[] vals) {
        float max = Float.NEGATIVE_INFINITY;
        for (final float val : vals) {
            max = Math.max(max, val);
        }
        float sum = 0.0f;
        for (int i = 0; i < vals.length; ++i) {
            vals[i] = (float) Math.exp(vals[i] - max);
            sum += vals[i];
        }
        for (int i = 0; i < vals.length; ++i) {
            vals[i] = vals[i] / sum;
        }
    }

    private float expit(final float x) {
        return (float) (1. / (1. + Math.exp(-x)));
    }

do I do anything wrong? it seems to me that there is something wrong in the model weights because no matter the input I get almost the same output.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.