import os
import keras
import tensorflow as tf
from keras import layers
import numpy as np#加载数据
def load_data(data_dir):"""data_dir:train的目录或test的目录输出:X:评论的字符串列表y:标签列表(0,1)"""classes = ['pos', 'neg']X, y = [], []for idx, cls in enumerate(classes):# 拼接某个类别的目录cls_path = os.path.join(data_dir, cls)os.listdir()# os.listdir:函数只返回当前目录下的文件和文件夹名称,不包括子目录中的内容。for file in os.listdir(cls_path):# 拼接单个文件的目录(cls_path/file)file_path = os.path.join(cls_path, file)with open(file_path, encoding='utf-8') as f:X.append(f.read().strip())y.append(idx)return X, np.array(y)# input_size:输入样本的数量(词汇表大小)
# seq_len:表示序列的长度 (列的长度)
# embed_dim:表示词向量的维度(行的长度)
#Input Embedding和Positional Encoding
class PositionalEmbedding(layers.Layer): #PositionalEmbedding继承layers.Layerdef __init__(self, input_size, seq_len, embed_dim):super(PositionalEmbedding, self).__init__()self.seq_len = seq_len# 词嵌入self.tokens_embedding = layers.Embedding(input_size, embed_dim)# 位置嵌入self.positions_embedding = layers.Embedding(seq_len, embed_dim)def call(self, inputs, *args, **kwargs):# 生成位置idpositions = tf.range(0, self.seq_len, dtype='int32')te = self.tokens_embedding(inputs)pe = self.positions_embedding(positions)return te + pe# transformer-encoder
class TransformerEncoder(layers.Layer): #TransformerEncoder继承layers.Layerdef __init__(self, embed_dim, hidden_dim, num_heads, **kwargs):super(TransformerEncoder, self).__init__(**kwargs)# Multi-Head Attention层; num_heads 注意头的数量;key_dim 查询和键的每个注意力头的大小self.attention = layers.MultiHeadAttention(num_heads=num_heads, key_dim=embed_dim)# Feed Forward层self.feed_forward = keras.Sequential([layers.Dense(hidden_dim, activation='relu'), #隐藏层layers.Dense(embed_dim)#输出层])# layernorm层self.layernorm1 = layers.LayerNormalization()self.layernorm2 = layers.LayerNormalization()def call(self, inputs, *args, **kwargs):# 计算Self-Attentionattention_output = self.attention(inputs, inputs)# 进行第一个Layer & Normff_input = self.layernorm1(inputs + attention_output)# Feed Forwardff_output = self.feed_forward(ff_input)# 进行第二个Layer & Normoutputs = self.layernorm2(ff_input + ff_output)return outputsdef train():# 超参数vocab_size = 20000 #词汇表seq_len = 180 #句子长度,超过会被截断batch_size = 64 #最大批次hidden_size = 1024 #全连接层维度embed_dim = 256 #词向量维度(每一个词,我们需要用多少位的向量表示)num_heads = 8 #多头8,也就是self-attion是8个# 加载数据X_train, y_train = load_data("C://Users//Administrator//Desktop//重要办公//gan//gan//aclImdb//train")X_test, y_test = load_data("C://Users//Administrator//Desktop//重要办公//gan//gan//aclImdb//test")#向量化 (Tokenizer分词算法是NLP大模型最基础的组件,基于Tokenizer可以将文本转换成独立的token列表,进而转换成输入的向量成为计算机可以理解的输入形式)vectorization = layers.TextVectorization(max_tokens=vocab_size, #词表大小output_sequence_length=seq_len, #最大长度pad_to_max_tokens=True)# 构建词表vectorization.adapt(X_train)# tokenizeX_train = vectorization(X_train)X_test = vectorization(X_test)# 构建模型inputs = layers.Input(shape=(seq_len,)) #输入是180个词# 180*20000||20000*256 == 180*256 的数据形状x = PositionalEmbedding(vocab_size, seq_len, embed_dim)(inputs) #输入180个词,并且限制最大输入也就是180,超过就截切成180,180不够直接paddingx = TransformerEncoder(embed_dim, hidden_size, num_heads)(x)#对文本数据进行平均池化操作x = layers.GlobalAveragePooling1D()(x)x = layers.Dropout(0.5)(x)outputs = layers.Dense(1, activation='sigmoid')(x)#构建函数模型,只需要传入输入和输出model = keras.Model(inputs, outputs)model.summary()# 训练model.compile(loss='binary_crossentropy', metrics=['accuracy'])model.fit(X_train,y_train,epochs=20,batch_size=batch_size,validation_data=(X_test, y_test))if __name__ == '__main__':train()'''
TextVectorization 层将分三个阶段处理文本:
首先,移除标点符号,并将输入内容转换成小写。
接下来,将文本分割成单个字符串词的列表。
最后,使用已知词汇表将字符串映射为数字输出。我们在此处可以尝试一个简单的方法,即多热编码,只考虑评论中是否存在术语。
例如,假设层词汇表为 ['movie', 'good', 'bad'],而评论为 'This movie was bad.'。
我们会将其编码为 [1, 0, 1],其中存在 movie(第一个词汇)和 bad(最后一个词汇)。
'''# 训练数据目录 下载地址:http://ai.stanford.edu/~amaas/data/sentiment/
# - aclImdb
# - test
# - neg
# - pos
# - labeledBow.feat
# - urls_neg.txt
# - urls_pos.txt
# - train
# - neg
# - pos
'''
这是一个电影影评数据集,neg中包含的评论是评分较低的评论,而pos中包含的是评分较高的评论。我们需要的数据分别是test里面的neg和pos,
以及train里面的neg和pos(neg表示negative,pos表示positive)。下面我们开始处理。
'''