5
5
import numpy as np
6
6
from sklearn .preprocessing import LabelBinarizer
7
7
from scipy .sparse .linalg import lsqr
8
+ from sklearn .gaussian_process import GaussianProcessRegressor , GaussianProcessClassifier
9
+ from sklearn .linear_model import LinearRegression
8
10
import tensorflow as tf
9
11
from tensorflow .keras import Sequential
10
12
from tensorflow .keras .layers import Flatten , Dense
@@ -186,7 +188,8 @@ def fit(self, Xt=None, yt=None, **fit_params):
186
188
187
189
if yt_ndim_below_one_ :
188
190
self .coef_ = self .coef_ .reshape (- 1 )
189
- self .intercept_ = self .intercept_ [0 ]
191
+ if self .estimator_ .fit_intercept :
192
+ self .intercept_ = self .intercept_ [0 ]
190
193
191
194
self .estimator_ .coef_ = self .coef_
192
195
if self .estimator_ .fit_intercept :
@@ -267,7 +270,11 @@ def fit(self, Xt=None, yt=None, **fit_params):
267
270
Xt , yt = check_arrays (Xt , yt )
268
271
269
272
_label_binarizer = LabelBinarizer (pos_label = 1 , neg_label = - 1 )
270
- yt = _label_binarizer .fit_transform (yt )
273
+ _label_binarizer .fit (self .estimator .classes_ )
274
+ yt = _label_binarizer .transform (yt )
275
+
276
+ print (yt .shape )
277
+
271
278
return super ().fit (Xt , yt , ** fit_params )
272
279
273
280
@@ -467,4 +474,177 @@ def predict_disc(self, X):
467
474
"""
468
475
Not used.
469
476
"""
470
- pass
477
+ pass
478
+
479
+
480
+ @make_insert_doc (supervised = True )
481
+ class RegularTransferGP (BaseAdaptEstimator ):
482
+ """
483
+ Regular Transfer with Gaussian Process
484
+
485
+ RegularTransferGP is a parameter-based domain adaptation method.
486
+
487
+ The method is based on the assumption that a good target estimator
488
+ can be obtained by adapting the parameters of a pre-trained source
489
+ estimator using a few labeled target data.
490
+
491
+ The approach consist in fitting the `alpha` coeficients of a
492
+ Gaussian Process estimator on target data according to an
493
+ objective function regularized by the euclidean distance between
494
+ the source and target `alpha`:
495
+
496
+ .. math::
497
+
498
+ \\ alpha_T = \\ underset{\\ alpha \in \\ mathbb{R}^n}{\\ text{argmin}}
499
+ \\ , ||K_{TS} \\ alpha - y_T||^2 + \\ lambda ||\\ alpha - \\ alpha_S||^2
500
+
501
+ Where:
502
+
503
+ - :math:`\\ alpha_T` are the target model coeficients.
504
+ - :math:`\\ alpha_S = \\ underset{\\ alpha \\ in \\ mathbb{R}^n}{\\ text{argmin}}
505
+ \\ , ||K_{SS} \\ alpha - y_S||^2` are the source model coeficients.
506
+ - :math:`y_S, y_T` are respectively the source and
507
+ the target labels.
508
+ - :math:`K_{SS}` is the pariwise kernel distance matrix between source
509
+ input data.
510
+ - :math:`K_{TS}` is the pariwise kernel distance matrix between target
511
+ and source input data.
512
+ - :math:`n` is the number of source data in :math:`X_S`
513
+ - :math:`\\ lambda` is a trade-off parameter. The larger :math:`\\ lambda`
514
+ the closer the target model will be from the source model.
515
+
516
+ The ``estimator`` given to ``RegularTransferGP`` should be from classes
517
+ ``sklearn.gaussian_process.GaussianProcessRegressor`` or
518
+ ``sklearn.gaussian_process.GaussianProcessClassifier``
519
+
520
+ Parameters
521
+ ----------
522
+ lambda_ : float (default=1.0)
523
+ Trade-Off parameter. For large ``lambda_``, the
524
+ target model will be similar to the source model.
525
+
526
+ Attributes
527
+ ----------
528
+ estimator_ : Same class as estimator
529
+ Fitted Estimator.
530
+
531
+ Examples
532
+ --------
533
+ >>> from sklearn.gaussian_process import GaussianProcessRegressor
534
+ >>> from sklearn.gaussian_process.kernels import Matern, WhiteKernel
535
+ >>> from adapt.utils import make_regression_da
536
+ >>> from adapt.parameter_based import RegularTransferGP
537
+ >>> Xs, ys, Xt, yt = make_regression_da()
538
+ >>> kernel = Matern() + WhiteKernel()
539
+ >>> src_model = GaussianProcessRegressor(kernel)
540
+ >>> src_model.fit(Xs, ys)
541
+ >>> print(src_model.score(Xt, yt))
542
+ -2.3409379221035382
543
+ >>> tgt_model = RegularTransferGP(src_model, lambda_=1.)
544
+ >>> tgt_model.fit(Xt[:3], yt[:3])
545
+ >>> tgt_model.score(Xt, yt)
546
+ -0.21947435769240653
547
+
548
+ See also
549
+ --------
550
+ RegularTransferLR, RegularTransferNN
551
+
552
+ References
553
+ ----------
554
+ .. [1] `[1] <https://www.microsoft.com/en-us/research/wp-\
555
+ content/uploads/2004/07/2004-chelba-emnlp.pdf>`_ C. Chelba and \
556
+ A. Acero. "Adaptation of maximum entropy classifier: Little data \
557
+ can help a lot". In EMNLP, 2004.
558
+ """
559
+
560
+ def __init__ (self ,
561
+ estimator = None ,
562
+ Xt = None ,
563
+ yt = None ,
564
+ lambda_ = 1. ,
565
+ copy = True ,
566
+ verbose = 1 ,
567
+ random_state = None ,
568
+ ** params ):
569
+
570
+ if not hasattr (estimator , "kernel_" ):
571
+ raise ValueError ("`estimator` argument has no ``kernel_`` attribute, "
572
+ "please call `fit` on `estimator` or use "
573
+ "another estimator as `GaussianProcessRegressor` or "
574
+ "`GaussianProcessClassifier`." )
575
+
576
+ estimator = check_fitted_estimator (estimator )
577
+
578
+ names = self ._get_param_names ()
579
+ kwargs = {k : v for k , v in locals ().items () if k in names }
580
+ kwargs .update (params )
581
+ super ().__init__ (** kwargs )
582
+
583
+
584
+ def fit (self , Xt = None , yt = None , ** fit_params ):
585
+ """
586
+ Fit RegularTransferGP.
587
+
588
+ Parameters
589
+ ----------
590
+ Xt : numpy array (default=None)
591
+ Target input data.
592
+
593
+ yt : numpy array (default=None)
594
+ Target output data.
595
+
596
+ fit_params : key, value arguments
597
+ Not used. Here for sklearn compatibility.
598
+
599
+ Returns
600
+ -------
601
+ self : returns an instance of self
602
+ """
603
+ Xt , yt = self ._get_target_data (Xt , yt )
604
+ Xt , yt = check_arrays (Xt , yt )
605
+ set_random_seed (self .random_state )
606
+
607
+ self .estimator_ = check_estimator (self .estimator ,
608
+ copy = self .copy ,
609
+ force_copy = True )
610
+
611
+ if isinstance (self .estimator , GaussianProcessRegressor ):
612
+ src_linear_model = LinearRegression (fit_intercept = False )
613
+ src_linear_model .coef_ = self .estimator_ .alpha_ .transpose ()
614
+
615
+ Kt = self .estimator_ .kernel_ (Xt , self .estimator_ .X_train_ )
616
+ tgt_linear_model = RegularTransferLR (src_linear_model , lambda_ = self .lambda_ )
617
+
618
+ tgt_linear_model .fit (Kt , yt )
619
+
620
+ self .estimator_ .alpha_ = np .copy (tgt_linear_model .coef_ ).transpose ()
621
+
622
+ elif isinstance (self .estimator , GaussianProcessClassifier ):
623
+
624
+ if hasattr (self .estimator_ .base_estimator_ , "estimators_" ):
625
+ for i in range (len (self .estimator_ .base_estimator_ .estimators_ )):
626
+ c = self .estimator_ .classes_ [i ]
627
+ if sum (yt == c ) > 0 :
628
+ yt_c = np .zeros (yt .shape [0 ])
629
+ yt_c [yt == c ] = 1
630
+ self .estimator_ .base_estimator_ .estimators_ [i ] = self ._fit_one_vs_one_classifier (
631
+ self .estimator_ .base_estimator_ .estimators_ [i ], Xt , yt_c )
632
+
633
+ else :
634
+ self .estimator_ .base_estimator_ = self ._fit_one_vs_one_classifier (
635
+ self .estimator_ .base_estimator_ , Xt , yt )
636
+ return self
637
+
638
+
639
+ def _fit_one_vs_one_classifier (self , estimator , Xt , yt ):
640
+ src_linear_model = LinearRegression (fit_intercept = False )
641
+ src_linear_model .coef_ = (estimator .y_train_ - estimator .pi_ )
642
+ src_linear_model .classes_ = estimator .classes_
643
+ Kt = estimator .kernel_ (Xt , estimator .X_train_ )
644
+
645
+ tgt_linear_model = RegularTransferLC (src_linear_model , lambda_ = self .lambda_ )
646
+
647
+ tgt_linear_model .fit (Kt , yt )
648
+
649
+ estimator .pi_ = (estimator .y_train_ - np .copy (tgt_linear_model .coef_ ).ravel ())
650
+ return estimator
0 commit comments