-
Notifications
You must be signed in to change notification settings - Fork 12
/
Copy pathrffridge.py
67 lines (55 loc) · 2.23 KB
/
rffridge.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
"""============================================================================
Kernel ridge regression using random Fourier features. Based on "Random
Features for Large-Scale Kernel Machines" by Rahimi and Recht (2007).
For more, see the accompanying blog post:
http://gregorygundersen.com/blog/2019/12/23/random-fourier-features/
============================================================================"""
import numpy as np
from sklearn.exceptions import NotFittedError
from sklearn.linear_model import Ridge
# -----------------------------------------------------------------------------
class RFFRidgeRegression:
def __init__(self, rff_dim=1, alpha=1.0, sigma=1.0):
"""Kernel ridge regression using random Fourier features.
rff_dim : Dimension of random feature.
alpha : Regularization strength. Should be a positive float.
"""
self.fitted = False
self.rff_dim = rff_dim
self.sigma = sigma
self.lm = Ridge(alpha=alpha)
self.b_ = None
self.W_ = None
def fit(self, X, y):
"""Fit model with training data X and target y.
"""
Z, W, b = self._get_rffs(X, return_vars=True)
self.lm.fit(Z.T, y)
self.b_ = b
self.W_ = W
self.fitted = True
return self
def predict(self, X):
"""Predict using fitted model and testing data X.
"""
if not self.fitted:
msg = "Call 'fit' with appropriate arguments first."
raise NotFittedError(msg)
Z = self._get_rffs(X, return_vars=False)
return self.lm.predict(Z.T)
def _get_rffs(self, X, return_vars):
"""Return random Fourier features based on data X, as well as random
variables W and b.
"""
N, D = X.shape
if self.W_ is not None:
W, b = self.W_, self.b_
else:
W = np.random.normal(loc=0, scale=1, size=(self.rff_dim, D))
b = np.random.uniform(0, 2*np.pi, size=self.rff_dim)
B = np.repeat(b[:, np.newaxis], N, axis=1)
norm = 1./ np.sqrt(self.rff_dim)
Z = norm * np.sqrt(2) * np.cos(self.sigma * W @ X.T + B)
if return_vars:
return Z, W, b
return Z