零、引注：本篇仅记录我一次构建NLP情感向量模型的经历，并非技术教程，如有错漏欢迎指出。毕设脑子一抽，设计了个巨复杂的系统，简单来说就是，构建一个以微服务为基础，Nacos作为注册中心，Thrift作为RPC框架，采用Laravel、Vue的全分离式前后端集群，具有CDN与对象存储文件服务的网络优化，使用Redis、MySQL、MongoDB集群，具有数据抓取与清洗服务，核心算法采用LSTM与BERT等NLP学习的综合网络股票信息平台。好吧，其实我自己也不是很理解为什么我做了这么个玩意儿，本来是纯粹想着秀技，结果秀着秀着把自己秀进去了，虽然工作已经稳了，其他事情也基本没了，但是这么个玩意儿说实话在俩月内写完也确实不太现实emm。不过好在，至少在中期答辩之前把整体框子搭出来了，也顺便炼了一枚小丹（其实是两枚），所以在此简单记录一下炼丹的过程，由于我本人钻研的是后端，所以对于机器学习并不甚了解，所以只懂得浅薄道理，如果有错漏欢迎大家指正。至于我毕设系统的其他部分，由于是个天坑，所以博客文章这边准备之后再慢慢填（当然也有可能彻底鸽掉）一、环境搭建首先当然是对算法的选择，因为是对网络股评进行分析，所以肯定是NLP相关的算法。我在上一家公司的时候做过医疗方向上的NLP系统，当时用的是BERT模型进行的病历标注，所以这次我一开始想的是用BERT先做一次词性标注，然后再聚类成不同维度，根据维度数据构建一个股价相关回归模型，简单尝试了一下，发现可供训练的数据集特别少，而且实在是太麻烦了，一两天内完成属实不太现实，于是就直接做情感分析模型了。翻了几篇论文，最后决定利用分词+词向量+LSTM的方式构建情感分析模型。分词就不用说了，自己练太费劲，直接用jieba，词向量也好办，word2vec方便的很，最后就是LSTM网络的构建，我选择的是直接用TensorFlow和Keras构建神经网络，方便，快捷，主要是不需要动脑（既然选择了tf，那就先进行一个环境的搭建。python自不必说，由于我电脑不知道重装过多少次了，需要先装一下轮子。TensorFlow在高版本上直接默认的就是GPU版本，不像以前，要安装tensorflow-gpu，现在直接安装tensorflow就可以了。其他的都还好说，最坑的其实是word2vec，这个需要源码编译一下，所以需要装gcc。因为我一直用的都是CLion+cygwin，所以自然gcc没什么问题，本来我是这么想的。结果我给忘了我上次重装完系统就只装了Visual Studio，没装cygwin，我还研究了半天我gcc哪去了，后来才想起来没装，属于是降智了。requirements.txt如下numpy matplotlib pandas jieba Cython word2vec tensorflow gensim scikit-learn python-dotenv requests keras Flask BeautifulSoup4 html5libpython依赖装好之后，简单整一下cuda，其实这块TensorFlow官网GPU支持文档已经非常详细了，按着一步一步走就行了。首先是GPU驱动，CUDA 11.2要求驱动在450.80.02以上版本，这对于我一个常年保持最新驱动的人来说那肯定是没什么问题，不过我的不是studio驱动，是game驱动，不过为了跑个模型就换成studio我觉得不值当，就没动，采用的是512.59版本。然后去英伟达官网下载一下CUDA工具包，因为工具包是附带CUPTI的所以不需要额外考虑，我下载的版本是11.6.2的最新版。最后是安装cuDNN，这个安装起来稍微麻烦一点，下载归档之后将bin，include，lib文件夹里的全部文件放到CUDA安装路径下对应的文件夹里就行，需要注意对应的版本。最后还可以装一下TensorRT，我嫌麻烦就没装。安装完之后用命令行工具检查一下情况。nvidia-smi二、数据集构建好了学习环境，我简单找了一下数据集，在GitHub上面找到了一个中文NLP的训练集收集的仓库，因为时间紧任务重，就直接拿来用了。其实一开始我下载的是清华的语料库，下载下来发现只有分类标注，就放弃了，后来选择了两个微博的情感向量标注数据集。因为这方面训练用的数据结构比较简单，所以数据集还算工整。用panda简单处理一下就可以直接用了，当然我没做数据清洗，懒了。数据集有了之后，用jieba简单做一下分词，就可以进行网络的构建了。（其实还应该清洗一下数据的，但是实在是来不及了）# 引入轮子 import jieba import matplotlib.pyplot as plt import numpy as np import pandas as pd from gensim.models.word2vec import Word2Vec from sklearn.model_selection import train_test_split from keras.models import Sequential from keras.layers import Dense, LSTM, Embedding # panda加载数据 df = pd.read_csv('data/weibo_senti_100k.csv') # 利用plot绘制数据集分布 df.label.value_counts().plot(kind='pie', autopct='%0.05f%%', labels=['negative', 'positive'], colors=['#f48fb1', '#ccff90']) plt.savefig("out/data.png") plt.show() plt.clf() # 对数据集进行jieba分词 df = df.sample(frac=1) word_cut = lambda x: jieba.lcut(x) df['words'] = df["review"].apply(word_cut) x = df["words"]三、浅层网络构建数据集准备好了之后，先利用word2vec简单构建一下浅层网络，利用训练集先构建一个简单的词向量模型，将词语转换为词向量方便后面训练。# word2vec模型 w2v = Word2Vec(vector_size=300,min_count=10) w2v.build_vocab(x) w2v.train(x, total_examples=w2v.corpus_count, epochs=20) # 保存模型 w2v.save('model/w2v_model.pkl') # 将文本转化为向量的方法 def average_vec(text): vec = np.zeros(300).reshape((1, 300)) for word in text: try: vec += w2v.wv[word].reshape((1, 300)) except KeyError: continue return vec # 将词向量保存为 Ndarray x_vec = np.concatenate([average_vec(z) for z in x]) y = pd.get_dummies(df['label']).values完成了word2vec模型训练并获取了词向量后，利用sklearn构建训练集，训练集80%，测试集20%。X_train, X_test, y_train, y_test = train_test_split(x_vec, y, test_size=0.2)四、LSTM网络构建通过Keras快速构建一个简单的LSTM网络模型model = Sequential() model.add(Embedding(100000, 100)) model.add(LSTM(100, dropout=0.2, recurrent_dropout=0.2)) model.add(Dense(2, activation='softmax')) model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy']) model.summary()五、模型训练与保存现在，我们对上面的模型利用构建好的测试集进行一个丹的炼，然后把损失函数和准确率绘图。这里我训练次数epochs选择40次，批次大小128，这个批次大小正好吃掉我的10G显存，整体训练下来耗时大概需要10小时左右。# 训练参数 epochs = 40 batch_size = 128 # 模型训练 history = model.fit(X_train, y_train, epochs=epochs, batch_size=batch_size, validation_split=0.2) history_dict = history.history history_dict.keys() #利用plot绘制损失与准确率 acc = history_dict['accuracy'] val_acc = history_dict['val_accuracy'] loss = history_dict['loss'] val_loss = history_dict['val_loss'] epochs = range(1, len(acc) + 1) plt.plot(epochs, loss, 'bo', label='Training loss') plt.plot(epochs, val_loss, 'b', label='Validation loss') plt.title('Training and validation loss') plt.xlabel('Epochs') plt.ylabel('Loss') plt.legend() plt.savefig("out/loss.png") plt.show() plt.clf() plt.plot(epochs, acc, 'bo', label='Training acc') plt.plot(epochs, val_acc, 'b', label='Validation acc') plt.title('Training and validation accuracy') plt.xlabel('Epochs') plt.ylabel('Accuracy') plt.savefig("out/accuracy.png") plt.legend() plt.show() # 进行一个模型的保存 model.save("model/svm_model")六、验证结果与测试通过上面的训练后，最终得出了一个acc 0.88的模型，还算理想，毕竟是在答辩前赶出来的，也不能奢望什么。然后简单写一下测试方法，对模型进行一个简单的测试import jieba import numpy as np import keras.models from gensim.models.word2vec import Word2Vec def average_vec(words): w2v = Word2Vec.load('model/w2v_model.pkl') vec = np.zeros(300).reshape((1, 300)) for word in words: try: vec += w2v.wv[word].reshape((1, 300)) except KeyError: continue return vec def model_predict(string): words = jieba.lcut(str(string)) words_vec = average_vec(words) keras.models.logging.set_verbosity(keras.models.logging.ERROR) model = keras.models.load_model("model/svm_model") result = np.argmax(model.predict(words_vec)) if int(result) == 1: return "正向" else: return "负向" while True: text = input("input> ") res = model_predict(text) print(text + " | " + res) 总体上看，准确率其实一般，因为训练集并不是专业的金融数据，有太多奇怪的数据在里面。只能说，凑合用。七、模型的使用最后，利用Flask构建一个简单的HTTP API服务，这部分具体的代码我已经放到我的Git上了，感兴趣可以自行查看，我这里只放一下Postman的测试了。最后与其他服务进行一个联调，带有环境的界面大概是这个样子八、结语其实整个项目现在都是赶鸭子上架的状态，写的很烂，所以就这样吧。本毕业设计项目源代码仓库地址：UtopiaXC's GitLab - UtopiaXC Graduation Project本模型仓库：UtopiaXC's GitLab - Stock Model Service 九、参考与感谢看了很多篇论文，就不放在这了，以后会写在毕业论文的参考文献里面，至于代码，因为大量参考了别人的代码，所以这里放出来源基于LSTM的电商评论情感分析-TensorFlow2实现（内附源码）【自然语言处理NLP-100例】 2022-05-03 13:05 UtopiaXC 于大连