import numpy as npimport torchimport matplotlib.pyplot as pltimport scipy.stats # Sinn =10000# x = np.linspace(-1,1, n)np.random.seed(8)x = np.random.uniform(-1,1,(n))x = np.sort(x)eps = np.random.normal(0,np.exp(1-x)/10)mu = np.sin(np.pi*x)/(np.pi*x)y = mu + epsdef truef(tau):return torch.sin(torch.pi*x)/(torch.pi*x) + torch.sqrt(torch.exp(1-x)/10)*scipy.stats.norm.ppf(tau)
Convert Data to PyTorch Tensors
Code
x = torch.as_tensor(x,dtype=torch.float32).view(-1,1)y = torch.as_tensor(y,dtype=torch.float32)plt.scatter(x,y,s=1)
Define the Model
Code
import torch.nn as nnclass QuantNet(nn.Module):def__init__(self, xsz=1):super(QuantNet, self).__init__()self.nh =64 hsz =32 hsz1 =32self.fcx = nn.Linear(xsz, hsz)self.fctau = nn.Linear(self.nh, hsz)self.fcxtau = nn.Linear(hsz , hsz1)self.fcxtau1 = nn.Linear(hsz1 , hsz1)self.fc = nn.Linear(hsz1 , 2)def forward(self, x,tau): tau = torch.cos(torch.arange(start=0,end=self.nh)*torch.pi*tau) tau = torch.relu(self.fctau(tau)) # function phi from paper x = torch.relu(self.fcx(x)) # function psi x = torch.relu(self.fcxtau(x*tau)) # first layer of function g x = torch.relu(self.fcxtau1(x)) # second layer of function g x =self.fc(x) # third layer of function greturn x
Model Estimation (a.k.a. Training)
Code
def train(model, x,y,optimizer,epochs): lv = np.zeros(epochs)for t inrange(epochs): tau = torch.rand(1).item() f = model(x,tau) e = y.view(-1,1)-f loss =0.1*torch.mean(torch.square(e[:,0]))# loss = 0 loss += torch.mean(torch.maximum(tau*e[:,1],(tau-1)*e[:,1])) optimizer.zero_grad() loss.backward() optimizer.step() lv[t] = loss.item()if t %2000==0:print(f"Epoch {t}: Loss = {loss.item():>7f}")print(f"Epoch {t}: Loss = {loss.item():>7f}")return lv
class FixedQuantNet(nn.Module):def__init__(self, xsz=1, tau = [0.5]):super(FixedQuantNet, self).__init__()self.nh =64 hsz =64self.fcx = nn.Linear(xsz, hsz)self.tau = tauself.nq =len(self.tau)self.fc = nn.Linear(hsz , self.nq +1)def forward(self, x): x = torch.relu(self.fcx(x)) x =self.fc(x)return xdef train(self,x,y,optimizer,epochs): lv = np.zeros(epochs)for t inrange(epochs): f =self(x) e = y.view(-1,1)-f loss =0.1*torch.mean(torch.square(e[:,0]))# loss = 0for i inrange(self.nq): loss += torch.mean(torch.maximum(self.tau[i]*e[:,i+1],(self.tau[i]-1)*e[:,i+1])) optimizer.zero_grad() loss.backward() optimizer.step() lv[t] = loss.item()if t %2000==0:print(f"Epoch {t}: Loss = {loss.item():>7f}")print(f"Epoch {t}: Loss = {loss.item():>7f}")return lv
We consider the following model: \[\begin{align*}
\tau &\sim \mathrm{Gamma}(0.5, 0.5) \\
\lambda_d &\sim \mathrm{Gamma}(0.5, 0.5) \\
\beta_d &\sim \mathcal{N}(0, 20) \\
y_n &\sim \mathrm{Bernoulli}(\sigma((\tau \lambda \odot \beta)^T x_n))),
\end{align*}\] - \(\tau\) is a scalar global coefficient scale - \(\lambda\) is a vector of local scales - \(\beta\) is the vector of unscaled coefficients,
Code
import tensorflow_probability.substrates.jax as tfpimport numpy as npimport jax.numpy as jnptfd = tfp.distributionsimport jaximport matplotlib.pyplot as plt
Taking the logarithm of both sides, we get \[
\log \pi(z) = \log \pi(\theta) + \log \left| \frac{\partial T }{\partial z}(z) \right|
\] Use \(T(z)=e^z\), and \(\log|\frac{\partial T}{\partial z}(z)| = z\)
Change of Variables in Code
Code
def unconstrained_joint_log_prob(x, y, theta): ndims = x.shape[-1] unc_tau, unc_lamb, beta = jnp.split(theta, [1, 1+ ndims]) unc_tau = unc_tau.reshape([]) # Make unc_tau a scalar tau = jnp.exp(unc_tau) ldj = unc_tau lamb = jnp.exp(unc_lamb) ldj += unc_lamb.sum()return joint_log_prob(x, y, tau, lamb, beta) + ldj
Let’s check out function
Code
from functools import partialtarget_log_prob = partial(unconstrained_joint_log_prob, x, y)theta = np.r_[tau,lamb,beta]target_log_prob(theta)