未验证 提交 713efd45 编写于 作者: K KP 提交者: GitHub

Custom dataset tutorial (#1165)

* Add tutorial about nlp dataset customization

* Update doc and tokenizer usage in seq-cls demo

* Updata tutorial
上级 394e4849
...@@ -50,6 +50,7 @@ model = hub.Module(name='ernie_tiny', version='2.0.1', task='token-cls', label_m ...@@ -50,6 +50,7 @@ model = hub.Module(name='ernie_tiny', version='2.0.1', task='token-cls', label_m
* `name`:模型名称,可以选择`ernie``ernie_tiny``bert-base-cased``bert-base-chinese`, `roberta-wwm-ext``roberta-wwm-ext-large`等。 * `name`:模型名称,可以选择`ernie``ernie_tiny``bert-base-cased``bert-base-chinese`, `roberta-wwm-ext``roberta-wwm-ext-large`等。
* `version`:module版本号 * `version`:module版本号
* `task`:fine-tune任务。此处为`token-cls`,表示序列标注任务。 * `task`:fine-tune任务。此处为`token-cls`,表示序列标注任务。
* `label_map`:数据集中的标签信息,实体识别任务中需要根据不同标签种类对模型性能进行评价。
PaddleHub还提供BERT等模型可供选择, 当前支持序列标注任务的模型对应的加载示例如下: PaddleHub还提供BERT等模型可供选择, 当前支持序列标注任务的模型对应的加载示例如下:
......
...@@ -31,7 +31,7 @@ python train.py ...@@ -31,7 +31,7 @@ python train.py
```python ```python
import paddlehub as hub import paddlehub as hub
model = hub.Module(name='ernie_tiny', version='2.0.1', task='seq-cls') model = hub.Module(name='ernie_tiny', version='2.0.1', task='seq-cls', num_classes=2)
``` ```
其中,参数: 其中,参数:
...@@ -39,6 +39,29 @@ model = hub.Module(name='ernie_tiny', version='2.0.1', task='seq-cls') ...@@ -39,6 +39,29 @@ model = hub.Module(name='ernie_tiny', version='2.0.1', task='seq-cls')
* `name`:模型名称,可以选择`ernie``ernie_tiny``bert-base-cased``bert-base-chinese`, `roberta-wwm-ext``roberta-wwm-ext-large`等。 * `name`:模型名称,可以选择`ernie``ernie_tiny``bert-base-cased``bert-base-chinese`, `roberta-wwm-ext``roberta-wwm-ext-large`等。
* `version`:module版本号 * `version`:module版本号
* `task`:fine-tune任务。此处为`seq-cls`,表示文本分类任务。 * `task`:fine-tune任务。此处为`seq-cls`,表示文本分类任务。
* `num_classes`:表示当前文本分类任务的类别数,根据具体使用的数据集确定,默认为2。
PaddleHub还提供BERT等模型可供选择, 当前支持文本分类任务的模型对应的加载示例如下:
模型名 | PaddleHub Module
---------------------------------- | :------:
ERNIE, Chinese | `hub.Module(name='ernie')`
ERNIE tiny, Chinese | `hub.Module(name='ernie_tiny')`
ERNIE 2.0 Base, English | `hub.Module(name='ernie_v2_eng_base')`
ERNIE 2.0 Large, English | `hub.Module(name='ernie_v2_eng_large')`
BERT-Base, Cased | `hub.Module(name='bert-base-cased')`
BERT-Base, Uncased | `hub.Module(name='bert-base-uncased')`
BERT-Large, Cased | `hub.Module(name='bert-large-cased')`
BERT-Large, Uncased | `hub.Module(name='bert-large-uncased')`
BERT-Base, Multilingual Cased | `hub.Module(nane='bert-base-multilingual-cased')`
BERT-Base, Multilingual Uncased | `hub.Module(nane='bert-base-multilingual-uncased')`
BERT-Base, Chinese | `hub.Module(name='bert-base-chinese')`
BERT-wwm, Chinese | `hub.Module(name='chinese-bert-wwm')`
BERT-wwm-ext, Chinese | `hub.Module(name='chinese-bert-wwm-ext')`
RoBERTa-wwm-ext, Chinese | `hub.Module(name='roberta-wwm-ext')`
RoBERTa-wwm-ext-large, Chinese | `hub.Module(name='roberta-wwm-ext-large')`
RBT3, Chinese | `hub.Module(name='rbt3')`
RBTL3, Chinese | `hub.Module(name='rbtl3')`
通过以上的一行代码,`model`初始化为一个适用于文本分类任务的模型,为ERNIE Tiny的预训练模型后拼接上一个全连接网络(Full Connected)。 通过以上的一行代码,`model`初始化为一个适用于文本分类任务的模型,为ERNIE Tiny的预训练模型后拼接上一个全连接网络(Full Connected)。
![](https://ai-studio-static-online.cdn.bcebos.com/f9e1bf9d56c6412d939960f2e3767c2f13b93eab30554d738b137ab2b98e328c) ![](https://ai-studio-static-online.cdn.bcebos.com/f9e1bf9d56c6412d939960f2e3767c2f13b93eab30554d738b137ab2b98e328c)
...@@ -49,9 +72,9 @@ model = hub.Module(name='ernie_tiny', version='2.0.1', task='seq-cls') ...@@ -49,9 +72,9 @@ model = hub.Module(name='ernie_tiny', version='2.0.1', task='seq-cls')
```python ```python
train_dataset = hub.datasets.ChnSentiCorp( train_dataset = hub.datasets.ChnSentiCorp(
tokenizer=model.get_tokenizer(tokenize_chinese_chars=True), max_seq_len=128, mode='train') tokenizer=model.get_tokenizer(), max_seq_len=128, mode='train')
dev_dataset = hub.datasets.ChnSentiCorp( dev_dataset = hub.datasets.ChnSentiCorp(
tokenizer=model.get_tokenizer(tokenize_chinese_chars=True), max_seq_len=128, mode='dev') tokenizer=model.get_tokenizer(), max_seq_len=128, mode='dev')
``` ```
* `tokenizer`:表示该module所需用到的tokenizer,其将对输入文本完成切词,并转化成module运行所需模型输入格式。 * `tokenizer`:表示该module所需用到的tokenizer,其将对输入文本完成切词,并转化成module运行所需模型输入格式。
......
...@@ -11,21 +11,43 @@ ...@@ -11,21 +11,43 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
import paddle import paddle
import paddlehub as hub import paddlehub as hub
from paddlehub.datasets import ChnSentiCorp
import ast
import argparse
parser = argparse.ArgumentParser(__doc__)
parser.add_argument("--num_epoch", type=int, default=3, help="Number of epoches for fine-tuning.")
parser.add_argument("--use_gpu", type=ast.literal_eval, default=True, help="Whether use GPU for fine-tuning, input should be True or False")
parser.add_argument("--learning_rate", type=float, default=5e-5, help="Learning rate used to train with warmup.")
parser.add_argument("--max_seq_len", type=int, default=128, help="Number of words of the longest seqence.")
parser.add_argument("--batch_size", type=int, default=32, help="Total examples' number in batch for training.")
parser.add_argument("--checkpoint_dir", type=str, default='./checkpoint', help="Directory to model checkpoint")
parser.add_argument("--save_interval", type=int, default=1, help="Save checkpoint every n epoch.")
args = parser.parse_args()
if __name__ == '__main__': if __name__ == '__main__':
model = hub.Module(name='ernie_tiny', version='2.0.1', task='seq-cls') model = hub.Module(name='ernie_tiny', version='2.0.1', task='seq-cls')
train_dataset = hub.datasets.ChnSentiCorp( train_dataset = ChnSentiCorp(
tokenizer=model.get_tokenizer(tokenize_chinese_chars=True), max_seq_len=128, mode='train') tokenizer=model.get_tokenizer(), max_seq_len=args.max_seq_len, mode='train')
dev_dataset = hub.datasets.ChnSentiCorp( dev_dataset = ChnSentiCorp(
tokenizer=model.get_tokenizer(tokenize_chinese_chars=True), max_seq_len=128, mode='dev') tokenizer=model.get_tokenizer(), max_seq_len=args.max_seq_len, mode='dev')
test_dataset = hub.datasets.ChnSentiCorp( test_dataset = ChnSentiCorp(
tokenizer=model.get_tokenizer(tokenize_chinese_chars=True), max_seq_len=128, mode='test') tokenizer=model.get_tokenizer(), max_seq_len=args.max_seq_len, mode='test')
optimizer = paddle.optimizer.AdamW(learning_rate=5e-5, parameters=model.parameters())
trainer = hub.Trainer(model, optimizer, checkpoint_dir='test_ernie_text_cls', use_gpu=True)
trainer.train(train_dataset, epochs=3, batch_size=32, eval_dataset=dev_dataset, save_interval=1) optimizer = paddle.optimizer.AdamW(
trainer.evaluate(test_dataset, batch_size=32) learning_rate=args.learning_rate, parameters=model.parameters())
trainer = hub.Trainer(model, optimizer, checkpoint_dir=args.checkpoint_dir, use_gpu=args.use_gpu)
trainer.train(
train_dataset,
epochs=args.num_epoch,
batch_size=args.batch_size,
eval_dataset=dev_dataset,
save_interval=args.save_interval,
)
trainer.evaluate(test_dataset, batch_size=args.batch_size)
...@@ -175,3 +175,143 @@ ccolor_set = MiniCOCO(transforms, mode='train') ...@@ -175,3 +175,143 @@ ccolor_set = MiniCOCO(transforms, mode='train')
``` ```
* `transforms`: 数据预处理方式。 * `transforms`: 数据预处理方式。
* `mode`: 选择数据模式,可选项有 `train`, `test`, 默认为`train` * `mode`: 选择数据模式,可选项有 `train`, `test`, 默认为`train`
## 四、文本分类数据集
利用PaddleHub进行文本分类任务使用自定义数据时,需要切分数据集,将数据集切分为训练集和测试集。
### 数据准备
#### 1. 设置数据集目录
用户需要将数据集目录设定为如下格式:
```shell
├──data: 数据目录
├── train.txt: 训练集数据
├── dev.txt: 验证集数据
└── test.txt: 测试集数据
```
#### 2. 设置文件格式和内容
训练/验证/测试集的数据文件的编码格式建议为utf8格式。内容的第一列是文本类别标签,第二列为文本内容,列与列之间以Tab键分隔。建议在数据集文件第一行填写列说明"label"和"text_a",中间以Tab键分隔,示例如下:
```shell
label text_a
房产 昌平京基鹭府10月29日推别墅1200万套起享97折
教育 贵州2011高考录取分数线发布理科一本448分
社会 众多白领因集体户口面临结婚难题
...
```
### 数据集加载
加载文本分类的自定义数据集,用户仅需要继承基类TextClassificationDataset,修改数据集存放地址以及类别即可,具体可以参考如下代码:
```python
from paddlehub.datasets.base_nlp_dataset import TextClassificationDataset
class MyDataset(TextClassificationDataset):
# 数据集存放目录
base_path = '/path/to/dataset'
# 数据集的标签列表
label_list=['体育', '科技', '社会', '娱乐', '股票', '房产', '教育', '时政', '财经', '星座', '游戏', '家居', '彩票', '时尚']
def __init__(self, tokenizer, max_seq_len: int = 128, mode: str = 'train'):
if mode == 'train':
data_file = 'train.txt'
elif mode == 'test':
data_file = 'test.txt'
else:
data_file = 'dev.txt'
super().__init__(
base_path=self.base_path,
tokenizer=tokenizer,
max_seq_len=max_seq_len,
mode=mode,
data_file=data_file,
label_list=self.label_list,
is_file_with_header=True)
# 选择所需要的模型,获取对应的tokenizer
import paddlehub as hub
model = hub.Module(name='ernie_tiny', task='seq-cls', num_classes=len(MyDataset.label_list))
tokenizer = model.get_tokenizer()
# 实例化训练集
train_dataset = MyDataset(tokenizer)
```
至此用户可以通过MyDataset实例化获取对应的数据集,可以通过hub.Trainer对预训练模型`model`完成文本分类任务,详情可参考[PaddleHub文本分类demo](https://github.com/PaddlePaddle/PaddleHub/tree/release/v2.0.0-beta/demo/text_classification)
## 五、序列标注数据集
利用PaddleHub进行序列标注任务使用自定义数据时,需要切分数据集,将数据集切分为训练集和测试集。
### 数据准备
#### 1. 设置数据集目录
用户需要将数据集目录设定为如下格式:
```shell
├──data: 数据目录
├── train.txt: 训练集数据
├── dev.txt: 验证集数据
└── test.txt: 测试集数据
```
#### 2. 设置文件格式和内容
训练/验证/测试集的数据文件的编码格式建议为utf8格式。内容的第一列是文本内容, 第二列为文本中每个token对应的标签。需要注意的是,在文本和标签中,都需使用分隔符(该例子中使用的是斜杠`/`)隔开不同的token。
列与列之间以Tab键分隔。建议在数据集文件第一行填写列说明"label"和"text_a",中间以Tab键分隔,示例如下:
```shell
text_a label
5/月/1/2/日/,/北/京/市/怀/柔/县/民/政/局/、/畜/牧/局/领/导/来/到/驻/守/在/偏/远/山/区/的/武/警/北/京/一/总/队/十/支/队/十/四/中/队/。 O/O/O/O/O/O/B-LOC/I-LOC/I-LOC/B-ORG/I-ORG/I-ORG/I-ORG/I-ORG/I-ORG/O/B-ORG/I-ORG/I-ORG/O/O/O/O/O/O/O/O/O/O/O/O/B-ORG/I-ORG/I-ORG/I-ORG/I-ORG/I-ORG/I-ORG/I-ORG/I-ORG/I-ORG/I-ORG/I-ORG/I-ORG/I-ORG/O
他/每/年/还/为/河/北/农/业/大/学/扶/助/多/名/贫/困/学/生/。 O/O/O/O/O/B-ORG/I-ORG/I-ORG/I-ORG/I-ORG/I-ORG/O/O/O/O/O/O/O/O/O
...
```
### 数据准备
加载文本分类的自定义数据集,用户仅需要继承基类SeqLabelingDataset,修改数据集存放地址、类别信息和分隔符即可,具体可以参考如下代码:
```python
from paddlehub.datasets.base_nlp_dataset import SeqLabelingDataset
class MyDataset(SeqLabelingDataset):
# 数据集存放目录
base_path = '/path/to/dataset'
# 数据集的标签列表
label_list = ["B-PER", "I-PER", "B-ORG", "I-ORG", "B-LOC", "I-LOC", "O"]
label_map = {idx: label for idx, label in enumerate(label_list)}
# 数据文件使用的分隔符
split_char = '/'
def __init__(self, tokenizer, max_seq_len: int = 128, mode: str = 'train'):
if mode == 'train':
data_file = 'train.txt'
elif mode == 'test':
data_file = 'test.txt'
else:
data_file = 'dev.txt'
super().__init__(
base_path=self.base_path,
tokenizer=tokenizer,
max_seq_len=max_seq_len,
mode=mode,
data_file=data_file,
label_file=None,
label_list=self.label_list,
split_char=self.split_char,
is_file_with_header=True)
# 选择所需要的模型,获取对应的tokenizer
import paddlehub as hub
model = hub.Module(name='ernie_tiny', task='token-cls', label_map=MyDataset.label_map)
tokenizer = model.get_tokenizer()
# 实例化训练集
train_dataset = MyDataset(tokenizer)
```
至此用户可以通过MyDataset实例化获取对应的数据集,可以通过hub.Trainer对预训练模型`model`完成系列标注任务,详情可参考[PaddleHub序列标注demo](https://github.com/PaddlePaddle/PaddleHub/tree/release/v2.0.0-beta/demo/sequence_labeling)
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册