通过p/invoke从C#使用XGBoost DLL [英] Use XGBoost DLL from c# via p/invoke

查看:141
本文介绍了通过p/invoke从C#使用XGBoost DLL的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 XGBoost的 dll(libxgboost.dll)创建DMatrix(就像一个2D数组),并获取它具有多少列.它可以正常运行,直到在下面的代码的int cols = ...行中抛出System.AccessViolationException为止:

I'm trying to use XGBoost's dll (libxgboost.dll) to create a DMatrix (which is like a 2D array) and get how many columns it has. It runs fine until it throws a System.AccessViolationException at the int cols = ... line in the code below:

using System;
using System.Runtime.InteropServices;

namespace basicXgboost
{
  class Program
  {
    [DllImport("../../libs/libxgboost.dll", CharSet = CharSet.Auto)]
    public static extern int XGDMatrixCreateFromFile([MarshalAs(UnmanagedType.LPStr)] string file, int silent, IntPtr outputPtr);

    [DllImport("../../libs/libxgboost.dll", CharSet = CharSet.Auto)]
    public static extern int XGDMatrixNumCol(IntPtr dmatrixPtr, IntPtr dmatrixColumnsPtr);

    static void Main(string[] args)
    {
      IntPtr dmatrixPtr = Marshal.AllocHGlobal(1000000);
      IntPtr dmatrixColumnsPtr = Marshal.AllocHGlobal(10);

      int result = XGDMatrixCreateFromFile("../../libs/test.txt", 0, dmatrixPtr);
      int cols = XGDMatrixNumCol(dmatrixPtr, dmatrixColumnsPtr);

      Marshal.FreeHGlobal(dmatrixPtr);
      Marshal.FreeHGlobal(dmatrixColumnsPtr);
    }
  }
}

为什么访问由XGDMatrixNumCol(dmatrixPtr, dmatrixColumnsPtr)分配的非托管内存会导致System.AccessViolationException?

Why does accessing unmanaged memory allocated with XGDMatrixNumCol(dmatrixPtr, dmatrixColumnsPtr) cause a System.AccessViolationException?

一种可能是我对这些功能使用的pinvoke错误.下面是我使用的每个dll函数的定义:

One possibility might be that I'm using pinvoke incorrectly for these functions. Below are the definitions for each dll function I use:

XGDMatrixCreateFromFile()

/*!
 * \brief load a data matrix
 * \param fname the name of the file
 * \param silent whether print messages during loading
 * \param out a loaded data matrix
 * \return 0 when success, -1 when failure happens
 */
XGB_DLL int XGDMatrixCreateFromFile(const char *fname,
                                    int silent,
                                    DMatrixHandle *out);

XGDMatrixNumCol()

/*!
 * \brief get number of columns
 * \param handle the handle to the DMatrix
 * \param out The output of number of columns
 * \return 0 when success, -1 when failure happens
 */
XGB_DLL int XGDMatrixNumCol(DMatrixHandle handle,
                            bst_ulong *out);

此处是我的项目的仓库.我正在使用Visual Studio Enterprise 2015.它在Windows 10 Pro(64位)上以调试"模式(针对x64)构建.可以在此处.尽管链接的存储库确实包含libxgboost.dll的副本.

Here is the repo for my project. I'm using Visual Studio Enterprise 2015 . It's built in "Debug" mode (targeting x64) on Windows 10 Pro (64-bit). x64 binaries for libxgboost.dll can be found here. Although the linked repo does contain a copy of libxgboost.dll.

推荐答案

尝试使用似乎由DLL使用的调用约定Cdecl.

Try to use the calling convention Cdecl which seems to be used by the DLL.

此外,XGDMatrixCreateFromFile函数的签名是错误的.预期的参数不是指向您分配的某些内存的指针,但是该函数将自行分配内存,然后将指针作为输出参数返回.

Also, the signature of the XGDMatrixCreateFromFile function is wrong. The parameter expected is not a pointer to some memory allocated by you, but the function will allocate memory itself and then return the pointer as an output parameter.

尝试以下代码.请注意在XGDMatrixCreateFromFile函数的outputPtr参数上使用out关键字.

Try the following code. Note the use of the the out keyword on the outputPtr parameter in the XGDMatrixCreateFromFile function.

[DllImport("C:\\dev\\libs\\xgboost\\build\\Release\\libxgboost.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int XGDMatrixCreateFromFile([MarshalAs(UnmanagedType.LPStr)] string file, int silent, out IntPtr outputPtr);

[DllImport("C:\\dev\\libs\\xgboost\\build\\Release\\libxgboost.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int XGDMatrixNumCol(IntPtr dmatrixPtr, IntPtr dmatrixColumnsPtr);

static void Main(string[] args)
{
    IntPtr dmatrixPtr;
    IntPtr dmatrixColumnsPtr = Marshal.AllocHGlobal(10);

    int result = XGDMatrixCreateFromFile("C:\\dev\\libs\\xgboost\\demo\\data\\agaricus.txt.test", 0, out dmatrixPtr);
    int cols = XGDMatrixNumCol(dmatrixPtr, dmatrixColumnsPtr);

    Marshal.FreeHGlobal(dmatrixColumnsPtr);
}


此方法有效时,您还可以使用ulong数据类型简化调用以获取列数:


When this works, you can then also simplify the call to get the number of columns by using the ulong datatype:

[DllImport("C:\\dev\\libs\\xgboost\\build\\Release\\libxgboost.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int XGDMatrixCreateFromFile([MarshalAs(UnmanagedType.LPStr)] string file, int silent, out IntPtr outputPtr);

[DllImport("C:\\dev\\libs\\xgboost\\build\\Release\\libxgboost.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int XGDMatrixNumCol(IntPtr dmatrixPtr, out ulong dmatrixColumnsPtr);

static void Main(string[] args)
{
    IntPtr dmatrixPtr;
    ulong dmatrixColumns;

    int result = XGDMatrixCreateFromFile("C:\\dev\\libs\\xgboost\\demo\\data\\agaricus.txt.test", 0, out dmatrixPtr);
    int cols = XGDMatrixNumCol(dmatrixPtr, out dmatrixColumns);
}

这篇关于通过p/invoke从C#使用XGBoost DLL的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆