Skip to content

Commit 86b3b0c

Browse files
committed
update
1 parent 831df33 commit 86b3b0c

File tree

1 file changed

+171
-0
lines changed

1 file changed

+171
-0
lines changed

torchtext.md

+171
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
## 简介
2+
3+
`torchtext` 可以方便的完成模型训练的前期数据预处理工作,常见功能有:
4+
5+
- 将句子转化成分词列表
6+
- 构建当前语料库中单词的词汇表,实现word和id之间的映射
7+
- 将数据集转化为一个一个的batch,训练时直接使用
8+
9+
10+
11+
12+
13+
## 基本原理
14+
15+
![](https://img2018.cnblogs.com/blog/1417244/201908/1417244-20190810142640277-664626915.png)
16+
17+
- 三大核心要素:`field``dataset``iterator`
18+
- `field`定义指定字段的处理方法
19+
- `dataset`定义语料库
20+
- `iterator`定义训练和测试模型时候的迭代器,里面是一个一个的`batch`
21+
22+
23+
24+
## 代码分析
25+
26+
#### field
27+
28+
- 一般情况下定义两个field:`text_field``label_field`分别定义文本域和标签域的处理方法,常见的属性为:
29+
30+
- lower = False:是否把数据转化为小写
31+
- sequential = True:是否把数据表示成序列,如果是False, 不能使用分词
32+
- 特别注意`pad_token='<pad>'``unk_token='<unk>'`,在label中不建议使用,可以定义为`None`
33+
```python
34+
def word_cut(text):
35+
text = re.compile(r'[^A-Za-z0-9\u4e00-\u9fa5]').sub(' ', text)
36+
# 将非中文字符、非a-z, 非A-Z,非0-9 全部替换为' '
37+
return [word.strip() for word in jieba.cut(text) if word.strip()]
38+
39+
40+
text_field = data.Field(lower=True, tokenize=word_cut)
41+
label_field = data.Field(sequential=False, unk_token=None, pad_token=None)
42+
```
43+
44+
- 之后传递`text_field``label_field`的时候是传递了对象的引用,所以会直接修改两个`field`对象
45+
46+
47+
48+
#### dataset
49+
50+
- dataset定义语料库,将文本转换为一个个example对象,准备好训练集和测试集之后,可以使用内置的split函数划分训练集和测试集,其中split参数如下
51+
52+
- path:数据所在的路径
53+
- format:数据的格式,tsv为 `\t` 分割的数据集
54+
- skip_header:是否跳过第一行
55+
- train、test:训练集和测试集文件名
56+
- fields:`list(tuple(string, field))` ,string为文件中每一列的列名,field为之前创建的field对象,定义了该个字段的处理方法,None表示忽略这个字段
57+
58+
```python
59+
train_dataset, test_dataset = data.TabularDataset.splits(
60+
path='data', format='tsv', skip_header=True,
61+
train='train.tsv', test='test.tsv',
62+
fields=[
63+
('index', None),
64+
('label', label_field),
65+
('text', text_field)
66+
]
67+
)
68+
```
69+
70+
71+
72+
#### vocab
73+
74+
- 此时完成了将文本转化为语料库的工作,但此时语料库中为 一个分词后的句子 + 一个标签 的形式,还需要处理成模型的输入,需要建立当前字段的语料库,方法是field中定义的build_vocab函数
75+
76+
- 如果使用与训练词向量,需要在函数中指定vectors参数,该参数是一个Vectors对象
77+
78+
```python
79+
label_field.build_vocab(train_dataset, test_dataset)
80+
81+
if args.static and args.pretrained_name and args.pretrained_path:
82+
vectors = Vectors(name=args.pretrained_name, cache=args.pretrained_path)
83+
text_field.build_vocab(train_dataset, test_dataset, vectors=vectors)
84+
else:
85+
text_field.build_vocab(train_dataset, test_dataset)
86+
```
87+
88+
89+
90+
- `build_vocab` 完成之后,对应的field之中会创建一个vocab对象,为词汇表
91+
- `itos`:一个list,获取对应index的word,`word = itos[index]`
92+
- `stoi`:一个dict,获取对应word的index,`index = stoi[word]`
93+
- `len(field.vocab)`:返回词汇表的长度
94+
95+
- 模型中可以使用如下代码定义部分层
96+
97+
```python
98+
self.embedding = nn.Embedding(len(text_field.vocab), embedding_dimension)
99+
output_size = len(label_field.vocab)
100+
self.fc = nn.Linear(input_size, output_size)
101+
```
102+
103+
- 需要注意,因为field在创建的时候默认的`pad_token='<pad>', unk_token='<unk>'`,如果不做处理的话 `output_size`中会因为两个默认的token儿变大,所以定义field的时候可以将两个设置为None,参见 [field](#field)
104+
105+
106+
107+
#### iterator
108+
109+
- 创建完语料库之后,需要对语料库batch化,使用`Iterator.splits`方法划分训练集和测试集合的迭代器
110+
111+
```python
112+
train_iter, test_iter = data.Iterator.splits(
113+
(train_dataset, test_dataset),
114+
batch_sizes=(args.batch_size, len(test_dataset)),
115+
sort_key=lambda x: len(x.text),
116+
**kwargs # device=-1, repeat=False, shuffle=True
117+
)
118+
```
119+
120+
- 第一个tuple指明了划分的两个dataset,两个dataset里面有指向两个field的引用,所以里面iterator里面可以拿到词汇表
121+
- batch_sizes指明了两个iterator的batch大小
122+
- sort_key用于排序
123+
124+
125+
126+
## 使用
127+
128+
#### 数据集训练
129+
130+
- 创建完`torchtext``iterator`对象之后,iter里面内置了 `__iter(self)__` 函数,使用方法为:
131+
132+
```python
133+
for batch in train_iter:
134+
feature, target = batch.text, batch.label
135+
feature.data.t_()
136+
logits = model(feature)
137+
```
138+
139+
140+
141+
#### 一般分类
142+
143+
- 模型训练完成之后需要模型在所有的数据上都能时候,而非训练测试两个数据。对于一般的数据处理思路如下:
144+
145+
- 首先将文本分词
146+
- **将分词后的文本转化为数值tensor**
147+
- 将tensor放到模型中,获取预测结果
148+
149+
-[vocab](#vocab) 中提到了每个field在build_vocab完成之后会创建一个vocab对象,完成string和int之间的转化
150+
151+
```python
152+
# 保存词汇表
153+
with open("data/vocab.pkl", "wb") as f:
154+
pickle.dump(vocab, f)
155+
156+
# 读取词汇表
157+
with open("data/vocab.pkl", "rb") as f:
158+
vocab = pickle.load(f)
159+
```
160+
161+
- 利用vocab对象中的stoi属性获取单词在词汇表中的index
162+
163+
```python
164+
text = "外观漂亮,安全性佳,动力够强,油耗够低"
165+
text = re.compile(r'[^A-Za-z0-9\u4e00-\u9fa5]').sub(' ', text)
166+
words = [word.strip() for word in jieba.cut(text) if word.strip()]
167+
indexes = [vocab.stoi[word] for word in words] # list(int)
168+
```
169+
170+
171+

0 commit comments

Comments
 (0)