通过 p/invoke 从 c# 使用 XGBoost DLL
Use XGBoost DLL from c# via p/invoke
我正在尝试使用 XGBoost's dll (libxgboost.dll) 创建一个 DMatrix(就像一个二维数组)并获取它有多少列。它运行良好,直到它在下面代码的 int cols = ...
行抛出一个 System.AccessViolationException
:
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
?
一种可能是我错误地使用了这些函数的 pinvoke。下面是我使用的每个 dll 函数的定义:
/*!
* \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);
/*!
* \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);
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。尽管链接的 repo 确实包含 libxgboost.dll 的副本。
尝试使用DLL似乎使用的调用约定Cdecl。
此外,XGDMatrixCreateFromFile
函数的签名是错误的。预期的参数不是指向您分配的某些内存的指针,但函数将自己分配内存,然后 return 指针作为输出参数。
试试下面的代码。请注意 XGDMatrixCreateFromFile
函数中 outputPtr
参数上的 out
关键字的使用。
[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
数据类型简化获取列数的调用:
[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);
}
我正在尝试使用 XGBoost's dll (libxgboost.dll) 创建一个 DMatrix(就像一个二维数组)并获取它有多少列。它运行良好,直到它在下面代码的 int cols = ...
行抛出一个 System.AccessViolationException
:
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
?
一种可能是我错误地使用了这些函数的 pinvoke。下面是我使用的每个 dll 函数的定义:
/*!
* \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);
/*!
* \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);
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。尽管链接的 repo 确实包含 libxgboost.dll 的副本。
尝试使用DLL似乎使用的调用约定Cdecl。
此外,XGDMatrixCreateFromFile
函数的签名是错误的。预期的参数不是指向您分配的某些内存的指针,但函数将自己分配内存,然后 return 指针作为输出参数。
试试下面的代码。请注意 XGDMatrixCreateFromFile
函数中 outputPtr
参数上的 out
关键字的使用。
[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
数据类型简化获取列数的调用:
[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);
}