- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章使用pytorch和torchtext进行文本分类的实例由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
文本分类是NLP领域的较为容易的入门问题,本文记录我自己在做文本分类任务以及复现相关论文时的基本流程,绝大部分操作都使用了torch和torchtext两个库.
1. 文本数据预处理 。
首先数据存储在三个csv文件中,分别是train.csv,valid.csv,test.csv,第一列存储的是文本数据,例如情感分类问题经常是用户的评论review,例如imdb或者amazon数据集。第二列是情感极性polarity,N分类问题的话就有N个值,假设值得范围是0~N-1.
下面是很常见的文本预处理流程,英文文本的话不需要分词,直接按空格split就行了,这里只会主要说说第4点.
1、去除非文本部分 。
2、分词 。
3、去除停用词 。
4、对英文单词进行词干提取(stemming)和词型还原(lemmatization) 。
5、转为小写 。
6、特征处理 。
Bag of Words 。
Tf-idf 。
N-gram 。
Word2vec 。
词干提取和词型还原 。
1
2
3
4
|
from
nltk.stem
import
SnowballStemmer
stemmer
=
SnowballStemmer(
"english"
)
# 选择语言
from
nltk.stem
import
WordNetLemmatizer
wnl
=
WordNetLemmatizer()
|
SnowballStemmer较为激进,转换有可能出现错误,这里较为推荐使用WordNetLemmatizer,它一般只在非常肯定的情况下才进行转换,否则会返回原来的单词.
1
2
3
4
|
stemmer.stem(
'knives'
)
# knive
wnl.lemmatize(
'knives'
)
# knife
|
因为我没有系统学习和研究过NLTK的代码,所以就不多说了,有兴趣的可以自己去阅读NLTK的源码.
2. 使用torchtext加载文本数据 。
本节主要是用的模块是torchtext里的data模块,处理的数据同上一节所描述.
首先定义一个tokenizer用来处理文本,比如分词,小写化,如果你已经根据上一节的词干提取和词型还原的方法处理过文本里的每一个单词后可以直接分词就够了.
1
|
tokenize
=
lambda
x: x.split()
|
或者也可以更保险点,使用spacy库,不过就肯定更耗费时间了.
1
2
3
4
5
|
import
spacy
spacy_en
=
spacy.load(
'en'
)
def
tokenizer(text):
return
[toke.text
for
toke
in
spacy_en.tokenizer(text)]
|
然后要定义Field,至于Field是啥,你可以简单地把它理解为一个能够加载、预处理和存储文本数据和标签的对象。我们可以用它根据训练数据来建立词表,加载预训练的Glove词向量等等.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
def
DataLoader():
tokenize
=
lambda
x: x.split()
# 用户评论,include_lengths设为True是为了方便之后使用torch的pack_padded_sequence
REVIEW
=
data.Field(sequential
=
True
,tokenize
=
tokenize, include_lengths
=
True
)
# 情感极性
POLARITY
=
data.LabelField(sequential
=
False
, use_vocab
=
False
, dtype
=
torch.
long
)
# 假如train.csv文件并不是只有两列,比如1、3列是review和polarity,2列是我们不需要的数据,
# 那么就要添加一个全是None的元组, fields列表存储的Field的顺序必须和csv文件中每一列的顺序对应,
# 否则review可能就加载到polarity Field里去了
fields
=
[(
'review'
, REVIEW), (
None
,
None
), (
'polarity'
, POLARITY)]
# 加载train,valid,test数据
train_data, valid_data, test_data
=
data.TabularDataset.splits(
path
=
'amazon'
,
train
=
'train.csv'
,
validation
=
'valid.csv'
,
test
=
'test.csv'
,
format
=
'csv'
,
fields
=
fields,
skip_header
=
False
# 是否跳过文件的第一行
)
return
REVIEW, POLARITY, train_data
|
加载完数据可以开始建词表。如果本地没有预训练的词向量文件,在运行下面的代码时会自动下载到当前文件夹下的'.vector_cache'文件夹内,如果本地已经下好了,可以用Vectors指定文件名name,路径cache,还可以使用Glove.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
from
torchtext.vocab
import
Vectors, Glove
import
torch
REVIEW, POLARITY, train_data
=
DataLoader()
# vectors = Vectors(name='glove.6B.300d.txt', cache='.vector_cache')
REVIEW.build_vocab(train_data,
# 建词表是用训练集建,不要用验证集和测试集
max_size
=
400000
,
# 单词表容量
vectors
=
'glove.6B.300d'
,
# 还有'glove.840B.300d'已经很多可以选
unk_init
=
torch.Tensor.normal_
# 初始化train_data中不存在预训练词向量词表中的单词
)
# print(REVIEW.vocab.freqs.most_common(20)) 数据集里最常出现的20个单词
# print(REVIEW.vocab.itos[:10]) 列表 index to word
# print(REVIEW.vocab.stoi) 字典 word to index
|
接着就是把预训练词向量加载到model的embedding weight里去了.
1
2
3
4
5
6
7
|
pretrained_embeddings
=
REVIEW.vocab.vectors
model.embedding.weight.data.copy_(pretrained_embeddings)
UNK_IDX
=
REVIEW.vocab.stoi[REVIEW.unk_token]
PAD_IDX
=
REVIEW.vocab.stoi[REVIEW.pad_token]
# 因为预训练的权重的unk和pad的词向量不是在我们的数据集语料上训练得到的,所以最好置零
model.embedding.weight.data[UNK_IDX]
=
torch.zeros(EMBEDDING_DIM)
model.embedding.weight.data[PAD_IDX]
=
torch.zeros(EMBEDDING_DIM)
|
然后用torchtext的迭代器来批量加载数据,torchtext.data里的BucketIterator非常好用,它可以把长度相近的文本数据尽量都放到一个batch里,这样最大程度地减少padding,数据就少了很多无意义的0,也减少了矩阵计算量,也许还能对最终准确度有帮助(误)?我凭直觉猜的,没有做实验对比过,但是至少能加速训练迭代应该是没有疑问的,如果哪天我有钱了买了台好点的服务器做完实验再来补充.
sort_within_batch设为True的话,一个batch内的数据就会按sort_key的排列规则降序排列,sort_key是排列的规则,这里使用的是review的长度,即每条用户评论所包含的单词数量.
1
2
3
4
5
6
|
train_iterator, valid_iterator, test_iterator
=
data.BucketIterator.splits(
(train_data, valid_data, test_data),
batch_size
=
32
,
sort_within_batch
=
True
,
sort_key
=
lambda
x:
len
(x.review),
device
=
torch.device(
'cpu'
))
|
最后就是加载数据喂给模型了.
1
2
3
4
5
6
7
8
|
for
batch
in
train_iterator:
# 因为REVIEW Field的inclue_lengths为True,所以还会包含一个句子长度的Tensor
review, review_len
=
batch.review
# review.size = (seq_length, batch_size) , review_len.size = (batch_size, )
polarity
=
batch.polarity
# polarity.size = (batch_size, )
predictions
=
model(review, review_lengths)
loss
=
criterion(predictions, polarity)
# criterion = nn.CrossEntropyLoss()
|
3. 使用pytorch写一个LSTM情感分类器 。
下面是我简略写的一个模型,仅供参考 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
import
torch.nn as nn
import
torch.nn.functional as F
from
torch.nn.utils.rnn
import
pack_padded_sequence
import
torch
class
LSTM(nn.Module):
def
__init__(
self
, vocab_size, embedding_dim, hidden_dim, output_dim,
n_layers, bidirectional, dropout, pad_idx):
super
(LSTM,
self
).__init__()
self
.embedding
=
nn.Embedding(vocab_size, embedding_dim, padding_idx
=
pad_idx)
self
.lstm
=
nn.LSTM(embedding_dim, hidden_dim, num_layers
=
n_layers,
bidirectional
=
bidirectional, dropout
=
dropout)
self
.Ws
=
nn.Parameter(torch.Tensor(hidden_dim, output_dim))
self
.bs
=
nn.Parameter(torch.zeros((output_dim, )))
nn.init.uniform_(
self
.Ws,
-
0.1
,
0.1
)
nn.init.uniform_(
self
.bs,
-
0.1
,
0.1
)
self
.dropout
=
nn.Dropout(p
=
0.5
)
def
forward(
self
, x, x_len):
x
=
self
.embedding(x)
x
=
pack_padded_sequence(x, x_len)
H, (h_n, c_n)
=
self
.lstm(x)
h_n
=
self
.dropout(h_n)
h_n
=
torch.squeeze(h_n)
res
=
torch.matmul(h_n,
self
.Ws)
+
self
.bs
y
=
F.softmax(res, dim
=
1
)
# y.size(batch_size, output_dim)
return
y
|
训练函数 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
def
train(model, iterator, optimizer, criterion):
epoch_loss
=
0
num_sample
=
0
correct
=
0
model.train()
for
batch
in
iterator:
optimizer.zero_grad()
review, review_lengths
=
batch.review
polarity
=
batch.polarity
predictions
=
model(review, review_lengths)
correct
+
=
torch.
sum
(torch.argmax(preds, dim
=
1
)
=
=
polarity)
loss
=
criterion(predictions, polarity)
loss.backward()
epoch_loss
+
=
loss.item()
num_sample
+
=
len
(batch)
optimizer.step()
return
epoch_loss
/
num_sample, correct.
float
()
/
num_sample
if
__name__
=
=
'__main__'
:
for
epoch
in
range
(N_EPOCHS):
train_loss, acc
=
train(model, train_iter, optimizer, criterion)
print
(f
'\tTrain Loss: {train_loss:.3f} | Train Acc: {acc* 100:.2f}%'
)
|
注意事项和遇到的一些坑 。
文本情感分类需不需要去除停用词?
应该是不用的,否则acc有可能下降.
data.TabularDataset.splits虽然好用,但是如果你只想加载训练集,这时候如果直接不给validation和test参数赋值,那么其他代码和原来一样,比如这样 。
1
2
3
4
5
6
7
|
train_data
=
data.TabularDataset.splits(
path
=
'',
train
=
'train.csv'
,
format
=
'csv'
,
fields
=
fields,
skip_header
=
False
# 是否跳过文件的第一行
)
|
那么底下你一定会报错,因为data.TabularDataset.splits返回的是一个元组,也就是如果是训练验证测试三个文件都给了函数,就返回(train_data, valid_data, test_data),这时候你用三个变量去接受函数返回值当然没问题,元组会自动拆包.
当只给函数一个文件train.csv时,函数返回的是(train_data)而非train_data,因此正确的写法应该如下 。
1
2
3
4
5
6
7
|
train_data
=
data.TabularDataset.splits(
path
=
'',
train
=
'train.csv'
,
format
=
'csv'
,
fields
=
fields,
skip_header
=
False
# 是否跳过文件的第一行
)[
0
]
# 注意这里的切片,选择元组的第一个也是唯一一个元素赋给train_data
|
同理data.BucketIterator.splits也有相同的问题,它不但返回的是元组,它的参数datasets要求也是以元组形式,即(train_data, valid_data, test_data)进行赋值,否则在下面的运行中也会出现各种各样奇怪的问题.
如果你要生成两个及以上的迭代器,那么没问题,直接照上面写就完事了.
如果你只要生成train_iterator,那么正确的写法应该是下面这样 。
1
2
3
4
5
6
7
8
|
train_iter
=
data.BucketIterator(
train_data,
batch_size
=
32
,
sort_key
=
lambda
x:
len
(x.review),
sort_within_batch
=
True
,
shuffle
=
True
# 训练集需要shuffle,但因为验证测试集不需要
# 可以生成验证和测试集的迭代器直接用data.iterator.Iterator类就足够了
)
|
出现的问题 x = pack_padded_sequence(x, x_len) 当数据集有长度为0的句子时, 就会后面报错 。
Adagrad效果比Adam好的多 。
4. 总结 。
不仅仅是NLP领域,在各大顶会中,越来越多的学者选择使用Pytorch而非TensorFlow,主要原因就是因为它的易用性,torchtext和pytorch搭配起来是非常方便的NLP工具,可以大大缩短文本预处理,加载数据的时间.
我本人之前用过tf 1.x以及keras,最终拥抱了Pytorch,也是因为它与Numpy极其类似的用法,更Pythonic的代码,清晰的源码让我在遇到bug时能一步一步找到问题所在,动态图让人能随时看到输出的Tensor的全部信息,这些都是Pytorch的优势.
现在tf 2.0也在不断改进,有人笑称tf越来越像pytorch了,其实pytorch也在不断向tf学习,在工业界,tf仍然处于王者地位,不知道未来pytorch能不能在工业界也与tf平分秋色,甚至更胜一筹呢?
以上这篇使用pytorch和torchtext进行文本分类的实例就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我.
原文链接:https://blog.csdn.net/qq_40367479/article/details/102772334 。
最后此篇关于使用pytorch和torchtext进行文本分类的实例的文章就讲到这里了,如果你想了解更多关于使用pytorch和torchtext进行文本分类的实例的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
已关闭。此问题不符合Stack Overflow guidelines 。目前不接受答案。 这个问题似乎与 help center 中定义的范围内的编程无关。 . 已关闭 3 年前。 此帖子于去年编辑
据我所知,在使用 GPU 训练和验证模型时,GPU 内存主要用于加载数据,向前和向后。据我所知,我认为 GPU 内存使用应该相同 1) 训练前,2) 训练后,3) 验证前,4) 验证后。但在我的例子中
我正在尝试在 PyTorch 中将两个复数矩阵相乘,看起来 the torch.matmul functions is not added yet to PyTorch library for com
我正在尝试定义二分类问题的损失函数。但是,目标标签不是硬标签0,1,而是0~1之间的一个 float 。 Pytorch 中的 torch.nn.CrossEntropy 不支持软标签,所以我想自己写
我正在尝试让 PyTorch 与 DataLoader 一起工作,据说这是处理小批量的最简单方法,在某些情况下这是获得最佳性能所必需的。 DataLoader 需要一个数据集作为输入。 大多数关于 D
Pytorch Dataloader 的迭代顺序是否保证相同(在温和条件下)? 例如: dataloader = DataLoader(my_dataset, batch_size=4,
PyTorch 的负对数似然损失,nn.NLLLoss定义为: 因此,如果以单批处理的标准重量计算损失,则损失的公式始终为: -1 * (prediction of model for correct
在PyTorch中,new_ones()与ones()有什么区别。例如, x2.new_ones(3,2, dtype=torch.double) 与 torch.ones(3,2, dtype=to
假设我有一个矩阵 src带形状(5, 3)和一个 bool 矩阵 adj带形状(5, 5)如下, src = tensor([[ 0, 1, 2], [ 3, 4,
我想知道如果不在第 4 行中使用“for”循环,下面的代码是否有更有效的替代方案? import torch n, d = 37700, 7842 k = 4 sample = torch.cat([
我有三个简单的问题。 如果我的自定义损失函数不可微会发生什么? pytorch 会通过错误还是做其他事情? 如果我在我的自定义函数中声明了一个损失变量来表示模型的最终损失,我应该放 requires_
我想知道 PyTorch Parameter 和 Tensor 的区别? 现有answer适用于使用变量的旧 PyTorch? 最佳答案 这就是 Parameter 的全部想法。类(附加)在单个图像中
给定以下张量(这是网络的结果 [注意 grad_fn]): tensor([121., 241., 125., 1., 108., 238., 125., 121., 13., 117., 12
什么是__constants__在 pytorch class Linear(Module):定义于 https://pytorch.org/docs/stable/_modules/torch/nn
我在哪里可以找到pytorch函数conv2d的源代码? 它应该在 torch.nn.functional 中,但我只找到了 _add_docstr 行, 如果我搜索conv2d。我在这里看了: ht
如 documentation 中所述在 PyTorch 中,Conv2d 层使用默认膨胀为 1。这是否意味着如果我想创建一个简单的 conv2d 层,我必须编写 nn.conv2d(in_chann
我阅读了 Pytorch 的源代码,发现它没有实现 convolution_backward 很奇怪。函数,唯一的 convolution_backward_overrideable 函数是直接引发错
我对编码真的很陌生,现在我正在尝试将我的标签变成一种热门编码。我已经完成将 np.array 传输到张量,如下所示 tensor([4., 4., 4., 4., 4., 4., 4., 4., 4.
我正在尝试实现 text classification model使用CNN。据我所知,对于文本数据,我们应该使用一维卷积。我在 pytorch 中看到了一个使用 Conv2d 的示例,但我想知道如何
我有一个多标签分类问题,我正试图用 Pytorch 中的 CNN 解决这个问题。我有 80,000 个训练示例和 7900 个类;每个示例可以同时属于多个类,每个示例的平均类数为 130。 问题是我的
我是一名优秀的程序员,十分优秀!