Khái quát về LiblinearLiblinear là 1 thư viện các công cụ sử dụng trong học máy, do nhóm nghiên cứu thuộc trường đại học Taiwan phát triển.Trang chủ tiếng Anh tại đây. Bài viết này sẽ cố gắng dịch, giải thích và 1 số ghi chú trong quá trình sử dụng Liblinear của cá nhân tôi. Tại thời điểm hiện tại, tôi viết bài này cho Liblinear bản mới nhất là Liblinear 1.9. Tùy theo phiên bản, sẽ có 1 số điểm khác nhau. Ví dụ như bản 1.8 và 1.9 hàm predict trả lại định dạng khác nhau : int với bản 1.8 và double với bản 1.9. Các cấu trúc dữ liệu cơ bảnstruct feature_node{ int index; double value; };
struct problem{ int l, n; double *y; struct feature_node **x; double bias; /* < 0 if no bias term */ };
struct parameter
struct model{ struct parameter param; int nr_class; /* number of classes */ int nr_feature; double *w; int *label; /* label of each class */ double bias; }; int save_model(const char *model_file_name, const struct model *model_); để lưu các model, và struct model *load_model(const char *model_file_name); để đọc các model từ file. Bạn không cần thiết phải hiểu quá rõ về cấu trúc model, vì thực tế bạn sẽ chỉ thao tác chủ yếu trên cấu trúc problem và feature_node, từ đó sử dụng các hàm có sẵn trong Liblinear để nhận lại model. Các model này ta sẽ chỉ sử dụng pointer để bê nó vào phần tham số của các hàm mà thôi.
Các thao tác cơ bản trên Liblineartrainstruct model* train(const struct problem *prob, const struct parameter *param); Dữ liệu được thay đổi kiểu thành problem cho phù hợp với Liblinear và đưa vào thông qua con trỏ. Tương tự với parameter . Sau khi huấn luyện, Liblinear sẽ trả lại 1 con trỏ chỉ đến model thu được. cross_validationvoid cross_validation(const struct problem *prob, const struct parameter *param, int nr_fold, double *target); predictdouble predict(const struct model *model_, const struct feature_node *x); Tham số là model và tập các đặc trưng feature_node . Hàm trả lại 1 giá trị dạng double , là 1 giá trị trong tập các nhãn của model . predict_probabilitydouble predict_probability(const struct model *model_, const struct feature_node *x, double* prob_estimates); save_modelint save_model(const char *model_file_name, const struct model *model_); load_modelstruct model *load_model(const char *model_file_name); get_nr_featureint get_nr_feature(const struct model *model_); get_nr_classint get_nr_class(const struct model *model_); get_labelsvoid get_labels(const struct model *model_, int* label); label trong model . free_model_contentvoid free_model_content(struct model *model_ptr); model . free_and_destroy_modelvoid free_and_destroy_model(struct model **model_ptr_ptr); model . destroy_paramvoid destroy_param(struct parameter *param); parameter . Cách sử dụng LiblinearCó 2 cách cơ bản để sử dụng Liblinear cũng như Libsvm là sử dụng như 1 chương trình riêng biệt, hoặc sử dụng như 1 thư viện.Sử dụng như một thư việnGiả sử ta có 1 project tên là Sample như sau :Sample |------------ sample.cpp Để sử dụng thư viện Liblinear, ta copy các file : linear.cpp, linear.h, tron.cpp, tron.h, thư mục blas vào dưới thư mục Sample. Ta sẽ được dạng sau : Sample |-------------blas |-------------linear.cpp |-------------linear.h |-------------tron.cpp | -------------tron.h |-------------sample.cpp Trong phần header của sample.cpp, ta khai báo thêm #include "linear.h" Sau đó ta có thể sử dụng các hàm xây dựng sẵn trong Liblinear mà tôi đã liệt kê ở trên. Sử dụng như 1 chương trình riêngBạn chỉ cần cài đặt giống như những chương trình linux miễn phí khác bằng lệnh configure và lệnh make.Liblinear có giao diện dòng lệnh cơ bản và không quá phức tạp. Bạn có thể tìm thấy trong phần hướng dẫn về Liblinear trên trang chủ. Để tạo ra các file có định dạng chuẩn cho Liblinear và Libsvm, bạn tham khảo thêm phần "quản lý problem". Một số đoạn code có íchDù Liblinear đã dựng sẵn cho ta 1 số thao tác cơ bản và cấu trúc dữ liệu, nhưng ta vẫn nên chỉnh sửa lại 1 chút để dễ dàng sử dụng và phát triển hơn. Ứng với mỗi cấu trúc dữ liệu cơ bản, tôi thường sử dụng 1 class tương ứng và các thao tác trên dữ liệu đó. Vì những thao tác này cũng không quá phức tạp nên tôi sẽ nhóm từng class vào 1 file .h chứ không để .h&.cpp. Quản lý và phân phối các chỉ số cho các feature và label
Quản lý các feature_node/* Debug : Done * class-Feats.h * * Created on: 2012/04/20 * Author: LUU TUAN ANH anh@jnlp.org */ #ifndef CLASS_FEATS_H_ #define CLASS_FEATS_H_ #include <set> #include <vector> using namespace std; typedef pair<int, set<int>*> Feat; class Feats { private: vector<Feat*> feats_; public: Feats() : feats_() {}; ~Feats() { for (vector<Feat*>::iterator it = feats_.begin(); it != feats_.end(); ++it) { delete (*it)->second; delete *it; } } int size() const { return static_cast<int>(feats_.size()); } const vector<Feat*>* get() const { return &feats_; } void push_back(Feat* f) { feats_.push_back(f); }; }; #endif /* CLASS_FEATS_H_ */ Quản lý problem/* Debug : done * class-Problem.h * * Created on: 2012/04/20 * Author: LUU TUAN ANH anh@jnlp.org */ #ifndef CLASS_PROBLEM_H_ #define CLASS_PROBLEM_H_ #include "linear.h" #include "class-Feats.h" //#include <fstream> using namespace std; template <class Feats> class Problem { private: problem problem_; public: Problem(const Feats* feats, int strnum) { // ofstream ofs(file_name); feature_node** x = new feature_node*[feats->size()]; double* y = new double[feats->size()]; for (int i = 0; i < static_cast<int>(feats->size()); ++i) { y[i] = double(feats->get()->at(i)->first); // ofs << y[i]; feature_node* xx = new feature_node[feats->get()->at(i)->second->size()+1]; x[i] = xx; int j = 0; for (set<int>::iterator it = feats->get()->at(i)->second->begin(); it != feats->get()->at(i)->second->end(); ++it) { xx[j].index = *it; xx[j].value = 1; // ofs << " " << xx[j].index << ":" << xx[j].value; ++j; } xx[j].index = -1; // ofs << endl; } problem_.l = feats->size(); problem_.n = strnum; problem_.y = y; problem_.x = x; problem_.bias = -1; // ofs.close(); } ~Problem() { for (int i = 0; i < problem_.l; ++i){ delete[] problem_.x[i]; } delete[] problem_.x; delete[] problem_.y; } problem* getProblem() { return &problem_; } }; #endif /* CLASS_PROBLEM_H_ */ Để tạo ra các file có định dạng chuẩn Liblinear và Libsvm, bạn chỉ cần bỏ đi các dấu comment. Quản lý parameter/* Debug : done * class-Parameter.h * * Created on: 2012/04/20 * Author: LUU TUAN ANH anh@jnlp.org */ #ifndef CLASS_PARAMETER_H_ #define CLASS_PARAMETER_H_ #include "linear.h" class Parameter { private: parameter parameter_; public: Parameter() { parameter_.solver_type = L2R_LR; // tùy theo dạng máy phân loại bạn muốn thực hiện parameter_.eps = 0.01; // mặc định parameter_.C = 1; // mặc định parameter_.nr_weight = 0; parameter_.weight_label = new int(1); parameter_.weight = new double(1.0); } Parameter(double c) { parameter_.solver_type = L2R_LR; parameter_.eps = 0.01; parameter_.C = c; parameter_.nr_weight = 0; parameter_.weight_label = new int(1); parameter_.weight = new double(1.0); } ~Parameter() { delete parameter_.weight_label; delete parameter_.weight; } const parameter* getParameter() const {return ¶meter_; } void set_c(double c) { parameter_.C = c; } }; #endif /* CLASS_PARAMETER_H_ */ |