1
- # Author: Peter Prettenhofer <peter.prettenhofer@gmail.com>
2
- # Mathieu Blondel (partial_fit support)
3
- # Rob Zinkov (passive-aggressive)
4
- # Lars Buitinck
5
- #
6
- # License: BSD 3 clause
1
+ {{py:
7
2
3
+ """
4
+ Template file to easily generate fused types consistent code using Tempita
5
+ (https://github.com/cython/cython/blob/master/Cython/Tempita/_tempita.py).
8
6
7
+ Generated file: _sgd_fast.pyx
8
+
9
+ Each relevant function is duplicated for the dtypes float and double.
10
+ The keywords between double braces are substituted in setup.py.
11
+
12
+ Authors: Peter Prettenhofer <peter.prettenhofer@gmail.com>
13
+ Mathieu Blondel (partial_fit support)
14
+ Rob Zinkov (passive-aggressive)
15
+ Lars Buitinck
16
+
17
+ License: BSD 3 clause
18
+ """
19
+
20
+ # The dtypes are defined as follows (name_suffix, c_type, np_type)
21
+ dtypes = [
22
+ ("64", "double", "np.float64"),
23
+ ("32", "float", "np.float32"),
24
+ ]
25
+
26
+ }}
27
+
28
+ #------------------------------------------------------------------------------
29
+
30
+ """
31
+ SGD implementation
32
+ WARNING: Do not edit .pyx file directly, it is generated from .pyx.tp
33
+ """
34
+
35
+ from cython cimport floating
9
36
import numpy as np
10
37
from time import time
11
38
12
39
from libc.math cimport exp, log, pow, fabs
13
40
cimport numpy as cnp
14
41
from numpy.math cimport INFINITY
15
42
cdef extern from "_sgd_fast_helpers.h":
16
- bint skl_isfinite(double ) nogil
43
+ bint skl_isfinite32(float) nogil
44
+ bint skl_isfinite64(double) nogil
17
45
18
- from ..utils._weight_vector cimport WeightVector64 as WeightVector
19
- from ..utils._seq_dataset cimport SequentialDataset64 as SequentialDataset
46
+ from ..utils._weight_vector cimport WeightVector32, WeightVector64
47
+ from ..utils._seq_dataset cimport SequentialDataset32, SequentialDataset64
20
48
21
49
cnp.import_array()
22
50
@@ -372,37 +400,48 @@ cdef class SquaredEpsilonInsensitive(Regression):
372
400
def __reduce__(self):
373
401
return SquaredEpsilonInsensitive, (self.epsilon,)
374
402
375
-
376
- def _plain_sgd (const double[::1] weights ,
377
- double intercept ,
378
- const double[::1] average_weights ,
379
- double average_intercept ,
380
- LossFunction loss ,
381
- int penalty_type ,
382
- double alpha , double C ,
383
- double l1_ratio ,
384
- SequentialDataset dataset ,
385
- const unsigned char[::1] validation_mask ,
386
- bint early_stopping , validation_score_cb ,
387
- int n_iter_no_change ,
388
- unsigned int max_iter , double tol , int fit_intercept ,
389
- int verbose , bint shuffle , cnp.uint32_t seed ,
390
- double weight_pos , double weight_neg ,
F438
391
- int learning_rate , double eta0 ,
392
- double power_t ,
393
- bint one_class ,
394
- double t = 1.0 ,
395
- double intercept_decay = 1.0 ,
396
- int average = 0 ):
403
+ {{for name_suffix, c_type, np_type in dtypes}}
404
+
405
+ def _plain_sgd{{name_suffix}}(
406
+ const {{c_type}}[::1] weights,
407
+ double intercept,
408
+ const {{c_type}}[::1] average_weights,
409
+ double average_intercept,
410
+ LossFunction loss,
411
+ int penalty_type,
412
+ double alpha,
413
+ double C,
414
+ double l1_ratio,
415
+ SequentialDataset{{name_suffix}} dataset,
416
+ const unsigned char[::1] validation_mask,
417
+ bint early_stopping,
418
+ validation_score_cb,
419
+ int n_iter_no_change,
420
+ unsigned int max_iter,
421
+ double tol,
422
+ int fit_intercept,
423
+ int verbose,
424
+ bint shuffle,
425
+ cnp.uint32_t seed,
426
+ double weight_pos,
427
+ double weight_neg,
428
+ int learning_rate,
429
+ double eta0,
430
+ double power_t,
431
+ bint one_class,
432
+ double t=1.0,
433
+ double intercept_decay=1.0,
434
+ int average=0,
435
+ ):
397
436
"""SGD for generic loss functions and penalties with optional averaging
398
437
399
438
Parameters
400
439
----------
401
- weights : ndarray[double , ndim=1]
440
+ weights : ndarray[{{c_type}} , ndim=1]
402
441
The allocated vector of weights.
403
442
intercept : double
404
443
The initial intercept.
405
- average_weights : ndarray[double , ndim=1]
444
+ average_weights : ndarray[{{c_type}} , ndim=1]
406
445
The average weights as computed for ASGD. Should be None if average
407
446
is 0.
408
447
average_intercept : double
@@ -489,8 +528,8 @@ def _plain_sgd(const double[::1] weights,
489
528
cdef Py_ssize_t n_samples = dataset.n_samples
490
529
cdef Py_ssize_t n_features = weights.shape[0]
491
530
492
- cdef WeightVector w = WeightVector(weights, average_weights)
493
- cdef double * x_data_ptr = NULL
531
+ cdef WeightVector{{name_suffix}} w = WeightVector{{name_suffix}} (weights, average_weights)
532
+ cdef {{c_type}} *x_data_ptr = NULL
494
533
cdef int *x_ind_ptr = NULL
495
534
496
535
# helper variables
@@ -505,9 +544,9 @@ def _plain_sgd(const double[::1] weights,
505
544
cdef double score = 0.0
506
545
cdef double best_loss = INFINITY
507
546
cdef double best_score = -INFINITY
508
- cdef double y = 0.0
509
- cdef double sample_weight
510
- cdef double class_weight = 1.0
547
+ cdef {{c_type}} y = 0.0
548
+ cdef {{c_type}} sample_weight
549
+ cdef {{c_type}} class_weight = 1.0
511
550
cdef unsigned int count = 0
512
551
cdef unsigned int train_count = n_samples - np.sum(validation_mask)
513
552
cdef unsigned int epoch = 0
@@ -520,10 +559,10 @@ def _plain_sgd(const double[::1] weights,
520
559
cdef long long sample_index
521
560
522
561
# q vector is only used for L1 regularization
523
- cdef double [::1 ] q = None
524
- cdef double * q_data_ptr = NULL
562
+ cdef {{c_type}} [::1] q = None
563
+ cdef {{c_type}} * q_data_ptr = NULL
525
564
if penalty_type == L1 or penalty_type == ELASTICNET:
526
- q = np.zeros((n_features,), dtype = np.float64 , order = " c" )
565
+ q = np.zeros((n_features,), dtype={{np_type}} , order="c")
527
566
q_data_ptr = &q[0]
528
567
cdef double u = 0.0
529
568
@@ -627,7 +666,7 @@ def _plain_sgd(const double[::1] weights,
627
666
628
667
if penalty_type == L1 or penalty_type == ELASTICNET:
629
668
u += (l1_ratio * eta * alpha)
630
- l1penalty(w, q_data_ptr, x_ind_ptr, xnnz, u)
669
+ l1penalty{{name_suffix}} (w, q_data_ptr, x_ind_ptr, xnnz, u)
631
670
632
671
t += 1
633
672
count += 1
@@ -694,15 +733,28 @@ def _plain_sgd(const double[::1] weights,
694
733
epoch + 1
695
734
)
696
735
736
+ {{endfor}}
737
+
738
+
739
+ cdef inline bint skl_isfinite(floating w) noexcept nogil:
740
+ if floating is float:
741
+ return skl_isfinite32(w)
742
+ else:
743
+ return skl_isfinite64(w)
697
744
698
- cdef bint any_nonfinite(const double * w, int n) noexcept nogil:
745
+
746
+ cdef inline bint any_nonfinite(const floating *w, int n) noexcept nogil:
699
747
for i in range(n):
700
748
if not skl_isfinite(w[i]):
701
749
return True
702
750
return 0
703
751
704
752
705
- cdef double sqnorm(double * x_data_ptr, int * x_ind_ptr, int xnnz) noexcept nogil:
753
+ cdef inline double sqnorm(
754
+ floating * x_data_ptr,
755
+ int * x_ind_ptr,
756
+ int xnnz,
757
+ ) noexcept nogil:
706
758
cdef double x_norm = 0.0
707
759
cdef int j
708
760
cdef double z
@@ -712,8 +764,15 @@ cdef double sqnorm(double * x_data_ptr, int * x_ind_ptr, int xnnz) noexcept nogi
712
764
return x_norm
713
765
714
766
715
- cdef void l1penalty(WeightVector w, double * q_data_ptr,
716
- int * x_ind_ptr, int xnnz, double u) noexcept nogil:
767
+ {{for name_suffix, c_type, np_type in dtypes}}
768
+
769
+ cdef void l1penalty{{name_suffix}}(
770
+ WeightVector{{name_suffix}} w,
771
+ {{c_type}} * q_data_ptr,
772
+ int *x_ind_ptr,
773
+ int xnnz,
774
+ double u,
775
+ ) noexcept nogil:
717
776
"""Apply the L1 penalty to each updated feature
718
777
719
778
This implements the truncated gradient approach by
@@ -723,7 +782,7 @@ cdef void l1penalty(WeightVector w, double * q_data_ptr,
723
782
cdef int j = 0
724
783
cdef int idx = 0
725
784
cdef double wscale = w.wscale
726
- cdef double * w_data_ptr = w.w_data_ptr
785
+ cdef {{c_type}} *w_data_ptr = w.w_data_ptr
727
786
for j in range(xnnz):
728
787
idx = x_ind_ptr[j]
729
788
z = w_data_ptr[idx]
@@ -736,3 +795,5 @@ cdef void l1penalty(WeightVector w, double * q_data_ptr,
736
795
0.0, w_data_ptr[idx] + ((u - q_data_ptr[idx]) / wscale))
737
796
738
797
q_data_ptr[idx] += wscale * (w_data_ptr[idx] - z)
798
+
799
+ {{endfor}}
0 commit comments