TensorFlow2实战-系列教程11:RNN文本分类3

🧡💛💚TensorFlow2实战-系列教程 总目录

有任何问题欢迎在下面留言
本篇文章的代码运行界面均在Jupyter Notebook中进行
本篇文章配套的代码资源已经上传

6、构建训练数据

  • 所有的输入样本必须都是相同shape(文本长度,词向量维度等)
  • tf.data.Dataset.from_tensor_slices(tensor):将tensor沿其第一个维度切片,返回一个含有N个样本的数据集,这样做的问题就是需要将整个数据集整体传入,然后切片建立数据集类对象,比较占内存。
  • tf.data.Dataset.from_generator(data_generator,output_data_type,output_data_shape):从一个生成器中不断读取样本
python 复制代码
def data_generator(f_path, params):
    with open(f_path,encoding='utf-8') as f:
        print('Reading', f_path)
        for line in f:
            line = line.rstrip()
            label, text = line.split('\t')
            text = text.split(' ')
            x = [params['word2idx'].get(w, len(word2idx)) for w in text]#得到当前词所对应的ID
            if len(x) >= params['max_len']:#截断操作
                x = x[:params['max_len']]
            else:
                x += [0] * (params['max_len'] - len(x))#补齐操作
            y = int(label)
            yield x, y
  1. 定义一个生成器函数,传进来读数据的路径、和一些有限制的参数,params 在是一个字典,它包含了最大序列长度(max_len)、词到索引的映射(word2idx)等关键信息
  2. 打开文件
  3. 打印文件路径
  4. 遍历每行数据
  5. 获取标签和文本
  6. 文本按照空格分离出单词
  7. 获取当前句子的所有词对应的索引,for w in text取出这个句子的每一个单词,[params['word2idx']取出params中对应的word2idx字典,.get(w, len(word2idx))从word2idx字典中取出该单词对应的索引,如果有这个索引则返回这个索引,如果没有则返回len(word2idx)作为索引,这个索引表示unknow
  8. 如果当前句子大于预设的最大句子长度
  9. 进行截断操作
  10. 如果小于
  11. 补充0
  12. 标签从str转换为int类型
  13. yield 关键字:用于从一个函数返回一个生成器(generator)。与 return 不同,yield 不会退出函数,而是将函数暂时挂起,保存当前的状态,当生成器再次被调用时,函数会从上次 yield 的地方继续执行,使用 yield 的函数可以在处理大数据集时节省内存,因为它允许逐个生成和处理数据,而不是一次性加载整个数据集到内存中

也就是说yield 会从上一次取得地方再接着去取数据,而return却不会

python 复制代码
def dataset(is_training, params):
    _shapes = ([params['max_len']], ())
    _types = (tf.int32, tf.int32)
  
    if is_training:
        ds = tf.data.Dataset.from_generator(
            lambda: data_generator(params['train_path'], params),
            output_shapes = _shapes,
            output_types = _types,)
        ds = ds.shuffle(params['num_samples'])
        ds = ds.batch(params['batch_size'])
        ds = ds.prefetch(tf.data.experimental.AUTOTUNE)
    else:
        ds = tf.data.Dataset.from_generator(
            lambda: data_generator(params['test_path'], params),
            output_shapes = _shapes,
            output_types = _types,)
        ds = ds.batch(params['batch_size'])
        ds = ds.prefetch(tf.data.experimental.AUTOTUNE)
  
    return ds
  1. 定义一个制作数据集的函数,is_training表示是否是训练,这个函数在验证和测试也会使用,训练的时候设置为True,验证和测试为False
  2. 当前shape值
  3. 1
  4. 是否在训练,如果是:
  5. 构建一个Dataset
  6. 传进我们刚刚定义的生成器函数,并且传进实际的路径和配置参数
  7. 输出的shape值
  8. 输出的类型
  9. 指定shuffle
  10. 指定 batch_size
  11. 设置缓存序列,根据可用的CPU动态设置并行调用的数量,说白了就是加速
  12. 如果不是在训练,则:
  13. 验证和测试不同的就是路径不同,以及没有shuffle操作,其他都一样
  14. 最后把做好的Datasets返回回去

7、自定义网络模型

一条文本变成一组向量/矩阵的基本流程:

  1. 拿到一个英文句子
  2. 通过查语料表将句子变成一组索引
  3. 通过词嵌入表结合索引将每个单词都变成一组向量,一条句子就变成了一个矩阵,这就是特征了


BiLSTM即双向LSTM,就是在原本的LSTM增加了一个从后往前走的模块,这样前向和反向两个方向都各自生成了一组特征,把两个特征拼接起来得到一组新的特征,得到翻倍的特征。其他前面和后续的处理操作都是一样的。

python 复制代码
class Model(tf.keras.Model):
    def __init__(self, params):
        super().__init__()
        self.embedding = tf.Variable(np.load('./vocab/word.npy'), dtype=tf.float32, name='pretrained_embedding', trainable=False,)
        self.drop1 = tf.keras.layers.Dropout(params['dropout_rate'])
        self.drop2 = tf.keras.layers.Dropout(params['dropout_rate'])
        self.drop3 = tf.keras.layers.Dropout(params['dropout_rate'])

        self.rnn1 = tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(params['rnn_units'], return_sequences=True))
        self.rnn2 = tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(params['rnn_units'], return_sequences=True))
        self.rnn3 = tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(params['rnn_units'], return_sequences=False))
        self.drop_fc = tf.keras.layers.Dropout(params['dropout_rate'])
        self.fc = tf.keras.layers.Dense(2*params['rnn_units'], tf.nn.elu)
        self.out_linear = tf.keras.layers.Dense(2)  
    def call(self, inputs, training=False):
        if inputs.dtype != tf.int32:
            inputs = tf.cast(inputs, tf.int32)
        batch_sz = tf.shape(inputs)[0]
        rnn_units = 2*params['rnn_units']
        x = tf.nn.embedding_lookup(self.embedding, inputs)        
        x = self.drop1(x, training=training)
        x = self.rnn1(x)
        x = self.drop2(x, training=training)
        x = self.rnn2(x)
        x = self.drop3(x, training=training)
        x = self.rnn3(x)
        x = self.drop_fc(x, training=training)
        x = self.fc(x)
        x = self.out_linear(x)
        return x
  1. 自定义一个模型,继承tf.keras.Model模块
  2. 初始化函数
  3. 初始化
  4. 词嵌入,把之前保存好的词嵌入文件向量读进来
  5. 定义一层dropout1
  6. 定义一层dropout2
  7. 定义一层dropout3
  8. 定义一个rnn1,rnn_units表示得到多少维的特征,return_sequences表示是返回一个序列还是最后一个输出
  9. 定义一个rnn2,最后一层的rnn肯定只需要最后一个输出,前后两个rnn的堆叠肯定需要返回一个序列
  10. 定义一个rnn3 ,tf.keras.layers.LSTM()直接就可以定义一个LSTM,在外面再封装一层API:tf.keras.layers.Bidirectional就实现了双向LSTM
  11. 定义全连接层的dropout
  12. 定义一个全连接层,因为是双向的,这里就需要把参数乘以2
  13. 定义最后输出的全连接层,只需要得到是正例还是负例,所以是2
  14. 定义前向传播函数,传进来一个batch的数据和是否是在训练
  15. 如果输入数据不是tf.int32类型
  16. 转换成tf.int32类型
  17. 取出batch_size
  18. 设置LSTM神经元个数,双向乘以2
  19. 使用 TensorFlow 的 embedding_lookup 函数将输入的整数索引转换为词向量
  20. 数据通过第1个 Dropout 层
  21. 数据通过第1个rnn
  22. 数据通过第2个 Dropout 层
  23. 数据通过第2个rnn
  24. 数据通过第3个 Dropout 层
  25. 数据通过第3个rnn
  26. 经过全连接层对应的Dropout
  27. 数据通过一个全连接层
  28. 最后,数据通过一个输出层
  29. 返回最终的模型输出
相关推荐
江上鹤.1487 小时前
Day40 复习日
人工智能·深度学习·机器学习
行如流水8 小时前
BLIP和BLIP2解析
深度学习
cskywit8 小时前
MobileMamba中的小波分析
人工智能·深度学习
HyperAI超神经9 小时前
【vLLM 学习】Prithvi Geospatial Mae
人工智能·python·深度学习·学习·大语言模型·gpu·vllm
L.fountain12 小时前
图像自回归生成(Auto-regressive image generation)实战学习(一)
人工智能·深度学习·学习·计算机视觉·图像自回归
لا معنى له13 小时前
学习笔记:卷积神经网络(CNN)
人工智能·笔记·深度学习·神经网络·学习·cnn
资源补给站13 小时前
论文13 | Nature: 数据驱动的地球系统科学的深度学习和过程理解
人工智能·深度学习
金融小师妹13 小时前
非农数据LSTM时序建模强化未来降息预期,GVX-GARCH驱动金价4300点位多空博弈
大数据·人工智能·深度学习
weixin_3954489114 小时前
迁移后的主要升级点(TDA4 相对 TDA2)
人工智能·深度学习·机器学习
光锥智能14 小时前
罗福莉首秀,雷军的AI新战事
人工智能·深度学习·机器学习