ãã¼ã»ãããã³ã®åæã«å¦ç¿çã¯é¢ä¿ãªã件
(2012-06-20追è¨) ãã ãï¼éã¿ãã¯ãã«ã®åæå¤ã0ã®ã¨ãã ãã¨ãããã¨ã®è¨è¿°å¿ãï¼ããã«ã¤ãã¦ä»¥ä¸ã®è¨äºåç § (パーセプトロンの収束に学習率が関係ないのは初期値が0のときだけ)
前回の記事ã« @shuyo ãããã以ä¸ã®ã³ã¡ã³ããé ããï¼ååé¨åãå¼ç¨ããï¼
ãå¦ç¿çãé©å½ãªå¤ã«è¨å®ããã¨çµé¨çã«ã¯åæãéããªããã¨ããã¾ãããæ¬å½ã«ããã§ããããï¼
éã¿ã®åæå¤ã¯ï¼ã§ããããæ´æ°å¼ããηåãã解ãæ±ã¾ãã ãã§ãåææ§ã«å½±é¿ãããããã«æãã¾ããã
ã¯ãï¼ãã®ã¨ããã§ãï¼éã¿ãã¯ãã«ã¯å®æ°åãã¦ãåé¢è¶
å¹³é¢ã¯å¤åããªãï¼
ãã®ããï¼å¦ç¿çãããã¤ã«ãªããã¨ï¼@shuyo ããã®ãã£ãããããã«Î·åããéã¿ãã¯ãã«ãå¾ãããã ãã§ï¼åæã«å½±é¿ããªãï¼ã¨ããããã§ãçµé¨çã«ã¯é©å½ãªå¦ç¿çãè¨å®ããæ¹ãåæãéããã¨ããã®ã¯èª¤ãï¼ãè©«ã³ãã¦è¨æ£ãã¾ãï¼ãã㦠@shuyo ãããããã¨ããããã¾ãï¼
æ¤è¨¼
ã¨ããããã§æ¤è¨¼ããã¾ã§ããªãã®ã ããã©ï¼ä½é¨ãã¦ã¿ããã¨ã大åãªæ°ãããã®ã§ç·å½¢åé¢å¯è½ãªãã¼ã¿ã»ãããä½æãï¼ç°ãªãå¦ç¿çãè¨å®ãããã¼ã»ãããã³ã§åæã¾ã§ã®èª¤ãåæ°ã¨æçµçãªéã¿ãã¯ãã«ã表示ããããã°ã©ã ãæ¸ãã¦å®è¡ãã¦ã¿ãï¼(å®é¨ã«ç¨ããã³ã¼ãã¯æ«å°¾ã«è¨è¼)
çµæã¯ä»¥ä¸ã®ã¨ããï¼ä¸ããå¦ç¿çã100, 10, 1, 0.1, 0.01, 0.001ï¼
% python gen_data.py > toy.txt % python perceptron.py toy.txt Converged. Error count=56621 [3441900.0, -356.84360002073299, -19582.371400038977] Converged. Error count=56621 [344190.0, -35.68436000034535, -1958.2371400047396] Converged. Error count=56621 [34419.0, -3.5684360000869333, -195.82371400042496] Converged. Error count=56621 [3441.8999999979651, -0.356843600001298, -19.582371400016243] Converged. Error count=56621 [344.18999999983197, -0.035684359999769488, -1.9582371400026064] Converged. Error count=56621 [34.419000000010485, -0.0035684360000880627, -0.19582371400070708]
çµæãªã©ã¿ãªãã¦ããããã¨ããï¼å ¨ã¦åã誤ãåæ°ã§åæãã¦ãããã¨ããããï¼
ãã ãï¼å¦ç¿çã大ããã¨éã¿ãã¯ãã«ã®å¤§ãããæ¿ãããã¨ã«ãªã£ã¦ããï¼æ£ååã®è¦³ç¹ããããã¨ï¼ãã«ã ã¯å°ããæ¹ãããï¼ã¾ãï¼ç·å½¢åé¢å¯è½ã§ãªãã¨ãã«ã¯åããã¨ã«ãªã£ã¦ããéã¿ãã¯ãã«ãå¾ããã¨ãããã®ã§ï¼å®ç¨ä¸ã¯å¦ç¿çã¯å°ããã«è¨å®ãã¦ãããæ¹ãããã¨æãã®ã ããã©ï¼ããã¯æ£ååã«ã¤ãã¦ãã¡ãã¨é ã®æ´çãã¤ãã¦ããï¼ã¾ãå¥ã®æ©ä¼ã«æ¸ããã¨ã«ããï¼
ã³ã¡ã³ãããã¦æ°ãä»ããã¨ãã¯å¸å£ã®ä¸ã§æ´ããã»ã©æ¥ããããã¦æ»ã«ããã ã£ãããã©ï¼å¤§æ¥ãããåã«ç¥ããã¨ãã§ãã¦ããã£ãã¨æãï¼@shuyo ããã«æ¹ãã¦æè¬ï¼
å©ç¨ããã³ã¼ã
- gen_date.py
# -*- coding:utf-8 -*- import random import math def box_muller (): x = random.random() y = random.random() z1 = math.sqrt( - 2.0 * math.log(x) ) * math.cos( 2.0 * math.pi * y ) z2 = math.sqrt( - 2.0 * math.log(x) ) * math.sin( 2.0 * math.pi * y ) return (z1, z2) def gauss_rand_2d (mu1, sigma1, mu2, sigma2): pair = box_muller() return ( (sigma1 * pair[ 0 ]) + mu1, (sigma2 * pair[ 1 ]) + mu2 ) def gen_data (settings): pos_num = settings['pos_num'] pos_xmu = settings['pos_xmu'] pos_xsigma = settings['pos_xsigma'] pos_ymu = settings['pos_ymu'] pos_ysigma = settings['pos_ysigma'] neg_num = settings['neg_num'] neg_xmu = settings['neg_xmu'] neg_xsigma = settings['neg_xsigma'] neg_ymu = settings['neg_ymu'] neg_ysigma = settings['neg_ysigma'] for i in range(0, pos_num): xy_pair = gauss_rand_2d( pos_xmu, pos_xsigma, pos_ymu, pos_ysigma ) print "1 1:%f 2:%f" % (xy_pair[0], xy_pair[1]) for i in range(0, neg_num): xy_pair = gauss_rand_2d( neg_xmu, neg_xsigma, neg_ymu, neg_ysigma ) print "-1 1:%f 2:%f" % (xy_pair[0], xy_pair[1]) if __name__ == '__main__': settings = {'pos_num':50, 'pos_xmu':50, 'pos_xsigma':50, 'pos_ymu':50, 'pos_ysigma':50, 'neg_num':50, 'neg_xmu':300, 'neg_xsigma':50, 'neg_ymu':300, 'neg_ysigma':50} gen_data( settings )
- perceptron.py
# -*- coding: utf-8 -*- import sys import random class Instance: def __init__ (self, line): self.label = 0 self.fvec = [] self.parse_line( line ) def parse_line (self, line): pair_list = line.split(' ') label = int( pair_list.pop( 0 ) ) if label != -1 and label != 1: print "Label must be +1 or -1" sys.exit(1) self.label = label for pair in pair_list: if pair.find(':') < 0: continue fid, fval = pair.split(':') self.fvec.append( (int(fid), float(fval)) ) def get_max_fid (self): return self.fvec[ -1 ][ 0 ] class Instances: def __init__ (self, filename): self.ins_list = [] self.load_file( filename ) def load_file (self, filename): max_fid = -1 for line in open( filename, 'r' ): ins = Instance( line ) cur_max_fid = ins.get_max_fid() if cur_max_fid > max_fid: max_fid = cur_max_fid self.ins_list.append( ins ) self.max_fid = cur_max_fid def get_random_instance (self): idx = random.randint(0, len(self.ins_list) - 1) return self.ins_list[ idx ] class Perceptron: def __init__ (self, inss, iternum = 1000, eta = 0.01): self.instances = inss self.wvec_size = self.instances.max_fid + 1 # Consider bias term self.wvec = [ 0.0 ] * self.wvec_size self.iternum = iternum self.eta = eta def check_convergence (self, iternum, eta): # Initialize weight vector and eta value self.wvec = [ 0.0 ] * self.wvec_size self.eta = eta convergence_flag = True error_count = 0 for i in range(0, iternum): convergence_flag = True for ins in self.instances.ins_list: wx = self.inner_prod( ins ) if ins.label * wx <= 0: # Error self.update_weight( ins ) error_count += 1 convergence_flag = False if convergence_flag: break if convergence_flag: print "Converged." else: print "Failed to converge." print "Error count=%d" % (error_count) print self.wvec def train (self): for i in range(0, self.iternum): ins = self.instances.get_random_instance() wx = self.inner_prod( ins ) if ins.label * wx <= 0: self.update_weight( ins ) def predict (self, instance): return 1 if self.inner_prod( instance ) >= 0 else -1 def inner_prod (self, instance): fx = self.wvec[ 0 ] # bias term for pair in instance.fvec: fx += self.wvec[ pair[ 0 ] ] * pair[ 1 ] return fx def update_weight (self, instance): self.wvec[ 0 ] += self.eta * instance.label for pair in instance.fvec: self.wvec[ pair[ 0 ] ] += self.eta * instance.label * pair[ 1 ] if __name__ == '__main__': argv = sys.argv argc = len( sys.argv ) if (argc < 2): print "Input filename" quit() inss = Instances( argv[ 1 ] ) p = Perceptron( inss ) p.check_convergence( 100000, 100 ) p.check_convergence( 100000, 10 ) p.check_convergence( 100000, 1 ) p.check_convergence( 100000, 0.1 ) p.check_convergence( 100000, 0.01 ) p.check_convergence( 100000, 0.001 )