@@ -48,10 +48,13 @@ def __init__(self, loss, penalty='l2', alpha=0.0001,
48
48
eta0 = 0.0 , power_t = 0.5 , warm_start = False ):
49
49
self .loss = str (loss )
50
50
self .penalty = str (penalty ).lower ()
51
- self .epsilon = float (epsilon )
52
- self ._set_loss_function (self .loss )
53
- self ._set_penalty_type (self .penalty )
51
+ self .learning_rate = str (learning_rate )
54
52
53
+ # raises ValueError if not registered
54
+ self .get_penalty_type (self .penalty )
55
+ self .get_learning_rate_type (self .learning_rate )
56
+
57
+ self .epsilon = float (epsilon )
55
58
self .alpha = float (alpha )
56
59
if self .alpha < 0.0 :
57
60
raise ValueError ("alpha must be greater than zero" )
@@ -68,8 +71,6 @@ def __init__(self, loss, penalty='l2', alpha=0.0001,
68
71
self .seed = se
10000
ed
69
72
self .verbose = int (verbose )
70
73
71
- self .learning_rate = str (learning_rate )
72
- self ._set_learning_rate (self .learning_rate )
73
74
self .eta0 = float (eta0 )
74
75
self .power_t = float (power_t )
75
76
if self .learning_rate != "optimal" :
@@ -78,7 +79,10 @@ def __init__(self, loss, penalty='l2', alpha=0.0001,
78
79
self .coef_ = None
79
80
self .warm_start = warm_start
80
81
81
- self ._init_t ()
82
+ #self._init_t()
83
+ # iteration count for learning rate schedule
84
+ # must not be int (e.g. if ``learning_rate=='optimal'``)
85
+ self .t_ = None
82
86
83
87
@abstractmethod
84
88
def fit (self , X , y ):
@@ -88,25 +92,39 @@ def fit(self, X, y):
88
92
def predict (self , X ):
89
93
"""Predict using model."""
90
94
91
- def _init_t (self ):
95
+ def _init_t (self , loss_function ):
96
+ """Initialize iteration counter attr ``t_``.
97
+
98
+ If ``self.loss=='optimal'`` initialize ``t_`` such that ``eta`` at
99
+ first sample equals ``self.eta0``.
100
+ """
92
101
self .t_ = 1.0
93
102
if self .learning_rate == "optimal" :
94
103
typw = np .sqrt (1.0 / np .sqrt (self .alpha ))
95
104
# computing eta0, the initial learning rate
96
- eta0 = typw / max (1.0 , self . loss_function .dloss (- typw , 1.0 ))
97
- # initialize t such that eta at first example equals eta0
105
+ eta0 = typw / max (1.0 , loss_function .dloss (- typw , 1.0 ))
106
+ # initialize t such that eta at first sample equals eta0
98
107
self .t_ = 1.0 / (eta0 * self .alpha )
99
108
100
- def _set_learning_rate (self , learning_rate ):
109
+ def get_loss_function (self , loss ):
110
+ """Get concrete ``LossFunction`` object for str ``loss``. """
101
111
try :
102
- self .learning_rate_type = LEARNING_RATE_TYPES [learning_rate ]
112
+ loss_ = self .loss_functions [loss ]
113
+ loss_class , args = loss_ [0 ], loss_ [1 :]
114
+ return loss_class (* args )
115
+ except KeyError :
116
+ raise ValueError ("The loss %s is not supported. " % loss )
117
+
118
+ def get_learning_rate_type (self , learning_rate ):
119
+ try :
120
+ return LEARNING_RATE_TYPES [learning_rate ]
103
121
except KeyError :
104
122
raise ValueError ("learning rate %s"
105
123
"is not supported. " % learning_rate )
106
124
107
- def _set_penalty_type (self , penalty ):
125
+ def get_penalty_type (self , penalty ):
108
126
try :
109
- self . penalty_type = PENALTY_TYPES [penalty ]
127
+ return PENALTY_TYPES [penalty ]
110
128
except KeyError :
111
129
raise ValueError ("Penalty %s is not supported. " % penalty )
112
130
@@ -338,27 +356,23 @@ def __init__(self, loss="hinge", penalty='l2', alpha=0.0001,
338
356
self .classes_ = None
339
357
self .n_jobs = int (n_jobs )
340
358
359
+ self .loss_functions = {
360
+ "hinge" : (Hinge , 1.0 ),
361
+ "perceptron" : (Hinge , 0.0 ),
362
+ "log" : (Log , ),
363
+ "modified_huber" : (ModifiedHuber , ),
364
+ "squared_loss" : (SquaredLoss , ),
365
+ "huber" : (Huber , self .epsilon ),
366
+ "epsilon_insensitive" : (EpsilonInsensitive , self .epsilon ),
367
+ }
368
+ if loss not in self .loss_functions :
369
+ raise ValueError ("The loss %s is not supported. " % loss )
370
+
341
371
@property
342
372
@deprecated ("to be removed in v0.13; use ``classes_`` instead." )
343
373
def classes (self ):
344
374
return self .classes_
345
375
346
- def _set_loss_function (self , loss ):
347
- """Set concrete LossFunction."""
348
- loss_functions = {
349
- "hinge" : Hinge (1.0 ),
350
- "perceptron" : Hinge (0.0 ),
351
- "log" : Log (),
352
- "modified_huber" : ModifiedHuber (),
353
- "squared_loss" : SquaredLoss (),
354
- "huber" : Huber (self .epsilon ),
355
- "epsilon_insensitive" : EpsilonInsensitive (self .epsilon ),
356
- }
357
- try :
358
- self .loss_function = loss_functions [loss ]
359
- except KeyError :
360
- raise ValueError ("The loss %s is not supported. " % loss )
361
-
362
376
def _set_class_weight (self , class_weight , classes , y ):
363
377
"""Estimate class weights for unbalanced datasets."""
364
378
if class_weight is None or len (class_weight ) == 0 :
@@ -513,7 +527,8 @@ def fit(self, X, y, coef_init=None, intercept_init=None,
513
527
self .intercept_ = None
514
528
515
529
# Need to re-initialize in case of multiple call to fit.
516
- self ._init_t ()
530
+ #self._init_t()
531
+ self .t_ = None
517
532
518
533
self ._partial_fit (X , y , self .n_iter , classes ,
519
534
sample_weight , coef_init , intercept_init )
@@ -678,12 +693,19 @@ def fit_binary(est, i, X, y, n_iter, pos_weight, neg_weight,
678
693
assert y_i .shape [0 ] == y .shape [0 ] == sample_weight .shape [0 ]
679
694
dataset , intercept_decay = _make_dataset (X , y_i , sample_weight )
680
695
681
- return plain_sgd (coef , intercept , est .loss_function ,
682
- est .penalty_type , est .alpha , est .rho ,
696
+ loss_function = est .get_loss_function (est .loss )
697
+ penalty_type = est .get_penalty_type (est .penalty )
698
+ learning_rate_type = est .get_learning_rate_type (est .learning_rate )
699
+
700
+ if est .t_ is None :
701
+ est ._init_t (loss_function )
702
+
703
+ return plain_sgd (coef , intercept , loss_function ,
704
+ penalty_type , est .alpha , est .rho ,
683
705
dataset , n_iter , est .fit_intercept ,
684
706
est .verbose , est .shuffle , est .seed ,
685
707
pos_weight , neg_weight ,
686
- est . learning_rate_type , est .eta0 ,
708
+ learning_rate_type , est .eta0 ,
687
709
est .power_t , est .t_ , intercept_decay )
688
710
689
711
@@ -813,16 +835,12 @@ def __init__(self, loss="squared_loss", penalty="l2", alpha=0.0001,
813
835
eta0 = eta0 , power_t = power_t ,
814
836
warm_start = False )
815
837
816
- def _set_loss_function (self , loss ):
817
- """Get concrete LossFunction"""
818
- loss_functions = {
819
- "squared_loss" : SquaredLoss (),
820
- "huber" : Huber (self .epsilon ),
821
- "epsilon_insensitive" : EpsilonInsensitive (self .epsilon ),
838
+ self .loss_functions = {
839
+ "squared_loss" : (SquaredLoss , ),
840
+ "huber" : (Huber , self .epsilon ),
841
+ "epsilon_insensitive" : (EpsilonInsensitive , self .epsilon )
822
842
}
823
- try :
824
- self .loss_function = loss_functions [loss ]
825
- except KeyError :
843
+ if loss not in self .loss_functions :
826
844
raise ValueError ("The loss %s is not supported. " % loss )
827
845
828
846
def _partial_fit (self , X , y , n_iter , sample_weight = None ,
@@ -903,7 +921,8 @@ def fit(self, X, y, coef_init=None, intercept_init=None,
903
921
self .intercept_ = None
904
922
905
923
# Need to re-initialize in case of multiple call to fit.
906
- self ._init_t ()
924
+ #self._init_t()
925
+ self .t_ = None
907
926
908
927
return self ._partial_fit (X , y , self .n_iter , sample_weight ,
909
928
coef_init , intercept_init )
@@ -941,10 +960,17 @@ def predict(self, X):
941
960
def _fit_regressor (self , X , y , sample_weight , n_iter ):
942
961
dataset , intercept_decay = _make_dataset (X , y , sample_weight )
943
962
963
+ loss_function = self .get_loss_function (self .loss )
964
+ penalty_type = self .get_penalty_type (self .penalty )
965
+ learning_rate_type = self .get_learning_rate_type (self .learning_rate )
966
+
967
+ if self .t_ is None :
968
+ self ._init_t (loss_function )
969
+
944
970
self .coef_ , intercept = plain_sgd (self .coef_ ,
945
971
self .intercept_ [0 ],
946
- self . loss_function ,
947
- self . penalty_type ,
972
+ loss_function ,
973
+ penalty_type ,
948
974
self .alpha , self .rho ,
949
975
dataset ,
950
976
n_iter ,
@@ -953,7 +979,7 @@ def _fit_regressor(self, X, y, sample_weight, n_iter):
953
979
int (self .shuffle ),
954
980
self .seed ,
955
981
1.0 , 1.0 ,
956
- self . learning_rate_type ,
982
+ learning_rate_type ,
957
983
self .eta0 , self .power_t , self .<
3F4B
span class=pl-c1>t_,
958
984
intercept_decay )
959
985
0 commit comments