白话RNN系列(一)

2024-09-06 05:38
文章标签 系列 rnn 白话

本文主要是介绍白话RNN系列(一),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

RNN,循环神经网络,全称Recurrent Neural Network。

本文,从RNN的基本原理讲起,会探讨RNN的前向传播和反向传播,并通过一些浅显易懂的小例子,展示RNN这个东东的神奇之处,尽最大可能以通俗易懂的方式,让看到本文的童鞋都能够掌握RNN。

1:RNN的基本原理

即便是RNN,也依旧脱离不了神经网络的基本架构,换句话说,我们看RNN的时候,一定要记住一句,它不过是高级一些的神经网络而已,其深层也不过是神经网络而已,没什么可怕的。

我们先拿个神经网络来做例子:

è¿éåå¾çæè¿°

上图展示的是最基础的神经网络,即全连接神经网络,除了最左侧的输入层和最右侧的输出层,其他均为隐藏层,其之所以叫做全连接神经网络,从图中我们也可以看出,输入元素会与隐藏层的每一个节点产生连接,同时,隐层的每个节点又会与下一层的所有节点产生连接,因此,叫做全连接神经网络。

而我们神经网络最终的目的是什么?求取的实际上是一个权重矩阵。

举个例子来说,如上图,我们可以看到输入层有五个节点,可以假设一个输入有五个特征的向量,如X=(x1,x2,x3,x4,x5)。

而隐藏层只有四个节点,这时候,我们需要一个维度为5*4的权重矩阵W,将其转化为4个特征的向量,而这个权重矩阵,就是我们最终需要的东西。

有些童鞋会提到偏置,我们这里不予考虑,或者可以将其简化入权重矩阵内。

那是不是神经网络就是这一层层的权重矩阵相乘,最后得到一个我们需要维度的输出呢?比如说最终我们需要做一个softmax的多分类,比如常见的手写字体识别,是不是最后输出一个十个维度的的向量,交给softmax就可以了呢?

显然不是。

这种方式下,可以看出,就成了完全的线性变换,如输入层与第一隐层之间的权重矩阵为W1,第一隐层与第二隐层之间的权重矩阵为W2,循环往复,最终的输出可能为:

Y = W1 * W2 * ···Wn * X

前面的多个矩阵的乘积,与一个单独的矩阵没什么本质区别,换句话说,我们多个隐层的存在是没有意义的,我们完全可以用一个简单的线性变换来完成我们的工作。

讨论到此结束,大家都去琢磨线性变换就可以了。

但是,神经网络绝不是那么简单的,其在线性变换的同时,于隐藏层的神经元内,做了非线性变换,线性变换与非线性变换的结合,最终完成了很多不可思议的任务。

必须注意,直到这里,我们谈论的也只是全连接神经网络,而其妙处,则是在隐藏层神经元上,我们看下隐藏层神经元的结构:

这是简单的M-P神经元模型,图片来自于周志华老师的机器学习一书;这里,我们单独看隐藏层的一个节点,其他节点的处理雷同。

上面所说的输入层与第一隐层之间的权重矩阵,其维度为5*4,原因在于,我们输入的特征是5维的,而隐藏层神经元的个数为4层;换算到这里,就相当于n=5,我们用一个隐藏层节点来分析的话,会发现对于这个节点来说,我们输入向量实际上是左乘了一个5维的向量,得到了一个实数。

向量乘法很简单: (1 * 5) * (5 * 1),得到一个实数;前面的1 * 5 是输入层与第一个神经元之间的权重关系,那么,如果隐藏层神经元为4个的话,我们把四个权重向量堆叠成权重矩阵,自然而然得到了一个 4 * 5 的权重矩阵;而这个权重矩阵与输入向量乘积,得到的则是一个 4 * 1的向量,正好对应于隐藏层神经元,每个节点的输出。

我们在吴恩达老师的课程中会看到,其写的是权重矩阵的转置,即这里的4 * 5 是权重矩阵的转置,实际上的权重矩阵应该是5 * 4的矩阵。

但是,这对于问题的理解并无影响,只是写起来更加方便,我们可以轻松地通过输入层的特征数目 * 隐藏层神经元的数目,得到第一个权重矩阵的维度。

在代码中的实现形如(手写字体的部分代码):

x = tf.placeholder(tf.float32, [None, 784])
y = tf.placeholder(tf.float32, [None, 10])
keep_prob = tf.placeholder(tf.float32)
# 自己定义一个学习率
lr = tf.Variable(0.001, dtype=tf.float32)# 设计第一层神经网络 : 784 * 2000
# 因为输入样本是784维向量,而输出时2000个神经元
W1 = tf.Variable(tf.truncated_normal([784, 500], stddev=0.1))
b1 = tf.Variable(tf.zeros([500]) + 0.1)
L1 = tf.nn.tanh(tf.matmul(x, W1) + b1)
L1_drop = tf.nn.dropout(L1, keep_prob)

手写字体识别的输入向量,是1 * 784维的,即具有784个特征的向量,而我们的权重矩阵,则是784 * 500维的,这种写法更好理解一些。

插了一些关于权重矩阵的闲话,我们继续看隐藏层神经元中隐藏的非线性变换。

常见的有sigmoid,tanh,relu等,我们通过矩阵与向量相乘得到的输入,在每个隐藏层节点内都会经过非线性变换,才能作为下一层神经元节点的输入。

神经网络就是这么简单,没什么神秘的地方,说起来加入了那么多东西,其实质也就是我们平日里见到的线性和非线性变换而已。

说了这么多,我们认真看下全连接神经网络到底存在什么缺点,才催生出后续的卷积神经网络和循环神经网络。

1:全连接,导致权重矩阵过大,同时特征会被割裂。

简单说,如果我们输入的是非常大的图片,比如1920 * 1920这种高清图片,光是输入特征的维度就高达百万级别,再加上隐藏层的的维度,比如说隐藏层设置128个节点,那第一个权重矩阵的维度就高达千万个参数,别忘了,我们还有偏置......

这个代价很高,如果全连接神经网络的层数再多一些,那计算代价,高的可怕,所以我们平常用到的全连接神经网络速度慢,就可以理解了。

特征割裂,是我对于不考虑特征之间相互关系的一个称呼,能看得出来,全连接建立在一个假设的基础上,即各个特征之间完全不存在相关关系,因此对于每个隐藏层节点而言,都有自己的权重,在一些情况下,这是合理的,但很遗憾,现在大多数数据都存在相关性,如果完全不考虑其相关关系,不仅权重矩阵过大,计算代价高,往往还不会得到理想的效果。

所以权值共享的概念被提了出来,在卷积神经网络和循环神经网络里,我们都可以看到其踪迹。

2:隐层内部的神经元互相之间,其实是没有任何连接的。

很简单,上面的图都可以看到这点,每个神经元节点的输出,只会不断向后传递,同一层神经元之间,不存在任何的相互关联。

乍一看,没啥问题;但随着我们处理的任务越来越多,尤其是NLP的高速发展,神经网络在NLP方面的缺陷就暴露出来,为什么?

每个人说一句话,都会掺杂进自己先前的背景知识,即记忆,一句话的前言和后语,通常都是有联系的,可惜的是,当前的神经网络解决这类问题效果不是很好,因为其不存在记忆。

在这种情况下,有人提出了循环神经网络,其实质在于,在隐藏层的神经元节点之间加入了联系,产生的效果就是,第一个神经元节点的输出,可以被第二个神经元节点获取到;同理,最后一个隐层神经元节点会接收到几乎上面所有神经元节点的输出(只不过最近的神经元肯定对其输入影响最大而已)。

通俗来说,就是RNN在分析每一句话的时候,会尽最大可能考虑前面用户输入的每个字,以期望达到一个比较好的效果,这是非常好的设想,也的确达到了不错的效果。

而这个RNN,就是我们接下来需要探讨的重点;其内部不仅有循环输入,同样也加入了权值共享,对于我们深入对其他神经网络的理解,很有帮助。

这篇关于白话RNN系列(一)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1141152

相关文章

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

科研绘图系列:R语言扩展物种堆积图(Extended Stacked Barplot)

介绍 R语言的扩展物种堆积图是一种数据可视化工具,它不仅展示了物种的堆积结果,还整合了不同样本分组之间的差异性分析结果。这种图形表示方法能够直观地比较不同物种在各个分组中的显著性差异,为研究者提供了一种有效的数据解读方式。 加载R包 knitr::opts_chunk$set(warning = F, message = F)library(tidyverse)library(phyl

【生成模型系列(初级)】嵌入(Embedding)方程——自然语言处理的数学灵魂【通俗理解】

【通俗理解】嵌入(Embedding)方程——自然语言处理的数学灵魂 关键词提炼 #嵌入方程 #自然语言处理 #词向量 #机器学习 #神经网络 #向量空间模型 #Siri #Google翻译 #AlexNet 第一节:嵌入方程的类比与核心概念【尽可能通俗】 嵌入方程可以被看作是自然语言处理中的“翻译机”,它将文本中的单词或短语转换成计算机能够理解的数学形式,即向量。 正如翻译机将一种语言

flume系列之:查看flume系统日志、查看统计flume日志类型、查看flume日志

遍历指定目录下多个文件查找指定内容 服务器系统日志会记录flume相关日志 cat /var/log/messages |grep -i oom 查找系统日志中关于flume的指定日志 import osdef search_string_in_files(directory, search_string):count = 0

GPT系列之:GPT-1,GPT-2,GPT-3详细解读

一、GPT1 论文:Improving Language Understanding by Generative Pre-Training 链接:https://cdn.openai.com/research-covers/languageunsupervised/language_understanding_paper.pdf 启发点:生成loss和微调loss同时作用,让下游任务来适应预训

Java基础回顾系列-第七天-高级编程之IO

Java基础回顾系列-第七天-高级编程之IO 文件操作字节流与字符流OutputStream字节输出流FileOutputStream InputStream字节输入流FileInputStream Writer字符输出流FileWriter Reader字符输入流字节流与字符流的区别转换流InputStreamReaderOutputStreamWriter 文件复制 字符编码内存操作流(

Java基础回顾系列-第五天-高级编程之API类库

Java基础回顾系列-第五天-高级编程之API类库 Java基础类库StringBufferStringBuilderStringCharSequence接口AutoCloseable接口RuntimeSystemCleaner对象克隆 数字操作类Math数学计算类Random随机数生成类BigInteger/BigDecimal大数字操作类 日期操作类DateSimpleDateForma

Java基础回顾系列-第三天-Lambda表达式

Java基础回顾系列-第三天-Lambda表达式 Lambda表达式方法引用引用静态方法引用实例化对象的方法引用特定类型的方法引用构造方法 内建函数式接口Function基础接口DoubleToIntFunction 类型转换接口Consumer消费型函数式接口Supplier供给型函数式接口Predicate断言型函数式接口 Stream API 该篇博文需重点了解:内建函数式

Java基础回顾系列-第二天-面向对象编程

面向对象编程 Java类核心开发结构面向对象封装继承多态 抽象类abstract接口interface抽象类与接口的区别深入分析类与对象内存分析 继承extends重写(Override)与重载(Overload)重写(Override)重载(Overload)重写与重载之间的区别总结 this关键字static关键字static变量static方法static代码块 代码块String类特

Java基础回顾系列-第六天-Java集合

Java基础回顾系列-第六天-Java集合 集合概述数组的弊端集合框架的优点Java集合关系图集合框架体系图java.util.Collection接口 List集合java.util.List接口java.util.ArrayListjava.util.LinkedListjava.util.Vector Set集合java.util.Set接口java.util.HashSetjava