lmc-code / src /online_stats.py
khanhvinh9's picture
Upload folder using huggingface_hub
a20151e verified
Raw
History Blame Contribute Delete
2.76 kB
"""Online-ish Pearson correlation of all n x n variable pairs simultaneously."""
from typing import NamedTuple
import jax.numpy as jnp
class OnlineMean(NamedTuple):
sum: jnp.ndarray
count: int
@staticmethod
def init(num_features: int):
return OnlineMean(sum=jnp.zeros(num_features), count=0)
def update(self, batch: jnp.ndarray):
return OnlineMean(self.sum + jnp.sum(batch, axis=0), self.count + batch.shape[0])
def mean(self):
return self.sum / self.count
class OnlineCovariance(NamedTuple):
a_mean: jnp.ndarray # (d, )
b_mean: jnp.ndarray # (d, )
cov: jnp.ndarray # (d, d)
var_a: jnp.ndarray # (d, )
var_b: jnp.ndarray # (d, )
count: int
@staticmethod
def init(a_mean: jnp.ndarray, b_mean: jnp.ndarray):
assert a_mean.shape == b_mean.shape
assert len(a_mean.shape) == 1
d = a_mean.shape[0]
return OnlineCovariance(a_mean,
b_mean,
cov=jnp.zeros((d, d)),
var_a=jnp.zeros((d, )),
var_b=jnp.zeros((d, )),
count=0)
def update(self, a_batch, b_batch):
assert a_batch.shape == b_batch.shape
batch_size, _ = a_batch.shape
a_res = a_batch - self.a_mean
b_res = b_batch - self.b_mean
return OnlineCovariance(a_mean=self.a_mean,
b_mean=self.b_mean,
cov=self.cov + a_res.T @ b_res,
var_a=self.var_a + jnp.sum(a_res**2, axis=0),
var_b=self.var_b + jnp.sum(b_res**2, axis=0),
count=self.count + batch_size)
def covariance(self):
return self.cov / (self.count - 1)
def a_variance(self):
return self.var_a / (self.count - 1)
def b_variance(self):
return self.var_b / (self.count - 1)
def a_stddev(self):
return jnp.sqrt(self.a_variance())
def b_stddev(self):
return jnp.sqrt(self.b_variance())
def E_ab(self):
return self.covariance() + jnp.outer(self.a_mean, self.b_mean)
def pearson_correlation(self):
# Note that the 1/(n-1) normalization terms cancel out nicely here.
# TODO: clip?
eps = 0
# Dead units will have zero variance, which produces NaNs. Convert those to
# zeros with nan_to_num.
return jnp.nan_to_num(self.cov / (jnp.sqrt(self.var_a[:, jnp.newaxis]) + eps) /
(jnp.sqrt(self.var_b) + eps))
class OnlineInnerProduct(NamedTuple):
val: jnp.ndarray # (d, d)
@staticmethod
def init(d: int):
return OnlineInnerProduct(val=jnp.zeros((d, d)))
def update(self, a_batch, b_batch):
assert a_batch.shape == b_batch.shape
return OnlineInnerProduct(val=self.val + a_batch.T @ b_batch)