├── COPYRIGHT-libsvm ├── FAQ.html ├── LICENSE-libMR.txt ├── LICENSE-libsvm-openset.txt ├── Makefile ├── Makefile.win ├── README ├── README-libsvm-openset ├── heart_scale ├── java ├── Makefile ├── libsvm.jar ├── libsvm │ ├── svm.java │ ├── svm.m4 │ ├── svm_model.java │ ├── svm_node.java │ ├── svm_parameter.java │ ├── svm_print_interface.java │ └── svm_problem.java ├── svm_predict.java ├── svm_scale.java ├── svm_toy.java ├── svm_train.java └── test_applet.html ├── matlab ├── Makefile ├── README ├── libsvmread.c ├── libsvmwrite.c ├── make.m ├── svm_model_matlab.c ├── svm_model_matlab.h ├── svmpredict.c └── svmtrain.c ├── python ├── Makefile ├── README ├── svm.py └── svmutil.py ├── svm-analyze.c ├── svm-predict.cpp ├── svm-scale.c ├── svm-toy ├── gtk │ ├── Makefile │ ├── callbacks.cpp │ ├── callbacks.h │ ├── interface.c │ ├── interface.h │ ├── main.c │ └── svm-toy.glade ├── qt │ ├── Makefile │ └── svm-toy.cpp └── windows │ └── svm-toy.cpp ├── svm-train.cpp ├── svm.cpp ├── svm.def ├── svm.h └── tools ├── README ├── checkdata.py ├── easy.py ├── grid.py └── subset.py /COPYRIGHT-libsvm: -------------------------------------------------------------------------------- 1 | Copyright (c) 2000-2011 Chih-Chung Chang and Chih-Jen Lin 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright 12 | notice, this list of conditions and the following disclaimer in the 13 | documentation and/or other materials provided with the distribution. 14 | 15 | 3. Neither name of copyright holders nor the names of its contributors 16 | may be used to endorse or promote products derived from this software 17 | without specific prior written permission. 18 | 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR 24 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 25 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 26 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 27 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 28 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 29 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | -------------------------------------------------------------------------------- /LICENSE-libMR.txt: -------------------------------------------------------------------------------- 1 | SOURCE CODE LICENSE AGREEMENT 2 | PREAMBLE 3 | 4 | This SOFTWARE implements concepts of statistical Meta-recognition for which Securics/Univ. of Colorado have a pending patent (CU TTO File CU2338C). Securics and University of Colorado, hereafter The Owners, have joint interest in the invention and the software. Securics currently holds the excusive license commercial to both the patent and the code. Securcs, hereafter the Licensor, is offering a non-exclusive right to use for non-commecial use. 5 | 6 | 7 | This license agreement allows you to use the source code for personal or non profit purposes. This includes any use that does not involve making money, and does not include uses like: 8 | • deploying the software for use by a for-profit organization 9 | • providing a service to a paying customer 10 | For-profit companies may not use this source code. If you work for a for-profit company, you may only use this software as an individual, for your personal use. 11 | 12 | This is a right to use license. It does not not include the right to redistribute copies. Non-profit users can only use the copies obtained from authroized sourcehs which include: securics.com, metarecognition.com or vast.uccs.edu. 13 | 14 | This license agreement also allows you to create derivative products for your own use, but does not permit re-distribute 15 | of modified code in any form. You may choose to destribute patch files, which can be applied to officially distributed 16 | code. Any the derivative products, must be distributed under the same conditions as specified in this agreement unless 17 | a separate commercial license is obtained from Securics Inc or its designates. 18 | 19 | As a condition of using this source code, you agree not to assert any patents or copyrights against the owners or any of 20 | the Owners’ licensees for use of derivative products. Any derivative products must include a copy of license and 21 | instructions for accessing the orignal source. You must also include attribution to the authors in any publication that 22 | results from the use of this code or data derived from the code. Any papers/research/report based on results that uses 23 | this software must cite: 24 | 25 | @article{Scheirer_2011_TPAMI, 26 | author = {Walter J. Scheirer and Anderson Rocha and Ross Michaels and Terrance E. Boult}, 27 | title = {Meta-Recognition: The Theory and Practice of Recognition Score Analysis}, 28 | journal = {IEEE Transactions on Pattern Analysis and Machine Intelligence (PAMI)}, 29 | volume = {33}, 30 | issue = {8}, 31 | pages = {1689--1695}, 32 | year = {2011} 33 | } 34 | 35 | 36 | Parts of this technology are subject to SBIR data rights and as described in DFARS 252.227-7018 (June 1995) SBIR Data Rights which apply to Contract Number: N00014-11-C-0243 and STTR N00014-07-M-0421 to Securics Inc, 1870 Austin Bluffs Parkway, Colorado Springs, CO 80918 37 | 38 | The Government's rights to use, modify, reproduce, release, perform, display, or disclose technical data or computer software marked with this legend are restricted during the period shown as provided in paragraph (b)(4) of the Rights in Noncommercial Technical Data and Computer Software-Small Business Innovative Research (SBIR) Program clause contained in the above identified contract. Expiration of SBIR Data Rights: Expires four years after completion of the above cited project work for this or any other follow-on SBIR contract, whichever is later. 39 | 40 | No restrictions on government use apply after the expiration date shown above. Any reproduction of technical data, computer software, or portions thereof marked with this legend must also reproduce the markings. 41 | 42 | 43 | 44 | 45 | 46 | This license includes other conditions that should be read carefully. This SOFWARE usage agreement (the "Agreement") applies to the libMR and is between YOU and the Licensor 47 | 48 | 1. DEFINITIONS 49 | 50 | "Software" means all or any portion of the human-readable source code files of the software programs including without limitation, associated flow charts, algorithms, comments and other written instructions and technical documentation, and all corrections, updates, and new versions incorporated into such programs. 51 | 52 | “Derivative Work” means a work based upon the Software, such as a revision, modification, translation, abridgement, condensation, expansion, collection, compilation, or any other form in which the Software may be recast, transformed, adapted, or distributed as a part of a larger work and which, if prepared without proper authorization would constitute a copyright infringement. If identifiable sections of that work are not derived from the Software, and can be reasonably considered independent and separate works in themselves, then they are not considered Derivative Work. 53 | 54 | "Personal Use" means use of Software and/or Derivative Work by an individual solely for his or her personal, private and non-commercial use. An individual's use in his or her capacity as an officer, employee, member, independent contractor or agent of a corporation, business or organization does not qualify as Personal Use. 55 | 56 | "You" or "Your" means an individual or a legal entity exercising rights under this License. For legal entities, "You" or "Your" includes any non-profit entity which controls, is controlled by, or is under common control with, You, where "control" means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of fifty percent (50%) or more of the beneficial ownership of such entity. 57 | 58 | 2. GRANT OF LICENSE: 59 | 60 | WHEREAS, the Licensor, desires to aid the academic and non-commercial research community and raise awareness of the PATENTED INVENTION and thereby agrees to grant a limited copyright license to the SOFTWARE for research and non-commercial purposes only, with the Owners retaining all ownership rights in the PATENTED INVENTION and the SOFTWARE; 61 | 62 | THEREFORE: 63 | The Licensor grants, and You accept, a personal, nonexclusive, nontransferable license: 64 | 65 | a) to use Software, at no charge, in accordance with the terms herein, solely for (i) Personal Use, or (ii) academic or non-commercial research, development and deployment; and 66 | 67 | b) to develop Derivative Works that may be used solely for (i) Personal Use or (ii) academic or non-commercial research, development and deployment; and 68 | 69 | c) to copy, distribute and sublicense Software and Derivative Works solely in accordance with the terms herein. Any Software or Derivative Works distributed shall be pursuant to a license agreement that contains all of the terms herein; and shall contain prominent notices stating how the Software, Derivative Works, or documentation was changed, the author and date of any such change and require acknowledgement of the orginal software/publicaitons by any users of the Derivative Works. 70 | 71 | d) You acknowledge that the Software is a valuable, proprietary asset of The Owners. You shall not market or sell the Software or Derivative Works. 72 | 73 | 3. LICENSE EXCLUSIONS 74 | 75 | a) EXCEPT AS EXPRESSLY PROVIDED HEREIN, YOU SHALL MAKE NO OTHER USE OF THE SOFTWARE. 76 | 77 | b) You must obtain permission from The Licensor before receiving payment for distribution of or services using the Software or Derivative Works. 78 | 79 | c) You shall not allege or enjoin infringement or misappropriation by The Licensor in any Derivative Works, or by any third party obtaining Derivative Works, prepared by The Licensor and under license from The Licensor. 80 | 81 | 82 | 4. TITLE AND PROTECTION OF SOFTWARE 83 | 84 | a) The Owners retains all title, right and interest to the Software and the underlying patents. 85 | 86 | b) Except for the Software, You retain all title, right and interest to the Derivative Works, subject to the terms of this Agreement. 87 | 88 | 5. NO REPRESENTATIONS 89 | 90 | THE OWNERS DISCLAIMS ALL OTHER REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 91 | 92 | 93 | 6. ATTRIBUTION 94 | 95 | a) You agree to retain and reproduce in all copies of Software the copyright and other proprietary notices and disclaimers as they appear in the Software, and keep intact all notices in the Software that refer to this License. 96 | 97 | b) You agree to provide attribution to the authors of this Software in any article based on research performed using Software or Derivative Works or with any distribution of Software or Derivative works. 98 | 99 | 7. DEFAULT 100 | 101 | If YOU fail to perform any of its obligations under this Agreement, The Licensor, in addition to any other rights available to it under law or equity, may terminate this Agreement and the licenses granted hereunder by written notice to You. Unless otherwise provided in this Agreement, remedies shall be cumulative and there shall be no obligation to exercise a particular remedy. 102 | 103 | 8. TERMINATION 104 | 105 | a) In the event that this Agreement is terminated, any sublicenses granted or Derivative Works distributed by Licensee shall remain in full force and effect. 106 | 107 | b) Within thirty (30) days of termination, You shall return to The Licensor or certify in writing to The Licensor that all copies or partial copies of Software in Your possession or control have been destroyed. c) In addition to this section, the sections entitled "Title and Protection of Software "No Representations" and “Limitation of Liability" shall survive termination of this Agreement. 108 | 109 | 9. GENERAL 110 | a) No agency, partnership or employment is created by this Agreement. 111 | 112 | b) You may not use any of The Owners’ names, the terms in Meta-Recognition, or W-score in any advertising, public relations or media release without the prior written consent of the Owner. 113 | 114 | c) This Agreement shall be governed by the laws of the State of Colorado. Venue for any action or proceeding shall be Denver, Colorado. This Agreement constitutes the entire agreement between the parties and may only be modified by a written instrument signed by each parties authorized officers. -------------------------------------------------------------------------------- /LICENSE-libsvm-openset.txt: -------------------------------------------------------------------------------- 1 | SOURCE CODE LICENSE AGREEMENT 2 | This SOFTWARE implements concepts of open-set recognition techniques mentioned in [1] [2] using LIBSVM (copy right specified in COPYRIGHT-libsvm file) and libMR (license information specified in LICENSE-libsvm file). The use of libsvm-openset library is subject to Copyright information of LIBSVM library and libMR license. 3 | All rights reserved. 4 | 5 | 6 | 7 | 8 | 9 | LIBSVM COPYRIGHT INFORMATION: 10 | Copyright (c) 2000-2011 Chih-Chung Chang and Chih-Jen Lin 11 | All rights reserved. 12 | 13 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 14 | 15 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 16 | 17 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the 18 | documentation and/or other materials provided with the distribution. 19 | 20 | 3. Neither name of copyright holders nor the names of its contributors may be used to endorse or promote products derived from this software 21 | without specific prior written permission. 22 | 23 | 24 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | 26 | 27 | 28 | 29 | 30 | 31 | LIBMR LICENSE INFORMATION: 32 | SOURCE CODE LICENSE AGREEMENT 33 | PREAMBLE 34 | 35 | This SOFTWARE implements concepts of statistical Meta-recognition for which Securics/Univ. of Colorado have a pending patent (CU TTO File CU2338C). Securics and University of Colorado, hereafter The Owners, have joint interest in the invention and the software. Securics currently holds the excusive license commercial to both the patent and the code. Securcs, hereafter the Licensor, is offering a non-exclusive right to use for non-commecial use. 36 | 37 | This license agreement allows you to use the source code for personal or non profit purposes. This includes any use that does not involve making money, and does not include uses like: 38 | • deploying the software for use by a for-profit organization 39 | • providing a service to a paying customer 40 | For-profit companies may not use this source code. If you work for a for-profit company, you may only use this software as an individual, for your personal use. 41 | 42 | This is a right to use license. It does not not include the right to redistribute copies. Non-profit users can only use the copies obtained from authroized sourcehs which include: securics.com, metarecognition.com or vast.uccs.edu. 43 | 44 | This license agreement also allows you to create derivative products for your own use, but does not permit re-distribute 45 | of modified code in any form. You may choose to destribute patch files, which can be applied to officially distributed 46 | code. Any the derivative products, must be distributed under the same conditions as specified in this agreement unless 47 | a separate commercial license is obtained from Securics Inc or its designates. 48 | 49 | As a condition of using this source code, you agree not to assert any patents or copyrights against the owners or any of 50 | the Owners’ licensees for use of derivative products. Any derivative products must include a copy of license and 51 | instructions for accessing the orignal source. You must also include attribution to the authors in any publication that 52 | results from the use of this code or data derived from the code. Any papers/research/report based on results that uses 53 | this software must cite: 54 | 55 | @article{Scheirer_2011_TPAMI, 56 | author = {Walter J. Scheirer and Anderson Rocha and Ross Michaels and Terrance E. Boult}, 57 | title = {Meta-Recognition: The Theory and Practice of Recognition Score Analysis}, 58 | journal = {IEEE Transactions on Pattern Analysis and Machine Intelligence (PAMI)}, 59 | volume = {33}, 60 | issue = {8}, 61 | pages = {1689--1695}, 62 | year = {2011} 63 | } 64 | 65 | Parts of this technology are subject to SBIR data rights and as described in DFARS 252.227-7018 (June 1995) SBIR Data Rights which apply to Contract Number: N00014-11-C-0243 and STTR N00014-07-M-0421 to Securics Inc, 1870 Austin Bluffs Parkway, Colorado Springs, CO 80918 66 | 67 | The Government's rights to use, modify, reproduce, release, perform, display, or disclose technical data or computer software marked with this legend are restricted during the period shown as provided in paragraph (b)(4) of the Rights in Noncommercial Technical Data and Computer Software-Small Business Innovative Research (SBIR) Program clause contained in the above identified contract. Expiration of SBIR Data Rights: Expires four years after completion of the above cited project work for this or any other follow-on SBIR contract, whichever is later. 68 | 69 | No restrictions on government use apply after the expiration date shown above. Any reproduction of technical data, computer software, or portions thereof marked with this legend must also reproduce the markings. 70 | 71 | This license includes other conditions that should be read carefully. This SOFWARE usage agreement (the "Agreement") applies to the libMR and is between YOU and the Licensor 72 | 73 | 1. DEFINITIONS 74 | 75 | "Software" means all or any portion of the human-readable source code files of the software programs including without limitation, associated flow charts, algorithms, comments and other written instructions and technical documentation, and all corrections, updates, and new versions incorporated into such programs. 76 | 77 | “Derivative Work” means a work based upon the Software, such as a revision, modification, translation, abridgement, condensation, expansion, collection, compilation, or any other form in which the Software may be recast, transformed, adapted, or distributed as a part of a larger work and which, if prepared without proper authorization would constitute a copyright infringement. If identifiable sections of that work are not derived from the Software, and can be reasonably considered independent and separate works in themselves, then they are not considered Derivative Work. 78 | 79 | "Personal Use" means use of Software and/or Derivative Work by an individual solely for his or her personal, private and non-commercial use. An individual's use in his or her capacity as an officer, employee, member, independent contractor or agent of a corporation, business or organization does not qualify as Personal Use. 80 | 81 | "You" or "Your" means an individual or a legal entity exercising rights under this License. For legal entities, "You" or "Your" includes any non-profit entity which controls, is controlled by, or is under common control with, You, where "control" means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of fifty percent (50%) or more of the beneficial ownership of such entity. 82 | 83 | 2. GRANT OF LICENSE: 84 | 85 | WHEREAS, the Licensor, desires to aid the academic and non-commercial research community and raise awareness of the PATENTED INVENTION and thereby agrees to grant a limited copyright license to the SOFTWARE for research and non-commercial purposes only, with the Owners retaining all ownership rights in the PATENTED INVENTION and the SOFTWARE; 86 | 87 | THEREFORE: 88 | The Licensor grants, and You accept, a personal, nonexclusive, nontransferable license: 89 | 90 | a) to use Software, at no charge, in accordance with the terms herein, solely for (i) Personal Use, or (ii) academic or non-commercial research, development and deployment; and 91 | 92 | b) to develop Derivative Works that may be used solely for (i) Personal Use or (ii) academic or non-commercial research, development and deployment; and 93 | 94 | c) to copy, distribute and sublicense Software and Derivative Works solely in accordance with the terms herein. Any Software or Derivative Works distributed shall be pursuant to a license agreement that contains all of the terms herein; and shall contain prominent notices stating how the Software, Derivative Works, or documentation was changed, the author and date of any such change and require acknowledgement of the orginal software/publicaitons by any users of the Derivative Works. 95 | 96 | d) You acknowledge that the Software is a valuable, proprietary asset of The Owners. You shall not market or sell the Software or Derivative Works. 97 | 98 | 3. LICENSE EXCLUSIONS 99 | 100 | a) EXCEPT AS EXPRESSLY PROVIDED HEREIN, YOU SHALL MAKE NO OTHER USE OF THE SOFTWARE. 101 | 102 | b) You must obtain permission from The Licensor before receiving payment for distribution of or services using the Software or Derivative Works. 103 | 104 | c) You shall not allege or enjoin infringement or misappropriation by The Licensor in any Derivative Works, or by any third party obtaining Derivative Works, prepared by The Licensor and under license from The Licensor. 105 | 106 | 107 | 4. TITLE AND PROTECTION OF SOFTWARE 108 | 109 | a) The Owners retains all title, right and interest to the Software and the underlying patents. 110 | 111 | b) Except for the Software, You retain all title, right and interest to the Derivative Works, subject to the terms of this Agreement. 112 | 113 | 5. NO REPRESENTATIONS 114 | 115 | THE OWNERS DISCLAIMS ALL OTHER REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 116 | 117 | 118 | 6. ATTRIBUTION 119 | 120 | a) You agree to retain and reproduce in all copies of Software the copyright and other proprietary notices and disclaimers as they appear in the Software, and keep intact all notices in the Software that refer to this License. 121 | 122 | b) You agree to provide attribution to the authors of this Software in any article based on research performed using Software or Derivative Works or with any distribution of Software or Derivative works. 123 | 124 | 7. DEFAULT 125 | 126 | If YOU fail to perform any of its obligations under this Agreement, The Licensor, in addition to any other rights available to it under law or equity, may terminate this Agreement and the licenses granted hereunder by written notice to You. Unless otherwise provided in this Agreement, remedies shall be cumulative and there shall be no obligation to exercise a particular remedy. 127 | 128 | 8. TERMINATION 129 | 130 | a) In the event that this Agreement is terminated, any sublicenses granted or Derivative Works distributed by Licensee shall remain in full force and effect. 131 | 132 | b) Within thirty (30) days of termination, You shall return to The Licensor or certify in writing to The Licensor that all copies or partial copies of Software in Your possession or control have been destroyed. c) In addition to this section, the sections entitled "Title and Protection of Software "No Representations" and “Limitation of Liability" shall survive termination of this Agreement. 133 | 134 | 9. GENERAL 135 | a) No agency, partnership or employment is created by this Agreement. 136 | 137 | b) You may not use any of The Owners’ names, the terms in Meta-Recognition, or W-score in any advertising, public relations or media release without the prior written consent of the Owner. 138 | 139 | c) This Agreement shall be governed by the laws of the State of Colorado. Venue for any action or proceeding shall be Denver, Colorado. This Agreement constitutes the entire agreement between the parties and may only be modified by a written instrument signed by each parties authorized officers. 140 | 141 | 142 | References: 143 | [1] Walter J. Scheirer*, Lalit P. Jain*, Terrance E. Boult: Probability Models for Open Set Recognition. IEEE Trans. Pattern Anal. Mach. Intell. (2014) 144 | [2] Walter J. Scheirer, Anderson de Rezende Rocha, Archana Sapkota, Terrance E. Boult: Toward Open Set Recognition. IEEE Trans. Pattern Anal. Mach. Intell. 35(7): 1757-1772 (2013) -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | #LIBMR_DIR should be absolute path, not relative (no ..) 2 | LIBMR_DIR = /Users/macuser/lalitphd/WSVM/libsvm-openset/libMR 3 | 4 | ifeq ($(OS),Windows_NT) 5 | CFLAGS += -D WIN32 6 | ifeq ($(PROCESSOR_ARCHITECTURE),AMD64) 7 | CFLAGS += -D AMD64 8 | LIBSUFFIX = .dll 9 | endif 10 | ifeq ($(PROCESSOR_ARCHITECTURE),x86) 11 | CFLAGS += -D IA32 12 | LIBSUFFIX = .dll 13 | endif 14 | else 15 | UNAME_S := $(shell uname -s) 16 | ifeq ($(UNAME_S),Linux) 17 | CFLAGS += -D LINUX -Wl,-rpath=$(LIBMR_DIR)/libMR/build/libMR/ 18 | LIBSUFFIX = .so 19 | endif 20 | ifeq ($(UNAME_S),Darwin) 21 | CFLAGS += -D OSX 22 | LIBSUFFIX = .dylib 23 | endif 24 | endif 25 | 26 | CXX ?= g++ -g 27 | #CFLAGS = -Wall -Wconversion -g 28 | 29 | LIBMR_LIB = $(LIBMR_DIR)/libMR/build/libMR/libMR$(LIBSUFFIX) 30 | #LIBMR_LIB = build/libMR/libMR.so 31 | 32 | CFLAGS += -Wall -g -I $(LIBMR_DIR)/libMR 33 | CFLAGS += -O2 -fPIC 34 | SHVER = 2 35 | 36 | all: svm-train svm-predict svm-scale $(LIBMR_LIB) 37 | 38 | $(LIBMR_LIB): $(LIBMR_DIR)/libMR/MetaRecognition.h $(LIBMR_DIR)/libMR/MetaRecognition.cpp 39 | mkdir -p $(LIBMR_DIR)/libMR/build 40 | cd $(LIBMR_DIR)/libMR/build; cmake -DCMAKE_BUILD_TYPE=Debug $(LIBMR_DIR); make 41 | 42 | 43 | 44 | lib: svm.o $(LIBMR_LIB) 45 | $(CXX) -shared -dynamiclib svm.o $(LIBMR_LIB) -o libsvm.so.$(SHVER) 46 | 47 | svm-predict: svm-predict.cpp svm.o $(LIBMR_LIB) 48 | $(CXX) $(CFLAGS) svm-predict.cpp svm.o $(LIBMR_LIB) -o svm-predict -lm 49 | svm-train: svm-train.cpp svm.o $(LIBMR_LIB) 50 | $(CXX) $(CFLAGS) svm-train.cpp svm.o $(LIBMR_LIB) -o svm-train -lm 51 | svm-scale: svm-scale.c $(LIBMR_LIB) 52 | $(CXX) $(CFLAGS) svm-scale.c $(LIBMR_LIB) -o svm-scale 53 | svm.o: svm.cpp svm.h 54 | $(CXX) $(CFLAGS) -c svm.cpp 55 | clean: 56 | rm -fr *~ svm.o svm-train svm-predict svm-scale libsvm.so.$(SHVER) $(LIBMR_DIR)/libMR/build 57 | -------------------------------------------------------------------------------- /Makefile.win: -------------------------------------------------------------------------------- 1 | #You must ensure nmake.exe, cl.exe, link.exe are in system path. 2 | #VCVARS32.bat 3 | #Under dosbox prompt 4 | #nmake -f Makefile.win 5 | 6 | ########################################## 7 | CXX = cl.exe 8 | CFLAGS = -nologo -O2 -EHsc -I. -D __WIN32__ -D _CRT_SECURE_NO_DEPRECATE 9 | TARGET = windows 10 | 11 | all: $(TARGET)\svm-train.exe $(TARGET)\svm-predict.exe $(TARGET)\svm-scale.exe $(TARGET)\svm-toy.exe lib 12 | 13 | $(TARGET)\svm-predict.exe: svm.h svm-predict.c svm.obj 14 | $(CXX) $(CFLAGS) svm-predict.c svm.obj -Fe$(TARGET)\svm-predict.exe 15 | 16 | $(TARGET)\svm-train.exe: svm.h svm-train.c svm.obj 17 | $(CXX) $(CFLAGS) svm-train.c svm.obj -Fe$(TARGET)\svm-train.exe 18 | 19 | $(TARGET)\svm-scale.exe: svm.h svm-scale.c 20 | $(CXX) $(CFLAGS) svm-scale.c -Fe$(TARGET)\svm-scale.exe 21 | 22 | $(TARGET)\svm-toy.exe: svm.h svm.obj svm-toy\windows\svm-toy.cpp 23 | $(CXX) $(CFLAGS) svm-toy\windows\svm-toy.cpp svm.obj user32.lib gdi32.lib comdlg32.lib -Fe$(TARGET)\svm-toy.exe 24 | 25 | svm.obj: svm.cpp svm.h 26 | $(CXX) $(CFLAGS) -c svm.cpp 27 | 28 | lib: svm.cpp svm.h svm.def 29 | $(CXX) $(CFLAGS) -LD svm.cpp -Fe$(TARGET)\libsvm -link -DEF:svm.def 30 | 31 | clean: 32 | -erase /Q *.obj $(TARGET)\. 33 | 34 | -------------------------------------------------------------------------------- /README-libsvm-openset: -------------------------------------------------------------------------------- 1 | The libsvm-openset package extends libsvm to support openset recognition using the PI-SVM, WSVM and 1-vs-set extension described in [1] [2] and [3] respectively. libsvm-openset incoporates all libsvm functionality PI-SVM described in [1] + WSVM described in [2] + 1-vs-set described in [3]. 2 | 3 | 4 | This package an extension to the well known libsvm package (see README for info on libsvm) and extends support for linear, poly, RBG and sigmod kernels (-t [0-3]). It should work with customer kernels, we just did not test that). 5 | 6 | PI-SVM/PI-OSVM functionality described in [1] in libsvm-openset: 7 | The extension uses the same command-line processing with a few added fields: 8 | In svm-train: 9 | -s 9 for the PI-OSVM based on one-class svms 10 | -s 10 for the PI-SVM based on 1-vs-rest binary svms 11 | In svm-predict: 12 | -P specify thresholded probability value to reject sample as unknowns for WSVM (default 0.0) 13 | 14 | To use WSVM in libsvm-openset: 15 | ************ Training 16 | ./svm-train -s 9 -t 0 TrainingDataFile ModelFile 17 | ./svm-train -s 10 -t 0 TrainingDataFile ModelFile 18 | where TrainingDataFile is training file in libsvm format. "ModelFile" will be genrated using one-class svms for PI-OSVM (-s 9 option) and 1-vs-rest SVM binary svms for PI-SVM (-s 10 option) respectively. Both PI-SVM and PI-OSVM estimates probability of inclusion for the single class. 19 | ************ Predicing Using model files ("ModelFile") 20 | ./svm-predict -P 0.1 TestDataFile ModelFile outputfile 21 | where TestDataFile is testing file in libsvm format. ModelFile is file generated during training. 22 | -P specify the threshold to consider for rejecting samples as unknown in PI-SVM and PI-OSVM. 23 | 24 | 25 | WSVM functionality described in [2] in libsvm-openset: 26 | The extension uses the same command-line processing with a few added fields: 27 | In svm-train: 28 | -s 8 for the WSVM based on 1-vs-rest binary svms 29 | In svm-predict: 30 | -P specify thresholded probability value to reject sample as unknowns for WSVM (default 0.0) 31 | -C specify thresholded probability value to reject sample as unknowns for CAP model in WSVM (default 0.0) 32 | 33 | To use WSVM in libsvm-openset: 34 | ************ Training 35 | ./svm-train -s 8 -t 0 TrainingDataFile ModelFile 36 | where if TrainingDataFile is training file in libsvm format. Two file "ModelFile" and "ModelFile_one_wsvm" will be genrated using 1-vs-rest SVM and one-class SVM (CAP) respectively for WSVM. 37 | ************ Predicing Using two model files ("ModelFile" and "ModelFile_one_wsvm") 38 | ./svm-predict -P 0.1 -C 0.001 TestDataFile ModelFile outputfile 39 | where TestDataFile is testing file in libsvm format. ModelFile is file generated during training. ./svm-predict by default looks for ModelFile_one_wsvm file generated for CAP model in WSVM training. 40 | -P specify the threshold to consider for rejecting samples as unknown in WSVM. 41 | -C specify the minimum threshold to consider for any sample in CAP model. 42 | 43 | 44 | 1-vs-set functionality described in [3] in libsvm-openset: 45 | The extension uses the same command-line processing with a few added fields: 46 | In svm-train: 47 | -s 7 for the 1-vs-set based on "1-vs-all" binary svms (which is the generally recommended model) 48 | -s 5 for the 1-vs-set based on one class svm (provides better generalization of one-class, but not truly a discriminative model ) 49 | -B optarg Defines the beta of fmeasure used in the balanced Balanced risk discussed in the paper. 50 | -G near_pessure far_pressure (which allows changes to the "pressure" of the open-set formulation. Increasing pressure causes increased generalization, negative pressures cause increased specialization (e.g. you know you only had a few negative training classes). 51 | -V logfilename (for verbose logs/debugging related to the actual openset optimization stages 52 | 53 | To use 1-vs-set (only linear and RBF kernels supported) in libsvm-openset: 54 | ************ Training using Pos/Negative or multi-class Files once ***************** 55 | ./svm-train -s 5 -t 0 TrainingDataFile 56 | where if TrainingDataFile is a mixed file with 1 for positive, -1 for negative 57 | This produces TrainingDataFile.model.1 58 | if TrainingDataFile is a mixed file with multiple class labels (1, 2 3.. 10) 59 | This produces TrainingDataFile.model.1 TrainingDataFile.model.2.. TrainingDataFile.model.10 60 | ************ Predicing Using single Model Files (against a multi-class or binary test file) ***************** 61 | ./svm-predict -o testingDataFile TrainingDataFile.model.7 outpufile 62 | outputfle has lines of the format predicted_label decision_score (target_label) 63 | if the model has an index other than 1, then the testfile must be in multi-class format (rows start with class label). 64 | ************ Predicing using multiple Model Files all at once ***************** 65 | ./svm-predict -o testingDataFile TrainingDataFile.model. outpufile 66 | outputfle has lines of the format predicted_label decision_score (target_label) 67 | (Note the trailing . after model.. that tell it to use all models could also do .* but must escape the *) 68 | 69 | 70 | 71 | 72 | Installation: 73 | In order to compile WSVM functionality incorporated in libsvm-openset, libMR library available at http://www.metarecognition.com/libmr-license is needed. Once libMR.zip is copied after accepting its license, unzip libMR, copy libMR in libsvm-openset and build libMR. 74 | 75 | libMR Quick Build Instruction: 76 | This needs CMake (version > 2.8) 77 | Quick build instructions for linux/Mac: 78 | $> tar -zxf libMR.tgz 79 | $> cd libMR 80 | %You can edit the CMakeLists.txt in libMR level, to change install dir if desired 81 | $> mkdir build; % or where you like to build it 82 | $> cd build 83 | $> cmake -DCMAKE_BUILD_TYPE=Debug .. 84 | $> make 85 | 86 | libsvm-openset Quick Build Instruction: 87 | Once libMR is build, next step is to specify the absolute path of libMR directory in Makefile available in libsvm-openset. Paste the absolute path of libMR folder in variable "LIBMR_DIR" in Makefile (line 2 of Makefile). For example: LIBMR_DIR = /Users/username/libsvm-openset/libMR 88 | On linux/mac systems, type `make' to build the `svm-train' and `svm-predict' programs. Run them without arguments to show the usages of them. 89 | e.g: 90 | $> cd libsvm-openset 91 | $> make 92 | $> ./svm-train 93 | $> ./svm-predict 94 | 95 | 96 | 97 | References: 98 | [1] Lalit P. Jain, Walter J. Scheirer, Terrance E. Boult: Multi-Class Open Set Recognition Using Probability of Inclusion. European Conference on Computer Vision (ECCV 2014), September 2014, Zurich, Switzerland. 99 | 100 | [2] Walter J. Scheirer*, Lalit P. Jain*, Terrance E. Boult: Probability Models for Open Set Recognition. IEEE Trans. Pattern Anal. Mach. Intell. (2014) 101 | 102 | [3] Walter J. Scheirer, Anderson de Rezende Rocha, Archana Sapkota, Terrance E. Boult: Toward Open Set Recognition. IEEE Trans. Pattern Anal. Mach. Intell. 35(7): 1757-1772 (2013) -------------------------------------------------------------------------------- /java/Makefile: -------------------------------------------------------------------------------- 1 | .SUFFIXES: .class .java 2 | FILES = libsvm/svm.class libsvm/svm_model.class libsvm/svm_node.class \ 3 | libsvm/svm_parameter.class libsvm/svm_problem.class \ 4 | libsvm/svm_print_interface.class \ 5 | svm_train.class svm_predict.class svm_toy.class svm_scale.class 6 | 7 | #JAVAC = jikes 8 | JAVAC_FLAGS = -target 1.5 -source 1.5 9 | JAVAC = javac 10 | # JAVAC_FLAGS = 11 | 12 | all: $(FILES) 13 | jar cvf libsvm.jar *.class libsvm/*.class 14 | 15 | .java.class: 16 | $(JAVAC) $(JAVAC_FLAGS) $< 17 | 18 | libsvm/svm.java: libsvm/svm.m4 19 | m4 libsvm/svm.m4 > libsvm/svm.java 20 | 21 | clean: 22 | rm -f libsvm/*.class *.class *.jar libsvm/*~ *~ libsvm/svm.java 23 | 24 | dist: clean all 25 | rm *.class libsvm/*.class 26 | -------------------------------------------------------------------------------- /java/libsvm.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ljain2/libsvm-openset/122298cf40c56d09e83c826024340854177ba5f8/java/libsvm.jar -------------------------------------------------------------------------------- /java/libsvm/svm_model.java: -------------------------------------------------------------------------------- 1 | // 2 | // svm_model 3 | // 4 | package libsvm; 5 | public class svm_model implements java.io.Serializable 6 | { 7 | public svm_parameter param; // parameter 8 | public int nr_class; // number of classes, = 2 in regression/one class svm 9 | public int l; // total #SV 10 | public svm_node[][] SV; // SVs (SV[l]) 11 | public double[][] sv_coef; // coefficients for SVs in decision functions (sv_coef[k-1][l]) 12 | public double[] rho; // constants in decision functions (rho[k*(k-1)/2]) 13 | public double[] probA; // pariwise probability information 14 | public double[] probB; 15 | 16 | // for classification only 17 | 18 | public int[] label; // label of each class (label[k]) 19 | public int[] nSV; // number of SVs for each class (nSV[k]) 20 | // nSV[0] + nSV[1] + ... + nSV[k-1] = l 21 | }; 22 | -------------------------------------------------------------------------------- /java/libsvm/svm_node.java: -------------------------------------------------------------------------------- 1 | package libsvm; 2 | public class svm_node implements java.io.Serializable 3 | { 4 | public int index; 5 | public double value; 6 | } 7 | -------------------------------------------------------------------------------- /java/libsvm/svm_parameter.java: -------------------------------------------------------------------------------- 1 | package libsvm; 2 | public class svm_parameter implements Cloneable,java.io.Serializable 3 | { 4 | /* svm_type */ 5 | public static final int C_SVC = 0; 6 | public static final int NU_SVC = 1; 7 | public static final int ONE_CLASS = 2; 8 | public static final int EPSILON_SVR = 3; 9 | public static final int NU_SVR = 4; 10 | 11 | /* kernel_type */ 12 | public static final int LINEAR = 0; 13 | public static final int POLY = 1; 14 | public static final int RBF = 2; 15 | public static final int SIGMOID = 3; 16 | public static final int PRECOMPUTED = 4; 17 | 18 | public int svm_type; 19 | public int kernel_type; 20 | public int degree; // for poly 21 | public double gamma; // for poly/rbf/sigmoid 22 | public double coef0; // for poly/sigmoid 23 | 24 | // these are for training only 25 | public double cache_size; // in MB 26 | public double eps; // stopping criteria 27 | public double C; // for C_SVC, EPSILON_SVR and NU_SVR 28 | public int nr_weight; // for C_SVC 29 | public int[] weight_label; // for C_SVC 30 | public double[] weight; // for C_SVC 31 | public double nu; // for NU_SVC, ONE_CLASS, and NU_SVR 32 | public double p; // for EPSILON_SVR 33 | public int shrinking; // use the shrinking heuristics 34 | public int probability; // do probability estimates 35 | 36 | public Object clone() 37 | { 38 | try 39 | { 40 | return super.clone(); 41 | } catch (CloneNotSupportedException e) 42 | { 43 | return null; 44 | } 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /java/libsvm/svm_print_interface.java: -------------------------------------------------------------------------------- 1 | package libsvm; 2 | public interface svm_print_interface 3 | { 4 | public void print(String s); 5 | } 6 | -------------------------------------------------------------------------------- /java/libsvm/svm_problem.java: -------------------------------------------------------------------------------- 1 | package libsvm; 2 | public class svm_problem implements java.io.Serializable 3 | { 4 | public int l; 5 | public double[] y; 6 | public svm_node[][] x; 7 | } 8 | -------------------------------------------------------------------------------- /java/svm_predict.java: -------------------------------------------------------------------------------- 1 | import libsvm.*; 2 | import java.io.*; 3 | import java.util.*; 4 | 5 | class svm_predict { 6 | private static double atof(String s) 7 | { 8 | return Double.valueOf(s).doubleValue(); 9 | } 10 | 11 | private static int atoi(String s) 12 | { 13 | return Integer.parseInt(s); 14 | } 15 | 16 | private static void predict(BufferedReader input, DataOutputStream output, svm_model model, int predict_probability) throws IOException 17 | { 18 | int correct = 0; 19 | int total = 0; 20 | double error = 0; 21 | double sumv = 0, sumy = 0, sumvv = 0, sumyy = 0, sumvy = 0; 22 | 23 | int svm_type=svm.svm_get_svm_type(model); 24 | int nr_class=svm.svm_get_nr_class(model); 25 | double[] prob_estimates=null; 26 | 27 | if(predict_probability == 1) 28 | { 29 | if(svm_type == svm_parameter.EPSILON_SVR || 30 | svm_type == svm_parameter.NU_SVR) 31 | { 32 | System.out.print("Prob. model for test data: target value = predicted value + z,\nz: Laplace distribution e^(-|z|/sigma)/(2sigma),sigma="+svm.svm_get_svr_probability(model)+"\n"); 33 | } 34 | else 35 | { 36 | int[] labels=new int[nr_class]; 37 | svm.svm_get_labels(model,labels); 38 | prob_estimates = new double[nr_class]; 39 | output.writeBytes("labels"); 40 | for(int j=0;j=argv.length-2) 129 | exit_with_help(); 130 | try 131 | { 132 | BufferedReader input = new BufferedReader(new FileReader(argv[i])); 133 | DataOutputStream output = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(argv[i+2]))); 134 | svm_model model = svm.svm_load_model(argv[i+1]); 135 | if(predict_probability == 1) 136 | { 137 | if(svm.svm_check_probability_model(model)==0) 138 | { 139 | System.err.print("Model does not support probabiliy estimates\n"); 140 | System.exit(1); 141 | } 142 | } 143 | else 144 | { 145 | if(svm.svm_check_probability_model(model)!=0) 146 | { 147 | System.out.print("Model supports probability estimates, but disabled in prediction.\n"); 148 | } 149 | } 150 | predict(input,output,model,predict_probability); 151 | input.close(); 152 | output.close(); 153 | } 154 | catch(FileNotFoundException e) 155 | { 156 | exit_with_help(); 157 | } 158 | catch(ArrayIndexOutOfBoundsException e) 159 | { 160 | exit_with_help(); 161 | } 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /java/svm_scale.java: -------------------------------------------------------------------------------- 1 | import libsvm.*; 2 | import java.io.*; 3 | import java.util.*; 4 | import java.text.DecimalFormat; 5 | 6 | class svm_scale 7 | { 8 | private String line = null; 9 | private double lower = -1.0; 10 | private double upper = 1.0; 11 | private double y_lower; 12 | private double y_upper; 13 | private boolean y_scaling = false; 14 | private double[] feature_max; 15 | private double[] feature_min; 16 | private double y_max = -Double.MAX_VALUE; 17 | private double y_min = Double.MAX_VALUE; 18 | private int max_index; 19 | private long num_nonzeros = 0; 20 | private long new_num_nonzeros = 0; 21 | 22 | private static void exit_with_help() 23 | { 24 | System.out.print( 25 | "Usage: svm-scale [options] data_filename\n" 26 | +"options:\n" 27 | +"-l lower : x scaling lower limit (default -1)\n" 28 | +"-u upper : x scaling upper limit (default +1)\n" 29 | +"-y y_lower y_upper : y scaling limits (default: no y scaling)\n" 30 | +"-s save_filename : save scaling parameters to save_filename\n" 31 | +"-r restore_filename : restore scaling parameters from restore_filename\n" 32 | ); 33 | System.exit(1); 34 | } 35 | 36 | private BufferedReader rewind(BufferedReader fp, String filename) throws IOException 37 | { 38 | fp.close(); 39 | return new BufferedReader(new FileReader(filename)); 40 | } 41 | 42 | private void output_target(double value) 43 | { 44 | if(y_scaling) 45 | { 46 | if(value == y_min) 47 | value = y_lower; 48 | else if(value == y_max) 49 | value = y_upper; 50 | else 51 | value = y_lower + (y_upper-y_lower) * 52 | (value-y_min) / (y_max-y_min); 53 | } 54 | 55 | System.out.print(value + " "); 56 | } 57 | 58 | private void output(int index, double value) 59 | { 60 | /* skip single-valued attribute */ 61 | if(feature_max[index] == feature_min[index]) 62 | return; 63 | 64 | if(value == feature_min[index]) 65 | value = lower; 66 | else if(value == feature_max[index]) 67 | value = upper; 68 | else 69 | value = lower + (upper-lower) * 70 | (value-feature_min[index])/ 71 | (feature_max[index]-feature_min[index]); 72 | 73 | if(value != 0) 74 | { 75 | System.out.print(index + ":" + value + " "); 76 | new_num_nonzeros++; 77 | } 78 | } 79 | 80 | private String readline(BufferedReader fp) throws IOException 81 | { 82 | line = fp.readLine(); 83 | return line; 84 | } 85 | 86 | private void run(String []argv) throws IOException 87 | { 88 | int i,index; 89 | BufferedReader fp = null, fp_restore = null; 90 | String save_filename = null; 91 | String restore_filename = null; 92 | String data_filename = null; 93 | 94 | 95 | for(i=0;i lower) || (y_scaling && !(y_upper > y_lower))) 118 | { 119 | System.err.println("inconsistent lower/upper specification"); 120 | System.exit(1); 121 | } 122 | if(restore_filename != null && save_filename != null) 123 | { 124 | System.err.println("cannot use -r and -s simultaneously"); 125 | System.exit(1); 126 | } 127 | 128 | if(argv.length != i+1) 129 | exit_with_help(); 130 | 131 | data_filename = argv[i]; 132 | try { 133 | fp = new BufferedReader(new FileReader(data_filename)); 134 | } catch (Exception e) { 135 | System.err.println("can't open file " + data_filename); 136 | System.exit(1); 137 | } 138 | 139 | /* assumption: min index of attributes is 1 */ 140 | /* pass 1: find out max index of attributes */ 141 | max_index = 0; 142 | 143 | if(restore_filename != null) 144 | { 145 | int idx, c; 146 | 147 | try { 148 | fp_restore = new BufferedReader(new FileReader(restore_filename)); 149 | } 150 | catch (Exception e) { 151 | System.err.println("can't open file " + restore_filename); 152 | System.exit(1); 153 | } 154 | if((c = fp_restore.read()) == 'y') 155 | { 156 | fp_restore.readLine(); 157 | fp_restore.readLine(); 158 | fp_restore.readLine(); 159 | } 160 | fp_restore.readLine(); 161 | fp_restore.readLine(); 162 | 163 | String restore_line = null; 164 | while((restore_line = fp_restore.readLine())!=null) 165 | { 166 | StringTokenizer st2 = new StringTokenizer(restore_line); 167 | idx = Integer.parseInt(st2.nextToken()); 168 | max_index = Math.max(max_index, idx); 169 | } 170 | fp_restore = rewind(fp_restore, restore_filename); 171 | } 172 | 173 | while (readline(fp) != null) 174 | { 175 | StringTokenizer st = new StringTokenizer(line," \t\n\r\f:"); 176 | st.nextToken(); 177 | while(st.hasMoreTokens()) 178 | { 179 | index = Integer.parseInt(st.nextToken()); 180 | max_index = Math.max(max_index, index); 181 | st.nextToken(); 182 | num_nonzeros++; 183 | } 184 | } 185 | 186 | try { 187 | feature_max = new double[(max_index+1)]; 188 | feature_min = new double[(max_index+1)]; 189 | } catch(OutOfMemoryError e) { 190 | System.err.println("can't allocate enough memory"); 191 | System.exit(1); 192 | } 193 | 194 | for(i=0;i<=max_index;i++) 195 | { 196 | feature_max[i] = -Double.MAX_VALUE; 197 | feature_min[i] = Double.MAX_VALUE; 198 | } 199 | 200 | fp = rewind(fp, data_filename); 201 | 202 | /* pass 2: find out min/max value */ 203 | while(readline(fp) != null) 204 | { 205 | int next_index = 1; 206 | double target; 207 | double value; 208 | 209 | StringTokenizer st = new StringTokenizer(line," \t\n\r\f:"); 210 | target = Double.parseDouble(st.nextToken()); 211 | y_max = Math.max(y_max, target); 212 | y_min = Math.min(y_min, target); 213 | 214 | while (st.hasMoreTokens()) 215 | { 216 | index = Integer.parseInt(st.nextToken()); 217 | value = Double.parseDouble(st.nextToken()); 218 | 219 | for (i = next_index; i num_nonzeros) 337 | System.err.print( 338 | "Warning: original #nonzeros " + num_nonzeros+"\n" 339 | +" new #nonzeros " + new_num_nonzeros+"\n" 340 | +"Use -l 0 if many original feature values are zeros\n"); 341 | 342 | fp.close(); 343 | } 344 | 345 | public static void main(String argv[]) throws IOException 346 | { 347 | svm_scale s = new svm_scale(); 348 | s.run(argv); 349 | } 350 | } 351 | -------------------------------------------------------------------------------- /java/svm_train.java: -------------------------------------------------------------------------------- 1 | import libsvm.*; 2 | import java.io.*; 3 | import java.util.*; 4 | 5 | class svm_train { 6 | private svm_parameter param; // set by parse_command_line 7 | private svm_problem prob; // set by read_problem 8 | private svm_model model; 9 | private String input_file_name; // set by parse_command_line 10 | private String model_file_name; // set by parse_command_line 11 | private String error_msg; 12 | private int cross_validation; 13 | private int nr_fold; 14 | 15 | private static svm_print_interface svm_print_null = new svm_print_interface() 16 | { 17 | public void print(String s) {} 18 | }; 19 | 20 | private static void exit_with_help() 21 | { 22 | System.out.print( 23 | "Usage: svm_train [options] training_set_file [model_file]\n" 24 | +"options:\n" 25 | +"-s svm_type : set type of SVM (default 0)\n" 26 | +" 0 -- C-SVC\n" 27 | +" 1 -- nu-SVC\n" 28 | +" 2 -- one-class SVM\n" 29 | +" 3 -- epsilon-SVR\n" 30 | +" 4 -- nu-SVR\n" 31 | +"-t kernel_type : set type of kernel function (default 2)\n" 32 | +" 0 -- linear: u'*v\n" 33 | +" 1 -- polynomial: (gamma*u'*v + coef0)^degree\n" 34 | +" 2 -- radial basis function: exp(-gamma*|u-v|^2)\n" 35 | +" 3 -- sigmoid: tanh(gamma*u'*v + coef0)\n" 36 | +" 4 -- precomputed kernel (kernel values in training_set_file)\n" 37 | +"-d degree : set degree in kernel function (default 3)\n" 38 | +"-g gamma : set gamma in kernel function (default 1/num_features)\n" 39 | +"-r coef0 : set coef0 in kernel function (default 0)\n" 40 | +"-c cost : set the parameter C of C-SVC, epsilon-SVR, and nu-SVR (default 1)\n" 41 | +"-n nu : set the parameter nu of nu-SVC, one-class SVM, and nu-SVR (default 0.5)\n" 42 | +"-p epsilon : set the epsilon in loss function of epsilon-SVR (default 0.1)\n" 43 | +"-m cachesize : set cache memory size in MB (default 100)\n" 44 | +"-e epsilon : set tolerance of termination criterion (default 0.001)\n" 45 | +"-h shrinking : whether to use the shrinking heuristics, 0 or 1 (default 1)\n" 46 | +"-b probability_estimates : whether to train a SVC or SVR model for probability estimates, 0 or 1 (default 0)\n" 47 | +"-wi weight : set the parameter C of class i to weight*C, for C-SVC (default 1)\n" 48 | +"-v n : n-fold cross validation mode\n" 49 | +"-q : quiet mode (no outputs)\n" 50 | ); 51 | System.exit(1); 52 | } 53 | 54 | private void do_cross_validation() 55 | { 56 | int i; 57 | int total_correct = 0; 58 | double total_error = 0; 59 | double sumv = 0, sumy = 0, sumvv = 0, sumyy = 0, sumvy = 0; 60 | double[] target = new double[prob.l]; 61 | 62 | svm.svm_cross_validation(prob,param,nr_fold,target); 63 | if(param.svm_type == svm_parameter.EPSILON_SVR || 64 | param.svm_type == svm_parameter.NU_SVR) 65 | { 66 | for(i=0;i=argv.length) 166 | exit_with_help(); 167 | switch(argv[i-1].charAt(1)) 168 | { 169 | case 's': 170 | param.svm_type = atoi(argv[i]); 171 | break; 172 | case 't': 173 | param.kernel_type = atoi(argv[i]); 174 | break; 175 | case 'd': 176 | param.degree = atoi(argv[i]); 177 | break; 178 | case 'g': 179 | param.gamma = atof(argv[i]); 180 | break; 181 | case 'r': 182 | param.coef0 = atof(argv[i]); 183 | break; 184 | case 'n': 185 | param.nu = atof(argv[i]); 186 | break; 187 | case 'm': 188 | param.cache_size = atof(argv[i]); 189 | break; 190 | case 'c': 191 | param.C = atof(argv[i]); 192 | break; 193 | case 'e': 194 | param.eps = atof(argv[i]); 195 | break; 196 | case 'p': 197 | param.p = atof(argv[i]); 198 | break; 199 | case 'h': 200 | param.shrinking = atoi(argv[i]); 201 | break; 202 | case 'b': 203 | param.probability = atoi(argv[i]); 204 | break; 205 | case 'q': 206 | print_func = svm_print_null; 207 | i--; 208 | break; 209 | case 'v': 210 | cross_validation = 1; 211 | nr_fold = atoi(argv[i]); 212 | if(nr_fold < 2) 213 | { 214 | System.err.print("n-fold cross validation: n must >= 2\n"); 215 | exit_with_help(); 216 | } 217 | break; 218 | case 'w': 219 | ++param.nr_weight; 220 | { 221 | int[] old = param.weight_label; 222 | param.weight_label = new int[param.nr_weight]; 223 | System.arraycopy(old,0,param.weight_label,0,param.nr_weight-1); 224 | } 225 | 226 | { 227 | double[] old = param.weight; 228 | param.weight = new double[param.nr_weight]; 229 | System.arraycopy(old,0,param.weight,0,param.nr_weight-1); 230 | } 231 | 232 | param.weight_label[param.nr_weight-1] = atoi(argv[i-1].substring(2)); 233 | param.weight[param.nr_weight-1] = atof(argv[i]); 234 | break; 235 | default: 236 | System.err.print("Unknown option: " + argv[i-1] + "\n"); 237 | exit_with_help(); 238 | } 239 | } 240 | 241 | svm.svm_set_print_string_function(print_func); 242 | 243 | // determine filenames 244 | 245 | if(i>=argv.length) 246 | exit_with_help(); 247 | 248 | input_file_name = argv[i]; 249 | 250 | if(i vy = new Vector(); 266 | Vector vx = new Vector(); 267 | int max_index = 0; 268 | 269 | while(true) 270 | { 271 | String line = fp.readLine(); 272 | if(line == null) break; 273 | 274 | StringTokenizer st = new StringTokenizer(line," \t\n\r\f:"); 275 | 276 | vy.addElement(atof(st.nextToken())); 277 | int m = st.countTokens()/2; 278 | svm_node[] x = new svm_node[m]; 279 | for(int j=0;j0) max_index = Math.max(max_index, x[m-1].index); 286 | vx.addElement(x); 287 | } 288 | 289 | prob = new svm_problem(); 290 | prob.l = vy.size(); 291 | prob.x = new svm_node[prob.l][]; 292 | for(int i=0;i 0) 299 | param.gamma = 1.0/max_index; 300 | 301 | if(param.kernel_type == svm_parameter.PRECOMPUTED) 302 | for(int i=0;i max_index) 310 | { 311 | System.err.print("Wrong input format: sample_serial_number out of range\n"); 312 | System.exit(1); 313 | } 314 | } 315 | 316 | fp.close(); 317 | } 318 | } 319 | -------------------------------------------------------------------------------- /java/test_applet.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /matlab/Makefile: -------------------------------------------------------------------------------- 1 | # This Makefile is used under Linux 2 | 3 | MATLABDIR ?= /usr/local/matlab 4 | # for Mac 5 | # MATLABDIR ?= /opt/local/matlab 6 | 7 | CXX ?= g++ 8 | #CXX = g++-4.1 9 | CFLAGS = -Wall -Wconversion -O3 -fPIC -I$(MATLABDIR)/extern/include -I.. 10 | 11 | MEX = $(MATLABDIR)/bin/mex 12 | MEX_OPTION = CC\#$(CXX) CXX\#$(CXX) CFLAGS\#"$(CFLAGS)" CXXFLAGS\#"$(CFLAGS)" 13 | # comment the following line if you use MATLAB on 32-bit computer 14 | MEX_OPTION += -largeArrayDims 15 | MEX_EXT = $(shell $(MATLABDIR)/bin/mexext) 16 | 17 | OCTAVEDIR ?= /usr/include/octave 18 | OCTAVE_MEX = env CC=$(CXX) mkoctfile 19 | OCTAVE_MEX_OPTION = --mex 20 | OCTAVE_MEX_EXT = mex 21 | OCTAVE_CFLAGS = -Wall -O3 -fPIC -I$(OCTAVEDIR) -I.. 22 | 23 | all: matlab 24 | 25 | matlab: binary 26 | 27 | octave: 28 | @make MEX="$(OCTAVE_MEX)" MEX_OPTION="$(OCTAVE_MEX_OPTION)" \ 29 | MEX_EXT="$(OCTAVE_MEX_EXT)" CFLAGS="$(OCTAVE_CFLAGS)" \ 30 | binary 31 | 32 | binary: svmpredict.$(MEX_EXT) svmtrain.$(MEX_EXT) libsvmread.$(MEX_EXT) libsvmwrite.$(MEX_EXT) 33 | 34 | svmpredict.$(MEX_EXT): svmpredict.c ../svm.h ../svm.o svm_model_matlab.o 35 | $(MEX) $(MEX_OPTION) svmpredict.c ../svm.o svm_model_matlab.o 36 | 37 | svmtrain.$(MEX_EXT): svmtrain.c ../svm.h ../svm.o svm_model_matlab.o 38 | $(MEX) $(MEX_OPTION) svmtrain.c ../svm.o svm_model_matlab.o 39 | 40 | libsvmread.$(MEX_EXT): libsvmread.c 41 | $(MEX) $(MEX_OPTION) libsvmread.c 42 | 43 | libsvmwrite.$(MEX_EXT): libsvmwrite.c 44 | $(MEX) $(MEX_OPTION) libsvmwrite.c 45 | 46 | svm_model_matlab.o: svm_model_matlab.c ../svm.h 47 | $(CXX) $(CFLAGS) -c svm_model_matlab.c 48 | 49 | ../svm.o: 50 | cd ../; make svm.o 51 | 52 | clean: 53 | rm -f *~ *.o *.mex* *.obj ../svm.o 54 | -------------------------------------------------------------------------------- /matlab/README: -------------------------------------------------------------------------------- 1 | ----------------------------------------- 2 | --- MATLAB/OCTAVE interface of LIBSVM --- 3 | ----------------------------------------- 4 | 5 | Table of Contents 6 | ================= 7 | 8 | - Introduction 9 | - Installation 10 | - Usage 11 | - Returned Model Structure 12 | - Other Utilities 13 | - Examples 14 | - Additional Information 15 | 16 | 17 | Introduction 18 | ============ 19 | 20 | This tool provides a simple interface to LIBSVM, a library for support vector 21 | machines (http://www.csie.ntu.edu.tw/~cjlin/libsvm). It is very easy to use as 22 | the usage and the way of specifying parameters are the same as that of LIBSVM. 23 | 24 | Installation 25 | ============ 26 | 27 | On Unix systems, we recommend using GNU g++ as your 28 | compiler and type 'make' to build 'svmtrain.mexglx' and 'svmpredict.mexglx'. 29 | Note that we assume your MATLAB is installed in '/usr/local/matlab', 30 | if not, please change MATLABDIR in Makefile. 31 | 32 | Example: 33 | linux> make 34 | 35 | To use Octave, type 'make octave': 36 | 37 | Example: 38 | linux> make octave 39 | 40 | On Windows systems, pre-built binary files are already in the directory 41 | `..\windows', so no need to conduct installation. Now we include both 42 | 32bit binary files and 64bit binary files, but in future releases, we 43 | will provide binary files only for 64bit MATLAB on Windows. If you have 44 | modified the sources and would like to re-build the package, type 45 | 'mex -setup' in MATLAB to choose a compiler for mex first. Then type 46 | 'make' to start the installation. 47 | 48 | Example: 49 | matlab> mex -setup 50 | (ps: MATLAB will show the following messages to setup default compiler.) 51 | Please choose your compiler for building external interface (MEX) files: 52 | Would you like mex to locate installed compilers [y]/n? y 53 | Select a compiler: 54 | [1] Microsoft Visual C/C++ version 7.1 in C:\Program Files\Microsoft Visual Studio 55 | [0] None 56 | Compiler: 1 57 | Please verify your choices: 58 | Compiler: Microsoft Visual C/C++ 7.1 59 | Location: C:\Program Files\Microsoft Visual Studio 60 | Are these correct?([y]/n): y 61 | 62 | matlab> make 63 | 64 | 65 | For list of supported/compatible compilers for MATLAB, please check the 66 | following page: 67 | 68 | http://www.mathworks.com/support/compilers/current_release/ 69 | 70 | Usage 71 | ===== 72 | 73 | matlab> model = svmtrain(training_label_vector, training_instance_matrix [, 'libsvm_options']); 74 | 75 | -training_label_vector: 76 | An m by 1 vector of training labels (type must be double). 77 | -training_instance_matrix: 78 | An m by n matrix of m training instances with n features. 79 | It can be dense or sparse (type must be double). 80 | -libsvm_options: 81 | A string of training options in the same format as that of LIBSVM. 82 | 83 | matlab> [predicted_label, accuracy, decision_values/prob_estimates] = svmpredict(testing_label_vector, testing_instance_matrix, model [, 'libsvm_options']); 84 | 85 | -testing_label_vector: 86 | An m by 1 vector of prediction labels. If labels of test 87 | data are unknown, simply use any random values. (type must be double) 88 | -testing_instance_matrix: 89 | An m by n matrix of m testing instances with n features. 90 | It can be dense or sparse. (type must be double) 91 | -model: 92 | The output of svmtrain. 93 | -libsvm_options: 94 | A string of testing options in the same format as that of LIBSVM. 95 | 96 | Returned Model Structure 97 | ======================== 98 | 99 | The 'svmtrain' function returns a model which can be used for future 100 | prediction. It is a structure and is organized as [Parameters, nr_class, 101 | totalSV, rho, Label, ProbA, ProbB, nSV, sv_coef, SVs]: 102 | 103 | -Parameters: parameters 104 | -nr_class: number of classes; = 2 for regression/one-class svm 105 | -totalSV: total #SV 106 | -rho: -b of the decision function(s) wx+b 107 | -Label: label of each class; empty for regression/one-class SVM 108 | -ProbA: pairwise probability information; empty if -b 0 or in one-class SVM 109 | -ProbB: pairwise probability information; empty if -b 0 or in one-class SVM 110 | -nSV: number of SVs for each class; empty for regression/one-class SVM 111 | -sv_coef: coefficients for SVs in decision functions 112 | -SVs: support vectors 113 | 114 | If you do not use the option '-b 1', ProbA and ProbB are empty 115 | matrices. If the '-v' option is specified, cross validation is 116 | conducted and the returned model is just a scalar: cross-validation 117 | accuracy for classification and mean-squared error for regression. 118 | 119 | More details about this model can be found in LIBSVM FAQ 120 | (http://www.csie.ntu.edu.tw/~cjlin/libsvm/faq.html) and LIBSVM 121 | implementation document 122 | (http://www.csie.ntu.edu.tw/~cjlin/papers/libsvm.pdf). 123 | 124 | Result of Prediction 125 | ==================== 126 | 127 | The function 'svmpredict' has three outputs. The first one, 128 | predictd_label, is a vector of predicted labels. The second output, 129 | accuracy, is a vector including accuracy (for classification), mean 130 | squared error, and squared correlation coefficient (for regression). 131 | The third is a matrix containing decision values or probability 132 | estimates (if '-b 1' is specified). If k is the number of classes, 133 | for decision values, each row includes results of predicting 134 | k(k-1)/2 binary-class SVMs. For probabilities, each row contains k values 135 | indicating the probability that the testing instance is in each class. 136 | Note that the order of classes here is the same as 'Label' field 137 | in the model structure. 138 | 139 | Other Utilities 140 | =============== 141 | 142 | A matlab function libsvmread reads files in LIBSVM format: 143 | 144 | [label_vector, instance_matrix] = libsvmread('data.txt'); 145 | 146 | Two outputs are labels and instances, which can then be used as inputs 147 | of svmtrain or svmpredict. 148 | 149 | A matlab function libsvmwrite writes Matlab matrix to a file in LIBSVM format: 150 | 151 | libsvmwrite('data.txt', label_vector, instance_matrix] 152 | 153 | The instance_matrix must be a sparse matrix. (type must be double) 154 | For 32bit and 64bit MATLAB on Windows, pre-built binary files are ready 155 | in the directory `..\windows', but in future releases, we will only 156 | include 64bit MATLAB binary files. 157 | 158 | These codes are prepared by Rong-En Fan and Kai-Wei Chang from National 159 | Taiwan University. 160 | 161 | Examples 162 | ======== 163 | 164 | Train and test on the provided data heart_scale: 165 | 166 | matlab> [heart_scale_label, heart_scale_inst] = libsvmread('../heart_scale'); 167 | matlab> model = svmtrain(heart_scale_label, heart_scale_inst, '-c 1 -g 0.07'); 168 | matlab> [predict_label, accuracy, dec_values] = svmpredict(heart_scale_label, heart_scale_inst, model); % test the training data 169 | 170 | For probability estimates, you need '-b 1' for training and testing: 171 | 172 | matlab> [heart_scale_label, heart_scale_inst] = libsvmread('../heart_scale'); 173 | matlab> model = svmtrain(heart_scale_label, heart_scale_inst, '-c 1 -g 0.07 -b 1'); 174 | matlab> [heart_scale_label, heart_scale_inst] = libsvmread('../heart_scale'); 175 | matlab> [predict_label, accuracy, prob_estimates] = svmpredict(heart_scale_label, heart_scale_inst, model, '-b 1'); 176 | 177 | To use precomputed kernel, you must include sample serial number as 178 | the first column of the training and testing data (assume your kernel 179 | matrix is K, # of instances is n): 180 | 181 | matlab> K1 = [(1:n)', K]; % include sample serial number as first column 182 | matlab> model = svmtrain(label_vector, K1, '-t 4'); 183 | matlab> [predict_label, accuracy, dec_values] = svmpredict(label_vector, K1, model); % test the training data 184 | 185 | We give the following detailed example by splitting heart_scale into 186 | 150 training and 120 testing data. Constructing a linear kernel 187 | matrix and then using the precomputed kernel gives exactly the same 188 | testing error as using the LIBSVM built-in linear kernel. 189 | 190 | matlab> [heart_scale_label, heart_scale_inst] = libsvmread('../heart_scale'); 191 | matlab> 192 | matlab> % Split Data 193 | matlab> train_data = heart_scale_inst(1:150,:); 194 | matlab> train_label = heart_scale_label(1:150,:); 195 | matlab> test_data = heart_scale_inst(151:270,:); 196 | matlab> test_label = heart_scale_label(151:270,:); 197 | matlab> 198 | matlab> % Linear Kernel 199 | matlab> model_linear = svmtrain(train_label, train_data, '-t 0'); 200 | matlab> [predict_label_L, accuracy_L, dec_values_L] = svmpredict(test_label, test_data, model_linear); 201 | matlab> 202 | matlab> % Precomputed Kernel 203 | matlab> model_precomputed = svmtrain(train_label, [(1:150)', train_data*train_data'], '-t 4'); 204 | matlab> [predict_label_P, accuracy_P, dec_values_P] = svmpredict(test_label, [(1:120)', test_data*train_data'], model_precomputed); 205 | matlab> 206 | matlab> accuracy_L % Display the accuracy using linear kernel 207 | matlab> accuracy_P % Display the accuracy using precomputed kernel 208 | 209 | Note that for testing, you can put anything in the 210 | testing_label_vector. For more details of precomputed kernels, please 211 | read the section ``Precomputed Kernels'' in the README of the LIBSVM 212 | package. 213 | 214 | Additional Information 215 | ====================== 216 | 217 | This interface was initially written by Jun-Cheng Chen, Kuan-Jen Peng, 218 | Chih-Yuan Yang and Chih-Huai Cheng from Department of Computer 219 | Science, National Taiwan University. The current version was prepared 220 | by Rong-En Fan and Ting-Fan Wu. If you find this tool useful, please 221 | cite LIBSVM as follows 222 | 223 | Chih-Chung Chang and Chih-Jen Lin, LIBSVM : a library for 224 | support vector machines, 2001. Software available at 225 | http://www.csie.ntu.edu.tw/~cjlin/libsvm 226 | 227 | For any question, please contact Chih-Jen Lin , 228 | or check the FAQ page: 229 | 230 | http://www.csie.ntu.edu.tw/~cjlin/libsvm/faq.html#/Q9:_MATLAB_interface 231 | -------------------------------------------------------------------------------- /matlab/libsvmread.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "mex.h" 8 | 9 | #if MX_API_VER < 0x07030000 10 | typedef int mwIndex; 11 | #endif 12 | #ifndef max 13 | #define max(x,y) (((x)>(y))?(x):(y)) 14 | #endif 15 | #ifndef min 16 | #define min(x,y) (((x)<(y))?(x):(y)) 17 | #endif 18 | 19 | void exit_with_help() 20 | { 21 | mexPrintf( 22 | "Usage: [label_vector, instance_matrix] = libsvmread('filename');\n" 23 | ); 24 | } 25 | 26 | static void fake_answer(mxArray *plhs[]) 27 | { 28 | plhs[0] = mxCreateDoubleMatrix(0, 0, mxREAL); 29 | plhs[1] = mxCreateDoubleMatrix(0, 0, mxREAL); 30 | } 31 | 32 | static char *line; 33 | static int max_line_len; 34 | 35 | static char* readline(FILE *input) 36 | { 37 | int len; 38 | 39 | if(fgets(line,max_line_len,input) == NULL) 40 | return NULL; 41 | 42 | while(strrchr(line,'\n') == NULL) 43 | { 44 | max_line_len *= 2; 45 | line = (char *) realloc(line, max_line_len); 46 | len = (int) strlen(line); 47 | if(fgets(line+len,max_line_len-len,input) == NULL) 48 | break; 49 | } 50 | return line; 51 | } 52 | 53 | // read in a problem (in libsvm format) 54 | void read_problem(const char *filename, mxArray *plhs[]) 55 | { 56 | int max_index, min_index, inst_max_index, i; 57 | long elements, k; 58 | FILE *fp = fopen(filename,"r"); 59 | int l = 0; 60 | char *endptr; 61 | mwIndex *ir, *jc; 62 | double *labels, *samples; 63 | 64 | if(fp == NULL) 65 | { 66 | mexPrintf("can't open input file %s\n",filename); 67 | fake_answer(plhs); 68 | return; 69 | } 70 | 71 | max_line_len = 1024; 72 | line = (char *) malloc(max_line_len*sizeof(char)); 73 | 74 | max_index = 0; 75 | min_index = 1; // our index starts from 1 76 | elements = 0; 77 | while(readline(fp) != NULL) 78 | { 79 | char *idx, *val; 80 | // features 81 | int index = 0; 82 | 83 | inst_max_index = -1; // strtol gives 0 if wrong format, and precomputed kernel has start from 0 84 | strtok(line," \t"); // label 85 | while (1) 86 | { 87 | idx = strtok(NULL,":"); // index:value 88 | val = strtok(NULL," \t"); 89 | if(val == NULL) 90 | break; 91 | 92 | errno = 0; 93 | index = (int) strtol(idx,&endptr,10); 94 | if(endptr == idx || errno != 0 || *endptr != '\0' || index <= inst_max_index) 95 | { 96 | mexPrintf("Wrong input format at line %d\n",l+1); 97 | fake_answer(plhs); 98 | return; 99 | } 100 | else 101 | inst_max_index = index; 102 | 103 | min_index = min(min_index, index); 104 | elements++; 105 | } 106 | max_index = max(max_index, inst_max_index); 107 | l++; 108 | } 109 | rewind(fp); 110 | 111 | // y 112 | plhs[0] = mxCreateDoubleMatrix(l, 1, mxREAL); 113 | // x^T 114 | if (min_index <= 0) 115 | plhs[1] = mxCreateSparse(max_index-min_index+1, l, elements, mxREAL); 116 | else 117 | plhs[1] = mxCreateSparse(max_index, l, elements, mxREAL); 118 | 119 | labels = mxGetPr(plhs[0]); 120 | samples = mxGetPr(plhs[1]); 121 | ir = mxGetIr(plhs[1]); 122 | jc = mxGetJc(plhs[1]); 123 | 124 | k=0; 125 | for(i=0;i start from 0 156 | 157 | errno = 0; 158 | samples[k] = strtod(val,&endptr); 159 | if (endptr == val || errno != 0 || (*endptr != '\0' && !isspace(*endptr))) 160 | { 161 | mexPrintf("Wrong input format at line %d\n",i+1); 162 | fake_answer(plhs); 163 | return; 164 | } 165 | ++k; 166 | } 167 | } 168 | jc[l] = k; 169 | 170 | fclose(fp); 171 | free(line); 172 | 173 | { 174 | mxArray *rhs[1], *lhs[1]; 175 | rhs[0] = plhs[1]; 176 | if(mexCallMATLAB(1, lhs, 1, rhs, "transpose")) 177 | { 178 | mexPrintf("Error: cannot transpose problem\n"); 179 | fake_answer(plhs); 180 | return; 181 | } 182 | plhs[1] = lhs[0]; 183 | } 184 | } 185 | 186 | void mexFunction( int nlhs, mxArray *plhs[], 187 | int nrhs, const mxArray *prhs[] ) 188 | { 189 | if(nrhs == 1) 190 | { 191 | char filename[256]; 192 | 193 | mxGetString(prhs[0], filename, mxGetN(prhs[0]) + 1); 194 | 195 | if(filename == NULL) 196 | { 197 | mexPrintf("Error: filename is NULL\n"); 198 | return; 199 | } 200 | 201 | read_problem(filename, plhs); 202 | } 203 | else 204 | { 205 | exit_with_help(); 206 | fake_answer(plhs); 207 | return; 208 | } 209 | } 210 | 211 | -------------------------------------------------------------------------------- /matlab/libsvmwrite.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "mex.h" 5 | 6 | #if MX_API_VER < 0x07030000 7 | typedef int mwIndex; 8 | #endif 9 | 10 | void exit_with_help() 11 | { 12 | mexPrintf( 13 | "Usage: libsvmwrite('filename', label_vector, instance_matrix);\n" 14 | ); 15 | } 16 | 17 | void libsvmwrite(const char *filename, const mxArray *label_vec, const mxArray *instance_mat) 18 | { 19 | FILE *fp = fopen(filename,"w"); 20 | int i, k, low, high, l; 21 | mwIndex *ir, *jc; 22 | int label_vector_row_num; 23 | double *samples, *labels; 24 | mxArray *instance_mat_col; // instance sparse matrix in column format 25 | 26 | if(fp ==NULL) 27 | { 28 | mexPrintf("can't open output file %s\n",filename); 29 | return; 30 | } 31 | 32 | // transpose instance matrix 33 | { 34 | mxArray *prhs[1], *plhs[1]; 35 | prhs[0] = mxDuplicateArray(instance_mat); 36 | if(mexCallMATLAB(1, plhs, 1, prhs, "transpose")) 37 | { 38 | mexPrintf("Error: cannot transpose instance matrix\n"); 39 | return; 40 | } 41 | instance_mat_col = plhs[0]; 42 | mxDestroyArray(prhs[0]); 43 | } 44 | 45 | // the number of instance 46 | l = (int) mxGetN(instance_mat_col); 47 | label_vector_row_num = (int) mxGetM(label_vec); 48 | 49 | if(label_vector_row_num!=l) 50 | { 51 | mexPrintf("Length of label vector does not match # of instances.\n"); 52 | return; 53 | } 54 | 55 | // each column is one instance 56 | labels = mxGetPr(label_vec); 57 | samples = mxGetPr(instance_mat_col); 58 | ir = mxGetIr(instance_mat_col); 59 | jc = mxGetJc(instance_mat_col); 60 | 61 | for(i=0;i 2 | #include 3 | #include "svm.h" 4 | 5 | #include "mex.h" 6 | 7 | #if MX_API_VER < 0x07030000 8 | typedef int mwIndex; 9 | #endif 10 | 11 | #define NUM_OF_RETURN_FIELD 10 12 | 13 | #define Malloc(type,n) (type *)malloc((n)*sizeof(type)) 14 | 15 | static const char *field_names[] = { 16 | "Parameters", 17 | "nr_class", 18 | "totalSV", 19 | "rho", 20 | "Label", 21 | "ProbA", 22 | "ProbB", 23 | "nSV", 24 | "sv_coef", 25 | "SVs" 26 | }; 27 | 28 | const char *model_to_matlab_structure(mxArray *plhs[], int num_of_feature, struct svm_model *model) 29 | { 30 | int i, j, n; 31 | double *ptr; 32 | mxArray *return_model, **rhs; 33 | int out_id = 0; 34 | 35 | rhs = (mxArray **)mxMalloc(sizeof(mxArray *)*NUM_OF_RETURN_FIELD); 36 | 37 | // Parameters 38 | rhs[out_id] = mxCreateDoubleMatrix(5, 1, mxREAL); 39 | ptr = mxGetPr(rhs[out_id]); 40 | ptr[0] = model->param.svm_type; 41 | ptr[1] = model->param.kernel_type; 42 | ptr[2] = model->param.degree; 43 | ptr[3] = model->param.gamma; 44 | ptr[4] = model->param.coef0; 45 | out_id++; 46 | 47 | // nr_class 48 | rhs[out_id] = mxCreateDoubleMatrix(1, 1, mxREAL); 49 | ptr = mxGetPr(rhs[out_id]); 50 | ptr[0] = model->nr_class; 51 | out_id++; 52 | 53 | // total SV 54 | rhs[out_id] = mxCreateDoubleMatrix(1, 1, mxREAL); 55 | ptr = mxGetPr(rhs[out_id]); 56 | ptr[0] = model->l; 57 | out_id++; 58 | 59 | // rho 60 | n = model->nr_class*(model->nr_class-1)/2; 61 | rhs[out_id] = mxCreateDoubleMatrix(n, 1, mxREAL); 62 | ptr = mxGetPr(rhs[out_id]); 63 | for(i = 0; i < n; i++) 64 | ptr[i] = model->rho[i]; 65 | out_id++; 66 | 67 | // Label 68 | if(model->label) 69 | { 70 | rhs[out_id] = mxCreateDoubleMatrix(model->nr_class, 1, mxREAL); 71 | ptr = mxGetPr(rhs[out_id]); 72 | for(i = 0; i < model->nr_class; i++) 73 | ptr[i] = model->label[i]; 74 | } 75 | else 76 | rhs[out_id] = mxCreateDoubleMatrix(0, 0, mxREAL); 77 | out_id++; 78 | 79 | // probA 80 | if(model->probA != NULL) 81 | { 82 | rhs[out_id] = mxCreateDoubleMatrix(n, 1, mxREAL); 83 | ptr = mxGetPr(rhs[out_id]); 84 | for(i = 0; i < n; i++) 85 | ptr[i] = model->probA[i]; 86 | } 87 | else 88 | rhs[out_id] = mxCreateDoubleMatrix(0, 0, mxREAL); 89 | out_id ++; 90 | 91 | // probB 92 | if(model->probB != NULL) 93 | { 94 | rhs[out_id] = mxCreateDoubleMatrix(n, 1, mxREAL); 95 | ptr = mxGetPr(rhs[out_id]); 96 | for(i = 0; i < n; i++) 97 | ptr[i] = model->probB[i]; 98 | } 99 | else 100 | rhs[out_id] = mxCreateDoubleMatrix(0, 0, mxREAL); 101 | out_id++; 102 | 103 | // nSV 104 | if(model->nSV) 105 | { 106 | rhs[out_id] = mxCreateDoubleMatrix(model->nr_class, 1, mxREAL); 107 | ptr = mxGetPr(rhs[out_id]); 108 | for(i = 0; i < model->nr_class; i++) 109 | ptr[i] = model->nSV[i]; 110 | } 111 | else 112 | rhs[out_id] = mxCreateDoubleMatrix(0, 0, mxREAL); 113 | out_id++; 114 | 115 | // sv_coef 116 | rhs[out_id] = mxCreateDoubleMatrix(model->l, model->nr_class-1, mxREAL); 117 | ptr = mxGetPr(rhs[out_id]); 118 | for(i = 0; i < model->nr_class-1; i++) 119 | for(j = 0; j < model->l; j++) 120 | ptr[(i*(model->l))+j] = model->sv_coef[i][j]; 121 | out_id++; 122 | 123 | // SVs 124 | { 125 | int ir_index, nonzero_element; 126 | mwIndex *ir, *jc; 127 | mxArray *pprhs[1], *pplhs[1]; 128 | 129 | if(model->param.kernel_type == PRECOMPUTED) 130 | { 131 | nonzero_element = model->l; 132 | num_of_feature = 1; 133 | } 134 | else 135 | { 136 | nonzero_element = 0; 137 | for(i = 0; i < model->l; i++) { 138 | j = 0; 139 | while(model->SV[i][j].index != -1) 140 | { 141 | nonzero_element++; 142 | j++; 143 | } 144 | } 145 | } 146 | 147 | // SV in column, easier accessing 148 | rhs[out_id] = mxCreateSparse(num_of_feature, model->l, nonzero_element, mxREAL); 149 | ir = mxGetIr(rhs[out_id]); 150 | jc = mxGetJc(rhs[out_id]); 151 | ptr = mxGetPr(rhs[out_id]); 152 | jc[0] = ir_index = 0; 153 | for(i = 0;i < model->l; i++) 154 | { 155 | if(model->param.kernel_type == PRECOMPUTED) 156 | { 157 | // make a (1 x model->l) matrix 158 | ir[ir_index] = 0; 159 | ptr[ir_index] = model->SV[i][0].value; 160 | ir_index++; 161 | jc[i+1] = jc[i] + 1; 162 | } 163 | else 164 | { 165 | int x_index = 0; 166 | while (model->SV[i][x_index].index != -1) 167 | { 168 | ir[ir_index] = model->SV[i][x_index].index - 1; 169 | ptr[ir_index] = model->SV[i][x_index].value; 170 | ir_index++, x_index++; 171 | } 172 | jc[i+1] = jc[i] + x_index; 173 | } 174 | } 175 | // transpose back to SV in row 176 | pprhs[0] = rhs[out_id]; 177 | if(mexCallMATLAB(1, pplhs, 1, pprhs, "transpose")) 178 | return "cannot transpose SV matrix"; 179 | rhs[out_id] = pplhs[0]; 180 | out_id++; 181 | } 182 | 183 | /* Create a struct matrix contains NUM_OF_RETURN_FIELD fields */ 184 | return_model = mxCreateStructMatrix(1, 1, NUM_OF_RETURN_FIELD, field_names); 185 | 186 | /* Fill struct matrix with input arguments */ 187 | for(i = 0; i < NUM_OF_RETURN_FIELD; i++) 188 | mxSetField(return_model,0,field_names[i],mxDuplicateArray(rhs[i])); 189 | /* return */ 190 | plhs[0] = return_model; 191 | mxFree(rhs); 192 | 193 | return NULL; 194 | } 195 | 196 | struct svm_model *matlab_matrix_to_model(const mxArray *matlab_struct, const char **msg) 197 | { 198 | int i, j, n, num_of_fields; 199 | double *ptr; 200 | int id = 0; 201 | struct svm_node *x_space; 202 | struct svm_model *model; 203 | mxArray **rhs; 204 | 205 | num_of_fields = mxGetNumberOfFields(matlab_struct); 206 | if(num_of_fields != NUM_OF_RETURN_FIELD) 207 | { 208 | *msg = "number of return field is not correct"; 209 | return NULL; 210 | } 211 | rhs = (mxArray **) mxMalloc(sizeof(mxArray *)*num_of_fields); 212 | 213 | for(i=0;irho = NULL; 218 | model->probA = NULL; 219 | model->probB = NULL; 220 | model->label = NULL; 221 | model->nSV = NULL; 222 | model->free_sv = 1; // XXX 223 | 224 | ptr = mxGetPr(rhs[id]); 225 | model->param.svm_type = (int)ptr[0]; 226 | model->param.kernel_type = (int)ptr[1]; 227 | model->param.degree = (int)ptr[2]; 228 | model->param.gamma = ptr[3]; 229 | model->param.coef0 = ptr[4]; 230 | id++; 231 | 232 | ptr = mxGetPr(rhs[id]); 233 | model->nr_class = (int)ptr[0]; 234 | id++; 235 | 236 | ptr = mxGetPr(rhs[id]); 237 | model->l = (int)ptr[0]; 238 | id++; 239 | 240 | // rho 241 | n = model->nr_class * (model->nr_class-1)/2; 242 | model->rho = (double*) malloc(n*sizeof(double)); 243 | ptr = mxGetPr(rhs[id]); 244 | for(i=0;irho[i] = ptr[i]; 246 | id++; 247 | 248 | // label 249 | if(mxIsEmpty(rhs[id]) == 0) 250 | { 251 | model->label = (int*) malloc(model->nr_class*sizeof(int)); 252 | ptr = mxGetPr(rhs[id]); 253 | for(i=0;inr_class;i++) 254 | model->label[i] = (int)ptr[i]; 255 | } 256 | id++; 257 | 258 | // probA 259 | if(mxIsEmpty(rhs[id]) == 0) 260 | { 261 | model->probA = (double*) malloc(n*sizeof(double)); 262 | ptr = mxGetPr(rhs[id]); 263 | for(i=0;iprobA[i] = ptr[i]; 265 | } 266 | id++; 267 | 268 | // probB 269 | if(mxIsEmpty(rhs[id]) == 0) 270 | { 271 | model->probB = (double*) malloc(n*sizeof(double)); 272 | ptr = mxGetPr(rhs[id]); 273 | for(i=0;iprobB[i] = ptr[i]; 275 | } 276 | id++; 277 | 278 | // nSV 279 | if(mxIsEmpty(rhs[id]) == 0) 280 | { 281 | model->nSV = (int*) malloc(model->nr_class*sizeof(int)); 282 | ptr = mxGetPr(rhs[id]); 283 | for(i=0;inr_class;i++) 284 | model->nSV[i] = (int)ptr[i]; 285 | } 286 | id++; 287 | 288 | // sv_coef 289 | ptr = mxGetPr(rhs[id]); 290 | model->sv_coef = (double**) malloc((model->nr_class-1)*sizeof(double)); 291 | for( i=0 ; i< model->nr_class -1 ; i++ ) 292 | model->sv_coef[i] = (double*) malloc((model->l)*sizeof(double)); 293 | for(i = 0; i < model->nr_class - 1; i++) 294 | for(j = 0; j < model->l; j++) 295 | model->sv_coef[i][j] = ptr[i*(model->l)+j]; 296 | id++; 297 | 298 | // SV 299 | { 300 | int sr, sc, elements; 301 | int num_samples; 302 | mwIndex *ir, *jc; 303 | mxArray *pprhs[1], *pplhs[1]; 304 | 305 | // transpose SV 306 | pprhs[0] = rhs[id]; 307 | if(mexCallMATLAB(1, pplhs, 1, pprhs, "transpose")) 308 | { 309 | svm_free_and_destroy_model(&model); 310 | *msg = "cannot transpose SV matrix"; 311 | return NULL; 312 | } 313 | rhs[id] = pplhs[0]; 314 | 315 | sr = (int)mxGetN(rhs[id]); 316 | sc = (int)mxGetM(rhs[id]); 317 | 318 | ptr = mxGetPr(rhs[id]); 319 | ir = mxGetIr(rhs[id]); 320 | jc = mxGetJc(rhs[id]); 321 | 322 | num_samples = (int)mxGetNzmax(rhs[id]); 323 | 324 | elements = num_samples + sr; 325 | 326 | model->SV = (struct svm_node **) malloc(sr * sizeof(struct svm_node *)); 327 | x_space = (struct svm_node *)malloc(elements * sizeof(struct svm_node)); 328 | 329 | // SV is in column 330 | for(i=0;iSV[i] = &x_space[low+i]; 335 | for(j=low;jSV[i][x_index].index = (int)ir[j] + 1; 338 | model->SV[i][x_index].value = ptr[j]; 339 | x_index++; 340 | } 341 | model->SV[i][x_index].index = -1; 342 | } 343 | 344 | id++; 345 | } 346 | mxFree(rhs); 347 | 348 | return model; 349 | } 350 | -------------------------------------------------------------------------------- /matlab/svm_model_matlab.h: -------------------------------------------------------------------------------- 1 | const char *model_to_matlab_structure(mxArray *plhs[], int num_of_feature, struct svm_model *model); 2 | struct svm_model *matlab_matrix_to_model(const mxArray *matlab_struct, const char **error_message); 3 | -------------------------------------------------------------------------------- /matlab/svmpredict.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "svm.h" 5 | 6 | #include "mex.h" 7 | #include "svm_model_matlab.h" 8 | 9 | #if MX_API_VER < 0x07030000 10 | typedef int mwIndex; 11 | #endif 12 | 13 | #define CMD_LEN 2048 14 | 15 | void read_sparse_instance(const mxArray *prhs, int index, struct svm_node *x) 16 | { 17 | int i, j, low, high; 18 | mwIndex *ir, *jc; 19 | double *samples; 20 | 21 | ir = mxGetIr(prhs); 22 | jc = mxGetJc(prhs); 23 | samples = mxGetPr(prhs); 24 | 25 | // each column is one instance 26 | j = 0; 27 | low = (int)jc[index], high = (int)jc[index+1]; 28 | for(i=low;iparam.kernel_type == PRECOMPUTED) 89 | { 90 | // precomputed kernel requires dense matrix, so we make one 91 | mxArray *rhs[1], *lhs[1]; 92 | rhs[0] = mxDuplicateArray(prhs[1]); 93 | if(mexCallMATLAB(1, lhs, 1, rhs, "full")) 94 | { 95 | mexPrintf("Error: cannot full testing instance matrix\n"); 96 | fake_answer(plhs); 97 | return; 98 | } 99 | ptr_instance = mxGetPr(lhs[0]); 100 | mxDestroyArray(rhs[0]); 101 | } 102 | else 103 | { 104 | mxArray *pprhs[1]; 105 | pprhs[0] = mxDuplicateArray(prhs[1]); 106 | if(mexCallMATLAB(1, pplhs, 1, pprhs, "transpose")) 107 | { 108 | mexPrintf("Error: cannot transpose testing instance matrix\n"); 109 | fake_answer(plhs); 110 | return; 111 | } 112 | } 113 | } 114 | 115 | if(predict_probability) 116 | { 117 | if(svm_type==NU_SVR || svm_type==EPSILON_SVR) 118 | mexPrintf("Prob. model for test data: target value = predicted value + z,\nz: Laplace distribution e^(-|z|/sigma)/(2sigma),sigma=%g\n",svm_get_svr_probability(model)); 119 | else 120 | prob_estimates = (double *) malloc(nr_class*sizeof(double)); 121 | } 122 | 123 | plhs[0] = mxCreateDoubleMatrix(testing_instance_number, 1, mxREAL); 124 | if(predict_probability) 125 | { 126 | // prob estimates are in plhs[2] 127 | if(svm_type==C_SVC || svm_type==NU_SVC) 128 | plhs[2] = mxCreateDoubleMatrix(testing_instance_number, nr_class, mxREAL); 129 | else 130 | plhs[2] = mxCreateDoubleMatrix(0, 0, mxREAL); 131 | } 132 | else 133 | { 134 | // decision values are in plhs[2] 135 | if(svm_type == ONE_CLASS || 136 | svm_type == EPSILON_SVR || 137 | svm_type == NU_SVR) 138 | plhs[2] = mxCreateDoubleMatrix(testing_instance_number, 1, mxREAL); 139 | else 140 | plhs[2] = mxCreateDoubleMatrix(testing_instance_number, nr_class*(nr_class-1)/2, mxREAL); 141 | } 142 | 143 | ptr_predict_label = mxGetPr(plhs[0]); 144 | ptr_prob_estimates = mxGetPr(plhs[2]); 145 | ptr_dec_values = mxGetPr(plhs[2]); 146 | x = (struct svm_node*)malloc((feature_number+1)*sizeof(struct svm_node) ); 147 | for(instance_index=0;instance_indexparam.kernel_type != PRECOMPUTED) // prhs[1]^T is still sparse 155 | read_sparse_instance(pplhs[0], instance_index, x); 156 | else 157 | { 158 | for(i=0;i 4 || nrhs < 3) 257 | { 258 | exit_with_help(); 259 | fake_answer(plhs); 260 | return; 261 | } 262 | 263 | if(!mxIsDouble(prhs[0]) || !mxIsDouble(prhs[1])) { 264 | mexPrintf("Error: label vector and instance matrix must be double\n"); 265 | fake_answer(plhs); 266 | return; 267 | } 268 | 269 | if(mxIsStruct(prhs[2])) 270 | { 271 | const char *error_msg; 272 | 273 | // parse options 274 | if(nrhs==4) 275 | { 276 | int i, argc = 1; 277 | char cmd[CMD_LEN], *argv[CMD_LEN/2]; 278 | 279 | // put options in argv[] 280 | mxGetString(prhs[3], cmd, mxGetN(prhs[3]) + 1); 281 | if((argv[argc] = strtok(cmd, " ")) != NULL) 282 | while((argv[++argc] = strtok(NULL, " ")) != NULL) 283 | ; 284 | 285 | for(i=1;i=argc) 289 | { 290 | exit_with_help(); 291 | fake_answer(plhs); 292 | return; 293 | } 294 | switch(argv[i-1][1]) 295 | { 296 | case 'b': 297 | prob_estimate_flag = atoi(argv[i]); 298 | break; 299 | default: 300 | mexPrintf("Unknown option: -%c\n", argv[i-1][1]); 301 | exit_with_help(); 302 | fake_answer(plhs); 303 | return; 304 | } 305 | } 306 | } 307 | 308 | model = matlab_matrix_to_model(prhs[2], &error_msg); 309 | if (model == NULL) 310 | { 311 | mexPrintf("Error: can't read model: %s\n", error_msg); 312 | fake_answer(plhs); 313 | return; 314 | } 315 | 316 | if(prob_estimate_flag) 317 | { 318 | if(svm_check_probability_model(model)==0) 319 | { 320 | mexPrintf("Model does not support probabiliy estimates\n"); 321 | fake_answer(plhs); 322 | svm_free_and_destroy_model(&model); 323 | return; 324 | } 325 | } 326 | else 327 | { 328 | if(svm_check_probability_model(model)!=0) 329 | mexPrintf("Model supports probability estimates, but disabled in predicton.\n"); 330 | } 331 | 332 | predict(plhs, prhs, model, prob_estimate_flag); 333 | // destroy model 334 | svm_free_and_destroy_model(&model); 335 | } 336 | else 337 | { 338 | mexPrintf("model file should be a struct array\n"); 339 | fake_answer(plhs); 340 | } 341 | 342 | return; 343 | } 344 | -------------------------------------------------------------------------------- /python/Makefile: -------------------------------------------------------------------------------- 1 | all = lib 2 | 3 | lib: 4 | cd ..; make lib; cd - 5 | -------------------------------------------------------------------------------- /python/README: -------------------------------------------------------------------------------- 1 | ---------------------------------- 2 | --- Python interface of LIBSVM --- 3 | ---------------------------------- 4 | 5 | Table of Contents 6 | ================= 7 | 8 | - Introduction 9 | - Installation 10 | - Quick Start 11 | - Design Description 12 | - Data Structures 13 | - Utility Functions 14 | - Additional Information 15 | 16 | Introduction 17 | ============ 18 | 19 | Python (http://www.python.org/) is a programming language suitable for rapid 20 | development. This tool provides a simple Python interface to LIBSVM, a library 21 | for support vector machines (http://www.csie.ntu.edu.tw/~cjlin/libsvm). The 22 | interface is very easy to use as the usage is the same as that of LIBSVM. The 23 | interface is developed with the built-in Python library "ctypes." 24 | 25 | Installation 26 | ============ 27 | 28 | On Unix systems, type 29 | 30 | > make 31 | 32 | The interface needs only LIBSVM shared library, which is generated by 33 | the above command. We assume that the shared library is on the LIBSVM 34 | main directory or in the system path. 35 | 36 | For windows, the shared library libsvm.dll is ready in the directory 37 | `..\windows'. You can also copy it to the system directory (e.g., 38 | `C:\WINDOWS\system32\' for Windows XP). To regenerate the shared library, 39 | please follow the instruction of building windows binaries in LIBSVM README. 40 | 41 | Quick Start 42 | =========== 43 | 44 | There are two levels of usage. The high-level one uses utility functions 45 | in svmutil.py and the usage is the same as the LIBSVM MATLAB interface. 46 | 47 | >>> from svmutil import * 48 | # Read data in LIBSVM format 49 | >>> y, x = svm_read_problem('../heart_scale') 50 | >>> m = svm_train(y[:200], x[:200], '-c 4') 51 | >>> p_label, p_acc, p_val = svm_predict(y[200:], x[200:], m) 52 | 53 | # Construct problem in python format 54 | # Dense data 55 | >>> y, x = [1,-1], [[1,0,1], [-1,0,-1]] 56 | # Sparse data 57 | >>> y, x = [1,-1], [{1:1, 3:1}, {1:-1,3:-1}] 58 | >>> prob = svm_problem(y, x) 59 | >>> param = svm_parameter('-c 4 -b 1') 60 | >>> m = svm_train(prob, param) 61 | 62 | # Other utility functions 63 | >>> svm_save_model('heart_scale.model', m) 64 | >>> m = svm_load_model('heart_scale.model') 65 | >>> p_label, p_acc, p_val = svm_predict(y, x, m, '-b 1') 66 | >>> ACC, MSE, SCC = evaluations(y, p_val) 67 | 68 | # Getting online help 69 | >>> help(svm_train) 70 | 71 | The low-level use directly calls C interfaces imported by svm.py. Note that 72 | all arguments and return values are in ctypes format. You need to handle them 73 | carefully. 74 | 75 | >>> from svm import * 76 | >>> prob = svm_problem([1,-1], [{1:1, 3:1}, {1:-1,3:-1}]) 77 | >>> param = svm_parameter('-c 4') 78 | >>> m = libsvm.svm_train(prob, param) # m is a ctype pointer to an svm_model 79 | # Convert a Python-format instance to svm_nodearray, a ctypes structure 80 | >>> x0, max_idx = gen_svm_nodearray({1:1, 3:1}) 81 | >>> label = libsvm.svm_predict(m, x0) 82 | 83 | Design Description 84 | ================== 85 | 86 | There are two files svm.py and svmutil.py, which respectively correspond to 87 | low-level and high-level use of the interface. 88 | 89 | In svm.py, we adopt the Python built-in library "ctypes," so that 90 | Python can directly access C structures and interface functions defined 91 | in svm.h. 92 | 93 | While advanced users can use structures/functions in svm.py, to 94 | avoid handling ctypes structures, in svmutil.py we provide some easy-to-use 95 | functions. The usage is similar to LIBSVM MATLAB interface. 96 | 97 | Data Structures 98 | =============== 99 | 100 | Four data structures derived from svm.h are svm_node, svm_problem, svm_parameter, 101 | and svm_model. They all contain fields with the same names in svm.h. Access 102 | these fields carefully because you directly use a C structure instead of a 103 | Python object. For svm_model, accessing the field directly is not recommanded. 104 | Programmers should use the interface functions or methods of svm_model class 105 | in Python to get the values. The following description introduces additional 106 | fields and methods. 107 | 108 | Before using the data structures, execute the following command to load the 109 | LIBSVM shared library: 110 | 111 | >>> from svm import * 112 | 113 | - class svm_node: 114 | 115 | Construct an svm_node. 116 | 117 | >>> node = svm_node(idx, val) 118 | 119 | idx: an integer indicates the feature index. 120 | 121 | val: a float indicates the feature value. 122 | 123 | - Function: gen_svm_nodearray(xi [,feature_max=None [,issparse=False]]) 124 | 125 | Generate a feature vector from a Python list/tuple or a dictionary: 126 | 127 | >>> xi, max_idx = gen_svm_nodearray({1:1, 3:1, 5:-2}) 128 | 129 | xi: the returned svm_nodearray (a ctypes structure) 130 | 131 | max_idx: the maximal feature index of xi 132 | 133 | issparse: if issparse == True, zero feature values are removed. The default 134 | value is False for supporting the pre-computed kernel. 135 | 136 | feature_max: if feature_max is assigned, features with indices larger than 137 | feature_max are removed. 138 | 139 | - class svm_problem: 140 | 141 | Construct an svm_problem instance 142 | 143 | >>> prob = svm_problem(y, x) 144 | 145 | y: a Python list/tuple of l labels (type must be int/double). 146 | 147 | x: a Python list/tuple of l data instances. Each element of x must be 148 | an instance of list/tuple/dictionary type. 149 | 150 | Note that if your x contains sparse data (i.e., dictionary), the internal 151 | ctypes data format is still sparse. 152 | 153 | - class svm_parameter: 154 | 155 | Construct an svm_parameter instance 156 | 157 | >>> param = svm_parameter('training_options') 158 | 159 | If 'training_options' is empty, LIBSVM default values are applied. 160 | 161 | Set param to LIBSVM default values. 162 | 163 | >>> param.set_to_default_values() 164 | 165 | Parse a string of options. 166 | 167 | >>> param.parse_options('training_options') 168 | 169 | Show values of parameters. 170 | 171 | >>> param.show() 172 | 173 | - class svm_model: 174 | 175 | There are two ways to obtain an instance of svm_model: 176 | 177 | >>> model = svm_train(y, x) 178 | >>> model = svm_load_model('model_file_name') 179 | 180 | Note that the returned structure of interface functions 181 | libsvm.svm_train and libsvm.svm_load_model is a ctypes pointer of 182 | svm_model, which is different from the svm_model object returned 183 | by svm_train and svm_load_model in svmutil.py. We provide a 184 | function toPyModel for the conversion: 185 | 186 | >>> model_ptr = libsvm.svm_train(prob, param) 187 | >>> model = toPyModel(model_ptr) 188 | 189 | If you obtain a model in a way other than the above approaches, 190 | handle it carefully to avoid memory leak or segmentation fault. 191 | 192 | Some interface functions to access LIBSVM models are wrapped as 193 | members of the class svm_model: 194 | 195 | >>> svm_type = model.get_svm_type() 196 | >>> nr_class = model.get_nr_class() 197 | >>> svr_probability = model.get_svr_probability() 198 | >>> class_labels = model.get_labels() 199 | >>> is_prob_model = model.is_probability_model() 200 | >>> support_vector_coefficients = model.get_sv_coef() 201 | >>> support_vectors = model.get_SV() 202 | 203 | Utility Functions 204 | ================= 205 | 206 | To use utility functions, type 207 | 208 | >>> from svmutil import * 209 | 210 | The above command loads 211 | svm_train() : train an SVM model 212 | svm_predict() : predict testing data 213 | svm_read_problem() : read the data from a LIBSVM-format file. 214 | svm_load_model() : load a LIBSVM model. 215 | svm_save_model() : save model to a file. 216 | evaluations() : evaluate prediction results. 217 | 218 | - Function: svm_train 219 | 220 | There are three ways to call svm_train() 221 | 222 | >>> model = svm_train(y, x [, 'training_options']) 223 | >>> model = svm_train(prob [, 'training_options']) 224 | >>> model = svm_train(prob, param) 225 | 226 | y: a list/tuple of l training labels (type must be int/double). 227 | 228 | x: a list/tuple of l training instances. The feature vector of 229 | each training instance is an instance of list/tuple or dictionary. 230 | 231 | training_options: a string in the same form as that for LIBSVM command 232 | mode. 233 | 234 | prob: an svm_problem instance generated by calling 235 | svm_problem(y, x). 236 | 237 | param: an svm_parameter instance generated by calling 238 | svm_parameter('training_options') 239 | 240 | model: the returned svm_model instance. See svm.h for details of this 241 | structure. If '-v' is specified, cross validation is 242 | conducted and the returned model is just a scalar: cross-validation 243 | accuracy for classification and mean-squared error for regression. 244 | 245 | To train the same data many times with different 246 | parameters, the second and the third ways should be faster.. 247 | 248 | Examples: 249 | 250 | >>> y, x = svm_read_problem('../heart_scale') 251 | >>> prob = svm_problem(y, x) 252 | >>> param = svm_parameter('-s 3 -c 5 -h 0') 253 | >>> m = svm_train(y, x, '-c 5') 254 | >>> m = svm_train(prob, '-t 2 -c 5') 255 | >>> m = svm_train(prob, param) 256 | >>> CV_ACC = svm_train(y, x, '-v 3') 257 | 258 | - Function: svm_predict 259 | 260 | To predict testing data with a model, use 261 | 262 | >>> p_labs, p_acc, p_vals = svm_predict(y, x, model [,'predicting_options']) 263 | 264 | y: a list/tuple of l true labels (type must be int/double). It is used 265 | for calculating the accuracy. Use [0]*len(x) if true labels are 266 | unavailable. 267 | 268 | x: a list/tuple of l predicting instances. The feature vector of 269 | each predicting instance is an instance of list/tuple or dictionary. 270 | 271 | predicting_options: a string of predicting options in the same format as 272 | that of LIBSVM. 273 | 274 | model: an svm_model instance. 275 | 276 | p_labels: a list of predicted labels 277 | 278 | p_acc: a tuple including accuracy (for classification), mean 279 | squared error, and squared correlation coefficient (for 280 | regression). 281 | 282 | p_vals: a list of decision values or probability estimates (if '-b 1' 283 | is specified). If k is the number of classes, for decision values, 284 | each element includes results of predicting k(k-1)/2 binary-class 285 | SVMs. For probabilities, each element contains k values indicating 286 | the probability that the testing instance is in each class. 287 | Note that the order of classes is the same as the 'model.label' 288 | field in the model structure. 289 | 290 | Example: 291 | 292 | >>> m = svm_train(y, x, '-c 5') 293 | >>> p_labels, p_acc, p_vals = svm_predict(y, x, m) 294 | 295 | - Functions: svm_read_problem/svm_load_model/svm_save_model 296 | 297 | See the usage by examples: 298 | 299 | >>> y, x = svm_read_problem('data.txt') 300 | >>> m = svm_load_model('model_file') 301 | >>> svm_save_model('model_file', m) 302 | 303 | - Function: evaluations 304 | 305 | Calculate some evaluations using the true values (ty) and predicted 306 | values (pv): 307 | 308 | >>> (ACC, MSE, SCC) = evaluations(ty, pv) 309 | 310 | ty: a list of true values. 311 | 312 | pv: a list of predict values. 313 | 314 | ACC: accuracy. 315 | 316 | MSE: mean squared error. 317 | 318 | SCC: squared correlation coefficient. 319 | 320 | 321 | Additional Information 322 | ====================== 323 | 324 | This interface was written by Hsiang-Fu Yu from Department of Computer 325 | Science, National Taiwan University. If you find this tool useful, please 326 | cite LIBSVM as follows 327 | 328 | Chih-Chung Chang and Chih-Jen Lin, LIBSVM : a library for 329 | support vector machines, 2001. Software available at 330 | http://www.csie.ntu.edu.tw/~cjlin/libsvm 331 | 332 | For any question, please contact Chih-Jen Lin , 333 | or check the FAQ page: 334 | 335 | http://www.csie.ntu.edu.tw/~cjlin/libsvm/faq.html 336 | -------------------------------------------------------------------------------- /python/svm.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from ctypes import * 4 | from ctypes.util import find_library 5 | import sys 6 | import os 7 | 8 | # For unix the prefix 'lib' is not considered. 9 | if find_library('svm'): 10 | libsvm = CDLL(find_library('svm')) 11 | elif find_library('libsvm'): 12 | libsvm = CDLL(find_library('libsvm')) 13 | else: 14 | if sys.platform == 'win32': 15 | libsvm = CDLL(os.path.join(os.path.dirname(__file__),\ 16 | '../windows/libsvm.dll')) 17 | else: 18 | libsvm = CDLL(os.path.join(os.path.dirname(__file__),\ 19 | '../libsvm.so.2')) 20 | 21 | # Construct constants 22 | SVM_TYPE = ['C_SVC', 'NU_SVC', 'ONE_CLASS', 'EPSILON_SVR', 'NU_SVR' ] 23 | KERNEL_TYPE = ['LINEAR', 'POLY', 'RBF', 'SIGMOID', 'PRECOMPUTED'] 24 | for i, s in enumerate(SVM_TYPE): exec("%s = %d" % (s , i)) 25 | for i, s in enumerate(KERNEL_TYPE): exec("%s = %d" % (s , i)) 26 | 27 | PRINT_STRING_FUN = CFUNCTYPE(None, c_char_p) 28 | def print_null(s): 29 | return 30 | 31 | def genFields(names, types): 32 | return list(zip(names, types)) 33 | 34 | def fillprototype(f, restype, argtypes): 35 | f.restype = restype 36 | f.argtypes = argtypes 37 | 38 | class svm_node(Structure): 39 | _names = ["index", "value"] 40 | _types = [c_int, c_double] 41 | _fields_ = genFields(_names, _types) 42 | 43 | def gen_svm_nodearray(xi, feature_max=None, issparse=None): 44 | if isinstance(xi, dict): 45 | index_range = xi.keys() 46 | elif isinstance(xi, (list, tuple)): 47 | index_range = range(len(xi)) 48 | else: 49 | raise TypeError('xi should be a dictionary, list or tuple') 50 | 51 | if feature_max: 52 | assert(isinstance(feature_max, int)) 53 | index_range = filter(lambda j: j <= feature_max, index_range) 54 | if issparse: 55 | index_range = filter(lambda j:xi[j] != 0, index_range) 56 | 57 | index_range = sorted(index_range) 58 | ret = (svm_node * (len(index_range)+1))() 59 | ret[-1].index = -1 60 | for idx, j in enumerate(index_range): 61 | ret[idx].index = j 62 | ret[idx].value = xi[j] 63 | max_idx = 0 64 | if index_range: 65 | max_idx = index_range[-1] 66 | return ret, max_idx 67 | 68 | class svm_problem(Structure): 69 | _names = ["l", "y", "x"] 70 | _types = [c_int, POINTER(c_double), POINTER(POINTER(svm_node))] 71 | _fields_ = genFields(_names, _types) 72 | 73 | def __init__(self, y, x): 74 | if len(y) != len(x): 75 | raise ValueError("len(y) != len(x)") 76 | self.l = l = len(y) 77 | 78 | max_idx = 0 79 | x_space = self.x_space = [] 80 | for i, xi in enumerate(x): 81 | tmp_xi, tmp_idx = gen_svm_nodearray(xi) 82 | x_space += [tmp_xi] 83 | max_idx = max(max_idx, tmp_idx) 84 | self.n = max_idx 85 | 86 | self.y = (c_double * l)() 87 | for i, yi in enumerate(y): self.y[i] = yi 88 | 89 | self.x = (POINTER(svm_node) * l)() 90 | for i, xi in enumerate(self.x_space): self.x[i] = xi 91 | 92 | class svm_parameter(Structure): 93 | _names = ["svm_type", "kernel_type", "degree", "gamma", "coef0", 94 | "cache_size", "eps", "C", "nr_weight", "weight_label", "weight", 95 | "nu", "p", "shrinking", "probability"] 96 | _types = [c_int, c_int, c_int, c_double, c_double, 97 | c_double, c_double, c_double, c_int, POINTER(c_int), POINTER(c_double), 98 | c_double, c_double, c_int, c_int] 99 | _fields_ = genFields(_names, _types) 100 | 101 | def __init__(self, options = None): 102 | if options == None: 103 | options = '' 104 | self.parse_options(options) 105 | 106 | def show(self): 107 | attrs = svm_parameter._names + self.__dict__.keys() 108 | values = map(lambda attr: getattr(self, attr), attrs) 109 | for attr, val in zip(attrs, values): 110 | print(' %s: %s' % (attr, val)) 111 | 112 | def set_to_default_values(self): 113 | self.svm_type = C_SVC; 114 | self.kernel_type = RBF 115 | self.degree = 3 116 | self.gamma = 0 117 | self.coef0 = 0 118 | self.nu = 0.5 119 | self.cache_size = 100 120 | self.C = 1 121 | self.eps = 0.001 122 | self.p = 0.1 123 | self.shrinking = 1 124 | self.probability = 0 125 | self.nr_weight = 0 126 | self.weight_label = (c_int*0)() 127 | self.weight = (c_double*0)() 128 | self.cross_validation = False 129 | self.nr_fold = 0 130 | self.print_func = None 131 | 132 | def parse_options(self, options): 133 | argv = options.split() 134 | self.set_to_default_values() 135 | self.print_func = cast(None, PRINT_STRING_FUN) 136 | weight_label = [] 137 | weight = [] 138 | 139 | i = 0 140 | while i < len(argv): 141 | if argv[i] == "-s": 142 | i = i + 1 143 | self.svm_type = int(argv[i]) 144 | elif argv[i] == "-t": 145 | i = i + 1 146 | self.kernel_type = int(argv[i]) 147 | elif argv[i] == "-d": 148 | i = i + 1 149 | self.degree = int(argv[i]) 150 | elif argv[i] == "-g": 151 | i = i + 1 152 | self.gamma = float(argv[i]) 153 | elif argv[i] == "-r": 154 | i = i + 1 155 | self.coef0 = float(argv[i]) 156 | elif argv[i] == "-n": 157 | i = i + 1 158 | self.nu = float(argv[i]) 159 | elif argv[i] == "-m": 160 | i = i + 1 161 | self.cache_size = float(argv[i]) 162 | elif argv[i] == "-c": 163 | i = i + 1 164 | self.C = float(argv[i]) 165 | elif argv[i] == "-e": 166 | i = i + 1 167 | self.eps = float(argv[i]) 168 | elif argv[i] == "-p": 169 | i = i + 1 170 | self.p = float(argv[i]) 171 | elif argv[i] == "-h": 172 | i = i + 1 173 | self.shrinking = int(argv[i]) 174 | elif argv[i] == "-b": 175 | i = i + 1 176 | self.probability = int(argv[i]) 177 | elif argv[i] == "-q": 178 | self.print_func = PRINT_STRING_FUN(print_null) 179 | elif argv[i] == "-v": 180 | i = i + 1 181 | self.cross_validation = 1 182 | self.nr_fold = int(argv[i]) 183 | if self.nr_fold < 2: 184 | raise ValueError("n-fold cross validation: n must >= 2") 185 | elif argv[i].startswith("-w"): 186 | i = i + 1 187 | self.nr_weight += 1 188 | nr_weight = self.nr_weight 189 | weight_label += [int(argv[i-1][2:])] 190 | weight += [float(argv[i])] 191 | else: 192 | raise ValueError("Wrong options") 193 | i += 1 194 | 195 | libsvm.svm_set_print_string_function(self.print_func) 196 | self.weight_label = (c_int*self.nr_weight)() 197 | self.weight = (c_double*self.nr_weight)() 198 | for i in range(self.nr_weight): 199 | self.weight[i] = weight[i] 200 | self.weight_label[i] = weight_label[i] 201 | 202 | class svm_model(Structure): 203 | _names = ['param', 'nr_class', 'l', 'SV', 'sv_coef', 'rho', 204 | 'probA', 'probB', 'label', 'nSV', 'free_sv'] 205 | _types = [svm_parameter, c_int, c_int, POINTER(POINTER(svm_node)), 206 | POINTER(POINTER(c_double)), POINTER(c_double), 207 | POINTER(c_double), POINTER(c_double), POINTER(c_int), 208 | POINTER(c_int), c_int] 209 | _fields_ = genFields(_names, _types) 210 | 211 | def __init__(self): 212 | self.__createfrom__ = 'python' 213 | 214 | def __del__(self): 215 | # free memory created by C to avoid memory leak 216 | if hasattr(self, '__createfrom__') and self.__createfrom__ == 'C': 217 | libsvm.svm_free_and_destroy_model(pointer(self)) 218 | 219 | def get_svm_type(self): 220 | return libsvm.svm_get_svm_type(self) 221 | 222 | def get_nr_class(self): 223 | return libsvm.svm_get_nr_class(self) 224 | 225 | def get_svr_probability(self): 226 | return libsvm.svm_get_svr_probability(self) 227 | 228 | def get_labels(self): 229 | nr_class = self.get_nr_class() 230 | labels = (c_int * nr_class)() 231 | libsvm.svm_get_labels(self, labels) 232 | return labels[:nr_class] 233 | 234 | def is_probability_model(self): 235 | return (libsvm.svm_check_probability_model(self) == 1) 236 | 237 | def get_sv_coef(self): 238 | return [tuple(self.sv_coef[j][i] for j in xrange(self.nr_class - 1)) 239 | for i in xrange(self.l)] 240 | 241 | def get_SV(self): 242 | result = [] 243 | for sparse_sv in self.SV[:self.l]: 244 | row = dict() 245 | 246 | i = 0 247 | while True: 248 | row[sparse_sv[i].index] = sparse_sv[i].value 249 | if sparse_sv[i].index == -1: 250 | break 251 | i += 1 252 | 253 | result.append(row) 254 | return result 255 | 256 | def toPyModel(model_ptr): 257 | """ 258 | toPyModel(model_ptr) -> svm_model 259 | 260 | Convert a ctypes POINTER(svm_model) to a Python svm_model 261 | """ 262 | if bool(model_ptr) == False: 263 | raise ValueError("Null pointer") 264 | m = model_ptr.contents 265 | m.__createfrom__ = 'C' 266 | return m 267 | 268 | fillprototype(libsvm.svm_train, POINTER(svm_model), [POINTER(svm_problem), POINTER(svm_parameter)]) 269 | fillprototype(libsvm.svm_cross_validation, None, [POINTER(svm_problem), POINTER(svm_parameter), c_int, POINTER(c_double)]) 270 | 271 | fillprototype(libsvm.svm_save_model, c_int, [c_char_p, POINTER(svm_model)]) 272 | fillprototype(libsvm.svm_load_model, POINTER(svm_model), [c_char_p]) 273 | 274 | fillprototype(libsvm.svm_get_svm_type, c_int, [POINTER(svm_model)]) 275 | fillprototype(libsvm.svm_get_nr_class, c_int, [POINTER(svm_model)]) 276 | fillprototype(libsvm.svm_get_labels, None, [POINTER(svm_model), POINTER(c_int)]) 277 | fillprototype(libsvm.svm_get_svr_probability, c_double, [POINTER(svm_model)]) 278 | 279 | fillprototype(libsvm.svm_predict_values, c_double, [POINTER(svm_model), POINTER(svm_node), POINTER(c_double)]) 280 | fillprototype(libsvm.svm_predict, c_double, [POINTER(svm_model), POINTER(svm_node)]) 281 | fillprototype(libsvm.svm_predict_probability, c_double, [POINTER(svm_model), POINTER(svm_node), POINTER(c_double)]) 282 | 283 | fillprototype(libsvm.svm_free_model_content, None, [POINTER(svm_model)]) 284 | fillprototype(libsvm.svm_free_and_destroy_model, None, [POINTER(POINTER(svm_model))]) 285 | fillprototype(libsvm.svm_destroy_param, None, [POINTER(svm_parameter)]) 286 | 287 | fillprototype(libsvm.svm_check_parameter, c_char_p, [POINTER(svm_problem), POINTER(svm_parameter)]) 288 | fillprototype(libsvm.svm_check_probability_model, c_int, [POINTER(svm_model)]) 289 | fillprototype(libsvm.svm_set_print_string_function, None, [PRINT_STRING_FUN]) 290 | -------------------------------------------------------------------------------- /python/svmutil.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from svm import * 4 | 5 | def svm_read_problem(data_file_name): 6 | """ 7 | svm_read_problem(data_file_name) -> [y, x] 8 | 9 | Read LIBSVM-format data from data_file_name and return labels y 10 | and data instances x. 11 | """ 12 | prob_y = [] 13 | prob_x = [] 14 | for line in open(data_file_name): 15 | line = line.split(None, 1) 16 | # In case an instance with all zero features 17 | if len(line) == 1: line += [''] 18 | label, features = line 19 | xi = {} 20 | for e in features.split(): 21 | ind, val = e.split(":") 22 | xi[int(ind)] = float(val) 23 | prob_y += [float(label)] 24 | prob_x += [xi] 25 | return (prob_y, prob_x) 26 | 27 | def svm_load_model(model_file_name): 28 | """ 29 | svm_load_model(model_file_name) -> model 30 | 31 | Load a LIBSVM model from model_file_name and return. 32 | """ 33 | model = libsvm.svm_load_model(model_file_name) 34 | if not model: 35 | print("can't open model file %s" % model_file_name) 36 | return None 37 | model = toPyModel(model) 38 | return model 39 | 40 | def svm_save_model(model_file_name, model): 41 | """ 42 | svm_save_model(model_file_name, model) -> None 43 | 44 | Save a LIBSVM model to the file model_file_name. 45 | """ 46 | libsvm.svm_save_model(model_file_name, model) 47 | 48 | def evaluations(ty, pv): 49 | """ 50 | evaluations(ty, pv) -> (ACC, MSE, SCC) 51 | 52 | Calculate accuracy, mean squared error and squared correlation coefficient 53 | using the true values (ty) and predicted values (pv). 54 | """ 55 | if len(ty) != len(pv): 56 | raise ValueError("len(ty) must equal to len(pv)") 57 | total_correct = total_error = 0 58 | sumv = sumy = sumvv = sumyy = sumvy = 0 59 | for v, y in zip(pv, ty): 60 | if y == v: 61 | total_correct += 1 62 | total_error += (v-y)*(v-y) 63 | sumv += v 64 | sumy += y 65 | sumvv += v*v 66 | sumyy += y*y 67 | sumvy += v*y 68 | l = len(ty) 69 | ACC = 100.0*total_correct/l 70 | MSE = total_error/l 71 | try: 72 | SCC = ((l*sumvy-sumv*sumy)*(l*sumvy-sumv*sumy))/((l*sumvv-sumv*sumv)*(l*sumyy-sumy*sumy)) 73 | except: 74 | SCC = float('nan') 75 | return (ACC, MSE, SCC) 76 | 77 | def svm_train(arg1, arg2=None, arg3=None): 78 | """ 79 | svm_train(y, x [, 'options']) -> model | ACC | MSE 80 | svm_train(prob, [, 'options']) -> model | ACC | MSE 81 | svm_train(prob, param) -> model | ACC| MSE 82 | 83 | Train an SVM model from data (y, x) or an svm_problem prob using 84 | 'options' or an svm_parameter param. 85 | If '-v' is specified in 'options' (i.e., cross validation) 86 | either accuracy (ACC) or mean-squared error (MSE) is returned. 87 | 'options': 88 | -s svm_type : set type of SVM (default 0) 89 | 0 -- C-SVC 90 | 1 -- nu-SVC 91 | 2 -- one-class SVM 92 | 3 -- epsilon-SVR 93 | 4 -- nu-SVR 94 | -t kernel_type : set type of kernel function (default 2) 95 | 0 -- linear: u'*v 96 | 1 -- polynomial: (gamma*u'*v + coef0)^degree 97 | 2 -- radial basis function: exp(-gamma*|u-v|^2) 98 | 3 -- sigmoid: tanh(gamma*u'*v + coef0) 99 | 4 -- precomputed kernel (kernel values in training_set_file) 100 | -d degree : set degree in kernel function (default 3) 101 | -g gamma : set gamma in kernel function (default 1/num_features) 102 | -r coef0 : set coef0 in kernel function (default 0) 103 | -c cost : set the parameter C of C-SVC, epsilon-SVR, and nu-SVR (default 1) 104 | -n nu : set the parameter nu of nu-SVC, one-class SVM, and nu-SVR (default 0.5) 105 | -p epsilon : set the epsilon in loss function of epsilon-SVR (default 0.1) 106 | -m cachesize : set cache memory size in MB (default 100) 107 | -e epsilon : set tolerance of termination criterion (default 0.001) 108 | -h shrinking : whether to use the shrinking heuristics, 0 or 1 (default 1) 109 | -b probability_estimates : whether to train a SVC or SVR model for probability estimates, 0 or 1 (default 0) 110 | -wi weight : set the parameter C of class i to weight*C, for C-SVC (default 1) 111 | -v n: n-fold cross validation mode 112 | -q : quiet mode (no outputs) 113 | """ 114 | prob, param = None, None 115 | if isinstance(arg1, (list, tuple)): 116 | assert isinstance(arg2, (list, tuple)) 117 | y, x, options = arg1, arg2, arg3 118 | prob = svm_problem(y, x) 119 | param = svm_parameter(options) 120 | elif isinstance(arg1, svm_problem): 121 | prob = arg1 122 | if isinstance(arg2, svm_parameter): 123 | param = arg2 124 | else: 125 | param = svm_parameter(arg2) 126 | if prob == None or param == None: 127 | raise TypeError("Wrong types for the arguments") 128 | 129 | if param.kernel_type == PRECOMPUTED: 130 | for xi in prob.x_space: 131 | idx, val = xi[0].index, xi[0].value 132 | if xi[0].index != 0: 133 | raise ValueError('Wrong input format: first column must be 0:sample_serial_number') 134 | if val <= 0 or val > prob.n: 135 | raise ValueError('Wrong input format: sample_serial_number out of range') 136 | 137 | if param.gamma == 0 and prob.n > 0: 138 | param.gamma = 1.0 / prob.n 139 | libsvm.svm_set_print_string_function(param.print_func) 140 | err_msg = libsvm.svm_check_parameter(prob, param) 141 | if err_msg: 142 | raise ValueError('Error: %s' % err_msg) 143 | 144 | if param.cross_validation: 145 | l, nr_fold = prob.l, param.nr_fold 146 | target = (c_double * l)() 147 | libsvm.svm_cross_validation(prob, param, nr_fold, target) 148 | ACC, MSE, SCC = evaluations(prob.y[:l], target[:l]) 149 | if param.svm_type in [EPSILON_SVR, NU_SVR]: 150 | print("Cross Validation Mean squared error = %g" % MSE) 151 | print("Cross Validation Squared correlation coefficient = %g" % SCC) 152 | return MSE 153 | else: 154 | print("Cross Validation Accuracy = %g%%" % ACC) 155 | return ACC 156 | else: 157 | m = libsvm.svm_train(prob, param) 158 | m = toPyModel(m) 159 | 160 | # If prob is destroyed, data including SVs pointed by m can remain. 161 | m.x_space = prob.x_space 162 | return m 163 | 164 | def svm_predict(y, x, m, options=""): 165 | """ 166 | svm_predict(y, x, m [, "options"]) -> (p_labels, p_acc, p_vals) 167 | 168 | Predict data (y, x) with the SVM model m. 169 | "options": 170 | -b probability_estimates: whether to predict probability estimates, 171 | 0 or 1 (default 0); for one-class SVM only 0 is supported. 172 | 173 | The return tuple contains 174 | p_labels: a list of predicted labels 175 | p_acc: a tuple including accuracy (for classification), mean-squared 176 | error, and squared correlation coefficient (for regression). 177 | p_vals: a list of decision values or probability estimates (if '-b 1' 178 | is specified). If k is the number of classes, for decision values, 179 | each element includes results of predicting k(k-1)/2 binary-class 180 | SVMs. For probabilities, each element contains k values indicating 181 | the probability that the testing instance is in each class. 182 | Note that the order of classes here is the same as 'model.label' 183 | field in the model structure. 184 | """ 185 | predict_probability = 0 186 | argv = options.split() 187 | i = 0 188 | while i < len(argv): 189 | if argv[i] == '-b': 190 | i += 1 191 | predict_probability = int(argv[i]) 192 | else: 193 | raise ValueError("Wrong options") 194 | i+=1 195 | 196 | svm_type = m.get_svm_type() 197 | is_prob_model = m.is_probability_model() 198 | nr_class = m.get_nr_class() 199 | pred_labels = [] 200 | pred_values = [] 201 | 202 | if predict_probability: 203 | if not is_prob_model: 204 | raise ValueError("Model does not support probabiliy estimates") 205 | 206 | if svm_type in [NU_SVR, EPSILON_SVR]: 207 | print("Prob. model for test data: target value = predicted value + z,\n" 208 | "z: Laplace distribution e^(-|z|/sigma)/(2sigma),sigma=%g" % m.get_svr_probability()); 209 | nr_class = 0 210 | 211 | prob_estimates = (c_double * nr_class)() 212 | for xi in x: 213 | xi, idx = gen_svm_nodearray(xi) 214 | label = libsvm.svm_predict_probability(m, xi, prob_estimates) 215 | values = prob_estimates[:nr_class] 216 | pred_labels += [label] 217 | pred_values += [values] 218 | else: 219 | if is_prob_model: 220 | print("Model supports probability estimates, but disabled in predicton.") 221 | if svm_type in (ONE_CLASS, EPSILON_SVR, NU_SVC): 222 | nr_classifier = 1 223 | else: 224 | nr_classifier = nr_class*(nr_class-1)//2 225 | dec_values = (c_double * nr_classifier)() 226 | for xi in x: 227 | xi, idx = gen_svm_nodearray(xi) 228 | label = libsvm.svm_predict_values(m, xi, dec_values) 229 | values = dec_values[:nr_classifier] 230 | pred_labels += [label] 231 | pred_values += [values] 232 | 233 | ACC, MSE, SCC = evaluations(y, pred_labels) 234 | l = len(y) 235 | if svm_type in [EPSILON_SVR, NU_SVR]: 236 | print("Mean squared error = %g (regression)" % MSE) 237 | print("Squared correlation coefficient = %g (regression)" % SCC) 238 | else: 239 | print("Accuracy = %g%% (%d/%d) (classification)" % (ACC, int(l*ACC/100), l)) 240 | 241 | return pred_labels, (ACC, MSE, SCC), pred_values 242 | 243 | -------------------------------------------------------------------------------- /svm-analyze.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "svm.h" 8 | 9 | #define MIN(x, y) (x < y ? x : y) 10 | 11 | struct score_data 12 | { 13 | double label; 14 | double score; 15 | }; 16 | 17 | struct svm_node *x; 18 | int max_nr_attr = 64; 19 | 20 | extern struct svm_model* model; 21 | int predict_probability=0; 22 | double min_threshold = 0, max_threshold = 0; 23 | bool min_set = false, max_set = false; 24 | int num_steps = 20; 25 | 26 | static char *line = NULL; 27 | static int max_line_len; 28 | 29 | extern static char* readline(FILE *input); 30 | void exit_input_error(int line_num); 31 | 32 | void analyze(FILE *input, FILE *output) 33 | { 34 | int correct = 0; 35 | int total = 0, inclass = 0; 36 | double error = 0; 37 | double sump = 0, sumt = 0, sumpp = 0, sumtt = 0, sumpt = 0; 38 | 39 | int svm_type=svm_get_svm_type(model); 40 | int nr_class=svm_get_nr_class(model); 41 | double *prob_estimates=NULL; 42 | int j; 43 | int max_scores = 64; 44 | struct score_data * scores = (struct score_data *) malloc(max_scores*sizeof(struct score_data)); 45 | 46 | max_line_len = 1024; 47 | line = (char *)malloc(max_line_len*sizeof(char)); 48 | while(readline(input) != NULL) 49 | { 50 | int i = 0; 51 | double target_label, predict_label; 52 | char *idx, *val, *label, *endptr; 53 | int inst_max_index = -1; // strtol gives 0 if wrong format, and precomputed kernel has start from 0 54 | 55 | //Make sure we don't go over the bounds of our score array 56 | if (total >= max_scores) 57 | { 58 | max_scores *= 2; 59 | scores = (struct score_data *) realloc(scores, max_scores*sizeof(struct score_data)); 60 | } 61 | 62 | label = strtok(line," \t\n"); 63 | if(label == NULL) // empty line 64 | exit_input_error(total+1); 65 | 66 | target_label = strtod(label,&endptr); 67 | if(endptr == label || *endptr != '\0') 68 | exit_input_error(total+1); 69 | 70 | if (target_label > 0) ++inclass; 71 | 72 | while(1) 73 | { 74 | if(i>=max_nr_attr-1) // need one more for index = -1 75 | { 76 | max_nr_attr *= 2; 77 | x = (struct svm_node *) realloc(x,max_nr_attr*sizeof(struct svm_node)); 78 | } 79 | 80 | idx = strtok(NULL,":"); 81 | val = strtok(NULL," \t"); 82 | 83 | if(val == NULL) 84 | break; 85 | errno = 0; 86 | x[i].index = (int) strtol(idx,&endptr,10); 87 | if(endptr == idx || errno != 0 || *endptr != '\0' || x[i].index <= inst_max_index) 88 | exit_input_error(total+1); 89 | else 90 | inst_max_index = x[i].index; 91 | 92 | errno = 0; 93 | x[i].value = strtod(val,&endptr); 94 | if(endptr == val || errno != 0 || (*endptr != '\0' && !isspace(*endptr))) 95 | exit_input_error(total+1); 96 | 97 | ++i; 98 | } 99 | x[i].index = -1; 100 | 101 | predict_label = svm_predict(model,x); 102 | //printf("%g %g\n", target_label, predict_label); 103 | 104 | scores[total].label = target_label; 105 | scores[total].score = predict_label; 106 | 107 | if((predict_label/fabs(predict_label)) == target_label) 108 | ++correct; 109 | error += (predict_label-target_label)*(predict_label-target_label); 110 | sump += predict_label; 111 | sumt += target_label; 112 | sumpp += predict_label*predict_label; 113 | sumtt += target_label*target_label; 114 | sumpt += predict_label*target_label; 115 | ++total; 116 | } 117 | 118 | //We have scores saved to file 119 | //It's easier to just read them back in 120 | double ma = 0, mi = 1; //Reasonable bounds on max/min to prevent outliers 121 | //from causing a poor p/r analysis. 122 | double step; 123 | double min_error = 0, min_error_m = 0, min_error_t = 0; 124 | 125 | for (int i = 0; i < total; i++) 126 | { 127 | ma = scores[i].score > ma ? scores[i].score : ma; 128 | mi = scores[i].score < mi ? scores[i].score : mi; 129 | } 130 | 131 | if (min_set) 132 | mi = mi > min_threshold ? mi : min_threshold; 133 | if (max_set) 134 | ma = ma < max_threshold ? ma : max_threshold; 135 | 136 | //fprintf(output, "%g, %g\n", ma, mi); 137 | step = (ma - mi)/num_steps; 138 | //Compute precision and recall 139 | 140 | for (int i = 0; i <= num_steps-1; i++) 141 | { 142 | double tl = mi + i*step; 143 | for (int j = i+1; j <= num_steps; j++) 144 | { 145 | double tu = mi + j*step; 146 | int retrieved = 0, relevant = 0; 147 | double precision = 0, recall = 0, fmeasure = 0, error = 0; 148 | double false_accept = 0, false_reject = 0; 149 | 150 | for (int i = 0; i < total; i++) 151 | { 152 | if (scores[i].score >= tl && scores[i].score <= tu) 153 | { 154 | retrieved++; 155 | if (scores[i].label > 0) // equals 1 156 | relevant++; 157 | else 158 | false_accept += MIN(fabs(scores[i].score - tl), fabs(tu - scores[i].score)); 159 | //false_accept++; 160 | } 161 | else 162 | { 163 | if (scores[i].label > 0) 164 | false_reject += MIN(fabs(scores[i].score - tl), fabs(tu - scores[i].score)); 165 | //false_reject++; 166 | } 167 | } 168 | 169 | error = fabs(false_accept - false_reject); 170 | 171 | if (retrieved > 0) 172 | precision = ((double) relevant)/retrieved; 173 | else 174 | precision = 0; 175 | 176 | recall = ((double) relevant)/inclass; 177 | 178 | fmeasure = 2*precision*recall/(precision + recall); 179 | if (precision > min_error) 180 | { 181 | min_error = precision; 182 | min_error_m = tl; 183 | min_error_t = tu; 184 | } 185 | 186 | //fprintf(output, "%g\t%g\t%g\t%g\n", precision, recall, tl, tu); 187 | } 188 | } 189 | 190 | free(scores); 191 | 192 | printf("min: %g, max: %g, error: %g\n", min_error_m, min_error_t, min_error); 193 | } 194 | 195 | /* 196 | int main(int argc, char **argv) 197 | { 198 | FILE *input, *output; 199 | int i; 200 | 201 | // parse options 202 | for(i=1;i=argc-2) 228 | exit_with_help(); 229 | 230 | input = fopen(argv[i],"r"); 231 | if(input == NULL) 232 | { 233 | fprintf(stderr,"can't open input file %s\n",argv[i]); 234 | exit(1); 235 | } 236 | 237 | output = fopen(argv[i+2],"w+"); 238 | if(output == NULL) 239 | { 240 | fprintf(stderr,"can't open output file %s\n",argv[i+2]); 241 | exit(1); 242 | } 243 | 244 | if((model=svm_load_model(argv[i+1]))==0) 245 | { 246 | fprintf(stderr,"can't open model file %s\n",argv[i+1]); 247 | exit(1); 248 | } 249 | 250 | x = (struct svm_node *) malloc(max_nr_attr*sizeof(struct svm_node)); 251 | if(predict_probability) 252 | { 253 | if(svm_check_probability_model(model)==0) 254 | { 255 | fprintf(stderr,"Model does not support probabiliy estimates\n"); 256 | exit(1); 257 | } 258 | } 259 | else 260 | { 261 | if(svm_check_probability_model(model)!=0) 262 | printf("Model supports probability estimates, but disabled in prediction.\n"); 263 | } 264 | predict(input,output); 265 | svm_free_and_destroy_model(&model); 266 | free(x); 267 | free(line); 268 | fclose(input); 269 | fclose(output); 270 | return 0; 271 | } 272 | */ 273 | -------------------------------------------------------------------------------- /svm-scale.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | void exit_with_help() 8 | { 9 | printf( 10 | "Usage: svm-scale [options] data_filename\n" 11 | "options:\n" 12 | "-l lower : x scaling lower limit (default -1)\n" 13 | "-u upper : x scaling upper limit (default +1)\n" 14 | "-y y_lower y_upper : y scaling limits (default: no y scaling)\n" 15 | "-s save_filename : save scaling parameters to save_filename\n" 16 | "-r restore_filename : restore scaling parameters from restore_filename\n" 17 | ); 18 | exit(1); 19 | } 20 | 21 | char *line = NULL; 22 | int max_line_len = 1024; 23 | double lower=-1.0,upper=1.0,y_lower,y_upper; 24 | int y_scaling = 0; 25 | double *feature_max; 26 | double *feature_min; 27 | double y_max = -DBL_MAX; 28 | double y_min = DBL_MAX; 29 | int max_index; 30 | long int num_nonzeros = 0; 31 | long int new_num_nonzeros = 0; 32 | 33 | #define max(x,y) (((x)>(y))?(x):(y)) 34 | #define min(x,y) (((x)<(y))?(x):(y)) 35 | 36 | void output_target(double value); 37 | void output(int index, double value); 38 | char* readline(FILE *input); 39 | 40 | int main(int argc,char **argv) 41 | { 42 | int i,index; 43 | FILE *fp, *fp_restore = NULL; 44 | char *save_filename = NULL; 45 | char *restore_filename = NULL; 46 | 47 | for(i=1;i lower) || (y_scaling && !(y_upper > y_lower))) 70 | { 71 | fprintf(stderr,"inconsistent lower/upper specification\n"); 72 | exit(1); 73 | } 74 | 75 | if(restore_filename && save_filename) 76 | { 77 | fprintf(stderr,"cannot use -r and -s simultaneously\n"); 78 | exit(1); 79 | } 80 | 81 | if(argc != i+1) 82 | exit_with_help(); 83 | 84 | fp=fopen(argv[i],"r"); 85 | 86 | if(fp==NULL) 87 | { 88 | fprintf(stderr,"can't open file %s\n", argv[i]); 89 | exit(1); 90 | } 91 | 92 | line = (char *) malloc(max_line_len*sizeof(char)); 93 | 94 | #define SKIP_TARGET\ 95 | while(isspace(*p)) ++p;\ 96 | while(!isspace(*p)) ++p; 97 | 98 | #define SKIP_ELEMENT\ 99 | while(*p!=':') ++p;\ 100 | ++p;\ 101 | while(isspace(*p)) ++p;\ 102 | while(*p && !isspace(*p)) ++p; 103 | 104 | /* assumption: min index of attributes is 1 */ 105 | /* pass 1: find out max index of attributes */ 106 | max_index = 0; 107 | 108 | if(restore_filename) 109 | { 110 | int idx, c; 111 | 112 | fp_restore = fopen(restore_filename,"r"); 113 | if(fp_restore==NULL) 114 | { 115 | fprintf(stderr,"can't open file %s\n", restore_filename); 116 | exit(1); 117 | } 118 | 119 | c = fgetc(fp_restore); 120 | if(c == 'y') 121 | { 122 | readline(fp_restore); 123 | readline(fp_restore); 124 | readline(fp_restore); 125 | } 126 | readline(fp_restore); 127 | readline(fp_restore); 128 | 129 | while(fscanf(fp_restore,"%d %*f %*f\n",&idx) == 1) 130 | max_index = max(idx,max_index); 131 | rewind(fp_restore); 132 | } 133 | 134 | while(readline(fp)!=NULL) 135 | { 136 | char *p=line; 137 | 138 | SKIP_TARGET 139 | 140 | while(sscanf(p,"%d:%*f",&index)==1) 141 | { 142 | max_index = max(max_index, index); 143 | SKIP_ELEMENT 144 | num_nonzeros++; 145 | } 146 | } 147 | rewind(fp); 148 | 149 | feature_max = (double *)malloc((max_index+1)* sizeof(double)); 150 | feature_min = (double *)malloc((max_index+1)* sizeof(double)); 151 | 152 | if(feature_max == NULL || feature_min == NULL) 153 | { 154 | fprintf(stderr,"can't allocate enough memory\n"); 155 | exit(1); 156 | } 157 | 158 | for(i=0;i<=max_index;i++) 159 | { 160 | feature_max[i]=-DBL_MAX; 161 | feature_min[i]=DBL_MAX; 162 | } 163 | 164 | /* pass 2: find out min/max value */ 165 | while(readline(fp)!=NULL) 166 | { 167 | char *p=line; 168 | int next_index=1; 169 | double target; 170 | double value; 171 | 172 | sscanf(p,"%lf",&target); 173 | y_max = max(y_max,target); 174 | y_min = min(y_min,target); 175 | 176 | SKIP_TARGET 177 | 178 | while(sscanf(p,"%d:%lf",&index,&value)==2) 179 | { 180 | for(i=next_index;i num_nonzeros) 288 | fprintf(stderr, 289 | "Warning: original #nonzeros %ld\n" 290 | " new #nonzeros %ld\n" 291 | "Use -l 0 if many original feature values are zeros\n", 292 | num_nonzeros, new_num_nonzeros); 293 | 294 | free(line); 295 | free(feature_max); 296 | free(feature_min); 297 | fclose(fp); 298 | return 0; 299 | } 300 | 301 | char* readline(FILE *input) 302 | { 303 | int len; 304 | 305 | if(fgets(line,max_line_len,input) == NULL) 306 | return NULL; 307 | 308 | while(strrchr(line,'\n') == NULL) 309 | { 310 | max_line_len *= 2; 311 | line = (char *) realloc(line, max_line_len); 312 | len = (int) strlen(line); 313 | if(fgets(line+len,max_line_len-len,input) == NULL) 314 | break; 315 | } 316 | return line; 317 | } 318 | 319 | void output_target(double value) 320 | { 321 | if(y_scaling) 322 | { 323 | if(value == y_min) 324 | value = y_lower; 325 | else if(value == y_max) 326 | value = y_upper; 327 | else value = y_lower + (y_upper-y_lower) * 328 | (value - y_min)/(y_max-y_min); 329 | } 330 | printf("%g ",value); 331 | } 332 | 333 | void output(int index, double value) 334 | { 335 | /* skip single-valued attribute */ 336 | if(feature_max[index] == feature_min[index]) 337 | return; 338 | 339 | if(value == feature_min[index]) 340 | value = lower; 341 | else if(value == feature_max[index]) 342 | value = upper; 343 | else 344 | value = lower + (upper-lower) * 345 | (value-feature_min[index])/ 346 | (feature_max[index]-feature_min[index]); 347 | 348 | if(value != 0) 349 | { 350 | printf("%d:%g ",index, value); 351 | new_num_nonzeros++; 352 | } 353 | } 354 | -------------------------------------------------------------------------------- /svm-toy/gtk/Makefile: -------------------------------------------------------------------------------- 1 | CC? = gcc 2 | CXX? = g++ 3 | CFLAGS = -Wall -O3 -g `pkg-config --cflags gtk+-2.0` 4 | LIBS = `pkg-config --libs gtk+-2.0` 5 | 6 | svm-toy: main.o interface.o callbacks.o ../../svm.o 7 | $(CXX) $(CFLAGS) main.o interface.o callbacks.o ../../svm.o -o svm-toy $(LIBS) 8 | 9 | main.o: main.c 10 | $(CC) $(CFLAGS) -c main.c 11 | 12 | interface.o: interface.c interface.h 13 | $(CC) $(CFLAGS) -c interface.c 14 | 15 | callbacks.o: callbacks.cpp callbacks.h 16 | $(CXX) $(CFLAGS) -c callbacks.cpp 17 | 18 | ../../svm.o: 19 | cd ../..; make svm.o 20 | 21 | clean: 22 | rm -f *~ callbacks.o svm-toy main.o interface.o callbacks.o ../../svm.o 23 | -------------------------------------------------------------------------------- /svm-toy/gtk/callbacks.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "callbacks.h" 7 | #include "interface.h" 8 | #include "../../svm.h" 9 | using namespace std; 10 | 11 | #define DEFAULT_PARAM "-t 2 -c 100" 12 | #define XLEN 500 13 | #define YLEN 500 14 | 15 | GdkColor colors[] = 16 | { 17 | {0,0,0,0}, 18 | {0,0,120<<8,120<<8}, 19 | {0,120<<8,120<<8,0}, 20 | {0,120<<8,0,120<<8}, 21 | {0,0,200<<8,200<<8}, 22 | {0,200<<8,200<<8,0}, 23 | {0,200<<8,0,200<<8}, 24 | }; 25 | 26 | GdkGC *gc; 27 | GdkPixmap *pixmap; 28 | extern "C" GtkWidget *draw_main; 29 | GtkWidget *draw_main; 30 | extern "C" GtkWidget *entry_option; 31 | GtkWidget *entry_option; 32 | 33 | typedef struct { 34 | double x, y; 35 | signed char value; 36 | } point; 37 | 38 | list point_list; 39 | int current_value = 1; 40 | 41 | extern "C" void svm_toy_initialize() 42 | { 43 | gboolean success[7]; 44 | 45 | gdk_colormap_alloc_colors( 46 | gdk_colormap_get_system(), 47 | colors, 48 | 7, 49 | FALSE, 50 | TRUE, 51 | success); 52 | 53 | gc = gdk_gc_new(draw_main->window); 54 | pixmap = gdk_pixmap_new(draw_main->window,XLEN,YLEN,-1); 55 | gdk_gc_set_foreground(gc,&colors[0]); 56 | gdk_draw_rectangle(pixmap,gc,TRUE,0,0,XLEN,YLEN); 57 | gtk_entry_set_text(GTK_ENTRY(entry_option),DEFAULT_PARAM); 58 | } 59 | 60 | void redraw_area(GtkWidget* widget, int x, int y, int w, int h) 61 | { 62 | gdk_draw_pixmap(widget->window, 63 | gc, 64 | pixmap, 65 | x,y,x,y,w,h); 66 | } 67 | 68 | void draw_point(const point& p) 69 | { 70 | gdk_gc_set_foreground(gc,&colors[p.value+3]); 71 | gdk_draw_rectangle(pixmap, gc, TRUE,int(p.x*XLEN),int(p.y*YLEN),4,4); 72 | gdk_draw_rectangle(draw_main->window, gc, TRUE,int(p.x*XLEN),int(p.y*YLEN),4,4); 73 | } 74 | 75 | void draw_all_points() 76 | { 77 | for(list::iterator p = point_list.begin(); p != point_list.end();p++) 78 | draw_point(*p); 79 | } 80 | 81 | void clear_all() 82 | { 83 | point_list.clear(); 84 | gdk_gc_set_foreground(gc,&colors[0]); 85 | gdk_draw_rectangle(pixmap,gc,TRUE,0,0,XLEN,YLEN); 86 | redraw_area(draw_main,0,0,XLEN,YLEN); 87 | } 88 | 89 | void 90 | on_button_change_clicked (GtkButton *button, 91 | gpointer user_data) 92 | { 93 | ++current_value; 94 | if(current_value > 3) current_value = 1; 95 | } 96 | 97 | void 98 | on_button_run_clicked (GtkButton *button, 99 | gpointer user_data) 100 | { 101 | // guard 102 | if(point_list.empty()) return; 103 | 104 | svm_parameter param; 105 | int i,j; 106 | 107 | // default values 108 | param.svm_type = C_SVC; 109 | param.kernel_type = RBF; 110 | param.degree = 3; 111 | param.gamma = 0; 112 | param.coef0 = 0; 113 | param.nu = 0.5; 114 | param.cache_size = 100; 115 | param.C = 1; 116 | param.eps = 1e-3; 117 | param.p = 0.1; 118 | param.shrinking = 1; 119 | param.probability = 0; 120 | param.nr_weight = 0; 121 | param.weight_label = NULL; 122 | param.weight = NULL; 123 | 124 | // parse options 125 | const char *p = gtk_entry_get_text(GTK_ENTRY(entry_option)); 126 | 127 | while (1) { 128 | while (*p && *p != '-') 129 | p++; 130 | 131 | if (*p == '\0') 132 | break; 133 | 134 | p++; 135 | switch (*p++) { 136 | case 's': 137 | param.svm_type = atoi(p); 138 | break; 139 | case 't': 140 | param.kernel_type = atoi(p); 141 | break; 142 | case 'd': 143 | param.degree = atoi(p); 144 | break; 145 | case 'g': 146 | param.gamma = atof(p); 147 | break; 148 | case 'r': 149 | param.coef0 = atof(p); 150 | break; 151 | case 'n': 152 | param.nu = atof(p); 153 | break; 154 | case 'm': 155 | param.cache_size = atof(p); 156 | break; 157 | case 'c': 158 | param.C = atof(p); 159 | break; 160 | case 'e': 161 | param.eps = atof(p); 162 | break; 163 | case 'p': 164 | param.p = atof(p); 165 | break; 166 | case 'h': 167 | param.shrinking = atoi(p); 168 | break; 169 | case 'b': 170 | param.probability = atoi(p); 171 | break; 172 | case 'w': 173 | ++param.nr_weight; 174 | param.weight_label = (int *)realloc(param.weight_label,sizeof(int)*param.nr_weight); 175 | param.weight = (double *)realloc(param.weight,sizeof(double)*param.nr_weight); 176 | param.weight_label[param.nr_weight-1] = atoi(p); 177 | while(*p && !isspace(*p)) ++p; 178 | param.weight[param.nr_weight-1] = atof(p); 179 | break; 180 | } 181 | } 182 | 183 | // build problem 184 | svm_problem prob; 185 | 186 | prob.l = point_list.size(); 187 | prob.y = new double[prob.l]; 188 | 189 | if(param.kernel_type == PRECOMPUTED) 190 | { 191 | } 192 | else if(param.svm_type == EPSILON_SVR || 193 | param.svm_type == NU_SVR) 194 | { 195 | if(param.gamma == 0) param.gamma = 1; 196 | svm_node *x_space = new svm_node[2 * prob.l]; 197 | prob.x = new svm_node *[prob.l]; 198 | 199 | i = 0; 200 | for (list ::iterator q = point_list.begin(); q != point_list.end(); q++, i++) 201 | { 202 | x_space[2 * i].index = 1; 203 | x_space[2 * i].value = q->x; 204 | x_space[2 * i + 1].index = -1; 205 | prob.x[i] = &x_space[2 * i]; 206 | prob.y[i] = q->y; 207 | } 208 | 209 | // build model & classify 210 | svm_model *model = svm_train(&prob, ¶m); 211 | svm_node x[2]; 212 | x[0].index = 1; 213 | x[1].index = -1; 214 | int *j = new int[XLEN]; 215 | 216 | for (i = 0; i < XLEN; i++) 217 | { 218 | x[0].value = (double) i / XLEN; 219 | j[i] = (int)(YLEN*svm_predict(model, x)); 220 | } 221 | 222 | gdk_gc_set_foreground(gc,&colors[0]); 223 | gdk_draw_line(pixmap,gc,0,0,0,YLEN-1); 224 | gdk_draw_line(draw_main->window,gc,0,0,0,YLEN-1); 225 | 226 | int p = (int)(param.p * YLEN); 227 | for(i = 1; i < XLEN; i++) 228 | { 229 | gdk_gc_set_foreground(gc,&colors[0]); 230 | gdk_draw_line(pixmap,gc,i,0,i,YLEN-1); 231 | gdk_draw_line(draw_main->window,gc,i,0,i,YLEN-1); 232 | 233 | gdk_gc_set_foreground(gc,&colors[5]); 234 | gdk_draw_line(pixmap,gc,i-1,j[i-1],i,j[i]); 235 | gdk_draw_line(draw_main->window,gc,i-1,j[i-1],i,j[i]); 236 | 237 | if(param.svm_type == EPSILON_SVR) 238 | { 239 | gdk_gc_set_foreground(gc,&colors[2]); 240 | gdk_draw_line(pixmap,gc,i-1,j[i-1]+p,i,j[i]+p); 241 | gdk_draw_line(draw_main->window,gc,i-1,j[i-1]+p,i,j[i]+p); 242 | 243 | gdk_gc_set_foreground(gc,&colors[2]); 244 | gdk_draw_line(pixmap,gc,i-1,j[i-1]-p,i,j[i]-p); 245 | gdk_draw_line(draw_main->window,gc,i-1,j[i-1]-p,i,j[i]-p); 246 | } 247 | } 248 | 249 | svm_free_and_destroy_model(&model); 250 | delete[] j; 251 | delete[] x_space; 252 | delete[] prob.x; 253 | delete[] prob.y; 254 | } 255 | else 256 | { 257 | if(param.gamma == 0) param.gamma = 0.5; 258 | svm_node *x_space = new svm_node[3 * prob.l]; 259 | prob.x = new svm_node *[prob.l]; 260 | 261 | i = 0; 262 | for (list ::iterator q = point_list.begin(); q != point_list.end(); q++, i++) 263 | { 264 | x_space[3 * i].index = 1; 265 | x_space[3 * i].value = q->x; 266 | x_space[3 * i + 1].index = 2; 267 | x_space[3 * i + 1].value = q->y; 268 | x_space[3 * i + 2].index = -1; 269 | prob.x[i] = &x_space[3 * i]; 270 | prob.y[i] = q->value; 271 | } 272 | 273 | // build model & classify 274 | svm_model *model = svm_train(&prob, ¶m); 275 | svm_node x[3]; 276 | x[0].index = 1; 277 | x[1].index = 2; 278 | x[2].index = -1; 279 | 280 | for (i = 0; i < XLEN; i++) 281 | for (j = 0; j < YLEN; j++) { 282 | x[0].value = (double) i / XLEN; 283 | x[1].value = (double) j / YLEN; 284 | double d = svm_predict(model, x); 285 | if (param.svm_type == ONE_CLASS && d<0) d=2; 286 | gdk_gc_set_foreground(gc,&colors[(int)d]); 287 | gdk_draw_point(pixmap,gc,i,j); 288 | gdk_draw_point(draw_main->window,gc,i,j); 289 | } 290 | 291 | svm_free_and_destroy_model(&model); 292 | delete[] x_space; 293 | delete[] prob.x; 294 | delete[] prob.y; 295 | } 296 | free(param.weight_label); 297 | free(param.weight); 298 | draw_all_points(); 299 | } 300 | 301 | void 302 | on_button_clear_clicked (GtkButton *button, 303 | gpointer user_data) 304 | { 305 | clear_all(); 306 | } 307 | 308 | void 309 | on_window1_destroy (GtkObject *object, 310 | gpointer user_data) 311 | { 312 | gtk_exit(0); 313 | } 314 | 315 | gboolean 316 | on_draw_main_button_press_event (GtkWidget *widget, 317 | GdkEventButton *event, 318 | gpointer user_data) 319 | { 320 | point p = {(double)event->x/XLEN, (double)event->y/YLEN, current_value}; 321 | point_list.push_back(p); 322 | draw_point(p); 323 | return FALSE; 324 | } 325 | 326 | gboolean 327 | on_draw_main_expose_event (GtkWidget *widget, 328 | GdkEventExpose *event, 329 | gpointer user_data) 330 | { 331 | redraw_area(widget, 332 | event->area.x, event->area.y, 333 | event->area.width, event->area.height); 334 | return FALSE; 335 | } 336 | 337 | GtkWidget *fileselection; 338 | static enum { SAVE, LOAD } fileselection_flag; 339 | 340 | void show_fileselection() 341 | { 342 | fileselection = create_fileselection(); 343 | gtk_signal_connect_object( 344 | GTK_OBJECT(GTK_FILE_SELECTION(fileselection)->ok_button), 345 | "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), 346 | (GtkObject *) fileselection); 347 | 348 | gtk_signal_connect_object (GTK_OBJECT 349 | (GTK_FILE_SELECTION(fileselection)->cancel_button), 350 | "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), 351 | (GtkObject *) fileselection); 352 | 353 | gtk_widget_show(fileselection); 354 | } 355 | 356 | void 357 | on_button_save_clicked (GtkButton *button, 358 | gpointer user_data) 359 | { 360 | fileselection_flag = SAVE; 361 | show_fileselection(); 362 | } 363 | 364 | 365 | void 366 | on_button_load_clicked (GtkButton *button, 367 | gpointer user_data) 368 | { 369 | fileselection_flag = LOAD; 370 | show_fileselection(); 371 | } 372 | 373 | void 374 | on_filesel_ok_clicked (GtkButton *button, 375 | gpointer user_data) 376 | { 377 | gtk_widget_hide(fileselection); 378 | const char *filename = gtk_file_selection_get_filename(GTK_FILE_SELECTION(fileselection)); 379 | 380 | if(fileselection_flag == SAVE) 381 | { 382 | FILE *fp = fopen(filename,"w"); 383 | if(fp) 384 | { 385 | for(list::iterator p = point_list.begin(); p != point_list.end();p++) 386 | fprintf(fp,"%d 1:%f 2:%f\n", p->value, p->x, p->y); 387 | fclose(fp); 388 | } 389 | 390 | } 391 | else if(fileselection_flag == LOAD) 392 | { 393 | FILE *fp = fopen(filename,"r"); 394 | if(fp) 395 | { 396 | clear_all(); 397 | char buf[4096]; 398 | while(fgets(buf,sizeof(buf),fp)) 399 | { 400 | int v; 401 | double x,y; 402 | if(sscanf(buf,"%d%*d:%lf%*d:%lf",&v,&x,&y)!=3) 403 | break; 404 | point p = {x,y,v}; 405 | point_list.push_back(p); 406 | } 407 | fclose(fp); 408 | draw_all_points(); 409 | } 410 | } 411 | } 412 | 413 | void 414 | on_fileselection_destroy (GtkObject *object, 415 | gpointer user_data) 416 | { 417 | } 418 | 419 | void 420 | on_filesel_cancel_clicked (GtkButton *button, 421 | gpointer user_data) 422 | { 423 | } 424 | -------------------------------------------------------------------------------- /svm-toy/gtk/callbacks.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #ifdef __cplusplus 4 | extern "C" { 5 | #endif 6 | 7 | void 8 | on_window1_destroy (GtkObject *object, 9 | gpointer user_data); 10 | 11 | gboolean 12 | on_draw_main_button_press_event (GtkWidget *widget, 13 | GdkEventButton *event, 14 | gpointer user_data); 15 | 16 | gboolean 17 | on_draw_main_expose_event (GtkWidget *widget, 18 | GdkEventExpose *event, 19 | gpointer user_data); 20 | 21 | void 22 | on_button_change_clicked (GtkButton *button, 23 | gpointer user_data); 24 | 25 | void 26 | on_button_run_clicked (GtkButton *button, 27 | gpointer user_data); 28 | 29 | void 30 | on_button_clear_clicked (GtkButton *button, 31 | gpointer user_data); 32 | 33 | void 34 | on_button_save_clicked (GtkButton *button, 35 | gpointer user_data); 36 | 37 | void 38 | on_button_load_clicked (GtkButton *button, 39 | gpointer user_data); 40 | 41 | void 42 | on_fileselection_destroy (GtkObject *object, 43 | gpointer user_data); 44 | 45 | void 46 | on_filesel_ok_clicked (GtkButton *button, 47 | gpointer user_data); 48 | 49 | void 50 | on_filesel_cancel_clicked (GtkButton *button, 51 | gpointer user_data); 52 | #ifdef __cplusplus 53 | } 54 | #endif 55 | -------------------------------------------------------------------------------- /svm-toy/gtk/interface.c: -------------------------------------------------------------------------------- 1 | /* 2 | * DO NOT EDIT THIS FILE - it is generated by Glade. 3 | */ 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | #include "callbacks.h" 14 | #include "interface.h" 15 | 16 | GtkWidget* 17 | create_window (void) 18 | { 19 | GtkWidget *window; 20 | GtkWidget *vbox1; 21 | extern GtkWidget *draw_main; 22 | GtkWidget *hbox1; 23 | GtkWidget *button_change; 24 | GtkWidget *button_run; 25 | GtkWidget *button_clear; 26 | GtkWidget *button_save; 27 | GtkWidget *button_load; 28 | extern GtkWidget *entry_option; 29 | 30 | window = gtk_window_new (GTK_WINDOW_TOPLEVEL); 31 | gtk_object_set_data (GTK_OBJECT (window), "window", window); 32 | gtk_window_set_title (GTK_WINDOW (window), "SVM Toy"); 33 | 34 | vbox1 = gtk_vbox_new (FALSE, 0); 35 | gtk_widget_ref (vbox1); 36 | gtk_object_set_data_full (GTK_OBJECT (window), "vbox1", vbox1, 37 | (GtkDestroyNotify) gtk_widget_unref); 38 | gtk_widget_show (vbox1); 39 | gtk_container_add (GTK_CONTAINER (window), vbox1); 40 | 41 | draw_main = gtk_drawing_area_new (); 42 | gtk_widget_ref (draw_main); 43 | gtk_object_set_data_full (GTK_OBJECT (window), "draw_main", draw_main, 44 | (GtkDestroyNotify) gtk_widget_unref); 45 | gtk_widget_show (draw_main); 46 | gtk_box_pack_start (GTK_BOX (vbox1), draw_main, TRUE, TRUE, 0); 47 | gtk_widget_set_usize (draw_main, 500, 500); 48 | gtk_widget_set_events (draw_main, GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK); 49 | 50 | hbox1 = gtk_hbox_new (FALSE, 0); 51 | gtk_widget_ref (hbox1); 52 | gtk_object_set_data_full (GTK_OBJECT (window), "hbox1", hbox1, 53 | (GtkDestroyNotify) gtk_widget_unref); 54 | gtk_widget_show (hbox1); 55 | gtk_box_pack_start (GTK_BOX (vbox1), hbox1, FALSE, FALSE, 0); 56 | 57 | button_change = gtk_button_new_with_label ("Change"); 58 | gtk_widget_ref (button_change); 59 | gtk_object_set_data_full (GTK_OBJECT (window), "button_change", button_change, 60 | (GtkDestroyNotify) gtk_widget_unref); 61 | gtk_widget_show (button_change); 62 | gtk_box_pack_start (GTK_BOX (hbox1), button_change, FALSE, FALSE, 0); 63 | 64 | button_run = gtk_button_new_with_label ("Run"); 65 | gtk_widget_ref (button_run); 66 | gtk_object_set_data_full (GTK_OBJECT (window), "button_run", button_run, 67 | (GtkDestroyNotify) gtk_widget_unref); 68 | gtk_widget_show (button_run); 69 | gtk_box_pack_start (GTK_BOX (hbox1), button_run, FALSE, FALSE, 0); 70 | 71 | button_clear = gtk_button_new_with_label ("Clear"); 72 | gtk_widget_ref (button_clear); 73 | gtk_object_set_data_full (GTK_OBJECT (window), "button_clear", button_clear, 74 | (GtkDestroyNotify) gtk_widget_unref); 75 | gtk_widget_show (button_clear); 76 | gtk_box_pack_start (GTK_BOX (hbox1), button_clear, FALSE, FALSE, 0); 77 | 78 | button_save = gtk_button_new_with_label ("Save"); 79 | gtk_widget_ref (button_save); 80 | gtk_object_set_data_full (GTK_OBJECT (window), "button_save", button_save, 81 | (GtkDestroyNotify) gtk_widget_unref); 82 | gtk_widget_show (button_save); 83 | gtk_box_pack_start (GTK_BOX (hbox1), button_save, FALSE, FALSE, 0); 84 | 85 | button_load = gtk_button_new_with_label ("Load"); 86 | gtk_widget_ref (button_load); 87 | gtk_object_set_data_full (GTK_OBJECT (window), "button_load", button_load, 88 | (GtkDestroyNotify) gtk_widget_unref); 89 | gtk_widget_show (button_load); 90 | gtk_box_pack_start (GTK_BOX (hbox1), button_load, FALSE, FALSE, 0); 91 | 92 | entry_option = gtk_entry_new (); 93 | gtk_widget_ref (entry_option); 94 | gtk_object_set_data_full (GTK_OBJECT (window), "entry_option", entry_option, 95 | (GtkDestroyNotify) gtk_widget_unref); 96 | gtk_widget_show (entry_option); 97 | gtk_box_pack_start (GTK_BOX (hbox1), entry_option, TRUE, TRUE, 0); 98 | 99 | gtk_signal_connect (GTK_OBJECT (window), "destroy", 100 | GTK_SIGNAL_FUNC (on_window1_destroy), 101 | NULL); 102 | gtk_signal_connect (GTK_OBJECT (draw_main), "button_press_event", 103 | GTK_SIGNAL_FUNC (on_draw_main_button_press_event), 104 | NULL); 105 | gtk_signal_connect (GTK_OBJECT (draw_main), "expose_event", 106 | GTK_SIGNAL_FUNC (on_draw_main_expose_event), 107 | NULL); 108 | gtk_signal_connect (GTK_OBJECT (button_change), "clicked", 109 | GTK_SIGNAL_FUNC (on_button_change_clicked), 110 | NULL); 111 | gtk_signal_connect (GTK_OBJECT (button_run), "clicked", 112 | GTK_SIGNAL_FUNC (on_button_run_clicked), 113 | NULL); 114 | gtk_signal_connect (GTK_OBJECT (button_clear), "clicked", 115 | GTK_SIGNAL_FUNC (on_button_clear_clicked), 116 | NULL); 117 | gtk_signal_connect (GTK_OBJECT (button_save), "clicked", 118 | GTK_SIGNAL_FUNC (on_button_save_clicked), 119 | NULL); 120 | gtk_signal_connect (GTK_OBJECT (button_load), "clicked", 121 | GTK_SIGNAL_FUNC (on_button_load_clicked), 122 | NULL); 123 | gtk_signal_connect (GTK_OBJECT (entry_option), "activate", 124 | GTK_SIGNAL_FUNC (on_button_run_clicked), 125 | NULL); 126 | 127 | return window; 128 | } 129 | 130 | GtkWidget* 131 | create_fileselection (void) 132 | { 133 | GtkWidget *fileselection; 134 | GtkWidget *filesel_ok; 135 | GtkWidget *filesel_cancel; 136 | 137 | fileselection = gtk_file_selection_new ("Select File"); 138 | gtk_object_set_data (GTK_OBJECT (fileselection), "fileselection", fileselection); 139 | gtk_container_set_border_width (GTK_CONTAINER (fileselection), 10); 140 | gtk_window_set_modal (GTK_WINDOW (fileselection), TRUE); 141 | 142 | filesel_ok = GTK_FILE_SELECTION (fileselection)->ok_button; 143 | gtk_object_set_data (GTK_OBJECT (fileselection), "filesel_ok", filesel_ok); 144 | gtk_widget_show (filesel_ok); 145 | GTK_WIDGET_SET_FLAGS (filesel_ok, GTK_CAN_DEFAULT); 146 | 147 | filesel_cancel = GTK_FILE_SELECTION (fileselection)->cancel_button; 148 | gtk_object_set_data (GTK_OBJECT (fileselection), "filesel_cancel", filesel_cancel); 149 | gtk_widget_show (filesel_cancel); 150 | GTK_WIDGET_SET_FLAGS (filesel_cancel, GTK_CAN_DEFAULT); 151 | 152 | gtk_signal_connect (GTK_OBJECT (fileselection), "destroy", 153 | GTK_SIGNAL_FUNC (on_fileselection_destroy), 154 | NULL); 155 | gtk_signal_connect (GTK_OBJECT (filesel_ok), "clicked", 156 | GTK_SIGNAL_FUNC (on_filesel_ok_clicked), 157 | NULL); 158 | gtk_signal_connect (GTK_OBJECT (filesel_cancel), "clicked", 159 | GTK_SIGNAL_FUNC (on_filesel_cancel_clicked), 160 | NULL); 161 | 162 | return fileselection; 163 | } 164 | 165 | -------------------------------------------------------------------------------- /svm-toy/gtk/interface.h: -------------------------------------------------------------------------------- 1 | /* 2 | * DO NOT EDIT THIS FILE - it is generated by Glade. 3 | */ 4 | 5 | #ifdef __cplusplus 6 | extern "C" { 7 | #endif 8 | 9 | GtkWidget* create_window (void); 10 | GtkWidget* create_fileselection (void); 11 | 12 | #ifdef __cplusplus 13 | } 14 | #endif 15 | -------------------------------------------------------------------------------- /svm-toy/gtk/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Initial main.c file generated by Glade. Edit as required. 3 | * Glade will not overwrite this file. 4 | */ 5 | 6 | #include 7 | #include "interface.h" 8 | void svm_toy_initialize(); 9 | 10 | int main (int argc, char *argv[]) 11 | { 12 | GtkWidget *window; 13 | 14 | gtk_set_locale (); 15 | gtk_init (&argc, &argv); 16 | 17 | window = create_window (); 18 | gtk_widget_show (window); 19 | 20 | svm_toy_initialize(); 21 | gtk_main (); 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /svm-toy/gtk/svm-toy.glade: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | svm-toy 6 | svm-toy 7 | 8 | src 9 | pixmaps 10 | C 11 | False 12 | False 13 | False 14 | True 15 | True 16 | True 17 | False 18 | interface.c 19 | interface.h 20 | callbacks.c 21 | callbacks.h 22 | support.c 23 | support.h 24 | 25 | 26 | 27 | 28 | GtkWindow 29 | window 30 | 31 | destroy 32 | on_window1_destroy 33 | Sun, 16 Apr 2000 09:47:10 GMT 34 | 35 | SVM Toy 36 | GTK_WINDOW_TOPLEVEL 37 | GTK_WIN_POS_NONE 38 | False 39 | False 40 | True 41 | False 42 | 43 | 44 | GtkVBox 45 | vbox1 46 | False 47 | 0 48 | 49 | 50 | GtkDrawingArea 51 | draw_main 52 | 500 53 | 500 54 | GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK 55 | 56 | button_press_event 57 | on_draw_main_button_press_event 58 | Sun, 16 Apr 2000 13:02:05 GMT 59 | 60 | 61 | expose_event 62 | on_draw_main_expose_event 63 | Sun, 16 Apr 2000 14:27:05 GMT 64 | 65 | 66 | 0 67 | True 68 | True 69 | 70 | 71 | 72 | 73 | GtkHBox 74 | hbox1 75 | False 76 | 0 77 | 78 | 0 79 | False 80 | False 81 | 82 | 83 | 84 | GtkButton 85 | button_change 86 | True 87 | 88 | clicked 89 | on_button_change_clicked 90 | Sun, 16 Apr 2000 09:40:18 GMT 91 | 92 | 93 | 94 | 0 95 | False 96 | False 97 | 98 | 99 | 100 | 101 | GtkButton 102 | button_run 103 | True 104 | 105 | clicked 106 | on_button_run_clicked 107 | Sun, 16 Apr 2000 09:40:37 GMT 108 | 109 | 110 | 111 | 0 112 | False 113 | False 114 | 115 | 116 | 117 | 118 | GtkButton 119 | button_clear 120 | True 121 | 122 | clicked 123 | on_button_clear_clicked 124 | Sun, 16 Apr 2000 09:40:44 GMT 125 | 126 | 127 | 128 | 0 129 | False 130 | False 131 | 132 | 133 | 134 | 135 | GtkButton 136 | button_save 137 | True 138 | 139 | clicked 140 | on_button_save_clicked 141 | Fri, 16 Jun 2000 18:23:46 GMT 142 | 143 | 144 | 145 | 0 146 | False 147 | False 148 | 149 | 150 | 151 | 152 | GtkButton 153 | button_load 154 | True 155 | 156 | clicked 157 | on_button_load_clicked 158 | Fri, 16 Jun 2000 18:23:56 GMT 159 | 160 | 161 | 162 | 0 163 | False 164 | False 165 | 166 | 167 | 168 | 169 | GtkEntry 170 | entry_option 171 | True 172 | 173 | activate 174 | on_button_run_clicked 175 | Sun, 16 Apr 2000 09:42:46 GMT 176 | 177 | True 178 | True 179 | 0 180 | 181 | 182 | 0 183 | True 184 | True 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | GtkFileSelection 193 | fileselection 194 | 10 195 | 196 | destroy 197 | on_fileselection_destroy 198 | Fri, 16 Jun 2000 18:11:28 GMT 199 | 200 | Select File 201 | GTK_WINDOW_TOPLEVEL 202 | GTK_WIN_POS_NONE 203 | True 204 | False 205 | True 206 | False 207 | True 208 | 209 | 210 | GtkButton 211 | FileSel:ok_button 212 | filesel_ok 213 | True 214 | True 215 | 216 | clicked 217 | on_filesel_ok_clicked 218 | Fri, 16 Jun 2000 18:09:56 GMT 219 | 220 | 221 | 222 | 223 | 224 | GtkButton 225 | FileSel:cancel_button 226 | filesel_cancel 227 | True 228 | True 229 | 230 | clicked 231 | on_filesel_cancel_clicked 232 | Fri, 16 Jun 2000 18:09:46 GMT 233 | 234 | 235 | 236 | 237 | 238 | 239 | -------------------------------------------------------------------------------- /svm-toy/qt/Makefile: -------------------------------------------------------------------------------- 1 | CXX? = g++ 2 | CFLAGS = -Wall -O3 -I$(INCLUDE) -I$(INCLUDE)/QtGui -lQtGui 3 | INCLUDE = /usr/include/qt4 4 | MOC = /usr/bin/moc-qt4 5 | 6 | svm-toy: svm-toy.cpp svm-toy.moc ../../svm.o 7 | $(CXX) $(CFLAGS) svm-toy.cpp ../../svm.o -o svm-toy 8 | 9 | svm-toy.moc: svm-toy.cpp 10 | $(MOC) svm-toy.cpp -o svm-toy.moc 11 | 12 | ../../svm.o: 13 | cd ../..; make svm.o 14 | 15 | clean: 16 | rm -f *~ svm-toy svm-toy.moc ../../svm.o 17 | 18 | -------------------------------------------------------------------------------- /svm-toy/qt/svm-toy.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "../../svm.h" 7 | using namespace std; 8 | 9 | #define DEFAULT_PARAM "-t 2 -c 100" 10 | #define XLEN 500 11 | #define YLEN 500 12 | 13 | QRgb colors[] = 14 | { 15 | qRgb(0,0,0), 16 | qRgb(0,120,120), 17 | qRgb(120,120,0), 18 | qRgb(120,0,120), 19 | qRgb(0,200,200), 20 | qRgb(200,200,0), 21 | qRgb(200,0,200) 22 | }; 23 | 24 | class SvmToyWindow : public QWidget 25 | { 26 | 27 | Q_OBJECT 28 | 29 | public: 30 | SvmToyWindow(); 31 | ~SvmToyWindow(); 32 | protected: 33 | virtual void mousePressEvent( QMouseEvent* ); 34 | virtual void paintEvent( QPaintEvent* ); 35 | 36 | private: 37 | QPixmap buffer; 38 | QPixmap icon1; 39 | QPixmap icon2; 40 | QPixmap icon3; 41 | QPushButton button_change_icon; 42 | QPushButton button_run; 43 | QPushButton button_clear; 44 | QPushButton button_save; 45 | QPushButton button_load; 46 | QLineEdit input_line; 47 | QPainter buffer_painter; 48 | struct point { 49 | double x, y; 50 | signed char value; 51 | }; 52 | list point_list; 53 | int current_value; 54 | const QPixmap& choose_icon(int v) 55 | { 56 | if(v==1) return icon1; 57 | else if(v==2) return icon2; 58 | else return icon3; 59 | } 60 | void clear_all() 61 | { 62 | point_list.clear(); 63 | buffer.fill(Qt::black); 64 | repaint(); 65 | } 66 | void draw_point(const point& p) 67 | { 68 | const QPixmap& icon = choose_icon(p.value); 69 | buffer_painter.drawPixmap((int)(p.x*XLEN),(int)(p.y*YLEN),icon); 70 | repaint(); 71 | } 72 | void draw_all_points() 73 | { 74 | for(list::iterator p = point_list.begin(); p != point_list.end();p++) 75 | draw_point(*p); 76 | } 77 | private slots: 78 | void button_change_icon_clicked() 79 | { 80 | ++current_value; 81 | if(current_value > 3) current_value = 1; 82 | button_change_icon.setIcon(choose_icon(current_value)); 83 | } 84 | void button_run_clicked() 85 | { 86 | // guard 87 | if(point_list.empty()) return; 88 | 89 | svm_parameter param; 90 | int i,j; 91 | 92 | // default values 93 | param.svm_type = C_SVC; 94 | param.kernel_type = RBF; 95 | param.degree = 3; 96 | param.gamma = 0; 97 | param.coef0 = 0; 98 | param.nu = 0.5; 99 | param.cache_size = 100; 100 | param.C = 1; 101 | param.eps = 1e-3; 102 | param.p = 0.1; 103 | param.shrinking = 1; 104 | param.probability = 0; 105 | param.nr_weight = 0; 106 | param.weight_label = NULL; 107 | param.weight = NULL; 108 | 109 | // parse options 110 | const char *p = input_line.text().toAscii().constData(); 111 | 112 | while (1) { 113 | while (*p && *p != '-') 114 | p++; 115 | 116 | if (*p == '\0') 117 | break; 118 | 119 | p++; 120 | switch (*p++) { 121 | case 's': 122 | param.svm_type = atoi(p); 123 | break; 124 | case 't': 125 | param.kernel_type = atoi(p); 126 | break; 127 | case 'd': 128 | param.degree = atoi(p); 129 | break; 130 | case 'g': 131 | param.gamma = atof(p); 132 | break; 133 | case 'r': 134 | param.coef0 = atof(p); 135 | break; 136 | case 'n': 137 | param.nu = atof(p); 138 | break; 139 | case 'm': 140 | param.cache_size = atof(p); 141 | break; 142 | case 'c': 143 | param.C = atof(p); 144 | break; 145 | case 'e': 146 | param.eps = atof(p); 147 | break; 148 | case 'p': 149 | param.p = atof(p); 150 | break; 151 | case 'h': 152 | param.shrinking = atoi(p); 153 | break; 154 | case 'b': 155 | param.probability = atoi(p); 156 | break; 157 | case 'w': 158 | ++param.nr_weight; 159 | param.weight_label = (int *)realloc(param.weight_label,sizeof(int)*param.nr_weight); 160 | param.weight = (double *)realloc(param.weight,sizeof(double)*param.nr_weight); 161 | param.weight_label[param.nr_weight-1] = atoi(p); 162 | while(*p && !isspace(*p)) ++p; 163 | param.weight[param.nr_weight-1] = atof(p); 164 | break; 165 | } 166 | } 167 | 168 | // build problem 169 | svm_problem prob; 170 | 171 | prob.l = point_list.size(); 172 | prob.y = new double[prob.l]; 173 | 174 | if(param.kernel_type == PRECOMPUTED) 175 | { 176 | } 177 | else if(param.svm_type == EPSILON_SVR || 178 | param.svm_type == NU_SVR) 179 | { 180 | if(param.gamma == 0) param.gamma = 1; 181 | svm_node *x_space = new svm_node[2 * prob.l]; 182 | prob.x = new svm_node *[prob.l]; 183 | 184 | i = 0; 185 | for (list ::iterator q = point_list.begin(); q != point_list.end(); q++, i++) 186 | { 187 | x_space[2 * i].index = 1; 188 | x_space[2 * i].value = q->x; 189 | x_space[2 * i + 1].index = -1; 190 | prob.x[i] = &x_space[2 * i]; 191 | prob.y[i] = q->y; 192 | } 193 | 194 | // build model & classify 195 | svm_model *model = svm_train(&prob, ¶m); 196 | svm_node x[2]; 197 | x[0].index = 1; 198 | x[1].index = -1; 199 | int *j = new int[XLEN]; 200 | 201 | for (i = 0; i < XLEN; i++) 202 | { 203 | x[0].value = (double) i / XLEN; 204 | j[i] = (int)(YLEN*svm_predict(model, x)); 205 | } 206 | 207 | buffer_painter.setPen(colors[0]); 208 | buffer_painter.drawLine(0,0,0,YLEN-1); 209 | 210 | int p = (int)(param.p * YLEN); 211 | for(i = 1; i < XLEN; i++) 212 | { 213 | buffer_painter.setPen(colors[0]); 214 | buffer_painter.drawLine(i,0,i,YLEN-1); 215 | 216 | buffer_painter.setPen(colors[5]); 217 | buffer_painter.drawLine(i-1,j[i-1],i,j[i]); 218 | 219 | if(param.svm_type == EPSILON_SVR) 220 | { 221 | buffer_painter.setPen(colors[2]); 222 | buffer_painter.drawLine(i-1,j[i-1]+p,i,j[i]+p); 223 | 224 | buffer_painter.setPen(colors[2]); 225 | buffer_painter.drawLine(i-1,j[i-1]-p,i,j[i]-p); 226 | } 227 | } 228 | 229 | svm_free_and_destroy_model(&model); 230 | delete[] j; 231 | delete[] x_space; 232 | delete[] prob.x; 233 | delete[] prob.y; 234 | } 235 | else 236 | { 237 | if(param.gamma == 0) param.gamma = 0.5; 238 | svm_node *x_space = new svm_node[3 * prob.l]; 239 | prob.x = new svm_node *[prob.l]; 240 | 241 | i = 0; 242 | for (list ::iterator q = point_list.begin(); q != point_list.end(); q++, i++) 243 | { 244 | x_space[3 * i].index = 1; 245 | x_space[3 * i].value = q->x; 246 | x_space[3 * i + 1].index = 2; 247 | x_space[3 * i + 1].value = q->y; 248 | x_space[3 * i + 2].index = -1; 249 | prob.x[i] = &x_space[3 * i]; 250 | prob.y[i] = q->value; 251 | } 252 | 253 | // build model & classify 254 | svm_model *model = svm_train(&prob, ¶m); 255 | svm_node x[3]; 256 | x[0].index = 1; 257 | x[1].index = 2; 258 | x[2].index = -1; 259 | 260 | for (i = 0; i < XLEN; i++) 261 | for (j = 0; j < YLEN ; j++) { 262 | x[0].value = (double) i / XLEN; 263 | x[1].value = (double) j / YLEN; 264 | double d = svm_predict(model, x); 265 | if (param.svm_type == ONE_CLASS && d<0) d=2; 266 | buffer_painter.setPen(colors[(int)d]); 267 | buffer_painter.drawPoint(i,j); 268 | } 269 | 270 | svm_free_and_destroy_model(&model); 271 | delete[] x_space; 272 | delete[] prob.x; 273 | delete[] prob.y; 274 | } 275 | free(param.weight_label); 276 | free(param.weight); 277 | draw_all_points(); 278 | } 279 | void button_clear_clicked() 280 | { 281 | clear_all(); 282 | } 283 | void button_save_clicked() 284 | { 285 | QString filename = QFileDialog::getSaveFileName(); 286 | if(!filename.isNull()) 287 | { 288 | FILE *fp = fopen(filename.toAscii().constData(),"w"); 289 | if(fp) 290 | { 291 | for(list::iterator p = point_list.begin(); p != point_list.end();p++) 292 | fprintf(fp,"%d 1:%f 2:%f\n", p->value, p->x, p->y); 293 | fclose(fp); 294 | } 295 | } 296 | } 297 | void button_load_clicked() 298 | { 299 | QString filename = QFileDialog::getOpenFileName(); 300 | if(!filename.isNull()) 301 | { 302 | FILE *fp = fopen(filename.toAscii().constData(),"r"); 303 | if(fp) 304 | { 305 | clear_all(); 306 | char buf[4096]; 307 | while(fgets(buf,sizeof(buf),fp)) 308 | { 309 | int v; 310 | double x,y; 311 | if(sscanf(buf,"%d%*d:%lf%*d:%lf",&v,&x,&y)!=3) 312 | break; 313 | point p = {x,y,v}; 314 | point_list.push_back(p); 315 | } 316 | fclose(fp); 317 | draw_all_points(); 318 | } 319 | } 320 | 321 | } 322 | }; 323 | 324 | #include "svm-toy.moc" 325 | 326 | SvmToyWindow::SvmToyWindow() 327 | :button_change_icon(this) 328 | ,button_run("Run",this) 329 | ,button_clear("Clear",this) 330 | ,button_save("Save",this) 331 | ,button_load("Load",this) 332 | ,input_line(this) 333 | ,current_value(1) 334 | { 335 | buffer = QPixmap(XLEN,YLEN); 336 | buffer.fill(Qt::black); 337 | 338 | buffer_painter.begin(&buffer); 339 | 340 | QObject::connect(&button_change_icon, SIGNAL(clicked()), this, 341 | SLOT(button_change_icon_clicked())); 342 | QObject::connect(&button_run, SIGNAL(clicked()), this, 343 | SLOT(button_run_clicked())); 344 | QObject::connect(&button_clear, SIGNAL(clicked()), this, 345 | SLOT(button_clear_clicked())); 346 | QObject::connect(&button_save, SIGNAL(clicked()), this, 347 | SLOT(button_save_clicked())); 348 | QObject::connect(&button_load, SIGNAL(clicked()), this, 349 | SLOT(button_load_clicked())); 350 | QObject::connect(&input_line, SIGNAL(returnPressed()), this, 351 | SLOT(button_run_clicked())); 352 | 353 | // don't blank the window before repainting 354 | setAttribute(Qt::WA_NoBackground); 355 | 356 | icon1 = QPixmap(4,4); 357 | icon2 = QPixmap(4,4); 358 | icon3 = QPixmap(4,4); 359 | 360 | 361 | QPainter painter; 362 | painter.begin(&icon1); 363 | painter.fillRect(0,0,4,4,QBrush(colors[4])); 364 | painter.end(); 365 | 366 | painter.begin(&icon2); 367 | painter.fillRect(0,0,4,4,QBrush(colors[5])); 368 | painter.end(); 369 | 370 | painter.begin(&icon3); 371 | painter.fillRect(0,0,4,4,QBrush(colors[6])); 372 | painter.end(); 373 | 374 | button_change_icon.setGeometry( 0, YLEN, 50, 25 ); 375 | button_run.setGeometry( 50, YLEN, 50, 25 ); 376 | button_clear.setGeometry( 100, YLEN, 50, 25 ); 377 | button_save.setGeometry( 150, YLEN, 50, 25); 378 | button_load.setGeometry( 200, YLEN, 50, 25); 379 | input_line.setGeometry( 250, YLEN, 250, 25); 380 | 381 | input_line.setText(DEFAULT_PARAM); 382 | button_change_icon.setIcon(icon1); 383 | } 384 | 385 | SvmToyWindow::~SvmToyWindow() 386 | { 387 | buffer_painter.end(); 388 | } 389 | 390 | void SvmToyWindow::mousePressEvent( QMouseEvent* event ) 391 | { 392 | point p = {(double)event->x()/XLEN, (double)event->y()/YLEN, current_value}; 393 | point_list.push_back(p); 394 | draw_point(p); 395 | } 396 | 397 | void SvmToyWindow::paintEvent( QPaintEvent* ) 398 | { 399 | // copy the image from the buffer pixmap to the window 400 | QPainter p(this); 401 | p.drawPixmap(0, 0, buffer); 402 | } 403 | 404 | int main( int argc, char* argv[] ) 405 | { 406 | QApplication myapp( argc, argv ); 407 | 408 | SvmToyWindow* mywidget = new SvmToyWindow(); 409 | mywidget->setGeometry( 100, 100, XLEN, YLEN+25 ); 410 | 411 | mywidget->show(); 412 | return myapp.exec(); 413 | } 414 | -------------------------------------------------------------------------------- /svm-toy/windows/svm-toy.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "../../svm.h" 7 | using namespace std; 8 | 9 | #define DEFAULT_PARAM "-t 2 -c 100" 10 | #define XLEN 500 11 | #define YLEN 500 12 | #define DrawLine(dc,x1,y1,x2,y2,c) \ 13 | do { \ 14 | HPEN hpen = CreatePen(PS_SOLID,0,c); \ 15 | HPEN horig = SelectPen(dc,hpen); \ 16 | MoveToEx(dc,x1,y1,NULL); \ 17 | LineTo(dc,x2,y2); \ 18 | SelectPen(dc,horig); \ 19 | DeletePen(hpen); \ 20 | } while(0) 21 | 22 | using namespace std; 23 | 24 | COLORREF colors[] = 25 | { 26 | RGB(0,0,0), 27 | RGB(0,120,120), 28 | RGB(120,120,0), 29 | RGB(120,0,120), 30 | RGB(0,200,200), 31 | RGB(200,200,0), 32 | RGB(200,0,200) 33 | }; 34 | 35 | HWND main_window; 36 | HBITMAP buffer; 37 | HDC window_dc; 38 | HDC buffer_dc; 39 | HBRUSH brush1, brush2, brush3; 40 | HWND edit; 41 | 42 | enum { 43 | ID_BUTTON_CHANGE, ID_BUTTON_RUN, ID_BUTTON_CLEAR, 44 | ID_BUTTON_LOAD, ID_BUTTON_SAVE, ID_EDIT 45 | }; 46 | 47 | struct point { 48 | double x, y; 49 | signed char value; 50 | }; 51 | 52 | list point_list; 53 | int current_value = 1; 54 | 55 | LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); 56 | 57 | int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, 58 | PSTR szCmdLine, int iCmdShow) 59 | { 60 | static char szAppName[] = "SvmToy"; 61 | MSG msg; 62 | WNDCLASSEX wndclass; 63 | 64 | wndclass.cbSize = sizeof(wndclass); 65 | wndclass.style = CS_HREDRAW | CS_VREDRAW; 66 | wndclass.lpfnWndProc = WndProc; 67 | wndclass.cbClsExtra = 0; 68 | wndclass.cbWndExtra = 0; 69 | wndclass.hInstance = hInstance; 70 | wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); 71 | wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); 72 | wndclass.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH); 73 | wndclass.lpszMenuName = NULL; 74 | wndclass.lpszClassName = szAppName; 75 | wndclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION); 76 | 77 | RegisterClassEx(&wndclass); 78 | 79 | main_window = CreateWindow(szAppName, // window class name 80 | "SVM Toy", // window caption 81 | WS_OVERLAPPEDWINDOW,// window style 82 | CW_USEDEFAULT, // initial x position 83 | CW_USEDEFAULT, // initial y position 84 | XLEN, // initial x size 85 | YLEN+52, // initial y size 86 | NULL, // parent window handle 87 | NULL, // window menu handle 88 | hInstance, // program instance handle 89 | NULL); // creation parameters 90 | 91 | ShowWindow(main_window, iCmdShow); 92 | UpdateWindow(main_window); 93 | 94 | CreateWindow("button", "Change", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 95 | 0, YLEN, 50, 25, main_window, (HMENU) ID_BUTTON_CHANGE, hInstance, NULL); 96 | CreateWindow("button", "Run", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 97 | 50, YLEN, 50, 25, main_window, (HMENU) ID_BUTTON_RUN, hInstance, NULL); 98 | CreateWindow("button", "Clear", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 99 | 100, YLEN, 50, 25, main_window, (HMENU) ID_BUTTON_CLEAR, hInstance, NULL); 100 | CreateWindow("button", "Save", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 101 | 150, YLEN, 50, 25, main_window, (HMENU) ID_BUTTON_SAVE, hInstance, NULL); 102 | CreateWindow("button", "Load", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 103 | 200, YLEN, 50, 25, main_window, (HMENU) ID_BUTTON_LOAD, hInstance, NULL); 104 | 105 | edit = CreateWindow("edit", NULL, WS_CHILD | WS_VISIBLE, 106 | 250, YLEN, 250, 25, main_window, (HMENU) ID_EDIT, hInstance, NULL); 107 | 108 | Edit_SetText(edit,DEFAULT_PARAM); 109 | 110 | brush1 = CreateSolidBrush(colors[4]); 111 | brush2 = CreateSolidBrush(colors[5]); 112 | brush3 = CreateSolidBrush(colors[6]); 113 | 114 | window_dc = GetDC(main_window); 115 | buffer = CreateCompatibleBitmap(window_dc, XLEN, YLEN); 116 | buffer_dc = CreateCompatibleDC(window_dc); 117 | SelectObject(buffer_dc, buffer); 118 | PatBlt(buffer_dc, 0, 0, XLEN, YLEN, BLACKNESS); 119 | 120 | while (GetMessage(&msg, NULL, 0, 0)) { 121 | TranslateMessage(&msg); 122 | DispatchMessage(&msg); 123 | } 124 | return msg.wParam; 125 | } 126 | 127 | int getfilename( HWND hWnd , char *filename, int len, int save) 128 | { 129 | OPENFILENAME OpenFileName; 130 | memset(&OpenFileName,0,sizeof(OpenFileName)); 131 | filename[0]='\0'; 132 | 133 | OpenFileName.lStructSize = sizeof(OPENFILENAME); 134 | OpenFileName.hwndOwner = hWnd; 135 | OpenFileName.lpstrFile = filename; 136 | OpenFileName.nMaxFile = len; 137 | OpenFileName.Flags = 0; 138 | 139 | return save?GetSaveFileName(&OpenFileName):GetOpenFileName(&OpenFileName); 140 | } 141 | 142 | void clear_all() 143 | { 144 | point_list.clear(); 145 | PatBlt(buffer_dc, 0, 0, XLEN, YLEN, BLACKNESS); 146 | InvalidateRect(main_window, 0, 0); 147 | } 148 | 149 | HBRUSH choose_brush(int v) 150 | { 151 | if(v==1) return brush1; 152 | else if(v==2) return brush2; 153 | else return brush3; 154 | } 155 | 156 | void draw_point(const point & p) 157 | { 158 | RECT rect; 159 | rect.left = int(p.x*XLEN); 160 | rect.top = int(p.y*YLEN); 161 | rect.right = int(p.x*XLEN) + 3; 162 | rect.bottom = int(p.y*YLEN) + 3; 163 | FillRect(window_dc, &rect, choose_brush(p.value)); 164 | FillRect(buffer_dc, &rect, choose_brush(p.value)); 165 | } 166 | 167 | void draw_all_points() 168 | { 169 | for(list::iterator p = point_list.begin(); p != point_list.end(); p++) 170 | draw_point(*p); 171 | } 172 | 173 | void button_run_clicked() 174 | { 175 | // guard 176 | if(point_list.empty()) return; 177 | 178 | svm_parameter param; 179 | int i,j; 180 | 181 | // default values 182 | param.svm_type = C_SVC; 183 | param.kernel_type = RBF; 184 | param.degree = 3; 185 | param.gamma = 0; 186 | param.coef0 = 0; 187 | param.nu = 0.5; 188 | param.cache_size = 100; 189 | param.C = 1; 190 | param.eps = 1e-3; 191 | param.p = 0.1; 192 | param.shrinking = 1; 193 | param.probability = 0; 194 | param.nr_weight = 0; 195 | param.weight_label = NULL; 196 | param.weight = NULL; 197 | 198 | // parse options 199 | char str[1024]; 200 | Edit_GetLine(edit, 0, str, sizeof(str)); 201 | const char *p = str; 202 | 203 | while (1) { 204 | while (*p && *p != '-') 205 | p++; 206 | 207 | if (*p == '\0') 208 | break; 209 | 210 | p++; 211 | switch (*p++) { 212 | case 's': 213 | param.svm_type = atoi(p); 214 | break; 215 | case 't': 216 | param.kernel_type = atoi(p); 217 | break; 218 | case 'd': 219 | param.degree = atoi(p); 220 | break; 221 | case 'g': 222 | param.gamma = atof(p); 223 | break; 224 | case 'r': 225 | param.coef0 = atof(p); 226 | break; 227 | case 'n': 228 | param.nu = atof(p); 229 | break; 230 | case 'm': 231 | param.cache_size = atof(p); 232 | break; 233 | case 'c': 234 | param.C = atof(p); 235 | break; 236 | case 'e': 237 | param.eps = atof(p); 238 | break; 239 | case 'p': 240 | param.p = atof(p); 241 | break; 242 | case 'h': 243 | param.shrinking = atoi(p); 244 | break; 245 | case 'b': 246 | param.probability = atoi(p); 247 | break; 248 | case 'w': 249 | ++param.nr_weight; 250 | param.weight_label = (int *)realloc(param.weight_label,sizeof(int)*param.nr_weight); 251 | param.weight = (double *)realloc(param.weight,sizeof(double)*param.nr_weight); 252 | param.weight_label[param.nr_weight-1] = atoi(p); 253 | while(*p && !isspace(*p)) ++p; 254 | param.weight[param.nr_weight-1] = atof(p); 255 | break; 256 | } 257 | } 258 | 259 | // build problem 260 | svm_problem prob; 261 | 262 | prob.l = point_list.size(); 263 | prob.y = new double[prob.l]; 264 | 265 | if(param.kernel_type == PRECOMPUTED) 266 | { 267 | } 268 | else if(param.svm_type == EPSILON_SVR || 269 | param.svm_type == NU_SVR) 270 | { 271 | if(param.gamma == 0) param.gamma = 1; 272 | svm_node *x_space = new svm_node[2 * prob.l]; 273 | prob.x = new svm_node *[prob.l]; 274 | 275 | i = 0; 276 | for (list::iterator q = point_list.begin(); q != point_list.end(); q++, i++) 277 | { 278 | x_space[2 * i].index = 1; 279 | x_space[2 * i].value = q->x; 280 | x_space[2 * i + 1].index = -1; 281 | prob.x[i] = &x_space[2 * i]; 282 | prob.y[i] = q->y; 283 | } 284 | 285 | // build model & classify 286 | svm_model *model = svm_train(&prob, ¶m); 287 | svm_node x[2]; 288 | x[0].index = 1; 289 | x[1].index = -1; 290 | int *j = new int[XLEN]; 291 | 292 | for (i = 0; i < XLEN; i++) 293 | { 294 | x[0].value = (double) i / XLEN; 295 | j[i] = (int)(YLEN*svm_predict(model, x)); 296 | } 297 | 298 | DrawLine(buffer_dc,0,0,0,YLEN,colors[0]); 299 | DrawLine(window_dc,0,0,0,YLEN,colors[0]); 300 | 301 | int p = (int)(param.p * YLEN); 302 | for(int i=1; i < XLEN; i++) 303 | { 304 | DrawLine(buffer_dc,i,0,i,YLEN,colors[0]); 305 | DrawLine(window_dc,i,0,i,YLEN,colors[0]); 306 | 307 | DrawLine(buffer_dc,i-1,j[i-1],i,j[i],colors[5]); 308 | DrawLine(window_dc,i-1,j[i-1],i,j[i],colors[5]); 309 | 310 | if(param.svm_type == EPSILON_SVR) 311 | { 312 | DrawLine(buffer_dc,i-1,j[i-1]+p,i,j[i]+p,colors[2]); 313 | DrawLine(window_dc,i-1,j[i-1]+p,i,j[i]+p,colors[2]); 314 | 315 | DrawLine(buffer_dc,i-1,j[i-1]-p,i,j[i]-p,colors[2]); 316 | DrawLine(window_dc,i-1,j[i-1]-p,i,j[i]-p,colors[2]); 317 | } 318 | } 319 | 320 | svm_free_and_destroy_model(&model); 321 | delete[] j; 322 | delete[] x_space; 323 | delete[] prob.x; 324 | delete[] prob.y; 325 | } 326 | else 327 | { 328 | if(param.gamma == 0) param.gamma = 0.5; 329 | svm_node *x_space = new svm_node[3 * prob.l]; 330 | prob.x = new svm_node *[prob.l]; 331 | 332 | i = 0; 333 | for (list::iterator q = point_list.begin(); q != point_list.end(); q++, i++) 334 | { 335 | x_space[3 * i].index = 1; 336 | x_space[3 * i].value = q->x; 337 | x_space[3 * i + 1].index = 2; 338 | x_space[3 * i + 1].value = q->y; 339 | x_space[3 * i + 2].index = -1; 340 | prob.x[i] = &x_space[3 * i]; 341 | prob.y[i] = q->value; 342 | } 343 | 344 | // build model & classify 345 | svm_model *model = svm_train(&prob, ¶m); 346 | svm_node x[3]; 347 | x[0].index = 1; 348 | x[1].index = 2; 349 | x[2].index = -1; 350 | 351 | for (i = 0; i < XLEN; i++) 352 | for (j = 0; j < YLEN; j++) { 353 | x[0].value = (double) i / XLEN; 354 | x[1].value = (double) j / YLEN; 355 | double d = svm_predict(model, x); 356 | if (param.svm_type == ONE_CLASS && d<0) d=2; 357 | SetPixel(window_dc, i, j, colors[(int)d]); 358 | SetPixel(buffer_dc, i, j, colors[(int)d]); 359 | } 360 | 361 | svm_free_and_destroy_model(&model); 362 | delete[] x_space; 363 | delete[] prob.x; 364 | delete[] prob.y; 365 | } 366 | free(param.weight_label); 367 | free(param.weight); 368 | draw_all_points(); 369 | } 370 | 371 | LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) 372 | { 373 | HDC hdc; 374 | PAINTSTRUCT ps; 375 | 376 | switch (iMsg) { 377 | case WM_LBUTTONDOWN: 378 | { 379 | int x = LOWORD(lParam); 380 | int y = HIWORD(lParam); 381 | point p = {(double)x/XLEN, (double)y/YLEN, current_value}; 382 | point_list.push_back(p); 383 | draw_point(p); 384 | } 385 | return 0; 386 | case WM_PAINT: 387 | { 388 | hdc = BeginPaint(hwnd, &ps); 389 | BitBlt(hdc, 0, 0, XLEN, YLEN, buffer_dc, 0, 0, SRCCOPY); 390 | EndPaint(hwnd, &ps); 391 | } 392 | return 0; 393 | case WM_COMMAND: 394 | { 395 | int id = LOWORD(wParam); 396 | switch (id) { 397 | case ID_BUTTON_CHANGE: 398 | ++current_value; 399 | if(current_value > 3) current_value = 1; 400 | break; 401 | case ID_BUTTON_RUN: 402 | button_run_clicked(); 403 | break; 404 | case ID_BUTTON_CLEAR: 405 | clear_all(); 406 | break; 407 | case ID_BUTTON_SAVE: 408 | { 409 | char filename[1024]; 410 | if(getfilename(hwnd,filename,1024,1)) 411 | { 412 | FILE *fp = fopen(filename,"w"); 413 | if(fp) 414 | { 415 | for (list::iterator p = point_list.begin(); p != point_list.end(); p++) 416 | fprintf(fp,"%d 1:%f 2:%f\n",p->value,p->x,p->y); 417 | fclose(fp); 418 | } 419 | } 420 | } 421 | break; 422 | case ID_BUTTON_LOAD: 423 | { 424 | char filename[1024]; 425 | if(getfilename(hwnd,filename,1024,0)) 426 | { 427 | FILE *fp = fopen(filename,"r"); 428 | if(fp) 429 | { 430 | clear_all(); 431 | char buf[4096]; 432 | while(fgets(buf,sizeof(buf),fp)) 433 | { 434 | int v; 435 | double x,y; 436 | if(sscanf(buf,"%d%*d:%lf%*d:%lf",&v,&x,&y)!=3) 437 | break; 438 | point p = {x,y,v}; 439 | point_list.push_back(p); 440 | } 441 | fclose(fp); 442 | draw_all_points(); 443 | } 444 | } 445 | } 446 | break; 447 | } 448 | } 449 | return 0; 450 | case WM_DESTROY: 451 | PostQuitMessage(0); 452 | return 0; 453 | } 454 | 455 | return DefWindowProc(hwnd, iMsg, wParam, lParam); 456 | } 457 | -------------------------------------------------------------------------------- /svm.def: -------------------------------------------------------------------------------- 1 | LIBRARY libsvm 2 | EXPORTS 3 | svm_train @1 4 | svm_cross_validation @2 5 | svm_save_model @3 6 | svm_load_model @4 7 | svm_get_svm_type @5 8 | svm_get_nr_class @6 9 | svm_get_labels @7 10 | svm_get_svr_probability @8 11 | svm_predict_values @9 12 | svm_predict @10 13 | svm_predict_probability @11 14 | svm_free_model_content @12 15 | svm_free_and_destroy_model @13 16 | svm_destroy_param @14 17 | svm_check_parameter @15 18 | svm_check_probability_model @16 19 | svm_set_print_string_function @17 20 | -------------------------------------------------------------------------------- /svm.h: -------------------------------------------------------------------------------- 1 | #ifndef _LIBSVM_H 2 | #define _LIBSVM_H 3 | 4 | #define LIBSVM_VERSION 310 5 | 6 | #define USEWSVM 7 | 8 | #ifdef USEWSVM 9 | #include "MetaRecognition.h" 10 | #endif 11 | 12 | 13 | #ifdef __cplusplus 14 | extern "C" { 15 | #endif 16 | 17 | extern int libsvm_version; 18 | 19 | struct svm_node{ 20 | int index; 21 | double value; 22 | }; 23 | 24 | struct svm_problem{ 25 | int l; 26 | double *y; 27 | struct svm_node **x; 28 | int nr_classes; 29 | int *labels; 30 | }; 31 | 32 | 33 | typedef enum { C_SVC, NU_SVC, ONE_CLASS, EPSILON_SVR, NU_SVR, OPENSET_OC, OPENSET_PAIR, OPENSET_BIN, ONE_VS_REST_WSVM, ONE_WSVM, PI_SVM} svm_type_t; /* svm_type */ 34 | typedef enum { LINEAR, POLY, RBF, SIGMOID, PRECOMPUTED } kernel_t; /* kernel_type */ 35 | 36 | typedef enum {OPT_PRECISION, OPT_RECALL, OPT_FMEASURE, OPT_HINGE, OPT_BALANCEDRISK} openset_optimization_t; 37 | 38 | 39 | 40 | struct svm_parameter{ 41 | int svm_type; 42 | int kernel_type; 43 | int do_open; /* do we want to do open-set expansion of base kernel */ 44 | int degree; /* for poly */ 45 | double gamma; /* for poly/rbf/sigmoid */ 46 | double coef0; /* for poly/sigmoid */ 47 | /* these are for training only */ 48 | double cache_size; /* in MB */ 49 | double eps; /* stopping criteria */ 50 | double C; /* for C_SVC, EPSILON_SVR and NU_SVR */ 51 | int nr_weight; /* for C_SVC */ 52 | int nr_fold; /* for cross-validation in training */ 53 | int cross_validation; /* for cross-validation */ 54 | int *weight_label; /* for C_SVC */ 55 | double* weight; /* for C_SVC */ 56 | double nu; /* for NU_SVC, ONE_CLASS, and NU_SVR */ 57 | double p; /* for EPSILON_SVR */ 58 | int shrinking; /* use the shrinking heuristics */ 59 | int probability; /* do probability estimates */ 60 | bool neg_labels; /* do we consider negative class labels (like -1) as a label for openset, or just negative.. default is false */ 61 | bool exaustive_open; /* do we do exaustive optimization for openset.. default is false */ 62 | openset_optimization_t optimize; /* choice of what to optimize */ 63 | double beta; /* for use in f-measure optimization */ 64 | double near_preasure, far_preasure; /* for openset risk preasures */ 65 | double openset_min_probability; /* for WSVM openset, what is minimum probability to consider positive */ 66 | double openset_min_probability_one_wsvm; /* for WSVM openset, what is minimum probability to consider positive for one class wsvm */ 67 | FILE* vfile; /* for logging verbose stuff during debugging */ 68 | int rejectedID; /* id for rejected classes (-99999 is the default) */ 69 | double cap_cost; /* for C_SVC, EPSILON_SVR and NU_SVR */ 70 | double cap_gamma; /* for poly/rbf/sigmoid */ 71 | }; 72 | 73 | // 74 | // svm_model 75 | // 76 | struct svm_model{ 77 | struct svm_parameter param; /* parameter */ 78 | int nr_class; /* number of classes, = 2 in regression/one class svm */ 79 | int l; /* total #SV */ 80 | struct svm_node **SV; /* SVs (SV[l]) */ 81 | double **sv_coef; /* coefficients for SVs in decision functions (sv_coef[k-1][l]) */ 82 | double *rho; /* constants in decision functions (rho[k*(k-1)/2]) */ 83 | double *probA; /* pariwise probability information */ 84 | double *probB; 85 | int openset_dim; /* dimension of data for 1-vs-set models, if open_set, wsvm or open_bset (5,6,7) then openset_dim=k, if open_pair then its k*(k-1)/2*/ 86 | double *alpha, *omega; /* planes offsets for 1-vs-set alpha[openset_dim], omega[openset_dim] */ 87 | //double *wbltrans,*wblshape,*wblscale; /* weibul parms for wsvm all of dimension [openset_dim] */ 88 | #ifdef USEWSVM 89 | MetaRecognition *MRpos_one_vs_all, *MRcomp_one_vs_all; //MetaRecognition Objects for positive (inclass) and complement classifiers for 1-vs-all 90 | MetaRecognition *MRpos_one_class; //MetaRecognition Objects for positive (inclass) one-class 91 | #endif 92 | /* for classification only */ 93 | 94 | int *label; /* label of each class (label[k]) */ 95 | int *nSV; /* number of SVs for each class (nSV[k]) */ 96 | /* nSV[0] + nSV[1] + ... + nSV[k-1] = l */ 97 | /* XXX */ 98 | int free_sv; /* 1 if svm_model is created by svm_load_model and needs to free its memory*/ 99 | /* 0 if svm_model is created by svm_train */ 100 | }; 101 | 102 | struct svm_model *svm_train(const struct svm_problem *prob, const struct svm_parameter *param); 103 | void svm_cross_validation(const struct svm_problem *prob, const struct svm_parameter *param, int nr_fold, double *target); 104 | void svm_cross_validation_wsvm(const struct svm_problem *prob, const struct svm_parameter *param,const struct svm_problem *prob_one_wsvm, const struct svm_parameter *param_one_wsvm, int nr_fold, double *target); 105 | 106 | int svm_save_model(const char *model_file_name, const struct svm_model *model); 107 | struct svm_model *svm_load_model(const char *model_file_name); 108 | 109 | int svm_get_svm_type(const struct svm_model *model); 110 | int svm_get_nr_class(const struct svm_model *model); 111 | void svm_get_labels(const struct svm_model *model, int *label); 112 | double svm_get_svr_probability(const struct svm_model *model); 113 | double svm_predict_values(const struct svm_model *model, const struct svm_node *x, double* dec_values); 114 | double svm_predict_values_extended(const struct svm_model *model, const struct svm_node *x, 115 | double*& dec_values, double **&scores, int*& vote); 116 | double svm_predict_values_extended_plus_one_wsvm(const struct svm_model *model,const struct svm_model *model_one_wsvm, const struct svm_node *x, 117 | double*& dec_values_wsvm,double*& dec_values_one_wsvm, double **&scores, int*& vote); 118 | 119 | double svm_predict(const struct svm_model *model, const struct svm_node *x); 120 | double svm_predict_extended(const struct svm_model *model, const struct svm_node *x, 121 | double **&scores, int *&vote); 122 | double svm_predict_extended_plus_one_wsvm(const struct svm_model *model,const struct svm_model *model_one_wsvm, const struct svm_node *x, 123 | double **&scores, int *&vote); 124 | double svm_predict_probability(const struct svm_model *model, const struct svm_node *x, double* prob_estimates); 125 | 126 | void svm_free_model_content(struct svm_model *model_ptr); 127 | void svm_free_and_destroy_model(struct svm_model **model_ptr_ptr); 128 | void svm_destroy_param(struct svm_parameter *param); 129 | 130 | const char *svm_check_parameter(const struct svm_problem *prob, const struct svm_parameter *param); 131 | int svm_check_probability_model(const struct svm_model *model); 132 | 133 | void svm_set_print_string_function(void (*print_func)(const char *)); 134 | 135 | typedef unsigned long ulong; 136 | #ifdef __cplusplus 137 | } 138 | #endif 139 | 140 | #endif /* _LIBSVM_H */ 141 | -------------------------------------------------------------------------------- /tools/README: -------------------------------------------------------------------------------- 1 | This directory includes some useful codes: 2 | 3 | 1. subset selection tools. 4 | 2. parameter selection tools. 5 | 3. LIBSVM format checking tools 6 | 7 | Part I: Subset selection tools 8 | 9 | Introduction 10 | ============ 11 | 12 | Training large data is time consuming. Sometimes one should work on a 13 | smaller subset first. The python script subset.py randomly selects a 14 | specified number of samples. For classification data, we provide a 15 | stratified selection to ensure the same class distribution in the 16 | subset. 17 | 18 | Usage: subset.py [options] dataset number [output1] [output2] 19 | 20 | This script selects a subset of the given data set. 21 | 22 | options: 23 | -s method : method of selection (default 0) 24 | 0 -- stratified selection (classification only) 25 | 1 -- random selection 26 | 27 | output1 : the subset (optional) 28 | output2 : the rest of data (optional) 29 | 30 | If output1 is omitted, the subset will be printed on the screen. 31 | 32 | Example 33 | ======= 34 | 35 | > python subset.py heart_scale 100 file1 file2 36 | 37 | From heart_scale 100 samples are randomly selected and stored in 38 | file1. All remaining instances are stored in file2. 39 | 40 | 41 | Part II: Parameter Selection Tools 42 | 43 | Introduction 44 | ============ 45 | 46 | grid.py is a parameter selection tool for C-SVM classification using 47 | the RBF (radial basis function) kernel. It uses cross validation (CV) 48 | technique to estimate the accuracy of each parameter combination in 49 | the specified range and helps you to decide the best parameters for 50 | your problem. 51 | 52 | grid.py directly executes libsvm binaries (so no python binding is needed) 53 | for cross validation and then draw contour of CV accuracy using gnuplot. 54 | You must have libsvm and gnuplot installed before using it. The package 55 | gnuplot is available at http://www.gnuplot.info/ 56 | 57 | On Mac OSX, the precompiled gnuplot file needs the library Aquarterm, 58 | which thus must be installed as well. In addition, this version of 59 | gnuplot does not support png, so you need to change "set term png 60 | transparent small" and use other image formats. For example, you may 61 | have "set term pbm small color". 62 | 63 | Usage: grid.py [-log2c begin,end,step] [-log2g begin,end,step] [-v fold] 64 | [-svmtrain pathname] [-gnuplot pathname] [-out pathname] [-png pathname] 65 | [additional parameters for svm-train] dataset 66 | 67 | The program conducts v-fold cross validation using parameter C (and gamma) 68 | = 2^begin, 2^(begin+step), ..., 2^end. 69 | 70 | You can specify where the libsvm executable and gnuplot are using the 71 | -svmtrain and -gnuplot parameters. 72 | 73 | For windows users, please use pgnuplot.exe. If you are using gnuplot 74 | 3.7.1, please upgrade to version 3.7.3 or higher. The version 3.7.1 75 | has a bug. If you use cygwin on windows, please use gunplot-x11. 76 | 77 | Example 78 | ======= 79 | 80 | > python grid.py -log2c -5,5,1 -log2g -4,0,1 -v 5 -m 300 heart_scale 81 | 82 | Users (in particular MS Windows users) may need to specify the path of 83 | executable files. You can either change paths in the beginning of 84 | grid.py or specify them in the command line. For example, 85 | 86 | > grid.py -log2c -5,5,1 -svmtrain c:\libsvm\windows\svm-train.exe -gnuplot c:\tmp\gnuplot\bin\pgnuplot.exe -v 10 heart_scale 87 | 88 | Output: two files 89 | dataset.png: the CV accuracy contour plot generated by gnuplot 90 | dataset.out: the CV accuracy at each (log2(C),log2(gamma)) 91 | 92 | Parallel grid search 93 | ==================== 94 | 95 | You can conduct a parallel grid search by dispatching jobs to a 96 | cluster of computers which share the same file system. First, you add 97 | machine names in grid.py: 98 | 99 | ssh_workers = ["linux1", "linux5", "linux5"] 100 | 101 | and then setup your ssh so that the authentication works without 102 | asking a password. 103 | 104 | The same machine (e.g., linux5 here) can be listed more than once if 105 | it has multiple CPUs or has more RAM. If the local machine is the 106 | best, you can also enlarge the nr_local_worker. For example: 107 | 108 | nr_local_worker = 2 109 | 110 | Example: 111 | 112 | > python grid.py heart_scale 113 | [local] -1 -1 78.8889 (best c=0.5, g=0.5, rate=78.8889) 114 | [linux5] -1 -7 83.3333 (best c=0.5, g=0.0078125, rate=83.3333) 115 | [linux5] 5 -1 77.037 (best c=0.5, g=0.0078125, rate=83.3333) 116 | [linux1] 5 -7 83.3333 (best c=0.5, g=0.0078125, rate=83.3333) 117 | . 118 | . 119 | . 120 | 121 | If -log2c, -log2g, or -v is not specified, default values are used. 122 | 123 | If your system uses telnet instead of ssh, you list the computer names 124 | in telnet_workers. 125 | 126 | Part III: LIBSVM format checking tools 127 | 128 | Introduction 129 | ============ 130 | 131 | `svm-train' conducts only a simple check of the input data. To do a 132 | detailed check, we provide a python script `checkdata.py.' 133 | 134 | Usage: checkdata.py dataset 135 | 136 | Exit status (returned value): 1 if there are errors, 0 otherwise. 137 | 138 | This tool is written by Rong-En Fan at National Taiwan University. 139 | 140 | Example 141 | ======= 142 | 143 | > cat bad_data 144 | 1 3:1 2:4 145 | > python checkdata.py bad_data 146 | line 1: feature indices must be in an ascending order, previous/current features 3:1 2:4 147 | Found 1 lines with error. 148 | 149 | 150 | -------------------------------------------------------------------------------- /tools/checkdata.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # 4 | # A format checker for LIBSVM 5 | # 6 | 7 | # 8 | # Copyright (c) 2007, Rong-En Fan 9 | # 10 | # All rights reserved. 11 | # 12 | # This program is distributed under the same license of the LIBSVM package. 13 | # 14 | 15 | from sys import argv, exit 16 | import os.path 17 | 18 | def err(line_no, msg): 19 | print("line {0}: {1}".format(line_no, msg)) 20 | 21 | # works like float() but does not accept nan and inf 22 | def my_float(x): 23 | if x.lower().find("nan") != -1 or x.lower().find("inf") != -1: 24 | raise ValueError 25 | 26 | return float(x) 27 | 28 | def main(): 29 | if len(argv) != 2: 30 | print("Usage: {0} dataset".format(argv[0])) 31 | exit(1) 32 | 33 | dataset = argv[1] 34 | 35 | if not os.path.exists(dataset): 36 | print("dataset {0} not found".format(dataset)) 37 | exit(1) 38 | 39 | line_no = 1 40 | error_line_count = 0 41 | for line in open(dataset, 'r'): 42 | line_error = False 43 | 44 | # each line must end with a newline character 45 | if line[-1] != '\n': 46 | err(line_no, "missing a newline character in the end") 47 | line_error = True 48 | 49 | nodes = line.split() 50 | 51 | # check label 52 | try: 53 | label = nodes.pop(0) 54 | 55 | if label.find(',') != -1: 56 | # multi-label format 57 | try: 58 | for l in label.split(','): 59 | l = my_float(l) 60 | except: 61 | err(line_no, "label {0} is not a valid multi-label form".format(label)) 62 | line_error = True 63 | else: 64 | try: 65 | label = my_float(label) 66 | except: 67 | err(line_no, "label {0} is not a number".format(label)) 68 | line_error = True 69 | except: 70 | err(line_no, "missing label, perhaps an empty line?") 71 | line_error = True 72 | 73 | # check features 74 | prev_index = -1 75 | for i in range(len(nodes)): 76 | try: 77 | (index, value) = nodes[i].split(':') 78 | 79 | index = int(index) 80 | value = my_float(value) 81 | 82 | # precomputed kernel's index starts from 0 and LIBSVM 83 | # checks it. Hence, don't treat index 0 as an error. 84 | if index < 0: 85 | err(line_no, "feature index must be positive; wrong feature {0}".format(nodes[i])) 86 | line_error = True 87 | elif index < prev_index: 88 | err(line_no, "feature indices must be in an ascending order, previous/current features {0} {1}".format(nodes[i-1], nodes[i])) 89 | line_error = True 90 | prev_index = index 91 | except: 92 | err(line_no, "feature '{0}' not an : pair, integer, real number ".format(nodes[i])) 93 | line_error = True 94 | 95 | line_no += 1 96 | 97 | if line_error: 98 | error_line_count += 1 99 | 100 | if error_line_count > 0: 101 | print("Found {0} lines with error.".format(error_line_count)) 102 | return 1 103 | else: 104 | print("No error.") 105 | return 0 106 | 107 | if __name__ == "__main__": 108 | exit(main()) 109 | -------------------------------------------------------------------------------- /tools/easy.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import sys 4 | import os 5 | from subprocess import * 6 | 7 | if len(sys.argv) <= 1: 8 | print('Usage: {0} training_file [testing_file]'.format(sys.argv[0])) 9 | raise SystemExit 10 | 11 | # svm, grid, and gnuplot executable files 12 | 13 | is_win32 = (sys.platform == 'win32') 14 | if not is_win32: 15 | svmscale_exe = "../svm-scale" 16 | svmtrain_exe = "../svm-train" 17 | svmpredict_exe = "../svm-predict" 18 | grid_py = "./grid.py" 19 | gnuplot_exe = "/usr/bin/gnuplot" 20 | else: 21 | # example for windows 22 | svmscale_exe = r"..\windows\svm-scale.exe" 23 | svmtrain_exe = r"..\windows\svm-train.exe" 24 | svmpredict_exe = r"..\windows\svm-predict.exe" 25 | gnuplot_exe = r"c:\tmp\gnuplot\bin\pgnuplot.exe" 26 | grid_py = r".\grid.py" 27 | 28 | assert os.path.exists(svmscale_exe),"svm-scale executable not found" 29 | assert os.path.exists(svmtrain_exe),"svm-train executable not found" 30 | assert os.path.exists(svmpredict_exe),"svm-predict executable not found" 31 | assert os.path.exists(gnuplot_exe),"gnuplot executable not found" 32 | assert os.path.exists(grid_py),"grid.py not found" 33 | 34 | train_pathname = sys.argv[1] 35 | assert os.path.exists(train_pathname),"training file not found" 36 | file_name = os.path.split(train_pathname)[1] 37 | scaled_file = file_name + ".scale" 38 | model_file = file_name + ".model" 39 | range_file = file_name + ".range" 40 | 41 | if len(sys.argv) > 2: 42 | test_pathname = sys.argv[2] 43 | file_name = os.path.split(test_pathname)[1] 44 | assert os.path.exists(test_pathname),"testing file not found" 45 | scaled_test_file = file_name + ".scale" 46 | predict_test_file = file_name + ".predict" 47 | 48 | cmd = '{0} -s "{1}" "{2}" > "{3}"'.format(svmscale_exe, range_file, train_pathname, scaled_file) 49 | print('Scaling training data...') 50 | Popen(cmd, shell = True, stdout = PIPE).communicate() 51 | 52 | cmd = '{0} -svmtrain "{1}" -gnuplot "{2}" "{3}"'.format(grid_py, svmtrain_exe, gnuplot_exe, scaled_file) 53 | print('Cross validation...') 54 | f = Popen(cmd, shell = True, stdout = PIPE).stdout 55 | 56 | line = '' 57 | while True: 58 | last_line = line 59 | line = f.readline() 60 | if not line: break 61 | c,g,rate = map(float,last_line.split()) 62 | 63 | print('Best c={0}, g={1} CV rate={2}'.format(c,g,rate)) 64 | 65 | cmd = '{0} -c {1} -g {2} "{3}" "{4}"'.format(svmtrain_exe,c,g,scaled_file,model_file) 66 | print('Training...') 67 | Popen(cmd, shell = True, stdout = PIPE).communicate() 68 | 69 | print('Output model: {0}'.format(model_file)) 70 | if len(sys.argv) > 2: 71 | cmd = '{0} -r "{1}" "{2}" > "{3}"'.format(svmscale_exe, range_file, test_pathname, scaled_test_file) 72 | print('Scaling testing data...') 73 | Popen(cmd, shell = True, stdout = PIPE).communicate() 74 | 75 | cmd = '{0} "{1}" "{2}" "{3}"'.format(svmpredict_exe, scaled_test_file, model_file, predict_test_file) 76 | print('Testing...') 77 | Popen(cmd, shell = True).communicate() 78 | 79 | print('Output prediction: {0}'.format(predict_test_file)) 80 | -------------------------------------------------------------------------------- /tools/subset.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from sys import argv, exit, stdout, stderr 3 | from random import randint 4 | 5 | method = 0 6 | global n 7 | global dataset_filename 8 | subset_filename = "" 9 | rest_filename = "" 10 | 11 | def exit_with_help(): 12 | print("""\ 13 | Usage: {0} [options] dataset number [output1] [output2] 14 | 15 | This script selects a subset of the given dataset. 16 | 17 | options: 18 | -s method : method of selection (default 0) 19 | 0 -- stratified selection (classification only) 20 | 1 -- random selection 21 | 22 | output1 : the subset (optional) 23 | output2 : rest of the data (optional) 24 | If output1 is omitted, the subset will be printed on the screen.""".format(argv[0])) 25 | exit(1) 26 | 27 | def process_options(): 28 | global method, n 29 | global dataset_filename, subset_filename, rest_filename 30 | 31 | argc = len(argv) 32 | if argc < 3: 33 | exit_with_help() 34 | 35 | i = 1 36 | while i < len(argv): 37 | if argv[i][0] != "-": 38 | break 39 | if argv[i] == "-s": 40 | i = i + 1 41 | method = int(argv[i]) 42 | if method < 0 or method > 1: 43 | print("Unknown selection method {0}".format(method)) 44 | exit_with_help() 45 | i = i + 1 46 | 47 | dataset_filename = argv[i] 48 | n = int(argv[i+1]) 49 | if i+2 < argc: 50 | subset_filename = argv[i+2] 51 | if i+3 < argc: 52 | rest_filename = argv[i+3] 53 | 54 | def main(): 55 | class Label: 56 | def __init__(self, label, index, selected): 57 | self.label = label 58 | self.index = index 59 | self.selected = selected 60 | 61 | process_options() 62 | 63 | # get labels 64 | i = 0 65 | labels = [] 66 | f = open(dataset_filename, 'r') 67 | for line in f: 68 | labels.append(Label(float((line.split())[0]), i, 0)) 69 | i = i + 1 70 | f.close() 71 | l = i 72 | 73 | # determine where to output 74 | if subset_filename != "": 75 | file1 = open(subset_filename, 'w') 76 | else: 77 | file1 = stdout 78 | split = 0 79 | if rest_filename != "": 80 | split = 1 81 | file2 = open(rest_filename, 'w') 82 | 83 | # select the subset 84 | warning = 0 85 | if method == 0: # stratified 86 | labels.sort(key = lambda x: x.label) 87 | 88 | label_end = labels[l-1].label + 1 89 | labels.append(Label(label_end, l, 0)) 90 | 91 | begin = 0 92 | label = labels[begin].label 93 | for i in range(l+1): 94 | new_label = labels[i].label 95 | if new_label != label: 96 | nr_class = i - begin 97 | k = i*n//l - begin*n//l 98 | # at least one instance per class 99 | if k == 0: 100 | k = 1 101 | warning = warning + 1 102 | for j in range(nr_class): 103 | if randint(0, nr_class-j-1) < k: 104 | labels[begin+j].selected = 1 105 | k = k - 1 106 | begin = i 107 | label = new_label 108 | elif method == 1: # random 109 | k = n 110 | for i in range(l): 111 | if randint(0,l-i-1) < k: 112 | labels[i].selected = 1 113 | k = k - 1 114 | i = i + 1 115 | 116 | # output 117 | i = 0 118 | if method == 0: 119 | labels.sort(key = lambda x: int(x.index)) 120 | 121 | f = open(dataset_filename, 'r') 122 | for line in f: 123 | if labels[i].selected == 1: 124 | file1.write(line) 125 | else: 126 | if split == 1: 127 | file2.write(line) 128 | i = i + 1 129 | 130 | if warning > 0: 131 | stderr.write("""\ 132 | Warning: 133 | 1. You may have regression data. Please use -s 1. 134 | 2. Classification data unbalanced or too small. We select at least 1 per class. 135 | The subset thus contains {0} instances. 136 | """.format(n+warning)) 137 | 138 | # cleanup 139 | f.close() 140 | 141 | file1.close() 142 | 143 | if split == 1: 144 | file2.close() 145 | 146 | main() 147 | --------------------------------------------------------------------------------