diff --git a/README.md b/README.md
index 1e040f4b..9d949482 100644
--- a/README.md
+++ b/README.md
@@ -110,6 +110,6 @@ fastNLP的大致工作流程如上图所示,而项目结构如下:
-
+
*In memory of @FengZiYjun. May his soul rest in peace. We will miss you very very much!*
diff --git a/docs/source/figures/fitlogChart.png b/docs/source/figures/fitlogChart.png
new file mode 100644
index 00000000..57ae1683
Binary files /dev/null and b/docs/source/figures/fitlogChart.png differ
diff --git a/docs/source/figures/fitlogTable.png b/docs/source/figures/fitlogTable.png
new file mode 100644
index 00000000..37551634
Binary files /dev/null and b/docs/source/figures/fitlogTable.png differ
diff --git a/docs/source/figures/workflow.png b/docs/source/figures/workflow.png
new file mode 100644
index 00000000..d2f22df8
Binary files /dev/null and b/docs/source/figures/workflow.png differ
diff --git a/docs/source/index.rst b/docs/source/index.rst
index 219e32f9..03a192dc 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -55,6 +55,7 @@ fastNLP 在 :mod:`~fastNLP.models` 模块中内置了如 :class:`~fastNLP.models
安装指南
快速入门
详细指南
+ 科研指南
API 文档
-------------
diff --git a/docs/source/user/with_fitlog.rst b/docs/source/user/with_fitlog.rst
index 97c3ea71..51445775 100644
--- a/docs/source/user/with_fitlog.rst
+++ b/docs/source/user/with_fitlog.rst
@@ -2,4 +2,121 @@
科研向导
=================
-本文介绍使用 fastNLP 和 fitlog 进行科学研究的方法
\ No newline at end of file
+本文介绍结合使用 fastNLP 和 fitlog 进行科研的方法。
+
+首先,我们需要安装 `fitlog `_ 。你需要确认你的电脑中没有其它名为 `fitlog` 的命令。
+
+我们从命令行中进入到一个文件夹,现在我们要在文件夹中创建我们的 fastNLP 项目。你可以在命令行输入 `fitlog init test1` ,
+然后你会看到如下提示::
+
+ Initialized empty Git repository in /Users/fdujyn/workspaces/test1/.git/
+ Auto commit by fitlog
+ Initialized empty Git repository in /Users/fdujyn/workspaces/test1/.git/
+ Fitlog project test1 is initialized.
+
+这表明你已经创建成功了项目文件夹,并且在项目文件夹中已经初始化了 Git。如果你不想初始化 Git,
+可以参考文档 `命令行工具 `_
+
+现在我们进入你创建的项目文件夹 test1 中,可以看到有一个名为 logs 的文件夹,后面我们将会在里面存放你的实验记录。
+同时也有一个名为 main.py 的文件,这是我们推荐你使用的训练入口文件。文件的内容如下::
+
+ import fitlog
+
+ fitlog.commit(__file__) # auto commit your codes
+ fitlog.add_hyper_in_file (__file__) # record your hyperparameters
+
+ """
+ Your training code here, you may use these functions to log your result:
+ fitlog.add_hyper()
+ fitlog.add_loss()
+ fitlog.add_metric()
+ fitlog.add_best_metric()
+ ......
+ """
+
+ fitlog.finish() # finish the logging
+
+我们推荐你保留除注释外的四行代码,它们有助于你的实验,
+他们的具体用处参见文档 `用户 API `_
+
+我们假定你要进行前两个教程中的实验,并已经把数据复制到了项目根目录下的 tutorial_sample_dataset.csv 文件中。
+现在我们编写如下的训练代码,使用 :class:`~fastNLP.core.callback.FitlogCallback` 进行实验记录保存::
+
+ import fitlog
+ from fastNLP import Vocabulary, Trainer, CrossEntropyLoss, AccuracyMetric
+ from fastNLP.io import CSVLoader
+ from fastNLP.models import CNNText
+ from fastNLP.core.callback import FitlogCallback
+
+ fitlog.commit(__file__) # auto commit your codes
+ fitlog.add_hyper_in_file (__file__) # record your hyperparameters
+
+ ############hyper
+ word_embed = 50
+ dropout = 0.1
+ ############hyper
+
+ loader = CSVLoader(headers=('raw_sentence', 'label'), sep='\t')
+ dataset = loader.load("tutorial_sample_dataset.csv")
+
+ dataset.apply(lambda x: x['raw_sentence'].lower(), new_field_name='sentence')
+ dataset.apply(lambda x: x['sentence'].split(), new_field_name='words', is_input=True)
+ dataset.apply(lambda x: int(x['label']), new_field_name='target', is_target=True)
+ vocab = Vocabulary(min_freq=2).from_dataset(dataset, field_name='words')
+ vocab.index_dataset(dataset, field_name='words',new_field_name='words')
+
+ model = CNNText((len(vocab),word_embed), num_classes=5, padding=2, dropout=dropout)
+
+ train_dev_data, test_data = dataset.split(0.1)
+ train_data, dev_data = train_dev_data.split(0.1)
+
+ trainer = Trainer(model=model, train_data=train_data, dev_data=dev_data,
+ loss=CrossEntropyLoss(), metrics=AccuracyMetric(),
+ callbacks=[FitlogCallback(test_data)])
+ trainer.train()
+
+ fitlog.finish() # finish the logging
+
+用命令行在项目目录下执行 `python main.py` 之后,输出结果如下::
+
+ Auto commit by fitlog
+ input fields after batch(if batch size is 2):
+ words: (1)type:torch.Tensor (2)dtype:torch.int64, (3)shape:torch.Size([2, 11])
+ target fields after batch(if batch size is 2):
+ target: (1)type:torch.Tensor (2)dtype:torch.int64, (3)shape:torch.Size([2])
+
+ training epochs started 2019-05-23-21-11-51
+ Evaluation at Epoch 1/10. Step:2/20. AccuracyMetric: acc=0.285714
+
+ Evaluation at Epoch 2/10. Step:4/20. AccuracyMetric: acc=0.285714
+
+ Evaluation at Epoch 3/10. Step:6/20. AccuracyMetric: acc=0.285714
+
+ Evaluation at Epoch 4/10. Step:8/20. AccuracyMetric: acc=0.428571
+
+ Evaluation at Epoch 5/10. Step:10/20. AccuracyMetric: acc=0.571429
+
+ Evaluation at Epoch 6/10. Step:12/20. AccuracyMetric: acc=0.571429
+
+ Evaluation at Epoch 7/10. Step:14/20. AccuracyMetric: acc=0.285714
+
+ Evaluation at Epoch 8/10. Step:16/20. AccuracyMetric: acc=0.142857
+
+ Evaluation at Epoch 9/10. Step:18/20. AccuracyMetric: acc=0.285714
+
+ Evaluation at Epoch 10/10. Step:20/20. AccuracyMetric: acc=0.571429
+
+
+ In Epoch:5/Step:10, got best dev performance:AccuracyMetric: acc=0.571429
+ Reloaded the best model.
+
+现在,我们在项目目录下输入 `fitlog log logs` ,命令行会启动一个网页,默认 url 为 ``0.0.0.0:5000`` 。
+我们在浏览器中打开网页,可以看到如下的统计表格:
+
+.. image:: ../figures/fitlogTable.png
+
+如果我们点击action中的最后一个键钮,可以看到详细的 loss 图:
+
+.. image:: ../figures/fitlogChart.png
+
+更多的教程还在编写中,敬请期待~
\ No newline at end of file
diff --git a/fastNLP/core/callback.py b/fastNLP/core/callback.py
index c65f2a56..483f6dc1 100644
--- a/fastNLP/core/callback.py
+++ b/fastNLP/core/callback.py
@@ -54,6 +54,7 @@ __all__ = [
"GradientClipCallback",
"EarlyStopCallback",
"TensorboardCallback",
+ "FitlogCallback",
"LRScheduler",
"ControlC",
@@ -65,6 +66,7 @@ import os
import torch
from copy import deepcopy
+
try:
from tensorboardX import SummaryWriter
@@ -81,6 +83,7 @@ try:
except:
pass
+
class Callback(object):
"""
别名::class:`fastNLP.Callback` :class:`fastNLP.core.callback.Callback`
@@ -367,16 +370,17 @@ class GradientClipCallback(Callback):
每次backward前,将parameter的gradient clip到某个范围。
- :param None,torch.Tensor,List[torch.Tensor] parameters: 一般通过model.parameters()获得。如果为None则默认对Trainer
- 的model中所有参数进行clip
+ :param None,torch.Tensor,List[torch.Tensor] parameters: 一般通过model.parameters()获得。
+ 如果为None则默认对Trainer的model中所有参数进行clip
:param float clip_value: 将gradient 限制到[-clip_value, clip_value]。clip_value应该为正数
:param str clip_type: 支持'norm', 'value'
两种::
1 'norm', 将gradient的norm rescale到[-clip_value, clip_value]
- 2 'value', 将gradient限制在[-clip_value, clip_value], 小于-clip_value的gradient被赋值为-clip_value;
- 大于clip_value的gradient被赋值为clip_value.
+ 2 'value', 将gradient限制在[-clip_value, clip_value],
+ 小于-clip_value的gradient被赋值为-clip_value;
+ 大于clip_value的gradient被赋值为clip_value.
"""
@@ -431,6 +435,7 @@ class EarlyStopCallback(Callback):
else:
raise exception # 抛出陌生Error
+
class FitlogCallback(Callback):
"""
别名: :class:`fastNLP.FitlogCallback` :class:`fastNLP.core.callback.FitlogCallback`
@@ -463,7 +468,7 @@ class FitlogCallback(Callback):
assert 'test' not in data, "Cannot use `test` as DataSet key, when tester is passed."
setattr(tester, 'verbose', 0)
self.testers['test'] = tester
-
+
if isinstance(data, dict):
for key, value in data.items():
assert isinstance(value, DataSet), f"Only DataSet object is allowed, not {type(value)}."
@@ -473,22 +478,22 @@ class FitlogCallback(Callback):
self.datasets['test'] = data
else:
raise TypeError("data receives dict[DataSet] or DataSet object.")
-
+
self.verbose = verbose
self._log_loss_every = log_loss_every
self._avg_loss = 0
def on_train_begin(self):
- if (len(self.datasets)>0 or len(self.testers)>0 ) and self.trainer.dev_data is None:
+ if (len(self.datasets) > 0 or len(self.testers) > 0) and self.trainer.dev_data is None:
raise RuntimeError("Trainer has no dev data, you cannot pass extra data to do evaluation.")
-
- if len(self.datasets)>0:
+
+ if len(self.datasets) > 0:
for key, data in self.datasets.items():
tester = Tester(data=data, model=self.model, batch_size=self.batch_size, metrics=self.trainer.metrics,
verbose=0)
self.testers[key] = tester
fitlog.add_progress(total_steps=self.n_steps)
-
+
def on_backward_begin(self, loss):
if self._log_loss_every>0:
self._avg_loss += loss.item()
@@ -503,11 +508,11 @@ class FitlogCallback(Callback):
eval_result['epoch'] = self.epoch
fitlog.add_best_metric(eval_result)
fitlog.add_metric(eval_result, step=self.step, epoch=self.epoch)
- if len(self.testers)>0:
+ if len(self.testers) > 0:
for key, tester in self.testers.items():
try:
eval_result = tester.test()
- if self.verbose!=0:
+ if self.verbose != 0:
self.pbar.write("Evaluation on DataSet {}:".format(key))
self.pbar.write(tester._format_eval_results(eval_result))
fitlog.add_metric(eval_result, name=key, step=self.step, epoch=self.epoch)
@@ -515,10 +520,10 @@ class FitlogCallback(Callback):
fitlog.add_best_metric(eval_result, name=key)
except Exception:
self.pbar.write("Exception happens when evaluate on DataSet named `{}`.".format(key))
-
+
def on_train_end(self):
fitlog.finish()
-
+
def on_exception(self, exception):
fitlog.finish(status=1)
if self._log_exception:
diff --git a/fastNLP/core/trainer.py b/fastNLP/core/trainer.py
index 3b1a8bf5..40e5a5c1 100644
--- a/fastNLP/core/trainer.py
+++ b/fastNLP/core/trainer.py
@@ -507,7 +507,8 @@ class Trainer(object):
seconds: float, 表示训练时长
以下三个内容只有在提供了dev_data的情况下会有。
- best_eval: Dict of Dict, 表示evaluation的结果。第一层的key为Metric的名称,第二层的key为具体的Metric
+ best_eval: Dict of Dict, 表示evaluation的结果。第一层的key为Metric的名称,
+ 第二层的key为具体的Metric
best_epoch: int,在第几个epoch取得的最佳值
best_step: int, 在第几个step(batch)更新取得的最佳值