Skip to content

NullReferenceException thrown in Tensorflow.Binding.dll when trying to run EfficientDetD0 #1077

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

Open
vinayak-barman opened this issue May 18, 2023 · 35 comments

Comments

@vinayak-barman
Copy link

Description

 public class tfDetEngine : DetectionEngine
    {
        private readonly Session _session;

        public tfDetEngine(string modelPath, string labelPath) : base(modelPath, labelPath)
        {
            _session = Session.LoadFromSavedModel(modelPath);
        }

        public override IEnumerable<Detection> Detect(Tensor image)
        {

            using (_session)
            {
                try
                {
                    var tensors = _session?.eval(image);
                    if (tensors != null)
                    {
                        var boxesP = tensors["detection_boxes"].ToArray<float>();

                        var boxes = new float[boxesP.Length / 4][];
                        for (int i = 0; i < boxesP.Length; i += 4)
                        {
                            boxes[i / 4] = new float[] { boxesP[i], boxesP[i + 1], boxesP[i + 2], boxesP[i + 3] };
                        }

                        var scores = tensors["detection_scores"].ToArray<float>();
                        var classes = tensors["detection_classes"].ToArray<float>();

                        var detectedObjects = boxes.Select((box, i) => new Detection
                        {
                            Box = box,
                            Score = scores[i],
                            Class = classes[i]
                        });

                        return detectedObjects;
                    }

                    return new List<Detection>();
                }

                catch (NullReferenceException e)
                {
                    return new List<Detection>();
                }
            }
        }

I keep getting NullReferenceException thrown in Tensorflow.Binding.dll whenever I try to evaluate the model with a (512, 512, 3) sized image tensor

@AsakusaRinne
Copy link
Collaborator

Could you please provide the stack trace of the exception?

@vinayak-barman
Copy link
Author

vinayak-barman commented May 18, 2023

The stack trace goes here:
at Tensorflow.Tensor._as_tf_output()
at Tensorflow.BaseSession.eval(Tensor tensor)
at Detection.Engines.tfDetEngine.Detect(Tensor image)

@AsakusaRinne
Copy link
Collaborator

Please check if the image is an EagerTensor. Using an EagerTensor under graph mode may cause this problem.

@vinayak-barman
Copy link
Author

The tensor isn't an EagerTensor indeed
{tf.Tensor '' shape=(512, 512, 3) dtype=uint8}

@AsakusaRinne
Copy link
Collaborator

Could you please provide some steps to reproduce it? I don't know what DetectionEngine is.

@vinayak-barman
Copy link
Author

Here is the DetectionEngine class:

 public abstract class DetectionEngine
    {
        public DetectionEngine(string modelPath, string labelPath)
        {
            ModelPath = modelPath;
            LabelPath = labelPath;
        }
        public string ModelPath { get; set; }
        public string LabelPath { get; set; }
        public abstract IEnumerable<Detection> Detect(Tensor frame);
    }

Here is where I run inference:



        public void StartVideo()
        {
            var devices = new List<int>();
            while (devices.Count == 0)
            {
                devices = GetDevices();
            }

            Environment.SetEnvironmentVariable("TF_CPP_MIN_LOG_LEVEL", "2");  // Disable TensorFlow logs
            Environment.SetEnvironmentVariable("OMP_NUM_THREADS", "4");     // Set the number of threads

            new Thread(() => {
                engine = new tfDetEngine(@"C:\Users\softm\Downloads\efficientdet_d0_coco17_tpu-32\efficientdet_d0_coco17_tpu-32\saved_model", "");
            }).Start();
            

            foreach (int device in devices)
            {
                StartVideoDaemon(device);
            }
        }

        async Task StartVideoDaemon(int id)
        {
            await Task.Factory.StartNew(() =>
            {
                VideoCapture capture = new(id);
                Mat frame = new();
                Bitmap img;
                while (true)
                {
                    capture.Read(frame);
                    if (frame.Empty())
                    {
                        break;
                    }

                    Mat frameN = new Mat();
                    Cv2.Resize(frame, frameN, new Size(512, 512));

                    var detections = engine?.Detect(ToTensor(frameN));

                    using (MemoryStream memory = frameN.ToMemoryStream())
                    {
                        img = new Bitmap(memory);

                        var port = "port" + (id + 1);
                        Dispatcher.UIThread.InvokeAsync(() =>
                        {
                            var image = this.FindControl<Image>(port);
                            if (image != null)
                            {
                                image.Source = img;
                            }
                        });
                    }
                    Task.Delay(10);
                }
            });

        }


        public static unsafe Tensor ToTensor(Mat src)
        {
            NumSharp.Shape shape = (src.Height, src.Width, src.Type().Channels);
            SafeTensorHandle handle;
            var tensor = new Tensor(handle = c_api.TF_AllocateTensor(TF_DataType.TF_UINT8, shape.Dimensions.Select(d => (long)d).ToArray(), shape.NDim, (ulong)shape.Size));

            new UnmanagedMemoryBlock<byte>(src.DataPointer, shape.Size)
                .CopyTo((byte*)c_api.TF_TensorData(handle));

            return tensor;
        }

        List<int> GetDevices()
        {
            var devices = new List<int>();
            int i = 0;
            while (true)
            {
                var cap = new VideoCapture(i);
                if (cap.IsOpened())
                {
                    devices.Add(i);
                    i++;
                    continue;
                }
                break;
            }
            return devices;
        }

@vinayak-barman
Copy link
Author

@AsakusaRinne
Copy link
Collaborator

Ok, I'll reproduce it and give you a feedback later. Which version are you using?

@vinayak-barman
Copy link
Author

vinayak-barman commented May 18, 2023 via email

@AsakusaRinne
Copy link
Collaborator

The UnmanagedMemoryBlock and Dispatcher are not defined in the code. Is there any extra information?

@vinayak-barman
Copy link
Author

vinayak-barman commented May 18, 2023 via email

@AsakusaRinne
Copy link
Collaborator

The error is caused by some wrong usages. Note that tf.net has no longer depended on NumSharp, please use Tensorflow.Numpy instead. Here's an example without this problem:

using OpenCvSharp;
using System;
using System.Collections.Generic;
using System.Linq;
using Tensorflow;
using Tensorflow.NumPy;
using static Tensorflow.Binding;

namespace TensorFlowNET.UnitTest.Training
{
    public record class Detection(float[] Box, float Score, float Class);

    public abstract class DetectionEngine
    {
        public DetectionEngine(string modelPath, string labelPath)
        {
            ModelPath = modelPath;
            LabelPath = labelPath;
        }
        public string ModelPath { get; set; }
        public string LabelPath { get; set; }
        public abstract IEnumerable<Detection> Detect(NDArray frame);
    }

    public class tfDetEngine : DetectionEngine
    {
        private readonly Session _session;

        public tfDetEngine(string modelPath, string labelPath) : base(modelPath, labelPath)
        {
            _session = Session.LoadFromSavedModel(modelPath);
        }

        public override IEnumerable<Detection> Detect(NDArray image)
        {
            var graph = _session.graph;
            graph.as_default();
            try
            {
                var assigned = tf.convert_to_tensor(image, name: "input_image");
                bool a = tf.Context.executing_eagerly();
                var tensors = _session?.run(assigned);
                if (tensors != null)
                {
                    var boxesP = tensors["detection_boxes"].ToArray<float>();

                    var boxes = new float[boxesP.Length / 4][];
                    for (int i = 0; i < boxesP.Length; i += 4)
                    {
                        boxes[i / 4] = new float[] { boxesP[i], boxesP[i + 1], boxesP[i + 2], boxesP[i + 3] };
                    }

                    var scores = tensors["detection_scores"].ToArray<float>();
                    var classes = tensors["detection_classes"].ToArray<float>();

                    var detectedObjects = boxes.Select((box, i) => new Detection
                    (
                        Box: box,
                        Score: scores[i],
                        Class: classes[i]
                    ));

                    return detectedObjects;
                }

                return new List<Detection>();
            }

            catch (NullReferenceException e)
            {
                return new List<Detection>();
            }
            finally
            {
                graph.Exit();
            }
        }
    }
    [TestClass]
    public class ObjectDetection
    {
        tfDetEngine engine;

        [TestMethod]
        public void DetectionWithEfficientDet()
        {
            StartVideo();
        }

        public void StartVideo()
        {
            var devices = new List<int>();
            while (devices.Count == 0)
            {
                devices = GetDevices();
            }

            Environment.SetEnvironmentVariable("TF_CPP_MIN_LOG_LEVEL", "2");  // Disable TensorFlow logs
            Environment.SetEnvironmentVariable("OMP_NUM_THREADS", "4");     // Set the number of threads

            engine = new tfDetEngine(@"C:\Users\liu_y\Downloads\efficientdet_d0_coco17_tpu-32\saved_model", "");


            foreach (int device in devices)
            {
                StartVideoDaemon(device);
            }
        }

        void StartVideoDaemon(int id)
        {
            VideoCapture capture = new(id);
            Mat frame = new();
            System.Drawing.Bitmap img;
            while (true)
            {
                capture.Read(frame);
                if (frame.Empty())
                {
                    break;
                }

                Mat frameN = new Mat();
                Cv2.Resize(frame, frameN, new Size(512, 512));

                var detections = engine?.Detect(ToTensor(frameN));
            }

        }


        public unsafe NDArray ToTensor(Mat src)
        {
            Shape shape = (src.Height, src.Width, src.Type().Channels);
            SafeTensorHandle handle;
            var tensor = new Tensor(handle = c_api.TF_AllocateTensor(TF_DataType.TF_UINT8, shape.dims.Select(d => (long)d).ToArray(), shape.ndim, (ulong)shape.size));

            new Span<byte>((void*)src.DataPointer, (int)shape.size)
                .CopyTo(new Span<byte>((byte*)c_api.TF_TensorData(handle), (int)shape.size));

            return tensor.numpy();
        }

        List<int> GetDevices()
        {
            var devices = new List<int>();
            int i = 0;
            while (true)
            {
                var cap = new VideoCapture(i);
                if (cap.IsOpened())
                {
                    devices.Add(i);
                    i++;
                    continue;
                }
                break;
            }
            return devices;
        }
    }
}

However it will still fail when executing var boxesP = tensors["detection_boxes"].ToArray<float>();. I know few about object detection so that I can't figure what is expected. Please check it again.

@vinayak-barman
Copy link
Author

vinayak-barman commented May 18, 2023

_session.run still leaves me with a NullReferenceException, here is the stack trace

   at Tensorflow.BaseSession._call_tf_sessionrun(KeyValuePair`2[] feed_dict, TF_Output[] fetch_list, List`1 target_list)
   at Tensorflow.BaseSession._do_run(List`1 target_list, List`1 fetch_list, Dictionary`2 feed_dict)
   at Tensorflow.BaseSession._run(Object fetches, FeedItem[] feed_dict)
   at Tensorflow.BaseSession.run(Tensor fetche, FeedItem[] feed_dict)
   at Detection.Engines.tfDetEngine.Detect(NDArray image)

@AsakusaRinne
Copy link
Collaborator

Are you using exactly the code I listed before?

@vinayak-barman
Copy link
Author

yes, still doesn't work

@vinayak-barman
Copy link
Author

Could it be that I have an installation issue? I might have a broken installation of Tensorflow. How can I test that TensorFlow.net will run using a simpler model?

@AsakusaRinne
Copy link
Collaborator

Could it be that I have an installation issue? I might have a broken installation of Tensorflow. How can I test that TensorFlow.net will run using a simpler model?

Please refer to https://github.com/SciSharp/SciSharp-Stack-Examples/tree/master/src/TensorFlowNET.Examples and choose one or two simple models of it

@AsakusaRinne
Copy link
Collaborator

yes, still doesn't work

I can't reproduce it at this time. Is there any further information?

@vinayak-barman
Copy link
Author

I think I have issues with my tensorflow installation or something. Everything should work fine. I am using SciSharp.Tensorflow.Redist as my laptop doesn't have a GPU but my PC does. What steps should I follow to make sure that my initial setups are correct? I suspect my setup is faulty, as you have a perfectly running Tensorflow.Net implementation on your end.

@AsakusaRinne
Copy link
Collaborator

Sorry, my bad. My local environment is actually the master branch. Could you please try it again with master branch? Please clone it and add a project reference but keep tensorflow.redist installed. We'll publish a nightly release if master branch fixes this problem.

@vinayak-barman
Copy link
Author

Pardon, which repo do I have to clone now?

@AsakusaRinne
Copy link
Collaborator

Pardon, which repo do I have to clone now?

Please clone this repo and reference the src/TensorFlowNET.Core/tensorflow.net.csproj

@vinayak-barman
Copy link
Author

vinayak-barman commented May 18, 2023 via email

@AsakusaRinne
Copy link
Collaborator

Yup, that's it. I got it wrong.

@vinayak-barman
Copy link
Author

I tried it with the source code, but it gave me the same error, but a little detailed. When debugging, I notcied that _session.status is null. Here is the stack trace:

   at Tensorflow.Status.op_Implicit(Status status) in C:\Users\softm\Downloads\TensorFlow.NET\src\TensorFlowNET.Core\Status\Status.cs:line 102
   at Tensorflow.BaseSession._call_tf_sessionrun(KeyValuePair`2[] feed_dict, TF_Output[] fetch_list, List`1 target_list) in C:\Users\softm\Downloads\TensorFlow.NET\src\TensorFlowNET.Core\Sessions\BaseSession.cs:line 216
   at Tensorflow.BaseSession._do_run(List`1 target_list, List`1 fetch_list, Dictionary`2 feed_dict) in C:\Users\softm\Downloads\TensorFlow.NET\src\TensorFlowNET.Core\Sessions\BaseSession.cs:line 205
   at Tensorflow.BaseSession._run(Object fetches, FeedItem[] feed_dict) in C:\Users\softm\Downloads\TensorFlow.NET\src\TensorFlowNET.Core\Sessions\BaseSession.cs:line 133
   at Tensorflow.BaseSession.run(Tensor fetche, FeedItem[] feed_dict) in C:\Users\softm\Downloads\TensorFlow.NET\src\TensorFlowNET.Core\Sessions\BaseSession.cs:line 57

@vinayak-barman
Copy link
Author

Just curious, what should I put in the place of feed_dict params?

@AsakusaRinne
Copy link
Collaborator

Sorry for the confusion, I've fixed the error of null reference of status, could you please pull the newest master branch and try again?

@AsakusaRinne
Copy link
Collaborator

feed_dict

feed_dict is a parameter to specify some initial values for the parameters

@vinayak-barman
Copy link
Author

Now I get "Invalid slice notation: 'detection_boxes"

@AsakusaRinne
Copy link
Collaborator

Now I get "Invalid slice notation: 'detection_boxes"

Yes, that's the same with what acts like in my local environment. Since I don't know much about object detection, could you please further explain what you want by var boxesP = tensors["detection_boxes"].ToArray<float>();?

@vinayak-barman
Copy link
Author

So, I couldn't convert boxes to Float array directly, because it is nullable. I couldn't just write it as ToArray<float[]>(), it should actually be a two dimensional array, and the extra for loop is there trying to convert the float[] to float[][]

@AsakusaRinne
Copy link
Collaborator

What are tensors and boxesP expected to be in object detection?

@vinayak-barman
Copy link
Author

tensors is the detections from the model, and boxes are the bounding boxes from detections.

@vinayak-barman
Copy link
Author

vinayak-barman commented May 19, 2023

But graph has no nodes, everything shows 0. Maybe the model isn't loaded correctly?

@AsakusaRinne
Copy link
Collaborator

@Oceania2018 Could you please look at this issue?

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

2 participants