Skip to content

Commit f93e778

Browse files
committed
fixes for tf+keras+tfp version upgrade (<3)
1 parent bf9c6bb commit f93e778

39 files changed

+1127
-595
lines changed

DESCRIPTION

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ Config/reticulate:
1717
list(
1818
packages = list(
1919
list(package = "six", pip = TRUE),
20-
list(package = "tensorflow", version = "2.10.0", pip = TRUE),
21-
list(package = "tensorflow_probability", version = "0.16", pip = TRUE),
22-
list(package = "keras", version = "2.10.0", pip = TRUE))
20+
list(package = "tensorflow", version = "2.15", pip = TRUE),
21+
list(package = "tensorflow_probability", version = "0.23", pip = TRUE),
22+
list(package = "keras", version = "2.15", pip = TRUE))
2323
)
2424
Depends:
2525
R (>= 4.0.0),
@@ -46,4 +46,4 @@ Imports:
4646
License: GPL-3
4747
Encoding: UTF-8
4848
LazyData: true
49-
RoxygenNote: 7.2.3
49+
RoxygenNote: 7.3.2

NAMESPACE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ export(extract_S)
3333
export(extract_pure_gam_part)
3434
export(extractlen)
3535
export(extractval)
36+
export(extractvals)
3637
export(extractvar)
3738
export(family_to_tfd)
3839
export(family_to_trafo)
@@ -129,7 +130,6 @@ export(tib_layer)
129130
export(tibgroup_layer)
130131
export(tibgroup_layer_torch)
131132
export(tiblinlasso_layer_torch)
132-
export(tweedie)
133133
export(weight_control)
134134
import(Matrix)
135135
import(R6)

R/families.R

Lines changed: 97 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -25,47 +25,47 @@ tfmult <- function(x,y) tf$math$multiply(x,y)
2525
#' with parameters (and corresponding inverse link function in brackets):
2626
#'
2727
#' \itemize{
28-
#' \item{"normal": }{normal distribution with location (identity), scale (exp)}
29-
#' \item{"bernoulli": }{bernoulli distribution with logits (identity)}
30-
#' \item{"bernoulli_prob": }{bernoulli distribution with probabilities (sigmoid)}
31-
#' \item{"beta": }{beta with concentration 1 = alpha (exp) and concentration
28+
#' \item{\code{"normal": }}{normal distribution with location (identity), scale (exp)}
29+
#' \item{\code{"bernoulli": }}{bernoulli distribution with logits (identity)}
30+
#' \item{\code{"bernoulli_prob": }}{bernoulli distribution with probabilities (sigmoid)}
31+
#' \item{\code{"beta": }}{beta with concentration 1 = alpha (exp) and concentration
3232
#' 0 = beta (exp)}
33-
#' \item{"betar": }{beta with mean (sigmoid) and scale (sigmoid)}
34-
#' \item{"cauchy": }{location (identity), scale (exp)}
35-
#' \item{"chi2": }{cauchy with df (exp)}
36-
#' \item{"chi": }{cauchy with df (exp)}
37-
#' \item{"exponential": }{exponential with lambda (exp)}
38-
#' \item{"gamma": }{gamma with concentration (exp) and rate (exp)}
39-
#' \item{"gammar": }{gamma with location (exp) and scale (exp), following
33+
#' \item{\code{"betar": }}{beta with mean (sigmoid) and scale (sigmoid)}
34+
#' \item{\code{"cauchy": }}{location (identity), scale (exp)}
35+
#' \item{\code{"chi2": }}{cauchy with df (exp)}
36+
#' \item{\code{"chi": }}{cauchy with df (exp)}
37+
#' \item{\code{"exponential": }}{exponential with lambda (exp)}
38+
#' \item{\code{"gamma": }}{gamma with concentration (exp) and rate (exp)}
39+
#' \item{\code{"gammar": }}{gamma with location (exp) and scale (exp), following
4040
#' \code{gamlss.dist::GA}, which implies that the expectation is the location,
4141
#' and the variance of the distribution is the \code{location^2 scale^2}}
42-
#' \item{"gumbel": }{gumbel with location (identity), scale (exp)}
43-
#' \item{"half_cauchy": }{half cauchy with location (identity), scale (exp)}
44-
#' \item{"half_normal": }{half normal with scale (exp)}
45-
#' \item{"horseshoe": }{horseshoe with scale (exp)}
46-
#' \item{"inverse_gamma": }{inverse gamma with concentation (exp) and rate (exp)}
47-
#' \item{"inverse_gamma_ls": }{inverse gamma with location (exp) and variance (1/exp)}
48-
#' \item{"inverse_gaussian": }{inverse Gaussian with location (exp) and concentation
42+
#' \item{\code{"gumbel": }}{gumbel with location (identity), scale (exp)}
43+
#' \item{\code{"half_cauchy": }}{half cauchy with location (identity), scale (exp)}
44+
#' \item{\code{"half_normal": }}{half normal with scale (exp)}
45+
#' \item{\code{"horseshoe": }}{horseshoe with scale (exp)}
46+
#' \item{\code{"inverse_gamma": }}{inverse gamma with concentation (exp) and rate (exp)}
47+
#' \item{\code{"inverse_gamma_ls": }}{inverse gamma with location (exp) and variance (1/exp)}
48+
#' \item{\code{"inverse_gaussian": }}{inverse Gaussian with location (exp) and concentation
4949
#' (exp)}
50-
#' \item{"laplace": }{Laplace with location (identity) and scale (exp)}
51-
#' \item{"log_normal": }{Log-normal with location (identity) and scale (exp) of
50+
#' \item{\code{"laplace": }}{Laplace with location (identity) and scale (exp)}
51+
#' \item{\code{"log_normal": }}{Log-normal with location (identity) and scale (exp) of
5252
#' underlying normal distribution}
53-
#' \item{"logistic": }{logistic with location (identity) and scale (exp)}
54-
#' \item{"negbinom": }{neg. binomial with count (exp) and prob (sigmoid)}
55-
#' \item{"negbinom_ls": }{neg. binomail with mean (exp) and clutter factor (exp)}
56-
#' \item{"pareto": }{Pareto with concentration (exp) and scale (1/exp)}
57-
#' \item{"pareto_ls": }{Pareto location scale version with mean (exp)
53+
#' \item{\code{"logistic": }}{logistic with location (identity) and scale (exp)}
54+
#' \item{\code{"negbinom": }}{neg. binomial with count (exp) and prob (sigmoid)}
55+
#' \item{\code{"negbinom_ls": }}{neg. binomail with mean (exp) and clutter factor (exp)}
56+
#' \item{\code{"pareto": }}{Pareto with concentration (exp) and scale (1/exp)}
57+
#' \item{\code{"pareto_ls": }}{Pareto location scale version with mean (exp)
5858
#' and scale (exp), which corresponds to a Pareto distribution with parameters scale = mean
5959
#' and concentration = 1/sigma, where sigma is the scale in the pareto_ls version}
60-
#' \item{"poisson": }{poisson with rate (exp)}
61-
#' \item{"poisson_lograte": }{poisson with lograte (identity))}
62-
#' \item{"student_t": }{Student's t with df (exp)}
63-
#' \item{"student_t_ls": }{Student's t with df (exp), location (identity) and
60+
#' \item{\code{"poisson": }}{poisson with rate (exp)}
61+
#' \item{\code{"poisson_lograte": }}{poisson with lograte (identity))}
62+
#' \item{\code{"student_t": }}{Student's t with df (exp)}
63+
#' \item{\code{"student_t_ls": }}{Student's t with df (exp), location (identity) and
6464
#' scale (exp)}
65-
#' \item{"uniform": }{uniform with upper and lower (both identity)}
66-
#' \item{"zinb": }{Zero-inflated negative binomial with mean (exp),
65+
#' \item{\code{"uniform": }}{uniform with upper and lower (both identity)}
66+
#' \item{\code{"zinb": }}{Zero-inflated negative binomial with mean (exp),
6767
#' variance (exp) and prob (sigmoid)}
68-
#' \item{"zip": }{Zero-inflated poisson distribution with mean (exp) and prob (sigmoid)}
68+
#' \item{\code{"zip": }}{Zero-inflated poisson distribution with mean (exp) and prob (sigmoid)}
6969
#' }
7070
#' @param add_const small positive constant to stabilize calculations
7171
#' @param trafo_list list of transformations for each distribution parameter.
@@ -281,9 +281,9 @@ family_to_tfd <- function(family)
281281
negbinom_ls = tfd_negative_binomial_ls,
282282
pareto = tfd_pareto,
283283
pareto_ls = tfd_pareto,
284-
poisson = tfd_poisson,
284+
poisson = tfd_poisson_fixed,
285285
poisson_lograte = function(log_rate)
286-
tfd_poisson(log_rate = log_rate),
286+
tfd_poisson_fixed(log_rate = log_rate),
287287
student_t = function(x)
288288
tfd_student_t(df=x,loc=0,scale=1),
289289
student_t_ls = tfd_student_t,
@@ -472,6 +472,15 @@ family_trafo_funs_special <- function(family, add_const = 1e-8)
472472

473473
}
474474

475+
tfd_poisson_fixed <- function (rate = NULL, log_rate = NULL, interpolate_nondiscrete = TRUE,
476+
validate_args = FALSE, allow_nan_stats = TRUE, name = "Poisson")
477+
{
478+
args <- list(rate = rate, log_rate = log_rate,
479+
validate_args = validate_args, allow_nan_stats = allow_nan_stats,
480+
name = name)
481+
do.call(tfp$distributions$Poisson, args)
482+
}
483+
475484
#' Implementation of a zero-inflated poisson distribution for TFP
476485
#'
477486
#' @param lambda scalar value for rate of poisson distribution
@@ -483,7 +492,7 @@ tfd_zip <- function(lambda, probs)
483492
return(
484493
tfd_mixture(cat = tfd_categorical(probs = probs),
485494
components =
486-
list(tfd_poisson(rate = lambda),
495+
list(tfd_poisson_fixed(rate = lambda),
487496
tfd_deterministic(loc = lambda * 0L)
488497
),
489498
name="zip")
@@ -543,56 +552,60 @@ tfd_mvr <- function(loc, scale,
543552

544553
}
545554

546-
# Implementation of a distribution-like layer for (Quasi-)Tweedie
547-
tfd_tweedie <- function(loc, phi, p = 1.5, quasi = FALSE,
548-
validate_args = FALSE,
549-
allow_nan_stats = TRUE,
550-
name = "Tweedie")
551-
{
552-
553-
args <- list(
554-
loc = loc,
555-
scale = phi,
556-
var_power = p,
557-
quasi = quasi,
558-
validate_args = validate_args,
559-
allow_nan_stats = allow_nan_stats,
560-
name = name
561-
)
562-
563-
python_path <- system.file("python", package = "deepregression")
564-
distributions <- reticulate::import_from_path("distributions", path = python_path)
565-
566-
return(do.call(distributions$Tweedie, args))
567-
568-
}
569-
570-
#' tfd_distfun for (Quasi-)Tweedie to allow for flexible p
571-
#' @param p integer; defines distribution
572-
#' @param quasi logical; whether to use quasi-likelihood or deviance resids
573-
#' @param output_dim integer; currently only univariate responses supported
574-
#' @export
575555
#'
576-
tweedie <- function(p, quasi = FALSE, output_dim = 1L)
577-
{
578-
579-
tfd_dist <- function(l, s) tfd_tweedie(loc = l, phi = s, p = p, quasi = quasi)
580-
trafo_list <- list(function(x) tf$add(1e-8, tfe(x)),
581-
function(x) tf$add(1e-8, tfe(x)))
582-
dist_dim <- 2L
583-
ret_fun <- function(x)
584-
do.call(tfd_dist,
585-
lapply(1:(x$shape[[2]]/output_dim),
586-
function(i)
587-
trafo_list[[i]](
588-
tf_stride_cols(x,(i-1L)*output_dim+1L,
589-
(i-1L)*output_dim+output_dim)))
590-
)
591-
attr(ret_fun, "nrparams_dist") <- 2L
592-
593-
return(ret_fun)
594-
595-
}
556+
#' # Implementation of a distribution-like layer for (Quasi-)Tweedie
557+
#' tfd_tweedie <- function(loc, phi, p = 1.5, quasi = FALSE,
558+
#' validate_args = FALSE,
559+
#' allow_nan_stats = TRUE,
560+
#' name = "Tweedie")
561+
#' {
562+
#'
563+
#' args <- list(
564+
#' loc = loc,
565+
#' scale = phi,
566+
#' var_power = p,
567+
#' quasi = quasi,
568+
#' validate_args = validate_args,
569+
#' allow_nan_stats = allow_nan_stats,
570+
#' name = name
571+
#' )
572+
#'
573+
#' python_path <- system.file("python", package = "deepregression")
574+
#' distributions <- reticulate::import_from_path("distributions", path = python_path)
575+
#'
576+
#' return(do.call(distributions$Tweedie, args))
577+
#'
578+
#' }
579+
#'
580+
#' #' tfd_distfun for (Quasi-)Tweedie to allow for flexible p
581+
#' #' @param p integer; defines distribution
582+
#' #' @param quasi logical; whether to use quasi-likelihood or deviance resids
583+
#' #' @param output_dim integer; currently only univariate responses supported
584+
#' #' @export
585+
#' #'
586+
#' tweedie <- function(p, quasi = FALSE, output_dim = 1L,
587+
#' linkfun_mean = function(x) tf$add(1e-8, tf$math$exp(x)),
588+
#' linkfun_phi = function(x) tf$add(1e-8, tf$math$exp(x)))
589+
#' {
590+
#'
591+
#' tfd_dist <- function(l, s) tfd_tweedie(loc = l, phi = s, p = p, quasi = quasi)
592+
#' trafo_list <- list(linkfun_mean, linkfun_phi)
593+
#' dist_dim <- 2L
594+
#' ret_fun <- function(x)
595+
#' do.call(tfd_dist,
596+
#' lapply(1:(x$shape[[2]]/output_dim),
597+
#' function(i)
598+
#' trafo_list[[i]](
599+
#' tf_stride_cols(x,(i-1L)*output_dim+1L,
600+
#' (i-1L)*output_dim+output_dim)))
601+
#' )
602+
#' attr(ret_fun, "nrparams_dist") <- 2L
603+
#'
604+
#' return(ret_fun)
605+
#'
606+
#' }
607+
#'
608+
596609

597610
#' For using mean squared error via TFP
598611
#'

R/formula_helpers.R

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,12 @@ extractval <- function(term, name, default_for_missing = FALSE, default = NULL)
112112

113113
}
114114

115-
# multiple value option of extractval
115+
#' Extractval with multiple options
116+
#' @param names character vector of names
117+
#' @export
118+
#' @rdname formulaHelpers
119+
#'
120+
#'
116121
extractvals <- function(term, names){
117122
if(is.character(term)) term <- as.formula(paste0("~", term))
118123
inputs <- as.list(as.list(term)[[2]])[-1]

R/layers.R

Lines changed: 1 addition & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ re_layer = function(units, ...) {
1515
#'
1616
#' @param units integer; number of units
1717
#' @param ... arguments passed to TensorFlow layer
18+
#' @param P penalty matrix
1819
#' @return layer object
1920
#' @export
2021
#' @rdname re_layers
@@ -139,29 +140,6 @@ layer_sparse_conv_2d <- function(filters,
139140
#' @param ... arguments passed to TensorFlow layer
140141
#' @return layer object
141142
#' @export
142-
#' @examples
143-
#' n <- 1000
144-
#' y <- rnorm(n)
145-
#' data <- data.frame(x1=rnorm(n), x2=rnorm(n), x3=rnorm(n))
146-
#'
147-
#' library(deepregression)
148-
#'
149-
#' mod <- keras_model_sequential()
150-
#' mod %>% layer_dense(1000) %>%
151-
#' layer_sparse_batch_normalization(lam = 100)() %>%
152-
#' layer_dense(1)
153-
#'
154-
#' mod %>% compile(optimizer = optimizer_adam(),
155-
#' loss = "mse")
156-
#'
157-
#' mod %>% fit(x = as.matrix(data), y = y, epochs = 1000,
158-
#' validation_split = 0.2,
159-
#' callbacks = list(callback_early_stopping(patience = 30,
160-
#' restore_best_weights = TRUE)),
161-
#' verbose = FALSE)
162-
#'
163-
#' lapply(mod$weights[3:4], function(x)
164-
#' summary(c(as.matrix(x))))
165143
#'
166144
#'
167145
layer_sparse_batch_normalization <- function(lam=NULL, ...) {

R/zzz.R

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
#' @importFrom stats na.omit
22

33
VERSIONPY = "3.10"
4-
VERSIONTF = "2.10"
5-
VERSIONKERAS = "2.10"
6-
VERSIONTFP = "0.16"
4+
VERSIONTF = "2.15"
5+
VERSIONKERAS = "2.15"
6+
VERSIONTFP = "0.23"
77

88
globalVariables("self")
99

-10 Bytes
Binary file not shown.
-29 Bytes
Binary file not shown.

inst/python/distributions/tweedie.py

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,21 @@
99
from tensorflow_probability.python.internal import tensor_util
1010
from tensorflow.math import exp, log
1111
from tensorflow.experimental import numpy as tnp
12+
import numpy as np
13+
from scipy.special import wright_bessel
14+
15+
16+
# Define the TensorFlow wrapper function for scipy's wright_bessel
17+
def tensorflow_wright_bessel(a, b, x):
18+
# The inner function to be applied
19+
def wright_bessel_inner(a_np, b_np, x_np):
20+
# Use the provided 'out' parameter to store the output directly in a NumPy array
21+
result = wright_bessel(a_np, b_np, x_np)
22+
return np.array(result, dtype=np.float64)
23+
24+
# Wrapping the Python function with tf.py_function
25+
# It takes the inner function, list of tensor inputs, and the output type as arguments
26+
return tf.py_function(wright_bessel_inner, [a, b, x], tf.float64)
1227

1328
class Tweedie(distribution.AutoCompositeTensorDistribution):
1429
"""Tweedie
@@ -113,19 +128,24 @@ def _log_prob(self, x):
113128
return llf - u
114129

115130
else:
116-
# from https://github.com/cran/statmod/blob/master/R/tweedie.R negative deviance residuals
117-
# x1 = x + 0.1 * tf.cast(tf.equal(x, 0), tf.float32)
118-
# theta = (tf.pow(x1, 1 - self.p) - tf.pow(self.loc, 1 - self.p)) / (1 - self.p)
119-
# kappa = (tf.pow(x, 2 - self.p) - tf.pow(self.loc, 2 - self.p)) / (2 - self.p)
120-
# return - 2 * (x * theta - kappa)
121-
# from https://github.com/cran/mgcv/blob/aff4560d187dfd7d98c7bd367f5a0076faf129b7/R/gamlss.r#L2474
122-
ethi = tf.exp(-self.p) # assuming p > 0
123-
p = (self.b + self.a * ethi)/(1+ethi)
124-
x1 = x + tf.cast(x == 0, tf.float32)
125-
theta = (tf.pow(x1, 1 - p) - tf.pow(self.loc, 1 - p)) / (1 - p)
126-
kappa = (tf.pow(x, 2 - p) - tf.pow(self.loc, 2 - p)) / (2 - p)
127-
return tf.sign(x - self.loc) * tf.sqrt(tf.nn.relu(2 * (x * theta - kappa) * 1 / self.scale))
131+
p = self.p
132+
mu = self.loc
133+
theta = mu ** (1 - p) / (1 - p)
134+
kappa = mu ** (2 - p) / (2 - p)
135+
alpha = (2 - p) / (1 - p)
128136

137+
ll_obs = (endog * theta - kappa) / scale
138+
idx = endog > 0
139+
if np.any(idx):
140+
if not np.isscalar(endog):
141+
endog = endog[idx]
142+
if not np.isscalar(scale):
143+
scale = scale[idx]
144+
x = ((p - 1) * scale / endog) ** alpha
145+
x /= (2 - p) * scale
146+
wb = special.wright_bessel(-alpha, 0, x)
147+
ll_obs[idx] += np.log(1/endog * wb)
148+
return ll_obs
129149

130150

131151
def _mean(self):
-29 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)