keras文本数据处理

"""深度学习用于文本和序列
对于处理文本(单词或字符)序列、时间序列和一般的序列数据常用的两种算法:
①循环神经网络②一维卷积神经网络
其具体应用:
   1.文档分类和时间序列分类,比如识别文章主题或书的作者
   2.时间序列对比,比如评估两个文档或两支股票行情的相关程度
   3.序列到序列的学习,比如机器翻译
   4.情感分析,比如将推文或电影评论的情感划分为正面或负面
   5.时间序列预测,比如根据某地最近的天气数据来预测未来天气"""


"""1.处理文本数据
由于神经网络只能处理张量数据,所以首先应该将文本数据进行向量化(verctorize)
常见方法:
    ①将文本分割为单词,并将每个单词转换为一个向量
    ②将文本分割为字符,并将每个字符转换为一个向量
    ③提取单词或字符的n-gram,并将每个n-gram转换为一个向量。n-gram是多个连续单词或字符的集合
文本分解而成的单元(单词、字符、n-gram)称之为标记(token),将文本分解成标记的过程称之为分词(tokenization)

如何将分词生成的标记于向量相关联?
    ①one-hot编码
    ②标记嵌入(词嵌入 word embedding)
    
"""
"""one-hot编码
将每个单词或字符与一个唯一的整数索引相关联,然后将这个整数索引i转换为长度为N的二进制向量(N是词表大小)
,这个向量只有第i个元素是1,其余元素为0"""

#使用keras内置函数对文本进行one-hot编码
# from tensorflow.keras.preprocessing.text import Tokenizer
#
# samples=["the cat sat on the mat.","the dog ate my homework."]  #文本序列
# tokenizer=Tokenizer(num_words=1000)  #创建分词器,设置只考虑前1000个最常见的单词
# tokenizer.fit_on_texts(samples)  #创建单词索引,即每个单词对应的一个整数索引
# sequences=tokenizer.texts_to_sequences(samples)  #将序列转换为索引列表
# one_hot_results=tokenizer.texts_to_matrix(samples,mode="binary")  #one_hot编码
# word_index=tokenizer.word_index  #得到单词与索引的对应关系
# print(sequences)  #[[1, 2, 3, 4, 1, 5], [1, 6, 7, 8, 9]]
# print(one_hot_results)  #[[0. 1. 1. ... 0. 0. 0.]
#                         #[0. 1. 0. ... 0. 0. 0.]]
# print(one_hot_results.shape) #(2, 1000)
# print(word_index)  #{'the': 1, 'cat': 2, 'sat': 3, 'on': 4, 'mat': 5, 'dog': 6, 'ate': 7, 'my': 8, 'homework': 9}

"""Embedding编码(词嵌入,word embedding)
one-hot编码得到的向量是二进制的,稀疏的(绝大部分元素都是0)、维度很高(维度大小等于词表中单词个数)
word embedding:低维的浮点数向量,并且词嵌入是从数据中学习得到的,词向量可以将更多的信息塞入更低的维度中

获取词嵌入的方法:
1.在完成主任务(比如文档分类,情感预测)的同时学习词嵌入,首先随机初始化词向量,然后对这些词向量进行学习,学习过程与神经网络权重学习一致
2.在不同于待解决的机器学习任务上预计算好词嵌入,然后将其加载到模型中,这些词嵌入叫做预训练词嵌入"""

#1.利用Embedding层学习词嵌入
from tensorflow.keras import layers
import numpy as np

"""
1.至少包含两个参数,标记的个数(词表中单词数)和嵌入的维度(每一个单词最后要表示的向量维度)
2.原理为:将其理解为一个字典,其会将整数索引(特定单词)映射为密集向量
3.其输入形状为[samples,sequences_length],且其输入的长度是可变的,即sequence_length可以为任意长度
4.其输出的形状为:[samples,sequences_length,embedding_dimensionality]"""
# embedding=layers.Embedding(1000,64)
# a=np.array([[1,2]])
# out=embedding(a)
# print(a.shape) #(1,2)
# print(out.shape)  #(1,2,64)

"""应用Embedding+Dense用于IMDB电影评论情感分类"""

#数据加载
# from tensorflow.keras.datasets import imdb
# (train_data,train_labels),(test_data,test_labels)=imdb.load_data(num_words=10000)
# print(train_data.shape,train_labels.shape)
# print(test_data.shape,test_labels.shape)

#由于每个句子长短不一,我们将其处理为统一长度20,多的句子直接截断
# from tensorflow.keras.preprocessing import sequence
# train_data=sequence.pad_sequences(train_data,maxlen=20)
# test_data=sequence.pad_sequences(test_data,maxlen=20)

# print(train_data.shape,test_data.shape)  #(25000, 20) (25000, 20)

#构建网络
# from tensorflow.keras import models
# from tensorflow.keras import optimizers,losses
#
# model=models.Sequential()
# model.add(layers.Embedding(10000,8,input_length=20))
# model.add(layers.Flatten())
# model.add(layers.Dense(1,activation="sigmoid"))
#
# #配置学习过程
# model.compile(optimizer=optimizers.RMSprop(1e-3),loss=losses.binary_crossentropy,metrics=["acc"])
# history=model.fit(train_data,train_labels,batch_size=32,epochs=10,validation_split=0.2)  #在验证集上准确率为75%左右


"""使用预训练的词嵌入:
如果当前训练数据很少,无法从头开始学习适合任务的词嵌入,此时我们可以使用预训练的词嵌入
常用的词嵌入数据库:word2vec,Glove
本次实验展示如何使用Glove词嵌入,我们从imdb原始文本数据集开始进行处理"""

#数据预处理
import os
#数据集路径
train_dir="aclImdb_v1/aclImdb/train"
# test_dir="aclImdb_v1/aclImdb/test"

def text_preprocess(dir_path):
    """

    :param dir_path: 数据集路径
    :return: texts:文本列表,labels:文本标签
    """
    texts=[]
    labels=[]
    for label_type in ["pos","neg"]:
        dir_fname=os.path.join(dir_path,label_type)
        for fname in os.listdir(dir_fname):
            if fname[-4:]==".txt": #判断是否为txt文件
                f=open(os.path.join(dir_fname,fname),encoding="utf-8")
                texts.append(f.read())
                f.close()
                if label_type=="pos":
                    labels.append(1)
                else:
                    labels.append(0)
    return texts,labels
# print(os.path.exists("aclImdb_v1/aclImdb/train\\pos"))
# input()
train_texts,train_labels=text_preprocess(train_dir)
# test_data,test_labels=text_preprocess(test_dir)
# print(train_data)
print("train texts:",len(train_texts),"\ttrain labels:",len(train_labels))  #train texts: 25000 	train labels: 25000
# print("test data:",len(test_data),"\ttest labels:",len(test_labels))

"""对原始数据进行分词:
由于预训练的词嵌入对样本数据很少的任务特别有用,(如果数据量很多的话,从头学习词嵌入效果会更好
所以我们对IMDB数据集进行划分,取200个样本作为训练集,取10000个样本作为验证集,并将句子长度统一为100
"""
from tensorflow.keras.preprocessing.text import Tokenizer  #分词
from tensorflow.keras.preprocessing.sequence import pad_sequences  #句子长短统一
maxlen=100  #取每个句子的前100个单词
training_samples=200
validate_samples=10000
max_words=10000  #只考虑前10000个最常见的单词来分词

tokenizer=Tokenizer(num_words=max_words)
tokenizer.fit_on_texts(train_texts)
sequences=tokenizer.texts_to_sequences(train_texts)

word_index=tokenizer.word_index
print(f"有{len(word_index)}个不同的单词")

data=pad_sequences(sequences,maxlen=maxlen)  #对序列进行长度统一

labels=np.array(train_labels)
print("data shape:",data.shape)
print("label shape",labels.shape)
#
indices=np.arange(data.shape[0])
np.random.shuffle(indices)  #数据索引打乱
data=data[indices]
labels=labels[indices]
#训练集和验证集的采样
x_train=data[:training_samples]
y_train=labels[:training_samples]
x_val=data[training_samples:training_samples+validate_samples]
y_val=labels[training_samples:training_samples+validate_samples]

"""
下载Glove词嵌入
Glove词嵌入介绍:
    下载链接:https://nlp.stanford.edu/projects/glove
"""
#文件解析
glove_dir="glove.6B"
embedding_index={}  #单词与对应的词向量字典
with open(os.path.join(glove_dir,"glove.6B.100d.txt"),encoding="utf-8") as f:
    for line in f:
        values=line.split()  #按空格进行切分,第一个为word,后面的为embedding
        word=values[0]
        coefs=np.asarray(values[1:])
        embedding_index[word]=coefs
print(f"词向量的个数为:{len(embedding_index)}")

"""构建词向量矩阵:
词向量矩阵现状为:[max_words,embedding_dimension]
max_words:单词个数
embedding_dimension:每个单词对应向量的维度"""
embedding_dim=100
embedding_matrix=np.zeros((max_words,embedding_dim))
for word,i in word_index.items():
    if i<max_words:
        embedding_vector=embedding_index.get(word)
        if embedding_vector is not None:
            embedding_matrix[i]=embedding_vector

"""构建模型"""
from tensorflow.keras import layers
from tensorflow.keras import models,losses,optimizers

model=models.Sequential()
model.add(layers.Embedding(max_words,embedding_dim,input_length=maxlen))
model.add(layers.Flatten())
model.add(layers.Dense(32,activation="relu"))
model.add(layers.Dense(1,activation="sigmoid"))
model.summary()

#在模型中加入预训练的embedding
model.layers[0].set_weights([embedding_matrix])
model.layers[0].trainable=False  #不可训练,冻结embedding层

#配置学习过程
model.compile(optimizer=optimizers.RMSprop(1e-4),loss=losses.binary_crossentropy,metrics=["acc"])
history=model.fit(x_train,y_train,batch_size=32,epochs=10,validation_data=(x_val,y_val))
model.save_weights("pre_trained_glove_model.h5")

#训练绘制
import matplotlib.pyplot as plt
"""损失函数绘制"""
history_dict=history.history
train_loss_values=history_dict["loss"]
val_loss_values=history_dict["val_loss"]
epochs=np.arange(1,len(train_loss_values)+1)

plt.figure(1)
plt.plot(epochs,train_loss_values,label="training loss")
plt.plot(epochs,val_loss_values,label="val loss")
plt.title("Training and Val Loss")
plt.xlabel("Epoch")
plt.ylabel("Loss")
plt.legend()

"""精度(准确率)绘制"""
train_acc=history_dict["acc"]
val_acc=history_dict["val_acc"]

plt.figure(2)
plt.plot(epochs,train_acc,label="Training Acc")
plt.plot(epochs,val_acc,label="Val Acc")
plt.title("Training and Val Acc")
plt.xlabel("Epoch")
plt.ylabel("Acc")
plt.legend()

plt.show()







你可能感兴趣的:(pytorch学习深度学习,keras,自然语言处理,深度学习)