forked from huawei/mindspore2022
add history and lambda callbacks
This commit is contained in:
parent
81ff4f4440
commit
7afcdfd211
|
|
@ -29,7 +29,9 @@ from ._summary_collector import SummaryCollector
|
||||||
from ._lr_scheduler_callback import LearningRateScheduler
|
from ._lr_scheduler_callback import LearningRateScheduler
|
||||||
from ._landscape import SummaryLandscape
|
from ._landscape import SummaryLandscape
|
||||||
from ._fl_manager import FederatedLearningManager
|
from ._fl_manager import FederatedLearningManager
|
||||||
|
from ._history import History
|
||||||
|
from ._lambda_callback import LambdaCallback
|
||||||
|
|
||||||
__all__ = ["Callback", "LossMonitor", "TimeMonitor", "ModelCheckpoint",
|
__all__ = ["Callback", "LossMonitor", "TimeMonitor", "ModelCheckpoint",
|
||||||
"SummaryCollector", "CheckpointConfig", "RunContext", "LearningRateScheduler", "SummaryLandscape",
|
"SummaryCollector", "CheckpointConfig", "RunContext", "LearningRateScheduler", "SummaryLandscape",
|
||||||
"FederatedLearningManager"]
|
"FederatedLearningManager", "History", "LambdaCallback"]
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,81 @@
|
||||||
|
# Copyright 2021 Huawei Technologies Co., Ltd
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
# ============================================================================
|
||||||
|
"""History Callback class."""
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
from mindspore.common.tensor import Tensor
|
||||||
|
from ._callback import Callback
|
||||||
|
|
||||||
|
class History(Callback):
|
||||||
|
"""
|
||||||
|
Records the first element of network outputs into a `History` object.
|
||||||
|
|
||||||
|
The first element of network outputs is the loss value if not
|
||||||
|
custimizing the train network or eval network.
|
||||||
|
|
||||||
|
Note:
|
||||||
|
Normally used in `mindspore.Model.train`.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
>>> from mindspore import Model, nn
|
||||||
|
>>> data = {"x": np.float32(np.random.rand(64, 10)), "y": np.random.randint(0, 5, (64,))}
|
||||||
|
>>> train_dataset = ds.NumpySlicesDataset(data=data).batch(32)
|
||||||
|
>>> net = nn.Dense(10, 5)
|
||||||
|
>>> crit = nn.SoftmaxCrossEntropyWithLogits(sparse=True, reduction='mean')
|
||||||
|
>>> opt = nn.Momentum(net.trainable_params(), 0.01, 0.9)
|
||||||
|
>>> history_cb = History()
|
||||||
|
>>> model = Model(network=net, optimizer=opt, loss_fn=crit, metrics={"recall"})
|
||||||
|
>>> model.train(2, train_dataset, callbacks=[history_cb])
|
||||||
|
>>> print(history_cb.epoch)
|
||||||
|
>>> print(history_cb.history)
|
||||||
|
[1, 2]
|
||||||
|
{'net_output': [1.607877, 1.6033841]}
|
||||||
|
"""
|
||||||
|
def __init__(self):
|
||||||
|
super(History, self).__init__()
|
||||||
|
self.history = {}
|
||||||
|
|
||||||
|
def begin(self, run_context):
|
||||||
|
"""
|
||||||
|
Initialize the `epoch` property at the begin of training.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
run_context (RunContext): Context of the `mindspore.Model.train/eval`.
|
||||||
|
"""
|
||||||
|
self.epoch = []
|
||||||
|
|
||||||
|
def epoch_end(self, run_context):
|
||||||
|
"""
|
||||||
|
Records the first element of network outputs at the end of epoch.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
run_context (RunContext): Context of the `mindspore.Model.train/eval`.
|
||||||
|
"""
|
||||||
|
cb_params = run_context.original_args()
|
||||||
|
epoch = cb_params.get("cur_epoch_num", 1)
|
||||||
|
self.epoch.append(epoch)
|
||||||
|
net_output = cb_params.net_outputs
|
||||||
|
if isinstance(net_output, (tuple, list)):
|
||||||
|
if isinstance(net_output[0], Tensor) and isinstance(net_output[0].asnumpy(), np.ndarray):
|
||||||
|
net_output = net_output[0]
|
||||||
|
if isinstance(net_output, Tensor) and isinstance(net_output.asnumpy(), np.ndarray):
|
||||||
|
net_output = np.mean(net_output.asnumpy())
|
||||||
|
|
||||||
|
metrics = cb_params.get("metrics")
|
||||||
|
cur_history = {"net_output": net_output}
|
||||||
|
if metrics:
|
||||||
|
cur_history.update(metrics)
|
||||||
|
for k, v in cur_history.items():
|
||||||
|
self.history.setdefault(k, []).append(v)
|
||||||
|
|
@ -0,0 +1,58 @@
|
||||||
|
# Copyright 2021 Huawei Technologies Co., Ltd
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
# ============================================================================
|
||||||
|
"""Lambda Callback class."""
|
||||||
|
|
||||||
|
from ._callback import Callback
|
||||||
|
|
||||||
|
class LambdaCallback(Callback):
|
||||||
|
"""
|
||||||
|
Callback for creating simple, custom callbacks.
|
||||||
|
|
||||||
|
This callback is constructed with anonymous functions that will be called
|
||||||
|
at the appropriate time (during `mindspore.Model.{train | eval}`).
|
||||||
|
|
||||||
|
Note that each stage of callbacks expects one positional arguments: `run_context`.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
epoch_begin: called at the beginning of every epoch.
|
||||||
|
epoch_end: called at the end of every epoch.
|
||||||
|
step_begin: called at the beginning of every batch.
|
||||||
|
step_end: called at the end of every batch.
|
||||||
|
begin: called at the beginning of model train/eval.
|
||||||
|
end: called at the end of model train/eval.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
>>> from mindspore import Model, nn
|
||||||
|
>>> data = {"x": np.float32(np.random.rand(64, 10)), "y": np.random.randint(0, 5, (64,))}
|
||||||
|
>>> train_dataset = ds.NumpySlicesDataset(data=data).batch(32)
|
||||||
|
>>> net = nn.Dense(10, 5)
|
||||||
|
>>> crit = nn.SoftmaxCrossEntropyWithLogits(sparse=True, reduction='mean')
|
||||||
|
>>> opt = nn.Momentum(net.trainable_params(), 0.01, 0.9)
|
||||||
|
>>> lambda_callback = LambdaCallback(epoch_end=
|
||||||
|
... lambda run_context: print("loss: ", run_context.original_args().net_outputs))
|
||||||
|
>>> model = Model(network=net, optimizer=opt, loss_fn=crit, metrics={"recall"})
|
||||||
|
>>> model.train(2, train_dataset, callbacks=[lambda_callback])
|
||||||
|
loss: 1.6127687
|
||||||
|
loss: 1.6106578
|
||||||
|
"""
|
||||||
|
def __init__(self, epoch_begin=None, epoch_end=None, step_begin=None,
|
||||||
|
step_end=None, begin=None, end=None):
|
||||||
|
super(LambdaCallback, self).__init__()
|
||||||
|
self.epoch_begin = epoch_begin if epoch_begin else lambda run_context: None
|
||||||
|
self.epoch_end = epoch_end if epoch_end else lambda run_context: None
|
||||||
|
self.step_begin = step_begin if step_begin else lambda run_context: None
|
||||||
|
self.step_end = step_end if step_end else lambda run_context: None
|
||||||
|
self.begin = begin if begin else lambda run_context: None
|
||||||
|
self.end = end if end else lambda run_context: None
|
||||||
|
|
@ -27,7 +27,7 @@ from .callback._checkpoint import _chg_ckpt_file_name_if_same_exist
|
||||||
from ..common.tensor import Tensor
|
from ..common.tensor import Tensor
|
||||||
from ..nn.metrics import get_metrics
|
from ..nn.metrics import get_metrics
|
||||||
from .._checkparam import check_input_data, check_output_data, Validator
|
from .._checkparam import check_input_data, check_output_data, Validator
|
||||||
from .callback import _InternalCallbackParam, RunContext, _CallbackManager, Callback
|
from .callback import _InternalCallbackParam, RunContext, _CallbackManager, Callback, History
|
||||||
from .. import context
|
from .. import context
|
||||||
from ..parallel._utils import _get_parallel_mode, _get_device_num, _get_global_rank, \
|
from ..parallel._utils import _get_parallel_mode, _get_device_num, _get_global_rank, \
|
||||||
_get_parameter_broadcast, _device_number_check, _parameter_broadcast_check, _parallel_predict_check
|
_get_parameter_broadcast, _device_number_check, _parameter_broadcast_check, _parallel_predict_check
|
||||||
|
|
@ -940,6 +940,9 @@ class Model:
|
||||||
if isinstance(self._eval_network, nn.GraphCell) and dataset_sink_mode:
|
if isinstance(self._eval_network, nn.GraphCell) and dataset_sink_mode:
|
||||||
raise ValueError("Sink mode is currently not supported when evaluating with a GraphCell.")
|
raise ValueError("Sink mode is currently not supported when evaluating with a GraphCell.")
|
||||||
|
|
||||||
|
if callbacks and (isinstance(callbacks, History) or any(isinstance(cb, History) for cb in callbacks)):
|
||||||
|
logger.warning("History callback is recommended to be used in training process.")
|
||||||
|
|
||||||
cb_params = _InternalCallbackParam()
|
cb_params = _InternalCallbackParam()
|
||||||
cb_params.eval_network = self._eval_network
|
cb_params.eval_network = self._eval_network
|
||||||
cb_params.valid_dataset = valid_dataset
|
cb_params.valid_dataset = valid_dataset
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ from mindspore.common.tensor import Tensor
|
||||||
from mindspore.nn import TrainOneStepCell, WithLossCell
|
from mindspore.nn import TrainOneStepCell, WithLossCell
|
||||||
from mindspore.nn.optim import Momentum
|
from mindspore.nn.optim import Momentum
|
||||||
from mindspore.train.callback import ModelCheckpoint, RunContext, LossMonitor, _InternalCallbackParam, \
|
from mindspore.train.callback import ModelCheckpoint, RunContext, LossMonitor, _InternalCallbackParam, \
|
||||||
_CallbackManager, Callback, CheckpointConfig, _set_cur_net, _checkpoint_cb_for_save_op
|
_CallbackManager, Callback, CheckpointConfig, _set_cur_net, _checkpoint_cb_for_save_op, History, LambdaCallback
|
||||||
from mindspore.train.callback._checkpoint import _chg_ckpt_file_name_if_same_exist
|
from mindspore.train.callback._checkpoint import _chg_ckpt_file_name_if_same_exist
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -492,3 +492,58 @@ def test_step_end_save_graph():
|
||||||
os.remove('./test_files/test-graph.meta')
|
os.remove('./test_files/test-graph.meta')
|
||||||
ckpoint_cb.step_end(run_context)
|
ckpoint_cb.step_end(run_context)
|
||||||
assert not os.path.exists('./test_files/test-graph.meta')
|
assert not os.path.exists('./test_files/test-graph.meta')
|
||||||
|
|
||||||
|
|
||||||
|
def test_history():
|
||||||
|
"""
|
||||||
|
Feature: callback.
|
||||||
|
Description: Test history object saves epoch and history properties.
|
||||||
|
Expectation: run success.
|
||||||
|
"""
|
||||||
|
cb_params = _InternalCallbackParam()
|
||||||
|
cb_params.cur_epoch_num = 4
|
||||||
|
cb_params.epoch_num = 4
|
||||||
|
cb_params.cur_step_num = 2
|
||||||
|
cb_params.batch_num = 2
|
||||||
|
cb_params.net_outputs = Tensor(2.0)
|
||||||
|
cb_params.metrics = {'mae': 6.343789100646973, 'mse': 59.03999710083008}
|
||||||
|
|
||||||
|
run_context = RunContext(cb_params)
|
||||||
|
history_cb = History()
|
||||||
|
callbacks = [history_cb]
|
||||||
|
with _CallbackManager(callbacks) as callbacklist:
|
||||||
|
callbacklist.begin(run_context)
|
||||||
|
callbacklist.epoch_begin(run_context)
|
||||||
|
callbacklist.step_begin(run_context)
|
||||||
|
callbacklist.step_end(run_context)
|
||||||
|
callbacklist.epoch_end(run_context)
|
||||||
|
callbacklist.end(run_context)
|
||||||
|
print(history_cb.epoch)
|
||||||
|
print(history_cb.history)
|
||||||
|
|
||||||
|
|
||||||
|
def test_lambda():
|
||||||
|
"""
|
||||||
|
Feature: callback.
|
||||||
|
Description: Test lambda callback.
|
||||||
|
Expectation: run success.
|
||||||
|
"""
|
||||||
|
cb_params = _InternalCallbackParam()
|
||||||
|
cb_params.cur_epoch_num = 4
|
||||||
|
cb_params.epoch_num = 4
|
||||||
|
cb_params.cur_step_num = 2
|
||||||
|
cb_params.batch_num = 2
|
||||||
|
cb_params.net_outputs = Tensor(2.0)
|
||||||
|
|
||||||
|
run_context = RunContext(cb_params)
|
||||||
|
lambda_cb = LambdaCallback(
|
||||||
|
epoch_end=lambda run_context: print("loss result: ", run_context.original_args().net_outputs))
|
||||||
|
|
||||||
|
callbacks = [lambda_cb]
|
||||||
|
with _CallbackManager(callbacks) as callbacklist:
|
||||||
|
callbacklist.begin(run_context)
|
||||||
|
callbacklist.epoch_begin(run_context)
|
||||||
|
callbacklist.step_begin(run_context)
|
||||||
|
callbacklist.step_end(run_context)
|
||||||
|
callbacklist.epoch_end(run_context)
|
||||||
|
callbacklist.end(run_context)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue