跳转至

1.2 baseline解决方案实现

随机森林的快速基线模型1.0


学习目标

  • 掌握对数据进行快速分析的代码实现.
  • 掌握利用随机森林快速实现并评估基线模型.

数据分析

  • 数据分析代码位置: /home/ec2-user/toutiao/baseline/random_forest/analysis.py
    • 第一步: 读数据并统计分类数量
    • 第二步: 分析样本分布
    • 第三步: 进行分词预处理
    • 第四步: 处理验证集和测试集数据

  • 第一步: 读数据并统计分类数量
import pandas as pd
from collections import Counter
import numpy as np
import jieba


content = pd.read_csv('./data/data/train.txt', sep='\t')

print(content.head(10))

print(len(content))

count = Counter(content.label.values)

print(count)
print(len(count))
print('***************************************')

  • 调用:
python analysis.py

  • 输出结果:
                    sentence  label
0         中华女子学院:本科层次仅1专业招男生      3
1     两天价网站背后重重迷雾:做个网站究竟要多少钱      4
2  东5环海棠公社230-290平2居准现房98折优惠      1
3  卡佩罗:告诉你德国脚生猛的原因 不希望英德战踢点球      7
4    82岁老太为学生做饭扫地44年获授港大荣誉院士      5
5       记者回访地震中可乐男孩:将受邀赴美国参观      5
6          冯德伦徐若�隔空传情 默认其是女友      9
7     传郭晶晶欲落户香港战伦敦奥运 装修别墅当婚房      1
8           《赤壁OL》攻城战诸侯战硝烟又起      8
9                “手机钱包”亮相科博会      4
180000
Counter({3: 18000, 4: 18000, 1: 18000, 7: 18000, 5: 18000, 9: 18000, 8: 18000, 2: 18000, 6: 18000, 0: 18000})
10
***************************************

  • 第二步: 分析样本分布
total = 0
for i, v in count.items():
    total += v

print(total)

for i, v in count.items():
    print(i, v / total * 100, '%')

print('***************************************')

content['sentence_len'] = content['sentence'].apply(len)

print(content.head(10))

length_mean = np.mean(content['sentence_len'])
length_std = np.std(content['sentence_len'])
print('length_mean = ', length_mean)
print('length_std = ', length_std)

  • 输出结果:
180000
3 10.0 %
4 10.0 %
1 10.0 %
7 10.0 %
5 10.0 %
9 10.0 %
8 10.0 %
2 10.0 %
6 10.0 %
0 10.0 %
***************************************
                    sentence  label  sentence_len
0         中华女子学院:本科层次仅1专业招男生      3            18
1     两天价网站背后重重迷雾:做个网站究竟要多少钱      4            22
2  东5环海棠公社230-290平2居准现房98折优惠      1            25
3  卡佩罗:告诉你德国脚生猛的原因 不希望英德战踢点球      7            25
4    82岁老太为学生做饭扫地44年获授港大荣誉院士      5            23
5       记者回访地震中可乐男孩:将受邀赴美国参观      5            20
6          冯德伦徐若�隔空传情 默认其是女友      9            17
7     传郭晶晶欲落户香港战伦敦奥运 装修别墅当婚房      1            22
8           《赤壁OL》攻城战诸侯战硝烟又起      8            16
9                “手机钱包”亮相科博会      4            11

length_mean =  19.21257222222222
length_std =  3.863787253359747

  • 第三步: 进行分词预处理.
def cut_sentence(s):
    return list(jieba.cut(s))

content['words'] = content['sentence'].apply(cut_sentence)

print(content.head(10))

content['words'] = content['sentence'].apply(lambda s: ' '.join(cut_sentence(s)))


content['words'] = content['words'].apply(lambda s: ' '.join(s.split())[:30])

content.to_csv('./data/data/train_new.csv')

  • 输出结果:
Building prefix dict from the default dictionary ...
Dumping model to file cache /tmp/jieba.cache
Loading model cost 0.908 seconds.
Prefix dict has been built successfully.
                    sentence  label  sentence_len                                              words
0         中华女子学院:本科层次仅1专业招男生      3            18           [中华, 女子, 学院, :, 本科, 层次, 仅, 1, 专业, 招, 男生]
1     两天价网站背后重重迷雾:做个网站究竟要多少钱      4            22   [两天, 价, 网站, 背后, 重重, 迷雾, :, 做个, 网站, 究竟, 要, 多少, 钱]
2  东5环海棠公社230-290平2居准现房98折优惠      1            25  [东, 5, 环, 海棠, 公社, 230, -, 290, 平, 2, 居, 准现房, 9...
3  卡佩罗:告诉你德国脚生猛的原因 不希望英德战踢点球      7            25  [卡佩罗, :, 告诉, 你, 德国, 脚, 生猛, 的, 原因,  , 不, 希望, 英德...
4    82岁老太为学生做饭扫地44年获授港大荣誉院士      5            23  [82, 岁, 老太, 为, 学生, 做饭, 扫地, 44, 年, 获授, 港大, 荣誉, 院士]
5       记者回访地震中可乐男孩:将受邀赴美国参观      5            20         [记者, 回访, 地震, 中, 可乐, 男孩, :, 将, 受邀, 赴美国, 参观]
6          冯德伦徐若�隔空传情 默认其是女友      9            17                [冯德伦, 徐若, �, 隔空, 传情,  , 默认, 其是, 女友]
7     传郭晶晶欲落户香港战伦敦奥运 装修别墅当婚房      1            22   [传, 郭晶晶, 欲, 落户, 香港, 战, 伦敦, 奥运,  , 装修, 别墅, 当婚, 房]
8           《赤壁OL》攻城战诸侯战硝烟又起      8            16               [《, 赤壁, OL, 》, 攻城战, 诸侯, 战, 硝烟, 又, 起]
9                “手机钱包”亮相科博会      4            11                            [“, 手机, 钱包, ”, 亮相, 科博会]

  • 第四步: 依次同样的代码处理验证集dev.txt, 测试集test.txt, 同一个文件夹下生成dev_new.csv, test_new.csv文件.

随机森林模型

  • 编写代码实现随机森林的模型训练.
    • 代码位置: /home/ec2-user/toutiao/baseline/random_forest/random_forest_baseline1.py

from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
import pandas as pd
from icecream import ic
from sklearn.metrics import accuracy_score
from sklearn.metrics import recall_score
from sklearn.metrics import precision_score
from sklearn.metrics import f1_score

TRAIN_CORPUS = './data/data/train_new.csv'
STOP_WORDS = './data/data/stopwords.txt'
WORDS_COLUMN = 'words'

content = pd.read_csv(TRAIN_CORPUS)
corpus = content[WORDS_COLUMN].values


stop_words_size = 749
WORDS_LONG_TAIL_BEGIN = 10000
WORDS_SIZE = WORDS_LONG_TAIL_BEGIN - stop_words_size

stop_words = open(STOP_WORDS).read().split()[:stop_words_size]

tfidf = TfidfVectorizer(max_features=WORDS_SIZE, stop_words=stop_words)
text_vectors = tfidf.fit_transform(corpus)
print(text_vectors.shape)

targets = content['label']

x_train, x_test, y_train, y_test = train_test_split(text_vectors, targets, test_size=0.2, random_state=0)

print('数据分割完毕, 开始模型训练...')
model = RandomForestClassifier()
model.fit(x_train, y_train)

print('模型训练结束, 开始预测...')
accuracy = accuracy_score(model.predict(x_test), y_test)
ic(accuracy)

  • 调用:
python random_forest_baseline1.py

  • 输出结果:
(180000, 9251)
数据分割完毕, 开始模型训练...
模型训练结束, 开始预测...
ic| accuracy: 0.7989444444444445

  • 结论: 随机森林构建模型简单, 训练快, 最终79.89%的准确率(可以视作80%)对于10分类任务来说也是不错的模型. 重要的是我们快速拥有了一个准确率达到80%的基线模型1.0


FastText的快速基线模型2.0

数据准备

  • 首先明确fasttext所要求的数据格式:
    • 文本: 正常的连续字符串即可.
    • 标签: 采用__label__name的格式.

  • 代码位置: /home/ec2-user/toutiao/baseline/fast_text/data/data/preprocess.py
import os
import sys
import jieba


id_to_label = {}

idx = 0
with open('class.txt', 'r', encoding='utf-8') as f1:
    for line in f1.readlines():
        line = line.strip('\n').strip()
        id_to_label[idx] = line
        idx += 1

print('id_to_label:', id_to_label)

count = 0
train_data = []
with open('train.txt', 'r', encoding='utf-8') as f2:
    for line in f2.readlines():
        line = line.strip('\n').strip()
        sentence, label = line.split('\t')

        # 1: 首先处理标签部分
        label_id = int(label)
        label_name = id_to_label[label_id]
        new_label = '__label__' + label_name

        # 2: 然后处理文本部分, 为了便于后续增加n-gram特性, 可以按字划分, 也可以按词划分
        sent_char = ' '.join(list(sentence))

        # 3: 将文本和标签组合成fasttext规定的格式
        new_sentence = new_label + ' ' + sent_char
        train_data.append(new_sentence)

        count += 1
        if count % 10000 == 0:
            print('count=', count)


with open('train_fast.txt', 'w', encoding='utf-8') as f3:
    for data in train_data:
        f3.write(data + '\n')

print('FastText训练数据预处理完毕!')

  • 调用:
python preprocess.py

  • 输出结果: 查看train_fast.txt文件如下
__label__education 中 华 女 子 学 院 : 本 科 层 次 仅 1 专 业 招 男 生
__label__science 两 天 价 网 站 背 后 重 重 迷 雾 : 做 个 网 站 究 竟 要 多 少 钱
__label__realty 东 5 环 海 棠 公 社 2 3 0 - 2 9 0 平 2 居 准 现 房 9 8 折 优 惠
__label__sports 卡 佩 罗 : 告 诉 你 德 国 脚 生 猛 的 原 因   不 希 望 英 德 战 踢 点 球
__label__society 8 2 岁 老 太 为 学 生 做 饭 扫 地 4 4 年 获 授 港 大 荣 誉 院 士
__label__society 记 者 回 访 地 震 中 可 乐 男 孩 : 将 受 邀 赴 美 国 参 观
__label__entertainment 冯 德 伦 徐 若 � 隔 空 传 情   默 认 其 是 女 友
__label__realty 传 郭 晶 晶 欲 落 户 香 港 战 伦 敦 奥 运   装 修 别 墅 当 婚 房
__label__game 《 赤 壁 O L 》 攻 城 战 诸 侯 战 硝 烟 又 起
__label__science “ 手 机 钱 包 ” 亮 相 科 博 会
__label__education 上 海 2 0 1 0 上 半 年 四 六 级 考 试 报 名 4 月 8 日 前 完 成
__label__sports 李 永 波 称 李 宗 伟 难 阻 林 丹 取 胜   透 露 谢 杏 芳 有 望 出 战
__label__society 3 岁 女 童 下 体 红 肿   自 称 被 幼 儿 园 老 师 用 尺 子 捅 伤
__label__stocks 金 证 顾 问 : 过 山 车 行 情 意 味 着 什 么
__label__realty 谁 料 地 王 如 此 虚
__label__game 《 光 环 5 》 L o g o 泄 露   K i n e c t 版 几 无 悬 念
__label__realty 海 淀 区 领 秀 新 硅 谷 宽 景 大 宅 预 计 1 0 月 底 开 盘
__label__realty 柴 志 坤 : 土 地 供 应 量 不 断 从 紧   地 价 难 现 0 7 水 平 ( 图 )
__label__game 伊 达 传 说 E D D A   O n l i n e
__label__science 三 联 书 店 建 起 书 香 巷
__label__science 宇 航 员 尿 液 堵 塞 国 际 空 间 站 水 循 环 系 统
__label__politics 研 究 发 现 开 车 技 术 差 或 与 基 因 相 关
__label__sports 皇 马 输 球 替 补 席 闹 丑 闻   队 副 女 球 迷 公 然 调 情 ( 视 频 )
__label__realty 北 京 建 工 与 市 政 府 再 度 合 作 推 出 郭 庄 子 限 价 房
__label__entertainment 组 图 : 李 欣 汝 素 颜 出 镜 拍 低 碳 环 保 大 片

  • 同上处理测试集数据, 得到test_fast.txt; 同上处理验证集的数据, 得到dev_fast.txt

模型搭建

  • 代码位置: /home/ec2-user/toutiao/baseline/fast_text/fast_text_baseline2.py
import fasttext

train_data_path = './data/data/train_fast.txt'
test_data_path = './data/data/test_fast.txt'

# 开启模型训练
model = fasttext.train_supervised(input=train_data_path, wordNgrams=2)

# 开启模型测试
result = model.test(test_data_path)
print(result)

  • 调用:
python fast_text_baseline2.py

  • 输出结果:
Read 3M words
Number of words:  4760
Number of labels: 10
Progress: 100.0% words/sec/thread: 1267929 lr:  0.000000 avg.loss:  0.279528 ETA:   0h 0m 0s
(10000, 0.9162, 0.9162)

  • 结论: 在10000条测试集上, 我们的模型得到了0.9162的精确率, 0.9162的召回率. 相比较随机森林已经有了大幅度的提升.

模型优化

  • 对于任意表现良好的模型, 优化的脚步都不能停止!

优化fasttest第一版

  • 在真实的生产环境下, 对于fasttext模型一般不会采用费时费力的人工调参, 而都是用自动化最优参数搜索的模式.
    • 代码位置: /home/ec2-user/toutiao/baseline/fast_text/fast_text_baseline2.py

import fasttext
import time

train_data_path = './data/data/train_fast.txt'
dev_data_path = './data/data/dev_fast.txt'
test_data_path = './data/data/test_fast.txt'

# autotuneValidationFile参数需要指定验证数据集所在路径,
# 它将在验证集上使用随机搜索方法寻找可能最优的超参数.
# 使用autotuneDuration参数可以控制随机搜索的时间, 默认是300s,
# 根据不同的需求, 我们可以延长或缩短时间.
# verbose: 该参数决定日志打印级别, 当设置为3, 可以将当前正在尝试的超参数打印出来.
model = fasttext.train_supervised(input=train_data_path,
                                  autotuneValidationFile=dev_data_path,
                                  autotuneDuration=600,
                                  wordNgrams=2,
                                  verbose=3)

# 在测试集上评估模型的表现
result = model.test(test_data_path)
print(result)

# 模型保存
time1 = int(time.time())
model_save_path = "./toutiao_fasttext_{}.bin".format(time1)
model.save_model(model_save_path)

  • 调用:
python fast_text_baseline2.py

  • 输出结果:
Trial = 1
epoch = 5
lr = 0.1
dim = 100
minCount = 1
wordNgrams = 2
minn = 0
maxn = 0
bucket = 2000000
dsub = 2
loss = softmax
Progress:   0.5% Trials:    1 Best score:   unknown ETA:   0h 9m56scurrentScore = 0.9119
train took = 3.20856
Trial = 2
epoch = 2
lr = 0.169298
dim = 105
minCount = 1
wordNgrams = 2
minn = 0
maxn = 0
bucket = 10000000
dsub = 16
loss = softmax
Progress:   1.4% Trials:    2 Best score:  0.911900 ETA:   0h 9m51scurrentScore = 0.906
train took = 5.66037
Trial = 3
epoch = 1
lr = 0.463758
dim = 52
minCount = 1
wordNgrams = 2
minn = 0
maxn = 0
bucket = 1036295
dsub = 2
loss = softmax
Progress:   1.6% Trials:    3 Best score:  0.911900 ETA:   0h 9m50scurrentScore = 0.9053


......
......
......


train took = 102.365
Trial = 18
epoch = 29
lr = 0.100404
dim = 318
minCount = 1
wordNgrams = 2
minn = 0
maxn = 0
bucket = 2932604
dsub = 16
loss = softmax
Progress:  94.0% Trials:   18 Best score:  0.913600 ETA:   0h 0m36scurrentScore = 0.9123
train took = 29.9363
Trial = 19
epoch = 61
lr = 0.230535
dim = 364
minCount = 1
wordNgrams = 2
minn = 0
maxn = 0
bucket = 3220875
dsub = 8
loss = softmax
Progress: 100.0% Trials:   19 Best score:  0.913600 ETA:   0h 0m 0s
Training again with best arguments
Best selected args = 0
epoch = 100
lr = 0.173311
dim = 355
minCount = 1
wordNgrams = 2
minn = 0
maxn = 0
bucket = 5091406
dsub = 16
loss = softmax
Read 3M words
Number of words:  4760
Number of labels: 10
Progress: 100.0% words/sec/thread:  571851 lr:  0.000000 avg.loss:  0.016739 ETA:   0h 0m 0s
(10000, 0.9173, 0.9173)

  • 查看模型:
# 命令行直接ll可以查看保存后的模型详情
# 可以看到保存后的模型大小为4.95GB
# 说明fasttext虽然效果好, 速度快, 但是占用很大存储空间, 比BERT大得多!

-rw-rw-r-- 1 ec2-user ec2-user 4949204992 1月 9 02:25 toutiao_fasttext_1640744707.bin

  • 结论: 经过参数的自动搜索, 得到了最好的一版模型, 主要参数包括词嵌入维度dim=355, wordNgrams=2等. 模型的最终表现精准率等于91.73%, 召回率也是91.73%, 相比较最初的91.62%有稍许提升但并不显著.

优化fasttext第二版

  • 模型的优化不仅仅在架构上, 更要注意回溯到源头, 也就是数据端的优化.
    • 第一步: 原始数据采用词向量级别.
    • 第二步: 重新训练模型并评估.

  • 第一步: 原始数据采用词向量级别.
    • 代码位置: /home/ec2-user/toutiao/baseline/fast_text/data/data/preprocess1.py

import os
import sys
import jieba


id_to_label = {}

idx = 0
with open('class.txt', 'r', encoding='utf-8') as f1:
    for line in f1.readlines():
        line = line.strip('\n').strip()
        id_to_label[idx] = line
        idx += 1

# print('id_to_label:', id_to_label)

count = 0
train_data = []
with open('train.txt', 'r', encoding='utf-8') as f2:
    for line in f2.readlines():
        line = line.strip('\n').strip()
        sentence, label = line.split('\t')

        # 1: 首先处理标签部分
        label_id = int(label)
        label_name = id_to_label[label_id]
        new_label = '__label__' + label_name

        # 2: 然后处理文本部分, 区别于之前的按字划分, 此处按词划分文本
        sent_char = ' '.join(jieba.lcut(sentence))

        # 3: 将文本和标签组合成fasttext规定的格式
        new_sentence = new_label + '\t' + sent_char
        train_data.append(new_sentence)

        count += 1
        if count % 10000 == 0:
            print('count=', count)


with open('train_fast1.txt', 'w', encoding='utf-8') as f3:
    for data in train_data:
        f3.write(data + '\n')

print('FastText训练数据预处理完毕!')

  • 调用:
python preprocess1.py

  • 输出结果(查看train_fast1.txt文件):
__label__education      中华 女子 学院 : 本科 层次 仅 1 专业 招 男生
__label__science        两天 价 网站 背后 重重 迷雾 : 做个 网站 究竟 要 多少 钱
__label__realty 东 5 环 海棠 公社 230 - 290 平 2 居 准现房 98 折 优惠
__label__sports 卡佩罗 : 告诉 你 德国 脚 生猛 的 原因   不 希望 英德 战 踢 点球
__label__society        82 岁 老太 为 学生 做饭 扫地 44 年 获授 港大 荣誉 院士
__label__society        记者 回访 地震 中 可乐 男孩 : 将 受邀 赴美国 参观
__label__entertainment  冯德伦 徐若 � 隔空 传情   默认 其是 女友
__label__realty 传 郭晶晶 欲 落户 香港 战 伦敦 奥运   装修 别墅 当婚 房
__label__game   《 赤壁 OL 》 攻城战 诸侯 战 硝烟 又 起
__label__science        “ 手机 钱包 ” 亮相 科博会
__label__education      上海 2010 上半年 四六级 考试 报名 4 月 8 日前 完成
__label__sports 李永波 称 李宗伟 难 阻林丹 取胜   透露 谢杏芳 有望 出战
__label__society        3 岁 女童 下体 红肿   自称 被 幼儿园 老师 用 尺子 捅 伤
__label__stocks 金证 顾问 : 过山车 行情 意味着 什么
__label__realty 谁料 地 王 如此 虚
__label__game   《 光环 5 》 Logo 泄露   Kinect 版几无 悬念
__label__realty 海淀区 领秀新 硅谷 宽景 大宅 预计 10 月底 开盘
__label__realty 柴志坤 : 土地 供应量 不断 从 紧   地价 难现 07 水平 ( 图 )
__label__game   伊达 传说 EDDA   Online
__label__science        三联书店 建起 书香 巷
__label__science        宇航员 尿液 堵塞 国际 空间站 水 循环系统
__label__politics       研究 发现 开车 技术 差 或 与 基因 相关
__label__sports 皇马 输球 替补席 闹 丑闻   队 副 女球迷 公然 调情 ( 视频 )
__label__realty 北京 建工 与 市政府 再度 合作 推出 郭 庄子 限价 房
__label__entertainment  组图 : 李欣汝素 颜 出镜 拍低 碳 环保 大片

  • 测试集同样的方法进行处理, 得到结果文件test_fast1.txt; 验证集同样的方法进行处理, 得到结果文件dev_fast1.txt

  • 模型训练, 代码位置: /home/ec2-user/toutiao/baseline/fast_text/fast_text_baseline3.py
import fasttext
import time

train_data_path = './data/data/train_fast1.txt'
dev_data_path = './data/data/dev_fast1.txt'
test_data_path = './data/data/test_fast1.txt'

# autotuneValidationFile参数需要指定验证数据集所在路径,
# 它将在验证集上使用随机搜索方法寻找可能最优的超参数.
# 使用autotuneDuration参数可以控制随机搜索的时间, 默认是300s,
# 根据不同的需求, 我们可以延长或缩短时间.
# verbose: 该参数决定日志打印级别, 当设置为3, 可以将当前正在尝试的超参数打印出来.
model = fasttext.train_supervised(input=train_data_path,
                                  autotuneValidationFile=dev_data_path,
                                  autotuneDuration=600,
                                  wordNgrams=2,
                                  verbose=3)

# 在测试集上评估模型的表现
result = model.test(test_data_path)
print(result)

# 模型保存
time1 = int(time.time())
model_save_path = "./toutiao_fasttext_{}.bin".format(time1)
model.save_model(model_save_path)

  • 调用:
python fast_text_baseline3.py

  • 输出结果:
al = 1
epoch = 5
lr = 0.1
dim = 100
minCount = 1
wordNgrams = 2
minn = 0
maxn = 0
bucket = 2000000
dsub = 2
loss = softmax
Progress:   0.5% Trials:    1 Best score:   unknown ETA:   0h 9m56scurrentScore = 0.9009
train took = 3.00675
Trial = 2
epoch = 2
lr = 0.169298
dim = 105
minCount = 1
wordNgrams = 2
minn = 0
maxn = 0
bucket = 10000000
dsub = 16
loss = softmax
Progress:   1.4% Trials:    2 Best score:  0.900900 ETA:   0h 9m51scurrentScore = 0.9003
train took = 5.71447
Trial = 3
epoch = 1
lr = 0.463758
dim = 52
minCount = 1
wordNgrams = 2
minn = 0
maxn = 0
bucket = 1036295
dsub = 2
loss = softmax
Progress:   1.7% Trials:    3 Best score:  0.900900 ETA:   0h 9m49scurrentScore = 0.897


......
......
......


train took = 59.9728
Trial = 34
epoch = 52
lr = 0.0350906
dim = 57
minCount = 1
wordNgrams = 2
minn = 3
maxn = 6
bucket = 191750
dsub = 2
loss = softmax
Progress:  96.0% Trials:   34 Best score:  0.912800 ETA:   0h 0m24scurrentScore = 0.9066
train took = 19.7419
Trial = 35
epoch = 100
lr = 0.0425606
dim = 71
minCount = 1
wordNgrams = 2
minn = 2
maxn = 5
bucket = 152421
dsub = 2
loss = softmax
Progress: 100.0% Trials:   35 Best score:  0.912800 ETA:   0h 0m 0s
Training again with best arguments
Best selected args = 0
epoch = 11
lr = 0.0573768
dim = 64
minCount = 1
wordNgrams = 2
minn = 2
maxn = 5
bucket = 255766
dsub = 2
loss = softmax
Read 2M words
Number of words:  118456
Number of labels: 10
Progress: 100.0% words/sec/thread:  616381 lr:  0.000000 avg.loss:  0.296281 ETA:   0h 0m 0s
(10000, 0.9193, 0.9193)

  • 查看模型:
# 命令行直接ll可以查看保存后的模型详情
# 可以看到保存后的模型大小为98MB, 相比于第一个模型小了太多, 同时效果反倒提升了!
# 参考与第一版优化中dim=355, 模型4.95GB, 此处最关键的参数dim=64, 是模型大幅度缩小的最重要原因.

-rw-rw-r-- 1 ec2-user ec2-user 97828230 1月 9 02:42 toutiao_fasttext_1640745760.bin

  • 结论: 采用词为单位的模型效果又有一次提升, 精准率和召回率都达到了91.93%, 相比于初始的91.62%和第一版优化的91.73%又有稍许提升, 但效果依然不显著. 同时我们注意到, fasttext模型可大可小, 存储空间的占用范围相差极大!

模型部署

  • 工业界中的AI是指"能落地的AI", 即指在生产环境中可以部署并提供在线, 或离线作业的模型.
    • 第一步: 编写主服务逻辑代码.
    • 第二步: 启动Flask服务.
    • 第三步: 编写测试代码.
    • 第四步: 执行测试并检验结果.

  • 第一步: 编写主服务逻辑代码.
    • 代码位置: /home/ec2-user/toutiao/baseline/fast_text/app.py
import time
import jieba
import fasttext

# 服务框架使用Flask, 导入工具包
from flask import Flask
from flask import request
app = Flask(__name__)

# 导入发送http请求的requests工具
import requests

# 加载自定义的停用词字典
jieba.load_userdict('./data/data/stopwords.txt')

# 提供已训练好的模型路径+名字
model_save_path = 'toutiao_fasttext_1640745760.bin'

# 实例化fasttext对象, 并加载模型参数用于推断, 提供服务请求
model = fasttext.load_model(model_save_path)
print('FastText模型实例化完毕...')

# 设定投满分服务的路由和请求方法
@app.route('/v1/main_server/', methods=["POST"])
def main_server():
    # 接收来自请求方发送的服务字段
    uid = request.form['uid']
    text = request.form['text']

    # 对请求文本进行处理, 因为前面加载的是基于词的模型, 所以这里用jieba进行分词
    input_text = ' '.join(jieba.lcut(text))

    # 执行预测
    res = model.predict(input_text)
    predict_name = res[0][0]

    return predict_name

  • 第二步: 启动Flask服务.
cd /home/ec2-user/toutiao/baseline/fast_text/

gunicorn -w 1 -b 0.0.0.0:5000 app:app

  • 输出结果:
[2022-1-10 07:42:28 +0000] [24922] [INFO] Starting gunicorn 20.0.4
[2022-1-10 07:42:28 +0000] [24922] [INFO] Listening at: http://0.0.0.0:5000 (24922)
[2022-1-10 07:42:28 +0000] [24922] [INFO] Using worker: sync
[2022-1-10 07:42:28 +0000] [24928] [INFO] Booting worker with pid: 24928
Building prefix dict from the default dictionary ...
Loading model from cache /tmp/jieba.cache
Loading model cost 0.744 seconds.
Prefix dict has been built successfully.
FastText模型实例化完毕...

  • 第三步: 编写测试代码.
    • 代码位置: /home/ec2-user/toutiao/baseline/fast_text/test.py
import requests
import time

# 定义请求url和传入的data
url = "http://0.0.0.0:5000/v1/main_server/"
data = {"uid": "AI-6-202104", "text": "公共英语(PETS)写作中常见的逻辑词汇汇总"}

start_time = time.time()
# 向服务发送post请求
res = requests.post(url, data=data)

cost_time = time.time() - start_time

# 打印返回的结果
print('输入文本:', data['text'])
print('分类结果:', res.text)
print('单条样本预测耗时: ', cost_time * 1000, 'ms')

  • 第四步: 执行测试并检验结果.
cd /home/ec2-user/toutiao/baseline/fast_text/

python test.py

  • 输出结果:
输入文本: 公共英语(PETS)写作中常见的逻辑词汇汇总
分类结果: __label__education
单条样本预测耗时:  4.739046096801758 ms

  • 结论: 预测结果非常准确, 同时更重要的是预测时间仅仅不到5ms!!! 这是工业界场景下fasttext工具最大的意义!!!