当前位置:   article > 正文

HuggingFace学习笔记--利用API实现简单的NLP任务_huggingface api

huggingface api

目录

1--中文分类

1-1--使用预训练模型推理

1-2--基于预训练模型实现下游任务

2--中文填空

3--中文句子关系推断


1--中文分类

1-1--使用预训练模型推理

代码实例:

  1. import torch
  2. from datasets import load_dataset
  3. from transformers import BertTokenizer, BertModel
  4. # 定义全局分词工具
  5. tokenizer = BertTokenizer.from_pretrained('bert-base-chinese')
  6. # 定义数据集
  7. class Dataset(torch.utils.data.Dataset):
  8. def __init__(self, split):
  9. self.dataset = load_dataset(path = 'lansinuote/ChnSentiCorp', split = split) # 加载数据集
  10. def __len__(self):
  11. return len(self.dataset)
  12. def __getitem__(self, i):
  13. text = self.dataset[i]['text']
  14. label = self.dataset[i]['label']
  15. return text, label
  16. # 自定义数据的处理(加载)方式
  17. def my_collate_fn(data): # data 的类型与 dataset 的返回值相同,本例中dataset返回一个列表[text, label]
  18. # 根据dataset的返回结果,取出对应的text和label
  19. sents = [i[0] for i in data]
  20. labels = [i[1] for i in data]
  21. # 使用全局的分词工具进行编码
  22. data = tokenizer.batch_encode_plus(batch_text_or_text_pairs = sents,
  23. truncation = True,
  24. padding = 'max_length',
  25. max_length = 500,
  26. return_tensors = 'pt',
  27. return_length = True)
  28. input_ids = data['input_ids']
  29. attention_mask = data['attention_mask']
  30. token_type_ids = data['token_type_ids']
  31. labels = torch.LongTensor(labels)
  32. return input_ids, attention_mask, token_type_ids, labels
  33. def main():
  34. dataset = Dataset('train') # 初始化训练集
  35. # print(len(dataset), dataset[0])
  36. # 定义dataloader
  37. loader = torch.utils.data.DataLoader(dataset = dataset,
  38. batch_size = 16,
  39. collate_fn = my_collate_fn,
  40. shuffle = True,
  41. drop_last = True)
  42. # 遍历dataloader加载数据
  43. for i, (input_ids, attention_mask, token_type_ids, labels) in enumerate(loader):
  44. break
  45. print(len(loader))
  46. print(input_ids.shape, attention_mask.shape, token_type_ids.shape, labels) # 打印一个样本
  47. # 加载预训练模型
  48. model = BertModel.from_pretrained('bert-base-chinese')
  49. for param in model.parameters(): # 不进行梯度计算和反向传播
  50. param.requires_grad_(False)
  51. # 调用预训练模型推理一个样本
  52. output = model(input_ids = input_ids, attention_mask = attention_mask, token_type_ids = token_type_ids)
  53. print(output.last_hidden_state.shape) # 打印最后一个隐层输出特征的维度
  54. if __name__ == "__main__":
  55. main()
  56. print("All done!")

输出结果:

  1. # dataloader单个样本:
  2. torch.Size([16, 500])
  3. torch.Size([16, 500])
  4. torch.Size([16, 500])
  5. tensor([1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1])
  6. # 最后一个隐层的输出特征:
  7. torch.Size([16, 500, 768])

1-2--基于预训练模型实现下游任务

        利用预训练 bert 模型最后一个隐层的[cls] token的特征进行中文分类;

代码:

  1. import torch
  2. from datasets import load_dataset
  3. from transformers import BertTokenizer, BertModel, AdamW
  4. # 定义全局分词工具
  5. tokenizer = BertTokenizer.from_pretrained('bert-base-chinese')
  6. # 定义数据集
  7. class Dataset(torch.utils.data.Dataset):
  8. def __init__(self, split):
  9. self.dataset = load_dataset(path = 'lansinuote/ChnSentiCorp', split = split) # 加载数据集
  10. def __len__(self):
  11. return len(self.dataset)
  12. def __getitem__(self, i):
  13. text = self.dataset[i]['text']
  14. label = self.dataset[i]['label']
  15. return text, label
  16. # 自定义数据的处理(加载)方式
  17. def my_collate_fn(data): # data 的类型与 dataset 的返回值相同,本例中dataset返回一个列表[text, label]
  18. # 根据dataset的返回结果,取出对应的text和label
  19. sents = [i[0] for i in data]
  20. labels = [i[1] for i in data]
  21. # 使用全局的分词工具进行编码
  22. data = tokenizer.batch_encode_plus(batch_text_or_text_pairs = sents,
  23. truncation = True,
  24. padding = 'max_length',
  25. max_length = 500,
  26. return_tensors = 'pt',
  27. return_length = True)
  28. input_ids = data['input_ids']
  29. attention_mask = data['attention_mask']
  30. token_type_ids = data['token_type_ids']
  31. labels = torch.LongTensor(labels)
  32. return input_ids, attention_mask, token_type_ids, labels
  33. # 定义下游任务模型
  34. class Model(torch.nn.Module):
  35. def __init__(self):
  36. super().__init__()
  37. self.pretrained_model = BertModel.from_pretrained('bert-base-chinese') # 加载预训练模型
  38. self.fc = torch.nn.Linear(768, 2)
  39. # 固定预训练模型
  40. for param in self.pretrained_model.parameters():
  41. param.requires_grad = False
  42. def forward(self, input_ids, attention_mask, token_type_ids):
  43. with torch.no_grad():
  44. output = self.pretrained_model(input_ids=input_ids,
  45. attention_mask=attention_mask,
  46. token_type_ids=token_type_ids)
  47. output = self.fc(output.last_hidden_state[:, 0]) # 利用最后一个隐层的[cls]token特征进行分类
  48. output = output.softmax(dim=1)
  49. return output
  50. # 定义测试函数
  51. def test(model, dataset):
  52. model.eval()
  53. correct = 0
  54. total = 0
  55. # 定义加载测试集的dataloader
  56. loader_test = torch.utils.data.DataLoader(dataset = dataset,
  57. batch_size = 32,
  58. collate_fn = my_collate_fn,
  59. shuffle = True,
  60. drop_last = True)
  61. for idx, (input_ids, attention_mask, token_type_ids, labels) in enumerate(loader_test):
  62. if idx == 5: # 测试5个batch
  63. break
  64. print(idx)
  65. with torch.no_grad():
  66. input_ids = input_ids.cuda()
  67. attention_mask = attention_mask.cuda()
  68. token_type_ids = token_type_ids.cuda()
  69. labels = labels.cuda()
  70. output = model(input_ids=input_ids, attention_mask=attention_mask, token_type_ids=token_type_ids)
  71. output = output.argmax(dim=1)
  72. correct += (output == labels).sum().item()
  73. total += len(labels)
  74. print("Acc: ", correct / total) # 打印5个batch的总体准确率
  75. def main():
  76. dataset = Dataset('train') # 初始化训练集
  77. # print(len(dataset), dataset[0])
  78. # 定义dataloader
  79. loader = torch.utils.data.DataLoader(dataset = dataset,
  80. batch_size = 16,
  81. num_workers = 8,
  82. collate_fn = my_collate_fn,
  83. shuffle = True,
  84. drop_last = True)
  85. # 初始化模型
  86. model = Model()
  87. model = model.cuda() # 使用GPU
  88. # 初始化优化器和损失函数
  89. optimizer = AdamW(model.parameters(), lr=5e-4)
  90. criterion = torch.nn.CrossEntropyLoss().cuda()
  91. # 训练模型
  92. model.train()
  93. for idx, (input_ids, attention_mask, token_type_ids, labels) in enumerate(loader): # 遍历加载数据
  94. input_ids = input_ids.cuda()
  95. attention_mask = attention_mask.cuda()
  96. token_type_ids = token_type_ids.cuda()
  97. labels = labels.cuda()
  98. output = model(input_ids=input_ids, attention_mask=attention_mask, token_type_ids=token_type_ids)
  99. loss = criterion(output, labels)
  100. loss.backward()
  101. optimizer.step()
  102. optimizer.zero_grad()
  103. if idx % 5 == 0: # 每5个batch打印当前准确率和损失
  104. output = output.argmax(dim=1)
  105. accuracy = (output == labels).sum().item() / len(labels)
  106. print(idx, loss.item(), accuracy)
  107. if idx == 300: # 使用300个batch进行训练
  108. break
  109. # 测试模型
  110. test(model, Dataset('validation'))
  111. if __name__ == "__main__":
  112. main()

部分输出结果:

  1. ...
  2. 260 0.5995925664901733 0.75
  3. 265 0.3791050910949707 1.0
  4. 270 0.42692136764526367 0.9375
  5. 275 0.4765201210975647 0.875
  6. 280 0.4071955382823944 0.9375
  7. 285 0.4194560945034027 0.875
  8. 290 0.449373722076416 0.9375
  9. 295 0.38813596963882446 1.0
  10. 300 0.5164415240287781 0.875
  11. Acc: 0.89375

2--中文填空

        对训练数据的第15个词进行 mask 掉,预测第15个词;

        利用 bert 模型提取特征,对最后一个隐层的第15个token特征进行分类;

        分类用的是一个简单的线性层,其维度为(768, token.vocab_size),其中token.vocab_sized的大小为21128,即预测21128个词的分类分数,再与真实标签进行损失计算;

代码:

  1. import torch
  2. from datasets import load_dataset, load_from_disk
  3. from transformers import BertTokenizer, BertModel, AdamW
  4. # 定义全局分词工具
  5. token = BertTokenizer.from_pretrained('bert-base-chinese')
  6. # 定义数据集
  7. class Dataset(torch.utils.data.Dataset):
  8. def __init__(self, split):
  9. dataset = load_dataset(path = 'lansinuote/ChnSentiCorp', split = split)
  10. # dataset = load_from_disk('./data/ChnSentiCorp')
  11. # dataset = dataset[split]
  12. def f(data):
  13. return len(data['text']) > 30
  14. self.dataset = dataset.filter(f) # 筛选数据集
  15. def __len__(self):
  16. return len(self.dataset)
  17. def __getitem__(self, i):
  18. text = self.dataset[i]['text']
  19. return text
  20. def collate_fn(data):
  21. # batch编码
  22. data = token.batch_encode_plus(batch_text_or_text_pairs = data,
  23. truncation = True,
  24. padding = 'max_length',
  25. max_length = 30, # padding到30个词
  26. return_tensors = 'pt', # 返回pytorch格式
  27. return_length = True)
  28. input_ids = data['input_ids']
  29. attention_mask = data['attention_mask']
  30. token_type_ids = data['token_type_ids']
  31. # 把第15个词固定替换为mask
  32. labels = input_ids[:, 15].reshape(-1).clone() # 记录真实标签
  33. input_ids[:, 15] = token.get_vocab()[token.mask_token]
  34. return input_ids, attention_mask, token_type_ids, labels
  35. # 定义下游任务模型
  36. class Model(torch.nn.Module):
  37. def __init__(self):
  38. super().__init__()
  39. self.decoder = torch.nn.Linear(768, token.vocab_size, bias=False) # token.vocab_size为21128,预测21128个词的分类分数
  40. self.bias = torch.nn.Parameter(torch.zeros(token.vocab_size))
  41. self.decoder.bias = self.bias
  42. self.pretrained = BertModel.from_pretrained('bert-base-chinese')
  43. # 固定预训练模型
  44. for param in self.pretrained.parameters():
  45. param.requires_grad = False
  46. def forward(self, input_ids, attention_mask, token_type_ids):
  47. # 使用bert模型提取特征
  48. with torch.no_grad():
  49. output = self.pretrained(input_ids=input_ids, attention_mask=attention_mask, token_type_ids=token_type_ids)
  50. output = self.decoder(output.last_hidden_state[:, 15])
  51. return output
  52. # 测试
  53. def test(model):
  54. model.eval()
  55. correct = 0
  56. total = 0
  57. loader_test = torch.utils.data.DataLoader(dataset = Dataset('test'),
  58. batch_size = 32,
  59. collate_fn = collate_fn,
  60. shuffle = True,
  61. drop_last = True)
  62. for idx, (input_ids, attention_mask, token_type_ids, labels) in enumerate(loader_test):
  63. input_ids = input_ids.cuda()
  64. attention_mask = attention_mask.cuda()
  65. token_type_ids = token_type_ids.cuda()
  66. labels = labels.cuda()
  67. if idx == 15: # 测试15个batch
  68. break
  69. with torch.no_grad():
  70. output = model(input_ids=input_ids, attention_mask=attention_mask, token_type_ids=token_type_ids)
  71. output = output.argmax(dim=1)
  72. correct += (output == labels).sum().item()
  73. total += len(labels)
  74. print(token.decode(input_ids[0])) # 打印测试数据
  75. print("真实标签: ", token.decode(labels[0]), "预测标签: ", token.decode(output[0]))
  76. print("Acc: ", correct / total)
  77. def main():
  78. # 初始化训练集
  79. dataset = Dataset('train')
  80. # 定义dataloader
  81. loader = torch.utils.data.DataLoader(dataset = dataset,
  82. batch_size = 16,
  83. collate_fn = collate_fn,
  84. shuffle = True,
  85. drop_last = True)
  86. # 初始化模型
  87. model = Model().cuda()
  88. # 训练
  89. optimizer = AdamW(model.parameters(), lr=5e-4)
  90. criterion = torch.nn.CrossEntropyLoss().cuda()
  91. model.train()
  92. for epoch in range(5):
  93. for idx, (input_ids, attention_mask, token_type_ids, labels) in enumerate(loader):
  94. input_ids = input_ids.cuda()
  95. attention_mask = attention_mask.cuda()
  96. token_type_ids = token_type_ids.cuda()
  97. labels = labels.cuda()
  98. output = model(input_ids=input_ids, attention_mask=attention_mask, token_type_ids=token_type_ids)
  99. loss = criterion(output, labels)
  100. loss.backward()
  101. optimizer.step()
  102. optimizer.zero_grad()
  103. if idx % 50 == 0:
  104. output = output.argmax(dim=1)
  105. accuracy = (output == labels).sum().item() / len(labels)
  106. print(epoch, idx, loss.item(), accuracy)
  107. # 测试模型
  108. test(model)
  109. if __name__ == "__main__":
  110. main()

部分输出结果:

  1. 4 200 0.7910566329956055 0.75
  2. 4 250 0.9690109491348267 0.8125
  3. 4 300 0.4056988060474396 0.9375
  4. 4 350 0.31916332244873047 1.0
  5. 4 400 0.8943865895271301 0.6875
  6. 4 450 0.4540601968765259 0.9375
  7. 4 500 0.7437821626663208 0.75
  8. 4 550 0.3669029474258423 0.9375
  9. [CLS] 之 前 看 到 很 多 评 论 , 说 很 好 兴 冲 [MASK] 买 了 , 看 了 看 感 觉 非 常 失 望 炒 [SEP]
  10. 真实标签: 冲 预测标签: 冲
  11. [CLS] 刚 看 了 一 章 就 丢 边 上 了 , 光 盘 也 [MASK] 知 道 放 哪 里 了 , 很 垃 圾 , 很 多 [SEP]
  12. 真实标签: 不 预测标签: 不
  13. [CLS] 酒 店 生 意 清 淡 , 大 堂 里 都 没 几 个 [MASK] 人 。 房 间 倒 是 不 小 , 但 觉 得 被 [SEP]
  14. 真实标签: 客 预测标签: 客
  15. [CLS] 选 购 的 时 候 , 还 是 有 货 的 。 最 后 [MASK] 通 知 我 说 , 没 货 了 。 当 当 的 服 [SEP]
  16. 真实标签: 却 预测标签: ,
  17. [CLS] 简 单 , 大 方 , 在 同 类 尺 寸 的 款 型 [MASK] 笔 记 本 中 不 显 厚 重 , 轻 薄 感 ! [SEP]
  18. 真实标签: 的 预测标签: 的
  19. [CLS] 当 时 是 同 事 极 力 推 荐 这 本 书 。 我 [MASK] 到 网 上 的 介 绍 和 那 么 多 的 [UNK] 名 [SEP]
  20. 真实标签: 看 预测标签: 看
  21. [CLS] 酒 店 位 置 离 火 车 站 很 近 , 走 路 10 [MASK] 钟 不 到 就 能 到 。 。 。 服 务 不 错 [SEP]
  22. 真实标签: 分 预测标签: 分
  23. [CLS] 买 之 前 也 没 见 过 这 本 书, 听 他 们 [MASK] 的 天 花 乱 坠, 翻 了 几 页 就 够 了 [SEP]
  24. 真实标签: 说 预测标签: 写
  25. [CLS] 看 了 百 家 讲 坛 , 来 了 兴 趣 。 因 为 [MASK] 作 忙 , 只 看 了 一 点 点 , 因 此 买 [SEP]
  26. 真实标签: 工 预测标签: 工
  27. [CLS] 第 一 次 买 的 拉 拉 升 职 记 , 三 天 到 [MASK] ( 我 住 北 京 三 环 边 上 ) , 还 比 [SEP]
  28. 真实标签: 货 预测标签: 手
  29. [CLS] 房 间 隔 音 效 果 极 差 , 深 夜 如 果 隔 [MASK] 客 人 大 声 喧 哗 的 话 [UNK] [UNK] 服 务 员 [SEP]
  30. 真实标签: 壁 预测标签: 音
  31. [CLS] 读 过 她 的 《 茶 人 三 部 曲 》 , 一 口 [MASK] 读 完 的 。 一 直 在 搜 寻 她 的 文 字 [SEP]
  32. 真实标签: 气 预测标签: 气
  33. [CLS] 条 件 、 服 务 、 设 施 都 很 好 , 房 间 [MASK] 干 净 、 很 舒 适 , 尤 其 是 前 台 服 [SEP]
  34. 真实标签: 很 预测标签: 很
  35. [CLS] 大 俗 即 大 雅 ! 这 是 看 郑 振 铎 先 生 [MASK] 部 书 后 最 由 衷 的 感 想 , 看 过 中 [SEP]
  36. 真实标签: 三 预测标签: 这
  37. [CLS] 觉 得 相 当 没 意 思 的 一 本 书 。 不 伦 [MASK] 类 的 。 看 的 时 候 很 纠 结 , 看 完 [SEP]
  38. 真实标签: 不 预测标签: 不
  39. Acc: 0.6979166666666666

3--中文句子关系推断

代码:

  1. import torch
  2. import random
  3. from datasets import load_dataset, load_from_disk
  4. from transformers import BertTokenizer, BertModel, AdamW
  5. # 定义全局分词工具
  6. token = BertTokenizer.from_pretrained('bert-base-chinese')
  7. # 定义数据集
  8. class Dataset(torch.utils.data.Dataset):
  9. def __init__(self, split):
  10. # dataset = load_dataset(path='lansinuote/ChnSentiCorp', split=split)
  11. dataset = load_from_disk('./data/ChnSentiCorp')
  12. dataset = dataset[split]
  13. def f(data):
  14. return len(data['text']) > 40
  15. self.dataset = dataset.filter(f)
  16. def __len__(self):
  17. return len(self.dataset)
  18. def __getitem__(self, i):
  19. text = self.dataset[i]['text']
  20. # 切分一句话为前半句和后半句
  21. sentence1 = text[:20]
  22. sentence2 = text[20:40]
  23. label = 0 # label为0表示为同一句
  24. # 有一半的概率把后半句替换为一句无关的话
  25. if random.randint(0, 1) == 0:
  26. j = random.randint(0, len(self.dataset) - 1)
  27. sentence2 = self.dataset[j]['text'][20:40]
  28. label = 1
  29. return sentence1, sentence2, label
  30. def collate_fn(data):
  31. sents = [i[:2] for i in data]
  32. labels = [i[2] for i in data]
  33. # 编码
  34. data = token.batch_encode_plus(batch_text_or_text_pairs = sents,
  35. truncation = True,
  36. padding = 'max_length',
  37. max_length = 45,
  38. return_tensors = 'pt',
  39. return_length = True,
  40. add_special_tokens = True)
  41. input_ids = data['input_ids']
  42. attention_mask = data['attention_mask']
  43. token_type_ids = data['token_type_ids']
  44. labels = torch.LongTensor(labels)
  45. return input_ids, attention_mask, token_type_ids, labels
  46. # 定义下游任务模型
  47. class Model(torch.nn.Module):
  48. def __init__(self):
  49. super().__init__()
  50. self.fc = torch.nn.Linear(768, 2) # 二分类
  51. self.pretrained = BertModel.from_pretrained('bert-base-chinese')
  52. # 固定预训练模型
  53. for param in self.pretrained.parameters():
  54. param.requires_grad = False
  55. def forward(self, input_ids, attention_mask, token_type_ids):
  56. with torch.no_grad():
  57. output = self.pretrained(input_ids = input_ids, attention_mask = attention_mask, token_type_ids = token_type_ids)
  58. output = self.fc(output.last_hidden_state[:, 0])
  59. output = output.softmax(dim=1)
  60. return output
  61. def main():
  62. model = Model().cuda()
  63. optimizer = AdamW(model.parameters(), lr=5e-4)
  64. criterion = torch.nn.CrossEntropyLoss().cuda()
  65. # dataloader
  66. loader = torch.utils.data.DataLoader(dataset = Dataset('train'),
  67. batch_size = 8,
  68. collate_fn = collate_fn,
  69. shuffle = True,
  70. drop_last = True)
  71. # 训练
  72. model.train()
  73. for idx, (input_ids, attention_mask, token_type_ids, labels) in enumerate(loader):
  74. input_ids = input_ids.cuda()
  75. attention_mask = attention_mask.cuda()
  76. token_type_ids = token_type_ids.cuda()
  77. labels = labels.cuda()
  78. output = model(input_ids=input_ids, attention_mask=attention_mask, token_type_ids=token_type_ids)
  79. loss = criterion(output, labels)
  80. loss.backward()
  81. optimizer.step()
  82. optimizer.zero_grad()
  83. if idx % 5 == 0: # 每5个batch打印
  84. output = output.argmax(dim=1)
  85. accuracy = (output == labels).sum().item() / len(labels)
  86. print(idx, loss.item(), accuracy)
  87. if idx == 300: # 训练300个batch
  88. break
  89. # 测试
  90. test(model)
  91. # 定义测试函数
  92. def test(model):
  93. model.eval()
  94. correct = 0
  95. total = 0
  96. loader_test = torch.utils.data.DataLoader(dataset = Dataset('test'),
  97. batch_size = 32,
  98. collate_fn = collate_fn,
  99. shuffle = True,
  100. drop_last = True)
  101. for idx, (input_ids, attention_mask, token_type_ids, labels) in enumerate(loader_test):
  102. input_ids = input_ids.cuda()
  103. attention_mask = attention_mask.cuda()
  104. token_type_ids = token_type_ids.cuda()
  105. labels = labels.cuda()
  106. if idx == 5: # 测试5个batch
  107. break
  108. with torch.no_grad():
  109. output = model(input_ids=input_ids, attention_mask=attention_mask, token_type_ids=token_type_ids)
  110. pred = output.argmax(dim=1)
  111. correct += (pred == labels).sum().item()
  112. total += len(labels)
  113. print('acc:', correct / total)
  114. if __name__ == "__main__":
  115. main()

部分运行结果:

  1. 240 0.39283961057662964 0.875
  2. 245 0.7069525122642517 0.5
  3. 250 0.41953372955322266 0.875
  4. 255 0.5032698512077332 0.75
  5. 260 0.6422066688537598 0.75
  6. 265 0.5467717051506042 0.75
  7. 270 0.4452913701534271 0.875
  8. 275 0.5998544096946716 0.625
  9. 280 0.4301206171512604 0.875
  10. 285 0.5177156329154968 0.75
  11. 290 0.3987200856208801 0.875
  12. 295 0.33609679341316223 1.0
  13. 300 0.3723036050796509 0.875
  14. acc: 0.925

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

闽ICP备14008679号