source: orange/source/orange/liblinear_interface.cpp @ 9409:7d3dab3e062b

Revision 9409:7d3dab3e062b, 10.3 KB checked in by janezd <janez.demsar@…>, 2 years ago (diff)

Fixed a warning in Visual Studio 10.0

Line 
1/*
2    This file is part of Orange.
3
4    Copyright 1996-2011 Faculty of Computer and Information Science, University of Ljubljana
5    Contact: janez.demsar@fri.uni-lj.si
6
7    Orange is free software: you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation, either version 3 of the License, or
10    (at your option) any later version.
11
12    Orange is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with Orange.  If not, see <http://www.gnu.org/licenses/>.
19*/
20
21#include <iostream>
22#include <sstream>
23
24#include <math.h>
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28#include <stdarg.h>
29#include "liblinear_interface.ppp"
30
31#define Malloc(type,n) (type *) malloc((n)*sizeof(type))
32
33// Defined in linear.cpp. If a new solver is added this should be updated.
34
35static const char *solver_type_table[]=
36{
37    "L2R_LR", "L2R_L2LOSS_SVC_DUAL", "L2R_L2LOSS_SVC", "L2R_L1LOSS_SVC_DUAL", "MCSVM_CS",
38    "L1R_L2LOSS_SVC", "L1R_LR", "L2R_LR_DUAL", NULL
39};
40
41/*
42 *The folowing load save functions are used for orange pickling
43 */
44
45/*
46 * Save the model to an std::ostream. This is a modified `save_model` function
47 * from `linear.cpp` in LIBLINEAR package.
48 */
49int linear_save_model_alt(ostream &stream, struct model *model_)
50{
51    int i;
52    int nr_feature=model_->nr_feature;
53    int n;
54    const parameter& param = model_->param;
55
56    if(model_->bias>=0)
57        n=nr_feature+1;
58    else
59        n=nr_feature;
60
61    int nr_classifier;
62    if(model_->nr_class==2 && model_->param.solver_type != MCSVM_CS)
63        nr_classifier=1;
64    else
65        nr_classifier=model_->nr_class;
66
67    stream.precision(17);
68
69    stream << "solver_type " << solver_type_table[param.solver_type] << endl;
70    stream << "nr_class " << model_->nr_class << endl;
71    stream << "label";
72    for(i=0; i<model_->nr_class; i++)
73        stream << " " << model_->label[i];
74    stream << endl;
75
76    stream << "nr_feature " << nr_feature << endl;
77
78    stream << "bias " << model_->bias << endl;
79
80    stream << "w" << endl;
81    for(i=0; i<n; i++)
82    {
83        int j;
84        for(j=0; j<nr_classifier; j++)
85            stream << model_->w[i*nr_classifier+j] << " ";
86        stream << endl;
87    }
88
89    if (stream.good())
90        return 0;
91    else
92        return -1;
93}
94
95/*
96 * Save linear model into a std::string.
97 */
98int linear_save_model_alt(string &buffer, struct model *model_)
99{
100    std::ostringstream strstream;
101    int ret = linear_save_model_alt(strstream, model_);
102    buffer = strstream.rdbuf()->str();
103    return ret;
104}
105
106/*
107 * Load a linear model from std::istream. This is a modified `load_model`
108 * function from `linear.cpp` in LIBLINEAR package.
109 */
110struct model *linear_load_model_alt(istream &stream)
111{
112    int i;
113    int nr_feature;
114    int n;
115    int nr_class;
116    double bias;
117    model *model_ = Malloc(model,1);
118    parameter& param = model_->param;
119
120    model_->label = NULL;
121
122    char cmd[81];
123    stream.width(80);
124    while(stream.good())
125    {
126        stream >> cmd;
127        if(strcmp(cmd, "solver_type")==0)
128        {
129            stream >> cmd;
130            int i;
131            for(i=0;solver_type_table[i];i++)
132            {
133                if(strcmp(solver_type_table[i],cmd)==0)
134                {
135                    param.solver_type=i;
136                    break;
137                }
138            }
139            if(solver_type_table[i] == NULL)
140            {
141                fprintf(stderr,"unknown solver type.\n");
142                free(model_->label);
143                free(model_);
144                return NULL;
145            }
146        }
147        else if(strcmp(cmd,"nr_class")==0)
148        {
149            stream >> nr_class;
150            model_->nr_class=nr_class;
151        }
152        else if(strcmp(cmd,"nr_feature")==0)
153        {
154            stream >> nr_feature;
155            model_->nr_feature=nr_feature;
156        }
157        else if(strcmp(cmd,"bias")==0)
158        {
159            stream >> bias;
160            model_->bias=bias;
161        }
162        else if(strcmp(cmd,"w")==0)
163        {
164            break;
165        }
166        else if(strcmp(cmd,"label")==0)
167        {
168            int nr_class = model_->nr_class;
169            model_->label = Malloc(int, nr_class);
170            for(int i=0;i<nr_class;i++)
171                stream >> model_->label[i];
172        }
173        else
174        {
175            fprintf(stderr,"unknown text in model file: [%s]\n",cmd);
176            free(model_->label);
177            free(model_);
178            return NULL;
179        }
180    }
181
182    nr_feature=model_->nr_feature;
183    if(model_->bias>=0)
184        n=nr_feature+1;
185    else
186        n=nr_feature;
187
188    int nr_classifier;
189    if(nr_class==2 && param.solver_type != MCSVM_CS)
190        nr_classifier = 1;
191    else
192        nr_classifier = nr_class;
193
194    model_->w=Malloc(double, n*nr_classifier);
195    for(i=0; i<n; i++)
196    {
197        int j;
198        for(j=0; j<nr_classifier; j++)
199            stream >> model_->w[i*nr_classifier+j];
200    }
201    if (stream.fail())
202        return NULL;
203    else
204        return model_;
205}
206
207/*
208 * Load a linear model from a std:string.
209 */
210struct model *linear_load_model_alt(string &buffer)
211{
212    std::istringstream str_stream(buffer);
213    return linear_load_model_alt(str_stream);
214}
215
216struct NodeSort{
217    bool operator () (const feature_node &lhs, const feature_node &rhs){
218        return lhs.index < rhs.index;
219    }
220};
221
222int countFeatures(const TExample &ex, bool includeMeta, bool includeRegular){
223    int count = 1;
224    if (includeRegular)
225        for (TExample::iterator i=ex.begin(); i!=ex.end(); i++)
226            if ((i->varType==TValue::INTVAR || i->varType==TValue::FLOATVAR) && i->isRegular() && i!=&ex.getClass())
227                count++;
228    if (includeMeta)
229        for (TMetaValues::const_iterator i=ex.meta.begin(); i!=ex.meta.end(); i++)
230            if ((i->second.varType==TValue::INTVAR || i->second.varType==TValue::FLOATVAR) && i->second.isRegular())
231                count++;
232    return count;
233}
234
235feature_node *feature_nodeFromExample(const TExample &ex, map<int, int> &indexMap, bool includeMeta=false, bool includeRegular=true){
236    //cout << "example " << endl;
237    int numOfNodes = countFeatures(ex, includeMeta, includeRegular);
238    /*if (includeRegular)
239        numOfNodes += ex.domain->attributes->size();
240    if (includeMeta)
241        numOfNodes += ex.meta.size();*/
242    feature_node *nodes = new feature_node[numOfNodes];
243    feature_node *ptr = nodes;
244    int index = 1;
245    int featureIndex = 1;
246    if (includeRegular){
247        for (TExample::iterator i=ex.begin(); i!=ex.end(); i++){
248            if ((i->varType==TValue::INTVAR || (i->varType==TValue::FLOATVAR && (*i==*i))) && i->isRegular() && i!=&ex.getClass()){
249                if (i->varType==TValue::INTVAR)
250                    ptr->value = (int) *i;
251                else
252                    ptr->value = (float) *i;
253                ptr->index = index;
254                if (indexMap.find(index)==indexMap.end()){
255                    ptr->index = featureIndex;
256                    indexMap[index] = featureIndex++;
257                } else
258                    ptr->index = indexMap[index];
259                //featureIndices.insert(index);
260                //cout << ptr->value << " ";
261                ptr++;
262            }
263            index++;
264        }
265    }
266    if (includeMeta){
267        feature_node *first = ptr;
268        for (TMetaValues::const_iterator i=ex.meta.begin(); i!=ex.meta.end(); i++){
269            if ((i->second.valueType==TValue::INTVAR || i->second.valueType==TValue::FLOATVAR) && i->second.isRegular()){
270                ptr->value = (float) i->second;
271                //ptr->index = index - i->first;
272                if (indexMap.find(i->first)==indexMap.end()){
273                    ptr->index = featureIndex;
274                    indexMap[i->first] = featureIndex++;
275                } else
276                    ptr->index = indexMap[i->first];
277                //featureIndices.insert(ptr->index);
278                ptr++;
279            }
280        }
281        //cout << endl << " sorting" << endl;
282        sort(first, ptr, NodeSort());
283    }
284    ptr->index = -1;
285    return nodes;
286}
287
288problem *problemFromExamples(PExampleGenerator examples, map<int, int> &indexMap, bool includeMeta=false, bool includeRegular=true){
289    problem *prob = new problem;
290    prob->l = examples->numberOfExamples();
291    prob->x = new feature_node* [prob->l];
292    prob->y = new int [prob->l];
293    prob->bias = -1.0;
294    feature_node **ptrX = prob->x;
295    int *ptrY = prob->y;
296    PEITERATE(iter, examples){
297        *ptrX = feature_nodeFromExample(*iter, indexMap, includeMeta, includeRegular);
298        *ptrY = (int) (*iter).getClass();
299        ptrX++;
300        ptrY++;
301    }
302    prob->n = indexMap.size();
303    //cout << "prob->n " << prob->n <<endl;
304    return prob;
305}
306
307void destroy_problem(problem *prob){
308    for (int i=0; i<prob->l; i++)
309        delete[] prob->x[i];
310    delete[] prob->x;
311    delete[] prob->y;
312}
313
314static void dont_print_string(const char *s){}
315
316TLinearLearner::TLinearLearner(){
317    solver_type = L2R_LR;
318    eps = 0.01f;
319    C=1;
320    set_print_string_function(&dont_print_string);
321}
322
323PClassifier TLinearLearner::operator()(PExampleGenerator examples, const int &weight){
324    //cout << "initializing param" << endl;
325    parameter *param = new parameter;
326    param->solver_type = solver_type;
327    param->eps = eps;
328    param->C = C;
329    param->nr_weight = 0;
330    param->weight_label = NULL;
331    param->weight = NULL;
332    //cout << "initializing problem" << endl;
333    map<int, int> *indexMap =new map<int, int>;
334    problem *prob = problemFromExamples(examples, *indexMap);
335    //cout << "cheking parameters" << endl;
336    const char * error_msg = check_parameter(prob, param);
337    if (error_msg){
338        delete param;
339        destroy_problem(prob);
340        raiseError("LIBLINEAR error: %s" , error_msg);
341    }
342    //cout << "trainig" << endl;
343    model *model = train(prob, param);
344    destroy_problem(prob);
345
346    return PClassifier(mlnew TLinearClassifier(examples->domain->classVar, examples, model, indexMap));
347}
348
349TLinearClassifier::TLinearClassifier(const PVariable &var, PExampleTable _examples, struct model *_model, map<int, int> *_indexMap){
350    classVar = var;
351    linmodel = _model;
352    examples = _examples;
353    domain = examples->domain;
354    indexMap = _indexMap;
355    computesProbabilities = check_probability_model(linmodel) != 0;
356    int nr_classifier = (linmodel->nr_class==2 && linmodel->param.solver_type != MCSVM_CS)? 1 : linmodel->nr_class;
357    weights = mlnew TFloatListList(nr_classifier);
358    for (int i=0; i<nr_classifier; i++){
359        weights->at(i) = mlnew TFloatList(linmodel->nr_feature);
360        for (int j=0; j<linmodel->nr_feature; j++)
361            weights->at(i)->at(j) = linmodel->w[j*nr_classifier+i];
362    }
363}
364
365TLinearClassifier::~TLinearClassifier(){
366    if (linmodel)
367        free_and_destroy_model(&linmodel);
368    if (indexMap)
369        delete indexMap;
370}
371
372PDistribution TLinearClassifier::classDistribution(const TExample &example){
373    int numClass = get_nr_class(linmodel);
374    map<int, int> indexMap;
375    feature_node *x = feature_nodeFromExample(example, indexMap, false);
376
377    int *labels = new int [numClass];
378    get_labels(linmodel, labels);
379
380    double *prob_est = new double [numClass];
381    predict_probability(linmodel, x, prob_est);
382
383    PDistribution dist = TDistribution::create(classVar);
384    for (int i=0; i<numClass; i++)
385        dist->setint(labels[i], prob_est[i]);
386
387    delete[] x;
388    delete[] labels;
389    delete[] prob_est;
390    return dist;
391}
392
393TValue TLinearClassifier::operator () (const TExample &example){
394    int numClass = get_nr_class(linmodel);
395    map<int, int> indexMap;
396    feature_node *x = feature_nodeFromExample(example, indexMap, false);
397
398    int predict_label = predict(linmodel ,x);
399    delete[] x;
400    return TValue(predict_label);
401}
402
Note: See TracBrowser for help on using the repository browser.