【问题标题】:BERT Multi-class Sentiment Analysis got low accuracy?BERT 多类情感分析准确率低?
【发布时间】:2020-11-10 07:12:10
【问题描述】:

我正在处理一个小型数据集:

  • 包含 1500 篇新闻文章。

  • 所有这些文章都根据人们的情绪/积极程度按 5 分制进行排名。

  • 清除拼写错误。在导入分析之前,我使用谷歌表检查拼写。还有一些字符没有正确编码,但不多。

  • 平均长度大于512字。

  • 稍微不平衡的数据集。

我认为这是一个多类分类问题,我想用这个数据集微调 BERT。为了做到这一点,我使用了Ktrain 包并基本上遵循教程。以下是我的代码:

(x_train, y_train), (x_test, y_test), preproc = text.texts_from_array(
                                                                    x_train=x_train, 
                                                                    y_train=y_train,
                                                                    x_test=x_test, 
                                                                    y_test=y_test,
                                                                    class_names=categories,
                                                                    preprocess_mode='bert',
                                                                    maxlen= 510,
                                                                    max_features=35000)

model = text.text_classifier('bert', train_data=(x_train, y_train), preproc=preproc)
learner = ktrain.get_learner(model, train_data=(x_train, y_train), batch_size=6)
learner.fit_onecycle(2e-5, 4)

但是,我的验证准确率只有 25% 左右,太低了。

          precision-recall f1-score support

   1       0.33      0.40      0.36        75
   2       0.27      0.36      0.31        84
   3       0.23      0.24      0.23        58
   4       0.18      0.09      0.12        54
   5       0.33      0.04      0.07        24
accuracy                               0.27       295
macro avg          0.27      0.23      0.22       295
weighted avg       0.26      0.27      0.25       295

我也尝试了头+尾截断策略,因为有些文章很长,但是性能保持不变。

谁能给我一些建议?

非常感谢!

最好的

================== 更新 7.21=================

按照 Kartikey 的建议,我尝试了 find_lr。下面是结果。看来 2e^-5 是一个合理的学习率。

simulating training for different learning rates... this may take a few 
moments...
Train on 1182 samples
Epoch 1/2
1182/1182 [==============================] - 223s 188ms/sample - loss: 1.6878 
- accuracy: 0.2487
Epoch 2/2
432/1182 [=========>....................] - ETA: 2:12 - loss: 3.4780 - 
accuracy: 0.2639
done.
Visually inspect loss plot and select learning rate associated with falling 
loss

learning rate.jpg

我只是试着用一些权重来运行它:

{0: 0,
 1: 0.8294736842105264,
 2: 0.6715909090909091,
 3: 1.0844036697247708,
 4: 1.1311004784688996,
 5: 2.0033898305084747}

这是结果。变化不大。

          precision    recall  f1-score   support

       1       0.43      0.27      0.33        88
       2       0.22      0.46      0.30        69
       3       0.19      0.09      0.13        64
       4       0.13      0.13      0.13        47
       5       0.16      0.11      0.13        28

accuracy                            0.24       296
macro avg       0.23      0.21      0.20       296
weighted avg    0.26      0.24      0.23       296

array([[24, 41,  9,  8,  6],
       [13, 32,  6, 12,  6],
       [ 9, 33,  6, 14,  2],
       [ 4, 25, 10,  6,  2],
       [ 6, 14,  0,  5,  3]])

============== 更新 7.22 =============

为了获得一些基线结果,我将 5 分等级的分类问题折叠为二元分类问题,这只是为了预测正面或负面。这次准确率提高到 55% 左右。以下是我的策略的详细描述:

training data: 956 samples (excluding those classified as neutural)
truncation strategy: use the first 128 and last 128 tokens
(x_train,  y_train), (x_test, y_test), preproc_l1 = 
                     text.texts_from_array(x_train=x_train, y_train=y_train,    
                     x_test=x_test, y_test=y_test                      
                     class_names=categories_1,                      
                     preprocess_mode='bert',                                                          
                     maxlen=  256,                                                                  
                     max_features=35000)
Results:
              precision    recall  f1-score   support

       1       0.65      0.80      0.72       151
       2       0.45      0.28      0.35        89

accuracy                               0.61       240
macro avg          0.55      0.54      0.53       240
weighted avg       0.58      0.61      0.58       240

array([[121,  30],
       [ 64,  25]])

不过,我认为 55% 的准确率仍然不够令人满意,比随机猜测略好。

============ 更新 7.26 ============

按照 Marcos Lima 的建议,我在程序中增加了几个步骤:

  1. 在 Ktrain pkg 预处理之前删除所有数字、标点符号和多余的空格。 (我认为 Ktrain pkg 会为我执行此操作,但不确定)

  2. 我使用示例中任何文本的前 384 个和后 128 个标记。这就是我所说的“头+尾”策略。

  3. 任务还是二分类(正vs负)

这是学习曲线图。它和我之前发布的一样。而且它看起来仍然与 Marcos Lima 发布的非常不同:

The updated learning curve

以下是我的结果,这可能是我得到的最好的一组结果。

begin training using onecycle policy with max lr of 1e-05...
Train on 1405 samples
Epoch 1/4
1405/1405 [==============================] - 186s 133ms/sample - loss: 0.7220 
- accuracy: 0.5431
Epoch 2/4
1405/1405 [==============================] - 167s 119ms/sample - loss: 0.6866 
- accuracy: 0.5843
Epoch 3/4
1405/1405 [==============================] - 166s 118ms/sample - loss: 0.6565 
- accuracy: 0.6335
Epoch 4/4
1405/1405 [==============================] - 166s 118ms/sample - loss: 0.5321 
- accuracy: 0.7587

             precision    recall  f1-score   support

       1       0.77      0.69      0.73       241
       2       0.46      0.56      0.50       111

accuracy                           0.65       352
macro avg       0.61      0.63      0.62       352
weighted avg       0.67      0.65      0.66       352

array([[167,  74],
       [ 49,  62]])

注意:我认为 pkg 很难很好地完成我的任务的原因可能是这个任务就像是分类和情感分析的结合。新闻文章的经典分类任务是分类新闻属于哪个类别,例如,生物学、经济学、体育。不同类别中使用的词非常不同。另一方面,情感分类的经典例子是分析 Yelp 或 IMDB 评论。我的猜测是,这些文本在表达情绪方面非常简单,而我的样本中的文本(经济新闻)在发布前经过精心整理和组织,因此情绪可能总是以某种隐含的方式出现,而 BERT 可能无法检测到。

【问题讨论】:

  • bert 的推荐 batch_size 为 16,32,尝试使用它。这是一篇关于使用 BERT 进行多类文本分类的文章,可能会有所帮助:pysnacks.com/machine-learning/… 另外,我建议根据 Google 的这篇论文增加批量大小而不是衰减学习:arxiv.org/abs/1711.00489

标签: machine-learning nlp sentiment-analysis bert-language-model ktrain


【解决方案1】:

尝试超参数优化。

在做learner.fit_onecycle(2e-5, 4)之前。试试看:learner.lr_find(show_plot=True, max_epochs=2)

所有课程的权重都在 20% 左右吗? 不妨试试这种方式:

MODEL_NAME = 'bert'
t = text.Transformer(MODEL_NAME, maxlen=500, class_names=train_b.target_names)

.....
.....

# the one we got most wrong
learner.view_top_losses(n=1, preproc=t)

为上述类增加权重。

验证集是分层抽样还是随机抽样?

【讨论】:

  • 谢谢你们。我刚刚更新了我的帖子。根据您的建议,我没有看到明显的改进。验证集具有随机抽样。
  • 在这一点上,我给你的建议是尝试一个基本的RNN 模型来获得一个基线想法。我曾研究过类似的problem。希望对您有所帮助。
【解决方案2】:

你的学习曲线的形式不是预期的。

我的曲线(上图)显示 TR 应该在 1e-5 左右,但你的曲线是平的。

尝试预处理您的数据:

  • 删除数字和表情符号。
  • 重新检查数据是否有错误(通常在 y_train 中)。
  • 如果不是英语,请使用您的语言模型或多语言。

你说过:

平均长度大于512字。

尝试将每个文本分成 512 个标记长,因为当 BERT 模型截断它时,您可能会丢失很多分类信息。

【讨论】:

  • 非常感谢您的 cmets。我已根据您的建议更新了我的帖子。他们更好,但仍然没有达到我的期望。我目前正在使用 Head + tail 策略来处理超过 512 的文章。这是您的建议吗?还是您的意思是我将每篇文章分成不同的部分并以某种方式汇总它们?
  • 您可以在多个样本中转换每个文本。例如,如果您有一个 2000 个标记的长文本,您可以生成大约四个。包含随机选择的句子的 500 长样本。这只是一种尝试,但它可能会奏效。通过 NBSVM 分类,我得到了更快更好的结果。尝试比较它们。
【解决方案3】:

尝试将问题视为文本回归任务,例如使用 ktrain 训练的 this Yelp sentiment model

【讨论】:

  • 感谢您的建议。我试图将其作为文本回归运行。我终于得到了 1.1 左右的 MAE,考虑到这是 1~5 的比例,1.1 的 mae 似乎相当大。我说的对吗?
猜你喜欢
  • 2020-02-12
  • 1970-01-01
  • 2018-05-29
  • 2020-06-29
  • 1970-01-01
  • 2016-12-03
  • 2019-02-14
  • 2020-07-14
  • 2020-05-14
相关资源
最近更新 更多