当前位置:   article > 正文

Pytorch:嵌入层Embedding、EmbeddingBag_pytorch神经网络的嵌入层

pytorch神经网络的嵌入层

日萌社

 

人工智能AI:Keras PyTorch MXNet TensorFlow PaddlePaddle 深度学习实战(不定时更新)


  1. Embedding
  2. keras.layers.Embedding(input_dim, output_dim, embeddings_initializer='uniform',
  3. embeddings_regularizer=None, activity_regularizer=None,
  4. embeddings_constraint=None, mask_zero=False, input_length=None)
  5. 1.将正整数(索引值)转换为固定尺寸的稠密向量。 例如: [[4], [20]] -> [[0.25, 0.1], [0.6, -0.2]]
  6. 该层只能用作模型中的第一层。
  7. 2.Embedding层输入是一维[单个字符/单个单词],那么输出为二维[单个字符/单个单词, embedding_dim];
  8. Embedding层输入是二维[batch_size, 单个字符/单个单词],那么输出为三维[batch_size, 单个字符/单个单词, embedding_dim]。
  9. 1.例子
  10. model = Sequential()
  11. model.add(Embedding(1000, 64, input_length=10))
  12. # 模型将输入一个大小为 (batch, input_length) 的整数矩阵。
  13. # 输入中最大的整数(即词索引)不应该大于 999 (词汇表大小)
  14. # 现在 model.output_shape == (None, 10, 64),其中 None 是 batch 的维度。
  15. # 输入input_array的shape为(batch_size, sequence_length) 的 2D 张量
  16. input_array = np.random.randint(1000, size=(32, 10))
  17. model.compile('rmsprop', 'mse')
  18. #输出output_array的shape为(batch_size, sequence_length, output_dim) 的 3D 张量
  19. output_array = model.predict(input_array)
  20. assert output_array.shape == (32, 10, 64)
  21. 2.输入尺寸
  22. 尺寸为 (batch_size, sequence_length) 的 2D 张量。
  23. 3.输出尺寸
  24. 尺寸为 (batch_size, sequence_length, output_dim) 的 3D 张量。
  25. 4.参数
  26. input_dim: int > 0。词汇表大小, 即,最大整数 index + 1
  27. output_dim: int >= 0。词向量的维度。
  28. embeddings_initializer: embeddings 矩阵的初始化方法 (详见 initializers)。
  29. embeddings_regularizer: embeddings matrix 的正则化方法 (详见 regularizer)。
  30. embeddings_constraint: embeddings matrix 的约束函数 (详见 constraints)。
  31. mask_zero:
  32. 是否把 0 看作为一个应该被遮蔽的特殊的 "padding" 值。这对于可变长的 循环神经网络层 十分有用。
  33. 如果设定为 True,那么接下来的所有层都必须支持 masking,否则就会抛出异常。
  34. 如果 mask_zeroTrue,作为结果,索引 0 就不能被用于词汇表中(input_dim 应该与 vocabulary + 1 大小相同)。
  35. input_length:
  36. 输入序列的长度,当它是固定的时。 如果你需要连接 Flatten 和 Dense 层,
  37. 则这个参数是必须的 (没有它,dense 层的输出尺寸就无法计算)。
  1. import torch.nn as nn
  2. import torch
  3. embedding = nn.Embedding(10, 3)
  4. x = torch.tensor([[0,1],[8,9]])
  5. result = embedding(x)
  6. # print(result)
  7. # tensor([[[ 0.8168, -0.9338, -0.3293],
  8. # [ 0.8791, 0.4560, 1.4109]],
  9. # [[ 0.3612, 0.9988, -0.5982],
  10. # [ 0.8584, -0.5055, 1.5467]]], grad_fn=<EmbeddingBackward>)
  11. """
  12. 设置padding_idx=0之后,那么传入的索引值0通过Embedding层之后,索引值0对应的输出权重值全为0.0000
  13. """
  14. embedding = nn.Embedding(10, 3, padding_idx=0)
  15. x = torch.tensor([[0,1],[8,9]])
  16. result = embedding(x)
  17. print(result)
  18. # tensor([[[ 0.0000, 0.0000, 0.0000],
  19. # [-1.3279, 0.6434, -0.5540]],
  20. # [[-0.2641, 0.1417, 0.0175],
  21. # [-2.8311, 2.0384, -0.0970]]], grad_fn=<EmbeddingBackward>)
  22. """
  23. 报错:RuntimeError: index out of range: Tried to access index 10 out of table with 9 rows.
  24. 报错意思可以翻译为:RuntimeError: index out of range: Tried to access index vocab词表大小 out of table with 单词索引值 rows.
  25. 分析:Embedding(词表大小, 词嵌入维度):
  26. 1.词表大小代表所有不重复单词数的总数大小,词嵌入维度代表一个单词对应的词嵌入维度的向量。
  27. Embedding底层中会构建一个“词表大小*词嵌入维度”的二维权重矩阵,行数即为词表大小,列数即为词嵌入维度。
  28. 每个不重复的词的索引值对应二维权重矩阵中的一行,那么一个单词通过Embedding层输出后为该单词的索引对应那行的词嵌入维度向量,
  29. 也就是说把该单词的索引值对应的二维权重矩阵中的那一行的词嵌入维度向量取出来,作为该单词对应的权重值向量信息。
  30. 2.<start>和<end>同样一开始也是要放到词表WordToIndex和IndexToWord的两个字典中,<start>对应索引值0,<end>对应索引值1。
  31. 3.Embedding层要求传入的单词索引值必须在“0到词表大小减1”的这个范围之间,传入到Embedding层中的单词索引值大于或等于词表大小值的时候,
  32. 就会报错表示单词索引值超出了词表大小范围。
  33. """
  34. embedding = nn.Embedding(10, 3)
  35. x = torch.tensor([[0,1],[5,10]])
  36. result = embedding(x)
  37. print(result)


Embedding版本.py

  1. """ pip install torchtext """
  2. # 导入torchtext.datasets中的文本分类任务
  3. # from torchtext.datasets import text_classification
  4. from day04 import My_text_classification
  5. # 导入相关的torch工具包
  6. import torch
  7. import os
  8. # 导入必备的torch模型构建工具
  9. import torch.nn as nn
  10. import torch.nn.functional as F
  11. # 导入torch中的数据加载器方法
  12. from torch.utils.data import DataLoader
  13. # 导入时间工具包
  14. import time
  15. # 导入数据随机划分方法工具
  16. from torch.utils.data.dataset import random_split
  17. import numpy as np
  18. #================================================================================================
  19. # 指定BATCH_SIZE的大小
  20. BATCH_SIZE = 2
  21. # 进行可用设备检测, 有GPU的话将优先使用GPU
  22. device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
  23. # 定义数据下载路径, 当前路径的data文件夹
  24. load_data_path = "./data"
  25. # 如果不存在该路径, 则创建这个路径
  26. if not os.path.isdir(load_data_path):
  27. os.mkdir(load_data_path)
  28. """
  29. 注意:
  30. 因为调用text_classification这个API的话,每次调用都会自动下载,因此修改text_classification其中的源码。
  31. 首先拷贝一份text_classification.py修改为My_text_classification放到自己项目中,
  32. 把所调用的底层中函数中的第一行download_from_url(URLS[dataset_name], root=root) 注释掉
  33. """
  34. # 选取torchtext中的文本分类数据集'AG_NEWS'即新闻主题分类数据, 保存在指定目录下
  35. # 并将数值映射后的训练和验证数据加载到内存中
  36. train_dataset, test_dataset = My_text_classification.DATASETS['AG_NEWS'](root=load_data_path)
  37. # train_dataset, test_dataset = text_classification.DATASETS['AG_NEWS'](root=load_data_path)
  38. """
  39. 1.EmbeddingBag API官方介绍:
  40. https://pytorch.org/docs/stable/nn.html?highlight=embeddingbag#torch.nn.EmbeddingBag
  41. 2.torch.nn.EmbeddingBag(num_embeddings, embedding_dim, max_norm=None, norm_type=2.0, scale_grad_by_freq=False,
  42. mode='mean', sparse=False, _weight=None)
  43. 参数解释:
  44. 计算嵌入的“bags”的sums或means的方法,而不实例化中间嵌入embeddings。
  45. 对于长度恒定且无per_sample_weights的bags,该类
  46. 其中 mode="sum" 等于嵌入 Embedding 后跟 torch.sum(dim=0)
  47. 其中 mode="mean" 等于嵌入 Embedding 后跟 torch.mean(dim=0)
  48. 其中 mode="max" 等于嵌入 Embedding 后跟 torch.max(dim=0)
  49. 使用:
  50. embedding = nn.EmbeddingBag(vocab_size, embed_dim)
  51. embedding(input, offsets)
  52. 参数解释:
  53. vocab_size: 词汇表不重复单词总数,整个语料包含的不同词汇的总数
  54. embed_dim: 指定词嵌入的维度,一个单词的词嵌入维度
  55. input:批量样本数据,用于准备输入到Embedding层中进行嵌入张量化
  56. offsets:
  57. offsets为一维张量,张量中每个值为每个句子头个单词在当前批量样本句子数据中的起始位置。
  58. 可以通过间接的方式计算出每个句子头个单词在当前批量样本句子数据中的起始位置,
  59. 首先计算出每个句子的长度,即每个句子中的单词数,然后通过cumsum函数可以计算出每个元素值的累计和,
  60. 比如[1.0, 2.0, 3.0] 通过cumsum函数计算出结果为[1., 3., 6.],即每个元素值是第一个元素值到当前元素值的累计和,
  61. 那么便可以通过这种方式,传入每个句子的长度到cumsum函数计算出每个句子的累计和,
  62. 那么即得出每个句子在当前批量样本句子数据中的起始位置。
  63. 3.例子
  64. >>> # vocab_size=10, embed_dim=3
  65. >>> embedding_sum = nn.EmbeddingBag(10, 3, mode='sum')
  66. >>> # 一个批量有2个样本,每个样本有4个数值
  67. >>> input = torch.LongTensor([1,2,4,5, 4,3,2,9])
  68. >>> #每个句子的头个单词的索引位置,即每个句子头个单词的起始位置
  69. >>> #offsets必须是1D张量,1D张量中每个值为input中每个bag(样本句子)的起始索引位置
  70. >>> #因为知道每个样本有4个数值,因此0为第一个句子头个单词的起始位置,4为第二个句子头个单词的起始位置
  71. >>> offsets = torch.LongTensor([0, 4])
  72. >>> embedding_sum(input, offsets)
  73. tensor([[-0.8861, -5.4350, -0.0523],
  74. [ 1.1306, -2.5798, -1.0044]])
  75. """
  76. """
  77. 第一步: 构建带有Embedding层的文本分类模型
  78. """
  79. class TextSentiment(nn.Module):
  80. """文本分类模型"""
  81. def __init__(self, vocab_size, embed_dim, num_class):
  82. """
  83. description: 类的初始化函数
  84. :param vocab_size: 整个语料包含的不同词汇总数
  85. :param embed_dim: 指定词嵌入的维度
  86. :param num_class: 文本分类的类别总数
  87. """
  88. super().__init__()
  89. """
  90. 使用torch.optim.Adam(model.parameters(), lr=0.1)后报错如下:
  91. RuntimeError: Adam does not support sparse gradients, please consider SparseAdam instead
  92. 分析:因为Adam的关系,所以nn.Embedding(vocab_size, embed_dim, sparse=True)中的sparse不能等于True,必须为False
  93. 解决:nn.Embedding(vocab_size, embed_dim, sparse=False)
  94. """
  95. # 实例化embedding层, sparse=True代表每次对该层求解梯度时, 只更新部分权重。使用Adam时,需要把设置sparse不能设置为True
  96. #nn.Embedding(vocab_size 词汇总数, embed_dim 单词嵌入维度)
  97. self.embedding = nn.Embedding(vocab_size, embed_dim, sparse=False) #vocab_size 95812,embed_dim 32
  98. # 实例化线性层, 参数分别是embed_dim和num_class
  99. self.fc = nn.Linear(embed_dim, num_class) #embed_dim 32,num_class 4
  100. # 为各层初始化权重
  101. self.init_weights()
  102. def init_weights(self):
  103. """初始化权重函数"""
  104. # 指定初始权重的取值范围数
  105. initrange = 0.5
  106. # 各层的权重参数都是初始化为均匀分布
  107. self.embedding.weight.data.uniform_(-initrange, initrange) #初始化 -0.50.5之间
  108. self.fc.weight.data.uniform_(-initrange, initrange) #初始化 -0.50.5之间
  109. # 偏置初始化为0
  110. self.fc.bias.data.zero_() ##初始化 0
  111. """
  112. output = model(text)
  113. 每次训练传入的text为tensor类型的一维数组,数组中的值均为单词对应在词汇列表中的索引值。
  114. text由16个句子的批量大小组成的一维数组,因此每个句子的长度都不一致的关系,
  115. 因此每个一维数组text的长度都不一致。
  116. embedded = self.embedding(text)
  117. embedded.shape为(m, 32),m为批量大小16个句子的单词总数,并且每个批量的embedded(同text原理)的m都是不相同的,
  118. 32为单词的嵌入维度(权重维度)。
  119. c = embedded.size(0) // BATCH_SIZE
  120. embedded = embedded[:BATCH_SIZE*c]
  121. 已知m的值远大于BATCH_SIZE=16,为了在模型中以便通过fc层后能计算相应的损失,
  122. 实际即为了(m, 32)中的m维度值可以整除BATCH_SIZE,
  123. 因此还需要将(m, 32) 转化成 (m//BATCH_SIZE*BATCH_SIZE, 32),c为批量个数,
  124. 即先用m整除BATCH_SIZE, 获得m中共包含c个BATCH_SIZE,之后再从embedded中取c*BATCH_SIZE个向量得到新的embedded。
  125. 这个新的embedded中的向量个数可以整除BATCH_SIZE。
  126. embedded = embedded.transpose(1, 0).unsqueeze(0)
  127. embedded = F.avg_pool1d(embedded, kernel_size=c)
  128. 因为我们想利用平均池化的方法求embedded中指定行数的列的平均数,但平均池化方法是作用在行上的,
  129. 并且需要3维输入因此我们对新的embedded进行转置后并拓展维度。
  130. 首先transpose(1, 0)把embedded的(m, 32)转换为(32, m),然后unsqueeze(0)拓展维度变成(1, 32, m),
  131. 然后就是调用平均池化avg_pool1d方法, 并且核的大小kernel_size为c(批量个数),
  132. 即取每c个的元素计算一次均值作为结果,即最终有 m/c(批量个数)个平均值,
  133. 即是对(m, 32)的embedded 中的m 即按行进行求平均值,
  134. 实际即 一共有m个单词,每个单词的嵌入维度为32,那么如果对每个单词的嵌入维度求平均值是毫无意义的,
  135. 应该是求一段单词的平均值,因此kernel_size=c 实际即卷积核的大小为c,那么就是按照c个单词数求一个平均值。
  136. embedded.shape: torch.Size([625, 32])
  137. c: 39 # 625 / batch_size(16) = 39.0625
  138. embedded.shape: torch.Size([624, 32]) # 39 * batch_size(16) = 624
  139. embedded.shape: torch.Size([1, 32, 624])
  140. embedded.shape: torch.Size([1, 32, 16]) # 624 / 39 = 16
  141. """
  142. def forward(self, text):
  143. """
  144. :param text: 文本数值映射后的结果
  145. :return: 与类别数尺寸相同的张量, 用以判断文本类别
  146. """
  147. # 获得embedding的结果embedded
  148. # >>> embedded.shape
  149. # (m, 32) 其中m是BATCH_SIZE大小的数据中词汇总数
  150. embedded = self.embedding(text)
  151. # print("embedded.shape:",embedded.shape)
  152. # 接下来我们需要将(m, 32)转化成(BATCH_SIZE, 32)
  153. # 以便通过fc层后能计算相应的损失
  154. # 首先, 我们已知m的值远大于BATCH_SIZE=16,
  155. # 用m整除BATCH_SIZE, 获得m中共包含c个BATCH_SIZE
  156. c = embedded.size(0) // BATCH_SIZE
  157. # print("c:",c)
  158. # 之后再从embedded中取c*BATCH_SIZE个向量得到新的embedded
  159. # 这个新的embedded中的向量个数可以整除BATCH_SIZE
  160. embedded = embedded[:BATCH_SIZE*c]
  161. # print("embedded.shape:",embedded.shape)
  162. # 因为我们想利用平均池化的方法求embedded中指定行数的列的平均数,
  163. # 但平均池化方法是作用在行上的, 并且需要3维输入
  164. # 因此我们对新的embedded进行转置并拓展维度
  165. embedded = embedded.transpose(1, 0).unsqueeze(0)
  166. # print("embedded.shape:",embedded.shape)
  167. # 然后就是调用平均池化的方法, 并且核的大小为c
  168. # 即取每c的元素计算一次均值作为结果
  169. embedded = F.avg_pool1d(embedded, kernel_size=c)
  170. # print("embedded.shape:",embedded.shape)
  171. # embedded = F.relu(embedded)
  172. # 最后,还需要减去新增的维度, 然后转置回去输送给fc层
  173. return self.fc(embedded[0].transpose(1, 0))
  174. """
  175. 实例化模型
  176. """
  177. # 获得整个语料包含的不同词汇总数
  178. VOCAB_SIZE = len(train_dataset.get_vocab())
  179. # 指定词嵌入维度
  180. EMBED_DIM = 32
  181. # 获得类别总数
  182. NUN_CLASS = len(train_dataset.get_labels())
  183. # print("VOCAB_SIZE词数:",VOCAB_SIZE) # 95812
  184. # print("NUN_CLASS类别数:",NUN_CLASS) # 4
  185. # 实例化模型
  186. model = TextSentiment(VOCAB_SIZE, EMBED_DIM, NUN_CLASS).to(device)
  187. """
  188. 第二步: 对数据进行batch处理
  189. """
  190. def generate_batch(batch):
  191. """
  192. description: 生成batch数据函数
  193. :param batch: 由样本张量和对应标签的元组组成的batch_size大小的列表
  194. 形如: [(label1, sample1), (label2, sample2), ..., (labelN, sampleN)]
  195. :return: 样本张量和标签各自的列表形式(张量)
  196. 形如:
  197. text = tensor([sample1, sample2, ..., sampleN])
  198. label = tensor([label1, label2, ..., labelN])
  199. """
  200. """
  201. batch:16个数据,格式为(标签值,样本数据),一共有16个这样的元祖构成一个列表
  202. """
  203. # print("batch size批量样本数:",len(batch)) # 列表中有 16 个元祖
  204. # print("batch[0][0]:",batch[0][0]) # 元祖中的 int标签值
  205. # print("batch[0][1]:",batch[0][1]) # 元祖中的 样本数据,数据值为单词在词汇列表中的索引值
  206. # 从batch中获得样本张量
  207. # text = torch.tensor()
  208. text = [entry[1] for entry in batch]
  209. # 从batch中获得标签张量
  210. label = [entry[0] for entry in batch]
  211. # print("batch_size批量大小的样本特征:", len(text)) #16
  212. # print("batch_size批量大小的标签:", len(label)) #16
  213. # text中包含16个句子,每个句子的长度都不一样,最终通过cat函数把16个句子的单词都封装到一个列表中
  214. #text中的值 实际是16句子中的单词对应的索引值,因此cat函数封装成的一个列表中的元素值都是单词对应的索引值
  215. #每个批量的16个句子都是长度不一致,因此每个批量中的text.shape都可能是不相同
  216. text = torch.cat(text)
  217. label = torch.tensor(label) #使用 torch.tensor 把 list 转换为 tensor类型
  218. # print("cat(text):", text.shape) #每个批量中的text的长度(16个句子一共的单词数)都可能是不相同
  219. # print("label:", label.shape) #torch.Size([16]) 16个句子对应的标签值
  220. # 返回结果
  221. return text.to(device), label.to(device)
  222. """
  223. 第三步: 构建训练与验证函数
  224. """
  225. # 指定训练轮数
  226. N_EPOCHS = 100
  227. # 定义初始的验证损失
  228. # min_valid_loss = float('inf')
  229. # 选择损失函数, 这里选择预定义的交叉熵损失函数
  230. criterion = torch.nn.CrossEntropyLoss().to(device)
  231. # 选择随机梯度下降优化器
  232. # optimizer = torch.optim.SGD(model.parameters(), lr=0.1)
  233. optimizer = torch.optim.Adam(model.parameters(),lr=0.01,betas=(0.9, 0.999), eps=1e-08, weight_decay=0, amsgrad=False)
  234. # 选择优化器步长调节方法StepLR, 用来衰减学习率
  235. # 5个step调节一次例如,每执行一次scheduler.step()为一个step。
  236. # scheduler = torch.optim.lr_scheduler.StepLR(optimizer, 1, gamma=0.9)
  237. # scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=N_EPOCHS)
  238. """
  239. 使用torch.optim.Adam(model.parameters(), lr=0.1)后报错如下:
  240. RuntimeError: Adam does not support sparse gradients, please consider SparseAdam instead
  241. 分析:因为Adam的关系,所以nn.Embedding(vocab_size, embed_dim, sparse=True)中的sparse不能等于True,必须为False
  242. 解决:nn.Embedding(vocab_size, embed_dim, sparse=False)
  243. class torch.optim.lr_scheduler.StepLR(optimizer,step_size,gamma=0.1,last_epoch=-1)
  244. optimizer(Optimizer对象)--优化器
  245. step_size(整数类型): 调整学习率的步长,每过step_size次,更新一次学习率。每执行一次scheduler.step()为一个step
  246. gamma(float 类型):学习率下降的乘数因子
  247. last_epoch(int类型):最后一次epoch的索引,默认为-1.
  248. """
  249. def train(train_data):
  250. """模型训练函数"""
  251. # 初始化训练损失和准确率为0
  252. train_loss = 0
  253. train_acc = 0
  254. # 使用数据加载器生成BATCH_SIZE大小的数据进行批次训练
  255. # data就是N多个generate_batch函数处理后的BATCH_SIZE大小的数据生成器
  256. #drop_last=True:丢弃不满足批量大小的批量数据,一般会是最后一个批量数据中的样本数可能不满足于批量大小,因此需要丢弃以防止报错
  257. data = DataLoader(train_data, batch_size=BATCH_SIZE, shuffle=True, collate_fn=generate_batch, drop_last=True)
  258. # 对data进行循环遍历, 使用每个batch的数据进行参数更新
  259. for i, (text, cls) in enumerate(data):
  260. """
  261. 如果当前批量数据中的样本数不满足批量大小的话,执行后面就会报错,因此需要每次训练的批量数据中的样本数必须满足批量大小
  262. 常见的情况就是一般最后一个批次数据中的样本数可能存在不满足于批量大小,因此都需要判断这个步骤
  263. """
  264. # if len(cls) != BATCH_SIZE:
  265. # continue
  266. # 设置优化器初始梯度为0
  267. optimizer.zero_grad()
  268. # 模型输入一个批次数据, 获得输出
  269. output = model(text)
  270. """
  271. 模型最后一个输出层输出的维度是类别数4,那么因为每个批量大小为16,
  272. 那么一个批量中的真实标签值一共有16个int值(16个句子对应16个真实标签值)。
  273. 因此模型的预测输出的维度是torch.Size([16, 4]),和真实标签值列表[16] 进行比较是否相同。
  274. """
  275. # print("output:",output.shape) #torch.Size([16, 4])
  276. # 根据真实标签与模型输出计算损失
  277. loss = criterion(output, cls)
  278. # 将该批次的损失加到总损失中
  279. train_loss += loss.item()
  280. # print("loss:",loss.item()) # loss.item()为一个 float小数值
  281. # 误差反向传播
  282. loss.backward()
  283. # 参数进行更新
  284. optimizer.step()
  285. """
  286. output维度为 [16, 4]。
  287. output.argmax(1) 取的是每行中最大元素值的索引值,一共有16行,那么最终得出16个索引值。
  288. output.argmax(0) 在此处使用的话为错误用法,只能取出4个值,取出的是 每列中最大元素值的索引值。
  289. """
  290. # 将该批次的准确率加到总准确率中
  291. train_acc += (output.argmax(1) == cls).sum().item()
  292. # 调整优化器学习率
  293. # scheduler.step()
  294. """
  295. len(train_data) 获取的是训练样本数量 114000
  296. 使用 train_loss/训练样本数量,train_acc/训练样本数量
  297. """
  298. # 返回本轮训练的平均损失和平均准确率
  299. return train_loss / len(train_data), train_acc / len(train_data)
  300. def valid(valid_data):
  301. """模型验证函数"""
  302. # 初始化验证损失和准确率为0
  303. loss = 0
  304. acc = 0
  305. # 和训练相同, 使用DataLoader获得训练数据生成器
  306. #drop_last=True:丢弃不满足批量大小的批量数据,一般会是最后一个批量数据中的样本数可能不满足于批量大小,因此需要丢弃以防止报错
  307. data = DataLoader(valid_data, batch_size=BATCH_SIZE, collate_fn=generate_batch, drop_last=True)
  308. # 按批次取出数据验证
  309. for text, cls in data:
  310. """
  311. 如果当前批量数据中的样本数不满足批量大小的话,执行后面就会报错,因此需要每次训练的批量数据中的样本数必须满足批量大小
  312. 常见的情况就是一般最后一个批次数据中的样本数可能存在不满足于批量大小,因此都需要判断这个步骤
  313. """
  314. # if len(cls) != BATCH_SIZE:
  315. # continue
  316. # 验证阶段, 不再求解梯度
  317. with torch.no_grad():
  318. # 使用模型获得输出
  319. output = model(text)
  320. # 计算损失
  321. loss = criterion(output, cls)
  322. # 将损失和准确率加到总损失和准确率中
  323. loss += loss.item()
  324. acc += (output.argmax(1) == cls).sum().item()
  325. # 返回本轮验证的平均损失和平均准确率
  326. return loss / len(valid_data), acc / len(valid_data)
  327. """
  328. 第四步: 进行模型训练和验证
  329. """
  330. def train_model():
  331. train_dataset_size = len(train_dataset)
  332. # print("train_dataset 总样本数",train_dataset_size) #120000
  333. # 从train_dataset取出0.95作为训练集, 先取其长度
  334. train_len = int(train_dataset_size * 0.95)
  335. valid_len = train_dataset_size - train_len
  336. # print("train_len 训练样本数",train_len) #114000
  337. # print("valid_len 验证本数",valid_len) #6000
  338. # while 1:
  339. # if (train_len % BATCH_SIZE == 0):
  340. # break
  341. # else:
  342. # train_len -= 1
  343. # while 1:
  344. # if (valid_len % BATCH_SIZE == 0):
  345. # break
  346. # else:
  347. # valid_len -= 1
  348. # print("处理后的训练样本数: %d, 处理后的验证样本数: %d" % (train_len, valid_len))
  349. # 然后使用random_split进行乱序划分, 得到对应的训练集和验证集
  350. sub_train_, sub_valid_ = random_split(train_dataset, [train_len, valid_len])
  351. """
  352. RuntimeError: Expected object of backend CUDA but got backend CPU for argument #3 'index'
  353. 分析:data数据或者model没有调用.to(device)
  354. 解决:
  355. # 进行可用设备检测, 有GPU的话将优先使用GPU
  356. device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
  357. model = model.to(device) 或 model = model.cuda(device)
  358. output = model(input.to(device)) 或 output = model(input.cuda(device))
  359. # 选择损失函数, 这里选择预定义的交叉熵损失函数
  360. criterion = torch.nn.CrossEntropyLoss().to(device) 或 criterion = torch.nn.CrossEntropyLoss().cuda(device)
  361. loss = criterion(output, lable.to(device)) 或 loss = criterion(output, lable.cuda(device))
  362. """
  363. # 开始每一轮训练
  364. for epoch in range(N_EPOCHS):
  365. # 记录概论训练的开始时间
  366. start_time = time.time()
  367. # 调用train和valid函数得到训练和验证的平均损失, 平均准确率
  368. train_loss, train_acc = train(sub_train_)
  369. valid_loss, valid_acc = valid(sub_valid_)
  370. # 计算训练和验证的总耗时(秒)
  371. secs = int(time.time() - start_time)
  372. # 用分钟和秒表示
  373. mins = secs / 60
  374. secs = secs % 60
  375. # 打印训练和验证耗时,平均损失,平均准确率
  376. print('Epoch: %d' % (epoch + 1), " | time in %d minutes, %d seconds" % (mins, secs))
  377. print(f'\tLoss: {train_loss:.4f}(train)\t|\tAcc: {train_acc * 100:.1f}%(train)')
  378. print(f'\tLoss: {valid_loss:.4f}(valid)\t|\tAcc: {valid_acc * 100:.1f}%(valid)')
  379. if __name__ == '__main__':
  380. """
  381. Epoch: 98 | time in 1 minutes, 0 seconds
  382. Loss: 0.0427(train) | Acc: 94.5%(train)
  383. Loss: 0.0000(valid) | Acc: 87.0%(valid)
  384. """
  385. train_model()

EmbeddingBag版本.py

  1. from day04 import My_text_classification
  2. from torchtext.datasets.text_classification import *
  3. import os
  4. import torch.nn as nn
  5. import torch.nn.functional as F
  6. """
  7. BATCH_SIZE大小设置对训练耗时的影响:
  8. 1.如果当设置BATCH_SIZE等于训练样本时,比如训练样本有512个,设置BATCH_SIZE=512,那么一次BATCH_SIZE=512的批量数据进行训练时,
  9. 会计算BATCH_SIZE=512个样本的反向传播,求出512个样本的梯度累计和,然后使用该梯度累计和进行一次权重参数更新。
  10. 2.如果当设置BATCH_SIZE等于1时,,比如训练样本有512个,设置BATCH_SIZE=1,那么一次BATCH_SIZE=1的批量数据进行训练时,
  11. 会计算BATCH_SIZE=1个样本的反向传播,求出1个样本的梯度,然后使用该梯度进行一次权重参数更新,
  12. 那么当所有512个样本都完成训练时,一共进行了512次反向传播(梯度计算),512次参数更新。
  13. 3.结论:
  14. 1.显然BATCH_SIZE设置越大,那么所有训练样本数据完成一次训练(完成一个epoch)要进行的参数更新次数会更少,
  15. 那么训练耗时更短,BATCH_SIZE设置越小,一个epoch训练完所有样本数据要进行的参数更新次数会更多,
  16. 因此训练耗时更长。
  17. 2.当然训练耗时也和你所选取的优化算法是全批量梯度下降BGD、随机梯度下降SGD、小批量梯度下降Mini-batch GD(MBGD)有关。
  18. 4.每个批量数据训练都要执行的代码流程
  19. # 设置优化器初始梯度为0
  20. optimizer.zero_grad()
  21. # 模型输入一个批次数据, 获得输出
  22. output = model(text)
  23. # 根据真实标签与模型输出计算损失
  24. loss = criterion(output, label)
  25. # 将该批次的损失加到总损失中
  26. train_loss += loss.item()
  27. # 误差反向传播
  28. loss.backward()
  29. # 参数进行更新
  30. optimizer.step()
  31. """
  32. learning_rate = 0.01
  33. train_ratio = 0.95
  34. N_EPOCHS = 50
  35. BATCH_SIZE = 1000
  36. EMBED_DIM = 32
  37. # 进行可用设备检测, 有GPU的话将优先使用GPU
  38. device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
  39. # 定义数据下载路径, 当前路径的data文件夹
  40. load_data_path = "./data"
  41. # 如果不存在该路径, 则创建这个路径
  42. if not os.path.isdir(load_data_path):
  43. os.mkdir(load_data_path)
  44. """
  45. 注意:
  46. 因为调用text_classification这个API的话,每次调用都会自动下载,因此修改text_classification其中的源码。
  47. 首先拷贝一份text_classification.py修改为My_text_classification放到自己项目中,
  48. 把所调用的底层中函数中的第一行download_from_url(URLS[dataset_name], root=root) 注释掉
  49. """
  50. # 选取torchtext中的文本分类数据集'AG_NEWS'即新闻主题分类数据, 保存在指定目录下
  51. # 并将数值映射后的训练和验证数据加载到内存中
  52. train_dataset, test_dataset = My_text_classification.DATASETS['AG_NEWS'](root=load_data_path)
  53. # train_dataset, test_dataset = text_classification.DATASETS['AG_NEWS'](root=load_data_path)
  54. class TextSentiment(nn.Module):
  55. def __init__(self, vocab_size, embed_dim, num_class):
  56. """
  57. :param vocab_size: 词汇表不重复单词总数,整个语料包含的不同词汇的总数
  58. :param embed_dim: 指定词嵌入的维度,一个单词的词嵌入维度
  59. :param num_class: 文本分类的类别总数
  60. """
  61. """
  62. 1.EmbeddingBag API官方介绍:
  63. https://pytorch.org/docs/stable/nn.html?highlight=embeddingbag#torch.nn.EmbeddingBag
  64. 2.torch.nn.EmbeddingBag(num_embeddings, embedding_dim, max_norm=None, norm_type=2.0, scale_grad_by_freq=False,
  65. mode='mean', sparse=False, _weight=None)
  66. 参数解释:
  67. 计算嵌入的“bags”的sums或means的方法,而不实例化中间嵌入embeddings。
  68. 对于长度恒定且无per_sample_weights的bags,该类
  69. 其中 mode="sum" 等于嵌入 Embedding 后跟 torch.sum(dim=0)
  70. 其中 mode="mean" 等于嵌入 Embedding 后跟 torch.mean(dim=0)
  71. 其中 mode="max" 等于嵌入 Embedding 后跟 torch.max(dim=0)
  72. 使用:
  73. embedding = nn.EmbeddingBag(vocab_size, embed_dim)
  74. embedding(input, offsets)
  75. 参数解释:
  76. vocab_size: 词汇表不重复单词总数,整个语料包含的不同词汇的总数
  77. embed_dim: 指定词嵌入的维度,一个单词的词嵌入维度
  78. input:批量样本数据,用于准备输入到Embedding层中进行嵌入张量化
  79. offsets:
  80. offsets为一维张量,张量中每个值为每个句子头个单词在当前批量样本句子数据中的起始位置。
  81. 可以通过间接的方式计算出每个句子头个单词在当前批量样本句子数据中的起始位置,
  82. 首先计算出每个句子的长度,即每个句子中的单词数,然后通过cumsum函数可以计算出每个元素值的累计和,
  83. 比如[1.0, 2.0, 3.0] 通过cumsum函数计算出结果为[1., 3., 6.],即每个元素值是第一个元素值到当前元素值的累计和,
  84. 那么便可以通过这种方式,传入每个句子的长度到cumsum函数计算出每个句子的累计和,
  85. 那么即得出每个句子在当前批量样本句子数据中的起始位置。
  86. 3.例子
  87. >>> # vocab_size=10, embed_dim=3
  88. >>> embedding_sum = nn.EmbeddingBag(10, 3, mode='sum')
  89. >>> # 一个批量有2个样本,每个样本有4个数值
  90. >>> input = torch.LongTensor([1,2,4,5, 4,3,2,9])
  91. >>> #每个句子的头个单词的索引位置,即每个句子头个单词的起始位置
  92. >>> #offsets必须是1D张量,1D张量中每个值为input中每个bag(样本句子)的起始索引位置
  93. >>> #因为知道每个样本有4个数值,因此0为第一个句子头个单词的起始位置,4为第二个句子头个单词的起始位置
  94. >>> offsets = torch.LongTensor([0, 4])
  95. >>> embedding_sum(input, offsets)
  96. tensor([[-0.8861, -5.4350, -0.0523],
  97. [ 1.1306, -2.5798, -1.0044]])
  98. """
  99. super().__init__()
  100. # 实例化embeddingBag层, sparse=True代表每次对该层求解梯度时, 只更新部分权重.
  101. self.embedding = nn.EmbeddingBag(vocab_size, embed_dim, sparse=False)
  102. # 实例化线性层, 参数分别是embed_dim和num_class.
  103. self.fc = nn.Linear(embed_dim, num_class)
  104. # 为各层初始化权重
  105. self.init_weights()
  106. def init_weights(self):
  107. """初始化权重函数"""
  108. # 指定初始权重的取值范围数
  109. initrange = 0.5
  110. # 各层的权重参数都是初始化为均匀分布
  111. self.embedding.weight.data.uniform_(-initrange, initrange)
  112. self.fc.weight.data.uniform_(-initrange, initrange)
  113. # 偏置初始化为0
  114. self.fc.bias.data.zero_()
  115. def forward(self, text, offsets):
  116. '''
  117. :param text: 批量句子样本的所有单词封装到一个一维张量中
  118. :param offsets:
  119. 一维张量中的每个值为每个句子头个单词在当前批量样本数据中的起始位置,
  120. 一维张量中的每个值也即是每个句子头个单词在text一维张量中的起始位置。
  121. :return: 真实类别标签值构成的一维张量,与类别数尺寸相同的张量, 用以判断文本类别
  122. '''
  123. # 获得embedding的结果embedded
  124. embedded = self.embedding(text, offsets)
  125. # 然后使用relu函数对输出进行处理,根据relu函数的特性, 将使Embedding矩阵更稀疏,以防止过拟合
  126. # embedded = F.relu(embedded)
  127. return self.fc(embedded)
  128. # 获得整个语料包含的不同词汇总数
  129. VOCAB_SIZE = len(train_dataset.get_vocab())
  130. # 获得类别总数
  131. NUN_CLASS = len(train_dataset.get_labels())
  132. # 实例化模型
  133. model = TextSentiment(VOCAB_SIZE, EMBED_DIM, NUN_CLASS).to(device)
  134. def generate_batch(batch):
  135. '''
  136. description: 生成batch数据函数
  137. :param batch: 由样本张量和对应标签的元组组成的batch_size大小的列表
  138. 形如: [(label1, sample1), (label2, sample2), ..., (labelN, sampleN)]
  139. :return:样本张量和标签各自的列表形式(张量)
  140. 形如:
  141. text = tensor([sample1, sample2, ..., sampleN])
  142. label = tensor([label1, label2, ..., labelN])
  143. '''
  144. # 从batch中获得标签张量,批量大小的真是类别标签值构成的一维向量
  145. label = torch.tensor([entry[0] for entry in batch])
  146. # 从batch中获得样本张量,批量大小句子样本数据构成的二维矩阵
  147. text = [entry[1] for entry in batch]
  148. """
  149. 1.计算出offsets(每个句子头在当前批量样本数据中的起始位置,或者说每个句子头个单词在text一维张量中的起始位置)的步骤:
  150. 1.第一步:第一个值必须是0,代表第一个句子头的起始位置,然后第二个值开始才是每个句子的长度值,即计算出每个句子的单词数
  151. 2.第二步:
  152. 通过cumsum函数可以计算出offsets一维张量中每个元素值的累计和,比如[1.0, 2.0, 3.0]通过cumsum函数计算出结果为[1., 3., 6.]。
  153. 那么便可以通过计算累计和的方式 计算出每个句子头个单词在当前批量样本数据中的起始位置。
  154. 2.标签值的计算
  155. 把批量大小的样本真实标签值都封装到一个一维的张量中
  156. 3.样本数据的计算
  157. 首先获取出批量大小的样本句子数据所构建的二维张量,然后把二维张量通过cat函数合并为一维张量,
  158. 即把每个句子的所有单词对应的索引值都合并到一个一维张量中。
  159. 4.样本数据和offsets传入到embedding嵌入层中
  160. embedding(text, offsets):可以直接把一维张量的样本数据text 和 一维张量的offsets 传入到embedding嵌入层中
  161. """
  162. # 计算出每个句子的单词数,即每个句子的长度,并且offsets的第一个必须为0,后面的值是每个句子的长度
  163. # 然后通过后面执行的cumsum函数根据offsets一维张量中的每个句子的长度 可以计算 元素的累计和,即可以计算出每个句子的头个单词在当前批量样本句子数据中的索引位置
  164. offsets = [0] + [len(entry) for entry in text]
  165. # print(offsets) #[0,。。。,。。。]
  166. # print(len(offsets)) # 171 + batch size
  167. # torch.Tensor.cumsum 返回dim维度元素的累积和
  168. # torch.Tensor([1.0, 2.0, 3.0]).cumsum(dim=0) 输出结果为 tensor([1., 3., 6.]),即第二个元素为前两个元素的累计和,第三个元素是前三个元素的累计和
  169. offsets = torch.tensor(offsets[:-1]).cumsum(dim=0)
  170. # print("cumsum:",offsets) #每个元素值 是第一个元素到当前元素的累计和,因此就可以计算出每个句子的头个单词在当前批量样本句子数据中的索引位置
  171. #把批量样本数据(batch size个句子的单词索引值) 合并为 一个一维张量
  172. text = torch.cat(text)
  173. # print(text.shape) #一维张量的维度,每个张量的维度都不一致
  174. # 返回结果
  175. return text.to(device), offsets.to(device), label.to(device)
  176. # 导入torch中的数据加载器方法
  177. from torch.utils.data import DataLoader
  178. def train_func(sub_train_):
  179. """模型训练函数"""
  180. # 初始化训练损失和准确率为0
  181. train_loss = 0
  182. train_acc = 0
  183. # 使用数据加载器生成BATCH_SIZE大小的数据进行批次训练
  184. # data就是N多个generate_batch函数处理后的BATCH_SIZE大小的数据生成器
  185. # drop_last=True:丢弃不满足批量大小的批量数据,一般会是最后一个批量数据中的样本数可能不满足于批量大小,因此需要丢弃以防止报错
  186. data = DataLoader(sub_train_, batch_size=BATCH_SIZE, shuffle=True, collate_fn=generate_batch, drop_last=True)
  187. # collate_fn的输入是大小为batch_size的张量的列表,collate_fn将列表打包进最小批次(mini-batch)
  188. # 原始数据批次输入的文本条目被打包到一个列表并串联成了一个单独张量作为nn.EmbeddingBag的输入
  189. # 对data进行循环遍历, 使用每个batch的数据进行参数更新
  190. for i, (text, offsets, cls) in enumerate(data):
  191. # 设置优化器初始梯度为0
  192. optimizer.zero_grad()
  193. text, offsets, cls = text, offsets, cls
  194. # 模型输入一个批次数据, 获得输出
  195. output = model(text, offsets)
  196. # 根据真实标签与模型输出计算损失
  197. loss = criterion(output, cls)
  198. # 将该批次的损失加到总损失中
  199. train_loss += loss.item()
  200. # 误差反向传播
  201. loss.backward()
  202. # 参数进行更新
  203. optimizer.step()
  204. # 将该批次的准确率加到总准确率中
  205. train_acc += (output.argmax(1) == cls).sum().item()
  206. # 调整优化器学习率
  207. # scheduler.step()
  208. # 返回本轮训练的平均损失和平均准确率
  209. return train_loss / len(sub_train_), train_acc / len(sub_train_)
  210. def gotest_func(data_):
  211. """模型验证函数"""
  212. # 初始化验证损失和准确率为0
  213. loss = 0
  214. acc = 0
  215. # 和训练相同, 使用DataLoader获得训练数据生成器
  216. data = DataLoader(data_, batch_size=BATCH_SIZE, collate_fn=generate_batch, drop_last=True)
  217. # 按批次取出数据验证
  218. for text, offsets, cls in data:
  219. text, offsets, cls = text.to(device), offsets.to(device), cls.to(device)
  220. # 验证阶段, 不再求解梯度
  221. with torch.no_grad():
  222. # 使用模型获得输出
  223. output = model(text, offsets)
  224. # 计算损失
  225. loss = criterion(output, cls)
  226. # 将损失和准确率加到总损失和准确率中
  227. loss += loss.item()
  228. acc += (output.argmax(1) == cls).sum().item()
  229. # 返回本轮验证的平均损失和平均准确率
  230. return loss / len(data_), acc / len(data_)
  231. # 导入时间工具包
  232. import time
  233. # 导入数据随机划分方法工具
  234. from torch.utils.data.dataset import random_split
  235. # 定义初始的验证损失
  236. # min_valid_loss = float('inf')
  237. # 选择损失函数, 这里选择预定义的交叉熵损失函数
  238. criterion = torch.nn.CrossEntropyLoss().to(device)
  239. # 选择随机梯度下降优化器
  240. # optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate)
  241. # 选择优化器步长调节方法StepLR, 用来衰减学习率
  242. optimizer = torch.optim.Adam(model.parameters(),lr=learning_rate,betas=(0.9, 0.999), eps=1e-08, weight_decay=0, amsgrad=False)
  243. # scheduler = torch.optim.lr_scheduler.StepLR(optimizer, 1, gamma=0.9)
  244. # 从train_dataset取出0.95作为训练集, 先取其长度
  245. # train_len = int(len(train_dataset) * 0.95)
  246. train_len = int(len(train_dataset) * train_ratio)
  247. # 然后使用random_split进行乱序划分, 得到对应的训练集和验证集
  248. sub_train_, sub_valid_ = random_split(train_dataset, [train_len, len(train_dataset) - train_len])
  249. # 开始每一轮训练
  250. for epoch in range(N_EPOCHS):
  251. # 记录概论训练的开始时间
  252. start_time = time.time()
  253. # 调用train和valid函数得到训练和验证的平均损失, 平均准确率
  254. train_loss, train_acc = train_func(sub_train_)
  255. valid_loss, valid_acc = gotest_func(sub_valid_)
  256. # 计算训练和验证的总耗时(秒)
  257. secs = int(time.time() - start_time)
  258. # 用分钟和秒表示
  259. mins = secs / 60
  260. secs = secs % 60
  261. # 打印训练和验证耗时,平均损失,平均准确率
  262. print('Epoch: %d' %(epoch + 1), " | time in %d minutes, %d seconds" %(mins, secs))
  263. print(f'\tLoss: {train_loss:.4f}(train)\t|\tAcc: {train_acc * 100:.1f}%(train)')
  264. print(f'\tLoss: {valid_loss:.4f}(valid)\t|\tAcc: {valid_acc * 100:.1f}%(valid)')
  265. print('Checking the results of test dataset...')
  266. test_loss, test_acc = gotest_func(test_dataset)
  267. print(f'\tLoss: {test_loss:.4f}(test)\t|\tAcc: {test_acc * 100:.1f}%(test)')

My_text_classification.py

  1. import logging
  2. import torch
  3. import io
  4. from torchtext.utils import download_from_url, extract_archive, unicode_csv_reader
  5. from torchtext.data.utils import ngrams_iterator
  6. from torchtext.data.utils import get_tokenizer
  7. from torchtext.vocab import build_vocab_from_iterator
  8. from torchtext.vocab import Vocab
  9. from tqdm import tqdm
  10. URLS = {
  11. 'AG_NEWS':
  12. 'https://drive.google.com/uc?export=download&id=0Bz8a_Dbh9QhbUDNpeUdjb0wxRms',
  13. 'SogouNews':
  14. 'https://drive.google.com/uc?export=download&id=0Bz8a_Dbh9QhbUkVqNEszd0pHaFE',
  15. 'DBpedia':
  16. 'https://drive.google.com/uc?export=download&id=0Bz8a_Dbh9QhbQ2Vic1kxMmZZQ1k',
  17. 'YelpReviewPolarity':
  18. 'https://drive.google.com/uc?export=download&id=0Bz8a_Dbh9QhbNUpYQ2N3SGlFaDg',
  19. 'YelpReviewFull':
  20. 'https://drive.google.com/uc?export=download&id=0Bz8a_Dbh9QhbZlU4dXhHTFhZQU0',
  21. 'YahooAnswers':
  22. 'https://drive.google.com/uc?export=download&id=0Bz8a_Dbh9Qhbd2JNdDBsQUdocVU',
  23. 'AmazonReviewPolarity':
  24. 'https://drive.google.com/uc?export=download&id=0Bz8a_Dbh9QhbaW12WVVZS2drcnM',
  25. 'AmazonReviewFull':
  26. 'https://drive.google.com/uc?export=download&id=0Bz8a_Dbh9QhbZVhsUnRWRDhETzA'
  27. }
  28. def _csv_iterator(data_path, ngrams, yield_cls=False):
  29. tokenizer = get_tokenizer("basic_english")
  30. with io.open(data_path, encoding="utf8") as f:
  31. reader = unicode_csv_reader(f)
  32. for row in reader:
  33. tokens = ' '.join(row[1:])
  34. tokens = tokenizer(tokens)
  35. if yield_cls:
  36. yield int(row[0]) - 1, ngrams_iterator(tokens, ngrams)
  37. else:
  38. yield ngrams_iterator(tokens, ngrams)
  39. def _create_data_from_iterator(vocab, iterator, include_unk):
  40. data = []
  41. labels = []
  42. with tqdm(unit_scale=0, unit='lines') as t:
  43. for cls, tokens in iterator:
  44. if include_unk:
  45. tokens = torch.tensor([vocab[token] for token in tokens])
  46. else:
  47. token_ids = list(filter(lambda x: x is not Vocab.UNK, [vocab[token]
  48. for token in tokens]))
  49. tokens = torch.tensor(token_ids)
  50. if len(tokens) == 0:
  51. logging.info('Row contains no tokens.')
  52. data.append((cls, tokens))
  53. labels.append(cls)
  54. t.update(1)
  55. return data, set(labels)
  56. class TextClassificationDataset(torch.utils.data.Dataset):
  57. """Defines an abstract text classification datasets.
  58. Currently, we only support the following datasets:
  59. - AG_NEWS
  60. - SogouNews
  61. - DBpedia
  62. - YelpReviewPolarity
  63. - YelpReviewFull
  64. - YahooAnswers
  65. - AmazonReviewPolarity
  66. - AmazonReviewFull
  67. """
  68. def __init__(self, vocab, data, labels):
  69. """Initiate text-classification dataset.
  70. Arguments:
  71. vocab: Vocabulary object used for dataset.
  72. data: a list of label/tokens tuple. tokens are a tensor after
  73. numericalizing the string tokens. label is an integer.
  74. [(label1, tokens1), (label2, tokens2), (label2, tokens3)]
  75. label: a set of the labels.
  76. {label1, label2}
  77. Examples:
  78. See the examples in examples/text_classification/
  79. """
  80. super(TextClassificationDataset, self).__init__()
  81. self._data = data
  82. self._labels = labels
  83. self._vocab = vocab
  84. def __getitem__(self, i):
  85. return self._data[i]
  86. def __len__(self):
  87. return len(self._data)
  88. def __iter__(self):
  89. for x in self._data:
  90. yield x
  91. def get_labels(self):
  92. return self._labels
  93. def get_vocab(self):
  94. return self._vocab
  95. def _setup_datasets(dataset_name, root='.data', ngrams=1, vocab=None, include_unk=False):
  96. # dataset_tar = download_from_url(URLS[dataset_name], root=root)
  97. # dataset_tar = "./data/ag_news_csv.tar.gz"
  98. # extracted_files = extract_archive(dataset_tar)
  99. extracted_files = ['./data/ag_news_csv/train.csv',
  100. './data/ag_news_csv/test.csv',
  101. './data/ag_news_csv/classes.txt',
  102. './data/ag_news_csv/readme.txt']
  103. # print(extracted_files)
  104. for fname in extracted_files:
  105. if fname.endswith('train.csv'):
  106. train_csv_path = fname
  107. if fname.endswith('test.csv'):
  108. test_csv_path = fname
  109. if vocab is None:
  110. logging.info('Building Vocab based on {}'.format(train_csv_path))
  111. vocab = build_vocab_from_iterator(_csv_iterator(train_csv_path, ngrams))
  112. else:
  113. if not isinstance(vocab, Vocab):
  114. raise TypeError("Passed vocabulary is not of type Vocab")
  115. logging.info('Vocab has {} entries'.format(len(vocab)))
  116. logging.info('Creating training data')
  117. train_data, train_labels = _create_data_from_iterator(
  118. vocab, _csv_iterator(train_csv_path, ngrams, yield_cls=True), include_unk)
  119. logging.info('Creating testing data')
  120. test_data, test_labels = _create_data_from_iterator(
  121. vocab, _csv_iterator(test_csv_path, ngrams, yield_cls=True), include_unk)
  122. if len(train_labels ^ test_labels) > 0:
  123. raise ValueError("Training and test labels don't match")
  124. return (TextClassificationDataset(vocab, train_data, train_labels),
  125. TextClassificationDataset(vocab, test_data, test_labels))
  126. def AG_NEWS(*args, **kwargs):
  127. """ Defines AG_NEWS datasets.
  128. The labels includes:
  129. - 1 : World
  130. - 2 : Sports
  131. - 3 : Business
  132. - 4 : Sci/Tech
  133. Create supervised learning dataset: AG_NEWS
  134. Separately returns the training and test dataset
  135. Arguments:
  136. root: Directory where the datasets are saved. Default: ".data"
  137. ngrams: a contiguous sequence of n items from s string text.
  138. Default: 1
  139. vocab: Vocabulary used for dataset. If None, it will generate a new
  140. vocabulary based on the train data set.
  141. include_unk: include unknown token in the data (Default: False)
  142. Examples:
  143. >>> train_dataset, test_dataset = torchtext.datasets.AG_NEWS(ngrams=3)
  144. """
  145. return _setup_datasets(*(("AG_NEWS",) + args), **kwargs)
  146. def SogouNews(*args, **kwargs):
  147. """ Defines SogouNews datasets.
  148. The labels includes:
  149. - 1 : Sports
  150. - 2 : Finance
  151. - 3 : Entertainment
  152. - 4 : Automobile
  153. - 5 : Technology
  154. Create supervised learning dataset: SogouNews
  155. Separately returns the training and test dataset
  156. Arguments:
  157. root: Directory where the datasets are saved. Default: ".data"
  158. ngrams: a contiguous sequence of n items from s string text.
  159. Default: 1
  160. vocab: Vocabulary used for dataset. If None, it will generate a new
  161. vocabulary based on the train data set.
  162. include_unk: include unknown token in the data (Default: False)
  163. Examples:
  164. >>> train_dataset, test_dataset = torchtext.datasets.SogouNews(ngrams=3)
  165. """
  166. return _setup_datasets(*(("SogouNews",) + args), **kwargs)
  167. def DBpedia(*args, **kwargs):
  168. """ Defines DBpedia datasets.
  169. The labels includes:
  170. - 1 : Company
  171. - 2 : EducationalInstitution
  172. - 3 : Artist
  173. - 4 : Athlete
  174. - 5 : OfficeHolder
  175. - 6 : MeanOfTransportation
  176. - 7 : Building
  177. - 8 : NaturalPlace
  178. - 9 : Village
  179. - 10 : Animal
  180. - 11 : Plant
  181. - 12 : Album
  182. - 13 : Film
  183. - 14 : WrittenWork
  184. Create supervised learning dataset: DBpedia
  185. Separately returns the training and test dataset
  186. Arguments:
  187. root: Directory where the datasets are saved. Default: ".data"
  188. ngrams: a contiguous sequence of n items from s string text.
  189. Default: 1
  190. vocab: Vocabulary used for dataset. If None, it will generate a new
  191. vocabulary based on the train data set.
  192. include_unk: include unknown token in the data (Default: False)
  193. Examples:
  194. >>> train_dataset, test_dataset = torchtext.datasets.DBpedia(ngrams=3)
  195. """
  196. return _setup_datasets(*(("DBpedia",) + args), **kwargs)
  197. def YelpReviewPolarity(*args, **kwargs):
  198. """ Defines YelpReviewPolarity datasets.
  199. The labels includes:
  200. - 1 : Negative polarity.
  201. - 2 : Positive polarity.
  202. Create supervised learning dataset: YelpReviewPolarity
  203. Separately returns the training and test dataset
  204. Arguments:
  205. root: Directory where the datasets are saved. Default: ".data"
  206. ngrams: a contiguous sequence of n items from s string text.
  207. Default: 1
  208. vocab: Vocabulary used for dataset. If None, it will generate a new
  209. vocabulary based on the train data set.
  210. include_unk: include unknown token in the data (Default: False)
  211. Examples:
  212. >>> train_dataset, test_dataset = torchtext.datasets.YelpReviewPolarity(ngrams=3)
  213. """
  214. return _setup_datasets(*(("YelpReviewPolarity",) + args), **kwargs)
  215. def YelpReviewFull(*args, **kwargs):
  216. """ Defines YelpReviewFull datasets.
  217. The labels includes:
  218. 1 - 5 : rating classes (5 is highly recommended).
  219. Create supervised learning dataset: YelpReviewFull
  220. Separately returns the training and test dataset
  221. Arguments:
  222. root: Directory where the datasets are saved. Default: ".data"
  223. ngrams: a contiguous sequence of n items from s string text.
  224. Default: 1
  225. vocab: Vocabulary used for dataset. If None, it will generate a new
  226. vocabulary based on the train data set.
  227. include_unk: include unknown token in the data (Default: False)
  228. Examples:
  229. >>> train_dataset, test_dataset = torchtext.datasets.YelpReviewFull(ngrams=3)
  230. """
  231. return _setup_datasets(*(("YelpReviewFull",) + args), **kwargs)
  232. def YahooAnswers(*args, **kwargs):
  233. """ Defines YahooAnswers datasets.
  234. The labels includes:
  235. - 1 : Society & Culture
  236. - 2 : Science & Mathematics
  237. - 3 : Health
  238. - 4 : Education & Reference
  239. - 5 : Computers & Internet
  240. - 6 : Sports
  241. - 7 : Business & Finance
  242. - 8 : Entertainment & Music
  243. - 9 : Family & Relationships
  244. - 10 : Politics & Government
  245. Create supervised learning dataset: YahooAnswers
  246. Separately returns the training and test dataset
  247. Arguments:
  248. root: Directory where the datasets are saved. Default: ".data"
  249. ngrams: a contiguous sequence of n items from s string text.
  250. Default: 1
  251. vocab: Vocabulary used for dataset. If None, it will generate a new
  252. vocabulary based on the train data set.
  253. include_unk: include unknown token in the data (Default: False)
  254. Examples:
  255. >>> train_dataset, test_dataset = torchtext.datasets.YahooAnswers(ngrams=3)
  256. """
  257. return _setup_datasets(*(("YahooAnswers",) + args), **kwargs)
  258. def AmazonReviewPolarity(*args, **kwargs):
  259. """ Defines AmazonReviewPolarity datasets.
  260. The labels includes:
  261. - 1 : Negative polarity
  262. - 2 : Positive polarity
  263. Create supervised learning dataset: AmazonReviewPolarity
  264. Separately returns the training and test dataset
  265. Arguments:
  266. root: Directory where the datasets are saved. Default: ".data"
  267. ngrams: a contiguous sequence of n items from s string text.
  268. Default: 1
  269. vocab: Vocabulary used for dataset. If None, it will generate a new
  270. vocabulary based on the train data set.
  271. include_unk: include unknown token in the data (Default: False)
  272. Examples:
  273. >>> train_dataset, test_dataset = torchtext.datasets.AmazonReviewPolarity(ngrams=3)
  274. """
  275. return _setup_datasets(*(("AmazonReviewPolarity",) + args), **kwargs)
  276. def AmazonReviewFull(*args, **kwargs):
  277. """ Defines AmazonReviewFull datasets.
  278. The labels includes:
  279. 1 - 5 : rating classes (5 is highly recommended)
  280. Create supervised learning dataset: AmazonReviewFull
  281. Separately returns the training and test dataset
  282. Arguments:
  283. root: Directory where the dataset are saved. Default: ".data"
  284. ngrams: a contiguous sequence of n items from s string text.
  285. Default: 1
  286. vocab: Vocabulary used for dataset. If None, it will generate a new
  287. vocabulary based on the train data set.
  288. include_unk: include unknown token in the data (Default: False)
  289. Examples:
  290. >>> train_dataset, test_dataset = torchtext.datasets.AmazonReviewFull(ngrams=3)
  291. """
  292. return _setup_datasets(*(("AmazonReviewFull",) + args), **kwargs)
  293. DATASETS = {
  294. 'AG_NEWS': AG_NEWS,
  295. 'SogouNews': SogouNews,
  296. 'DBpedia': DBpedia,
  297. 'YelpReviewPolarity': YelpReviewPolarity,
  298. 'YelpReviewFull': YelpReviewFull,
  299. 'YahooAnswers': YahooAnswers,
  300. 'AmazonReviewPolarity': AmazonReviewPolarity,
  301. 'AmazonReviewFull': AmazonReviewFull
  302. }
  303. LABELS = {
  304. 'AG_NEWS': {1: 'World',
  305. 2: 'Sports',
  306. 3: 'Business',
  307. 4: 'Sci/Tech'},
  308. 'SogouNews': {1: 'Sports',
  309. 2: 'Finance',
  310. 3: 'Entertainment',
  311. 4: 'Automobile',
  312. 5: 'Technology'},
  313. 'DBpedia': {1: 'Company',
  314. 2: 'EducationalInstitution',
  315. 3: 'Artist',
  316. 4: 'Athlete',
  317. 5: 'OfficeHolder',
  318. 6: 'MeanOfTransportation',
  319. 7: 'Building',
  320. 8: 'NaturalPlace',
  321. 9: 'Village',
  322. 10: 'Animal',
  323. 11: 'Plant',
  324. 12: 'Album',
  325. 13: 'Film',
  326. 14: 'WrittenWork'},
  327. 'YelpReviewPolarity': {1: 'Negative polarity',
  328. 2: 'Positive polarity'},
  329. 'YelpReviewFull': {1: 'score 1',
  330. 2: 'score 2',
  331. 3: 'score 3',
  332. 4: 'score 4',
  333. 5: 'score 5'},
  334. 'YahooAnswers': {1: 'Society & Culture',
  335. 2: 'Science & Mathematics',
  336. 3: 'Health',
  337. 4: 'Education & Reference',
  338. 5: 'Computers & Internet',
  339. 6: 'Sports',
  340. 7: 'Business & Finance',
  341. 8: 'Entertainment & Music',
  342. 9: 'Family & Relationships',
  343. 10: 'Politics & Government'},
  344. 'AmazonReviewPolarity': {1: 'Negative polarity',
  345. 2: 'Positive polarity'},
  346. 'AmazonReviewFull': {1: 'score 1',
  347. 2: 'score 2',
  348. 3: 'score 3',
  349. 4: 'score 4',
  350. 5: 'score 5'}
  351. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/article/detail/46918
推荐阅读
相关标签
  

闽ICP备14008679号