参考:《Tensorflow和keras-深度学习人工智能实践应用》
第13、14章
GitHub:点我
部分封装函数请看文章:【keras】1. MNIST手写数据集识别(重要)_myaijarvis notebook-CSDN博客
步骤
数据预处理
分析数据
import urllib.request # 下载文件
import os
import tarfile # 解压缩文件
# 下载数据集
url="http://ai.stanford.edu/~amaas/data/sentiment/aclImdb_v1.tar.gz"
filepath=r"data/aclImdb_v1.tar.gz"
if not os.path.isfile(filepath): # 如果该路径下没有文件就下载
result=urllib.request.urlretrieve(url,filepath)
print('downloaded:',result)
# 解压文件
if not os.path.exists(r"data/aclImdb"):
tfile=tarfile.open(filepath,'r:gz')
result=tfile.extractall(r"data/")
读取数据
import re # 正则
def rm_tags(text):
re_tag=re.compile(r'<[^>]+>') # 剔除html标签
return re_tag.sub('',text)
# 读取文件
import os
# filetype: train test
def read_file(filetype):
path="data/aclImdb/"
file_list=[]
positive_path=path+filetype+'/pos/' # 正面评价的文件路径
for f in os.listdir(positive_path):
file_list+=[positive_path+f] # 加入所有文件
negative_path=path+filetype+'/neg/'
for f in os.listdir(negative_path):
file_list+=[negative_path+f]
print("read",filetype,"files:",len(file_list)) # 文件个数
all_labels=([1]*12500 + [0]*12500) # 前12500 是正面 都为1 后面12500 是负面 都为0
all_texts=[]
# 读取所有文件
for fi in file_list:
with open(fi,encoding="utf8") as file_input:
# 先读取文件 使用join连接所有字符串 然后使用rm_tags剔除tag 最后加入all_texts
all_texts.append(rm_tags("".join(file_input.readlines())))
return all_labels,all_texts
y_train,train_text=read_file("train")
y_test,test_text=read_file("test")
y_train=np.array(y_train)
y_test=np.array(y_test)
建立token字典
from tensorflow.python.keras.preprocessing.text import Tokenizer # 建立字典
# 建立 token
token=Tokenizer(num_words=2000) # 词典的单词数为2000
# 建立token词典
token.fit_on_texts(train_text) # 按单词出现次数排序 取前2000个
将影评文字转化为数字列表
# 将影评文字转化为数字列表(一条影评文字转化为一条数字列表)
x_train_seq=token.texts_to_sequences(train_text)
x_test_seq=token.texts_to_sequences(test_text)
对“数字列表”截长补短 ,全部弄成100位
from tensorflow.python.keras.preprocessing import sequence # 截长补短
# 截长补短
x_train=sequence.pad_sequences(x_train_seq,maxlen=100)
x_test=sequence.pad_sequences(x_test_seq,maxlen=100)
MLP
模型
# tf 2.0+ tensorflow.python 加个前缀
from tensorflow.python.keras.models import Sequential
from tensorflow.python.keras.layers.core import Dense,Dropout,Activation,Flatten
from tensorflow.python.keras.layers.embeddings import Embedding
model = Sequential([])
model.add(
Embedding( # 将数字列表转换成词向量
output_dim=32 # 将每一个数字列表里面的数字都转换成32维向量,即一个单词用32维词向量表示
,input_dim=2000 # 输入维数 字典词数2000
,input_length=100 # 每个数字列表有100个数字 相当于用100个数字去表示一条评论
)
)
model.add(Dropout(0.35))
model.add(Flatten()) # 将输入“压平”,即把多维的输入一维化 共有32*100=3200个
model.add(Dense(
units=256 # 神经元节点数
,activation="relu" # 激活函数
))# 隐藏层
model.add(Dropout(0.35))
model.add(Dense(
units=1 # 输出 1表示正面评价 0表示负面评价
,activation='sigmoid'
))
model.summary() # 模型摘要
# 配置
model.compile(
loss="binary_crossentropy" # 损失函数
,optimizer='adam' # 优化器
,metrics=['accuracy'] # 评估
)
# 训练
train_history=model.fit(
x=x_train
,y=y_train
,validation_split=0.2 # 验证集占20%
,epochs=10 # 训练10个周期
,batch_size=100 # 每一批次训练100项数据 一个周期大概训练20000/100=200批次
,verbose=1
)
'''
verbose:日志显示
verbose = 0 为不在标准输出流输出日志信息
verbose = 1 为输出进度条记录
verbose = 2 为每个epoch输出一行记录
注意: 默认为 1
'''
评估
scores=model.evaluate(
x_test
,y_test
,batch_size=100 # 一批次使用100个样本 共训练25000/100=250批次
,verbose=1)
print(scores)
250/250 [==============================] - 2s 8ms/step - loss: 0.6740 - accuracy: 0.8614
[0.6740041375160217, 0.8614000082015991]
print('Test loss:', scores[0])
print('Test accuracy:', scores[1])
Test loss: 0.7183531522750854
Test accuracy: 0.8219599723815918
预测
predict=model.predict_classes(x_test) # 预测的是类别,打印出来的值就是类别号
predict_calsses_vector=predict.reshape(-1) # 转为一维数组
predict_calsses_vector[:10]
array([1, 1, 1, 1, 1, 1, 1, 1, 1, 1])
SentimentDict={1:'正面的',0:'负面的'}
def display_test_Sentiment(i):
print('影评:',test_text[i])
print(f'真实值:{SentimentDict[y_test[i]]} \n预测值:{SentimentDict[predict_calsses_vector[i]]}')
预测其他评论 ***
# 封装函数
def predict_review(input_text):
# 将影评文字转换为数字列表
input_seq=token.texts_to_sequences([input_text])
# 截断或者填充至100
pad_input_seq=sequence.pad_sequences(input_seq,maxlen=100)
predict_result=model.predict_classes(pad_input_seq) # predict_result是二维的
print(SentimentDict[predict_result[0][0]])
# 差评
# 将近300元买的杜比首映场,是真的不值。除了花里胡哨的特效外,一无是处,没有插科打诨和反高潮冷笑话,漫威就不会拍电影啦?花了十年塑造的人物形象性格在本作随意全部推翻,每个人所做的决策都不计后果,意气用事,幼稚且儿戏。巨作难逃烂尾,或许真的是个定律。
bad_text='''
Nearly 300 yuan for a Dolby premiere is really not worth it. Nothing but fancy special effects, and without gags and anti-climax dry jokes, marvel wouldn't make a movie? The characters that took ten years to build are overthrown at will, and everyone's decisions are reckless, emotional, childish and playful. It may be the rule that a blockbuster ends badly.
'''
predict_review(bad_text)
负面的
加大词典
加大词典,增加预测准确度
这里只放修改的地方
token=Tokenizer(num_words=3800) # 词典的大小改为3800
token.fit_on_texts(train_text)
...
x_train=sequence.pad_sequences(x_train_seq,maxlen=380) # 长度改为380
x_test=sequence.pad_sequences(x_test_seq,maxlen=380)
...
model = Sequential()
model.add(Embedding(
output_dim=32
,input_dim=3800 # 修改
,input_length=380 # 修改
))
RNN
模型
from tensorflow.python.keras.layers.recurrent import SimpleRNN
model=Sequential()
model.add(Embedding(output_dim=32,input_dim=3800,input_length=380))
model.add(Dropout(0.35))
model.add(SimpleRNN(16)) # RNN
model.add(Dense(units=256,activation='relu'))
model.add(Dropout(0.35))
model.add(Dense(units=1,activation='sigmoid'))
model.summary()
model.compile(loss='binary_crossentropy',optimizer='adam',metrics=['accuracy'])
train_history=model.fit(
x=x_train
,y=y_train
,validation_split=0.2
,epochs=10
,batch_size=100 # 每一批次训练100项数据 一个周期大概训练20000/100=200批次
,verbose=1
)
评估
scores=model.evaluate(x_test,y_test) # 默认batch_size=32 25000/32=782
print('accuracy=',scores[1])
782/782 [==============================] - 4s 5ms/step - loss: 0.8148 - accuracy: 0.8408
accuracy= 0.8407999873161316
可以自己用评论去预测一下
LSTM
模型
from tensorflow.python.keras.layers.recurrent import LSTM
model=Sequential()
model.add(Embedding(output_dim=32,input_dim=3800,input_length=380))
model.add(Dropout(0.35))
model.add(LSTM(32))
model.add(Dense(units=256,activation='relu'))
model.add(Dropout(0.35))
model.add(Dense(units=1,activation='sigmoid'))
model.summary()
# 这里训练比较慢 可以要花几分钟
model.compile(loss='binary_crossentropy',optimizer='adam',metrics=['accuracy'])
train_history=model.fit(x=x_train,y=y_train,validation_split=0.2,epochs=10,batch_size=100,verbose=1)
scores=model.evaluate(x_test,y_test)
print('accuracy=',scores[1])
782/782 [==============================] - 22s 28ms/step - loss: 0.4828 - accuracy: 0.8532
accuracy= 0.8532400131225586
可以自己用评论去预测一下