【深度学习】05-Rnn循环神经网络-01- 自然语言处理概述/词嵌入层/循环网络/文本生成案例精讲

news2024/11/17 6:55:08

循环神经网络(RNN)主要用于自然语言处理的。

循环神经网络(RNN)、卷积神经网络(CNN)和全连接神经网络(FCN)是三种常见的神经网络类型,各自擅长处理不同类型的数据。下面是它们的简要对比和解释:

1. 循环神经网络(RNN - Recurrent Neural Network)

  • 特点:RNN擅长处理序列数据。与普通神经网络不同,RNN具有“记忆”功能,即它们可以保留之前时刻的信息,并用于当前时刻的输出。其核心特点是循环结构,每个时间步的输出不仅依赖于当前输入,还依赖于前一个时间步的输出。

  • 应用场景:时间序列数据(如股票价格预测)、自然语言处理(如文本生成、机器翻译)、语音识别等。

  • 局限性:标准的RNN在处理长序列时会遇到“梯度消失”问题,导致网络难以学习长时间的依赖关系。为了解决这个问题,改进的RNN结构如LSTM(长短期记忆网络)和GRU(门控循环单元)被引入。

2. 卷积神经网络(CNN - Convolutional Neural Network)

  • 特点:CNN擅长处理图像数据。其核心是卷积层,卷积操作可以提取图像中的局部特征。CNN通常包含多个卷积层、池化层和最后的全连接层。卷积层通过共享权重,能够大大减少网络的参数数量,同时保留重要的空间信息。

  • 应用场景:图像识别、目标检测、图像生成、视频处理等。CNN也是计算机视觉任务中的核心模型。

  • 优势:通过卷积操作,CNN能够有效捕捉局部特征,并能处理较大的图片,具备较好的空间不变性。

3. 全连接神经网络(FCN - Fully Connected Network)

  • 特点:FCN是最基础的神经网络,每一层的神经元与前一层的所有神经元相连。它们通常用于处理结构化数据(如表格数据),但对于高维数据(如图像、文本)来说,它们的参数规模过于庞大,计算效率低,且容易过拟合。

  • 应用场景:主要用于结构化数据的分类和回归任务,如金融数据、医学数据等。它通常用于作为深度神经网络中最后几层的输出层。

  • 局限性:参数数量随着网络层数和每层神经元数量的增加而快速增长,因此不适用于处理高维数据。

三者的对比:

  • 数据类型

    • RNN:适合处理序列数据。

    • CNN:适合处理图像或空间结构化数据。

    • FCN:适合处理结构化数据,但在复杂的任务中通常与CNN、RNN结合使用。

  • 应用场景

    • RNN:时序预测、语言模型、语音识别等。

    • CNN:图像识别、目标检测、视频处理等。

    • FCN:分类、回归等结构化数据任务。

通过这种对比,你可以根据数据类型和任务的不同,选择最合适的神经网络结构。

自然语言处理概述

自然语言处理(Natural Language Processing, NLP)是计算机科学和人工智能的一个重要分支,旨在通过计算机算法分析、理解、生成和处理人类自然语言(如汉语、英语等)。自然语言具有丰富的结构、含义和上下文,难以像传统的结构化数据一样简单地进行数值化处理。

在自然语言处理的任务中,循环神经网络(RNN - Recurrent Neural Network)是一个重要的深度学习模型,尤其适用于处理序列数据,如文本和语音。为了更好地理解RNN在NLP中的作用,下面是一个详细的概述。

一、自然语言处理中的挑战

与传统数据不同,自然语言具有以下几个关键挑战:

  1. 顺序依赖性:语言中的单词或字符通常是有顺序的,单词的顺序对句子的意思有重要影响。例如,"我喜欢你"和"你喜欢我"虽然使用了相同的单词,但顺序不同,意义也不同。

  2. 上下文依赖性:同一个单词在不同的上下文中可能有不同的含义。例如,英语中的单词“bank”可以指“银行”或者“河岸”,这取决于上下文。

  3. 数据稀疏性:词汇表通常非常庞大,且自然语言中的同义词、变体等现象使得数据非常稀疏,难以直接进行数值化处理。

  4. 长程依赖性:有些句子中,单词之间可能存在较远的依赖关系,传统的浅层模型很难捕捉这种长距离依赖。

二、循环神经网络在自然语言处理中的优势

RNN是一类专门设计来处理序列数据的神经网络,能够很好地应对自然语言处理中的顺序依赖和上下文依赖问题。

1. RNN的基本结构

RNN的基本特点是它能够处理一系列输入并保留序列中的上下文信息。在RNN中,每个时间步的输入不仅仅是当前的输入单元(如当前单词或字符),还会结合上一个时间步的信息,从而在处理每个单词时,能够考虑到前面出现过的内容。

在RNN中,输出 ( h_t ) 是当前时间步的隐藏状态,由前一个时间步的隐藏状态 ( h_{t-1} )和当前输入( x_t ) 共同决定的:[ h_t = f(h_{t-1}, x_t) ] 这种递归结构使RNN能够有效地捕捉序列中前后依赖关系。

2. 长短期记忆网络(LSTM)和门控循环单元(GRU)

由于传统的RNN在处理长序列时容易出现“梯度消失”或“梯度爆炸”问题,导致模型难以学习长距离的依赖,改进版的RNN结构,如LSTM和GRU,被广泛应用于自然语言处理。

  • LSTM(Long Short-Term Memory):通过引入特殊的“门”机制,LSTM能够选择性地保留或丢弃过去的信息,从而解决了标准RNN在处理长程依赖时的梯度消失问题。LSTM中的三个门——输入门、遗忘门和输出门——使得它可以灵活地控制信息的流动和记忆。

  • GRU(Gated Recurrent Unit):GRU是LSTM的简化版本,具有类似的性能,但结构更加简单,计算开销较小。GRU结合了两个门:更新门和重置门,用于决定哪些信息需要保留或丢弃。

3. 应用场景

RNN及其变种(如LSTM和GRU)在自然语言处理中的应用非常广泛,特别是在以下任务中表现出色:

  • 机器翻译:通过将一个语言的序列映射到另一个语言的序列,RNN可以捕捉到两种语言之间的语义依赖。例如,谷歌翻译等机器翻译系统大量使用RNN或LSTM。

  • 文本生成:RNN能够生成与给定上下文相关的文本内容。例如,基于输入的部分内容,生成小说、对话等。

  • 情感分析:RNN可以根据输入文本的上下文捕捉情感信息,判断文本的情感倾向(如正面、负面等)。

  • 语言模型:通过预测文本中的下一个单词,RNN可以学习语言的统计规律,从而生成自然的语言序列。语言模型是诸多NLP任务的基础。

  • 语音识别:RNN也被应用于语音到文本的转换,通过分析语音中的时序特征,将其转化为文本。

三、RNN在自然语言处理中的不足与改进

尽管RNN在NLP中表现出色,但它也有一些局限性:

  1. 长程依赖问题:标准RNN在处理非常长的序列时,仍然难以捕捉远距离的依赖关系。虽然LSTM和GRU有所改善,但它们仍有一定的局限性。

  2. 并行性差:由于RNN的序列性特点,前向传播和反向传播必须逐步进行,难以并行计算。这使得RNN的训练效率较低,特别是在处理长序列时。

为了解决这些问题,近年来一些新的模型,如Transformer,逐渐取代RNN,成为主流的NLP模型。Transformer通过自注意力机制,能够并行处理整个序列,并有效捕捉长距离依赖。

四、RNN在NLP中的实际案例

  1. 文本分类

    • 任务:根据给定文本,自动分类为不同类别(如新闻分类、情感分类)。

    • 流程:首先将文本转化为向量序列,然后通过RNN模型处理该序列并输出分类结果。RNN能够根据文本中的语义关系进行分类。

  2. 机器翻译

    • 任务:将一个语言的句子翻译为另一个语言。

    • 流程:使用一个编码器-解码器架构,其中编码器RNN将源语言的句子编码成一个隐藏状态,解码器RNN根据隐藏状态生成目标语言的句子。

总结

循环神经网络(RNN)在自然语言处理中的应用十分广泛,尤其擅长处理序列依赖问题,如语言中的词序和上下文关系。尽管RNN具有局限性,诸如LSTM、GRU等改进版本在很多NLP任务中表现出色,并且通过自注意力机制的Transformer进一步推动了NLP领域的发展。

在自然语言处理(NLP)的预处理中,语料库语料样本分词词表是经常提到的概念。了解这些概念有助于我们更好地理解分词以及NLP任务中的文本处理流程。下面是对这些术语的详细解释:

1. 语料库(Corpus)

语料库是指大量经过收集和整理的文本数据集合,用于语言学研究或自然语言处理的训练和测试。它通常包含了多种形式的文本,例如书籍、新闻文章、对话记录、社交媒体内容等。

  • 用途:语料库是训练自然语言处理模型的基础。通过大规模的语料库,模型可以学习语言的结构、词汇的用法、常见的词汇组合等。

  • 特征:语料库可以是单一语言的(如中文语料库),也可以是多语言的(如英汉双语语料库)。此外,语料库可以标注更多信息,如词性、命名实体等。

    例子

    • Wikipedia语料库:收集自维基百科的文本数据,是一个常见的开源语料库。

    • COCA语料库(Corpus of Contemporary American English):一个专门收集现代美式英语的语料库。

2. 语料(Text/Document)

语料是指语料库中的具体文本数据。简单来说,语料就是语言处理任务中需要分析、训练或者测试的原始文本内容。

  • 用途:语料是构成语料库的基本单元,每个语料通常是具体的文本数据,如一篇文章、一段对话等。它是模型分析和学习的输入数据。

  • 特征:语料可以是结构化的(如已标注词性、句法结构)或非结构化的(纯文本),视任务需求而定。

    例子

    • "我喜欢学习自然语言处理。" 这是一个语料样本,通常被用作模型的输入进行处理。

3. 样本(Sample)

样本是从语料库中提取出来的一小部分数据,通常用作训练或测试模型的具体数据实例。样本可以是句子、段落,甚至是一个完整的文本。

  • 用途:在模型的训练和测试过程中,样本是用于输入到模型中的单位。样本的数量和质量对模型的效果有很大影响。

  • 特征:样本可以是一个单词、一句话或一个段落,具体取决于任务的定义。例如,在情感分析任务中,样本可能是单个句子,而在机器翻译任务中,样本则可能是整段文本。

    例子

    • "我喜欢苹果。" 这是一个样本,用于训练一个情感分类模型时,它会被标注为"正面"情感。

4. 分词(Tokenization)

分词是将连续的文本分割成若干个独立的词汇(或“词语”)的过程。对于像中文这样的语言,由于没有明确的单词边界(不像英文有空格),分词是必要的预处理步骤。在分词过程中,文本被切分为“词”或“标记”(token)。

  • 用途:分词后的结果被用作模型的输入,模型会基于这些词汇进行进一步的分析和处理。

  • 特征:不同语言的分词方式不同。英文的分词相对简单,通常可以通过空格来分隔单词,而中文则需要通过分词算法来确定词语边界。

    例子

    • 对于句子“我爱自然语言处理”,分词结果可能是:[“我”,“爱”,“自然语言处理”]。

5. 词表(Vocabulary)

词表是指分词之后所有独立词汇的集合。它包含了在语料库中出现过的所有词语,每个词语都会有一个唯一的编号,方便后续的处理和计算。词表可以看作是模型的“词汇量”。

  • 用途:词表是模型进行词汇映射的基础。通过将文本中的词汇与词表中的编号对应,模型能够将文本转化为数值形式。词表也是语言模型训练过程中控制词汇范围的重要工具。

  • 特征:词表的大小通常根据语料库中的词汇数量决定。较大的词表可以覆盖更多的词汇,但会导致计算资源的增加,而较小的词表则可能会忽略一些低频或罕见词汇。

    例子

    • 词表可能包含:[“我”:1,"爱”:2,"自然语言处理”:3,"喜欢”:4,"学习”:5]。

这些概念的关系

  1. 语料库是一个大规模的文本集合,里面包含了许多语料

  2. 语料可以进一步被处理成若干个样本,供模型进行训练或测试。

  3. 分词是将语料样本切分为一个个独立的词汇

  4. 所有经过分词处理后的词语会形成一个词表,用来统一词汇的编号。

总结

  • 语料库是一个语言数据的整体集合,语料是其中的单个文本数据,样本是从语料中提取出来的一部分。

  • 分词是将语料或样本切分为词的过程,而词表是分词结果中所有词汇的集合。

分词是自然语言处理(NLP)中的关键预处理步骤之一,特别是在处理中文、日文等没有明确单词边界的语言中。在分词的过程中,文本被切分为一个个独立的词汇或短语,方便后续的分析和处理。

一、分词的作用

在大多数NLP任务中,计算机需要将语言转化为数值表示才能进行处理。原始的句子是一串连续的字符,对于计算机而言,它并不能直接理解这些字符的含义。分词的作用就是将这段连续的文本按词语的边界切分开,形成一个个独立的单词或短语,作为后续处理的基础。

二、分词的重要性

  1. 词汇层次的信息:分词可以提取句子中的词汇信息,保留了词语的基本含义。尤其是像中文这样的语言,词与词之间没有空格,需要分词才能构建基本的词汇单位。

  2. 提高模型效果:在文本分类、情感分析等任务中,分词后的词语序列能够更好地反映文本的语义信息,有助于提高模型的准确性和性能。

  3. 简化处理:通过分词,可以减少文本的长度,降低处理难度。与处理字符级别的文本相比,词级别的文本处理更简单且更高效。

三、分词的类型

在进行分词时,根据任务需求和语言的特点,分词可以分为以下几种类型:

1. 基于规则的分词

这种方法使用预定义的词典和规则进行匹配,通常根据最大匹配原则进行分词:

  • 正向最大匹配:从左到右逐步扫描文本,尽可能匹配最长的词。例如,“研究生命科学”可能被切分为[“研究”, “生命科学”]。

  • 逆向最大匹配:从右到左进行匹配,同样优先选择最长的词。

优点:实现简单,适合词汇量不大且有明确边界的文本。

缺点:对未登录词(词典中没有的词)表现不好,且容易出现歧义问题。例如,“长春市长春药店”中的“长春市”和“长春”会引发分词歧义。

2. 基于统计的分词

这种方法基于文本中的词频统计,通过大规模语料训练模型,判断两个字符之间的关联度,并据此进行分词。例如,使用常见的隐马尔可夫模型(HMM)最大熵模型等。

  • 核心思想:根据每个词在训练语料中的出现频率以及上下文的关联度,判断是否将字符组合成词。比如“生活质量”这几个字会比“生”和“活质量”在语料库中组合出现的次数更多,因此被分成“生活”和“质量”两个词。

优点:能够处理未登录词,灵活性高。

缺点:需要大量语料来进行训练,可能对罕见词或新词效果不好。

3. 基于深度学习的分词

近年来,基于神经网络的分词方法越来越流行,尤其是结合了RNNLSTMBERT等模型的端到端分词。通过深度学习模型,计算机能够自动学习文本的语义和句法结构。

  • 例子:BERT等预训练语言模型可以基于上下文信息进行分词,并能够处理复杂的语境。

优点:能够结合上下文信息,解决多义词和歧义问题,处理效果更好。

缺点:训练时间较长,计算资源消耗较大。

四、分词中的常见问题

  1. 歧义问题:由于语言的复杂性,分词时经常会遇到歧义。例如,句子“研究生命科学”可以分为“研究/生命/科学”或“研究/生命科学”,不同的分词方式对应着不同的语义。

  2. 未登录词问题:词典中没有的词(如新词、专有名词等),在基于规则的分词方法中难以处理。这也是为什么需要引入基于统计或深度学习的分词方法的原因。

  3. 多义词问题:同一个词在不同语境下可能有不同的含义,分词时可能无法准确判断。例如,“苹果”既可以是水果的名字,也可以是公司名。

五、中文分词的常用工具

  1. 结巴分词(jieba)

    • 这是一个非常流行的中文分词工具,基于前缀词典、HMM等技术,提供了多种分词模式,如全模式、精确模式和搜索引擎模式。

  2. THULAC

    • 清华大学开发的一个分词工具,支持词性标注,适合中文处理任务。

  3. HanLP

    • 支持多种自然语言处理任务的开源工具,性能较高,并且集成了分词、词性标注、命名实体识别等功能。

六、分词的实际案例

假设我们有一句话:“我爱自然语言处理”,通过不同的分词方式,我们可以得到不同的结果:

  • 结巴分词(精确模式):["我", "爱", "自然语言处理"]

  • 结巴分词(全模式):["我", "爱", "自然", "自然语言", "语言", "语言处理", "处理"]

  • 基于深度学习的分词:["我", "爱", "自然语言", "处理"]

分词后的结果可以用作文本分类、情感分析、机器翻译等任务的输入数据。

总结

分词是自然语言处理中的一个关键步骤,尤其对于中文等没有空格分隔的语言来说尤为重要。根据任务需求和语言特点,分词方法可以分为基于规则、统计和深度学习的方式。在处理自然语言的过程中,分词质量对后续任务的效果有着重要影响。

预处理分词和词嵌入层:本质是把文本变成向量,然后输入到循环神经网络中

以下是对预处理过程词嵌入层的详细解释和验证:

1. 预处理过程:文本转数字

在自然语言处理(NLP)的预处理中,将文本(字符串)转换为数字的过程通常包括以下几步:

a. 分词

分词是将文本切分成词的过程,比如中文需要通过分词工具(如结巴分词)将句子拆解成词。

b. 词汇表映射

分词后的词会被映射到一个唯一的数字ID,通常使用一个词汇表(Vocabulary)进行映射。例如,一个词汇表可能包含以下映射:

  • "我" -> 1

  • "爱" -> 2

  • "自然语言处理" -> 3

最终,原始句子 "我爱自然语言处理" 会被转换为 [1, 2, 3] 的索引序列。

总结:预处理过程是将字符串转化为离散的数字索引,表示单词的位置和唯一性,但不包含语义信息。这个过程不涉及向量或嵌入,只是简单的编号。

2. 词嵌入层:词转向量

词嵌入层是一种将离散的词汇索引(数字)转换为向量表示的方法。通过词嵌入,模型可以将每个单词转换成一个包含语义信息的向量。

a. 词嵌入的作用

词嵌入层通过学习一个词汇表中所有词的语义信息,将每个单词转换为一个固定长度的向量。例如:

  • "我" -> [0.2, 0.4, 0.6, 0.8]

  • "爱" -> [0.1, 0.3, 0.7, 0.9]

  • "自然语言处理" -> [0.5, 0.2, 0.4, 0.6]

这些向量表示捕捉了单词之间的语义相似性,比如“猫”和“狗”可能会有相似的向量表示,因为它们的语义相近。

b. 训练方式

词嵌入层可以通过以下两种方式进行训练:

  • 随机初始化后通过模型训练学习:在深度学习模型中,词嵌入层会随着整个模型的训练一同更新和优化。

  • 使用预训练嵌入:如Word2Vec、GloVe等预训练模型生成的词向量,可以直接使用。

c. 词嵌入层的特点
  • 连续向量表示:词嵌入层会将每个单词表示为一个连续的、固定长度的向量,向量中的每个值表示该单词在不同维度上的特征。

  • 语义相似性:词嵌入向量通过学习能够捕捉到单词之间的语义相似性,表现出更强的泛化能力。

3. 区别验证

为了确保理解正确,可以进一步明确预处理和词嵌入的区别:

  • 预处理过程:将文本中的单词通过分词和词汇表映射为离散的数字索引,不包含语义信息。

  • 词嵌入层:将数字索引映射为向量表示,捕捉单词的语义信息。这是神经网络模型的一部分,包含了学习单词之间关系的能力。

确保正确性:分词和词汇表映射属于文本预处理阶段,用于将文本转为可以被模型处理的数字序列。而词嵌入属于模型的一部分,通过向量化表示将单词的语义关系编码到模型中。

词嵌入层讲解

接下来,我们就实现下刚才的需求:

1. 安装 jieba 分词模块

在命令行或终端中运行以下命令来安装 jieba

pip install jieba

2. 验证安装

安装完成后,可以在 Python 中导入 jieba 来验证是否成功:

import jieba
​
# 测试分词
text = "巴黎奥运会的进度条已经过半,不少外国运动员在完成自己的比赛后踏上归途"
words = jieba.lcut(text)
print("分词结果:", words)

如果安装成功,程序将正确输出分词结果。

['巴黎', '奥运会', '的', '进度条', '已经', '过半', ',', '不少', '外国', '运动员', '在', '完成', '自己', '的', '比赛', '后', '踏上', '归途']

这些分词将用于构建词嵌入层。现在你可以将这些分词映射到唯一的索引,并通过词嵌入层来将这些索引转换为向量表示。

代码:

import torch
import torch.nn as nn
import jieba

if __name__ == '__main__':
    # 1.文本数据
    test = "巴黎奥运会的进度条已经过半,不少外国运动员在完成自己的比赛后踏上归途"
    # 2.分词
    words = jieba.lcut(test)
    print(words)
    
    # 3.构建词向量矩阵,构建的时候,矩阵的里面的值是随机的初始化的
    embed = nn.Embedding(num_embeddings=len(words), embedding_dim=4)
    print(embed(torch.tensor(1)))

输出 

疑惑的点是,这个embed 初始化的时候,只用了,样本个数和向量的维度,然后使用的时候,只是用了一个id,那么他是怎么和这个words 拉上关系的呢,我没有看到申明

疑惑很合理。关键点是关于词汇表的映射问题,以及 nn.Embedding 是如何工作的。让我们逐步分析。

1. 关于 nn.Embedding 的工作原理

nn.Embedding 是 PyTorch 提供的一个用于词嵌入的模块,作用是将一个词汇索引(整数)映射到一个固定大小的向量。在构建 Embedding 层时:

embed = nn.Embedding(num_embeddings=len(words), embedding_dim=4)

这段代码创建了一个嵌入矩阵,其中:

  • num_embeddings=len(words) 定义了词汇表的大小,也就是有多少个不同的词(在例子中就是分词后的 words 列表)。

  • embedding_dim=4 定义了每个词的向量维度是 4(语料库很大,这个值就需要调特别大)。

所以 nn.Embedding 实际上创建了一个 len(words) * 4 大小的矩阵。每一行代表一个词对应的向量,初始向量是随机生成的,并且会在模型训练时逐渐调整。

2. 关于输入 torch.tensor(1)

当调用:

print(embed(torch.tensor(1)))

传入的是整数 1,这里的 1 是一个索引。这个索引告诉 Embedding 层从嵌入矩阵中返回第 1 行对应的嵌入向量。

例如,在这个调用中,索引 1 可能对应于分词结果中的第二个词("奥运会")。因此,

embed(torch.tensor(1))

返回的是与 "奥运会" 相关联的随机初始化向量

[ -0.0131, -0.9808, 0.9618, -0.4715 ]

注意:这里的词和向量的关系是由索引直接对应的,但代码中并没有显式创建词与索引的映射。

3. 为什么看不到显式声明的映射?

在代码中,实际上 words 列表中的每个词都隐式地被索引了:

  • 列表中的第一个词 "巴黎" 的索引是 0。

  • 第二个词 "奥运会" 的索引是 1。

  • 第三个词 "的" 的索引是 2。

  • 以此类推。

当传递 torch.tensor(1)Embedding 层时,它只是简单地根据这个整数索引从嵌入矩阵中选择相应的向量。由于 PyTorch 的 nn.Embedding 只处理索引到向量的映射,因此它只需要提供一个索引,它会自动从嵌入矩阵中返回相应的向量。

但是:在实际的 NLP 应用中,通常会有一个明确的词汇表,将词映射到索引。需要手动将词汇表的每个词与其对应的索引关联起来,然后使用这些索引去查找词嵌入。

4. 补充说明:如何创建显式的词汇映射

在实际的 NLP 项目中,我们通常会显式地创建一个词汇表并将其映射到索引,比如:

# 创建一个词汇表,将词映射到索引,下面是一个字典表达式: word:i 即单词:索引组合成字典
vocab = {word: i for i, word in enumerate(words)}
​
# 打印词汇表
print(vocab)  # {"巴黎": 0, "奥运会": 1, "的": 2, ...}
​
# 查询"奥运会"的嵌入向量
word_idx = vocab["奥运会"]
print(embed(torch.tensor(word_idx)))

这样,可以明确地看到每个词与其索引的关系,随后就可以使用这些索引来查询词嵌入向量。

5. 总结

  • nn.Embedding 内部维护了一个嵌入矩阵,每一行对应一个词汇的向量表示。这个映射是基于词汇的索引进行的。

  • 在代码中,虽然没有显式创建词汇和索引的映射,但实际上 words 列表中的词通过其顺序隐式地与整数索引对应。

  • torch.tensor(1) 作为索引,告诉 nn.Embedding 去返回嵌入矩阵中对应行的向量。

  • 为了更清晰地控制词汇和索引的对应关系,建议显式地构建一个词汇表(如字典 vocab),并通过索引来访问词嵌入向量。

代码

import torch
import torch.nn as nn
import jieba

if __name__ == '__main__':
    # 1. 文本数据,准备要处理的文本字符串
    sentence = "巴黎奥运会的进度条已经过半,不少外国运动员在完成自己的比赛后踏上归途"
    
    # 2. 分词,将句子拆分成词语列表
    word_list = jieba.lcut(sentence)
    
    # 3. 构建词汇表 (去重,确保每个词只出现一次)
    unique_words = list(set(word_list))
    vocab_size = len(unique_words)  # 获取词汇表大小
    print("词汇表:", unique_words)
    print("词汇表大小:", vocab_size)
    
    
    # 4. 构建词嵌入层,参数为词汇表大小和词向量的维度
    embedding_dim = 4  # 定义词向量的维度
    embedding_layer = nn.Embedding(num_embeddings=vocab_size, embedding_dim=embedding_dim)
    
    # 5. 输出每个词的词向量
    for word_index, word in enumerate(unique_words):
        word_index = torch.tensor([word_index])  # 获取词的索引,并转换为张量
        word_embedding = embedding_layer(word_index)  # 获取对应的词向量
        print(f"词语: {word},索引: {word_index},词向量: {word_embedding}")

输出 

词汇表: ['不少', '过半', '的', '外国', '自己', '在', '已经', '进度条', '运动员', '归途', ',', '比赛', '巴黎', '后', '奥运会', '踏上', '完成']
词汇表大小: 17
词语: 不少,索引: tensor([0]),词向量: tensor([[2.1497, 1.0149, 0.9918, 0.5382]], grad_fn=<EmbeddingBackward0>)
词语: 过半,索引: tensor([1]),词向量: tensor([[ 0.8716, -1.8488,  0.2891,  1.1344]], grad_fn=<EmbeddingBackward0>)
词语: 的,索引: tensor([2]),词向量: tensor([[-1.7215,  2.2367, -1.3738, -0.3897]], grad_fn=<EmbeddingBackward0>)
词语: 外国,索引: tensor([3]),词向量: tensor([[-0.9484, -0.0633,  1.4533,  0.2565]], grad_fn=<EmbeddingBackward0>)
词语: 自己,索引: tensor([4]),词向量: tensor([[-0.1045,  1.2132, -0.6344,  2.3763]], grad_fn=<EmbeddingBackward0>)
词语: 在,索引: tensor([5]),词向量: tensor([[-0.4545, -0.6336,  0.6195, -0.6505]], grad_fn=<EmbeddingBackward0>)
词语: 已经,索引: tensor([6]),词向量: tensor([[-0.5900,  1.6933, -0.7605,  0.1284]], grad_fn=<EmbeddingBackward0>)
词语: 进度条,索引: tensor([7]),词向量: tensor([[ 2.2881, -0.3610,  1.8706, -0.5137]], grad_fn=<EmbeddingBackward0>)
词语: 运动员,索引: tensor([8]),词向量: tensor([[-0.3448,  0.1217, -0.0943,  0.3493]], grad_fn=<EmbeddingBackward0>)
词语: 归途,索引: tensor([9]),词向量: tensor([[ 0.0720,  0.2340,  1.6238, -0.6006]], grad_fn=<EmbeddingBackward0>)
词语: ,,索引: tensor([10]),词向量: tensor([[-0.5438,  0.6621, -2.4010, -0.3911]], grad_fn=<EmbeddingBackward0>)
词语: 比赛,索引: tensor([11]),词向量: tensor([[ 0.6472, -0.0451,  1.4426,  0.4981]], grad_fn=<EmbeddingBackward0>)
词语: 巴黎,索引: tensor([12]),词向量: tensor([[-0.9074, -0.0805,  0.9370, -1.2739]], grad_fn=<EmbeddingBackward0>)
词语: 后,索引: tensor([13]),词向量: tensor([[-1.0162,  0.8043, -0.6054,  0.7315]], grad_fn=<EmbeddingBackward0>)
词语: 奥运会,索引: tensor([14]),词向量: tensor([[-0.9563, -0.2509, -0.2551,  0.6060]], grad_fn=<EmbeddingBackward0>)
词语: 踏上,索引: tensor([15]),词向量: tensor([[ 0.9793,  1.2424, -0.4906, -0.5413]], grad_fn=<EmbeddingBackward0>)
词语: 完成,索引: tensor([16]),词向量: tensor([[ 0.5868,  0.6690,  0.3030, -0.6114]], grad_fn=<EmbeddingBackward0>)

这样一个句子就被分词,然后和初始化的词向量关联起来了,那么每个词向量就有了其表达的意义了,那么在神经网络中,由于反向传播的存在,这些词向量都相当于参数会被一步一步的更新,最终如果训练的好的话,那么同义词的话,距离会更近,反义词的距离会远一些,如果语料库更大,那么我们要区别出词语的向量就需要更多的维度,也就是embedding_dim 的值要更大,即向量的元素 更多一些。最终训练完成,那么这些向量就有了词语的意义。

注意⚠️: 我们这里只是使用一句话来讲解这个分词和词嵌入层的作用,实际中,输入会是一个.txt的语料库,里面会有很多句子。

循环网络层 

RNN 网络原理讲解

循环神经网络(Recurrent Neural Network,RNN)的原理。

1. 为什么要使用循环神经网络(RNN)?

在自然语言处理(NLP)、时间序列预测等任务中,我们的数据通常是具有时间序列上下文依赖的。也就是说,某个时刻的数据不仅仅依赖于当前的输入,还依赖于之前的输入。例如:

• 在一个句子中,后面的单词往往和前面的单词有很强的关联。比如句子“我爱你”,如果我们颠倒顺序说“爱你我”或者“你我爱”,整个意思就完全变了。

• 在股价预测中,明天的股价往往取决于过去几天的走势,而不仅仅取决于今天的股价。

因此,我们需要一种神经网络模型,能够“记住”过去的数据,并基于这些历史数据来做当前时刻的预测。

RNN能够捕捉这种序列关系,并逐步处理序列中的每个单元,保留过去的信息,并在未来的计算中利用这些信息。这是循环神经网络(RNN)正是为了解决这个问题而设计的,解决自然语言、时间序列等任务时的关键优势。

2. 什么是循环神经网络?

在传统的前馈神经网络(Feedforward Neural Network, FNN)中,每个输入数据点是相互独立的,模型一次性处理输入,然后输出结果。它无法处理序列数据,因为它“看不到”前后输入之间的关系。

RNN 的核心不同点在于它具备一个“记忆”功能,能够在每一个时间步保留之前时间步的信息。它的网络结构中有一个隐藏状态(hidden state),这个隐藏状态会在每个时间步更新,并传递到下一个时间步,这样每一步的输出不仅仅依赖于当前的输入,还依赖于之前的隐藏状态,形成了循环结构。

2. RNN的基本原理

RNN 的核心特性是它的循环结构,可以在不同时间步之间传递隐藏状态信息。在每个时间步,RNN会接收当前的输入数据,并结合前一个时间步的隐藏状态,传递到当前神经元,计算新的隐藏状态和输出。举个例子:

  • 让我们用PPT中的例子“我爱你”来解释这个概念:

        1.    输入“我”:RNN接收输入“我”,结合初始隐藏状态(通常为零向量),计算出一个新的隐藏状态  h_1
        2.    输入“爱”:接下来RNN接收输入“爱”,这时候它不只依赖“爱”这个词的输入,还会结合之前的隐藏状态  h_1 ,输出新的隐藏状态  h_2  和当前时刻的输出。
        3.    输入“你”:同样,RNN接收输入“你”,结合前一个隐藏状态  h_2​​​​​​​  计算新的隐藏状态  h_3  和最终输出。

    这种“记住”过去输入的能力,使得RNN能够很好地处理上下文依赖的任务。

3. 为什么RNN可以实现“循环”?

在PPT中,我们看到了一个非常形象的RNN结构图,每个蓝色的神经元代表一个时间步的计算。虽然看起来像是不同的神经元,但实际上,RNN的神经元是共享的,也就是说,不同时间步上,实际上是同一个神经元在反复使用

具体来说,每一步的计算结果(隐藏状态)都会被传递到下一时间步,这就是所谓的“循环”:

• 当前时间步的输出不仅依赖于当前的输入,还依赖于前一个时间步的隐藏状态。

• 这种循环结构使得RNN能够在处理序列时保持对之前输入的记忆,直到序列结束。

3. RNN的循环过程

如PPT中所示,RNN的结构是一个循环网络。每个神经元接收当前时间步的输入和前一个时间步的隐藏状态,计算出新的隐藏状态和输出。

  • 初始隐藏状态 ( h_0 ) 一般是零向量。

  • 每个时间步的输出和更新是基于当前的输入向量 ( x_t) 和前一个时间步的隐藏状态 (h_{t-1} ) 计算出来的。

尽管在图中展示的是多个神经元,但实际上所有的时间步共享同一个神经元。这个共享机制让RNN能够有效处理长序列数据。

4. RNN 的内部计算

​​​​​​​

通过这个公式,RNN能够不断更新隐藏状态,并保持对序列数据的记忆。

5. RNN的应用

RNN在自然语言处理中的应用非常广泛,典型任务包括:

  • 文本生成:给定句子的前几个词,预测下一个词。

  • 机器翻译:从源语言序列翻译成目标语言序列。

  • 情感分析:根据句子或段落的内容判断其情感倾向。

6. 具体例子:句子“我爱你”

通过具体的例子“我爱你”,我们可以详细解释RNN的计算过程。

这种逐步计算的方式使得RNN能够记住前面的输入,并结合当前的输入,生成当前的输出。

7. 优点与局限

优点

  • 处理序列数据的能力:RNN非常适合处理序列化的数据,如自然语言、时间序列、视频等。它能够利用前后信息做出更加合理的预测或分类。

    共享参数:每一个时间步使用相同的神经元和参数,这使得模型可以很好地泛化,处理任意长度的序列。

局限

  • 梯度消失问题:当序列过长时,RNN很难将早期的信息保留到后面的时间步,这会导致梯度消失问题,从而使模型难以学习到长程依赖关系。这也是为什么后来出现了长短期记忆网络(LSTM)和 门控循环单元(GRU)来解决这个问题。

总结

RNN的核心优势在于它能够处理带有时间序列或上下文依赖的数据,通过循环结构,它能够记住过去的信息,并结合当前输入来做出预测。这种特性在自然语言处理、语音识别、时间序列预测等领域中非常重要。

我们今天讲解了RNN的基本工作原理和它为什么能够捕捉到序列中的依赖关系。

接下来我们来讲解一个三层循环神经网络(RNN)的计算过程(事实上我们一般是使用一层的,很少说用三层来做RNN),通过实例推演每个时间步的计算,并解释为什么它能够处理序列数据。为了简单,我们假设句子为“我爱你”,并且每个词用向量表示。

1. 设定输入

  • 输入句子是“我爱你”,每个词语通过词嵌入层转换成向量:

    • “我” -> 向量 (x_1)

    • “爱” -> 向量 ( x_2 )

    • “你” -> 向量 ( x_3 )

2. RNN层设计

在RNN中,每个时间步会有输入  x_t (当前时刻的输入向量),以及前一个时间步的隐藏状态  h_{t-1}。隐藏状态可以看作是记忆,它记录了之前时间步的信息。

初始的隐藏状态  h_0  一般设置为全零向量  h_0 = [0, 0, 0] (具体维度是几个0,自己设定,是超参数)。

我们假设使用三层的RNN,每层都有隐藏状态,以下是结构:

  • 第一层RNN会接收输入数据 ( x_t ),并计算出隐藏状态 ( h_1 )。

  • 第二层RNN使用第一层的隐藏状态作为输入,计算出新的隐藏状态 ( h_2)。

  • 第三层RNN再接收第二层的隐藏状态,最终输出 (h_3 )。

每一层的计算遵循公式:

3. 计算过程推演

时间步1:处理“我”

输入: 当前时间步的输入是“我”的向量  x_1 ,同时有初始隐藏状态  h_0(初始隐藏状态通常为全零向量,后续的隐藏状态则是计算出来的。)

加权和:RNN会计算“我”的输入  x_1  和初始隐藏状态  h_0  的加权和:

具体来看,计算步骤如下:
    •     W_{ih} x_1:将输入 x_1  乘以权重矩阵  W_{ih} ,表示输入的加权求和。
    •     W_{hh} h_0 :将前一个时间步的隐藏状态  h_0  乘以权重矩阵  W_{hh}
    •    将以上两部分相加,再加上偏置  b_{ih}  和  b_{hh} ,形成一个新的隐藏状态 h_1
    •    使用激活函数  \tanh 来处理这个加权和,使得输出值限制在 -1 到 1 之间。
得到的隐藏状态  h_1  就包含了输入“我”的信息,记住了第一步的内容。​​​​​​​

时间步2:处理“爱”

输入: 当前时间步的输入是“爱”的向量  x_2 ,同时有前一步的隐藏状态 h_{1,3}

加权和:​​​​​​​RNN会计算“我”的输入  x_1  和初始隐藏状态 h_{1,3} 的加权和:

h_2 = \tanh(W_{ih} x_2 + b_{ih} + W_{hh} h_{1,3} + b_{hh})

这一步的计算步骤与第一个‘我’时间步类似,但是这次隐藏状态  h_{1,3}   不是全零,而是来自于前一个时间步第三层的输出。RNN会将“爱”的信息和“我”的信息结合,生成一个新的隐藏状态  h_2
解释:通过这种方式,RNN在第二个时间步不仅考虑了“爱”的输入,还记住了之前输入“我”的信息。因此, h_2  包含了“我”和“爱”两个词的上下文信息。

​​​​​​​

时间步3:处理“你”

输入: 当前时间步的输入是“你”的向量  x_3 ,同时有前一个时间步的隐藏状态 h_{2,3}  。

加权和:RNN继续计算“你”的输入  x_3  和隐藏状态  h_{2,3}  的加权和:

h_3 = \tanh(W_{ih} x_3 + b_{ih} + W_{hh} h_{2,3} + b_{hh})

最终生成的隐藏状态  h_{3,3}  包含了“我”、“爱”、“你”这三个词的信息。此时,RNN已经处理完了整个序列,它对这个句子的上下文有了完整的理解。

4. 输出层(可选)

在每一个时间步,RNN除了更新隐藏状态,还可以产生一个输出。这通常是通过输出层(例如全连接层)来实现。假设我们在每个时间步预测下一个单词:

• 在处理“我”时,预测下一个单词可能是“爱”。

• 在处理“爱”时,预测下一个单词可能是“你”。

• 在处理“你”时,可能会预测句子的结束。

这一步通常会结合交叉熵损失(cross-entropy loss)来优化模型,使得RNN能够更准确地预测下一个词。

5. 设计思路总结

通过这个例子,我们可以看到 RNN 是如何利用循环结构来处理序列数据的。它的关键特点是隐藏状态的循环传播,每个时间步的计算不仅仅依赖于当前输入,还结合了之前时间步的信息。这种机制使得RNN能够捕捉序列中的上下文依赖。

通过三层的RNN,我们每个时间步的输入不仅依赖于当前词语的向量表示,还结合了前面时间步的隐藏状态。这样的设计确保了模型能够记住之前时间步的上下文信息,从而在序列任务中捕捉前后依赖关系。

每一层RNN不断更新隐藏状态,并将其传递给下一层,这种多层堆叠的方式能够提高模型的表达能力,使得模型在处理复杂的序列任务时表现更好。

6.RNN的关键步骤总结:

    1.    输入数据: 每个时间步接收当前的输入向量  x_t
    2.    隐藏状态:每个时间步保留和更新一个隐藏状态  h_t ,它结合了之前时间步的隐藏状态  h_{t-1}  和当前的输入。
    3.    激活函数:通过  \tanh   激活函数对加权和进行非线性变换。
    4.    循环传递:每一步的隐藏状态被传递到下一个时间步,形成“循环”结构。

通常而言,我们使用RNN 循环神经网络的时候都是只有一层循环层的,而不是多层循环。

每一层的 W ,b 是固定的对吗?​​​​​​​

是的,每一层的权重矩阵 W 和偏置项 b  是固定的,也就是说,同一层在处理不同的输入(例如“我”、“爱”、“你”)时,权重和偏置不发生变化。具体来说:

1.输入权重矩阵 W_{ih}  和输入偏置项  b_{ih}

  • ( W_{ih}):输入到隐藏状态的权重矩阵,表示如何将每个时间步的输入(例如“我”、“爱”、“你”对应的词向量)映射到隐藏状态。

  • (b_{ih}):输入到隐藏状态的偏置项。

  • 这两个参数在整个序列中的所有时间步都是共享的,也就是说,不管是“我”、“爱”还是“你”作为输入,它们使用的都是相同的 ( W_{ih}) 和 ( b_{ih} ) 值。​​​​​​​

2.隐藏状态权重矩阵 ( W_{hh}) 和隐藏状态偏置项 ( b_{hh})

  • ( W_{hh}):隐藏状态到隐藏状态的权重矩阵,表示如何将前一个时间步的隐藏状态 ( h_{t-1} ) 映射到当前时间步。

  • ( b_{hh} ):隐藏状态的偏置项。

  1. 同样,( W_{hh} ) 和 ( b_{hh} ) 也在所有时间步中共享,不管是处理“我”、“爱”还是“你”,它们使用的都是相同的权重和偏置值。

3. 注意⚠️:输入权重矩阵 W_{ih}  , b_{ih} 和  隐藏状态权重矩阵  W_{hh},  b_{hh} 并不是想等的,神经网络中的每一层的值和每一层的值也是不想等的。各自有各自的权重和偏置值,初始化的时候值是随机的,但是由于神经网络的反向传播梯度下降的方式,会根据每个batch 数据进行优化权重,相同的w,b 是说每个批次batch的每一层是确定好了值,那么不管输入的文字是什么,输入层和隐藏状态的 W 和 b 就不会再改变了~,然后等下一次batch 数据的时候,会是新的w,b

batch,epoch 在循环神经网络中指的是什么?

在循环神经网络(RNN)以及其他神经网络训练过程中,batchepoch是两个关键概念,涉及到如何将数据分块并进行多次训练。让我们逐一解释它们在循环神经网络中的含义。

1. Batch(批次)

  • 定义batch 是指在神经网络训练过程中,一次性输入到模型中的数据样本数量。由于整个训练数据集可能非常大,模型通常无法一次处理整个数据集,因此将数据分成多个小批次来进行训练。

  • 作用:在RNN中,每次前向传播和反向传播都是在一个batch上进行的。每处理完一个batch后,模型会根据这个batch的损失值来更新模型的参数(权重和偏置)。

  • 大小:通常称为 batch size,即每个batch中包含的样本数量。比如,如果你有1000个数据样本,而batch size设置为50,则每个batch包含50个样本,整个数据集会分成20个batch。

    例子:假设你有1000条股票数据,而batch size设为10。模型会在每次训练中处理10条数据,进行前向传播、反向传播,并更新权重。每处理完一个batch就进行一次参数更新。

2. Epoch(轮次/世代)

  • 定义epoch 是指将整个训练数据集通过神经网络模型进行一次完整的训练。也就是说,一个epoch意味着模型已经看过了所有的训练数据一次。

  • 作用:在循环神经网络中,每一个epoch意味着模型使用整个训练数据集完成了一轮训练。通常,模型需要进行多次epoch训练来优化权重,并逐步减少预测误差。每经过一个epoch,模型会不断调整权重和偏置,以学习到更好的参数。

  • 多次迭代:通常,一个epoch并不意味着模型已经收敛(即找到了最佳参数)。通常会训练多个epoch,以确保模型能够更好地拟合数据。

    例子:如果你的数据集有1000条记录,batch size为100,那么一个epoch就是处理10个batch,直到所有的1000条数据都被模型“看过”一次。如果你设置训练20个epoch,那模型将会遍历整个数据集20次。

Batch和Epoch的关系

  • 一个epoch:是对整个训练集的完整处理一次,可能需要处理多个batch。比如,如果你的训练集有1000条数据,batch size为100,那么一个epoch由10个batch组成。

  • 一个batch:是对模型一次前向传播和反向传播的单位。在每个batch后,模型的参数会更新一次。

总结

  • Batch:在循环神经网络中,每个batch是训练模型的基本单位,包含一部分数据样本。每次处理一个batch后,模型会更新参数。

  • Epoch:一个epoch是指对整个训练集完成一次训练。通常,模型需要经过多次epoch才能学习到合适的参数。

Batch和epoch的调优取决于数据集的大小、模型的复杂度和计算资源。通常较大的batch size会更快,但可能需要更多的内存,而多次epoch有助于模型收敛。

​​​​​​​循环神经网络中的权重和偏置共享指的是,在一个batch(批次,指的是小部分数据) 中值是固定的,下一个批次的时候是新的w,b 对吗,尽管他们属于同一个epoch(一次完整的数据训练) ?

我们详细解释RNN中的权重和偏置共享的过程。

1. 权重和偏置在一个batch中的共享性

在RNN(循环神经网络)中,权重 (W) 和偏置 (b) 在同一个batch中处理所有输入序列时,是共享的。这意味着在一次前向传播中,无论输入序列的不同时间步(比如“我”、“爱”、“你”),它们都使用相同的权重和偏置进行计算。

  • 共享的概念:无论处理的哪个时间步或者哪个输入单元,模型使用的权重 (W)(输入权重矩阵和隐藏状态权重矩阵)和偏置 (b) 都是一样的。这使得RNN在整个序列上保持一致的参数,从而能够捕捉序列中前后时间步的依赖关系。

2. 每个batch后权重更新

当一个batch完成前向传播和反向传播后,模型会更新权重和偏置。这是通过反向传播算法(BPTT:Backpropagation Through Time)进行的。

  • 梯度下降和权重更新:通过计算每个batch中的损失,模型会计算损失关于权重和偏置的梯度,接着通过梯度下降算法来更新参数(权重 (W) 和偏置 (b))。因此,在下一个batch中,权重和偏置将是更新后的值

3. 同一个epoch中的不同batch:权重是否共享?

  • 答案是:不共享。尽管多个batch属于同一个epoch,但在每个batch后,权重 (W) 和偏置 (b) 都会根据前一批次的梯度更新。这意味着,在同一个epoch中的不同batch之间,权重和偏置是不同的,因为它们会在每次batch训练后更新。

  • 例如:

    • 在第1个batch中,RNN使用初始的权重 (W_{(0)}) 和偏置 (b_{(0)}) 处理数据。

    • 完成第1个batch后,模型更新权重 (W_{(1)}) 和偏置 (b_{(1)}),然后使用它们来处理第2个batch。

4. 权重和偏置更新与共享的关系

  • 权重和偏置在同一个batch中的前向传播时是共享的,这意味着在处理同一批次的数据时,RNN每个时间步用相同的参数计算。

  • 但在不同batch之间,权重和偏置是更新的,不再共享。虽然它们属于同一个epoch,但每个batch后,模型的参数都根据梯度更新,因此每个batch的权重和偏置都会变化。

总结:

  • 权重和偏置的共享性:在一个batch中的所有时间步共享相同的权重和偏置,即在同一个batch中,无论是处理“我”、“爱”、“你”,使用的权重和偏置都是一样的。

  • 权重和偏置的更新:在每个batch完成训练后,模型的权重和偏置会通过梯度下降进行更新。因此,在不同的batch之间,权重和偏置是不同的

  • 同一个epoch中的不同batch:权重和偏置在同一个epoch内的不同batch中并不共享,因为它们会在每个batch后更新。

为什么权重和偏置共享?

3.权重共享的原因

  • RNN的设计初衷就是处理序列数据,模型希望在每个时间步都能应用相同的转换规则。因此,权重共享意味着RNN在处理每个时间步的输入时,应用相同的计算机制,从而让模型具有很好的泛化能力,能够处理任意长度的序列。

  1. 减少参数的数量

    • 如果每个时间步都有不同的权重矩阵,那么整个网络的参数数量将非常庞大,训练过程会变得更加复杂,容易过拟合。共享权重能够显著减少需要学习的参数,使得模型在合理的计算资源内可以处理更长的序列。

总结:

  • 同一层的权重矩阵 ( W_{ih}, W_{hh} ) 和偏置项 ( b_{ih}, b_{hh} ) 是固定的,在处理整个序列中的每个时间步时都是共享的。

  • 输入“我”、“爱”、“你”时使用相同的权重和偏置,不同时间步只改变输入向量和前一个时间步的隐藏状态。

这个设计确保了RNN能够高效地处理序列数据,并捕捉到前后文之间的关系。

循环神经网络中的真实值是啥,预测值是啥?

在循环神经网络(RNN)中,真实值预测值是用于衡量模型预测准确性的重要概念。它们分别代表模型的期望输出和模型的实际输出。

1. 真实值(Ground Truth)

  • 定义:真实值是模型在训练或评估过程中期望输出的值。它是已知的正确答案,通常从标注好的训练数据中获得。

  • 例子

    • 文本分类:如果你在处理情感分析任务,真实值就是每个文本对应的标签,比如“正面”或“负面”。

    • 时间序列预测:在股票价格预测中,真实值是历史上实际的股票价格。

    • 语言建模:在预测句子中下一个单词时,真实值就是输入序列后续的正确单词。

2. 预测值(Predicted Value)

  • 定义:预测值是模型根据输入数据计算出的输出,通常是通过前向传播(forward propagation)得到的结果。它是模型试图逼近真实值的结果。

  • 例子

    • 文本分类:模型在处理文本分类时,会输出一个概率分布,表示输入文本属于各个分类的概率。预测值是模型选择的概率最高的分类标签。

    • 时间序列预测:对于股票价格预测,预测值是模型根据过去的数据对未来价格的估计。

    • 语言建模:在预测句子中下一个单词时,模型给出的预测值是最有可能的下一个词的概率。

3. 真实值与预测值的关系

  • 在训练过程中,损失函数用于比较真实值和预测值的差异,损失函数越小,说明模型的预测越接近真实值。模型的目标是通过最小化损失函数,使预测值尽可能接近真实值。

  • 举例

    • 假设你有一段文本 “我爱你”,并使用RNN进行下一个词的预测:

      • 真实值:句子中的下一个词,如“爱”。

      • 预测值:模型根据“我”这个输入,预测下一个最有可能的词。如果模型预测的词是“喜欢”,则预测值就是“喜欢”。

通过优化模型的参数(如权重和偏置),模型可以逐渐调整预测值,越来越接近真实值,从而提高其准确性。

循环神经网络中的损失函数是什么?

循环神经网络(RNN)中,损失函数是用于衡量模型预测值与真实值之间的差异,并在反向传播过程中帮助调整权重以提高模型性能。适用于循环神经网络的损失函数主要根据任务的类型来选择。以下是几种常见且适用于RNN的损失函数:

1. 交叉熵损失(Cross-Entropy Loss)

  • 适用任务分类任务,特别是语言建模、文本生成、情感分析等自然语言处理(NLP)任务。

  • 定义:交叉熵损失衡量两个概率分布之间的差异。对于分类问题,交叉熵损失函数通过衡量预测类别分布和真实类别标签之间的差距,来优化模型的性能。

  • RNN中的应用:RNN在处理序列分类任务多类别词预测时,交叉熵损失是首选。例如,在语言建模中,RNN逐个时间步预测下一个单词,使用交叉熵损失衡量每个时间步的预测结果。

2. 稀疏分类交叉熵(Sparse Categorical Cross-Entropy)

  • 适用任务多类别分类任务,与交叉熵类似,但标签是整数编码,而不是独热编码(one-hot encoding)。

  • 定义:稀疏分类交叉熵是交叉熵的一种变体,适用于类别数量较大的情况(如词汇表非常大的语言模型)。它可以直接使用整数索引的标签,避免了独热编码的开销。

  • RNN中的应用:在处理带有大量类别的文本或序列预测时,RNN可以通过稀疏交叉熵来优化性能,比如在大规模词汇表的自然语言处理中预测下一个词。

3. 均方误差(MSE, Mean Squared Error)

  • 适用任务回归任务,如时间序列预测、金融数据预测等。

  • 定义:MSE衡量模型预测值与真实值之间的平方差的平均值,用于回归任务中连续值的预测。

  • RNN中的应用:在时间序列预测中,RNN逐个时间步预测连续值(如股票价格或温度),使用MSE作为损失函数来衡量预测值和真实值的差异。

4. 对数似然损失(Log-Likelihood Loss)

  • 适用任务:时间序列中的序列生成任务,特别是生成式模型如RNN生成文本或语言模型。

  • 定义:对数似然损失用于评估生成模型的输出序列与真实序列的匹配程度。模型通过最大化生成序列的对数似然,优化其生成能力。

  • RNN中的应用:RNN生成文本序列时,通过最大化生成的每一个词的对数似然来进行优化。例如,在机器翻译中,RNN会根据输入序列生成目标语言的输出序列。

5. CTC损失(Connectionist Temporal Classification Loss)

  • 适用任务语音识别手写识别等任务,输入与输出的长度不对齐。

  • 定义:CTC损失适用于输入长度和输出长度不匹配的序列任务。它允许模型在没有精确时间步标注的情况下,对变长序列进行预测。

  • RNN中的应用:CTC损失常用于语音识别任务中,输入是一段语音信号,输出是对应的文字序列。RNN使用CTC损失来处理序列对齐问题。

6. 序列到序列损失(Seq2Seq Loss)

  • 适用任务序列到序列任务,如机器翻译、文本摘要生成等。

  • 定义:在序列到序列模型中,每个时间步都会有一个输出词,并且损失函数需要衡量每个时间步上的预测误差,常常是交叉熵损失的扩展,适用于多个输出时间步的累计损失。

  • RNN中的应用:在机器翻译或自动摘要生成中,RNN模型会逐时间步预测输出序列的下一个词,并通过累积多个时间步的损失进行优化。

总结:

适用于RNN的损失函数主要取决于具体的任务类型:

  • 分类任务:交叉熵损失、稀疏交叉熵损失。

  • 回归任务:均方误差(MSE)。

  • 序列生成和对齐任务:对数似然损失、CTC损失。

每种损失函数针对不同类型的任务都具有不同的优化目标。

循环神经网络中的梯度下降算法有哪些?

​​​​​​​目前常用:Adam优化器

循环神经网络(RNN)中,梯度下降算法是用于优化网络参数(如权重和偏置)的关键算法。RNN模型通过最小化损失函数来调整这些参数,梯度下降算法帮助模型找到使损失最小的参数组合。RNN中的梯度下降算法主要用于通过反向传播更新参数。

1. 梯度下降在RNN中的角色

梯度下降是深度学习中常见的优化算法,用于通过最小化损失函数来调整模型的参数。在RNN中,模型通过前向传播计算输出,然后通过反向传播(Backpropagation Through Time,BPTT)算法计算梯度,并使用梯度下降算法来更新参数。

  • 前向传播:模型接受输入数据,通过网络进行前向传播,生成预测值。

  • 损失计算:计算预测值和真实值之间的差异,通常使用交叉熵损失或均方误差损失。

  • 反向传播:通过BPTT,计算各个时间步上参数的梯度,将误差反向传播到每一个时间步,最后通过梯度下降算法更新权重和偏置。

2. BPTT(Backpropagation Through Time)

RNN中特有的梯度下降算法是时间上的反向传播(BPTT),这是梯度下降的一种变体,专门用于处理RNN的时间依赖性。由于RNN会在每个时间步上更新隐藏状态并与前一时间步的信息共享,因此在训练过程中,误差必须沿时间轴反向传播。

BPTT的工作原理

  1. 前向传播:RNN处理输入序列的每个时间步,并在每个时间步计算输出和隐藏状态。

  2. 反向传播:通过BPTT,计算每个时间步的误差,并将误差通过时间反向传播。然后通过梯度下降更新权重,使损失函数逐步减小。

  3. 梯度更新:每个batch中,RNN会根据梯度下降法更新权重,逐步优化模型。

3. 常见的梯度下降算法

在RNN的训练中,最常用的梯度下降算法包括以下几种:

1. 随机梯度下降(SGD,Stochastic Gradient Descent)
  • 特点:每次更新参数时,SGD只使用一个样本或小批量数据计算梯度。它的更新频率较高,适合处理大规模数据集,但容易受噪声影响。

  • 优点:计算速度快,适合在线学习。

  • 缺点:收敛速度较慢,且在复杂任务上表现不如其他优化算法稳定。

2. Adam优化器(Adaptive Moment Estimation)
  • 特点:Adam结合了动量(Momentum)RMSProp优化方法的优点,通过自适应学习率调整,能够加快收敛速度并避免振荡。

  • 优点:Adam是当前使用最广泛的优化算法之一,尤其在RNN中表现良好。它适合处理长序列任务,能够更好地处理复杂数据集,适应不同梯度变化。

  • 应用:在RNN、LSTM等模型中,Adam常常作为默认的优化算法,能够高效处理梯度消失和梯度爆炸问题。

3. RMSProp(Root Mean Square Propagation)
  • 特点:RMSProp是一种自适应学习率优化算法,能够根据过去的梯度平方平均值动态调整学习率,避免步长过大或过小。

  • 优点:RMSProp对于RNN中的梯度消失问题有一定的缓解作用,适合处理长时间序列任务。

  • 应用:在语音识别、自然语言处理等长序列预测任务中常使用RMSProp作为优化算法。

4. Adagrad(Adaptive Gradient Algorithm)
  • 特点:Adagrad会为每个参数单独调整学习率,使得稀疏特征有较大的学习率,常用在文本数据中。

  • 优点:对于处理高维稀疏数据较为有效,适用于RNN在自然语言处理任务中的优化。

  • 缺点:随着训练进行,学习率会逐渐减小,容易导致训练提前停止。

4. RNN中的梯度问题:梯度消失和梯度爆炸

在训练RNN时,梯度消失梯度爆炸是常见的问题,特别是在长序列中:

  • 梯度消失:随着时间步的增加,梯度会变得越来越小,导致RNN难以学习到长时间的依赖。

  • 梯度爆炸:梯度在反向传播中可能会迅速增大,导致模型的参数更新过大,使模型不稳定。

为了解决这些问题,常用的方法有:

  • 梯度裁剪(Gradient Clipping):限制梯度的最大值,避免梯度爆炸。

  • LSTM 和 GRU:这些是RNN的变体,通过门控机制缓解了梯度消失问题,能够捕捉长时间依赖。

5. 常用优化算法在RNN中的使用频率

  • Adam 是目前使用最多的优化算法,适合处理长时间序列和复杂任务。

  • RMSProp 也较为常见,特别是在自然语言处理和序列生成任务中表现良好。

  • SGD 通常用于简单任务或模型结构较为轻量的场景,但在RNN中表现不如Adam和RMSProp稳定。

总结

在循环神经网络中,梯度下降算法的选择对于模型性能至关重要。目前Adam优化器是使用最广泛的算法,因为它能够动态调整学习率,并且适应复杂的长序列任务。其他算法如RMSPropSGD也被广泛使用,特别是在不同的场景中。

好了我们的循环网络层的原理就讲解完毕了,接下来我们会用一个文本生成的案例,去讲解如何使用pytorch 来应用 RNN 循环神经网络进行文本生成。

文本生成案例讲解:

好了,具体代码可以自己思考下,我会另开一篇文章去写完整的代码过程,预知后续如何,请听下回分解~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2173634.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

转做大模型开发,能不能挽救职业生涯?

大模型算是当之无愧最火的一个方向了&#xff0c;算是新时代的风口。有小伙伴觉得&#xff0c;既然是新领域、新方向&#xff0c;那么&#xff0c;人才需求肯定比较大&#xff0c;相应的人才缺乏&#xff0c;竞争也会更少&#xff0c;那转行去做大模型是不是一个更好的选择呢&a…

Leetcode 2320. 统计放置房子的方式数

原题链接&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 一条街道上共有 n * 2 个 地块 &#xff0c;街道的两侧各有 n 个地块。每一边的地块都按从 1 到 n 编号。每个地块上都可以放置一所房子。 现要求街道同一侧不能存在两所房子相邻的情况&#xff0c;请你计算并…

高并发内存池(五):ThreadCache、CentralCache和PageCache的内存回收机制 及 释放内存过程的调试

目录 ThreadCache的内存回收机制 补充内容1 补充内容2 补充内容3 新增关键函数ListTooLong CentralCache的内存回收机制 补充内容1 新增关键函数MapObjectToSpan 新增关键函数ReleaseListToSpans PageCache的内存回收机制 补充内容1 补充内容2 新增关键函数Releas…

初试React前端框架

文章目录 一、React概述二、React核心特性1、组件化设计2、虚拟DOM3、生态系统 三、实例操作1、准备工作2、创建项目结构3、启动项目4、编写React组件5、添加React样式6、运行项目&#xff0c;查看效果 四、实战小结 一、React概述 大家好&#xff0c;今天我们将一起探索React…

c语言 memmove模拟和momcpy模拟的比较

1.memcpy&#xff08;两者引用的头文件均是<stdlib.h>) 这个函数适用于开辟了两个空间的字符串数组&#xff0c;无法进行自身与自身的拷贝。eg: char* my_memcpy(void* s1, void* s2,int count) {char* start s1;while (count--) {*(char*)s1 *(char*)s2;(char*)s1 …

windows10使用bat脚本安装前后端环境之nginx注册服务

首先需要搞清楚nginx本地是怎么安装配置的、然后在根据如下步骤编写bat脚本&#xff1a; 思路 1.下载nginx-1.26 zip压缩包安装包 2.调整conf配置 3.借助winsw将nginx应用注册为服务&#xff0c;winsw下载地址 然后重命名nginx_service.exe 4.配置nginx-service.xml 5.注册wi…

【运维资料】系统运维管理方案(Doc原件2024)

1 编制目的 2 系统运行维护 2.1 系统运维内容 2.2 日常运行维护方案 2.2.1 日常巡检 2.2.2 状态监控 2.2.3 系统优化 2.2.4 软件系统问题处理及升级 2.2.5 系统数据库管理维护 2.2.6 灾难恢复 2.3 应急运行维护方案 2.3.1 启动应急流程 2.3.2 成立应急小组 2.3.3 应急处理过程 …

【数据结构】栈和队列(有完整的模拟实现代码!)

1、栈 1.1 栈的概念及结构 栈&#xff1a;一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶&#xff0c;另一端称为栈底。栈中的数据元素遵守后进先出LIFO&#xff08;Last In First Out&#xff09;的原则。…

爬取元气手机壁纸简单案例(仅用于教学,禁止任何非法获利)

爬虫常用的库 爬虫&#xff08;Web Scraping&#xff09;是一种从网页上提取数据的技术。在 Python 中&#xff0c;有许多库可以帮助实现这一目标。以下是一些常用的爬虫库&#xff0c;以及对 BeautifulSoup 的详细介绍。 常用爬虫库 1.Requests ​ a.功能&#xff1a;用于发…

利用 Llama-3.1-Nemotron-51B 推进精度-效率前沿的发展

今天&#xff0c;英伟达™&#xff08;NVIDIA&#xff09;发布了一款独特的语言模型&#xff0c;该模型具有无与伦比的准确性和效率性能。Llama 3.1-Nemotron-51B 源自 Meta 的 Llama-3.1-70B&#xff0c;它采用了一种新颖的神经架构搜索&#xff08;NAS&#xff09;方法&#…

MySQL的安装(环境为CentOS云服务器)

卸载内置环境 我们初期使用root账号&#xff0c;后期再切换成普通账号 使用 ps axj | grep mysql 查看系统中是否有MySQL相关的进程 使用 systemctl stop mysqld 关停进程 使用 rpm -qa | grep mysql 查看MySQL相关的安装包 使用 rpm -qa | grep mysql | xargs yum -y remo…

试用Debian12.7和Ubuntu24.4小札

Debian GNU/Linux 12 (bookworm)和Ubuntu 24.04.1 LTS是现阶段&#xff08;2024年9月26日&#xff09;两个发行版的最新版本。Ubuntu Server版本默认就不带桌面&#xff08;ubuntu-24.04-live-server-amd64.iso&#xff09;&#xff0c;这个默认就是最小化安装&#xff08;安装…

长芯微LPQ76930锂电池组保护芯片完全P2P替代BQ76930

LPQ76930系列芯片可作为 3-15 节串联电池组监控和保护解决方案的一部分。通过 TWI 通信&#xff0c;MCU 可以使用 LPQ76930 来执行电池管理功能1&#xff0c;例如监测&#xff08;电池电压、电池 组电流、电池组温度&#xff09;、保护&#xff08;控制充电/放电 FET&#xff0…

java中的强软弱虚

在java中对象的引用有强、软、弱、虚四种&#xff0c;这些引用级别的区别主要体现在对象的生命周期、回收时机的不同。 文章目录 准备工作1. 设置内存2. 内存检测 强引用软引用弱引用虚引用 准备工作 1. 设置内存 为方便调试&#xff0c;将内存设置为16MB 依次点击菜单栏的R…

springboot基于学习行为的学生选课成绩分析系统设计与实现

目录 功能介绍使用说明系统实现截图开发核心技术介绍&#xff1a;开发步骤编译运行核心代码部分展示开发环境需求分析详细视频演示源码获取 功能介绍 学生 课程学习行为数据录入: 学生填写每门课程的学习时长、学习态度、课后作业质量等。 课程学习行为数据修改: 学生可修改已…

基于SpringBoot+Vue的大学生公考服务平台

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码 精品专栏&#xff1a;Java精选实战项目…

php 平滑重启 kill -SIGUSR2 <PID> pgrep命令查看进程号

有时候我们使用nginx 大家都知道平滑重启命令: /web/nginx/sbin/nginx -s reload 但大家对php-fpm 重启 可能就是简单暴力的kill 直接搞起了 下面介绍一个sh 文件名保存为start_php.sh 来对php-fpm 进行平滑重启 #!/bin/bash# 检查 PHP-FPM 是否运行 if ! pgrep php-…

JAVA开源项目 技术交流分享平台 计算机毕业设计

本文项目编号 T 053 &#xff0c;文末自助获取源码 \color{red}{T053&#xff0c;文末自助获取源码} T053&#xff0c;文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析 六、核心代码6.1 新…

论文阅读(十一):CBAM: Convolutional Block Attention Module

文章目录 1.Introduction2.Convolutional Block Attention ModuleExperimentsConclusion 论文题目&#xff1a;CBAM: Convolutional Block Attention Module&#xff08;CBAM&#xff1a;卷积注意力机制&#xff09;   论文链接&#xff1a;点击跳转   代码链接&#xff1a…

运维,36岁,正在经历中年危机,零基础入门到精通,收藏这一篇就够了

我今年36岁&#xff0c;运维经理&#xff0c;985硕士毕业&#xff0c;目前正在经历中年危机&#xff0c;真的很焦虑&#xff0c;对未来充满担忧。不知道这样的日子还会持续多久&#xff0c;突然很想把这些年的经历记录下来&#xff0c;那就从今天开始吧。 先说一下我的中年危机…