Здравствуйте.
Мне нужно использовать библиотеку liblinear в моей программе на C#. Я экспортировал её в dll. функции вроде вызываются, но программа падает от ошибок работы с памятью, а именно, скорее всего потому, что происходят ошибки при её освобождении или она вообще не освобождается.
то что было
struct feature_node
{
int index;
double value;
};
struct problem
{
int l, n;
int *y;
struct feature_node **x;
double bias; /* < 0 if no bias term */
};
enum { L2R_LR, L2R_L2LOSS_SVC_DUAL, L2R_L2LOSS_SVC, L2R_L1LOSS_SVC_DUAL, MCSVM_CS, L1R_L2LOSS_SVC, L1R_LR, L2R_LR_DUAL }; /* solver_type */
struct parameter
{
int solver_type;
/* these are for training only */
double eps; /* stopping criteria */
double C;
int nr_weight;
int *weight_label;
double* weight;
};
struct model
{
struct parameter param;
int nr_class; /* number of classes */
int nr_feature;
double *w;
int *label; /* label of each class */
double bias;
};
__declspec(dllexport) struct model* train(const struct problem *prob, const struct parameter *param);
__declspec(dllexport) void cross_validation(const struct problem *prob, const struct parameter *param, int nr_fold, int *target);
__declspec(dllexport) int predict_values(const struct model *model_, const struct feature_node *x, double* dec_values);
__declspec(dllexport) int predict(const struct model *model_, const struct feature_node *x);
__declspec(dllexport) int predict_probability(const struct model *model_, const struct feature_node *x, double* prob_estimates);
__declspec(dllexport) int save_model(const char *model_file_name, const struct model *model_);
__declspec(dllexport) int save_model_and_clean(char *model_file_name, struct model *model_,parameter* param);
__declspec(dllexport) struct model *load_model(const char *model_file_name);
__declspec(dllexport) int get_nr_feature(const struct model *model_);
__declspec(dllexport) int get_nr_class(const struct model *model_);
__declspec(dllexport) void get_labels(const struct model *model_, int* label);
__declspec(dllexport) void free_model_content(struct model *model_ptr);
__declspec(dllexport) void free_and_destroy_model(struct model **model_ptr_ptr);
__declspec(dllexport) void destroy_param(struct parameter *param);
__declspec(dllexport) const char *check_parameter(const struct problem *prob, const struct parameter *param);
__declspec(dllexport) int check_probability_model(const struct model *model);
__declspec(dllexport) void set_print_string_function(void (*print_func) (const char*));
это как я объявил функции в C# программе
unsafe struct LiBlinear
{
public struct feature_node
{
public int index;
public double value;
};
public struct problem
{
public int l, n;
public int* y;
public feature_node** x;
public double bias; /* < 0 if no bias term */
};
public struct parameter
{
public int solver_type;
/* these are for training only */
public double eps; /* stopping criteria */
public double C;
public int nr_weight;
public int* weight_label;
public double* weight;
};
public struct model
{
public parameter param;
public int nr_class; /* number of classes */
public int nr_feature;
public double* w;
public int* label; /* label of each class */
public double bias;
};
public enum ENUM_ { L2R_LR, L2R_L2LOSS_SVC_DUAL, L2R_L2LOSS_SVC, L2R_L1LOSS_SVC_DUAL, MCSVM_CS, L1R_L2LOSS_SVC, L1R_LR, L2R_LR_DUAL }; /* solver_type */
[DllImport("LIBlinearDLL.dll", EntryPoint = "train")]
public static extern model* train( problem* prob, parameter* param);
[DllImport("LIBlinearDLL.dll")]
public static extern int predict_values(model* model_, feature_node* x, double* dec_values);
[DllImport("LIBlinearDLL.dll")]
public static extern int predict(model* model_, feature_node* x);
[DllImport("LIBlinearDLL.dll")]
public static extern int save_model(byte* model_file_name, model* model_);
[DllImport("LIBlinearDLL.dll")]
public static extern int save_model_and_clean(byte* model_file_name, model* model_, parameter* param);
[DllImport("LIBlinearDLL.dll")]
public static extern model* load_model(char* model_file_name);
[DllImport("LIBlinearDLL.dll")]
public static extern int get_nr_feature(model* model_);
[DllImport("LIBlinearDLL.dll")]
public static extern void free_and_destroy_model(model** model_ptr_ptr);
[DllImport("LIBlinearDLL.dll")]
public static extern void destroy_param(parameter* param);
}
собственно использование
const int NUM_FEATURES = 2000;
LiBlinear.problem prob = new LiBlinear.problem();
prob.l = selection.Count; // number of instances
prob.bias = -1; // bias feature
prob.n = NUM_FEATURES; // number of features + one for bias if needed
prob.y = (int*)Marshal.AllocCoTaskMem(prob.l); // allocate space for labels
prob.x = (LiBlinear.feature_node**)Marshal.AllocCoTaskMem(prob.l); // allocate space for features
for (int i = 0; i < prob.l; i++)
{
prob.x[i] = (LiBlinear.feature_node*)Marshal.AllocCoTaskMem(sizeof(LiBlinear.feature_node) * (NUM_FEATURES + 2));
prob.x[i][NUM_FEATURES].index = -1; // -1 marks the end of list
for (int j = 0; j < NUM_FEATURES; j++)
{
prob.x[i][j].index = 1 + j; // 1-based feature number
prob.x[i][j].value = selection[i][j];
}
prob.y[i] = labels[i];
selection[i].Clear();
}
selection.Clear();
LiBlinear.parameter param = new LiBlinear.parameter();
param.solver_type = (int)LiBlinear.ENUM_.L2R_L2LOSS_SVC_DUAL;
param.C = 1;
param.eps = 1e-4;
param.nr_weight = 0;
param.weight_label = null;
param.weight = null;
LiBlinear.model* model = LiBlinear.train(&prob, ¶m);
byte[] save_model_file_name=new byte[]{bla bla bla};
byte* save_name = (byte*)Marshal.AllocCoTaskMem(save_model_file_name.Length);
for (int i = 0; i < save_model_file_name.Length; i++)
save_name[i] = save_model_file_name[i];
LiBlinear.save_model_and_clean(save_name, model, ¶m);
Marshal.FreeCoTaskMem((IntPtr)save_name);
Marshal.FreeCoTaskMem((IntPtr)prob.y);
for (int i = 0; i < prob.l; i++) Marshal.FreeCoTaskMem((IntPtr)prob.x[i]);
Marshal.FreeCoTaskMem((IntPtr)prob.x);
если объем памяти используемой не очень велик, то иногда работает нормально, но умирает при повторных вызовах.
буду признателен за конструктивные предложения.
весь проект
здесь
Здравствуйте!
Вот отличная статья о том, как интегрировать Native(C++) код в C# проект. Надеюсь она вам поможет:
http://itw66.ru/blog/c_sharp/499.html
Может быть причина в использовании методов выделения памяти для взаимодействия с COM-объектами: Marshal.AllocCoTaskMem и Marshal.FreeCoTaskMem?
Кажется для выделения неуправляемой памяти в общем случае служат методы Marshal.AllocHGlobal и Marshal.FreeHGlobal, разве нет?