比赛链接:
https://www.heywhale.com/home/competition/609cc718ca31cd0017835fdc
内含4个数据集:
商品信息.csv (product_information.csv)
商品类别列表.csv (product_cls.csv)
训练集.csv (product_train.csv)
测试集.csv (product_test.csv)
我们首先将product_train.csv处理成bert能处理的语料product_review_train_bert.csv。
代码如下:
import csv
with open('data/product/product_train.csv','rt',encoding='utf-8') as f1,\
open('data/product/product_review_train_bert.csv','wt',encoding='utf-8') as f2:
reader = csv.reader(f1)
for num, i in enumerate(reader):
if num == 0:
continue
str1 = list(i[4]+i[5])
str1.insert(int(len(str1)/2),'\n')
text = "".join(str1)
print(text)
writer = csv.writer(f2)
writer.writerow([text])
product_train.csv:
数据ID,用户ID,商品ID,评论时间戳,评论标题,评论内容,评分
TRAIN_0,300212.0,PRODUCT_60357,1282579200,刚到!!!!!!!!,"刚刚收到,2天我晕,一般快递最快到我们这要3天呢,赞个!!! 包装台简单了,说明书看不懂。 瓶子半透明。 问了官方,说卓越也是他们的合作伙伴,正品放心。",4.0
TRAIN_1,213838.0,PRODUCT_354315,1305561600,很好的一本书,不过这本书没有赠送什么代金券。体现不出以前的正版图书送网站学习代金券的特点。,5.0
TRAIN_2,1045492.0,PRODUCT_192005,1357747200,二手手机,"很负责任的说一句,亚马逊给我发过来的手机绝对是二手的!!",1.0
TRAIN_3,587784.0,PRODUCT_1531,1305129600,送的光盘不行,"这本书内容很好,就是送的光盘不行。这次重新订购了一套,期望发过来的光盘能用",4.0
TRAIN_4,1244067.0,PRODUCT_324528,1285689600,很实用,"很实用的一本书,非常喜欢!",5.0
TRAIN_5,3361.0,PRODUCT_4163,1346256000,关于书籍的包装,"书籍本身没有问题,货物的包装实在不敢恭维。不知出于何种考虑,先前的纸盒包装现在换成了塑料袋,拍下的两本精装书拿到手居然卷了边,超级郁闷。以此种方式来降低成本,实在不足取。省下的只是仨瓜俩枣,失去的却是人们的信任。",4.0
product_review_train_bert.csv:
"刚到!!!!!!!!刚刚收到,2天我晕,一般快递最快到我们这要3天呢,赞个!!! 包装
台简单了,说明书看不懂。 瓶子半透明。 问了官方,说卓越也是他们的合作伙伴,正品放心。"
"很好的一本书不过这本书没有赠送什么代金券。体
现不出以前的正版图书送网站学习代金券的特点。"
"二手手机很负责任的说一句,亚马逊
给我发过来的手机绝对是二手的!!"
"送的光盘不行这本书内容很好,就是送的光盘不
行。这次重新订购了一套,期望发过来的光盘能用"
"很实用很实用的一
本书,非常喜欢!"
然后将训练集.csv中70000条数据分为train.csv(50000条),dev.csv(10000条),test.csv(10000条)
注意: 标签要从0开始
部分代码:
with open('data/product/product_train.csv','rt',encoding='utf-8') as f1,\
open('data/product/product_review_train_train.csv','wt',encoding='utf-8') as f2,\
open('data/product/product_review_train_dev.csv','wt',encoding='utf-8') as f3,\
open('data/product/product_review_train_test.csv','wt',encoding='utf-8') as f4:
reader = csv.reader(f1)
for num, i in enumerate(reader):
if num<=50000:
if num == 0:
tgt = 'label'
text = 'text_a'
else:
tgt = str(int(float(i[-1])))
text = i[4] + i[5]
str1 = tgt + '\t' + text + '\n'
writer = csv.writer(f2)
f2.write(str1)
elif num>50000 and num<=60000:
if num == 50001:
tgt = 'label'
text = 'text_a'
else:
tgt = str(int(float(i[-1])))
text = i[4] + i[5]
str2 = tgt + '\t' + text + '\n'
writer = csv.writer(f3)
f3.write(str2)
else:
if num == 60001:
tgt = 'label'
text = 'text_a'
else:
tgt = str(int(float(i[-1])))
text = i[4] + i[5]
str3 = tgt + '\t' + text + '\n'
writer = csv.writer(f4)
f4.write(str3)
label text_a
3 刚到!!!!!!!!刚刚收到,2天我晕,一般快递最快到我们这要3天呢,赞个!!! 包装台简单了,说明书看不懂。 瓶子半透明。 问了官方,说卓越也是他们的合作伙伴,正品放心。
4 很好的一本书不过这本书没有赠送什么代金券。体现不出以前的正版图书送网站学习代金券的特点。
0 二手手机很负责任的说一句,亚马逊给我发过来的手机绝对是二手的!!
3 送的光盘不行这本书内容很好,就是送的光盘不行。这次重新订购了一套,期望发过来的光盘能用
4 很实用很实用的一本书,非常喜欢!
3 关于书籍的包装书籍本身没有问题,货物的包装实在不敢恭维。不知出于何种考虑,先前的纸盒包装现在换成了塑料袋,拍下的两本精装书拿到手居然卷了边,超级郁闷。以此种方式来降低成本,实在不足取。省下的只是仨瓜俩枣,失去的却是人们的信任。
label text_a
4 L'OREAL PARIS巴黎欧莱雅多效修复去屑洗发露400mlL'OREAL PARIS巴黎欧莱雅多效修复去屑洗发露400ml,老婆一直用这个牌子,还行吧
0 你如果阻止我评论,我会奉陪到底。我想告诉你的是,在维权的路上我从没败下阵来。 我退货的款为什么还不到我的银行卡上?已经一个多月了。我之前发的商品评论3次,为什么都被你们删去了?卓越你是大公司还是小作坊?前天客服谢亮答应给我把钱转到银行卡上,为什么现在还不到?你耍弄顾客? SKIN79钻石闪耀系列钻石光泽BB霜SPF25/PA++/40g 我选择货到付款免运费,你为什么要用我退货的钱,还要扣我运费?
4 适合小学生的适合小学生的小说,不错
3 好货值,但是使用起来有些麻烦,还要申请一个电信号码
4 很喜欢很喜欢,三层不锈钢奶锅,用料很足,但是有些重....总体很美观
2 比较一般,笼统,随便看看的就行,不要期望它能给多大启发。比较一般,笼统,随便看看的就行,不要期望它能给多大启发。
label text_a
4 很精致帮朋友买的 很精致的书 朋友很喜欢
3 还行,看了一遍本来想看英文版的,没找到合适的,这本又降了一点价,就看了中文版的。 书里图片很少,每一章节开头一小张,全黑白。 书里讲得不光是 这只叫杜威的猫的事情,很大程度上算是 图书馆馆长(养杜威的主要负责人)的叙述,所以包含了一些她自己的事情。 可以看一下,看一遍不觉得难受(既没有读不下去的难受,也没有感动到难受),但是也没有激起看第二遍的欲望。
1 用后非常干!!!如题,在夏天用过的时候还是会脱皮,坚持用完一半,之后扔了……
2 预装WIN8略鸡肋本身看机子配置不错,性价比高才买,之前用的几个本子都是thinkpad,还是相信其质量。不过预装的win8用不习惯,考虑到毕竟是花钱买的正版系统,且看网上说这款机子改装别的系统比较麻烦,我还是磨合着用win8吧,目前运行以前xp时代的老游戏,没出太大问题,遗憾的是win8太耗资源,在这种配置的机子上跑不起来。机子预装的软件都没什么用,全删了。本身硬盘只有一个分区,不太习惯,我自己又重新分了一下区。另外无线网卡的驱动有问题,老掉线,说是跟win8没兼容好,重新更新驱动后解决问题。散热还不错,运行游戏没觉得很烫。不过这款机子是没有小键盘区的,对于经常玩游戏的来说,没有小键盘还是有些不方便,建议可买同配置的e530。机子上的触控鼠标板不太好使,没用几次就发出咯吱咯吱的声音,因为缝隙太大,似乎有杂物卡进去了,好在我平时几乎不用这个触控板,不好使也无所谓。
3 2~3M/s,就这速度吧。发货速度很快。外观看起来还行,速度就那么回事吧。包装要是取消纸盒是不是更环保?
1 ZTE 中兴买了10多天了。前五天的时候打点话老是自动关机,这几天好像没事了。问了客服要检测我嫌太麻烦。几百的东西,没那必要。
4 无论世间如何喧嚣,它就在那里,安安静静无疑说,这是迄今读过的最没有佐料的历史书。 所有的历史里,都是被人收拾过的,或者加了盐,或者加了味精,或者穿了衣服。 这是一本纯粹的历史书,一本关于物的历史。 特别推荐第1号木乃伊,第12乌尔旗,第25号克罗伊金币,第49号新罗瓦当,第61号刘易斯棋子,第100号太阳能灯具与充电器。 重点推荐第65号泰诺仪式用椅,第80号八里尔银币。 他们一直在那里,无论世间多么喧嚣,他们始终安安静静,一言不发。 这才是真正的历史书。
1 为何我只给2颗星的评价?从小学4年级开始就看言情作品,至今也有十余载了。看文的数量与质量也不断在提高。月沉吟一作,个人感觉,他的文笔不差,不差。在某一方面,譬如说某些场景的描写,在文字间都让人回归到作者的文章主题——是,我看的是一部战乱四起,爱恨缠绕的文,我也知道,女主角身兼数任,但是她坚毅的个性使得她得到了作者文下各个人物的怜爱。可惜的是,看评价的各位亲,你们发现问题没——仅仅的,我只是认知了这部作品的思路,它的走向,而却完全没有融入里面的起起伏伏。作者的场景描写不错,但是她缺乏的是在人物状态的描写。不是说没有描写,而是,描写依旧生硬稚嫩,正如我刚才所说,我只知道女主角的伟大情操,但是,看完了,作为读者的我,是没有本应存在的心痛难熬、怅然若失的感觉的。当场景与人物的描写不能同步时,真真很难让人对一部作品做出华丽得令人光华的赞美。所以我——不认为卿妃这部作品是上乘之品。话说回来,月沉吟也是卿妃刚出道的作品罢了,来日方长,假以时日,卿妃的文字将会更加成熟。2星,与君共勉的成绩罢。
4 我想你了。 我爱你,某人。我想念你了,你知道吗? 是一本用朴实的文字让我们心灵颤动的青春回忆录。
对测试集.csv进行处理
代码如下:
with open('data/product/product_test.csv','rt',encoding='utf-8') as f1,\
open('data/product/test_nolabel.csv','wt',encoding='utf-8') as f2:
reader = csv.reader(f1)
for num, i in enumerate(reader):
if num == 0:
text = 'text_a'
else:
text = i[4] + i[5]
str1 = text + '\n'
writer = csv.writer(f2)
f2.write(str1)
text_a
东西不错大三元之一 东西看上去不错,包装也都很好,关键是价格比京东便宜很多。 还没试过,回去试一下。 不足是不能开增票。比较遗憾
这么丰富的经历没写出来这么丰富的经历没写出来,对于我们以后上哪玩挺有帮助,作为游记一般吧。
很喜欢 支持离歌 支持饶雪漫~~很喜欢 支持离歌 支持饶雪漫~~
内容空洞,不值得买内容很空洞,有炫富意味,其它的倒还真没看出什么所以然来。很后悔买了这本书。完全想废纸一样。
爱自己多一点这个书的内容总的来说不错的,书名有点夸张,但看了内容后,发现真的很实实在在的,一点也不夸大。本人特别喜欢后面部分关于鼓舞的内容。一个女人天生长得美人见人爱,而长得不好看的有很多人都自卑,于是总想方设法运用各种化妆品来装饰自己,以此来让别人喜欢自己。看了这个书的内容,很感动,并不是说她的观点如何的好,而是这样的观点出在减肥书上,不漂亮没关系,对自己自信一点,对周围的人更关心一点,你也可以由内而外变得越来越美丽,每天给自己一个小小的肯定,对自己说OK。
词典文件的格式是一行一个单词,我们使用谷歌提供的包含21128个中文字符的词典文件models/google_zh_vocab.txt
预处理阶段需要指定模型的目标任务(–target):
python3 preprocess.py --corpus_path corpora/product_review_train_bert.csv --vocab_path models/google_zh_vocab.txt \
--dataset_path dataset_product.pt --processes_num 8 --target bert
预处理非常耗时,使用多个进程可以大大加快预处理速度(–processes_num)。默认的分词器为 --tokenizer bert 。原始文本在预处理之后被转换为pretrain.py的可以接收的输入,dataset_product.pt。
然后下载Google中文预训练模型google_zh_model.bin,并将其放在 models 文件夹中。接着加载Google中文预训练模型,在书评语料上对其进行增量预训练。预训练模型由词向量层,编码层和目标任务层组成。因此要构建预训练模型,我们应明确指定模型的词向量层(–embedding),编码器层(–encoder 和 --mask)和目标任务层(–target)的类型。
python3 pretrain.py --dataset_path dataset_product.pt --vocab_path models/google_zh_vocab.txt \
--pretrained_model_path models/google_zh_model.bin \
--output_model_path models/product_review_train_model.bin \
--world_size 1 --gpu_ranks 0 \
--total_steps 5000 --save_checkpoint_steps 1000 --batch_size 8 \
--embedding word_pos_seg --encoder transformer --mask fully_visible --target bert
mv models/product_review_train_model.bin-5000 models/product_review_train_model.bin
–mask 指定注意力网络中使用的遮罩类型。BERT使用双向语言模型,句子中的任意一个词可以看到所有词的信息,因此我们使用 fully_visible 遮罩类型。BERT模型的词向量层是word(token)、position、segment向量的求和,因此我们使用 --embedding word_pos_seg 。默认情况下,配置文件为 models/bert/base_config.json 。配置文件指定了模型的超参数。 请注意,pretrain.py输出的模型会带有记录训练步数的后缀(–total_steps),这里我们可以删除后缀以方便使用。
运行结果:
然后,我们在下游分类数据集上微调预训练模型,我们使用 pretrain.py 的输出product_review_train_model.bin:
python3 finetune/run_classifier.py --pretrained_model_path models/product_review_train_model.bin \
--vocab_path models/google_zh_vocab.txt \
--train_path datasets/product_review/train_train.csv \
--dev_path datasets/product_review/train_dev.csv \
--test_path datasets/product_review/train_test.csv \
--output_model_path models/finetune_product_train_model.bin \
--epochs_num 3 --batch_size 8 \
--embedding word_pos_seg --encoder transformer --mask fully_visible
微调后的模型的默认路径是models/finetuned_model.bin,
注意到我们在微调阶段可以使用 --output_model_path 指定微调后的模型的输出路径。
Test set evaluation.
Confusion matrix:
tensor([[ 216, 65, 25, 6, 7],
[ 58, 124, 73, 10, 2],
[ 84, 189, 600, 307, 87],
[ 5, 14, 243, 731, 382],
[ 44, 14, 177, 1419, 5117]])
Report precision, recall, and f1:
Label 0: 0.677, 0.531, 0.595
Label 1: 0.464, 0.305, 0.368
Label 2: 0.474, 0.537, 0.503
Label 3: 0.532, 0.296, 0.380
Label 4: 0.756, 0.915, 0.828
Acc. (Correct/Total): 0.6789 (6788/9999)
之后我们利用微调后的分类器模型进行预测:
python3 inference/run_classifier_infer.py --load_model_path models/finetune_product_train_model.bin \
--vocab_path models/google_zh_vocab.txt \
--test_path datasets/product_review/test_nolabel.csv \
--prediction_path datasets/product_review/prediction.csv \
--labels_num 5 \
--embedding word_pos_seg --encoder transformer --mask fully_visible
prediction.csv:
label
4
2
4
0
4
4
4
我们发现数据中标签为0,1的样本很少,通过NLP中一些简单的数据增强技术:
同义词替换(SR: Synonyms Replace):不考虑stopwords,在句子中随机抽取n个词,然后从同义词词典中随机抽取同义词,并进行替换。
随机插入(RI: Randomly Insert):不考虑stopwords,随机抽取一个词,然后在该词的同义词集合中随机选择一个,插入原句子中的随机位置。该过程可以重复n次。
随机交换(RS: Randomly Swap):句子中,随机选择两个词,位置交换。该过程可以重复n次。
随机删除(RD: Randomly Delete):句子中的每个词,以概率p随机删除。
重新设置每条原始语句增强的语句数为4。每条语句中将会被改变的单词数占比0.1。将标签为0,1,的样本进行数据增强。增强后的总数据量由70000到91776条。将数据打乱product_train_aug_shuffle02.csv。
1.把数据处理成bert可以处理的数据product_aug_bert02.csv
2.将55000条作为train,18000作为dev,18776作为test,生成product_aug_train02.csv,product_aug_dev02.csv,product_aug_test02.csv
预处理:
python3 preprocess.py --corpus_path corpora/product_aug_bert02.csv --vocab_path models/google_zh_vocab.txt \
--dataset_path dataset_product_aug02.pt --processes_num 8 --target bert
预训练:
python3 pretrain.py --dataset_path dataset_product_aug02.pt --vocab_path models/google_zh_vocab.txt \
--pretrained_model_path models/google_zh_model.bin \
--output_model_path models/product_train_model_aug02.bin \
--world_size 1 --gpu_ranks 0 \
--total_steps 5000 --save_checkpoint_steps 1000 --batch_size 8 \
--embedding word_pos_seg --encoder transformer --mask fully_visible --target bert
mv models/product_train_model_aug02.bin-5000 models/product_train_model_aug02.bin
微调:
python3 finetune/run_classifier.py --pretrained_model_path models/product_train_model_aug02.bin \
--vocab_path models/google_zh_vocab.txt \
--train_path datasets/product_review/product_aug_train02.csv \
--dev_path datasets/product_review/product_aug_dev02.csv \
--test_path datasets/product_review/product_aug_test02.csv \
--output_model_path models/finetune_product_train_model_aug02.bin \
--epochs_num 3 --batch_size 8 \
--embedding word_pos_seg --encoder transformer --mask fully_visible
运行结果:
Test set evaluation.
Confusion matrix:
tensor([[2540, 151, 60, 17, 13],
[ 136, 2127, 140, 19, 13],
[ 119, 362, 834, 440, 143],
[ 22, 21, 476, 1321, 988],
[ 73, 12, 175, 1622, 6951]])
Report precision, recall, and f1:
Label 0: 0.913, 0.879, 0.896
Label 1: 0.874, 0.796, 0.833
Label 2: 0.439, 0.495, 0.466
Label 3: 0.467, 0.386, 0.423
Label 4: 0.787, 0.857, 0.821
Acc. (Correct/Total): 0.7336 (13773/18775)
预测结果:
python3 inference/run_classifier_infer.py --load_model_path models/finetune_product_train_model_aug02.bin \
--vocab_path models/google_zh_vocab.txt \
--test_path datasets/product_review/test_nolabel.csv \
--prediction_path datasets/product_review/prediction_aug02.csv \
--labels_num 5 \
--embedding word_pos_seg --encoder transformer --mask fully_visible
prediction_aug02.csv:
label
3
2
4
0
4
4
3
4
提交到比赛结果却并不理想(0.6606)
在eda这篇论文( Easy Data Augmentation Techniques for Boosting Performance on Text Classification Tasks)中
Should I use EDA if I’m using a pre-trained model such as BERT or ELMo?
Models that have been pre-trained on massive datasets probably don’t need EDA.
因此我怀疑使用数据增强却没有得到理想的结果的原因可能是论文中所说的在大量数据集上预先训练好的模型可能不需要EDA。
预训练
python3 pretrain.py --dataset_path dataset_product.pt --vocab_path models/google_zh_vocab.txt \
--pretrained_model_path models/google_zh_model.bin \
--output_model_path models/product_review_train_model.bin \
--world_size 1 --gpu_ranks 0 --dropout 0.5 \
--total_steps 5000 --save_checkpoint_steps 1000 --batch_size 8 \
--embedding word_pos_seg --encoder transformer --mask fully_visible --target bert
预测结果
python3 inference/run_classifier_infer.py --load_model_path models/finetune_product_train_model_dropout.bin \
--vocab_path models/google_zh_vocab.txt \
--test_path datasets/product_review/test_nolabel.csv \
--prediction_path datasets/product_review/prediction_dropout.csv \
--labels_num 5 \
--embedding word_pos_seg --encoder transformer --mask fully_visible
BERT参数量大,计算较慢。我们希望加速模型的同时让模型仍然在下游任务上有好的表现。这里我们选择2层LSTM编码器来替代12层Transformer编码器。我们首先下载2层LSTM编码器的预训练模型cluecorpussmall_lstm_lm_model.bin。这个预训练模型在CLUECorpusSmall语料上训练了50万步
mv models/cluecorpussmall_lstm_lm_model.bin-500000 models/cluecorpussmall_lstm_lm_model.bin
python3 finetune/run_classifier.py --pretrained_model_path models/cluecorpussmall_lstm_lm_model.bin \
--vocab_path models/google_zh_vocab.txt --config_path models/rnn_config.json \
--train_path datasets/product_review/train_train.csv \
--dev_path datasets/product_review/train_dev.csv \
--test_path datasets/product_review/train_test.csv \
--output_model_path models/finetune_product_lstm_lm_model.bin \
--learning_rate 1e-3 --batch_size 8 --epochs_num 3 \
--embedding word --remove_embedding_layernorm --encoder lstm --pooling mean
Test set evaluation.
Confusion matrix:
tensor([[ 217, 85, 45, 12, 13],
[ 32, 79, 39, 5, 2],
[ 88, 186, 514, 264, 69],
[ 15, 25, 326, 754, 411],
[ 55, 31, 194, 1438, 5100]])
Report precision, recall, and f1:
Label 0: 0.583, 0.533, 0.557
Label 1: 0.503, 0.195, 0.281
Label 2: 0.459, 0.460, 0.459
Label 3: 0.492, 0.305, 0.377
Label 4: 0.748, 0.912, 0.822
Acc. (Correct/Total): 0.6665 (6664/9999)
python3 inference/run_classifier_infer.py --load_model_path models/finetune_product_lstm_lm_model.bin \
--vocab_path models/google_zh_vocab.txt \
--config_path models/rnn_config.json \
--test_path datasets/product_review/test_nolabel.csv \
--prediction_path datasets/product_review/prediction_lstm.csv \
--labels_num 5 \
--embedding word --remove_embedding_layernorm --encoder lstm --pooling mean
提交比赛得分:0.6583