Skip to content

Commit 1977148

Browse files
authored
New Metrics; New Vignette; update Layer(); add create_layer_wrapper()
* New vignette: Making New Layers via Subclassing * Update metrics: - all the metric functions gain the ability to return a `keras$metrics$Metric` instance if called without `y_true` and `y_pred` - Each metric function is now documented separately, with a common `?Metric` topic demonstrating example usage. - New built in metrics: - `metric_true_negatives()` - `metric_true_positives()` - `metric_false_negatives()` - `metric_false_positives()` - `metric_specificity_at_sensitivity()` - `metric_sensitivity_at_specificity()` - `metric_precision()` - `metric_precision_at_recall()` - `metric_sum()` - `metric_recall()` - `metric_recall_at_precision()` - `metric_root_mean_squared_error()` - `metric_sparse_categorical_accuracy()` - `metric_mean_tensor()` - `metric_mean_wrapper()` - `metric_mean_iou()` - `metric_mean_relative_error()` - `metric_logcosh_error()` - `metric_mean()` - `metric_cosine_similarity()` - `metric_categorical_hinge()` - `metric_accuracy()` - `metric_auc()` * Make `Layer()` lazy about initializing the Python session. It is now safe to use in a package. * Add `create_layer_wrapper()` * Restore R-3.6 compat (subtle changes in active-bindings and S3 dispatch) * Accept install_keras(version="cpu") * Bump github actions TF test version
1 parent 4d41ff3 commit 1977148

File tree

511 files changed

+18831
-487
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

511 files changed

+18831
-487
lines changed

.github/workflows/main.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,15 @@ jobs:
3434
# - {os: 'windows-latest', tf: 'release', r: 'release'}
3535
# - {os: 'macOS-latest' , tf: 'release', r: 'release'}
3636

37-
# - {os: 'ubuntu-20.04', tf: '2.5', r: 'release'}
37+
- {os: 'ubuntu-20.04', tf: '2.5', r: 'release'}
3838
- {os: 'ubuntu-20.04', tf: '2.4', r: 'release'}
3939
- {os: 'ubuntu-20.04', tf: '2.3', r: 'release'}
4040
- {os: 'ubuntu-20.04', tf: '2.2', r: 'release'}
4141
- {os: 'ubuntu-20.04', tf: '2.1', r: 'release'}
4242

4343
# these are allowed to fail
4444
- {os: 'ubuntu-20.04', tf: 'default', r: 'devel'}
45-
- {os: 'ubuntu-20.04', tf: '2.6.0rc2', r: 'release'}
45+
# - {os: 'ubuntu-20.04', tf: '2.6.0rc2', r: 'release'}
4646
# - {os: 'ubuntu-20.04', tf: 'nightly' , r: 'release'}
4747

4848
runs-on: ${{ matrix.os }}

NAMESPACE

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ S3method(py_str,keras.engine.training.Model)
5454
S3method(py_to_r_wrapper,keras.engine.training.Model)
5555
S3method(py_to_r_wrapper,kerastools.model.RModel)
5656
S3method(r_to_py,R6ClassGenerator)
57+
S3method(r_to_py,keras_layer_wrapper)
5758
S3method(round,keras.engine.keras_tensor.KerasTensor)
5859
S3method(sign,keras.engine.keras_tensor.KerasTensor)
5960
S3method(sin,keras.engine.keras_tensor.KerasTensor)
@@ -121,6 +122,7 @@ export(constraint_nonneg)
121122
export(constraint_unitnorm)
122123
export(count_params)
123124
export(create_layer)
125+
export(create_layer_wrapper)
124126
export(create_wrapper)
125127
export(custom_metric)
126128
export(dataset_boston_housing)
@@ -588,6 +590,7 @@ importFrom(reticulate,tuple)
588590
importFrom(reticulate,use_condaenv)
589591
importFrom(reticulate,use_python)
590592
importFrom(reticulate,use_virtualenv)
593+
importFrom(rlang,"%||%")
591594
importFrom(stats,predict)
592595
importFrom(tensorflow,evaluate)
593596
importFrom(tensorflow,export_savedmodel)

NEWS.md

Lines changed: 77 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,49 @@
11
# keras (development version)
22

33
Breaking changes:
4-
`set_vocabulary()` arguments `df_data` and `oov_df_value` are deprecated. They are superseded by the new argument `idf_weights`.
54

6-
TF 2.6 changes:
7-
- `predict_proba` and `predict_classes` were removed.
5+
- `predict_proba()` and `predict_classes()` were removed.
86
- model serialization to/from yaml was removed.
97
- default changed: `layer_text_vectorization(pad_to_max_tokens=FALSE)`
8+
- `set_vocabulary()` arguments `df_data` and `oov_df_value` are deprecated. They are superseded by the new argument `idf_weights`.
109

1110
New Features:
12-
- Default Tensorflow/Keras version is now 2.6
1311

14-
- The `keras` python module is exported
12+
- Default Tensorflow/Keras version is now 2.6
1513

16-
- Introduced `%py_class%`, a new python class generator constructor.
14+
- Introduced `%py_class%`, an R-language constructor for Python classes.
1715

1816
- New vignettes:
19-
- Subclassing python classes: How to use `%py_class%`.
17+
- Subclassing Python classes: How to use `%py_class%`.
18+
- Making new layers and models via subclassing.
2019
- Customizing what happens in fit (example of how to define a model, like a GAN, with a custom train step).
2120
- Writing your own callbacks.
2221

23-
- All optimizer had argument `lr` renamed to `learning_rate`.
24-
(backwards compatibility is preserved, an R warning is now issued).
25-
26-
- keras now imports the glue package
27-
28-
- The `compile()` method for keras models has been updated:
29-
- `optimizer` is now an optional argument. It defaults to "rmsprop" for regular keras models. Custom models can specify their own default optimizer.
30-
- `loss` is now an optional argument.
31-
- New optional arguments: `run_eagerly`, `steps_per_execution`.
32-
- `target_tensors` and `sample_weight_mode` must now be supplied as named arguments.
22+
- The `keras` Python module is exported
3323

3424
- Major changes to the underlying handling of custom R6 layer classes.
35-
- A new `r_to_py` method is provided for `R6ClassGenerator` objects.
36-
- R6 custom layers can now inherit directly from python layer classes
37-
or other R6 custom layer classes
38-
- Custom R6 layers can now be instantiated directly after conversion of the class generator with `r_to_py`, without going through `create_layer`.
39-
- `KerasLayer` is deprecated (new classes should inherit directly from `keras$layers$Layer`)
40-
- `KerasWrapper` is deprecated (new classes should inherit directly from `keras$layers$Wrapper`)
41-
- `create_wrapper` is deprecated (no longer needed, use `create_layer` directly)
42-
- All layer class methods provided as R functions now have a `super` in scope that resolves to the python super class object
25+
- A new `r_to_py()` method is provided for `R6ClassGenerator` objects.
26+
- R6 custom layers can now inherit directly from Python layer classes
27+
or other R6 custom layer classes.
28+
- Custom R6 layers can now be instantiated directly after conversion of the class generator with `r_to_py()`, without going through `create_layer()`.
29+
- `KerasLayer` is deprecated (new classes should inherit directly from `keras$layers$Layer`).
30+
- `KerasWrapper` is deprecated (new classes should inherit directly from `keras$layers$Wrapper`).
31+
- `create_wrapper()` is deprecated (no longer needed, use `create_layer()` directly).
32+
- All layer class methods provided as R functions now have a `super` in scope that resolves to the Python super class object.
4333
- Methods of `super` can be accessed in the 3 common ways:
44-
(python3 style): `super()$"__init__"()`
45-
(python2 style): `super(ClassName, self)$"__init__"()`
46-
(R6 style): `super$initialize()`
47-
- User defined custom classes that inherit from a python type are responsible for calling `super()$__init__(...)` if appropriate.
34+
- (Python 3 style): `super()$"__init__"()`
35+
- (Python 2 style): `super(ClassName, self)$"__init__"()`
36+
- (R6 style): `super$initialize()`
37+
- User defined custom classes that inherit from a Python type are responsible for calling ```super()$`__init__`(...)``` if appropriate.
4838
- Custom layers can now properly handle masks (#1225)
4939
- `supports_masking = TRUE` attribute is now supported
5040
- `compute_mask()` user defined method is now supported
5141
- `call()` methods now support a `training` argument, as well as any additional arbitrary user-defined arguments
5242

43+
- `Layer()` custom layer constructor is now lazy about initializing the Python session and safe to use on the top level of an R package (#1229).
44+
45+
- New function `create_layer_wrapper()` that can create a composing R function wrapper around a custom layer class.
46+
5347
- Refactored `install_keras()` (along with `tensorflow::install_tensorflow()`).
5448
Installation should be more reliable for more users now.
5549
If you encounter installation issues, please file an issue: https://github.com/rstudio/keras/issues/new
@@ -58,50 +52,49 @@ New Features:
5852

5953
- pandas is now a default extra packages installed by `install_keras()`
6054

61-
- loss functions:
62-
- all the loss functions gain the ability to return a callable
55+
- Loss functions:
56+
- All the loss functions gain the ability to return a callable
6357
(a `keras$losses$Loss` instance) if `y_true` and `y_pred` arguments are missing.
64-
- new builtin loss functions: loss_huber(), loss_kl_divergence()
58+
- New builtin loss functions:
6559

66-
- metric functions:
67-
- all the metric functions gain the ability to return a `keras$metrics$Metric` instance if called without `y_true` and `y_pred`
60+
- `loss_huber()`
61+
- `loss_kl_divergence()`
62+
63+
- Metric functions:
64+
- All the metric functions gain the ability to return a `keras$metrics$Metric` instance if called without `y_true` and `y_pred`
6865
- Each metric function is now documented separately, with a common `?Metric` topic demonstrating example usage.
69-
- New built in metrics:
70-
metric_true_negatives
71-
metric_true_positives
72-
metric_false_negatives
73-
metric_false_positives
74-
metric_specificity_at_sensitivity
75-
metric_sensitivity_at_specificity
76-
metric_precision
77-
metric_precision_at_recall
78-
metric_sum
79-
metric_recall
80-
metric_recall_at_precision
81-
metric_root_mean_squared_error
82-
metric_sparse_categorical_accuracy
83-
metric_mean_tensor
84-
metric_mean_wrapper
85-
metric_mean_iou
86-
metric_mean_relative_error
87-
metric_logcosh_error
88-
metric_mean
89-
metric_cosine_similarity
90-
metric_categorical_hinge
91-
metric_accuracy
92-
metric_auc
93-
94-
- keras_model_sequential() gains the ability to accept arguments that
95-
define input layer like `input_shape` and `dtype`.
66+
- New built-in metrics:
67+
68+
- `metric_true_negatives()`
69+
- `metric_true_positives()`
70+
- `metric_false_negatives()`
71+
- `metric_false_positives()`
72+
- `metric_specificity_at_sensitivity()`
73+
- `metric_sensitivity_at_specificity()`
74+
- `metric_precision()`
75+
- `metric_precision_at_recall()`
76+
- `metric_sum()`
77+
- `metric_recall()`
78+
- `metric_recall_at_precision()`
79+
- `metric_root_mean_squared_error()`
80+
- `metric_sparse_categorical_accuracy()`
81+
- `metric_mean_tensor()`
82+
- `metric_mean_wrapper()`
83+
- `metric_mean_iou()`
84+
- `metric_mean_relative_error()`
85+
- `metric_logcosh_error()`
86+
- `metric_mean()`
87+
- `metric_cosine_similarity()`
88+
- `metric_categorical_hinge()`
89+
- `metric_accuracy()`
90+
- `metric_auc()`
91+
92+
- `keras_model_sequential()` gains the ability to accept arguments that
93+
define the input layer like `input_shape` and `dtype`.
9694
See `?keras_model_sequential` for details and examples.
9795

98-
- Refactored automated tests to closer match the default installation procedure
99-
and compute environment of most user.
100-
101-
- Expanded CI test coverage to include R devel, oldrel and 3.6.
102-
10396
- Many layers gained new arguments, coming to parity with the interface
104-
available in the latest python version:
97+
available in the latest Python version:
10598

10699
| layer name | new argument |
107100
|------------------------------|------------------|
@@ -119,11 +112,28 @@ New Features:
119112
| `layer_text_vectorization` | `vocabulary` |
120113

121114

115+
- The `compile()` method for keras models has been updated:
116+
- `optimizer` is now an optional argument. It defaults to `"rmsprop"` for regular keras models.
117+
Custom models can specify their own default optimizer.
118+
- `loss` is now an optional argument.
119+
- New optional arguments: `run_eagerly`, `steps_per_execution`.
120+
- `target_tensors` and `sample_weight_mode` must now be supplied as named arguments.
122121

123122
- Added activation functions swish and gelu. (#1226)
124123

125124
- `set_vocabulary()` gains a `idf_weights` argument.
126125

126+
- All optimizer had argument `lr` renamed to `learning_rate`.
127+
(backwards compatibility is preserved, an R warning is now issued).
128+
129+
- The glue package was added to Imports
130+
131+
- Refactored automated tests to closer match the default installation procedure
132+
and compute environment of most user.
133+
134+
- Expanded CI test coverage to include R devel, oldrel and 3.6.
135+
136+
127137
# keras 2.4.0
128138

129139
- Use compat module when using `set_session` and `get_session`. (#1046)

R/Layer.R

Lines changed: 17 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -62,68 +62,26 @@ Layer <- function(classname, initialize, build = NULL, call = NULL,
6262
compute_output_shape = NULL, ...,
6363
inherit = tensorflow::tf$keras$layers$Layer) {
6464

65+
inherit <- substitute(inherit)
6566

66-
defs <- list(
67-
initialize = initialize,
68-
build = build,
69-
call = call,
70-
compute_output_shape = compute_output_shape
71-
)
72-
defs <- Filter(Negate(is.null), defs)
73-
defs <- append(defs, list(...))
67+
public <- list(...)
68+
public$initialize <- initialize
69+
public$build <- build
70+
public$call <- call
71+
public$compute_output_shape <- compute_output_shape
7472

73+
parent_env <- parent.frame()
7574

76-
# allow using the initialize method
77-
if ("initialize" %in% names(defs)) {
78-
if (!is.null(defs$`__init__`))
79-
stop("You should not specify both __init__ and initialize methods.", call.=FALSE)
80-
81-
defs[["__init__"]] <- defs$initialize
82-
}
83-
84-
# automatically add the `self` argument
85-
defs <- lapply(defs, function(x) {
86-
87-
if (inherits(x, "function")) {
88-
formals(x) <- append(
89-
pairlist(self = NULL),
90-
formals(x)
91-
)
92-
}
93-
94-
x
95-
})
96-
97-
# makes the function return NULL. `__init__` in python must always return None
98-
defs$`__init__` <- wrap_return_null(defs$`__init__`)
99-
100-
# allow inheriting from custom created layers
101-
if (!is.null(attr(inherit, "layer")))
102-
inherit <- attr(inherit, "layer")
103-
104-
layer <- reticulate::PyClass(
75+
# R6Class() calls substitute() on inherit;
76+
r_cls <- eval(as.call(list(
77+
quote(R6::R6Class),
10578
classname = classname,
106-
defs = defs,
107-
inherit = inherit
108-
)
109-
layer$`__module__` <- classname
110-
111-
# build the function to be used
112-
f <- function(object) {
113-
.args <- as.list(match.call())[-c(1)]
114-
.args <- .args[names(.args) != "object"]
115-
create_layer(layer, object, .args)
116-
}
117-
formals(f) <- append(
118-
formals(f),
119-
formals(initialize)
120-
)
121-
attr(f, "layer") <- layer
122-
f
123-
}
79+
public = public,
80+
active = NULL,
81+
inherit = inherit,
82+
cloneable = FALSE,
83+
parent_env = parent_env
84+
)))
12485

125-
# makes the function return NULL. `__init__` in python must always return None.
126-
wrap_return_null <- function(f) {
127-
body(f)[[length(body(f)) + 1]] <- substitute(return(NULL))
128-
f
86+
create_layer_wrapper(r_cls)
12987
}

0 commit comments

Comments
 (0)