From 64c7ce54682ae404e7566ccd1a9409317ff49230 Mon Sep 17 00:00:00 2001 From: yhcc Date: Tue, 31 May 2022 22:29:58 +0800 Subject: [PATCH 1/3] =?UTF-8?q?1.=E4=BF=AE=E5=A4=8Drich=E5=9C=A8jupyter?= =?UTF-8?q?=E7=9A=84=E6=97=B6=E5=80=99=E4=B8=8D=E6=89=93=E5=8D=B0=E7=9A=84?= =?UTF-8?q?=E9=97=AE=E9=A2=98;2.=E4=BF=AE=E5=A4=8D=E8=8B=A5=E5=B9=B2?= =?UTF-8?q?=E5=85=B6=E4=BB=96bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- fastNLP/core/callbacks/more_evaluate_callback.py | 3 ++- fastNLP/core/collators/collator.py | 4 ++-- fastNLP/core/collators/padders/exceptions.py | 9 +++++++- fastNLP/core/collators/padders/get_padder.py | 17 ++++++--------- fastNLP/core/collators/padders/jittor_padder.py | 2 +- fastNLP/core/collators/padders/torch_padder.py | 2 +- fastNLP/core/dataloaders/jittor_dataloader/fdl.py | 2 +- fastNLP/core/dataloaders/paddle_dataloader/fdl.py | 2 +- fastNLP/core/dataloaders/prepare_dataloader.py | 20 ++++++----------- fastNLP/core/dataloaders/torch_dataloader/fdl.py | 12 +++++------ fastNLP/core/utils/rich_progress.py | 25 +++++++++++++++++++--- fastNLP/models/torch/seq2seq_generator.py | 2 +- fastNLP/models/torch/seq2seq_model.py | 2 +- .../modules/torch/generator/seq2seq_generator.py | 4 ++-- tests/core/collators/test_collator.py | 7 ++++++ tests/core/dataloaders/test_prepare_dataloader.py | 17 ++++++++++++++- 16 files changed, 85 insertions(+), 45 deletions(-) diff --git a/fastNLP/core/callbacks/more_evaluate_callback.py b/fastNLP/core/callbacks/more_evaluate_callback.py index e11bacde..690146a2 100644 --- a/fastNLP/core/callbacks/more_evaluate_callback.py +++ b/fastNLP/core/callbacks/more_evaluate_callback.py @@ -81,7 +81,8 @@ class MoreEvaluateCallback(HasMonitorCallback): **kwargs): super(MoreEvaluateCallback, self).__init__(watch_monitor, watch_monitor_larger_better, must_have_monitor=False) - + if watch_monitor is not None and evaluate_every == -1: # 将evaluate_every 弄掉。 + evaluate_every = None if watch_monitor is None and evaluate_every is None: raise RuntimeError("`evaluate_every` and `watch_monitor` cannot be None at the same time.") if watch_monitor is not None and evaluate_every is not None: diff --git a/fastNLP/core/collators/collator.py b/fastNLP/core/collators/collator.py index 7fc11ec8..dab5028c 100644 --- a/fastNLP/core/collators/collator.py +++ b/fastNLP/core/collators/collator.py @@ -176,8 +176,8 @@ class Collator: self.padders = dict(sorted(self.padders.items(), key=lambda x:int(x[0][1:]))) # sort, 这样 _0, _1 能够保持顺序 try: for key, padder in self.padders.items(): - batch = unpack_batch.get(key) - pad_batch[key] = padder(batch) + batch = unpack_batch.get(key) + pad_batch[key] = padder(batch) except BaseException as e: try: logger.error(f"The following exception happens when try to pad the `{key}` field with padder:{padder}:") diff --git a/fastNLP/core/collators/padders/exceptions.py b/fastNLP/core/collators/padders/exceptions.py index 8b08683d..a2b97cbf 100644 --- a/fastNLP/core/collators/padders/exceptions.py +++ b/fastNLP/core/collators/padders/exceptions.py @@ -3,7 +3,8 @@ __all__ = [ 'EleDtypeUnsupportedError', 'EleDtypeDtypeConversionError', 'DtypeUnsupportedError', - "DtypeError" + "DtypeError", + "NoProperPadderError" ] @@ -22,6 +23,12 @@ class DtypeError(BaseException): self.msg = msg +class NoProperPadderError(BaseException): + def __init__(self, msg, *args): + super(NoProperPadderError, self).__init__(msg, *args) + self.msg = msg + + class EleDtypeUnsupportedError(DtypeError): """ 当 batch 中的 element 的类别本身无法 pad 的时候报错。 diff --git a/fastNLP/core/collators/padders/get_padder.py b/fastNLP/core/collators/padders/get_padder.py index 66d2eee2..dfc228a3 100644 --- a/fastNLP/core/collators/padders/get_padder.py +++ b/fastNLP/core/collators/padders/get_padder.py @@ -49,8 +49,7 @@ def get_padder(batch_field:Sequence[Any], pad_val, dtype, backend, field_name)-> f"information please set logger's level to DEBUG." if must_pad: raise InconsistencyError(msg) - logger.debug(msg) - return NullPadder() + raise NoProperPadderError(msg) # 再检查所有的元素 shape 是否一致? shape_lens = set([len(v[0]) for v in catalog.values()]) @@ -60,8 +59,7 @@ def get_padder(batch_field:Sequence[Any], pad_val, dtype, backend, field_name)-> f"information please set logger's level to DEBUG." if must_pad: raise InconsistencyError(msg) - logger.debug(msg) - return NullPadder() + raise NoProperPadderError(msg) # 再检查所有的元素 type 是否一致 try: @@ -74,8 +72,7 @@ def get_padder(batch_field:Sequence[Any], pad_val, dtype, backend, field_name)-> f"information please set logger's level to DEBUG." if must_pad: raise InconsistencyError(msg) - logger.debug(msg) - return NullPadder() + raise NoProperPadderError(msg) depth = depths.pop() shape_len = shape_lens.pop() @@ -131,8 +128,7 @@ def get_padder(batch_field:Sequence[Any], pad_val, dtype, backend, field_name)-> msg = "Does not support pad tensor under nested list. If you need this, please report." if must_pad: raise RuntimeError(msg) - logger.debug(msg) - return NullPadder() + raise NoProperPadderError(msg) except DtypeError as e: msg = f"Fail to get padder for field:{field_name}. " + e.msg + " To view more " \ @@ -140,8 +136,9 @@ def get_padder(batch_field:Sequence[Any], pad_val, dtype, backend, field_name)-> if must_pad: logger.error(msg) raise type(e)(msg=msg) - logger.debug(msg) - return NullPadder() + + except NoProperPadderError as e: + logger.debug(f"{e.msg}") except BaseException as e: raise e diff --git a/fastNLP/core/collators/padders/jittor_padder.py b/fastNLP/core/collators/padders/jittor_padder.py index d85893f1..c9b36b89 100644 --- a/fastNLP/core/collators/padders/jittor_padder.py +++ b/fastNLP/core/collators/padders/jittor_padder.py @@ -188,7 +188,7 @@ def fill_tensor(batch_field, padded_batch, dtype): padded_batch[i, j, :len(content_ii)] = jittor.Var(np.array(content_ii, dtype=dtype)) elif padded_batch.ndim == 4: try: # 应该是图像,所以直接应该就 ok 了。 - padded_batch = np.array(batch_field) + padded_batch = jittor.Var(batch_field) except: for i, content_i in enumerate(batch_field): for j, content_ii in enumerate(content_i): diff --git a/fastNLP/core/collators/padders/torch_padder.py b/fastNLP/core/collators/padders/torch_padder.py index c208adca..911c7d8c 100644 --- a/fastNLP/core/collators/padders/torch_padder.py +++ b/fastNLP/core/collators/padders/torch_padder.py @@ -175,7 +175,7 @@ def fill_tensor(batch_field, padded_batch, dtype): padded_batch[i, j, :len(content_ii)] = torch.tensor(content_ii, dtype=dtype) elif padded_batch.ndim == 4: try: # 应该是图像,所以直接应该就 ok 了。 - padded_batch = np.array(batch_field) + padded_batch = torch.tensor(batch_field) except: for i, content_i in enumerate(batch_field): for j, content_ii in enumerate(content_i): diff --git a/fastNLP/core/dataloaders/jittor_dataloader/fdl.py b/fastNLP/core/dataloaders/jittor_dataloader/fdl.py index 96f6747b..9f1d5e6f 100644 --- a/fastNLP/core/dataloaders/jittor_dataloader/fdl.py +++ b/fastNLP/core/dataloaders/jittor_dataloader/fdl.py @@ -203,7 +203,7 @@ def prepare_jittor_dataloader(ds_or_db, batch_size: int = 16, shuffle: bool = Fa drop_last: bool = False, num_workers: int = 0, buffer_size: int = 512 * 1024 * 1024, stop_grad: bool = True, keep_numpy_array: bool = False, endless: bool = False, collate_fn: Union[None, str, Callable] = "auto", - non_train_batch_size: int = 16) \ + non_train_batch_size: int = None) \ -> Union[Sequence[JittorDataLoader], Dict[str, JittorDataLoader], JittorDataLoader]: """ ``prepare_jittor_dataloader`` 的功能是将输入的单个或多个 dataset 同时转为 ``JittorDataloader``对象, 详见 :class: `~fastNLP.core.dataloaders.JittorDataLoader`。 diff --git a/fastNLP/core/dataloaders/paddle_dataloader/fdl.py b/fastNLP/core/dataloaders/paddle_dataloader/fdl.py index 3f1b6acd..50bac34b 100644 --- a/fastNLP/core/dataloaders/paddle_dataloader/fdl.py +++ b/fastNLP/core/dataloaders/paddle_dataloader/fdl.py @@ -254,7 +254,7 @@ def prepare_paddle_dataloader(ds_or_db, feed_list=None, places=None, num_workers: int = 0, use_buffer_reader: bool = True, use_shared_memory: bool = True, timeout: int = 0, worker_init_fn: Callable = None, persistent_workers=False, - non_train_batch_size: int = 16) \ + non_train_batch_size: int = None) \ -> Union[Sequence[PaddleDataLoader], Dict[str, PaddleDataLoader], PaddleDataLoader]: """ ``prepare_paddle_dataloader`` 的功能是将输入的单个或多个 dataset 同时转为 ``PaddleDataloader``对象, 详见 :class: `~fastNLP.core.dataloaders.PaddleDataLoader`。 diff --git a/fastNLP/core/dataloaders/prepare_dataloader.py b/fastNLP/core/dataloaders/prepare_dataloader.py index 358578fc..f717841d 100644 --- a/fastNLP/core/dataloaders/prepare_dataloader.py +++ b/fastNLP/core/dataloaders/prepare_dataloader.py @@ -6,7 +6,6 @@ from typing import Union, Callable import os import sys -from ..samplers import RandomBatchSampler, RandomSampler from .torch_dataloader import prepare_torch_dataloader from .paddle_dataloader import prepare_paddle_dataloader from .jittor_dataloader import prepare_jittor_dataloader @@ -16,7 +15,7 @@ from ..log import logger def prepare_dataloader(dataset, batch_size: int = 16, shuffle: bool = False, drop_last: bool = False, collate_fn: Union[Callable, str, None] = 'auto', num_workers: int = 0, - seed: int = 0, backend: str = 'auto'): + backend: str = 'auto'): """ 自动创建合适的 ``DataLoader`` 对象。例如,检测当当前环境是 ``torch`` 的,则返回 ``TorchDataLoader`` , 是 ``paddle`` 的则 返回 ``PaddleDataLoader`` 。如果有更多需要定制的参数,请直接使用对应的 ``prepare`` 函数,例如 @@ -43,7 +42,6 @@ def prepare_dataloader(dataset, batch_size: int = 16, shuffle: bool = False, dro * 为 ``None`` 时 使用各个框架的 DataLoader 的默认 ``collate_fn`` 。 :param num_workers: 使用多少进程进行数据的 fetch 。 - :param seed: 使用的随机数种子。 :param backend: 当前支持 ``["auto", "torch", "paddle", "jittor"]`` 四种类型。 * 为 ``auto`` 时 @@ -61,18 +59,14 @@ def prepare_dataloader(dataset, batch_size: int = 16, shuffle: bool = False, dro if backend == 'auto': backend = _get_backend() if backend == 'torch': - batch_sampler = RandomBatchSampler(dataset=dataset, batch_size=batch_size, shuffle=shuffle, - drop_last=drop_last, seed=seed) - return prepare_torch_dataloader(ds_or_db=dataset, batch_sampler=batch_sampler, collate_fn=collate_fn, - num_workers=num_workers, shuffle=False, sampler=None) + return prepare_torch_dataloader(ds_or_db=dataset, batch_sampler=None, collate_fn=collate_fn, + num_workers=num_workers, shuffle=shuffle, sampler=None, + batch_size=batch_size) elif backend == 'paddle': - batch_sampler = RandomBatchSampler(dataset=dataset, batch_size=batch_size, shuffle=shuffle, - drop_last=drop_last, seed=seed) - return prepare_paddle_dataloader(ds_or_db=dataset, batch_sampler=batch_sampler, collate_fn=collate_fn, - num_workers=num_workers) + return prepare_paddle_dataloader(ds_or_db=dataset, batch_sampler=None, collate_fn=collate_fn, + num_workers=num_workers, batch_size=batch_size, shuffle=shuffle) elif backend == 'jittor': - sampler = RandomSampler(dataset=dataset, shuffle=shuffle, seed=seed) - prepare_jittor_dataloader(ds_or_db=dataset, sampler=sampler, collate_fn=collate_fn, + prepare_jittor_dataloader(ds_or_db=dataset, sampler=None, collate_fn=collate_fn, num_workers=num_workers, batch_size=batch_size, shuffle=shuffle, drop_last=drop_last) else: diff --git a/fastNLP/core/dataloaders/torch_dataloader/fdl.py b/fastNLP/core/dataloaders/torch_dataloader/fdl.py index 4e208b3f..0ef98ae2 100644 --- a/fastNLP/core/dataloaders/torch_dataloader/fdl.py +++ b/fastNLP/core/dataloaders/torch_dataloader/fdl.py @@ -222,7 +222,7 @@ def prepare_torch_dataloader(ds_or_db, multiprocessing_context=None, generator=None, prefetch_factor: int = 2, persistent_workers: bool = False, non_train_sampler: Union["Sampler[int]", ReproducibleSampler, UnrepeatedSampler] = None, - non_train_batch_size: int = 16) \ + non_train_batch_size: int = None) \ -> Union[TorchDataLoader, Dict[str, TorchDataLoader], Sequence[TorchDataLoader]]: """ ``prepare_torch_dataloader`` 的功能是将输入的单个或多个 dataset 同时转为 ``TorchDataloader``对象, 详见 :class: `~fastNLP.core.dataloaders.TorchDataLoader`。 @@ -254,13 +254,13 @@ def prepare_torch_dataloader(ds_or_db, :param non_train_batch_size: 非 'train' 数据集的 ``TorchDataLoader`` 批次大小,默认为 ``16`` 且当 batch_sampler 为 None 有效。 :param shuffle: 是否打乱数据集, 默认为 ``False``。 :param sampler: 实现了 __len__() 和 __iter__() 的实例化对象,其 __iter__() 方法每次都会返回 dataset 的一个下标 index , - 默认为None, 当其不为 None 时, shuffle 参数无效。 + 默认为None, 当其不为 None 时, shuffle 参数无效。 :param non_train_sampler: 非 'train' 数据集的的实现了 __len__() 和 __iter__() 的实例化对象,其 __iter__() 方法每次都会返回 dataset 的一个下标 index , - 默认为None, 当其不为 None 时, shuffle 参数无效。 + 默认为None, 当其不为 None 时, shuffle 参数无效。 :param batch_sampler: 实现了 __len__() 和 __iter__() 的实例化对象,,其__iter__() 方法每次都会返回一个 List 对象, List中的值为 - dataset 的下标 index ;默认为 None,当其不为 None 时,bacth_size, sampler, shuffle 参数均失效。 + dataset 的下标 index ;默认为 None,当其不为 None 时,bacth_size, sampler, shuffle 参数均失效。 :param num_workers: 当 ``num_workers > 0`` 时, ``TorchDataLoader`` 会开启 num_workers 个子进程来处理数据, 可以加快 - 数据处理速度,但同时也消耗大量内存。 当 ``num_workers=0`` 时, 不开启子进程。 默认为 ``0``。 + 数据处理速度,但同时也消耗大量内存。 当 ``num_workers=0`` 时, 不开启子进程。 默认为 ``0``。 :param collate_fn: 用于从 dataset 取到的一个 batch 数据进行打包处理的 Callable 函数,其值应该为以下三个: ``[None, "auto", Callable]``. * callate_fn 为 'None' 时,需要注意的是此时传进来的 datset 类型不能为 :class:`~fastNLP.core.dataset.DataSet` , 当 collate_fn 为 ``None`` 时, @@ -273,7 +273,7 @@ def prepare_torch_dataloader(ds_or_db, :param pin_memory: 如果其为 ``True``, 那么 ``TorchDataLoader`` 会在返回数据张量之前将其 copy 到 cud a的 pin memory 中。 :param drop_last: 当 ``drop_last=True`` 时,``TorchDataLoader`` 会扔掉最后一个长度小于 ``batch_size`` 的 batch 数据; - 若 ``drop_last=False`` , 则会返回该 batch 数据。 默认为 ``False`` 。 + 若 ``drop_last=False`` , 则会返回该 batch 数据。 默认为 ``False`` 。 :param timeout: 子进程的输出队列获取数据的超时值 :param worker_init_fn: init 函数,如果不设置为 None ,则将会在每个子进程初始化时调用该函数。 :param multiprocessing_context: 多进程的上下文环境 diff --git a/fastNLP/core/utils/rich_progress.py b/fastNLP/core/utils/rich_progress.py index d8e9d45b..b28bb3f7 100644 --- a/fastNLP/core/utils/rich_progress.py +++ b/fastNLP/core/utils/rich_progress.py @@ -46,7 +46,6 @@ class DummyFRichProgress: class FRichProgress(Progress, metaclass=Singleton): def new_progess(self, *columns: Union[str, ProgressColumn], - console: Optional[Console] = None, # 这里将 auto_refresh 关掉是想要避免单独开启线程,同时也是为了避免pdb的时候会持续刷新 auto_refresh: bool = False, refresh_per_second: float = 10, @@ -81,7 +80,7 @@ class FRichProgress(Progress, metaclass=Singleton): self.expand = expand self.live = Live( - console=console or get_console(), + console=get_console(), auto_refresh=auto_refresh, refresh_per_second=refresh_per_second, transient=transient, @@ -92,6 +91,12 @@ class FRichProgress(Progress, metaclass=Singleton): self.get_time = get_time or self.console.get_time self.print = self.console.print self.log = self.console.log + self.auto_refresh = auto_refresh + self.transient = transient + self.redirect_stdout = redirect_stdout + self.redirect_stderr = redirect_stderr + self.refresh_per_second = refresh_per_second + self._need_renew_live = False return self @@ -125,7 +130,19 @@ class FRichProgress(Progress, metaclass=Singleton): from .tqdm_progress import f_tqdm_progress assert not f_tqdm_progress.not_empty(), "Cannot use rich before tqdm finish loop." - if self.live._started is False: + # 如果需要替换,应该是由于destroy的时候给换掉了 + if self._need_renew_live: + self.live = Live( + console=get_console(), + auto_refresh=self.auto_refresh, + refresh_per_second=self.refresh_per_second, + transient=self.transient, + redirect_stdout=self.redirect_stdout, + redirect_stderr=self.redirect_stderr, + get_renderable=self.get_renderable, + ) + self._need_renew_live = False + if not self.live.is_started: self.start() post_desc = fields.pop('post_desc', '') return super().add_task(description=description, @@ -155,6 +172,8 @@ class FRichProgress(Progress, metaclass=Singleton): setattr(self.live.console, 'line', lambda *args,**kwargs:...) self.live.stop() setattr(self.live.console, 'line', old_line) + # 在 jupyter 的情况下需要替换一下,不然会出不打印的问题。 + self._need_renew_live = True if is_notebook() else False def start(self) -> None: super().start() diff --git a/fastNLP/models/torch/seq2seq_generator.py b/fastNLP/models/torch/seq2seq_generator.py index 9ee723e5..68b405ba 100755 --- a/fastNLP/models/torch/seq2seq_generator.py +++ b/fastNLP/models/torch/seq2seq_generator.py @@ -65,7 +65,7 @@ class SequenceGeneratorModel(nn.Module): if tgt_seq_len is not None: mask = seq_len_to_mask(tgt_seq_len, max_len=tgt_tokens.size(1)) tgt_tokens = tgt_tokens.masked_fill(mask.eq(0), -100) - loss = F.cross_entropy(pred.transpose(1, 2), tgt_tokens) + loss = F.cross_entropy(pred[:, :-1].transpose(1, 2), tgt_tokens[:, 1:]) return {'loss': loss} def evaluate_step(self, src_tokens, src_seq_len=None): diff --git a/fastNLP/models/torch/seq2seq_model.py b/fastNLP/models/torch/seq2seq_model.py index 057fb93b..1420375e 100755 --- a/fastNLP/models/torch/seq2seq_model.py +++ b/fastNLP/models/torch/seq2seq_model.py @@ -59,7 +59,7 @@ class Seq2SeqModel(nn.Module): if tgt_seq_len is not None: mask = seq_len_to_mask(tgt_seq_len, max_len=tgt_tokens.size(1)) tgt_tokens = tgt_tokens.masked_fill(mask.eq(0), -100) - loss = F.cross_entropy(pred.transpose(1, 2), tgt_tokens) + loss = F.cross_entropy(pred[:, :-1].transpose(1, 2), tgt_tokens[:, 1:]) return {'loss': loss} def prepare_state(self, src_tokens, src_seq_len=None): diff --git a/fastNLP/modules/torch/generator/seq2seq_generator.py b/fastNLP/modules/torch/generator/seq2seq_generator.py index cf9c5306..b54eea28 100755 --- a/fastNLP/modules/torch/generator/seq2seq_generator.py +++ b/fastNLP/modules/torch/generator/seq2seq_generator.py @@ -368,13 +368,13 @@ def _beam_search_generate(decoder: Seq2SeqDecoder, tokens=None, state=None, max_ next_scores, ids = _scores.topk(2 * num_beams, dim=1, largest=True, sorted=True) _tokens = _tokens.view(batch_size, num_beams * (num_beams + 1)) next_tokens = _tokens.gather(dim=1, index=ids) # (batch_size, 2*num_beams) - from_which_beam = ids // (num_beams + 1) # (batch_size, 2*num_beams) + from_which_beam = torch.floor(ids / (num_beams + 1)).long() # (batch_size, 2*num_beams) else: scores = F.log_softmax(scores, dim=-1) # (batch_size * num_beams, vocab_size) _scores = scores + beam_scores[:, None] # (batch_size * num_beams, vocab_size) _scores = _scores.view(batch_size, -1) # (batch_size, num_beams*vocab_size) next_scores, ids = torch.topk(_scores, 2 * num_beams, dim=1, largest=True, sorted=True) # (bsz, 2*num_beams) - from_which_beam = ids // vocab_size # (batch_size, 2*num_beams) + from_which_beam = torch.floor(ids / vocab_size).long() # (batch_size, 2*num_beams) next_tokens = ids % vocab_size # (batch_size, 2*num_beams) # 接下来需要组装下一个batch的结果。 diff --git a/tests/core/collators/test_collator.py b/tests/core/collators/test_collator.py index 09ec4af8..8443ef92 100644 --- a/tests/core/collators/test_collator.py +++ b/tests/core/collators/test_collator.py @@ -318,6 +318,13 @@ class TestCollator: with pytest.raises(KeyError): collator.set_pad((1, 2)) + @pytest.mark.torch + def test_torch_4d(self): + collator = Collator(backend='torch') + data = [{'x': [[[0,1], [2,3]]]}, {'x': [[[0,1]]]}] + output = collator(data) + assert output['x'].size() == (2, 1, 2, 2) + @pytest.mark.torch def test_torch_dl(): diff --git a/tests/core/dataloaders/test_prepare_dataloader.py b/tests/core/dataloaders/test_prepare_dataloader.py index 223b7880..be6d5feb 100644 --- a/tests/core/dataloaders/test_prepare_dataloader.py +++ b/tests/core/dataloaders/test_prepare_dataloader.py @@ -2,6 +2,7 @@ import pytest from fastNLP import prepare_dataloader from fastNLP import DataSet +from fastNLP.io import DataBundle @pytest.mark.torch @@ -10,4 +11,18 @@ def test_torch(): ds = DataSet({"x": [[1, 2], [2, 3, 4], [4, 5, 6, 7]] * 10, "y": [1, 0, 1] * 10}) dl = prepare_dataloader(ds, batch_size=2, shuffle=True) for batch in dl: - assert isinstance(batch['x'], torch.Tensor) \ No newline at end of file + assert isinstance(batch['x'], torch.Tensor) + + +@pytest.mark.torch +def test_torch_data_bundle(): + import torch + ds = DataSet({"x": [[1, 2], [2, 3, 4], [4, 5, 6, 7]] * 10, "y": [1, 0, 1] * 10}) + dl = DataBundle() + dl.set_dataset(dataset=ds, name='train') + dl.set_dataset(dataset=ds, name='test') + dls = prepare_dataloader(dl, batch_size=2, shuffle=True) + for dl in dls.values(): + for batch in dl: + assert isinstance(batch['x'], torch.Tensor) + assert batch['x'].size(0) == 2 From e55ca8a1d1eb94bf3bc40cd6c598ce5e17f60e3f Mon Sep 17 00:00:00 2001 From: lxr-tech <1838593642@qq.com> Date: Tue, 31 May 2022 23:25:01 +0800 Subject: [PATCH 2/3] update example-12 lxr 220531 --- tutorials/fastnlp_tutorial_2.ipynb | 2 +- tutorials/fastnlp_tutorial_3.ipynb | 16 +- tutorials/fastnlp_tutorial_4.ipynb | 10 +- tutorials/fastnlp_tutorial_5.ipynb | 59 +++ tutorials/fastnlp_tutorial_6.ipynb | 59 +++ tutorials/fastnlp_tutorial_7.ipynb | 59 +++ tutorials/fastnlp_tutorial_8.ipynb | 59 +++ tutorials/fastnlp_tutorial_e1.ipynb | 14 +- tutorials/fastnlp_tutorial_e2.ipynb | 734 +++++++++++++++++++++++++++++---- tutorials/figures/E2-fig-pet-model.png | Bin 0 -> 57162 bytes 10 files changed, 916 insertions(+), 96 deletions(-) create mode 100644 tutorials/fastnlp_tutorial_5.ipynb create mode 100644 tutorials/fastnlp_tutorial_6.ipynb create mode 100644 tutorials/fastnlp_tutorial_7.ipynb create mode 100644 tutorials/fastnlp_tutorial_8.ipynb create mode 100644 tutorials/figures/E2-fig-pet-model.png diff --git a/tutorials/fastnlp_tutorial_2.ipynb b/tutorials/fastnlp_tutorial_2.ipynb index 3aa27c86..4ee9579f 100644 --- a/tutorials/fastnlp_tutorial_2.ipynb +++ b/tutorials/fastnlp_tutorial_2.ipynb @@ -867,7 +867,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.4" + "version": "3.7.13" }, "pycharm": { "stem_cell": { diff --git a/tutorials/fastnlp_tutorial_3.ipynb b/tutorials/fastnlp_tutorial_3.ipynb index 353e4645..172e1232 100644 --- a/tutorials/fastnlp_tutorial_3.ipynb +++ b/tutorials/fastnlp_tutorial_3.ipynb @@ -29,13 +29,7 @@ "\n", "### 1.1 dataloader 的职责描述\n", "\n", - "在`fastNLP 0.8`中,在数据加载模块`DataLoader`之前,还存在其他的一些模块,负责例如对文本数据\n", - "\n", - "  进行补零对齐,即 **核对器`collator`模块**,进行分词标注,即 **分词器`tokenizer`模块**\n", - "\n", - "  本节将对`fastNLP`中的核对器`collator`等展开介绍,分词器`tokenizer`将在下一节中详细介绍\n", - "\n", - "在`fastNLP 0.8`中,**核对器`collator`模块负责文本序列的补零对齐**,通过" + "在`fastNLP 0.8`中,在数据加载模块`DataLoader`之前" ] }, { @@ -45,13 +39,7 @@ "source": [ "### 1.2 dataloader 的基本使用\n", "\n", - "在`fastNLP 0.8`中,在数据加载模块`DataLoader`之前,还存在其他的一些模块,负责例如对文本数据\n", - "\n", - "  进行补零对齐,即 **核对器`collator`模块**,进行分词标注,即 **分词器`tokenizer`模块**\n", - "\n", - "  本节将对`fastNLP`中的核对器`collator`等展开介绍,分词器`tokenizer`将在下一节中详细介绍\n", - "\n", - "在`fastNLP 0.8`中,**核对器`collator`模块负责文本序列的补零对齐**,通过" + "在`fastNLP 0.8`中,在数据加载模块`DataLoader`之前," ] }, { diff --git a/tutorials/fastnlp_tutorial_4.ipynb b/tutorials/fastnlp_tutorial_4.ipynb index 532118b0..3e148bf3 100644 --- a/tutorials/fastnlp_tutorial_4.ipynb +++ b/tutorials/fastnlp_tutorial_4.ipynb @@ -5,21 +5,21 @@ "id": "fdd7ff16", "metadata": {}, "source": [ - "# T4. model 的搭建与 driver 的概念\n", + "# T4. trainer 和 evaluator 的深入介绍(一)\n", "\n", - "  1   fastNLP 中预训练模型的使用\n", + "  1   fastNLP 结合 pytorch 搭建模型\n", " \n", "    1.1   \n", "\n", "    1.2   \n", "\n", - "  2   fastNLP 中使用 Pytorch 搭建模型\n", + "  2   fastNLP 中的 driver 与 device\n", "\n", "    2.1   \n", "\n", "    2.2   \n", "\n", - "  3   fastNLP 中的 driver\n", + "  3   fastNLP 中 trainer 的补充介绍\n", "\n", "    3.1   \n", "\n", @@ -51,7 +51,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.4" + "version": "3.7.13" } }, "nbformat": 4, diff --git a/tutorials/fastnlp_tutorial_5.ipynb b/tutorials/fastnlp_tutorial_5.ipynb new file mode 100644 index 00000000..1e41a36e --- /dev/null +++ b/tutorials/fastnlp_tutorial_5.ipynb @@ -0,0 +1,59 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "fdd7ff16", + "metadata": {}, + "source": [ + "# T5. fastNLP 与 paddle 或 jittor 的结合\n", + "\n", + "  1   fastNLP 结合 paddle 训练模型\n", + " \n", + "    1.1   \n", + "\n", + "    1.2   \n", + "\n", + "  2   fastNLP 结合 jittor 训练模型\n", + "\n", + "    2.1   \n", + "\n", + "    2.2   \n", + "\n", + "  3   fastNLP 实现 paddle 与 pytorch 互转\n", + "\n", + "    3.1   \n", + "\n", + "    3.2   " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "08752c5a", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.13" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/tutorials/fastnlp_tutorial_6.ipynb b/tutorials/fastnlp_tutorial_6.ipynb new file mode 100644 index 00000000..bd4b37ed --- /dev/null +++ b/tutorials/fastnlp_tutorial_6.ipynb @@ -0,0 +1,59 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "fdd7ff16", + "metadata": {}, + "source": [ + "# T6. trainer 和 evaluator 的深入介绍(二)\n", + "\n", + "  1   fastNLP 中预定义模型 models\n", + " \n", + "    1.1   \n", + "\n", + "    1.2   \n", + "\n", + "  2   fastNLP 中预定义模型 modules\n", + " \n", + "    2.1   \n", + "\n", + "    2.2   \n", + "\n", + "  3   fastNLP 中的更多 metric 类型\n", + "\n", + "    3.1   \n", + "\n", + "    3.2   " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "08752c5a", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.13" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/tutorials/fastnlp_tutorial_7.ipynb b/tutorials/fastnlp_tutorial_7.ipynb new file mode 100644 index 00000000..0a7d6922 --- /dev/null +++ b/tutorials/fastnlp_tutorial_7.ipynb @@ -0,0 +1,59 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "fdd7ff16", + "metadata": {}, + "source": [ + "# T7. callback 自定义训练过程\n", + "\n", + "  1   \n", + " \n", + "    1.1   \n", + "\n", + "    1.2   \n", + "\n", + "  2   \n", + "\n", + "    2.1   \n", + "\n", + "    2.2   \n", + "\n", + "  3   \n", + "\n", + "    3.1   \n", + "\n", + "    3.2   " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "08752c5a", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.13" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/tutorials/fastnlp_tutorial_8.ipynb b/tutorials/fastnlp_tutorial_8.ipynb new file mode 100644 index 00000000..0664bc41 --- /dev/null +++ b/tutorials/fastnlp_tutorial_8.ipynb @@ -0,0 +1,59 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "fdd7ff16", + "metadata": {}, + "source": [ + "# T8. fastNLP 中的文件读取模块\n", + "\n", + "  1   fastNLP 中的 EmbedLoader 模块\n", + " \n", + "    1.1   \n", + "\n", + "    1.2   \n", + "\n", + "  2   fastNLP 中的 Loader 模块\n", + "\n", + "    2.1   \n", + "\n", + "    2.2   \n", + "\n", + "  3   fastNLP 中的 Pipe 模块\n", + "\n", + "    3.1   \n", + "\n", + "    3.2   " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "08752c5a", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.13" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/tutorials/fastnlp_tutorial_e1.ipynb b/tutorials/fastnlp_tutorial_e1.ipynb index 6ec04cb4..8897c800 100644 --- a/tutorials/fastnlp_tutorial_e1.ipynb +++ b/tutorials/fastnlp_tutorial_e1.ipynb @@ -6,7 +6,7 @@ "source": [ "  从这篇开始,我们将开启**`fastNLP v0.8 tutorial`的`example`系列**,在接下来的\n", "\n", - "  每篇`tutorial`里,我们将会介绍`fastNLP v0.8`在一些自然语言处理任务上的应用" + "  每篇`tutorial`里,我们将会介绍`fastNLP v0.8`在自然语言处理任务上的应用实例" ] }, { @@ -82,9 +82,9 @@ "\n", "  包含9个数据集,各语料的语言均为英语,涉及多个自然语言理解`NLU`任务,包括\n", "\n", - "    **`CoLA`**,文本分类任务,预测单句语法正误分类;**`SST2`**,文本分类任务,预测单句情感二分类\n", + "    **`CoLA`**,文本分类任务,预测单句语法正误分类;**`SST-2`**,文本分类任务,预测单句情感二分类\n", "\n", - "    **`MRPC`**,句对分类任务,预测句对语义一致性;**`STSB`**,相似度打分任务,预测句对语义相似度回归\n", + "    **`MRPC`**,句对分类任务,预测句对语义一致性;**`STS-B`**,相似度打分任务,预测句对语义相似度回归\n", "\n", "    **`QQP`**,句对分类任务,预测问题对语义一致性;**`MNLI`**,文本推理任务,预测句对蕴含/矛盾/中立预测\n", "\n", @@ -216,15 +216,15 @@ "\n", "  即使用较小的、不区分大小写的数据集,**对`bert-base`进行知识蒸馏后的版本**,结构上\n", "\n", - "  模型包含1个编码层、6个自注意力层,详解见本篇末尾,更多细节请参考[DistilBert论文](https://arxiv.org/pdf/1910.01108.pdf)\n", + "  包含**1个编码层**、**6个自注意力层**,**参数量`66M`**,详解见本篇末尾,更多请参考[DistilBert论文](https://arxiv.org/pdf/1910.01108.pdf)\n", "\n", - "首先,通过从`transformers`库中导入`AutoTokenizer`模块,使用`from_pretrained`函数初始化\n", + "首先,通过从`transformers`库中导入**`AutoTokenizer`模块**,**使用`from_pretrained`函数初始化**\n", "\n", "  此处的`use_fast`表示是否使用`tokenizer`的快速版本;尝试序列化示例数据,检查加载结果\n", "\n", - "  需要注意的是,处理后返回的两个键值,`'input_ids'`表示原始文本对应的词素编号序列\n", + "  需要注意的是,处理后返回的两个键值,**`'input_ids'`**表示原始文本对应的词素编号序列\n", "\n", - "    `'attention_mask'`表示自注意力运算时的掩模(标上`0`的部分对应`padding`的内容" + "    **`'attention_mask'`**表示自注意力运算时的掩模(标上`0`的部分对应`padding`的内容" ] }, { diff --git a/tutorials/fastnlp_tutorial_e2.ipynb b/tutorials/fastnlp_tutorial_e2.ipynb index 93143090..c8f4b7dc 100644 --- a/tutorials/fastnlp_tutorial_e2.ipynb +++ b/tutorials/fastnlp_tutorial_e2.ipynb @@ -25,31 +25,53 @@ "\n", "    将首先简单介绍提示学习模型的研究,以及与`fastNLP v0.8`结合的优势\n", "\n", - "**`prompt`**,**提示词、提词器**,最早出自**`PET`**,\n", + "**`prompt`**,**提示词**,最早出自论文[Exploiting Cloze Questions for Few Shot TC and NLI](https://arxiv.org/pdf/2001.07676.pdf)中的**`PET`模型**\n", "\n", - "  \n", + "    全称 **`Pattern-Exploiting Training`**,虽然文中并没有提到**`prompt`的说法,但仍视为其开山之作\n", "\n", - "**`prompt-based tuning`**,**基于提示的微调**,描述\n", + "  其大致思路包括,对于文本分类任务,假定输入文本为,后来被称`prompt`,后来被称`verbalizer`,\n", "\n", - "  **`prompt-based model`**,**基于提示的模型**\n", + "  其主要贡献在于,\n", "\n", - "**`prompt-based model`**,**基于提示的模型**,举例\n", + "\n", "\n", - "  案例一:**`P-Tuning v1`**\n", + "**`prompt-based tuning`**,**基于提示的微调**,\n", "\n", - "  案例二:**`PromptTuning`**\n", + "  xxxx,更多参考[prompt综述](https://arxiv.org/pdf/2107.13586.pdf)\n", "\n", - "  案例三:**`PrefixTuning`**\n", + "    以下列举些经典的`prompt-based tuning`案例,简单地介绍下`prompt-based tuning`的脉络\n", "\n", - "  案例四:**`SoftPrompt`**\n", + "  案例一:**`P-Tuning v1`**,详细内容参考[P-Tuning-v1论文](https://arxiv.org/pdf/2103.10385.pdf)\n", "\n", - "使用`fastNLP v0.8`实现`prompt-based model`的优势\n", + "    其主要贡献在于,\n", "\n", - "  \n", + "    其方法大致包括,\n", "\n", - "  本示例仍使用了`tutorial-E1`的`SST2`数据集,将`bert-base-uncased`作为基础模型\n", + "  案例二:**`PromptTuning`**,详细内容参考[PromptTuning论文](https://arxiv.org/pdf/2104.08691.pdf)\n", "\n", - "    在后续实现中,意图通过将连续的`prompt`与`model`拼接,解决`SST2`二分类任务" + "    其主要贡献在于,\n", + "\n", + "    其方法大致包括,\n", + "\n", + "  案例三:**`PrefixTuning`**,详细内容参考[PrefixTuning论文](https://arxiv.org/pdf/2101.00190.pdf)\n", + "\n", + "    其主要贡献在于,\n", + "\n", + "    其方法大致包括,\n", + "\n", + "通过上述介绍可以发现`prompt-based tuning`只是模型微调方式,独立于预训练模型基础`backbone`\n", + "\n", + "  目前,加载预训练模型的主流方法是使用`transformers`模块,而实现微调的框架则\n", + "\n", + "    可以是`pytorch`、`paddle`、`jittor`等,而不同框架间又存在不兼容的问题\n", + "\n", + "  因此,**使用`fastNLP v0.8`实现`prompt-based tuning`**,可以**很好地解决`paddle`等框架**\n", + "\n", + "    **和`transformers`模块之间的桥接**(`transformers`模块基于`pytorch`实现)\n", + "\n", + "本示例仍使用了`tutorial-E1`的`SST2`数据集、`distilbert-base-uncased`模型(便于比较\n", + "\n", + "  使用`pytorch`框架,通过将连续的`prompt`与`model`拼接,解决`SST2`二分类任务" ] }, { @@ -98,7 +120,7 @@ "print(transformers.__version__)\n", "\n", "task = 'sst2'\n", - "model_checkpoint = 'bert-base-uncased'" + "model_checkpoint = 'distilbert-base-uncased' # 'bert-base-uncased'" ] }, { @@ -111,20 +133,32 @@ "\n", "    以下首先简述`P-Tuning v2`的论文原理,并由此引出`fastNLP v0.8`的代码实践\n", "\n", - "`P-Tuning v2`出自论文 [Prompt Tuning Can Be Comparable to Fine-tuning Universally Across Scales and Tasks](https://arxiv.org/pdf/2110.07602.pdf)\n", + "**`P-Tuning v2`**出自论文[Prompt Tuning Can Be Comparable to Fine-tuning Universally Across Scales and Tasks](https://arxiv.org/pdf/2110.07602.pdf)\n", + "\n", + "  其主要贡献在于,**在`PrefixTuning`等深度提示学习基础上**,**提升了其在分类标注等`NLU`任务的表现**\n", + "\n", + "    并使之在中等规模模型,主要是**参数量在`100M-1B`区间的模型上**,**获得与全参数微调相同的效果**\n", + "\n", + "  其结构如图所示,通过**在输入序列的分类符`[CLS]`之前**,**加入前缀序列**(**序号对应嵌入是待训练的连续值向量**\n", + "\n", + "    **刺激模型在新任务下**,从`[CLS]`对应位置,**输出符合微调任务的输出**,从而达到适应微调任务的目的\n", + "\n", + "\n", "\n", - "  其主要贡献在于,在`PrefixTuning`等深度提示学习基础上,提升了其在分类标注等`NLU`任务的表现\n", + "本示例使用`bert-base-uncased`模型,作为`P-Tuning v2`的基础`backbone`,设置`requires_grad=False`\n", "\n", - "    并使之在中等规模模型,主要是参数量在`100M-1B`区间的模型上,获得与全参数微调相同的效果\n", + "    固定其参数不参与训练,**设置`pre_seq_len`长的`prefix_tokens`作为输入的提示前缀序列**\n", "\n", - "  其结构如图所示,\n", + "  **使用基于`nn.Embedding`的`prefix_encoder`为提示前缀嵌入**,通过`get_prompt`函数获取,再将之\n", "\n", - "" + "    拼接至批量内每笔数据前得到`inputs_embeds`,同时更新自注意力掩模`attention_mask`\n", + "\n", + "  将`inputs_embeds`、`attention_mask`和`labels`输入`backbone`,**得到输出包括`loss`和`logits`**" ] }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 2, "metadata": {}, "outputs": [], "source": [ @@ -178,24 +212,24 @@ "source": [ "接着,通过确定分类数量初始化模型实例,同时调用`torch.optim.AdamW`模块初始化优化器\n", "\n", - "  根据`P-Tuning v2`论文:*Generally, simple classification tasks prefer shorter prompts (less than 20)*\n", + "  根据`P-Tuning v2`论文:*`Generally, simple classification tasks prefer shorter prompts (less than 20)`*\n", "\n", "  此处`pre_seq_len`参数设定为`20`,学习率相应做出调整,其他内容和`tutorial-E1`中的内容一致" ] }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "Some weights of the model checkpoint at bert-base-uncased were not used when initializing BertForSequenceClassification: ['cls.predictions.transform.dense.bias', 'cls.predictions.decoder.weight', 'cls.predictions.transform.LayerNorm.weight', 'cls.predictions.transform.LayerNorm.bias', 'cls.seq_relationship.weight', 'cls.predictions.transform.dense.weight', 'cls.predictions.bias', 'cls.seq_relationship.bias']\n", - "- This IS expected if you are initializing BertForSequenceClassification from the checkpoint of a model trained on another task or with another architecture (e.g. initializing a BertForSequenceClassification model from a BertForPreTraining model).\n", - "- This IS NOT expected if you are initializing BertForSequenceClassification from the checkpoint of a model that you expect to be exactly identical (initializing a BertForSequenceClassification model from a BertForSequenceClassification model).\n", - "Some weights of BertForSequenceClassification were not initialized from the model checkpoint at bert-base-uncased and are newly initialized: ['classifier.bias', 'classifier.weight']\n", + "Some weights of the model checkpoint at distilbert-base-uncased were not used when initializing DistilBertForSequenceClassification: ['vocab_layer_norm.bias', 'vocab_layer_norm.weight', 'vocab_projector.weight', 'vocab_transform.bias', 'vocab_transform.weight', 'vocab_projector.bias']\n", + "- This IS expected if you are initializing DistilBertForSequenceClassification from the checkpoint of a model trained on another task or with another architecture (e.g. initializing a BertForSequenceClassification model from a BertForPreTraining model).\n", + "- This IS NOT expected if you are initializing DistilBertForSequenceClassification from the checkpoint of a model that you expect to be exactly identical (initializing a BertForSequenceClassification model from a BertForSequenceClassification model).\n", + "Some weights of DistilBertForSequenceClassification were not initialized from the model checkpoint at distilbert-base-uncased and are newly initialized: ['pre_classifier.weight', 'classifier.weight', 'pre_classifier.bias', 'classifier.bias']\n", "You should probably TRAIN this model on a down-stream task to be able to use it for predictions and inference.\n" ] } @@ -225,7 +259,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 4, "metadata": { "scrolled": false }, @@ -240,7 +274,7 @@ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "b72eeebd34354a88a99b2e07ec9a86df", + "model_id": "21cbd92c3397497d84dc10f017ec96f4", "version_major": 2, "version_minor": 0 }, @@ -262,30 +296,17 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "Loading cached processed dataset at /remote-home/xrliu/.cache/huggingface/datasets/glue/sst2/1.0.0/dacbe3125aa31d7f70367a07a8a9e72a5a0bfeb5fc42e75c9db75b96da6053ad/cache-18ec0e709f05e61e.arrow\n", - "Loading cached processed dataset at /remote-home/xrliu/.cache/huggingface/datasets/glue/sst2/1.0.0/dacbe3125aa31d7f70367a07a8a9e72a5a0bfeb5fc42e75c9db75b96da6053ad/cache-e2f02ee7442ad73e.arrow\n" + "Loading cached processed dataset at /remote-home/xrliu/.cache/huggingface/datasets/glue/sst2/1.0.0/dacbe3125aa31d7f70367a07a8a9e72a5a0bfeb5fc42e75c9db75b96da6053ad/cache-294e481a713c5754.arrow\n", + "Loading cached processed dataset at /remote-home/xrliu/.cache/huggingface/datasets/glue/sst2/1.0.0/dacbe3125aa31d7f70367a07a8a9e72a5a0bfeb5fc42e75c9db75b96da6053ad/cache-ed9d9258aaf0fb54.arrow\n", + "Loading cached processed dataset at /remote-home/xrliu/.cache/huggingface/datasets/glue/sst2/1.0.0/dacbe3125aa31d7f70367a07a8a9e72a5a0bfeb5fc42e75c9db75b96da6053ad/cache-f44c5576b89f9e6b.arrow\n" ] - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "d15505d825b34f649b719f1ff0d56114", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - " 0%| | 0/2 [00:00[22:53:00] INFO Running evaluator sanity check for 2 batches. trainer.py:592\n", + "\n" + ], + "text/plain": [ + "\u001b[2;36m[22:53:00]\u001b[0m\u001b[2;36m \u001b[0m\u001b[34mINFO \u001b[0m Running evaluator sanity check for \u001b[1;36m2\u001b[0m batches. \u001b]8;id=406635;file://../fastNLP/core/controllers/trainer.py\u001b\\\u001b[2mtrainer.py\u001b[0m\u001b]8;;\u001b\\\u001b[2m:\u001b[0m\u001b]8;id=951504;file://../fastNLP/core/controllers/trainer.py#592\u001b\\\u001b[2m592\u001b[0m\u001b]8;;\u001b\\\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Output()" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n"
+      ],
+      "text/plain": []
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "application/vnd.jupyter.widget-view+json": {
+       "model_id": "",
+       "version_major": 2,
+       "version_minor": 0
+      },
+      "text/plain": [
+       "Output()"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/html": [
+       "
\n",
+       "
\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
----------------------------- Eval. results on Epoch:1, Batch:0 -----------------------------\n",
+       "
\n" + ], + "text/plain": [ + "----------------------------- Eval. results on Epoch:\u001b[1;36m1\u001b[0m, Batch:\u001b[1;36m0\u001b[0m -----------------------------\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
{\n",
+       "  \"acc#acc\": 0.540625,\n",
+       "  \"total#acc\": 320.0,\n",
+       "  \"correct#acc\": 173.0\n",
+       "}\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m{\u001b[0m\n", + " \u001b[1;34m\"acc#acc\"\u001b[0m: \u001b[1;36m0.540625\u001b[0m,\n", + " \u001b[1;34m\"total#acc\"\u001b[0m: \u001b[1;36m320.0\u001b[0m,\n", + " \u001b[1;34m\"correct#acc\"\u001b[0m: \u001b[1;36m173.0\u001b[0m\n", + "\u001b[1m}\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "
\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
----------------------------- Eval. results on Epoch:2, Batch:0 -----------------------------\n",
+       "
\n" + ], + "text/plain": [ + "----------------------------- Eval. results on Epoch:\u001b[1;36m2\u001b[0m, Batch:\u001b[1;36m0\u001b[0m -----------------------------\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
{\n",
+       "  \"acc#acc\": 0.5,\n",
+       "  \"total#acc\": 320.0,\n",
+       "  \"correct#acc\": 160.0\n",
+       "}\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m{\u001b[0m\n", + " \u001b[1;34m\"acc#acc\"\u001b[0m: \u001b[1;36m0.5\u001b[0m,\n", + " \u001b[1;34m\"total#acc\"\u001b[0m: \u001b[1;36m320.0\u001b[0m,\n", + " \u001b[1;34m\"correct#acc\"\u001b[0m: \u001b[1;36m160.0\u001b[0m\n", + "\u001b[1m}\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "
\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
----------------------------- Eval. results on Epoch:3, Batch:0 -----------------------------\n",
+       "
\n" + ], + "text/plain": [ + "----------------------------- Eval. results on Epoch:\u001b[1;36m3\u001b[0m, Batch:\u001b[1;36m0\u001b[0m -----------------------------\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
{\n",
+       "  \"acc#acc\": 0.509375,\n",
+       "  \"total#acc\": 320.0,\n",
+       "  \"correct#acc\": 163.0\n",
+       "}\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m{\u001b[0m\n", + " \u001b[1;34m\"acc#acc\"\u001b[0m: \u001b[1;36m0.509375\u001b[0m,\n", + " \u001b[1;34m\"total#acc\"\u001b[0m: \u001b[1;36m320.0\u001b[0m,\n", + " \u001b[1;34m\"correct#acc\"\u001b[0m: \u001b[1;36m163.0\u001b[0m\n", + "\u001b[1m}\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "
\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
----------------------------- Eval. results on Epoch:4, Batch:0 -----------------------------\n",
+       "
\n" + ], + "text/plain": [ + "----------------------------- Eval. results on Epoch:\u001b[1;36m4\u001b[0m, Batch:\u001b[1;36m0\u001b[0m -----------------------------\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
{\n",
+       "  \"acc#acc\": 0.634375,\n",
+       "  \"total#acc\": 320.0,\n",
+       "  \"correct#acc\": 203.0\n",
+       "}\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m{\u001b[0m\n", + " \u001b[1;34m\"acc#acc\"\u001b[0m: \u001b[1;36m0.634375\u001b[0m,\n", + " \u001b[1;34m\"total#acc\"\u001b[0m: \u001b[1;36m320.0\u001b[0m,\n", + " \u001b[1;34m\"correct#acc\"\u001b[0m: \u001b[1;36m203.0\u001b[0m\n", + "\u001b[1m}\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "
\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
----------------------------- Eval. results on Epoch:5, Batch:0 -----------------------------\n",
+       "
\n" + ], + "text/plain": [ + "----------------------------- Eval. results on Epoch:\u001b[1;36m5\u001b[0m, Batch:\u001b[1;36m0\u001b[0m -----------------------------\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
{\n",
+       "  \"acc#acc\": 0.6125,\n",
+       "  \"total#acc\": 320.0,\n",
+       "  \"correct#acc\": 196.0\n",
+       "}\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m{\u001b[0m\n", + " \u001b[1;34m\"acc#acc\"\u001b[0m: \u001b[1;36m0.6125\u001b[0m,\n", + " \u001b[1;34m\"total#acc\"\u001b[0m: \u001b[1;36m320.0\u001b[0m,\n", + " \u001b[1;34m\"correct#acc\"\u001b[0m: \u001b[1;36m196.0\u001b[0m\n", + "\u001b[1m}\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "
\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
----------------------------- Eval. results on Epoch:6, Batch:0 -----------------------------\n",
+       "
\n" + ], + "text/plain": [ + "----------------------------- Eval. results on Epoch:\u001b[1;36m6\u001b[0m, Batch:\u001b[1;36m0\u001b[0m -----------------------------\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
{\n",
+       "  \"acc#acc\": 0.675,\n",
+       "  \"total#acc\": 320.0,\n",
+       "  \"correct#acc\": 216.0\n",
+       "}\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m{\u001b[0m\n", + " \u001b[1;34m\"acc#acc\"\u001b[0m: \u001b[1;36m0.675\u001b[0m,\n", + " \u001b[1;34m\"total#acc\"\u001b[0m: \u001b[1;36m320.0\u001b[0m,\n", + " \u001b[1;34m\"correct#acc\"\u001b[0m: \u001b[1;36m216.0\u001b[0m\n", + "\u001b[1m}\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "
\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
----------------------------- Eval. results on Epoch:7, Batch:0 -----------------------------\n",
+       "
\n" + ], + "text/plain": [ + "----------------------------- Eval. results on Epoch:\u001b[1;36m7\u001b[0m, Batch:\u001b[1;36m0\u001b[0m -----------------------------\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
{\n",
+       "  \"acc#acc\": 0.64375,\n",
+       "  \"total#acc\": 320.0,\n",
+       "  \"correct#acc\": 206.0\n",
+       "}\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m{\u001b[0m\n", + " \u001b[1;34m\"acc#acc\"\u001b[0m: \u001b[1;36m0.64375\u001b[0m,\n", + " \u001b[1;34m\"total#acc\"\u001b[0m: \u001b[1;36m320.0\u001b[0m,\n", + " \u001b[1;34m\"correct#acc\"\u001b[0m: \u001b[1;36m206.0\u001b[0m\n", + "\u001b[1m}\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "
\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
----------------------------- Eval. results on Epoch:8, Batch:0 -----------------------------\n",
+       "
\n" + ], + "text/plain": [ + "----------------------------- Eval. results on Epoch:\u001b[1;36m8\u001b[0m, Batch:\u001b[1;36m0\u001b[0m -----------------------------\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
{\n",
+       "  \"acc#acc\": 0.665625,\n",
+       "  \"total#acc\": 320.0,\n",
+       "  \"correct#acc\": 213.0\n",
+       "}\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m{\u001b[0m\n", + " \u001b[1;34m\"acc#acc\"\u001b[0m: \u001b[1;36m0.665625\u001b[0m,\n", + " \u001b[1;34m\"total#acc\"\u001b[0m: \u001b[1;36m320.0\u001b[0m,\n", + " \u001b[1;34m\"correct#acc\"\u001b[0m: \u001b[1;36m213.0\u001b[0m\n", + "\u001b[1m}\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "
\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
----------------------------- Eval. results on Epoch:9, Batch:0 -----------------------------\n",
+       "
\n" + ], + "text/plain": [ + "----------------------------- Eval. results on Epoch:\u001b[1;36m9\u001b[0m, Batch:\u001b[1;36m0\u001b[0m -----------------------------\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
{\n",
+       "  \"acc#acc\": 0.659375,\n",
+       "  \"total#acc\": 320.0,\n",
+       "  \"correct#acc\": 211.0\n",
+       "}\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m{\u001b[0m\n", + " \u001b[1;34m\"acc#acc\"\u001b[0m: \u001b[1;36m0.659375\u001b[0m,\n", + " \u001b[1;34m\"total#acc\"\u001b[0m: \u001b[1;36m320.0\u001b[0m,\n", + " \u001b[1;34m\"correct#acc\"\u001b[0m: \u001b[1;36m211.0\u001b[0m\n", + "\u001b[1m}\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "
\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
---------------------------- Eval. results on Epoch:10, Batch:0 -----------------------------\n",
+       "
\n" + ], + "text/plain": [ + "---------------------------- Eval. results on Epoch:\u001b[1;36m10\u001b[0m, Batch:\u001b[1;36m0\u001b[0m -----------------------------\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
{\n",
+       "  \"acc#acc\": 0.696875,\n",
+       "  \"total#acc\": 320.0,\n",
+       "  \"correct#acc\": 223.0\n",
+       "}\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m{\u001b[0m\n", + " \u001b[1;34m\"acc#acc\"\u001b[0m: \u001b[1;36m0.696875\u001b[0m,\n", + " \u001b[1;34m\"total#acc\"\u001b[0m: \u001b[1;36m320.0\u001b[0m,\n", + " \u001b[1;34m\"correct#acc\"\u001b[0m: \u001b[1;36m223.0\u001b[0m\n", + "\u001b[1m}\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n"
+      ],
+      "text/plain": []
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/html": [
+       "
\n",
+       "
\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "trainer.run(num_eval_batch_per_dl=10)" ] @@ -421,14 +976,55 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + "可以发现,其效果远远逊色于`fine-tuning`,这是因为`P-Tuning v2`虽然能够适应参数量\n", + "\n", + "  在`100M-1B`区间的模型,但是,**`distilbert-base`的参数量仅为`66M`**,无法触及其下限\n", + "\n", + "另一方面,**`fastNLP v0.8`不支持`jupyter`多卡**,所以无法在笔者的电脑/服务器上,完成\n", + "\n", + "  合适规模模型的学习,例如`110M`的`bert-base`模型,以及`340M`的`bert-large`模型" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 10, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Output()" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n"
+      ],
+      "text/plain": []
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/plain": [
+       "{'acc#acc': 0.737385, 'total#acc': 872.0, 'correct#acc': 643.0}"
+      ]
+     },
+     "execution_count": 10,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
    "source": [
     "trainer.evaluator.run()"
    ]
diff --git a/tutorials/figures/E2-fig-pet-model.png b/tutorials/figures/E2-fig-pet-model.png
new file mode 100644
index 0000000000000000000000000000000000000000..c3c377c08a0ba3199cca4fb3610aa0ad08ce41fb
GIT binary patch
literal 57162
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�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≪c&6C_5)4~dcVATcrkDTEXk
zqcK)T#%&&lX$M{5U#xMA+aN}4j?oH!j?rxF$>!et8ts{hYcP(@G1|5X0R{+8O5!HW
zbKin1h1$pLu8@k3%HJxGiU!0P81>6`K>?A^m1(|IB`r(|lir$>H|VNL@v
z-0L{fG}_urCMSR^4{pFYkvU7<84@GHnjkSUen^a@2Z@mZkQnKkEQDPA3XV>Lu_RP;
zts<`N!ZfaJ2o?qFw>5|?=Q!4Q`~u%x?t?_5O%=9RQR2piXm&~VgF6;13;*!
zCvU{mRbS%!Q1!(dQ*rjhXgG3WHu2O&WncNNOW3k&7)I@wi-r5=x6Qse_#Ec33W*V6O^_HFKO{!dgT%-HEJuuFh>hKewcblH=hwl46bW%2hAI1h#Oe#)h|s(e
zQxOBtgKUAvL6~t##{!Rvlttm>={cCZa~WJhkHh=g1}t#-8qUFi8dscBar*cu?zr}t
zaPoX>tvm#K-I;``JvNQ7t4^oXuR3)@NQ?+;g2c%9Au*C3Bt`~ckwa;QrZ^fwX%QU`
zrKv|=5|6N?GdPzVg7{+Y!$71D8%hgJ4bvJ*lX^&u2y24G$oL^Kk{%>R20&s&(F}p75tQLMd2*UDdZX_`>c5)+c3a>696-bN>prp1~^yEmf
z-qbbK3BMf#Vfp;_+i%DYlZ&3kQ0$N(xEDn(C@6zfg%Z_UDQ2SHc|
zw{GN#p5Q5+OG$c>@X8WWfyBrFnp&DfPmUDp%&nRN;WvXItcS|na?uk!rE{q*tr1>X
zLMo6L8Ax$$k?2X1VtuJ?sug}K2*P@3X=>po42zxQDTaj&qp{&hLRyd*8AwBOgXl?;
zVqGby&ZiGF!fGkMStfd-rx=!+BD#4)ijWv}f||w}(UT>`I+9Q<%j>Jd_f#K;IRL1L4#^Qv-1PpB004HMt8
zx>Ej*M1mm1X=!djWnKje6Y^9W!
zTul&$!+!>HqQvfAv-)ta17UuU7!d?P5ClO8kQfmJK@bE%2#^>N1VIo4K?sl-5d=XH
z1VIRp7!d?P5ClO8kQfmJK@bE%2#^>N1VIo4K?sl-5d=XH1VIRp7!d?P5ClO8kQfmJ
zK@bE%2#^>N1VIo4K?sl-5d=XH1VIRp7!d?P5ClO8kQfmJK@bE%2#^>N1VIo4LGS?o
d4-@rNX@HP30RR9107*qoM6N<$f&l;k|Nolj0H6Q>

literal 0
KcmV+b0RR6000031


From 2d838b8927b438db5773323d950b94ad0457e873 Mon Sep 17 00:00:00 2001
From: lxr-tech <1838593642@qq.com>
Date: Wed, 1 Jun 2022 23:15:21 +0800
Subject: [PATCH 3/3] update tutorial-45 lxr 220601

---
 tutorials/fastnlp_tutorial_0.ipynb  |  786 +++++++++++++-
 tutorials/fastnlp_tutorial_2.ipynb  |    4 +-
 tutorials/fastnlp_tutorial_4.ipynb  |  289 +++++-
 tutorials/fastnlp_tutorial_5.ipynb  | 1921 ++++++++++++++++++++++++++++++++++-
 tutorials/fastnlp_tutorial_6.ipynb  |   18 +-
 tutorials/fastnlp_tutorial_e1.ipynb |  556 +++++++++-
 tutorials/fastnlp_tutorial_e2.ipynb |   52 +-
 7 files changed, 3536 insertions(+), 90 deletions(-)

diff --git a/tutorials/fastnlp_tutorial_0.ipynb b/tutorials/fastnlp_tutorial_0.ipynb
index 245eaf91..8312353b 100644
--- a/tutorials/fastnlp_tutorial_0.ipynb
+++ b/tutorials/fastnlp_tutorial_0.ipynb
@@ -15,15 +15,15 @@
     "\n",
     "    1.3   trainer 内部初始化 evaluater\n",
     "\n",
-    "  2   使用 fastNLP 0.8 搭建 argmax 模型\n",
+    "  2   使用 fastNLP 搭建 argmax 模型\n",
     "\n",
     "    2.1   trainer_step 和 evaluator_step\n",
     "\n",
     "    2.2   trainer 和 evaluator 的参数匹配\n",
     "\n",
-    "    2.3   一个实际案例:argmax 模型\n",
+    "    2.3   示例:argmax 模型的搭建\n",
     "\n",
-    "  3   使用 fastNLP 0.8 训练 argmax 模型\n",
+    "  3   使用 fastNLP 训练 argmax 模型\n",
     " \n",
     "    3.1   trainer 外部初始化的 evaluator\n",
     "\n",
@@ -248,7 +248,7 @@
    "id": "f62b7bb1",
    "metadata": {},
    "source": [
-    "### 2.3 一个实际案例:argmax 模型\n",
+    "### 2.3 示例:argmax 模型的搭建\n",
     "\n",
     "下文将通过训练`argmax`模型,简单介绍如何`Trainer`模块的使用方式\n",
     "\n",
@@ -271,7 +271,7 @@
     "\n",
     "class ArgMaxModel(nn.Module):\n",
     "    def __init__(self, num_labels, feature_dimension):\n",
-    "        super(ArgMaxModel, self).__init__()\n",
+    "        nn.Module.__init__(self)\n",
     "        self.num_labels = num_labels\n",
     "\n",
     "        self.linear1 = nn.Linear(in_features=feature_dimension, out_features=10)\n",
@@ -434,7 +434,7 @@
     "\n",
     "  通过`progress_bar`设定进度条格式,默认为`\"auto\"`,此外还有`\"rich\"`、`\"raw\"`和`None`\n",
     "\n",
-    "    但对于`\"auto\"`和`\"rich\"`格式,在notebook中,进度条在训练结束后会被丢弃\n",
+    "    但对于`\"auto\"`和`\"rich\"`格式,在`jupyter`中,进度条会在训练结束后会被丢弃\n",
     "\n",
     "  通过`n_epochs`设定优化迭代轮数,默认为20;全部`Trainer`的全部变量与函数可以通过`dir(trainer)`查询"
    ]
@@ -489,7 +489,7 @@
     "\n",
     "  其中,可以通过参数`num_train_batch_per_epoch`决定每个`epoch`运行多少个`batch`后停止,默认全部\n",
     "\n",
-    "  此外,可以通过`inspect.getfullargspec(trainer.run)`查询`run`函数的全部参数列表"
+    "  `run`函数完成后在`jupyter`中没有输出保留,此外,通过`help(trainer.run)`可以查询`run`函数的详细内容"
    ]
   },
   {
@@ -590,7 +590,7 @@
     "\n",
     "  其中,可以通过参数`num_eval_batch_per_dl`决定每个`evaluate_dataloader`运行多少个`batch`停止,默认全部\n",
     "\n",
-    "  最终,输出形如`{'acc#acc': acc}`的字典,在notebook中,进度条在评测结束后会被丢弃"
+    "  最终,输出形如`{'acc#acc': acc}`的字典,在`jupyter`中,进度条会在评测结束后会被丢弃"
    ]
   },
   {
@@ -605,6 +605,20 @@
    "outputs": [
     {
      "data": {
+      "application/vnd.jupyter.widget-view+json": {
+       "model_id": "",
+       "version_major": 2,
+       "version_minor": 0
+      },
+      "text/plain": [
+       "Output()"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
       "text/html": [
        "
\n"
       ],
@@ -616,11 +630,11 @@
     {
      "data": {
       "text/html": [
-       "
{'acc#acc': 0.37, 'total#acc': 100.0, 'correct#acc': 37.0}\n",
+       "
{'acc#acc': 0.31, 'total#acc': 100.0, 'correct#acc': 31.0}\n",
        "
\n" ], "text/plain": [ - "\u001b[1m{\u001b[0m\u001b[32m'acc#acc'\u001b[0m: \u001b[1;36m0.37\u001b[0m, \u001b[32m'total#acc'\u001b[0m: \u001b[1;36m100.0\u001b[0m, \u001b[32m'correct#acc'\u001b[0m: \u001b[1;36m37.0\u001b[0m\u001b[1m}\u001b[0m\n" + "\u001b[1m{\u001b[0m\u001b[32m'acc#acc'\u001b[0m: \u001b[1;36m0.31\u001b[0m, \u001b[32m'total#acc'\u001b[0m: \u001b[1;36m100.0\u001b[0m, \u001b[32m'correct#acc'\u001b[0m: \u001b[1;36m31.0\u001b[0m\u001b[1m}\u001b[0m\n" ] }, "metadata": {}, @@ -629,7 +643,7 @@ { "data": { "text/plain": [ - "{'acc#acc': 0.37, 'total#acc': 100.0, 'correct#acc': 37.0}" + "{'acc#acc': 0.31, 'total#acc': 100.0, 'correct#acc': 31.0}" ] }, "execution_count": 9, @@ -650,9 +664,9 @@ "\n", "通过在初始化`trainer`实例时加入`evaluate_dataloaders`和`metrics`,可以实现在训练过程中进行评测\n", "\n", - "  通过`progress_bar`同时设定训练和评估进度条格式,在notebook中,在进度条训练结束后会被丢弃\n", + "  通过`progress_bar`同时设定训练和评估进度条格式,在`jupyter`中,在进度条训练结束后会被丢弃\n", "\n", - "  **通过`evaluate_every`设定评估频率**,可以为负数、正数或者函数:\n", + "  但是中间的评估结果仍会保留;**通过`evaluate_every`设定评估频率**,可以为负数、正数或者函数:\n", "\n", "    **为负数时**,**表示每隔几个`epoch`评估一次**;**为正数时**,**则表示每隔几个`batch`评估一次**" ] @@ -687,9 +701,9 @@ "source": [ "通过使用`Trainer`类的`run`函数,进行训练\n", "\n", - "  还可以通过参数`num_eval_sanity_batch`决定每次训练前运行多少个`evaluate_batch`进行评测,默认为2\n", + "  还可以通过**参数`num_eval_sanity_batch`决定每次训练前运行多少个`evaluate_batch`进行评测**,**默认为`2`**\n", "\n", - "  之所以“先评测后训练”,是为了保证训练很长时间的数据,不会在评测阶段出问题,故作此试探性评测" + "  之所以“先评测后训练”,是为了保证训练很长时间的数据,不会在评测阶段出问题,故作此**试探性评测**" ] }, { @@ -705,6 +719,33 @@ { "data": { "text/html": [ + "
[18:28:25] INFO     Running evaluator sanity check for 2 batches.              trainer.py:592\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[2;36m[18:28:25]\u001b[0m\u001b[2;36m \u001b[0m\u001b[34mINFO \u001b[0m Running evaluator sanity check for \u001b[1;36m2\u001b[0m batches. \u001b]8;id=549287;file://../fastNLP/core/controllers/trainer.py\u001b\\\u001b[2mtrainer.py\u001b[0m\u001b]8;;\u001b\\\u001b[2m:\u001b[0m\u001b]8;id=645362;file://../fastNLP/core/controllers/trainer.py#592\u001b\\\u001b[2m592\u001b[0m\u001b]8;;\u001b\\\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Output()" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ "
\n"
       ],
       "text/plain": []
@@ -714,6 +755,490 @@
     },
     {
      "data": {
+      "application/vnd.jupyter.widget-view+json": {
+       "model_id": "",
+       "version_major": 2,
+       "version_minor": 0
+      },
+      "text/plain": [
+       "Output()"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/html": [
+       "
\n",
+       "
\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
----------------------------- Eval. results on Epoch:1, Batch:0 -----------------------------\n",
+       "
\n" + ], + "text/plain": [ + "----------------------------- Eval. results on Epoch:\u001b[1;36m1\u001b[0m, Batch:\u001b[1;36m0\u001b[0m -----------------------------\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
{\n",
+       "  \"acc#acc\": 0.31,\n",
+       "  \"total#acc\": 100.0,\n",
+       "  \"correct#acc\": 31.0\n",
+       "}\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m{\u001b[0m\n", + " \u001b[1;34m\"acc#acc\"\u001b[0m: \u001b[1;36m0.31\u001b[0m,\n", + " \u001b[1;34m\"total#acc\"\u001b[0m: \u001b[1;36m100.0\u001b[0m,\n", + " \u001b[1;34m\"correct#acc\"\u001b[0m: \u001b[1;36m31.0\u001b[0m\n", + "\u001b[1m}\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "
\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
----------------------------- Eval. results on Epoch:2, Batch:0 -----------------------------\n",
+       "
\n" + ], + "text/plain": [ + "----------------------------- Eval. results on Epoch:\u001b[1;36m2\u001b[0m, Batch:\u001b[1;36m0\u001b[0m -----------------------------\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
{\n",
+       "  \"acc#acc\": 0.33,\n",
+       "  \"total#acc\": 100.0,\n",
+       "  \"correct#acc\": 33.0\n",
+       "}\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m{\u001b[0m\n", + " \u001b[1;34m\"acc#acc\"\u001b[0m: \u001b[1;36m0.33\u001b[0m,\n", + " \u001b[1;34m\"total#acc\"\u001b[0m: \u001b[1;36m100.0\u001b[0m,\n", + " \u001b[1;34m\"correct#acc\"\u001b[0m: \u001b[1;36m33.0\u001b[0m\n", + "\u001b[1m}\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "
\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
----------------------------- Eval. results on Epoch:3, Batch:0 -----------------------------\n",
+       "
\n" + ], + "text/plain": [ + "----------------------------- Eval. results on Epoch:\u001b[1;36m3\u001b[0m, Batch:\u001b[1;36m0\u001b[0m -----------------------------\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
{\n",
+       "  \"acc#acc\": 0.34,\n",
+       "  \"total#acc\": 100.0,\n",
+       "  \"correct#acc\": 34.0\n",
+       "}\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m{\u001b[0m\n", + " \u001b[1;34m\"acc#acc\"\u001b[0m: \u001b[1;36m0.34\u001b[0m,\n", + " \u001b[1;34m\"total#acc\"\u001b[0m: \u001b[1;36m100.0\u001b[0m,\n", + " \u001b[1;34m\"correct#acc\"\u001b[0m: \u001b[1;36m34.0\u001b[0m\n", + "\u001b[1m}\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "
\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
----------------------------- Eval. results on Epoch:4, Batch:0 -----------------------------\n",
+       "
\n" + ], + "text/plain": [ + "----------------------------- Eval. results on Epoch:\u001b[1;36m4\u001b[0m, Batch:\u001b[1;36m0\u001b[0m -----------------------------\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
{\n",
+       "  \"acc#acc\": 0.36,\n",
+       "  \"total#acc\": 100.0,\n",
+       "  \"correct#acc\": 36.0\n",
+       "}\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m{\u001b[0m\n", + " \u001b[1;34m\"acc#acc\"\u001b[0m: \u001b[1;36m0.36\u001b[0m,\n", + " \u001b[1;34m\"total#acc\"\u001b[0m: \u001b[1;36m100.0\u001b[0m,\n", + " \u001b[1;34m\"correct#acc\"\u001b[0m: \u001b[1;36m36.0\u001b[0m\n", + "\u001b[1m}\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "
\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
----------------------------- Eval. results on Epoch:5, Batch:0 -----------------------------\n",
+       "
\n" + ], + "text/plain": [ + "----------------------------- Eval. results on Epoch:\u001b[1;36m5\u001b[0m, Batch:\u001b[1;36m0\u001b[0m -----------------------------\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
{\n",
+       "  \"acc#acc\": 0.36,\n",
+       "  \"total#acc\": 100.0,\n",
+       "  \"correct#acc\": 36.0\n",
+       "}\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m{\u001b[0m\n", + " \u001b[1;34m\"acc#acc\"\u001b[0m: \u001b[1;36m0.36\u001b[0m,\n", + " \u001b[1;34m\"total#acc\"\u001b[0m: \u001b[1;36m100.0\u001b[0m,\n", + " \u001b[1;34m\"correct#acc\"\u001b[0m: \u001b[1;36m36.0\u001b[0m\n", + "\u001b[1m}\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "
\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
----------------------------- Eval. results on Epoch:6, Batch:0 -----------------------------\n",
+       "
\n" + ], + "text/plain": [ + "----------------------------- Eval. results on Epoch:\u001b[1;36m6\u001b[0m, Batch:\u001b[1;36m0\u001b[0m -----------------------------\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
{\n",
+       "  \"acc#acc\": 0.36,\n",
+       "  \"total#acc\": 100.0,\n",
+       "  \"correct#acc\": 36.0\n",
+       "}\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m{\u001b[0m\n", + " \u001b[1;34m\"acc#acc\"\u001b[0m: \u001b[1;36m0.36\u001b[0m,\n", + " \u001b[1;34m\"total#acc\"\u001b[0m: \u001b[1;36m100.0\u001b[0m,\n", + " \u001b[1;34m\"correct#acc\"\u001b[0m: \u001b[1;36m36.0\u001b[0m\n", + "\u001b[1m}\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "
\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
----------------------------- Eval. results on Epoch:7, Batch:0 -----------------------------\n",
+       "
\n" + ], + "text/plain": [ + "----------------------------- Eval. results on Epoch:\u001b[1;36m7\u001b[0m, Batch:\u001b[1;36m0\u001b[0m -----------------------------\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
{\n",
+       "  \"acc#acc\": 0.36,\n",
+       "  \"total#acc\": 100.0,\n",
+       "  \"correct#acc\": 36.0\n",
+       "}\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m{\u001b[0m\n", + " \u001b[1;34m\"acc#acc\"\u001b[0m: \u001b[1;36m0.36\u001b[0m,\n", + " \u001b[1;34m\"total#acc\"\u001b[0m: \u001b[1;36m100.0\u001b[0m,\n", + " \u001b[1;34m\"correct#acc\"\u001b[0m: \u001b[1;36m36.0\u001b[0m\n", + "\u001b[1m}\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "
\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
----------------------------- Eval. results on Epoch:8, Batch:0 -----------------------------\n",
+       "
\n" + ], + "text/plain": [ + "----------------------------- Eval. results on Epoch:\u001b[1;36m8\u001b[0m, Batch:\u001b[1;36m0\u001b[0m -----------------------------\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
{\n",
+       "  \"acc#acc\": 0.36,\n",
+       "  \"total#acc\": 100.0,\n",
+       "  \"correct#acc\": 36.0\n",
+       "}\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m{\u001b[0m\n", + " \u001b[1;34m\"acc#acc\"\u001b[0m: \u001b[1;36m0.36\u001b[0m,\n", + " \u001b[1;34m\"total#acc\"\u001b[0m: \u001b[1;36m100.0\u001b[0m,\n", + " \u001b[1;34m\"correct#acc\"\u001b[0m: \u001b[1;36m36.0\u001b[0m\n", + "\u001b[1m}\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "
\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
----------------------------- Eval. results on Epoch:9, Batch:0 -----------------------------\n",
+       "
\n" + ], + "text/plain": [ + "----------------------------- Eval. results on Epoch:\u001b[1;36m9\u001b[0m, Batch:\u001b[1;36m0\u001b[0m -----------------------------\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
{\n",
+       "  \"acc#acc\": 0.37,\n",
+       "  \"total#acc\": 100.0,\n",
+       "  \"correct#acc\": 37.0\n",
+       "}\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m{\u001b[0m\n", + " \u001b[1;34m\"acc#acc\"\u001b[0m: \u001b[1;36m0.37\u001b[0m,\n", + " \u001b[1;34m\"total#acc\"\u001b[0m: \u001b[1;36m100.0\u001b[0m,\n", + " \u001b[1;34m\"correct#acc\"\u001b[0m: \u001b[1;36m37.0\u001b[0m\n", + "\u001b[1m}\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "
\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
---------------------------- Eval. results on Epoch:10, Batch:0 -----------------------------\n",
+       "
\n" + ], + "text/plain": [ + "---------------------------- Eval. results on Epoch:\u001b[1;36m10\u001b[0m, Batch:\u001b[1;36m0\u001b[0m -----------------------------\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
{\n",
+       "  \"acc#acc\": 0.4,\n",
+       "  \"total#acc\": 100.0,\n",
+       "  \"correct#acc\": 40.0\n",
+       "}\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m{\u001b[0m\n", + " \u001b[1;34m\"acc#acc\"\u001b[0m: \u001b[1;36m0.4\u001b[0m,\n", + " \u001b[1;34m\"total#acc\"\u001b[0m: \u001b[1;36m100.0\u001b[0m,\n", + " \u001b[1;34m\"correct#acc\"\u001b[0m: \u001b[1;36m40.0\u001b[0m\n", + "\u001b[1m}\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { "text/html": [ "
\n"
       ],
@@ -748,6 +1273,20 @@
    "outputs": [
     {
      "data": {
+      "application/vnd.jupyter.widget-view+json": {
+       "model_id": "",
+       "version_major": 2,
+       "version_minor": 0
+      },
+      "text/plain": [
+       "Output()"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
       "text/html": [
        "
\n"
       ],
@@ -759,7 +1298,7 @@
     {
      "data": {
       "text/plain": [
-       "{'acc#acc': 0.47, 'total#acc': 100.0, 'correct#acc': 47.0}"
+       "{'acc#acc': 0.4, 'total#acc': 100.0, 'correct#acc': 40.0}"
       ]
      },
      "execution_count": 12,
@@ -773,9 +1312,222 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 13,
    "id": "db784d5b",
    "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "['__annotations__',\n",
+       " '__class__',\n",
+       " '__delattr__',\n",
+       " '__dict__',\n",
+       " '__dir__',\n",
+       " '__doc__',\n",
+       " '__eq__',\n",
+       " '__format__',\n",
+       " '__ge__',\n",
+       " '__getattribute__',\n",
+       " '__gt__',\n",
+       " '__hash__',\n",
+       " '__init__',\n",
+       " '__init_subclass__',\n",
+       " '__le__',\n",
+       " '__lt__',\n",
+       " '__module__',\n",
+       " '__ne__',\n",
+       " '__new__',\n",
+       " '__reduce__',\n",
+       " '__reduce_ex__',\n",
+       " '__repr__',\n",
+       " '__setattr__',\n",
+       " '__sizeof__',\n",
+       " '__str__',\n",
+       " '__subclasshook__',\n",
+       " '__weakref__',\n",
+       " '_check_callback_called_legality',\n",
+       " '_check_train_batch_loop_legality',\n",
+       " '_custom_callbacks',\n",
+       " '_driver',\n",
+       " '_evaluate_dataloaders',\n",
+       " '_fetch_matched_fn_callbacks',\n",
+       " '_set_num_eval_batch_per_dl',\n",
+       " '_train_batch_loop',\n",
+       " '_train_dataloader',\n",
+       " '_train_step',\n",
+       " '_train_step_signature_fn',\n",
+       " 'accumulation_steps',\n",
+       " 'add_callback_fn',\n",
+       " 'backward',\n",
+       " 'batch_idx_in_epoch',\n",
+       " 'batch_step_fn',\n",
+       " 'callback_manager',\n",
+       " 'check_batch_step_fn',\n",
+       " 'cur_epoch_idx',\n",
+       " 'data_device',\n",
+       " 'dataloader',\n",
+       " 'device',\n",
+       " 'driver',\n",
+       " 'driver_name',\n",
+       " 'epoch_evaluate',\n",
+       " 'evaluate_batch_step_fn',\n",
+       " 'evaluate_dataloaders',\n",
+       " 'evaluate_every',\n",
+       " 'evaluate_fn',\n",
+       " 'evaluator',\n",
+       " 'extract_loss_from_outputs',\n",
+       " 'fp16',\n",
+       " 'get_no_sync_context',\n",
+       " 'global_forward_batches',\n",
+       " 'has_checked_train_batch_loop',\n",
+       " 'input_mapping',\n",
+       " 'kwargs',\n",
+       " 'larger_better',\n",
+       " 'load_checkpoint',\n",
+       " 'load_model',\n",
+       " 'marker',\n",
+       " 'metrics',\n",
+       " 'model',\n",
+       " 'model_device',\n",
+       " 'monitor',\n",
+       " 'move_data_to_device',\n",
+       " 'n_epochs',\n",
+       " 'num_batches_per_epoch',\n",
+       " 'on',\n",
+       " 'on_after_backward',\n",
+       " 'on_after_optimizers_step',\n",
+       " 'on_after_trainer_initialized',\n",
+       " 'on_after_zero_grad',\n",
+       " 'on_before_backward',\n",
+       " 'on_before_optimizers_step',\n",
+       " 'on_before_zero_grad',\n",
+       " 'on_evaluate_begin',\n",
+       " 'on_evaluate_end',\n",
+       " 'on_exception',\n",
+       " 'on_fetch_data_begin',\n",
+       " 'on_fetch_data_end',\n",
+       " 'on_load_checkpoint',\n",
+       " 'on_load_model',\n",
+       " 'on_sanity_check_begin',\n",
+       " 'on_sanity_check_end',\n",
+       " 'on_save_checkpoint',\n",
+       " 'on_save_model',\n",
+       " 'on_train_batch_begin',\n",
+       " 'on_train_batch_end',\n",
+       " 'on_train_begin',\n",
+       " 'on_train_end',\n",
+       " 'on_train_epoch_begin',\n",
+       " 'on_train_epoch_end',\n",
+       " 'optimizers',\n",
+       " 'output_mapping',\n",
+       " 'progress_bar',\n",
+       " 'run',\n",
+       " 'run_evaluate',\n",
+       " 'save_checkpoint',\n",
+       " 'save_model',\n",
+       " 'start_batch_idx_in_epoch',\n",
+       " 'state',\n",
+       " 'step',\n",
+       " 'step_evaluate',\n",
+       " 'total_batches',\n",
+       " 'train_batch_loop',\n",
+       " 'train_dataloader',\n",
+       " 'train_fn',\n",
+       " 'train_step',\n",
+       " 'trainer_state',\n",
+       " 'zero_grad']"
+      ]
+     },
+     "execution_count": 13,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "dir(trainer)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 14,
+   "id": "953533c4",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Help on method run in module fastNLP.core.controllers.trainer:\n",
+      "\n",
+      "run(num_train_batch_per_epoch: int = -1, num_eval_batch_per_dl: int = -1, num_eval_sanity_batch: int = 2, resume_from: str = None, resume_training: bool = True, catch_KeyboardInterrupt=None) method of fastNLP.core.controllers.trainer.Trainer instance\n",
+      "    该函数是在 ``Trainer`` 初始化后用于真正开始训练的函数;\n",
+      "    \n",
+      "    注意如果是断点重训的第一次训练,即还没有保存任何用于断点重训的文件,那么其应当置 resume_from 为 None,并且使用 ``CheckpointCallback``\n",
+      "    去保存断点重训的文件;\n",
+      "    \n",
+      "    :param num_train_batch_per_epoch: 每个 epoch 训练多少个 batch 后停止,*-1* 表示使用 train_dataloader 本身的长度;\n",
+      "    :param num_eval_batch_per_dl: 每个 evaluate_dataloader 验证多少个 batch 停止,*-1* 表示使用 evaluate_dataloader 本身的长度;\n",
+      "    :param num_eval_sanity_batch: 在训练之前运行多少个 evaluation batch 来检测一下 evaluation 的过程是否有错误。为 0 表示不检测;\n",
+      "    :param resume_from: 从哪个路径下恢复 trainer 的状态,注意该值需要为一个文件夹,例如使用 ``CheckpointCallback`` 时帮助您创建的保存的子文件夹;\n",
+      "    :param resume_training: 是否按照 checkpoint 中训练状态恢复。如果为 False,则只恢复 model 和 optimizers 的状态;该参数如果为 ``True``,\n",
+      "        在下一次断点重训的时候我们会精确到上次训练截止的具体的 sample 进行训练;否则我们只会恢复 model 和 optimizers 的状态,而 ``Trainer`` 中的\n",
+      "        其余状态都是保持初始化时的状态不会改变;\n",
+      "    :param catch_KeyboardInterrupt: 是否捕获 KeyboardInterrupt;如果该参数为 ``True``,在训练时如果您使用 ``ctrl+c`` 来终止程序,\n",
+      "        ``Trainer`` 不会抛出异常,但是会提前退出,然后 ``trainer.run()`` 之后的代码会继续运行。注意该参数在您使用分布式训练的 ``Driver``\n",
+      "        时无效,例如 ``TorchDDPDriver``;非分布式训练的 ``Driver`` 下该参数默认为 True;\n",
+      "    \n",
+      "    .. warning::\n",
+      "    \n",
+      "        注意初始化的 ``Trainer`` 只能调用一次 ``run`` 函数,即之后的调用 ``run`` 函数实际不会运行,因为此时\n",
+      "        ``trainer.cur_epoch_idx == trainer.n_epochs``;\n",
+      "    \n",
+      "        这意味着如果您需要再次调用 ``run`` 函数,您需要重新再初始化一个 ``Trainer``;\n",
+      "    \n",
+      "    .. note::\n",
+      "    \n",
+      "        您可以使用 ``num_train_batch_per_epoch`` 来简单地对您的训练过程进行验证,例如,当您指定 ``num_train_batch_per_epoch=10`` 后,\n",
+      "        每一个 epoch 下实际训练的 batch 的数量则会被修改为 10。您可以先使用该值来设定一个较小的训练长度,在验证整体的训练流程没有错误后,再将\n",
+      "        该值设定为 **-1** 开始真正的训练;\n",
+      "    \n",
+      "        ``num_eval_batch_per_dl`` 的意思和 ``num_train_batch_per_epoch`` 类似,即您可以通过设定 ``num_eval_batch_per_dl`` 来验证\n",
+      "        整体的验证流程是否正确;\n",
+      "    \n",
+      "        ``num_eval_sanity_batch`` 的作用可能会让人产生迷惑,其本质和 ``num_eval_batch_per_dl`` 作用一致,但是其只被 ``Trainer`` 使用;\n",
+      "        并且其只会在训练的一开始使用,意思为:我们在训练的开始时会先使用 ``Evaluator``(如果其不为 ``None``) 进行验证,此时验证的 batch 的\n",
+      "        数量只有 ``num_eval_sanity_batch`` 个;但是对于 ``num_eval_batch_per_dl`` 而言,其表示在实际的整体的训练过程中,每次 ``Evaluator``\n",
+      "        进行验证时会验证的 batch 的数量。\n",
+      "    \n",
+      "        并且,在实际真正的训练中,``num_train_batch_per_epoch`` 和 ``num_eval_batch_per_dl`` 应当都被设置为 **-1**,但是 ``num_eval_sanity_batch``\n",
+      "        应当为一个很小的正整数,例如 2;\n",
+      "    \n",
+      "    .. note::\n",
+      "    \n",
+      "        参数 ``resume_from`` 和 ``resume_training`` 的设立是为了支持断点重训功能;仅当 ``resume_from`` 不为 ``None`` 时,``resume_training`` 才有效;\n",
+      "    \n",
+      "        断点重训的意思为将上一次训练过程中的 ``Trainer`` 的状态保存下来,包括模型和优化器的状态、当前训练过的 epoch 的数量、对于当前的 epoch\n",
+      "        已经训练过的 batch 的数量、callbacks 的状态等等;然后在下一次训练时直接加载这些状态,从而直接恢复到上一次训练过程的某一个具体时间点的状态开始训练;\n",
+      "    \n",
+      "        fastNLP 将断点重训分为了 **保存状态** 和 **恢复断点重训** 两部分:\n",
+      "    \n",
+      "            1. 您需要使用 ``CheckpointCallback`` 来保存训练过程中的 ``Trainer`` 的状态;具体详见 :class:`~fastNLP.core.callbacks.CheckpointCallback`;\n",
+      "            ``CheckpointCallback`` 会帮助您把 ``Trainer`` 的状态保存到一个具体的文件夹下,这个文件夹的名字由 ``CheckpointCallback`` 自己生成;\n",
+      "            2. 在第二次训练开始时,您需要找到您想要加载的 ``Trainer`` 状态所存放的文件夹,然后传入给参数 ``resume_from``;\n",
+      "    \n",
+      "        需要注意的是 **保存状态** 和 **恢复断点重训** 是互不影响的。\n",
+      "\n"
+     ]
+    }
+   ],
+   "source": [
+    "help(trainer.run)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "1bc7cb4a",
+   "metadata": {},
    "outputs": [],
    "source": []
   }
diff --git a/tutorials/fastnlp_tutorial_2.ipynb b/tutorials/fastnlp_tutorial_2.ipynb
index 4ee9579f..64c4bc8b 100644
--- a/tutorials/fastnlp_tutorial_2.ipynb
+++ b/tutorials/fastnlp_tutorial_2.ipynb
@@ -281,13 +281,13 @@
     "## 2. fastNLP 中的 tokenizer\n",
     "\n",
     "### 2.1 PreTrainTokenizer 的提出\n",
-    "\n",
+    "\n",
     "在`fastNLP 0.8`中,**使用`PreTrainedTokenizer`模块来为数据集中的词语进行词向量的标注**\n",
     "\n",
     "  需要注意的是,`PreTrainedTokenizer`模块的下载和导入**需要确保环境安装了`transformers`模块**\n",
diff --git a/tutorials/fastnlp_tutorial_4.ipynb b/tutorials/fastnlp_tutorial_4.ipynb
index 3e148bf3..ee5a0c6b 100644
--- a/tutorials/fastnlp_tutorial_4.ipynb
+++ b/tutorials/fastnlp_tutorial_4.ipynb
@@ -5,32 +5,292 @@
    "id": "fdd7ff16",
    "metadata": {},
    "source": [
-    "# T4. trainer 和 evaluator 的深入介绍(一)\n",
+    "# T4. trainer 和 evaluator 的深入介绍\n",
     "\n",
-    "  1   fastNLP 结合 pytorch 搭建模型\n",
+    "  1   fastNLP 中的更多 metric 类型\n",
+    "\n",
+    "    1.1   预定义的 metric 类型\n",
+    "\n",
+    "    1.2   自定义的 metric 类型\n",
+    "\n",
+    "  2   fastNLP 中 trainer 的补充介绍\n",
     " \n",
-    "    1.1   \n",
+    "    2.1   trainer 的提出构想 \n",
     "\n",
-    "    1.2   \n",
+    "    2.2   trainer 的内部结构\n",
     "\n",
-    "  2   fastNLP 中的 driver 与 device\n",
+    "    2.3   实例:\n",
     "\n",
-    "    2.1   \n",
+    "  3   fastNLP 中的 driver 与 device\n",
     "\n",
-    "    2.2   \n",
+    "    3.1   driver 的提出构想\n",
+    "\n",
+    "    3.2   device 与多卡训练"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "8d19220c",
+   "metadata": {},
+   "source": [
+    "## 1. fastNLP 中的更多 metric 类型\n",
     "\n",
-    "  3   fastNLP 中 trainer 的补充介绍\n",
+    "### 1.1  预定义的 metric 类型\n",
     "\n",
-    "    3.1   \n",
+    "在`fastNLP 0.8`中,除了前几篇`tutorial`中经常见到的**正确率`Accuracy`**,还有其他**预定义的评价标准`metric`**\n",
+    "\n",
+    "  包括**所有`metric`的基类`Metric`**、适配`Transformers`中相关模型的正确率`TransformersAccuracy`\n",
+    "\n",
+    "    **适用于分类语境下的`F1`值`ClassifyFPreRecMetric`**(其中也包括**召回率`Pre`**、**精确率`Rec`**\n",
+    "\n",
+    "    **适用于抽取语境下的`F1`值`SpanFPreRecMetric`**;相关基本信息内容见下表,之后是详细分析\n",
+    "\n",
+    "| 
代码名称
|
简要介绍
|
代码路径
|\n", + "|:--|:--|:--|\n", + "| `Metric` | 定义`metrics`时继承的基类 | `/core/metrics/metric.py` |\n", + "| `Accuracy` | 正确率,最为常用 | `/core/metrics/accuracy.py` |\n", + "| `TransformersAccuracy` | 正确率,为了兼容`Transformers`中相关模型 | `/core/metrics/accuracy.py` |\n", + "| `ClassifyFPreRecMetric` | 召回率、精确率、F1值,适用于**分类问题** | `/core/metrics/classify_f1_pre_rec_metric.py` |\n", + "| `SpanFPreRecMetric` | 召回率、精确率、F1值,适用于**抽取问题** | `/core/metrics/span_f1_pre_rec_metric.py` |" + ] + }, + { + "cell_type": "markdown", + "id": "fdc083a3", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "source": [ + "大概的描述一下,给出各个正确率的计算公式" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9775ea5e", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "8a22f522", + "metadata": {}, + "source": [ + "### 2.2 自定义的 metric 类型\n", "\n", - "    3.2   " + "在`fastNLP 0.8`中,  给一个案例,训练部分留到trainer部分" ] }, { "cell_type": "code", "execution_count": null, + "id": "d8caba1d", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4e6247dd", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", "id": "08752c5a", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "## 2. fastNLP 中 trainer 的补充介绍\n", + "\n", + "### 2.1 trainer 的提出构想\n", + "\n", + "在`fastNLP 0.8`中,  " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "977a6355", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "69203cdc", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "ab1cea7d", + "metadata": {}, + "source": [ + "### 2.2 trainer 的内部结构\n", + "\n", + "在`fastNLP 0.8`中,  \n", + "\n", + "'accumulation_steps', 'add_callback_fn', 'backward', 'batch_idx_in_epoch', 'batch_step_fn',\n", + "'callback_manager', 'check_batch_step_fn', 'cur_epoch_idx', 'data_device', 'dataloader',\n", + "'device', 'driver', 'driver_name', 'epoch_evaluate', 'evaluate_batch_step_fn', 'evaluate_dataloaders',\n", + "'evaluate_every', 'evaluate_fn', 'evaluator', 'extract_loss_from_outputs', 'fp16',\n", + "'get_no_sync_context', 'global_forward_batches', 'has_checked_train_batch_loop',\n", + "'input_mapping', 'kwargs', 'larger_better', 'load_checkpoint', 'load_model', 'marker',\n", + "'metrics', 'model', 'model_device', 'monitor', 'move_data_to_device', 'n_epochs', 'num_batches_per_epoch',\n", + "'on', 'on_after_backward', 'on_after_optimizers_step', 'on_after_trainer_initialized',\n", + "'on_after_zero_grad', 'on_before_backward', 'on_before_optimizers_step', 'on_before_zero_grad',\n", + "'on_evaluate_begin', 'on_evaluate_end', 'on_exception', 'on_fetch_data_begin', 'on_fetch_data_end',\n", + "'on_load_checkpoint', 'on_load_model', 'on_sanity_check_begin', 'on_sanity_check_end',\n", + "'on_save_checkpoint', 'on_save_model', 'on_train_batch_begin', 'on_train_batch_end',\n", + "'on_train_begin', 'on_train_end', 'on_train_epoch_begin', 'on_train_epoch_end',\n", + "'optimizers', 'output_mapping', 'progress_bar', 'run', 'run_evaluate',\n", + "'save_checkpoint', 'save_model', 'start_batch_idx_in_epoch', 'state',\n", + "'step', 'step_evaluate', 'total_batches', 'train_batch_loop', 'train_dataloader', 'train_fn', 'train_step',\n", + "'trainer_state', 'zero_grad'\n", + "\n", + "  run(num_train_batch_per_epoch: int = -1, num_eval_batch_per_dl: int = -1, num_eval_sanity_batch: int = 2, resume_from: str = None, resume_training: bool = True, catch_KeyboardInterrupt=None)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b3c8342e", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d28f2624", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "ce6322b4", "metadata": {}, + "source": [ + "### 2.3 实例:\n", + "\n", + "在`fastNLP 0.8`中,  " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "43be274f", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c348864c", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "175d6ebb", + "metadata": {}, + "source": [ + "## 3. fastNLP 中的 driver 与 device\n", + "\n", + "### 3.1 driver 的提出构想\n", + "\n", + "在`fastNLP 0.8`中,  " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "47100e7a", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0204a223", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "6e723b87", + "metadata": {}, + "source": [ + "### 3.2 device 与多卡训练\n", + "\n", + "在`fastNLP 0.8`中,  " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5ad81ac7", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cfb28b1b", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [], "source": [] } @@ -52,6 +312,15 @@ "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.13" + }, + "pycharm": { + "stem_cell": { + "cell_type": "raw", + "metadata": { + "collapsed": false + }, + "source": [] + } } }, "nbformat": 4, diff --git a/tutorials/fastnlp_tutorial_5.ipynb b/tutorials/fastnlp_tutorial_5.ipynb index 1e41a36e..cb105c89 100644 --- a/tutorials/fastnlp_tutorial_5.ipynb +++ b/tutorials/fastnlp_tutorial_5.ipynb @@ -5,31 +5,1930 @@ "id": "fdd7ff16", "metadata": {}, "source": [ - "# T5. fastNLP 与 paddle 或 jittor 的结合\n", + "# T5. fastNLP 中的预定义模型\n", "\n", - "  1   fastNLP 结合 paddle 训练模型\n", + "  1   fastNLP 中 modules 的介绍\n", " \n", - "    1.1   \n", + "    1.1   modules 模块、models 模块 简介\n", "\n", - "    1.2   \n", + "    1.2   示例一:modules 实现 LSTM 分类\n", "\n", - "  2   fastNLP 结合 jittor 训练模型\n", + "  2   fastNLP 中 models 的介绍\n", + " \n", + "    2.1   示例一:models 实现 CNN 分类\n", "\n", - "    2.1   \n", + "    2.3   示例二:models 实现 BiLSTM 标注" + ] + }, + { + "cell_type": "markdown", + "id": "d3d65d53", + "metadata": {}, + "source": [ + "## 1. fastNLP 中 modules 模块的介绍\n", "\n", - "    2.2   \n", + "### 1.1 modules 模块、models 模块 简介\n", "\n", - "  3   fastNLP 实现 paddle 与 pytorch 互转\n", + "在`fastNLP 0.8`中,**`modules.torch`路径下定义了一些基于`pytorch`实现的基础模块**\n", "\n", - "    3.1   \n", + "    包括长短期记忆网络`LSTM`、条件随机场`CRF`、`transformer`的编解码器模块等,详见下表\n", "\n", - "    3.2   " + "|
代码名称
|
简要介绍
|
代码路径
|\n", + "|:--|:--|:--|\n", + "| `LSTM` | 轻量封装`pytorch`的`LSTM` | `/modules/torch/encoder/lstm.py` |\n", + "| `Seq2SeqEncoder` | 序列变换编码器,基类 | `/modules/torch/encoder/seq2seq_encoder.py` |\n", + "| `LSTMSeq2SeqEncoder` | 序列变换编码器,基于`LSTM` | `/modules/torch/encoder/seq2seq_encoder.py` |\n", + "| `TransformerSeq2SeqEncoder` | 序列变换编码器,基于`transformer` | `/modules/torch/encoder/seq2seq_encoder.py` |\n", + "| `StarTransformer` | `Star-Transformer`的编码器部分 | `/modules/torch/encoder/star_transformer.py` |\n", + "| `VarRNN` | 实现`Variational Dropout RNN` | `/modules/torch/encoder/variational_rnn.py` |\n", + "| `VarLSTM` | 实现`Variational Dropout LSTM` | `/modules/torch/encoder/variational_rnn.py` |\n", + "| `VarGRU` | 实现`Variational Dropout GRU` | `/modules/torch/encoder/variational_rnn.py` |\n", + "| `ConditionalRandomField` | 条件随机场模型 | `/modules/torch/decoder/crf.py` |\n", + "| `Seq2SeqDecoder` | 序列变换解码器,基类 | `/modules/torch/decoder/seq2seq_decoder.py` |\n", + "| `LSTMSeq2SeqDecoder` | 序列变换解码器,基于`LSTM` | `/modules/torch/decoder/seq2seq_decoder.py` |\n", + "| `TransformerSeq2SeqDecoder` | 序列变换解码器,基于`transformer` | `/modules/torch/decoder/seq2seq_decoder.py` |\n", + "| `SequenceGenerator` | 序列生成,封装`Seq2SeqDecoder` | `/models/torch/sequence_labeling.py` |\n", + "| `TimestepDropout` | 在每个`timestamp`上`dropout` | `/modules/torch/dropout.py` |" + ] + }, + { + "cell_type": "markdown", + "id": "89ffcf07", + "metadata": {}, + "source": [ + "  **`models.torch`路径下定义了一些基于`pytorch`、`modules`实现的预定义模型** \n", + "\n", + "    例如基于`CNN`的分类模型、基于`BiLSTM+CRF`的标注模型、基于[双仿射注意力机制](https://arxiv.org/pdf/1611.01734.pdf)的分析模型\n", + "\n", + "    基于`modules.torch`中的`LSTM`/`transformer`编/解码器模块的序列变换/生成模型,详见下表\n", + "\n", + "|
代码名称
|
简要介绍
|
代码路径
|\n", + "|:--|:--|:--|\n", + "| `BiaffineParser` | 句法分析模型,基于双仿射注意力 | `/models/torch/biaffine_parser.py` |\n", + "| `CNNText` | 文本分类模型,基于`CNN` | `/models/torch/cnn_text_classification.py` |\n", + "| `Seq2SeqModel` | 序列变换,基类`encoder+decoder` | `/models/torch/seq2seq_model.py` |\n", + "| `LSTMSeq2SeqModel` | 序列变换,基于`LSTM` | `/models/torch/seq2seq_model.py` |\n", + "| `TransformerSeq2SeqModel` | 序列变换,基于`transformer` | `/models/torch/seq2seq_model.py` |\n", + "| `SequenceGeneratorModel` | 封装`Seq2SeqModel`,结合`SequenceGenerator` | `/models/torch/seq2seq_generator.py` |\n", + "| `SeqLabeling` | 标注模型,基类`LSTM+FC+CRF` | `/models/torch/sequence_labeling.py` |\n", + "| `BiLSTMCRF` | 标注模型,`BiLSTM+FC+CRF` | `/models/torch/sequence_labeling.py` |\n", + "| `AdvSeqLabel` | 标注模型,`LN+BiLSTM*2+LN+FC+CRF` | `/models/torch/sequence_labeling.py` |" + ] + }, + { + "cell_type": "markdown", + "id": "61318354", + "metadata": {}, + "source": [ + "上述`fastNLP`模块,不仅**为入门级用户提供了简单易用的工具**,以解决各种`NLP`任务,或复现相关论文\n", + "\n", + "  同时**也为专业研究人员提供了便捷可操作的接口**,封装部分代码的同时,也能指定参数修改细节\n", + "\n", + "  在接下来的`tutorial`中,我们将通过`SST-2`分类和`CoNLL-2003`标注,展示相关模型使用\n", + "\n", + "注一:**`SST`**,**单句情感分类**数据集,包含电影评论和对应情感极性,1 对应正面情感,0 对应负面情感\n", + "\n", + "  数据集包括三部分:训练集 67350 条,验证集 873 条,测试集 1821 条,更多参考[下载链接](https://gluebenchmark.com/tasks)\n", + "\n", + "注二:**`CoNLL-2003`**,**文本语法标注**数据集,包含语句和对应的词性标签`pos_tags`(名动形数量代)\n", + "\n", + "  语法结构标签`chunk_tags`(主谓宾定状补)、命名实体标签`ner_tags`(人名、组织名、地名、时间等)\n", + "\n", + "  数据集包括三部分:训练集 14041 条,验证集 3250 条,测试集 3453 条,更多参考[原始论文](https://aclanthology.org/W03-0419.pdf)" + ] + }, + { + "cell_type": "markdown", + "id": "2a36bbe4", + "metadata": {}, + "source": [ + "### 1.2 示例一:modules 实现 LSTM 分类" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "40e66b21", + "metadata": {}, + "outputs": [], + "source": [ + "# import sys\n", + "# sys.path.append('..')\n", + "\n", + "# from fastNLP.io import SST2Pipe # 没有 SST2Pipe 会运行很长时间,并且还会报错\n", + "\n", + "# databundle = SST2Pipe(tokenizer='raw').process_from_file()\n", + "\n", + "# dataset = databundle.get_dataset('train')[:6000]\n", + "\n", + "# dataset.apply_more(lambda ins:{'words': ins['sentence'].lower().split(), 'target': ins['label']}, \n", + "# progress_bar=\"tqdm\")\n", + "# dataset.delete_field('sentence')\n", + "# dataset.delete_field('label')\n", + "# dataset.delete_field('idx')\n", + "\n", + "# from fastNLP import Vocabulary\n", + "\n", + "# vocab = Vocabulary()\n", + "# vocab.from_dataset(dataset, field_name='words')\n", + "# vocab.index_dataset(dataset, field_name='words')\n", + "\n", + "# train_dataset, evaluate_dataset = dataset.split(ratio=0.85)" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "50960476", + "metadata": {}, + "outputs": [], + "source": [ + "# from fastNLP import prepare_torch_dataloader\n", + "\n", + "# train_dataloader = prepare_torch_dataloader(train_dataset, batch_size=16, shuffle=True)\n", + "# evaluate_dataloader = prepare_torch_dataloader(evaluate_dataset, batch_size=16)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "0b25b25c", + "metadata": {}, + "outputs": [], + "source": [ + "# import torch\n", + "# import torch.nn as nn\n", + "\n", + "# from fastNLP.modules.torch import LSTM, MLP # 没有 MLP\n", + "# from fastNLP import Embedding, CrossEntropyLoss\n", + "\n", + "\n", + "# class ClsByModules(nn.Module):\n", + "# def __init__(self, vocab_size, embedding_dim, output_dim, hidden_dim=64, num_layers=2, dropout=0.5):\n", + "# nn.Module.__init__(self)\n", + "\n", + "# self.embedding = Embedding((vocab_size, embedding_dim))\n", + "# self.lstm = LSTM(embedding_dim, hidden_dim, num_layers=num_layers, bidirectional=True)\n", + "# self.mlp = MLP([hidden_dim * 2, output_dim], dropout=dropout)\n", + " \n", + "# self.loss_fn = CrossEntropyLoss()\n", + "\n", + "# def forward(self, words):\n", + "# output = self.embedding(words)\n", + "# output, (hidden, cell) = self.lstm(output)\n", + "# output = self.mlp(torch.cat((hidden[-1], hidden[-2]), dim=1))\n", + "# return output\n", + " \n", + "# def train_step(self, words, target):\n", + "# pred = self(words)\n", + "# return {\"loss\": self.loss_fn(pred, target)}\n", + "\n", + "# def evaluate_step(self, words, target):\n", + "# pred = self(words)\n", + "# pred = torch.max(pred, dim=-1)[1]\n", + "# return {\"pred\": pred, \"target\": target}" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "9dbbf50d", + "metadata": {}, + "outputs": [], + "source": [ + "# model = ClsByModules(vocab_size=len(vocabulary), embedding_dim=100, output_dim=2)\n", + "\n", + "# from torch.optim import AdamW\n", + "\n", + "# optimizers = AdamW(params=model.parameters(), lr=5e-5)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "7a93432f", + "metadata": {}, + "outputs": [], + "source": [ + "# from fastNLP import Trainer, Accuracy\n", + "\n", + "# trainer = Trainer(\n", + "# model=model,\n", + "# driver='torch',\n", + "# device=0, # 'cuda'\n", + "# n_epochs=10,\n", + "# optimizers=optimizers,\n", + "# train_dataloader=train_dataloader,\n", + "# evaluate_dataloaders=evaluate_dataloader,\n", + "# metrics={'acc': Accuracy()}\n", + "# )" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "31102e0f", + "metadata": {}, + "outputs": [], + "source": [ + "# trainer.run(num_eval_batch_per_dl=10)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "8bc4bfb2", + "metadata": {}, + "outputs": [], + "source": [ + "# trainer.evaluator.run()" + ] + }, + { + "cell_type": "markdown", + "id": "d9443213", + "metadata": {}, + "source": [ + "## 2. fastNLP 中 models 模块的介绍\n", + "\n", + "### 2.1 示例一:models 实现 CNN 分类\n", + "\n", + "  本示例使用`fastNLP 0.8`中预定义模型`models`中的`CNNText`模型,实现`SST-2`文本二分类任务\n", + "\n", + "模型使用方面,如上所述,这里使用**基于卷积神经网络`CNN`的预定义文本分类模型`CNNText`**,结构如下所示\n", + "\n", + "  首先是内置的`100`维嵌入层、`dropout`层、紧接着是三个一维卷积,将`100`维嵌入特征,分别通过\n", + "\n", + "    **感受野为`1`、`3`、`5`的卷积算子变换至`30`维、`40`维、`50`维的卷积特征**,再将三者拼接\n", + "\n", + "  最终再次通过`dropout`层、线性变换层,映射至二元的输出值,对应两个分类结果上的几率`logits`\n", + "\n", + "```\n", + "CNNText(\n", + " (embed): Embedding(\n", + " (embed): Embedding(5194, 100)\n", + " (dropout): Dropout(p=0.0, inplace=False)\n", + " )\n", + " (conv_pool): ConvMaxpool(\n", + " (convs): ModuleList(\n", + " (0): Conv1d(100, 30, kernel_size=(1,), stride=(1,), bias=False)\n", + " (1): Conv1d(100, 40, kernel_size=(3,), stride=(1,), padding=(1,), bias=False)\n", + " (2): Conv1d(100, 50, kernel_size=(5,), stride=(1,), padding=(2,), bias=False)\n", + " )\n", + " )\n", + " (dropout): Dropout(p=0.1, inplace=False)\n", + " (fc): Linear(in_features=120, out_features=2, bias=True)\n", + ")\n", + "```\n", + "\n", + "数据使用方面,此处**使用`datasets`模块中的`load_dataset`函数**,以如下形式,指定`SST-2`数据集自动加载\n", + "\n", + "  首次下载后会保存至`~/.cache/huggingface/modules/datasets_modules/datasets/glue/`目录下" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "1aa5cf6d", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Using the latest cached version of the module from /remote-home/xrliu/.cache/huggingface/modules/datasets_modules/datasets/glue/dacbe3125aa31d7f70367a07a8a9e72a5a0bfeb5fc42e75c9db75b96da6053ad (last modified on Thu May 26 15:30:15 2022) since it couldn't be found locally at glue., or remotely on the Hugging Face Hub.\n", + "Reusing dataset glue (/remote-home/xrliu/.cache/huggingface/datasets/glue/sst2/1.0.0/dacbe3125aa31d7f70367a07a8a9e72a5a0bfeb5fc42e75c9db75b96da6053ad)\n" + ] + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "70cde65067c64fdba1d5e798e2b8d631", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + " 0%| | 0/3 [00:00\n", + "
\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Processing: 0%| | 0/6000 [00:00[17:45:59] INFO Running evaluator sanity check for 2 batches. trainer.py:592\n", + "\n" + ], + "text/plain": [ + "\u001b[2;36m[17:45:59]\u001b[0m\u001b[2;36m \u001b[0m\u001b[34mINFO \u001b[0m Running evaluator sanity check for \u001b[1;36m2\u001b[0m batches. \u001b]8;id=147745;file://../fastNLP/core/controllers/trainer.py\u001b\\\u001b[2mtrainer.py\u001b[0m\u001b]8;;\u001b\\\u001b[2m:\u001b[0m\u001b]8;id=708408;file://../fastNLP/core/controllers/trainer.py#592\u001b\\\u001b[2m592\u001b[0m\u001b]8;;\u001b\\\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Output()" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n"
+      ],
+      "text/plain": []
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "application/vnd.jupyter.widget-view+json": {
+       "model_id": "",
+       "version_major": 2,
+       "version_minor": 0
+      },
+      "text/plain": [
+       "Output()"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/html": [
+       "
\n",
+       "
\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
----------------------------- Eval. results on Epoch:1, Batch:0 -----------------------------\n",
+       "
\n" + ], + "text/plain": [ + "----------------------------- Eval. results on Epoch:\u001b[1;36m1\u001b[0m, Batch:\u001b[1;36m0\u001b[0m -----------------------------\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
{\n",
+       "  \"acc#acc\": 0.575,\n",
+       "  \"total#acc\": 160.0,\n",
+       "  \"correct#acc\": 92.0\n",
+       "}\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m{\u001b[0m\n", + " \u001b[1;34m\"acc#acc\"\u001b[0m: \u001b[1;36m0.575\u001b[0m,\n", + " \u001b[1;34m\"total#acc\"\u001b[0m: \u001b[1;36m160.0\u001b[0m,\n", + " \u001b[1;34m\"correct#acc\"\u001b[0m: \u001b[1;36m92.0\u001b[0m\n", + "\u001b[1m}\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "
\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
----------------------------- Eval. results on Epoch:2, Batch:0 -----------------------------\n",
+       "
\n" + ], + "text/plain": [ + "----------------------------- Eval. results on Epoch:\u001b[1;36m2\u001b[0m, Batch:\u001b[1;36m0\u001b[0m -----------------------------\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
{\n",
+       "  \"acc#acc\": 0.75625,\n",
+       "  \"total#acc\": 160.0,\n",
+       "  \"correct#acc\": 121.0\n",
+       "}\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m{\u001b[0m\n", + " \u001b[1;34m\"acc#acc\"\u001b[0m: \u001b[1;36m0.75625\u001b[0m,\n", + " \u001b[1;34m\"total#acc\"\u001b[0m: \u001b[1;36m160.0\u001b[0m,\n", + " \u001b[1;34m\"correct#acc\"\u001b[0m: \u001b[1;36m121.0\u001b[0m\n", + "\u001b[1m}\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "
\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
----------------------------- Eval. results on Epoch:3, Batch:0 -----------------------------\n",
+       "
\n" + ], + "text/plain": [ + "----------------------------- Eval. results on Epoch:\u001b[1;36m3\u001b[0m, Batch:\u001b[1;36m0\u001b[0m -----------------------------\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
{\n",
+       "  \"acc#acc\": 0.78125,\n",
+       "  \"total#acc\": 160.0,\n",
+       "  \"correct#acc\": 125.0\n",
+       "}\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m{\u001b[0m\n", + " \u001b[1;34m\"acc#acc\"\u001b[0m: \u001b[1;36m0.78125\u001b[0m,\n", + " \u001b[1;34m\"total#acc\"\u001b[0m: \u001b[1;36m160.0\u001b[0m,\n", + " \u001b[1;34m\"correct#acc\"\u001b[0m: \u001b[1;36m125.0\u001b[0m\n", + "\u001b[1m}\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "
\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
----------------------------- Eval. results on Epoch:4, Batch:0 -----------------------------\n",
+       "
\n" + ], + "text/plain": [ + "----------------------------- Eval. results on Epoch:\u001b[1;36m4\u001b[0m, Batch:\u001b[1;36m0\u001b[0m -----------------------------\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
{\n",
+       "  \"acc#acc\": 0.8,\n",
+       "  \"total#acc\": 160.0,\n",
+       "  \"correct#acc\": 128.0\n",
+       "}\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m{\u001b[0m\n", + " \u001b[1;34m\"acc#acc\"\u001b[0m: \u001b[1;36m0.8\u001b[0m,\n", + " \u001b[1;34m\"total#acc\"\u001b[0m: \u001b[1;36m160.0\u001b[0m,\n", + " \u001b[1;34m\"correct#acc\"\u001b[0m: \u001b[1;36m128.0\u001b[0m\n", + "\u001b[1m}\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "
\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
----------------------------- Eval. results on Epoch:5, Batch:0 -----------------------------\n",
+       "
\n" + ], + "text/plain": [ + "----------------------------- Eval. results on Epoch:\u001b[1;36m5\u001b[0m, Batch:\u001b[1;36m0\u001b[0m -----------------------------\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
{\n",
+       "  \"acc#acc\": 0.79375,\n",
+       "  \"total#acc\": 160.0,\n",
+       "  \"correct#acc\": 127.0\n",
+       "}\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m{\u001b[0m\n", + " \u001b[1;34m\"acc#acc\"\u001b[0m: \u001b[1;36m0.79375\u001b[0m,\n", + " \u001b[1;34m\"total#acc\"\u001b[0m: \u001b[1;36m160.0\u001b[0m,\n", + " \u001b[1;34m\"correct#acc\"\u001b[0m: \u001b[1;36m127.0\u001b[0m\n", + "\u001b[1m}\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "
\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
----------------------------- Eval. results on Epoch:6, Batch:0 -----------------------------\n",
+       "
\n" + ], + "text/plain": [ + "----------------------------- Eval. results on Epoch:\u001b[1;36m6\u001b[0m, Batch:\u001b[1;36m0\u001b[0m -----------------------------\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
{\n",
+       "  \"acc#acc\": 0.80625,\n",
+       "  \"total#acc\": 160.0,\n",
+       "  \"correct#acc\": 129.0\n",
+       "}\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m{\u001b[0m\n", + " \u001b[1;34m\"acc#acc\"\u001b[0m: \u001b[1;36m0.80625\u001b[0m,\n", + " \u001b[1;34m\"total#acc\"\u001b[0m: \u001b[1;36m160.0\u001b[0m,\n", + " \u001b[1;34m\"correct#acc\"\u001b[0m: \u001b[1;36m129.0\u001b[0m\n", + "\u001b[1m}\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "
\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
----------------------------- Eval. results on Epoch:7, Batch:0 -----------------------------\n",
+       "
\n" + ], + "text/plain": [ + "----------------------------- Eval. results on Epoch:\u001b[1;36m7\u001b[0m, Batch:\u001b[1;36m0\u001b[0m -----------------------------\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
{\n",
+       "  \"acc#acc\": 0.81875,\n",
+       "  \"total#acc\": 160.0,\n",
+       "  \"correct#acc\": 131.0\n",
+       "}\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m{\u001b[0m\n", + " \u001b[1;34m\"acc#acc\"\u001b[0m: \u001b[1;36m0.81875\u001b[0m,\n", + " \u001b[1;34m\"total#acc\"\u001b[0m: \u001b[1;36m160.0\u001b[0m,\n", + " \u001b[1;34m\"correct#acc\"\u001b[0m: \u001b[1;36m131.0\u001b[0m\n", + "\u001b[1m}\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "
\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
----------------------------- Eval. results on Epoch:8, Batch:0 -----------------------------\n",
+       "
\n" + ], + "text/plain": [ + "----------------------------- Eval. results on Epoch:\u001b[1;36m8\u001b[0m, Batch:\u001b[1;36m0\u001b[0m -----------------------------\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
{\n",
+       "  \"acc#acc\": 0.825,\n",
+       "  \"total#acc\": 160.0,\n",
+       "  \"correct#acc\": 132.0\n",
+       "}\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m{\u001b[0m\n", + " \u001b[1;34m\"acc#acc\"\u001b[0m: \u001b[1;36m0.825\u001b[0m,\n", + " \u001b[1;34m\"total#acc\"\u001b[0m: \u001b[1;36m160.0\u001b[0m,\n", + " \u001b[1;34m\"correct#acc\"\u001b[0m: \u001b[1;36m132.0\u001b[0m\n", + "\u001b[1m}\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "
\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
----------------------------- Eval. results on Epoch:9, Batch:0 -----------------------------\n",
+       "
\n" + ], + "text/plain": [ + "----------------------------- Eval. results on Epoch:\u001b[1;36m9\u001b[0m, Batch:\u001b[1;36m0\u001b[0m -----------------------------\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
{\n",
+       "  \"acc#acc\": 0.81875,\n",
+       "  \"total#acc\": 160.0,\n",
+       "  \"correct#acc\": 131.0\n",
+       "}\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m{\u001b[0m\n", + " \u001b[1;34m\"acc#acc\"\u001b[0m: \u001b[1;36m0.81875\u001b[0m,\n", + " \u001b[1;34m\"total#acc\"\u001b[0m: \u001b[1;36m160.0\u001b[0m,\n", + " \u001b[1;34m\"correct#acc\"\u001b[0m: \u001b[1;36m131.0\u001b[0m\n", + "\u001b[1m}\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "
\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
---------------------------- Eval. results on Epoch:10, Batch:0 -----------------------------\n",
+       "
\n" + ], + "text/plain": [ + "---------------------------- Eval. results on Epoch:\u001b[1;36m10\u001b[0m, Batch:\u001b[1;36m0\u001b[0m -----------------------------\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
{\n",
+       "  \"acc#acc\": 0.81875,\n",
+       "  \"total#acc\": 160.0,\n",
+       "  \"correct#acc\": 131.0\n",
+       "}\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m{\u001b[0m\n", + " \u001b[1;34m\"acc#acc\"\u001b[0m: \u001b[1;36m0.81875\u001b[0m,\n", + " \u001b[1;34m\"total#acc\"\u001b[0m: \u001b[1;36m160.0\u001b[0m,\n", + " \u001b[1;34m\"correct#acc\"\u001b[0m: \u001b[1;36m131.0\u001b[0m\n", + "\u001b[1m}\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n"
+      ],
+      "text/plain": []
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/html": [
+       "
\n",
+       "
\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "trainer.run(num_eval_batch_per_dl=10)" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "f47a6a35", + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Output()" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n"
+      ],
+      "text/plain": []
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/plain": [
+       "{'acc#acc': 0.79, 'total#acc': 900.0, 'correct#acc': 711.0}"
+      ]
+     },
+     "execution_count": 14,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "trainer.evaluator.run()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "7c811257",
+   "metadata": {},
+   "source": [
+    "  注:此处使用`gc`模块删除相关变量,释放内存,为接下来新的模型训练预留存储空间"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 15,
+   "id": "c1a2e2ca",
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "342"
+      ]
+     },
+     "execution_count": 15,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "import gc\n",
+    "\n",
+    "del model\n",
+    "del trainer\n",
+    "del dataset\n",
+    "del sst2data\n",
+    "\n",
+    "gc.collect()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "6aec2a19",
+   "metadata": {},
+   "source": [
+    "### 2.2  示例二:models 实现 BiLSTM 标注\n",
+    "\n",
+    "  通过两个示例一的对比可以发现,得益于`models`对模型结构的封装,使用`models`明显更加便捷\n",
+    "\n",
+    "    针对更加复杂的模型时,编码更加轻松;本示例将使用`models`中的`BiLSTMCRF`模型\n",
+    "\n",
+    "  避免`CRF`和`Viterbi`算法代码书写的困难,轻松实现`CoNLL-2003`中的命名实体识别`NER`任务\n",
+    "\n",
+    "模型使用方面,如上所述,这里使用**基于双向`LSTM`+条件随机场`CRF`的标注模型`BiLSTMCRF`**,结构如下所示\n",
+    "\n",
+    "  其中,隐藏层维度默认`100`维,因此对应双向`LSTM`输出`200`维,`dropout`层退学概率、`LSTM`层数可调\n",
+    "\n",
+    "```\n",
+    "BiLSTMCRF(\n",
+    "  (embed): Embedding(7590, 100)\n",
+    "  (lstm): LSTM(\n",
+    "    (lstm): LSTM(100, 100, batch_first=True, bidirectional=True)\n",
+    "  )\n",
+    "  (dropout): Dropout(p=0.1, inplace=False)\n",
+    "  (fc): Linear(in_features=200, out_features=9, bias=True)\n",
+    "  (crf): ConditionalRandomField()\n",
+    ")\n",
+    "```\n",
+    "\n",
+    "数据使用方面,此处仍然**使用`datasets`模块中的`load_dataset`函数**,以如下形式,加载`CoNLL-2003`数据集\n",
+    "\n",
+    "  首次下载后会保存至`~.cache/huggingface/datasets/conll2003/conll2003/1.0.0/`目录下"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 16,
+   "id": "03e66686",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stderr",
+     "output_type": "stream",
+     "text": [
+      "Reusing dataset conll2003 (/remote-home/xrliu/.cache/huggingface/datasets/conll2003/conll2003/1.0.0/63f4ebd1bcb7148b1644497336fd74643d4ce70123334431a3c053b7ee4e96ee)\n"
+     ]
+    },
+    {
+     "data": {
+      "application/vnd.jupyter.widget-view+json": {
+       "model_id": "3ec9e0ce9a054339a2453420c2c9f28b",
+       "version_major": 2,
+       "version_minor": 0
+      },
+      "text/plain": [
+       "  0%|          | 0/3 [00:00[17:49:16] INFO     Running evaluator sanity check for 2 batches.              trainer.py:592\n",
+       "\n"
+      ],
+      "text/plain": [
+       "\u001b[2;36m[17:49:16]\u001b[0m\u001b[2;36m \u001b[0m\u001b[34mINFO    \u001b[0m Running evaluator sanity check for \u001b[1;36m2\u001b[0m batches.              \u001b]8;id=766109;file://../fastNLP/core/controllers/trainer.py\u001b\\\u001b[2mtrainer.py\u001b[0m\u001b]8;;\u001b\\\u001b[2m:\u001b[0m\u001b]8;id=787419;file://../fastNLP/core/controllers/trainer.py#592\u001b\\\u001b[2m592\u001b[0m\u001b]8;;\u001b\\\n"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "application/vnd.jupyter.widget-view+json": {
+       "model_id": "",
+       "version_major": 2,
+       "version_minor": 0
+      },
+      "text/plain": [
+       "Output()"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/html": [
+       "
\n"
+      ],
+      "text/plain": []
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "application/vnd.jupyter.widget-view+json": {
+       "model_id": "",
+       "version_major": 2,
+       "version_minor": 0
+      },
+      "text/plain": [
+       "Output()"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/html": [
+       "
\n",
+       "
\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
----------------------------- Eval. results on Epoch:1, Batch:0 -----------------------------\n",
+       "
\n" + ], + "text/plain": [ + "----------------------------- Eval. results on Epoch:\u001b[1;36m1\u001b[0m, Batch:\u001b[1;36m0\u001b[0m -----------------------------\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
{\n",
+       "  \"f#F1\": 0.220374,\n",
+       "  \"pre#F1\": 0.25,\n",
+       "  \"rec#F1\": 0.197026\n",
+       "}\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m{\u001b[0m\n", + " \u001b[1;34m\"f#F1\"\u001b[0m: \u001b[1;36m0.220374\u001b[0m,\n", + " \u001b[1;34m\"pre#F1\"\u001b[0m: \u001b[1;36m0.25\u001b[0m,\n", + " \u001b[1;34m\"rec#F1\"\u001b[0m: \u001b[1;36m0.197026\u001b[0m\n", + "\u001b[1m}\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "
\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
----------------------------- Eval. results on Epoch:2, Batch:0 -----------------------------\n",
+       "
\n" + ], + "text/plain": [ + "----------------------------- Eval. results on Epoch:\u001b[1;36m2\u001b[0m, Batch:\u001b[1;36m0\u001b[0m -----------------------------\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
{\n",
+       "  \"f#F1\": 0.442857,\n",
+       "  \"pre#F1\": 0.426117,\n",
+       "  \"rec#F1\": 0.460967\n",
+       "}\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m{\u001b[0m\n", + " \u001b[1;34m\"f#F1\"\u001b[0m: \u001b[1;36m0.442857\u001b[0m,\n", + " \u001b[1;34m\"pre#F1\"\u001b[0m: \u001b[1;36m0.426117\u001b[0m,\n", + " \u001b[1;34m\"rec#F1\"\u001b[0m: \u001b[1;36m0.460967\u001b[0m\n", + "\u001b[1m}\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "
\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
----------------------------- Eval. results on Epoch:3, Batch:0 -----------------------------\n",
+       "
\n" + ], + "text/plain": [ + "----------------------------- Eval. results on Epoch:\u001b[1;36m3\u001b[0m, Batch:\u001b[1;36m0\u001b[0m -----------------------------\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
{\n",
+       "  \"f#F1\": 0.572954,\n",
+       "  \"pre#F1\": 0.549488,\n",
+       "  \"rec#F1\": 0.598513\n",
+       "}\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m{\u001b[0m\n", + " \u001b[1;34m\"f#F1\"\u001b[0m: \u001b[1;36m0.572954\u001b[0m,\n", + " \u001b[1;34m\"pre#F1\"\u001b[0m: \u001b[1;36m0.549488\u001b[0m,\n", + " \u001b[1;34m\"rec#F1\"\u001b[0m: \u001b[1;36m0.598513\u001b[0m\n", + "\u001b[1m}\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "
\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
----------------------------- Eval. results on Epoch:4, Batch:0 -----------------------------\n",
+       "
\n" + ], + "text/plain": [ + "----------------------------- Eval. results on Epoch:\u001b[1;36m4\u001b[0m, Batch:\u001b[1;36m0\u001b[0m -----------------------------\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
{\n",
+       "  \"f#F1\": 0.665399,\n",
+       "  \"pre#F1\": 0.680934,\n",
+       "  \"rec#F1\": 0.650558\n",
+       "}\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m{\u001b[0m\n", + " \u001b[1;34m\"f#F1\"\u001b[0m: \u001b[1;36m0.665399\u001b[0m,\n", + " \u001b[1;34m\"pre#F1\"\u001b[0m: \u001b[1;36m0.680934\u001b[0m,\n", + " \u001b[1;34m\"rec#F1\"\u001b[0m: \u001b[1;36m0.650558\u001b[0m\n", + "\u001b[1m}\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "
\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
----------------------------- Eval. results on Epoch:5, Batch:0 -----------------------------\n",
+       "
\n" + ], + "text/plain": [ + "----------------------------- Eval. results on Epoch:\u001b[1;36m5\u001b[0m, Batch:\u001b[1;36m0\u001b[0m -----------------------------\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
{\n",
+       "  \"f#F1\": 0.734694,\n",
+       "  \"pre#F1\": 0.733333,\n",
+       "  \"rec#F1\": 0.736059\n",
+       "}\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m{\u001b[0m\n", + " \u001b[1;34m\"f#F1\"\u001b[0m: \u001b[1;36m0.734694\u001b[0m,\n", + " \u001b[1;34m\"pre#F1\"\u001b[0m: \u001b[1;36m0.733333\u001b[0m,\n", + " \u001b[1;34m\"rec#F1\"\u001b[0m: \u001b[1;36m0.736059\u001b[0m\n", + "\u001b[1m}\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "
\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
----------------------------- Eval. results on Epoch:6, Batch:0 -----------------------------\n",
+       "
\n" + ], + "text/plain": [ + "----------------------------- Eval. results on Epoch:\u001b[1;36m6\u001b[0m, Batch:\u001b[1;36m0\u001b[0m -----------------------------\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
{\n",
+       "  \"f#F1\": 0.742647,\n",
+       "  \"pre#F1\": 0.734545,\n",
+       "  \"rec#F1\": 0.750929\n",
+       "}\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m{\u001b[0m\n", + " \u001b[1;34m\"f#F1\"\u001b[0m: \u001b[1;36m0.742647\u001b[0m,\n", + " \u001b[1;34m\"pre#F1\"\u001b[0m: \u001b[1;36m0.734545\u001b[0m,\n", + " \u001b[1;34m\"rec#F1\"\u001b[0m: \u001b[1;36m0.750929\u001b[0m\n", + "\u001b[1m}\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "
\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
----------------------------- Eval. results on Epoch:7, Batch:0 -----------------------------\n",
+       "
\n" + ], + "text/plain": [ + "----------------------------- Eval. results on Epoch:\u001b[1;36m7\u001b[0m, Batch:\u001b[1;36m0\u001b[0m -----------------------------\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
{\n",
+       "  \"f#F1\": 0.773585,\n",
+       "  \"pre#F1\": 0.785441,\n",
+       "  \"rec#F1\": 0.762082\n",
+       "}\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m{\u001b[0m\n", + " \u001b[1;34m\"f#F1\"\u001b[0m: \u001b[1;36m0.773585\u001b[0m,\n", + " \u001b[1;34m\"pre#F1\"\u001b[0m: \u001b[1;36m0.785441\u001b[0m,\n", + " \u001b[1;34m\"rec#F1\"\u001b[0m: \u001b[1;36m0.762082\u001b[0m\n", + "\u001b[1m}\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "
\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
----------------------------- Eval. results on Epoch:8, Batch:0 -----------------------------\n",
+       "
\n" + ], + "text/plain": [ + "----------------------------- Eval. results on Epoch:\u001b[1;36m8\u001b[0m, Batch:\u001b[1;36m0\u001b[0m -----------------------------\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
{\n",
+       "  \"f#F1\": 0.770115,\n",
+       "  \"pre#F1\": 0.794466,\n",
+       "  \"rec#F1\": 0.747212\n",
+       "}\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m{\u001b[0m\n", + " \u001b[1;34m\"f#F1\"\u001b[0m: \u001b[1;36m0.770115\u001b[0m,\n", + " \u001b[1;34m\"pre#F1\"\u001b[0m: \u001b[1;36m0.794466\u001b[0m,\n", + " \u001b[1;34m\"rec#F1\"\u001b[0m: \u001b[1;36m0.747212\u001b[0m\n", + "\u001b[1m}\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "
\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
----------------------------- Eval. results on Epoch:9, Batch:0 -----------------------------\n",
+       "
\n" + ], + "text/plain": [ + "----------------------------- Eval. results on Epoch:\u001b[1;36m9\u001b[0m, Batch:\u001b[1;36m0\u001b[0m -----------------------------\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
{\n",
+       "  \"f#F1\": 0.7603,\n",
+       "  \"pre#F1\": 0.766038,\n",
+       "  \"rec#F1\": 0.754647\n",
+       "}\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m{\u001b[0m\n", + " \u001b[1;34m\"f#F1\"\u001b[0m: \u001b[1;36m0.7603\u001b[0m,\n", + " \u001b[1;34m\"pre#F1\"\u001b[0m: \u001b[1;36m0.766038\u001b[0m,\n", + " \u001b[1;34m\"rec#F1\"\u001b[0m: \u001b[1;36m0.754647\u001b[0m\n", + "\u001b[1m}\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "
\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
---------------------------- Eval. results on Epoch:10, Batch:0 -----------------------------\n",
+       "
\n" + ], + "text/plain": [ + "---------------------------- Eval. results on Epoch:\u001b[1;36m10\u001b[0m, Batch:\u001b[1;36m0\u001b[0m -----------------------------\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
{\n",
+       "  \"f#F1\": 0.743682,\n",
+       "  \"pre#F1\": 0.722807,\n",
+       "  \"rec#F1\": 0.765799\n",
+       "}\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m{\u001b[0m\n", + " \u001b[1;34m\"f#F1\"\u001b[0m: \u001b[1;36m0.743682\u001b[0m,\n", + " \u001b[1;34m\"pre#F1\"\u001b[0m: \u001b[1;36m0.722807\u001b[0m,\n", + " \u001b[1;34m\"rec#F1\"\u001b[0m: \u001b[1;36m0.765799\u001b[0m\n", + "\u001b[1m}\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n"
+      ],
+      "text/plain": []
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/html": [
+       "
\n",
+       "
\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "trainer.run(num_eval_batch_per_dl=10)" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "37871d6b", + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Output()" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n"
+      ],
+      "text/plain": []
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/plain": [
+       "{'f#F1': 0.75283, 'pre#F1': 0.727438, 'rec#F1': 0.780059}"
+      ]
+     },
+     "execution_count": 22,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "trainer.evaluator.run()"
    ]
   },
   {
    "cell_type": "code",
    "execution_count": null,
-   "id": "08752c5a",
+   "id": "96bae094",
    "metadata": {},
    "outputs": [],
    "source": []
diff --git a/tutorials/fastnlp_tutorial_6.ipynb b/tutorials/fastnlp_tutorial_6.ipynb
index bd4b37ed..2052189e 100644
--- a/tutorials/fastnlp_tutorial_6.ipynb
+++ b/tutorials/fastnlp_tutorial_6.ipynb
@@ -5,21 +5,21 @@
    "id": "fdd7ff16",
    "metadata": {},
    "source": [
-    "# T6. trainer 和 evaluator 的深入介绍(二)\n",
+    "# T6. fastNLP 与 paddle 或 jittor 的结合\n",
     "\n",
-    "  1   fastNLP 中预定义模型 models\n",
+    "  1   fastNLP 结合 paddle 训练模型\n",
     " \n",
-    "    1.1   \n",
+    "    1.1   关于 paddle 的简单介绍\n",
     "\n",
-    "    1.2   \n",
+    "    1.2   使用 paddle 搭建并训练模型\n",
     "\n",
-    "  2   fastNLP 中预定义模型 modules\n",
-    " \n",
-    "    2.1   \n",
+    "  2   fastNLP 结合 jittor 训练模型\n",
+    "\n",
+    "    2.1   关于 jittor 的简单介绍\n",
     "\n",
-    "    2.2   \n",
+    "    2.2   使用 jittor 搭建并训练模型\n",
     "\n",
-    "  3   fastNLP 中的更多 metric 类型\n",
+    "  3   fastNLP 实现 paddle 与 pytorch 互转\n",
     "\n",
     "    3.1   \n",
     "\n",
diff --git a/tutorials/fastnlp_tutorial_e1.ipynb b/tutorials/fastnlp_tutorial_e1.ipynb
index 8897c800..b0df8fc1 100644
--- a/tutorials/fastnlp_tutorial_e1.ipynb
+++ b/tutorials/fastnlp_tutorial_e1.ipynb
@@ -13,9 +13,9 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "# E1. 使用 Bert + fine-tuning 完成 SST2 分类\n",
+    "# E1. 使用 Bert + fine-tuning 完成 SST-2 分类\n",
     "\n",
-    "  1   基础介绍:`GLUE`通用语言理解评估、`SST2`文本情感二分类数据集 \n",
+    "  1   基础介绍:`GLUE`通用语言理解评估、`SST-2`文本情感二分类数据集 \n",
     "\n",
     "  2   准备工作:加载`tokenizer`、预处理`dataset`、`dataloader`使用\n",
     "\n",
@@ -63,7 +63,7 @@
     "\n",
     "import fastNLP\n",
     "from fastNLP import Trainer\n",
-    "from fastNLP.core.metrics import Accuracy\n",
+    "from fastNLP import Accuracy\n",
     "\n",
     "print(transformers.__version__)"
    ]
@@ -72,11 +72,11 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "### 1. 基础介绍:GLUE 通用语言理解评估、SST2 文本情感二分类数据集\n",
+    "### 1. 基础介绍:GLUE 通用语言理解评估、SST-2 文本情感二分类数据集\n",
     "\n",
-    "  本示例使用`GLUE`评估基准中的`SST2`数据集,通过`fine-tuning`方式\n",
+    "  本示例使用`GLUE`评估基准中的`SST-2`数据集,通过`fine-tuning`方式\n",
     "\n",
-    "    调整`distilbert-bert`分类模型,以下首先简单介绍下`GLUE`和`SST2`\n",
+    "    调整`distilbert-bert`分类模型,以下首先简单介绍下`GLUE`和`SST-2`\n",
     "\n",
     "**`GLUE`**,**全称`General Language Understanding Evaluation`**,**通用语言理解评估**,\n",
     "\n",
@@ -92,7 +92,7 @@
     "\n",
     "  诸如`BERT`、`T5`等经典模型都会在此基准上验证效果,更多参考[GLUE论文](https://arxiv.org/pdf/1804.07461v3.pdf)\n",
     "\n",
-    "    此处,我们使用`SST2`来训练`bert`,实现文本分类,其他任务描述见下图"
+    "    此处,我们使用`SST-2`来训练`bert`,实现文本分类,其他任务描述见下图"
    ]
   },
   {
@@ -116,9 +116,9 @@
     "\n",
     "  包含电影评论语句和对应的情感极性,1 对应`positive` 正面情感,0 对应`negative` 负面情感\n",
     "\n",
-    "  数据集包括三部分:训练集 67350 条,开发集 873 条,测试集 1821 条,更多参考[下载链接](https://gluebenchmark.com/tasks)\n",
+    "  数据集包括三部分:训练集 67350 条,验证集 873 条,测试集 1821 条,更多参考[下载链接](https://gluebenchmark.com/tasks)\n",
     "\n",
-    "对应到代码上,此处使用`datasets`模块中的`load_dataset`函数,指定`SST2`数据集,自动加载\n",
+    "对应到代码上,此处使用`datasets`模块中的`load_dataset`函数,指定`SST-2`数据集,自动加载\n",
     "\n",
     "  首次下载后会保存至`~/.cache/huggingface/modules/datasets_modules/datasets/glue/`目录下"
    ]
@@ -134,14 +134,13 @@
      "name": "stderr",
      "output_type": "stream",
      "text": [
-      "Using the latest cached version of the module from /remote-home/xrliu/.cache/huggingface/modules/datasets_modules/datasets/glue/dacbe3125aa31d7f70367a07a8a9e72a5a0bfeb5fc42e75c9db75b96da6053ad (last modified on Thu May 26 15:30:15 2022) since it couldn't be found locally at glue., or remotely on the Hugging Face Hub.\n",
       "Reusing dataset glue (/remote-home/xrliu/.cache/huggingface/datasets/glue/sst2/1.0.0/dacbe3125aa31d7f70367a07a8a9e72a5a0bfeb5fc42e75c9db75b96da6053ad)\n"
      ]
     },
     {
      "data": {
       "application/vnd.jupyter.widget-view+json": {
-       "model_id": "adc9449171454f658285f220b70126e1",
+       "model_id": "c5915debacf9443986b5b3b34870b303",
        "version_major": 2,
        "version_minor": 0
       },
@@ -163,7 +162,7 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "  加载之后,根据`GLUE`中`SST2`数据集的格式,尝试打印部分数据,检查加载结果"
+    "  加载之后,根据`GLUE`中`SST-2`数据集的格式,尝试打印部分数据,检查加载结果"
    ]
   },
   {
@@ -287,7 +286,7 @@
     "\n",
     "  其中,**`__getitem__`函数各返回值引用的键值**,**必须和原始数据集中的属性对应**\n",
     "\n",
-    "  例如,`'label'`是`SST2`数据集中原有的内容(包括`'sentence'`和`'label'`\n",
+    "  例如,`'label'`是`SST-2`数据集中原有的内容(包括`'sentence'`和`'label'`\n",
     "\n",
     "    `'input_ids'`和`'attention_mask'`则是`tokenizer`处理后添加的字段"
    ]
@@ -440,10 +439,10 @@
      "name": "stderr",
      "output_type": "stream",
      "text": [
-      "Some weights of the model checkpoint at distilbert-base-uncased were not used when initializing DistilBertForSequenceClassification: ['vocab_layer_norm.weight', 'vocab_layer_norm.bias', 'vocab_projector.weight', 'vocab_transform.bias', 'vocab_projector.bias', 'vocab_transform.weight']\n",
+      "Some weights of the model checkpoint at distilbert-base-uncased were not used when initializing DistilBertForSequenceClassification: ['vocab_transform.bias', 'vocab_projector.bias', 'vocab_layer_norm.weight', 'vocab_projector.weight', 'vocab_transform.weight', 'vocab_layer_norm.bias']\n",
       "- This IS expected if you are initializing DistilBertForSequenceClassification from the checkpoint of a model trained on another task or with another architecture (e.g. initializing a BertForSequenceClassification model from a BertForPreTraining model).\n",
       "- This IS NOT expected if you are initializing DistilBertForSequenceClassification from the checkpoint of a model that you expect to be exactly identical (initializing a BertForSequenceClassification model from a BertForSequenceClassification model).\n",
-      "Some weights of DistilBertForSequenceClassification were not initialized from the model checkpoint at distilbert-base-uncased and are newly initialized: ['pre_classifier.bias', 'classifier.weight', 'classifier.bias', 'pre_classifier.weight']\n",
+      "Some weights of DistilBertForSequenceClassification were not initialized from the model checkpoint at distilbert-base-uncased and are newly initialized: ['classifier.weight', 'pre_classifier.weight', 'classifier.bias', 'pre_classifier.bias']\n",
       "You should probably TRAIN this model on a down-stream task to be able to use it for predictions and inference.\n"
      ]
     }
@@ -472,7 +471,7 @@
     "trainer = Trainer(\n",
     "    model=model,\n",
     "    driver='torch',\n",
-    "    device=1,  # 'cuda'\n",
+    "    device=0,  # 'cuda'\n",
     "    n_epochs=10,\n",
     "    optimizers=optimizers,\n",
     "    train_dataloader=dataloader_train,\n",
@@ -498,6 +497,33 @@
     {
      "data": {
       "text/html": [
+       "
[09:12:45] INFO     Running evaluator sanity check for 2 batches.              trainer.py:592\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[2;36m[09:12:45]\u001b[0m\u001b[2;36m \u001b[0m\u001b[34mINFO \u001b[0m Running evaluator sanity check for \u001b[1;36m2\u001b[0m batches. \u001b]8;id=408427;file://../fastNLP/core/controllers/trainer.py\u001b\\\u001b[2mtrainer.py\u001b[0m\u001b]8;;\u001b\\\u001b[2m:\u001b[0m\u001b]8;id=303634;file://../fastNLP/core/controllers/trainer.py#592\u001b\\\u001b[2m592\u001b[0m\u001b]8;;\u001b\\\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Output()" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ "
\n"
       ],
       "text/plain": []
@@ -507,6 +533,490 @@
     },
     {
      "data": {
+      "application/vnd.jupyter.widget-view+json": {
+       "model_id": "",
+       "version_major": 2,
+       "version_minor": 0
+      },
+      "text/plain": [
+       "Output()"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/html": [
+       "
\n",
+       "
\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
----------------------------- Eval. results on Epoch:1, Batch:0 -----------------------------\n",
+       "
\n" + ], + "text/plain": [ + "----------------------------- Eval. results on Epoch:\u001b[1;36m1\u001b[0m, Batch:\u001b[1;36m0\u001b[0m -----------------------------\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
{\n",
+       "  \"acc#acc\": 0.884375,\n",
+       "  \"total#acc\": 320.0,\n",
+       "  \"correct#acc\": 283.0\n",
+       "}\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m{\u001b[0m\n", + " \u001b[1;34m\"acc#acc\"\u001b[0m: \u001b[1;36m0.884375\u001b[0m,\n", + " \u001b[1;34m\"total#acc\"\u001b[0m: \u001b[1;36m320.0\u001b[0m,\n", + " \u001b[1;34m\"correct#acc\"\u001b[0m: \u001b[1;36m283.0\u001b[0m\n", + "\u001b[1m}\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "
\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
----------------------------- Eval. results on Epoch:2, Batch:0 -----------------------------\n",
+       "
\n" + ], + "text/plain": [ + "----------------------------- Eval. results on Epoch:\u001b[1;36m2\u001b[0m, Batch:\u001b[1;36m0\u001b[0m -----------------------------\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
{\n",
+       "  \"acc#acc\": 0.878125,\n",
+       "  \"total#acc\": 320.0,\n",
+       "  \"correct#acc\": 281.0\n",
+       "}\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m{\u001b[0m\n", + " \u001b[1;34m\"acc#acc\"\u001b[0m: \u001b[1;36m0.878125\u001b[0m,\n", + " \u001b[1;34m\"total#acc\"\u001b[0m: \u001b[1;36m320.0\u001b[0m,\n", + " \u001b[1;34m\"correct#acc\"\u001b[0m: \u001b[1;36m281.0\u001b[0m\n", + "\u001b[1m}\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "
\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
----------------------------- Eval. results on Epoch:3, Batch:0 -----------------------------\n",
+       "
\n" + ], + "text/plain": [ + "----------------------------- Eval. results on Epoch:\u001b[1;36m3\u001b[0m, Batch:\u001b[1;36m0\u001b[0m -----------------------------\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
{\n",
+       "  \"acc#acc\": 0.884375,\n",
+       "  \"total#acc\": 320.0,\n",
+       "  \"correct#acc\": 283.0\n",
+       "}\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m{\u001b[0m\n", + " \u001b[1;34m\"acc#acc\"\u001b[0m: \u001b[1;36m0.884375\u001b[0m,\n", + " \u001b[1;34m\"total#acc\"\u001b[0m: \u001b[1;36m320.0\u001b[0m,\n", + " \u001b[1;34m\"correct#acc\"\u001b[0m: \u001b[1;36m283.0\u001b[0m\n", + "\u001b[1m}\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "
\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
----------------------------- Eval. results on Epoch:4, Batch:0 -----------------------------\n",
+       "
\n" + ], + "text/plain": [ + "----------------------------- Eval. results on Epoch:\u001b[1;36m4\u001b[0m, Batch:\u001b[1;36m0\u001b[0m -----------------------------\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
{\n",
+       "  \"acc#acc\": 0.9,\n",
+       "  \"total#acc\": 320.0,\n",
+       "  \"correct#acc\": 288.0\n",
+       "}\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m{\u001b[0m\n", + " \u001b[1;34m\"acc#acc\"\u001b[0m: \u001b[1;36m0.9\u001b[0m,\n", + " \u001b[1;34m\"total#acc\"\u001b[0m: \u001b[1;36m320.0\u001b[0m,\n", + " \u001b[1;34m\"correct#acc\"\u001b[0m: \u001b[1;36m288.0\u001b[0m\n", + "\u001b[1m}\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "
\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
----------------------------- Eval. results on Epoch:5, Batch:0 -----------------------------\n",
+       "
\n" + ], + "text/plain": [ + "----------------------------- Eval. results on Epoch:\u001b[1;36m5\u001b[0m, Batch:\u001b[1;36m0\u001b[0m -----------------------------\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
{\n",
+       "  \"acc#acc\": 0.8875,\n",
+       "  \"total#acc\": 320.0,\n",
+       "  \"correct#acc\": 284.0\n",
+       "}\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m{\u001b[0m\n", + " \u001b[1;34m\"acc#acc\"\u001b[0m: \u001b[1;36m0.8875\u001b[0m,\n", + " \u001b[1;34m\"total#acc\"\u001b[0m: \u001b[1;36m320.0\u001b[0m,\n", + " \u001b[1;34m\"correct#acc\"\u001b[0m: \u001b[1;36m284.0\u001b[0m\n", + "\u001b[1m}\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "
\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
----------------------------- Eval. results on Epoch:6, Batch:0 -----------------------------\n",
+       "
\n" + ], + "text/plain": [ + "----------------------------- Eval. results on Epoch:\u001b[1;36m6\u001b[0m, Batch:\u001b[1;36m0\u001b[0m -----------------------------\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
{\n",
+       "  \"acc#acc\": 0.88125,\n",
+       "  \"total#acc\": 320.0,\n",
+       "  \"correct#acc\": 282.0\n",
+       "}\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m{\u001b[0m\n", + " \u001b[1;34m\"acc#acc\"\u001b[0m: \u001b[1;36m0.88125\u001b[0m,\n", + " \u001b[1;34m\"total#acc\"\u001b[0m: \u001b[1;36m320.0\u001b[0m,\n", + " \u001b[1;34m\"correct#acc\"\u001b[0m: \u001b[1;36m282.0\u001b[0m\n", + "\u001b[1m}\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "
\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
----------------------------- Eval. results on Epoch:7, Batch:0 -----------------------------\n",
+       "
\n" + ], + "text/plain": [ + "----------------------------- Eval. results on Epoch:\u001b[1;36m7\u001b[0m, Batch:\u001b[1;36m0\u001b[0m -----------------------------\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
{\n",
+       "  \"acc#acc\": 0.875,\n",
+       "  \"total#acc\": 320.0,\n",
+       "  \"correct#acc\": 280.0\n",
+       "}\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m{\u001b[0m\n", + " \u001b[1;34m\"acc#acc\"\u001b[0m: \u001b[1;36m0.875\u001b[0m,\n", + " \u001b[1;34m\"total#acc\"\u001b[0m: \u001b[1;36m320.0\u001b[0m,\n", + " \u001b[1;34m\"correct#acc\"\u001b[0m: \u001b[1;36m280.0\u001b[0m\n", + "\u001b[1m}\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "
\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
----------------------------- Eval. results on Epoch:8, Batch:0 -----------------------------\n",
+       "
\n" + ], + "text/plain": [ + "----------------------------- Eval. results on Epoch:\u001b[1;36m8\u001b[0m, Batch:\u001b[1;36m0\u001b[0m -----------------------------\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
{\n",
+       "  \"acc#acc\": 0.865625,\n",
+       "  \"total#acc\": 320.0,\n",
+       "  \"correct#acc\": 277.0\n",
+       "}\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m{\u001b[0m\n", + " \u001b[1;34m\"acc#acc\"\u001b[0m: \u001b[1;36m0.865625\u001b[0m,\n", + " \u001b[1;34m\"total#acc\"\u001b[0m: \u001b[1;36m320.0\u001b[0m,\n", + " \u001b[1;34m\"correct#acc\"\u001b[0m: \u001b[1;36m277.0\u001b[0m\n", + "\u001b[1m}\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "
\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
----------------------------- Eval. results on Epoch:9, Batch:0 -----------------------------\n",
+       "
\n" + ], + "text/plain": [ + "----------------------------- Eval. results on Epoch:\u001b[1;36m9\u001b[0m, Batch:\u001b[1;36m0\u001b[0m -----------------------------\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
{\n",
+       "  \"acc#acc\": 0.884375,\n",
+       "  \"total#acc\": 320.0,\n",
+       "  \"correct#acc\": 283.0\n",
+       "}\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m{\u001b[0m\n", + " \u001b[1;34m\"acc#acc\"\u001b[0m: \u001b[1;36m0.884375\u001b[0m,\n", + " \u001b[1;34m\"total#acc\"\u001b[0m: \u001b[1;36m320.0\u001b[0m,\n", + " \u001b[1;34m\"correct#acc\"\u001b[0m: \u001b[1;36m283.0\u001b[0m\n", + "\u001b[1m}\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "
\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
---------------------------- Eval. results on Epoch:10, Batch:0 -----------------------------\n",
+       "
\n" + ], + "text/plain": [ + "---------------------------- Eval. results on Epoch:\u001b[1;36m10\u001b[0m, Batch:\u001b[1;36m0\u001b[0m -----------------------------\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
{\n",
+       "  \"acc#acc\": 0.878125,\n",
+       "  \"total#acc\": 320.0,\n",
+       "  \"correct#acc\": 281.0\n",
+       "}\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m{\u001b[0m\n", + " \u001b[1;34m\"acc#acc\"\u001b[0m: \u001b[1;36m0.878125\u001b[0m,\n", + " \u001b[1;34m\"total#acc\"\u001b[0m: \u001b[1;36m320.0\u001b[0m,\n", + " \u001b[1;34m\"correct#acc\"\u001b[0m: \u001b[1;36m281.0\u001b[0m\n", + "\u001b[1m}\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { "text/html": [ "
\n"
       ],
@@ -540,10 +1050,14 @@
    "outputs": [
     {
      "data": {
-      "text/html": [
-       "
\n"
-      ],
-      "text/plain": []
+      "application/vnd.jupyter.widget-view+json": {
+       "model_id": "",
+       "version_major": 2,
+       "version_minor": 0
+      },
+      "text/plain": [
+       "Output()"
+      ]
      },
      "metadata": {},
      "output_type": "display_data"
@@ -561,7 +1075,7 @@
     {
      "data": {
       "text/plain": [
-       "{'acc#acc': 0.87156, 'total#acc': 872.0, 'correct#acc': 760.0}"
+       "{'acc#acc': 0.884174, 'total#acc': 872.0, 'correct#acc': 771.0}"
       ]
      },
      "execution_count": 14,
diff --git a/tutorials/fastnlp_tutorial_e2.ipynb b/tutorials/fastnlp_tutorial_e2.ipynb
index c8f4b7dc..ca0b4754 100644
--- a/tutorials/fastnlp_tutorial_e2.ipynb
+++ b/tutorials/fastnlp_tutorial_e2.ipynb
@@ -4,7 +4,7 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "# E2. 使用 Bert + prompt 完成 SST2 分类\n",
+    "# E2. 使用 Bert + prompt 完成 SST-2 分类\n",
     "\n",
     "  1   基础介绍:`prompt-based model`简介、与`fastNLP`的结合\n",
     "\n",
@@ -19,7 +19,7 @@
    "source": [
     "### 1. 基础介绍:prompt-based model 简介、与 fastNLP 的结合\n",
     "\n",
-    "  本示例使用`GLUE`评估基准中的`SST2`数据集,通过`prompt-based tuning`方式\n",
+    "  本示例使用`GLUE`评估基准中的`SST-2`数据集,通过`prompt-based tuning`方式\n",
     "\n",
     "    微调`bert-base-uncased`模型,实现文本情感的二分类,在此之前本示例\n",
     "\n",
@@ -27,41 +27,53 @@
     "\n",
     "**`prompt`**,**提示词**,最早出自论文[Exploiting Cloze Questions for Few Shot TC and NLI](https://arxiv.org/pdf/2001.07676.pdf)中的**`PET`模型**\n",
     "\n",
-    "    全称 **`Pattern-Exploiting Training`**,虽然文中并没有提到**`prompt`的说法,但仍视为其开山之作\n",
+    "    全称 **`Pattern-Exploiting Training`**,虽然文中并没有提到`prompt`的说法,但仍被视为开山之作\n",
     "\n",
-    "  其大致思路包括,对于文本分类任务,假定输入文本为,后来被称`prompt`,后来被称`verbalizer`,\n",
+    "  其大致思路包括,对于文本分类任务,假定输入文本为`\" X . \"`,设计**输入模板`template`**,**后来被称为`prompt`**\n",
     "\n",
-    "  其主要贡献在于,\n",
+    "    将输入重构为`\" X . It is [MASK] . \"`,**诱导或刺激语言模型在`[MASK]`位置生成含有情感倾向的词汇**\n",
+    "\n",
+    "    接着将该词汇**输入分类器中**,**后来被称为`verbalizer`**,从而得到该语句对应的情感倾向,实现文本分类\n",
+    "\n",
+    "  其主要贡献在于,通过构造`prompt`,诱导/刺激预训练模型生成期望适应下游任务特征,适合少样本学习的需求\n",
     "\n",
     "\n",
     "\n",
-    "**`prompt-based tuning`**,**基于提示的微调**,\n",
+    "**`prompt-based tuning`**,**基于提示的微调**,将`prompt`应用于**参数高效微调**,**`parameter-efficient tuning`**\n",
+    "\n",
+    "  通过**设计模板调整模型输入**或者**调整模型内部状态**,**固定预训练模型**,**诱导/刺激模型**调整输出以适应\n",
     "\n",
-    "  xxxx,更多参考[prompt综述](https://arxiv.org/pdf/2107.13586.pdf)\n",
+    "  当前任务,极大降低了训练开销,也省去了`verbalizer`的构造,更多参考[prompt综述](https://arxiv.org/pdf/2107.13586.pdf)、[DeltaTuning综述](https://arxiv.org/pdf/2203.06904.pdf)\n",
     "\n",
     "    以下列举些经典的`prompt-based tuning`案例,简单地介绍下`prompt-based tuning`的脉络\n",
     "\n",
-    "  案例一:**`P-Tuning v1`**,详细内容参考[P-Tuning-v1论文](https://arxiv.org/pdf/2103.10385.pdf)\n",
+    "  **案例一**:**`PrefixTuning`**,详细内容参考[PrefixTuning论文](https://arxiv.org/pdf/2101.00190.pdf)\n",
+    "\n",
+    "    其主要贡献在于,**提出连续的、非人工构造的、任务导向的`prompt`**,即**前缀`prefix`**,**调整**\n",
+    "\n",
+    "      **模型内部更新状态**,诱导模型在特定任务下生成期望目标,降低优化难度,提升微调效果\n",
+    "\n",
+    "    其主要研究对象,是`GPT2`和`BART`,主要面向生成任务`NLG`,如`table-to-text`和摘要\n",
     "\n",
-    "    其主要贡献在于,\n",
+    "  **案例二**:**`P-Tuning v1`**,详细内容参考[P-Tuning-v1论文](https://arxiv.org/pdf/2103.10385.pdf)\n",
     "\n",
-    "    其方法大致包括,\n",
+    "    其主要贡献在于,**通过连续的、非人工构造的`prompt`调整模型输入**,取代原先基于单词设计的\n",
     "\n",
-    "  案例二:**`PromptTuning`**,详细内容参考[PromptTuning论文](https://arxiv.org/pdf/2104.08691.pdf)\n",
+    "      但离散且不易于优化的`prompt`;同时也**证明了`GPT2`在语言理解任务上仍然是可以胜任的**\n",
     "\n",
-    "    其主要贡献在于,\n",
+    "    其主要研究对象,是`GPT2`,主要面向知识探测`knowledge probing`和自然语言理解`NLU`\n",
     "\n",
-    "    其方法大致包括,\n",
+    "  **案例三**:**`PromptTuning`**,详细内容参考[PromptTuning论文](https://arxiv.org/pdf/2104.08691.pdf)\n",
     "\n",
-    "  案例三:**`PrefixTuning`**,详细内容参考[PrefixTuning论文](https://arxiv.org/pdf/2101.00190.pdf)\n",
+    "    其主要贡献在于,通过连续的`prompt`调整模型输入,**证明了`prompt-based tuning`的效果**\n",
     "\n",
-    "    其主要贡献在于,\n",
+    "      **随模型参数量的增加而提升**,最终**在`10B`左右追上了全参数微调`fine-tuning`的效果**\n",
     "\n",
-    "    其方法大致包括,\n",
+    "    其主要面向自然语言理解`NLU`,通过为每个任务定义不同的`prompt`,从而支持多任务语境\n",
     "\n",
     "通过上述介绍可以发现`prompt-based tuning`只是模型微调方式,独立于预训练模型基础`backbone`\n",
     "\n",
-    "  目前,加载预训练模型的主流方法是使用`transformers`模块,而实现微调的框架则\n",
+    "  目前,加载预训练模型的主流方法是使用**`transformers`模块**,而实现微调的框架则\n",
     "\n",
     "    可以是`pytorch`、`paddle`、`jittor`等,而不同框架间又存在不兼容的问题\n",
     "\n",
@@ -69,9 +81,9 @@
     "\n",
     "    **和`transformers`模块之间的桥接**(`transformers`模块基于`pytorch`实现)\n",
     "\n",
-    "本示例仍使用了`tutorial-E1`的`SST2`数据集、`distilbert-base-uncased`模型(便于比较\n",
+    "本示例仍使用了`tutorial-E1`的`SST-2`数据集、`distilbert-base-uncased`模型(便于比较\n",
     "\n",
-    "  使用`pytorch`框架,通过将连续的`prompt`与`model`拼接,解决`SST2`二分类任务"
+    "  使用`pytorch`框架,通过将连续的`prompt`与`model`拼接,解决`SST-2`二分类任务"
    ]
   },
   {
@@ -246,7 +258,7 @@
    "source": [
     "### 3. 模型训练:加载 tokenizer、预处理 dataset、模型训练与分析\n",
     "\n",
-    "  本示例沿用`tutorial-E1`中的数据集,即使用`GLUE`评估基准中的`SST2`数据集\n",
+    "  本示例沿用`tutorial-E1`中的数据集,即使用`GLUE`评估基准中的`SST-2`数据集\n",
     "\n",
     "    以`bert-base-uncased`模型作为基准,基于`P-Tuning v2`方式微调\n",
     "\n",