def train(self, X, f, weights=None): """Train the least-squares-fit polynomial approximation. Parameters ---------- X : ndarray an ndarray of training points for the polynomial approximation. The shape is M-by-m, where m is the number of dimensions. f : ndarray an ndarray of function values used to train the polynomial approximation. The shape of `f` is M-by-1. weights : ndarray, optional an ndarray of weights for the least-squares. (default is None, which means uniform weights) Notes ----- This method sets all the attributes of the class for use in the `predict` method. """ X, f, M, m = process_inputs_outputs(X, f) # check that there are enough points to train the polynomial if M < comb(self.N + m, m): raise Exception( 'Not enough points to fit response surface of order {:d}'. format(self.N)) B, indices = polynomial_bases(X, self.N) p = B.shape[1] if weights is not None: B, f = weights * B, weights * f poly_weights = np.linalg.lstsq(B, f)[0] Rsqr = 1.0 - (np.linalg.norm(np.dot(B, poly_weights) - f)**2 / (M * np.var(f))) # store data self.X, self.f = X, f self.poly_weights = poly_weights.reshape((p, 1)) self.Rsqr = Rsqr # organize linear and quadratic coefficients self.g = poly_weights[1:m + 1].copy().reshape((m, 1)) if self.N > 1: H = np.zeros((m, m)) for i in range(m + 1, int(m + 1 + comb(m + 1, 2))): ind = indices[i, :] loc = np.nonzero(ind != 0)[0] if loc.size == 1: H[loc, loc] = 2.0 * poly_weights[i] elif loc.size == 2: H[loc[0], loc[1]] = poly_weights[i] H[loc[1], loc[0]] = poly_weights[i] else: raise Exception('Error creating quadratic coefficients.') self.H = H
def train(self, X, f, weights=None): """Train the least-squares-fit polynomial approximation. Parameters ---------- X : ndarray an ndarray of training points for the polynomial approximation. The shape is M-by-m, where m is the number of dimensions. f : ndarray an ndarray of function values used to train the polynomial approximation. The shape of `f` is M-by-1. weights : ndarray, optional an ndarray of weights for the least-squares. (default is None, which means uniform weights) Notes ----- This method sets all the attributes of the class for use in the `predict` method. """ X, f, M, m = process_inputs_outputs(X, f) # check that there are enough points to train the polynomial if M < comb(self.N + m, m): raise Exception('Not enough points to fit response surface of order {:d}'.format(self.N)) B, indices = polynomial_bases(X, self.N) p = B.shape[1] if weights is not None: B, f = weights*B, weights*f poly_weights = np.linalg.lstsq(B, f)[0] Rsqr = 1.0 - ( np.linalg.norm(np.dot(B, poly_weights) - f)**2 / (M*np.var(f)) ) # store data self.X, self.f = X, f self.poly_weights = poly_weights.reshape((p,1)) self.Rsqr = Rsqr # organize linear and quadratic coefficients self.g = poly_weights[1:m+1].copy().reshape((m,1)) if self.N > 1: H = np.zeros((m, m)) for i in range(m+1, int(m+1+comb(m+1,2))): ind = indices[i,:] loc = np.nonzero(ind!=0)[0] if loc.size==1: H[loc,loc] = 2.0*poly_weights[i] elif loc.size==2: H[loc[0],loc[1]] = poly_weights[i] H[loc[1],loc[0]] = poly_weights[i] else: raise Exception('Error creating quadratic coefficients.') self.H = H
def train(self, X, f, weights=None): """ Train the least-squares-fit polynomial approximation. :param ndarray X: An ndarray of training points for the polynomial approximation. The shape is M-by-m, where m is the number of dimensions. :param ndarray f: An ndarray of function values used to train the polynomial approximation. The shape of `f` is M-by-1. :param ndarray f: An ndarray of weights for the least-squares. **Notes** This method sets all the attributes of the class for use in the `predict` method. """ X, f, M, m = process_inputs_outputs(X, f) # check that there are enough points to train the polynomial if M < comb(self.N + m, m): raise Exception('Not enough points to fit response surface of order {:d}'.format(self.N)) logging.getLogger(__name__).debug('Training a degree {:d} polynomial in {:d} dims with {:d} points.'.format(self.N, m, M)) B, indices = polynomial_bases(X, self.N) p = B.shape[1] if weights is not None: B, f = weights*B, weights*f Q, R = np.linalg.qr(B) Qf = np.dot(Q.T, f) poly_weights = np.linalg.solve(R, Qf) Rsqr = 1.0 - ( np.linalg.norm(np.dot(R, poly_weights) - Qf)**2 / np.var(f) ) # store data self.X, self.f = X, f self.poly_weights = poly_weights.reshape((p,1)) self.Rsqr = Rsqr # organize linear and quadratic coefficients self.g = poly_weights[1:m+1].copy().reshape((m,1)) if self.N > 1: H = np.zeros((m, m)) for i in range(m+1, indices.shape[0]): ind = indices[i,:] loc = np.nonzero(ind!=0)[0] if loc.size==1: H[loc,loc] = 2.0*poly_weights[i] elif loc.size==2: H[loc[0],loc[1]] = poly_weights[i] H[loc[1],loc[0]] = poly_weights[i] else: raise Exception('Error creating quadratic coefficients.') self.H = H
def train(self, X, f, v=None, e=None): """ Train the radial basis approximation. :param ndarray X: An ndarray of training points for the polynomial approximation. The shape is M-by-m, where m is the number of dimensions. :parma ndarray f: An ndarray of function values used to train the polynomial approximation. The shape of `f` is M-by-1. :param ndarray v: Contains the regularization parameters that model error in the function values. :param ndarray e: An ndarray containing the eigenvalues from the active subspace analysis. If present, the radial basis uses it to determine the appropriate anisotropy in the length scales. **Notes** The approximation uses an multivariate, squared exponential radial basis. If `e` is not None, then the radial basis is anisotropic with length scales determined by `e`. Otherwise, the basis is isotropic. The length scale parameters (i.e., the rbf shape parameters) are determined with a maximum likelihood heuristic inspired by techniques for fitting a Gaussian process model. The approximation also includes a monomial basis with monomials of total degree up to order `N`. These are fit with weighted least-squares, where the weight matrix is the inverse of the matrix of radial basis functions evaluated at the training points. This method sets all the attributes of the class for use in the `predict` method. """ X, f, M, m = process_inputs_outputs(X, f) # check that there are enough points to train the polynomial if M < comb(self.N + m, m): raise Exception('Not enough points to fit response surface of order {:d}'.format(self.N)) logging.getLogger(__name__).debug('Training an RBF surface with degree {:d} polynomial in {:d} dims with {:d} points.'.format(self.N, m, M)) # use maximum likelihood to tune parameters log10g = fminbound(rbf_objective, -10.0, 1.0, args=(X, f, v, self.N, e, )) g = 10**(log10g) if e is None: ell = g*np.ones((m,1)) if v is None: v = 1e-6*np.ones(f.shape) else: ell = g*np.sum(e)/e[:m] if v is None: v = g*np.sum(e[m:])*np.ones(f.shape) # covariance matrix of observations K = exponential_squared(X, X, 1.0, ell) K += np.diag(v.reshape((M,))) B = polynomial_bases(X, self.N)[0] p = B.shape[1] C = np.hstack(( np.vstack(( K, B.T )), np.vstack(( B, np.zeros((p, p)) )) )) weights = np.linalg.solve(C, np.vstack(( f, np.zeros((p, 1)) )) ) radial_weights, poly_weights = weights[:M], weights[M:] res = f - np.dot(B, poly_weights) Rsqr = 1.0 - (np.dot( res.T, np.linalg.solve(K, res)) / np.dot( f.T, np.linalg.solve(K, f) )) # store parameters self.X, self.f = X, f self.ell, self.K = ell, K self.Rsqr = Rsqr[0,0] self.radial_weights, self.poly_weights = radial_weights, poly_weights
def train(self, X, f, v=None, e=None): """Train the radial basis approximation. Parameters ---------- X : ndarray an ndarray of training points for the polynomial approximation. The shape is M-by-m, where m is the number of dimensions. f : ndarray an ndarray of function values used to train the polynomial approximation. The shape of `f` is M-by-1. v : ndarray, optional contains the regularization parameters that model error in the function values (default None) e : ndarray, optional an ndarray containing the eigenvalues from the active subspace analysis. If present, the radial basis uses it to determine the appropriate anisotropy in the length scales. (default None) Notes ----- The approximation uses an multivariate, squared exponential radial basis. If `e` is not None, then the radial basis is anisotropic with length scales determined by `e`. Otherwise, the basis is isotropic. The length scale parameters (i.e., the rbf shape parameters) are determined with a maximum likelihood heuristic inspired by techniques for fitting a Gaussian process model. The approximation also includes a monomial basis with monomials of total degree up to order `N`. These are fit with weighted least-squares, where the weight matrix is the inverse of the matrix of radial basis functions evaluated at the training points. This method sets all the attributes of the class for use in the `predict` method. """ X, f, M, m = process_inputs_outputs(X, f) # check that there are enough points to train the polynomial if M < comb(self.N + m, m): raise Exception( 'Not enough points to fit response surface of order {:d}'. format(self.N)) # use maximum likelihood to tune parameters log10g = fminbound(_rbf_objective, -10.0, 1.0, args=( X, f, v, self.N, e, )) g = 10**(log10g) if e is None: ell = g * np.ones((m, 1)) if v is None: v = 1e-6 * np.ones(f.shape) else: ell = g * np.sum(e) / e[:m] if v is None: v = g * np.sum(e[m:]) * np.ones(f.shape) # ensure conditioning v = np.amax([v.reshape(f.shape), 1e-6 * np.ones(f.shape)], axis=0) # covariance matrix of observations K = exponential_squared(X, X, 1.0, ell) K += np.diag(v.reshape((M, ))) B = polynomial_bases(X, self.N)[0] p = B.shape[1] C = np.hstack((np.vstack((K, B.T)), np.vstack((B, np.zeros((p, p)))))) weights = np.linalg.solve(C, np.vstack((f, np.zeros((p, 1))))) radial_weights, poly_weights = weights[:M], weights[M:] res = f - np.dot(B, poly_weights) Rsqr = 1.0 - (np.dot(res.T, np.linalg.solve(K, res)) / np.dot(f.T, np.linalg.solve(K, f))) # store parameters self.X, self.f = X, f self.ell, self.K = ell, K self.Rsqr = Rsqr[0, 0] self.radial_weights, self.poly_weights = radial_weights, poly_weights