之前搞了很久的深度模型,看bert相关论文后感慨深度学习不单要有足够的理论知识(数学数学数学),也要有足够的资源(tpu、数据集、财力计算力)和足够的科学想象力(双向transfermer加mask就真的能搞定上下文信息?什么?位置?加个位置向量加成不就好了?),不禁为我这个通信半路出家的人感到凄凉。
相比之下其实许多亲民的基本算法模型已经能提供足够的精确度,而且在某些程度上机器学习算法的可解释性会更佳。
今天总结一下,当做是复习,并利用编程实现。
简单的都运行一遍比较一下效果
训练原料:六万多条电商评论,分为正负极性,平衡语料 ,利用64维训练好的word2vec映射词向量模型(1.4个g,当时训练了几天,虽然不久就会被bert模型代替了)
训练框架及环境:tensorflow-gpu 1.3 keras 2.0 sklearn gpu1080ti(亲测i5cpu笔记本也可以跑,但是得大幅减少数据量,除非内存很多很多,其次就是慢,指用tf、keras的cpu版)
必要的步骤,去停用词,设置timestep等(句子长度,我这里设词向量维度为维度)
至于数据预处理就比较繁杂,在这里就不说了。我一般习惯把不同极性分开存放便于提取,有人则喜欢放一起用正则式提取,但是对我而言代码永远是实现目标的工具,当然越少越好。
VECTOR_DIR = 'embedding_64.bin' # 词向量模型文件,同目录下
model = gensim.models.KeyedVectors.load_word2vec_format(VECTOR_DIR, binary=True)
def rep_sentencevector(sentence):
word_list = [word for word in sentence.split(' ')]
embedding_dim = 64
embedding_matrix = np.zeros(embedding_dim)
for index, word in enumerate(word_list):
try:
embedding_matrix += model[word]
except:
pass
return embedding_matrix/len(word_list)
def build_traindata():
X_train = list()
Y_train = list()
X_test = list()
Y_test = list()
for line in open('./data/train.txt',encoding="UTF-8"):
line = line.strip().strip().split('\t')
sent_vector = rep_sentencevector(line[-1])
X_train.append(sent_vector)
if line[0] == '1':
Y_train.append(1)
else:
Y_train.append(0)
for line in open('./data/test.txt',encoding="UTF-8"):
line = line.strip().strip().split('\t')
sent_vector = rep_sentencevector(line[-1])
X_test.append(sent_vector)
if line[0] == '1':
Y_test.append(1)
else:
Y_test.append(0)
return np.array(X_train), np.array(Y_train), np.array(X_test), np.array(Y_test)
由此构建好了数据集划分
首先是
逻辑回归,本质就是在线性回归的基础上加入了激活函数,使得输出可以用类似概率的形式输出来判定类别,而线性回归里的最小二乘法基本上可以说是机器学习中的经典。利用sklearn包倒入轻松实现,这里利用sklearn的acc评价函数来查看训练时候的概率值
def train_LogisticRegression(X_train, Y_train, X_test, Y_test):
model = LogisticRegression()
model.fit(X_train, Y_train)
joblib.dump(model, './model/LogisticRegression_model.m')
acc = accuracy_score(Y_test,model.predict(X_test))
print("lr精确度%f"%acc)
sklearn真的是开源界的暖男,api丰富,说明清晰,与keras都是我的心头好(说白了就是代码能力差的救星),只要单词认识就上sk官网撸,简单粗暴,多了就熟了,毕竟机器学习算法就那么几个。
可以看到测试精度到了可怕的88.9%,有句话说的好,分类任务都先用逻辑回归试一试,能用逻辑回归还用啥rnn?因为不涉及调参,所以也就没有验证集了,深度会用验证集但是也别指望细调,毕竟我写这篇记录的预算也只有一下午。
朴素贝叶斯是将已知的特征群去求状态的问题,根据贝叶斯公布方式巧妙的转换成已知状态求特征群的问题,然后通过假设特征间独立(朴素之来源)从而变成了独立特征与状态的概率乘积,简单,但精度较差。
def train_bayes(X_train, Y_train, X_test, Y_test):
model = GaussianNB()
model.fit(X_train, Y_train)
joblib.dump(model, './model/sentiment_bayes_model.m')
acc = accuracy_score(Y_test,model.predict(X_test))
print("bayes精确度%f"%acc)
比预料差太多了一样,思考了一下,会不会是因为假设特征间与特征间的独立性有问题?但无论如何这个效果也太差,五成还不如蒙?但是在垃圾邮件分类仍然是主流算法,速度比较快。
这是我当时和老师第一次汇报内容就是决策树,所谓决策树就是不断去切分每个特征去形成节点。切分顺序可以根据切分前后的信息熵增益(id3),改进后的根据信息熵增益率(C4.5),以及用来分割连续值的gini系数(CART)的决策树,而随机森林就是一堆决策树的集成,属于bagging,就是一堆一起来,每颗分配不同的数据或者维度然后平均每棵树输出的结果。
接近八成,效果中规中矩,可以看到效果居然还不上逻辑回归,就问问还有谁。
在许多文章里,svm和随机森林都被称为是机器学习里的万金油,啥都能干,能分类能回归,还能保证一定的精确度,但我隐约感觉svm会更好。
支持向量机的核心就是所谓的那几个支持向量,软间隔和核函数。说来惭愧,之前还手动推过支持向量机,现在都忘得差不多了,都钻研深度学习模型去了。然而师兄和我说面试面试官都喜欢问支持向量机。因为里面知识点太多。准备找个时间好好复习再推一遍。model = SVC(kernel='linear')
与前面一样只不过把model换了下而已。
精确度在***89%***左右出头,目前领先所有机器学习算法。
也没什么好讲了,世界上最好解释的机器学习算法(什么?朴素贝叶斯?我愣是给我师妹讲了半小时),戏称墙头草分类法,哪边人多就算哪边的。
def train_knn(X_train, Y_train, X_test, Y_test):
for x in range(1, 15):
model = KNeighborsClassifier(n_neighbors=x)
model.fit(X_train, Y_train)
preds = knnclf.predict(X_test)
num = 0
num = 0
preds = preds.tolist()
for i, pred in enumerate(preds):
if int(pred) == int(Y_test[i]):
num += 1
print('K= ' + str(x) + ', precision_score:' + str(float(num) / len(preds)))
#选择K=20进行KNN训练
model = KNeighborsClassifier(n_neighbors=14)
model.fit(X_train, Y_train)
joblib.dump(model, './model/sentiment_knn_model.m')
acc = accuracy_score(Y_test,model.predict(X_test))
print("knn精确度%f"%acc)
精度截图不见了,大概在七成,比贝叶斯好点还快,毕竟计算复杂度摆在那里。
也就是深度模型里最常说的全连接层,代码用keras写的(import的)
keras支持可视化,我就简单的打印出了
def train_mlp(X_train, Y_train, X_test, Y_test):
from keras.models import Sequential
from keras.layers import Dense, Dropout
model = Sequential()
model.add(Dense(64, input_dim=(2560), activation='relu'))#2560=40*64,句子数乘以词向量维度
model.add(Dropout(0.5))
model.add(Dense(64, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(2, activation='sigmoid'))
model.compile(loss='binary_crossentropy', optimizer='rmsprop', metrics=['accuracy'])
history=model.fit(X_train, Y_train, batch_size=100, epochs=20, validation_data=(X_test, Y_test))
# 绘制训练 & 验证的准确率值
plt.plot(history.history['acc'])
plt.plot(history.history['val_acc'])
plt.title('Model accuracy')
plt.ylabel('Accuracy')
plt.xlabel('Epoch')
plt.legend(['Train', 'Test'], loc='upper left')
plt.show()
# 绘制训练 & 验证的损失值
plt.plot(history.history['loss'])
plt.plot(history.history['val_loss'])
plt.title('Model loss')
plt.ylabel('Loss')
plt.xlabel('Epoch')
plt.legend(['Train', 'Test'], loc='upper left')
plt.show()
model.save('./model/sentiment_mlp_model.h5')
最后一个epoch的精度,看得出来效果都比前面的好
但是看看图
明显在第五个的时候已经就可以停止迭代了,或者再调参(调参不可能的,这辈子不可能调参的)。
怎么说都是深度学习,而且维度还比较大,领先机器学习算法也比较正常(毕竟参数量摆在那),虽说不到一个百分点。
再看看测试
虽然dropoout了还是赤裸裸的过拟合(算了就这样吧反正只是个输出层)
人工智能那么火,无非就是被这个玩意儿卷起来的,这里的卷积和本科的信号与系统不一样,刚学的时候还有点蒙
注意这里的CNN1D其实和图像里的CNN2D是一样的,只不CNN1D默认了数据的维度为词向量的维度而已.
def CNN1D_train(x_train,y_train,x_test,y_test,model_name=''):
#y_test = utils.to_categorical(y_test)
#y_train = utils.to_categorical(y_train)
n_classes=y_train.shape[1]
print(n_classes)
input_vec = Input(shape=(40,64))
x = Conv1D(128, 3,use_bias=True, activation='relu')(input_vec)
#x = MaxPooling1D(5)(x)
x = Conv1D(64, 3, activation='relu')(x)#filter_size=3*64(紧跟上层的input的维度,自动的)
#x = MaxPooling1D(5)(x)
x=Dropout(0.5)(x)
x = Conv1D(64, 3, activation='relu')(x)
x = GlobalMaxPooling1D()(x)
x = Dense(128, activation='relu')(x)
output = Dense(n_classes, activation='sigmoid')(x)
model = Model(inputs=input_vec, outputs=output)
#model.compile(loss=lambda y_true,y_pred: y_true*K.relu(0.9-y_pred)**2 + 0.25*(1-y_true)*K.relu(y_pred-0.1)**2,optimizer='adam', metrics=['accuracy'])
model.compile(loss='categorical_crossentropy',optimizer='adam',metrics=['accuracy',recall_threshold(0.5),precision_threshold(0.5)])
model.summary()
# filepath = "model/CNN1D_best_whight.hdf5"
# checkpoint = ModelCheckpoint(filepath, monitor='val_loss',verbose=1,save_best_only=True,save_weights_only=True, mode='auto')
# callbacks_list = [checkpoint]
starttime = datetime.datetime.now()
#model.fit(x_train, y_train,batch_size=256,epochs=30,verbose=1,validation_data=(x_test, y_test),callbacks=callbacks_list)
history =model.fit(x_train, y_train,batch_size=256,epochs=30,verbose=1,validation_data=(x_test, y_test))
# 绘制训练 & 验证的准确率值
plt.plot(history.history['acc'])
plt.plot(history.history['val_acc'])
plt.title('Model accuracy')
plt.ylabel('Accuracy')
plt.xlabel('Epoch')
plt.legend(['Train', 'Test'], loc='upper left')
plt.show()
# 绘制训练 & 验证的损失值
plt.plot(history.history['loss'])
plt.plot(history.history['val_loss'])
plt.title('Model loss')
plt.ylabel('Loss')
plt.xlabel('Epoch')
plt.legend(['Train', 'Test'], loc='upper left')
plt.show()
#score, acc,recall,precision= model.evaluate(x_test, y_test, batch_size=128)
endtime = datetime.datetime.now()
print("\nTraing using time:%.4f" % ((endtime - starttime).seconds))
print("\nTest score: %.4f, accuracy: %.4f, recall: %.4f,precision: %.4f s" % (score, acc,recall,precision))
print('&&end&&' * 10)
之前犯了个错误,没有把各个模型的训练时间作对比(毕竟比 performance比不过人家,只能比别的了,这个思想早该根深蒂固了,科研的苦TT)
cnn就是调参大户了,一般任务都是先选模型>层数>参数>参数>参数>参数>…>TT
参数就是那么多了,讲句来良心话,虽然cnn参数多,但是结构上是并行计算,速度还是很快的,而且准确率也够高,不会输给rnn结构太多。一般来说cnn的结构窄而深效果会好(没人知道为啥),CNN就是调参问题太多了。
至于gru/LSTM其实都不想怎么谈了,在新的模型不断迭代下(以注意力模型为首)客服了cnn的上下文关联问题及语义、rnn的训练慢、长文本效果的短板。这些性价比不高的模型很容易就会成为古董(科研上)。
下面我就直接po效果最好的BI-GRU的训练图以及所有效果排名了。关于深度学习-人工智能,其实只不过还是数据学习。
因为是在慢的忍无可忍,我把epoch数改为了3,实际上测试准确率最高可以到96.7%(测试集不是验证集),而在这个数据即跑的最好的是之前用的word2vec+textcnn+attention 最好performance到了98%,但是由于不是公开数据所以没什么说服力,只能自己比较了模型用了。
BI-GRU代码
def biGRU_train(x_train,y_train,x_test,y_test,model_name=''):
#y_test0 = to_categorical(y_test)
#y_train = to_categorical(y_train)
num_classes=y_train.shape[1]
input1=Input(shape=(40,64))
x=Bidirectional(GRU(128, return_sequences=True))(input1)
x=Bidirectional(GRU(128,dropout=0.25, recurrent_dropout=0.25))(x)
x=Dense(num_classes,activation='sigmoid')(x)
model = Model(inputs=input1, outputs=x)
#model.add(Activation('softmax'))
#model.compile(loss='categorical_crossentropy', optimizer='rmsprop')
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy',recall_threshold(0.5),precision_threshold(0.5)])
model.summary()
filepath="model/biGRU_best_whight.hdf5"
checkpoint = ModelCheckpoint(filepath, monitor='val_loss',verbose=1,save_best_only=True,save_weights_only=True, mode='auto')
callbacks_list = [checkpoint]
#print('Train...')
starttime = datetime.datetime.now()
model.fit(x_train, y_train, batch_size=128, epochs=30, validation_data=(x_test, y_test), callbacks=callbacks_list)
score, acc,recall,precision= model.evaluate(x_test, y_test, batch_size=128)
endtime = datetime.datetime.now()
print("\nTraing using time:%.4f" % ((endtime - starttime).seconds))
print("\nTest score: %.4f, accuracy: %.4f, recall: %.4f,precision: %.4f" % (score, acc,recall,precision))
print('&&end&&'*10)
明显看得出来还有上升空间,测试精度还在往上走,loss还在减少,两个epoch太少了。效果很好,但确实太慢了
这是这次参加比赛的所有模型
#biLSTM_train(x_train,y_train,x_test,y_test,model_name='')
#LSTM_train(x_train,y_train,x_test,y_test,model_name='')
#biGRU_train(x_train,y_train,x_test,y_test,model_name='')
CNN1D_train(x_train,y_train,x_test,y_test,model_name='')
#GRU_train(x_train,y_train,x_test,y_test,model_name='')
#CNN_LSTM_train(x_train,y_train,x_test,y_test,model_name='')
#train_LogisticRegression(x_train, y_train, x_test, y_test)
#train_decisiontree(x_train, y_train, x_test, y_test)
# train_bayes(x_train, y_train, x_test, y_test)
# train_knn(x_train, y_train, x_test, y_test)
#train_mlp(x_train, y_train, x_test, y_test)
看得出来还有很多烂七八糟的模型(尤其是cnn-lstm模型,我下意识的觉得cnn的池化层会破坏语序信息牺牲了RNN的提取效果,同时lstm还会使整个模型训练变慢,这种模型不可取不可取)
排名
biGRU ——96.7—— 15个epoch
biLSTM—— 95.9—— 15个epoch
GRU ——95.4—— 15个epoch
LSTM ——95.2—— 15个epoch
CNN1D ——94.6—— 20个epoch
mlp ——90
SVM ——89.9
LogisticRegression ——88.9
Randomdecisiontree ——77.9
knn ——70.4
bayes ——54
但我还是想给
感谢keras带给了这么简单的编程体验,封装程度可以真的说是傻瓜式的了。
好像很多师弟来问我深度学习究竟怎么样,应不应该转行(我是被迫的),在考察过整个人工智能热密度最高的深圳后,得到以下的想法以及认识(纯属个人):
1,兴趣是最好的老师,有热情的人才能创造价值。
2,有没有团队接纳你,有没有资源。(有专业的科研大牛(博士,精通行业趋势的道士)带,自己无疑也会更快进步。另外就是硬件条件,没有足够好足够多的gpu,确实很难去做深度做图像、视频、识别数据量大的工作,光模型参数都有1个g了,内存够吗?不过国内的服务器供应行业好像越来越多了,虽然收费也贵。)
3,数学基础好不好,凸(秃)优化了解一下?(我有个建筑设计的朋友跨考了经济系硕士,也要学习机器学习建模方法,叫苦连天)
4,工程能力强不强?(可以理解为代码能力,试想如果一个算法想到了段时间就可以实现并调试,看完了别人论文就可以复现出来,这种人也很适合机器学习岗位,毕竟都要通过代码来实现。我有个师兄就是代码能力超级强论文复现分分钟,虽然后面也只是去了中兴。在我接触那么多学习深度学习的人中,厉害的都是编程能力强的)
还有就是我感觉媒体把人工智能这个ip炒的太火,很多公众号进去把人工智能说的多好多好的到底还是卖课程。虽然人工智能的岗位薪资普遍偏高,尤其算法岗,但其实并不是谁都适合,而且竞争激烈,我们学校数理、机软、信工、甚至乎经管都有相应的机器学习课程,更别说一些院校还设置了专门的人工智能学院,也是为了那句中国要赢在人工智能的竞争上。有很多师兄也告诉过我工作不好找,只会python还是不够。
当然,其实说那么多,只要符合以上四个条件的任何一个都可以去尝试,这是一个入门容易(tensorflow都把库封装成那样了)但是做好很难的工作。但是阻止你进步的都只有你自己对不对?
password: utqv