Skip to content

Consuming more time to pass object from .net to python #658

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

Closed
48naveen opened this issue Apr 11, 2018 · 10 comments
Closed

Consuming more time to pass object from .net to python #658

48naveen opened this issue Apr 11, 2018 · 10 comments

Comments

@48naveen
Copy link

48naveen commented Apr 11, 2018

Environment

  • Pythonnet version: master
  • Python version: 3.5
  • Operating System: Windows 7

Details

  • I am calling python function from my c# code . Initially I import python module using Py.Import function . After importing , will pass a List data type of size 299x299x3 to python function as argument . This passing of argument taking 1.5 seconds where as a block of python code takes only 90 msec .

Here is c# code

using(Py.GIL())
{
dynamic Python_predict = Py.Import("Prediction");
Python_predict.__init__(modelpath);


List<float> imagelist=GetNormalizedFloatBGRImage(image).Data.Cast<float>().ToList();
DateTime t1 = System.DateTime.Now;
Predicted_Type=Python_predict.Findtype(imagelist);
DateTime t2 = System.DateTime.Now;
Console.WriteLine("Predict timing from c# {0} seconds", (t2.Second + ((float)t2.Millisecond / 1000)) - (t1.Second + ((float)t1.Millisecond / 1000)));

}

Here is python code

def __init__(model_path):
        kr.model = kr.load_model(model_path) #Model is loaded only once
def Findtype(ImageData):
        t1=time.time()
        N_array = np.array(ImageData,dtype=np.float64)#creates Numpy array from .net List<float> array
        N_array_reshaped=np.reshape(N_array,(299,299,3))

        #convert BGR to RGB
        temp_array[:,:,0] = N_array_reshaped[:,:,2]#bgR -> Rgb 
        temp_array[:,:,2] = N_array_reshaped[:,:,0]#Bgr -> rgB
        temp_array[:,:,1] = N_array_reshaped[:,:,1]#bGr -> rGb
        img_list[0]=temp_array
        
        #prediction = kr.model.predict(img_list, batch_size=1, verbose=0) # Predictions can be made throughout the lifecycle of MakePrediction class's instance
        #predicted_class = np.argmax(prediction, axis=1)
        t2=time.time()
        print('time on python ',t2-t1)
        return predicted_class[0] + 1

So c# code send image array of size 2992993 of float time to python , by which it gets converted into numpy array and makes the prediction on gpu .
if i run the standalone python code , it takes 90msec but if i call from .net 1.5 sec for passing an argument .

Kindly help me to reduce the timing since it is for real time application .

here is a attached screenshots
untitled

@den-run-ai
Copy link
Contributor

@48naveen you should not use List when you need performance on either python or C# side. See how to pass numpy arrays to C# arrays here:

#514

@48naveen
Copy link
Author

@denfromufa Thanks a lot . Copying from memory pointer worked for me with lot more performance gain()
It would be very useful for users , if all these answers are made into a proper pythonnet usage documentation .

@den-run-ai
Copy link
Contributor

@48naveen yes contributions for docs are welcome!

@gkomix88
Copy link

@48naveen Hi, I am working on converting c# Bitmap to CV2 numpy array image. May I know how you copy from memory pointer?

for my scenario is, the c# program will call the python program and pass a Bitmap object to it, in which need to convert it to numpy array cv2 image compatible to further process.

Would you mind to share your idea or solution? Thanks in advance.

@lostmsu
Copy link
Member

lostmsu commented Aug 25, 2020

@gkomix88 you might want to look at Python Buffer Protocol and this PR (available in master)

@gkomix88
Copy link

gkomix88 commented Aug 27, 2020

@lostmsu thanks for the feedback.

Following are the codes to pass C# Bitmap to Python function.

C# :

dynamic np = Py.Import("numpy");
var watch = System.Diagnostics.Stopwatch.StartNew();
ImgLib.ProcImage(ref imageList, img.Width, img.Height); // imageList is c# Bitmap in List type after remove Alpha
watch.Stop();
var elapsedMs = watch.ElapsedMilliseconds;

Python (ImgLib.py file):

def ProcImage(img, w, h):
img= np.array(img, np.uint8).reshape(h,w,3) # this part took more than 1000 ms to process
# do some image processing ...
cv2.imwrite("test.jpg", img)

=================

May I know how to implement Python Buffer Protocol? I tried adding memoryview(img). but the memoryview itself will took 1000ms too. If save the bitmap file from c# and cv2.imread from python only too 100++ms 10 times faster. I want it faster without secondary IO. Any suggestion?

I also tried #514 using Numsharp NDArray. But it slower than the above method.

@lostmsu
Copy link
Member

lostmsu commented Aug 27, 2020

You need to write something like https://github.com/koubaa/pythonnet/blob/0ed417ca4606f5f235cb938863bab6c96068f686/src/embed_tests/TestPyBuffer.cs#L29

Then pass bytearray to NumPy.

@gkomix88
Copy link

gkomix88 commented Aug 27, 2020

Thanks for the feedback.
The PyBuffer class seem like is not available on the latest Python.Runtime.

Would it be the same as follows?

def ProcImage(img, w, h):
image_bytes = bytearray(img) # convert to byte array then pass to numpy
img= np.array(image_bytes, np.uint8).reshape(h,w,3)

The processing time improved a bit to 1120ms but still quite slow. The image process is 1197w x 797h pixels.

@gkomix88
Copy link

gkomix88 commented Nov 16, 2020

You need to write something like https://github.com/koubaa/pythonnet/blob/0ed417ca4606f5f235cb938863bab6c96068f686/src/embed_tests/TestPyBuffer.cs#L29

Then pass bytearray to NumPy.

Hi, I follow your advice to build the pythonnet-master. However, the following error show when imported the built python.runtime.dll to the c# application:

System.DllNotFoundException: 'Unable to load DLL 'python3.7': The specified module could not be found. (Exception from HRESULT: 0x8007007E)'

I configured the build to x64, PYTHON37, pointing the PYTHONHOME path to python folder etc. The following is the code:


string pythonPath = @"C:\Python37";
Environment.SetEnvironmentVariable("PYTHONHOME", pythonPath);
Environment.SetEnvironmentVariable("PYTHONPATH ", $@"{pythonPath}\Lib;{pythonPath}\Lib\site-packages;");
PythonEngine.PythonHome = Environment.GetEnvironmentVariable("PYTHONHOME", EnvironmentVariableTarget.Process); // error here
PythonEngine.PythonPath = Environment.GetEnvironmentVariable("PYTHONPATH", EnvironmentVariableTarget.Process);


I tested with pythonnet git (not master) no error. But with pythonnet master the error show up.

Can provide help? Thanks in advance. I need to use PyBuffer (only available in master) to speed up the Bitmap passing from C# to python without writing to disk.

@gkomix88
Copy link

Hi, @lostmsu , I manage to make it run by install the python lib with local pythonnet source directory. Thanks.

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

No branches or pull requests

4 participants