lstm代码java lstm代码keras
好答案送分啊
作 者: precom (皮蛋)
创新互联建站坚信:善待客户,将会成为终身客户。我们能坚持多年,是因为我们一直可值得信赖。我们从不忽悠初访客户,我们用心做好本职工作,不忘初心,方得始终。10多年网站建设经验创新互联建站是成都老牌网站营销服务商,为您提供成都网站建设、网站设计、网站设计、H5页面制作、网站制作、品牌网站建设、微信平台小程序开发服务,给众多知名企业提供过好品质的建站服务。
其中的opDb.java
============================================
package ymbean;
import java.sql.*;
import java.util.*;
import java.text.*;
import com.chinazjj.sql.dsql;
import com.chinazjj.util.dutil;
//其他的包dsql,dutil中的内容我就不再贴了,在本文件中用到的两个函数都很简
单
public class opDb {
private String inquire_value="",inquire_item="",disptype="",inqtyp
e="";
private String inquire_num="",inquire_addr="",inquire_name="";
private dutil ldutil=new dutil();
public opDb() {
}
public void setinquire_item(String name) { inquire_item= name
;}
public void setinquire_value( String name ) { inquire_value = ldut
il.chineseToUnicode(name);}
public void setdisptype(String name) { disptype=name;}
public void setinqtype(String name) { inqtype=name;}
public void setinquire_num( String name ) { inquire_num = ldutil.c
hineseToUnicode(name);}
public void setinquire_addr( String name ) { inquire_addr = ldutil
.chineseToUnicode(name);}
public void setinquire_name( String name ) { inquire_name = ldutil
.chineseToUnicode(name);}
public String getinquire_dndata()
{
return "";
}
public ResultSet executeQuery(String sql)
{
ResultSet rs = null;
Statement lstmt = null;
try {
lstmt = connectdb();
rs = lstmt.executeQuery(sql);
System.out.println("executeQuery: "+sql);
} catch(SQLException ex) { System.err.println("executeQuery: " +
ex.getMessage());}
return rs;
}
public Statement getStmt()
{
Statement lstmt = null;
lstmt = connectdb();
return lstmt;
}
public String executeUpdate(String sql)
{
ResultSet rs = null;
Statement lstmt = null;
try {
lstmt = connectdb();
lstmt.executeUpdate(sql);
System.out.println("executeUpdate: "+sql);
lstmt.executeUpdate("commit");
}
catch(SQLException ex) { System.err.println("executeQuery: " + e
x.getMessage());
return(ex.getMessage());
}
return("executeUpdate ok");
}
public Statement connectdb()
{
Statement lstmt=null;
Connection conn=null;
final String connect_string="jdbc:oracle:thin:scott/tiger@192.168.
0.1:1521:clubdb";
final String driver_string="oracle.jdbc.driver.OracleDriver";
dsql mysql=new dsql();
lstmt=mysql.dconnectdb(driver_string,connect_string);
return lstmt;
}
public Statement connectdb(String connect_string)
{
Statement lstmt=null;
Connection conn=null;
final String driver_string="oracle.jdbc.driver.OracleDriver";
dsql mysql=new dsql();
lstmt=mysql.dconnectdb(driver_string,connect_string);
return lstmt;
}
//=========other function ===================================
public String getCurrentDate(String ldateform)
{
return(new SimpleDateFormat(ldateform).format(new java.util.Date(
)));
}
//========"/n" to ";br;" =====================================
//去掉奇怪的:
public String removeComment(String Content){
String makeContent=new String();
StringTokenizer strToken=new StringTokenizer(Content,"\n");
String tempToken=null;
while(strToken.hasMoreTokens()){
tempToken=strToken.nextToken();
if(tempToken.indexOf(":")!=0)
makeContent=makeContent+tempToken+"\n";
}
return makeContent;
}
//将/n转换成为回车;br;
public String addBr(String Content){
String makeContent=new String();
StringTokenizer strToken=new StringTokenizer(Content,"\n");
while(strToken.hasMoreTokens()){
makeContent=makeContent+";br;"+strToken.nextToken();
}
return makeContent;
}
//将;br;转换成为回车/n
public String addCr(String Content){
String makeContent=new String();
StringTokenizer strToken=new StringTokenizer(Content,";br;");
while(strToken.hasMoreTokens()){
makeContent=makeContent+"\n"+strToken.nextToken();
}
return makeContent;
}
//====================================================================
=====
public boolean getIdentify(String name1,String pwd1)
{
try
{
String sql="select * from club_users where username='" + name1 + "'
and password='" + pwd1 + "'";
ResultSet rs = executeQuery(sql);
if(rs.next()) { rs.close(); return(true);}
else { rs.close();return(false);}
}catch (Exception e) { return(false);}
}
public void counts(String pagename)
{
executeUpdate("update call_count set counts=counts + 1 where pagenam
e='"+pagename+"'");
}
//==================张家界市民虚拟社区管理============================
======
public String getDeptSuper(String vp) //取版主
{
String vst="未知";
try{
String sql="select administrator from club_cvcdept where deptno=
'"+vp+"'";
ResultSet rs = executeQuery(sql);
if(rs.next()) vst=rs.getString(1);
rs.close();
} catch (Exception e) {}
return vst;
}
public String getDeptName(String vp) //取版名
{
String vst="未知";
try{
String sql="select deptnote from club_cvcdept where deptno='"+vp
+"'";
ResultSet rs = executeQuery(sql);
if(rs.next()) vst=rs.getString(1);
rs.close();
} catch (Exception e) {}
return vst;
}
public String getUserEmail(String vp) //取社区用户email
{
String vst="未知";
try{
String sql="select email from club_users where username='"+vp+"'
";
ResultSet rs = executeQuery(sql);
if(rs.next()) vst=rs.getString(1);
rs.close();
} catch (Exception e) {}
return vst;
}
public Object getaValue(String vp) //取社区用户email及其他
{
Object vst=null;
try{
String sql=vp;
ResultSet rs = executeQuery(sql);
if(rs.next()) vst=rs.getObject(1);
rs.close();
} catch (Exception e) {}
return vst;
}
public String getsValue(String vp) //取社区用户email及其他
{
String vst="";
try{
String sql=vp;
ResultSet rs = executeQuery(sql);
if(rs.next()) vst=rs.getString(1);
rs.close();
} catch (Exception e) {}
return vst;
}
}//end opDb.java
参考资料:
人工神经网络概念梳理与实例演示
人工神经网络概念梳理与实例演示
神经网络是一种模仿生物神经元的机器学习模型,数据从输入层进入并流经激活阈值的多个节点。
递归性神经网络一种能够对之前输入数据进行内部存储记忆的神经网络,所以他们能够学习到数据流中的时间依赖结构。
如今机器学习已经被应用到很多的产品中去了,例如,siri、Google Now等智能助手,推荐引擎——亚马逊网站用于推荐商品的推荐引擎,Google和Facebook使用的广告排名系统。最近,深度学习的一些进步将机器学习带入公众视野:AlphaGo 打败围棋大师李世石事件以及一些图片识别和机器翻译等新产品的出现。
在这部分中,我们将介绍一些强大并被普遍使用的机器学习技术。这当然包括一些深度学习以及一些满足现代业务需求传统方法。读完这一系列的文章之后,你就掌握了必要的知识,便可以将具体的机器学习实验应用到你所在的领域当中。
随着深层神经网络的精度的提高,语音和图像识别技术的应用吸引了大众的注意力,关于AI和深度学习的研究也变得更加普遍了。但是怎么能够让它进一步扩大影响力,更受欢迎仍然是一个问题。这篇文章的主要内容是:简述前馈神经网络和递归神经网络、怎样搭建一个递归神经网络对时间系列数据进行异常检测。为了让我们的讨论更加具体化,我们将演示一下怎么用Deeplearning4j搭建神经网络。
一、什么是神经网络?
人工神经网络算法的最初构思是模仿生物神经元。但是这个类比很不可靠。人工神经网络的每一个特征都是对生物神经元的一种折射:每一个节点与激活阈值、触发的连接。
连接人工神经元系统建立起来之后,我们就能够对这些系统进行训练,从而让他们学习到数据中的一些模式,学到之后就能执行回归、分类、聚类、预测等功能。
人工神经网络可以看作是计算节点的集合。数据通过这些节点进入神经网络的输入层,再通过神经网络的隐藏层直到关于数据的一个结论或者结果出现,这个过程才会停止。神经网络产出的结果会跟预期的结果进行比较,神经网络得出的结果与正确结果的不同点会被用来更正神经网络节点的激活阈值。随着这个过程的不断重复,神经网络的输出结果就会无限靠近预期结果。
二、训练过程
在搭建一个神经网络系统之前,你必须先了解训练的过程以及网络输出结果是怎么产生的。然而我们并不想过度深入的了解这些方程式,下面是一个简短的介绍。
网络的输入节点收到一个数值数组(或许是叫做张量多维度数组)就代表输入数据。例如, 图像中的每个像素可以表示为一个标量,然后将像素传递给一个节点。输入数据将会与神经网络的参数相乘,这个输入数据被扩大还是减小取决于它的重要性,换句话说,取决于这个像素就不会影响神经网络关于整个输入数据的结论。
起初这些参数都是随机的,也就是说神经网络在建立初期根本就不了解数据的结构。每个节点的激活函数决定了每个输入节点的输出结果。所以每个节点是否能够被激活取决于它是否接受到足够的刺激强度,即是否输入数据和参数的结果超出了激活阈值的界限。
在所谓的密集或完全连接层中,每个节点的输出值都会传递给后续层的节点,在通过所有隐藏层后最终到达输出层,也就是产生输入结果的地方。在输出层, 神经网络得到的最终结论将会跟预期结论进行比较(例如,图片中的这些像素代表一只猫还是狗?)。神经网络猜测的结果与正确结果的计算误差都会被纳入到一个测试集中,神经网络又会利用这些计算误差来不断更新参数,以此来改变图片中不同像素的重要程度。整个过程的目的就是降低输出结果与预期结果的误差,正确地标注出这个图像到底是不是一条狗。
深度学习是一个复杂的过程,由于大量的矩阵系数需要被修改所以它就涉及到矩阵代数、衍生品、概率和密集的硬件使用问题,但是用户不需要全部了解这些复杂性。
但是,你也应该知道一些基本参数,这将帮助你理解神经网络函数。这其中包括激活函数、优化算法和目标函数(也称为损失、成本或误差函数)。
激活函数决定了信号是否以及在多大程度上应该被发送到连接节点。阶梯函数是最常用的激活函数, 如果其输入小于某个阈值就是0,如果其输入大于阈值就是1。节点都会通过阶梯激活函数向连接节点发送一个0或1。优化算法决定了神经网络怎么样学习,以及测试完误差后,权重怎么样被更准确地调整。最常见的优化算法是随机梯度下降法。最后, 成本函数常用来衡量误差,通过对比一个给定训练样本中得出的结果与预期结果的不同来评定神经网络的执行效果。
Keras、Deeplearning4j 等开源框架让创建神经网络变得简单。创建神经网络结构时,需要考虑的是怎样将你的数据类型匹配到一个已知的被解决的问题,并且根据你的实际需求来修改现有结构。
三、神经网络的类型以及应用
神经网络已经被了解和应用了数十年了,但是最近的一些技术趋势才使得深度神经网络变得更加高效。
GPUs使得矩阵操作速度更快;分布式计算结构让计算能力大大增强;多个超参数的组合也让迭代的速度提升。所有这些都让训练的速度大大加快,迅速找到适合的结构。
随着更大数据集的产生,类似于ImageNet 的大型高质量的标签数据集应运而生。机器学习算法训练的数据越大,那么它的准确性就会越高。
最后,随着我们理解能力以及神经网络算法的不断提升,神经网络的准确性在语音识别、机器翻译以及一些机器感知和面向目标的一些任务等方面不断刷新记录。
尽管神经网络架构非常的大,但是主要用到的神经网络种类也就是下面的几种。
3.1前馈神经网络
前馈神经网络包括一个输入层、一个输出层以及一个或多个的隐藏层。前馈神经网络可以做出很好的通用逼近器,并且能够被用来创建通用模型。
这种类型的神经网络可用于分类和回归。例如,当使用前馈网络进行分类时,输出层神经元的个数等于类的数量。从概念上讲, 激活了的输出神经元决定了神经网络所预测的类。更准确地说, 每个输出神经元返回一个记录与分类相匹配的概率数,其中概率最高的分类将被选为模型的输出分类。
前馈神经网络的优势是简单易用,与其他类型的神经网络相比更简单,并且有一大堆的应用实例。
3.2卷积神经网络
卷积神经网络和前馈神经网络是非常相似的,至少是数据的传输方式类似。他们结构大致上是模仿了视觉皮层。卷积神经网络通过许多的过滤器。这些过滤器主要集中在一个图像子集、补丁、图块的特征识别上。每一个过滤器都在寻找不同模式的视觉数据,例如,有的可能是找水平线,有的是找对角线,有的是找垂直的。这些线条都被看作是特征,当过滤器经过图像时,他们就会构造出特征图谱来定位各类线是出现在图像的哪些地方。图像中的不同物体,像猫、747s、榨汁机等都会有不同的图像特征,这些图像特征就能使图像完成分类。卷积神经网络在图像识别和语音识别方面是非常的有效的。
卷积神经网络与前馈神经网络在图像识别方面的异同比较。虽然这两种网络类型都能够进行图像识别,但是方式却不同。卷积神经网络是通过识别图像的重叠部分,然后学习识别不同部分的特征进行训练;然而,前馈神经网络是在整张图片上进行训练。前馈神经网络总是在图片的某一特殊部分或者方向进行训练,所以当图片的特征出现在其他地方时就不会被识别到,然而卷积神经网络却能够很好的避免这一点。
卷积神经网络主要是用于图像、视频、语音、声音识别以及无人驾驶的任务。尽管这篇文章主要是讨论递归神经网络的,但是卷积神经网络在图像识别方面也是非常有效的,所以很有必要了解。
3.3递归神经网络
与前馈神经网络不同的是,递归神经网络的隐藏层的节点里有内部记忆存储功能,随着输入数据的改变而内部记忆内容不断被更新。递归神经网络的结论都是基于当前的输入和之前存储的数据而得出的。递归神经网络能够充分利用这种内部记忆存储状态处理任意序列的数据,例如时间序列。
递归神经网络经常用于手写识别、语音识别、日志分析、欺诈检测和网络安全。
递归神经网络是处理时间维度数据集的最好方法,它可以处理以下数据:网络日志和服务器活动、硬件或者是医疗设备的传感器数据、金融交易、电话记录。想要追踪数据在不同阶段的依赖和关联关系需要你了解当前和之前的一些数据状态。尽管我们通过前馈神经网络也可以获取事件,随着时间的推移移动到另外一个事件,这将使我们限制在对事件的依赖中,所以这种方式很不灵活。
追踪在时间维度上有长期依赖的数据的更好方法是用内存来储存重要事件,以使近期事件能够被理解和分类。递归神经网络最好的一点就是在它的隐藏层里面有“内存”可以学习到时间依赖特征的重要性。
接下来我们将讨论递归神经网络在字符生成器和网络异常检测中的应用。递归神经网络可以检测出不同时间段的依赖特征的能力使得它可以进行时间序列数据的异常检测。
递归神经网络的应用
网络上有很多使用RNNs生成文本的例子,递归神经网络经过语料库的训练之后,只要输入一个字符,就可以预测下一个字符。下面让我们通过一些实用例子发现更多RNNs的特征。
应用一、RNNs用于字符生成
递归神经网络经过训练之后可以把英文字符当做成一系列的时间依赖事件。经过训练后它会学习到一个字符经常跟着另外一个字符(“e”经常跟在“h”后面,像在“the、he、she”中)。由于它能预测下一个字符是什么,所以它能有效地减少文本的输入错误。
Java是个很有趣的例子,因为它的结构包括很多嵌套结构,有一个开的圆括号必然后面就会有一个闭的,花括号也是同理。他们之间的依赖关系并不会在位置上表现的很明显,因为多个事件之间的关系不是靠所在位置的距离确定的。但是就算是不明确告诉递归神经网络Java中各个事件的依赖关系,它也能自己学习了解到。
在异常检测当中,我们要求神经网络能够检测出数据中相似、隐藏的或许是并不明显的模式。就像是一个字符生成器在充分地了解数据的结构后就会生成一个数据的拟像,递归神经网络的异常检测就是在其充分了解数据结构后来判断输入的数据是不是正常。
字符生成的例子表明递归神经网络有在不同时间范围内学习到时间依赖关系的能力,它的这种能力还可以用来检测网络活动日志的异常。
异常检测能够使文本中的语法错误浮出水面,这是因为我们所写的东西是由语法结构所决定的。同理,网络行为也是有结构的,它也有一个能够被学习的可预测模式。经过在正常网络活动中训练的递归神经网络可以监测到入侵行为,因为这些入侵行为的出现就像是一个句子没有标点符号一样异常。
应用二、一个网络异常检测项目的示例
假设我们想要了解的网络异常检测就是能够得到硬件故障、应用程序失败、以及入侵的一些信息。
模型将会向我们展示什么呢?
随着大量的网络活动日志被输入到递归神经网络中去,神经网络就能学习到正常的网络活动应该是什么样子的。当这个被训练的网络被输入新的数据时,它就能偶判断出哪些是正常的活动,哪些是被期待的,哪些是异常的。
训练一个神经网络来识别预期行为是有好处的,因为异常数据不多,或者是不能够准确的将异常行为进行分类。我们在正常的数据里进行训练,它就能够在未来的某个时间点提醒我们非正常活动的出现。
说句题外话,训练的神经网络并不一定非得识别到特定事情发生的特定时间点(例如,它不知道那个特殊的日子就是周日),但是它一定会发现一些值得我们注意的一些更明显的时间模式和一些可能并不明显的事件之间的联系。
我们将概述一下怎么用 Deeplearning4j(一个在JVM上被广泛应用的深度学习开源数据库)来解决这个问题。Deeplearning4j在模型开发过程中提供了很多有用的工具:DataVec是一款为ETL(提取-转化-加载)任务准备模型训练数据的集成工具。正如Sqoop为Hadoop加载数据,DataVec将数据进行清洗、预处理、规范化与标准化之后将数据加载到神经网络。这跟Trifacta’s Wrangler也相似,只不过它更关注二进制数据。
开始阶段
第一阶段包括典型的大数据任务和ETL:我们需要收集、移动、储存、准备、规范化、矢量话日志。时间跨度的长短是必须被规定好的。数据的转化需要花费一些功夫,这是由于JSON日志、文本日志、还有一些非连续标注模式都必须被识别并且转化为数值数组。DataVec能够帮助进行转化和规范化数据。在开发机器学习训练模型时,数据需要分为训练集和测试集。
训练神经网络
神经网络的初始训练需要在训练数据集中进行。
在第一次训练的时候,你需要调整一些超参数以使模型能够实现在数据中学习。这个过程需要控制在合理的时间内。关于超参数我们将在之后进行讨论。在模型训练的过程中,你应该以降低错误为目标。
但是这可能会出现神经网络模型过度拟合的风险。有过度拟合现象出现的模型往往会在训练集中的很高的分数,但是在遇到新的数据时就会得出错误结论。用机器学习的语言来说就是它不够通用化。Deeplearning4J提供正则化的工具和“过早停止”来避免训练过程中的过度拟合。
神经网络的训练是最花费时间和耗费硬件的一步。在GPUs上训练能够有效的减少训练时间,尤其是做图像识别的时候。但是额外的硬件设施就带来多余的花销,所以你的深度学习的框架必须能够有效的利用硬件设施。Azure和亚马逊等云服务提供了基于GPU的实例,神经网络还可以在异构集群上进行训练。
创建模型
Deeplearning4J提供ModelSerializer来保存训练模型。训练模型可以被保存或者是在之后的训练中被使用或更新。
在执行异常检测的过程中,日志文件的格式需要与训练模型一致,基于神经网络的输出结果,你将会得到是否当前的活动符合正常网络行为预期的结论。
代码示例
递归神经网络的结构应该是这样子的:
MultiLayerConfiguration conf = new NeuralNetConfiguration.Builder(
.seed(123)
.optimizationAlgo(OptimizationAlgorithm.STOCHASTIC_GRADIENT_DESCENT).iterations(1)
.weightInit(WeightInit.XAVIER)
.updater(Updater.NESTEROVS).momentum(0.9)
.learningRate(0.005)
.gradientNormalization(GradientNormalization.ClipElementWiseAbsoluteValue)
.gradientNormalizationThreshold(0.5)
.list()
.layer(0, new GravesLSTM.Builder().activation("tanh").nIn(1).nOut(10).build())
.layer(1, new RnnOutputLayer.Builder(LossFunctions.LossFunction.MCXENT)
.activation("softmax").nIn(10).nOut(numLabelClasses).build())
.pretrain(false).backprop(true).build();
MultiLayerNetwork net = new MultiLayerNetwork(conf);
net.init();
下面解释一下几行重要的代码:
.seed(123)
随机设置一个种子值对神经网络的权值进行初始化,以此获得一个有复验性的结果。系数通常都是被随机的初始化的,以使我们在调整其他超参数时仍获得一致的结果。我们需要设定一个种子值,让我们在调整和测试的时候能够用这个随机的权值。
.optimizationAlgo(OptimizationAlgorithm.STOCHASTIC_GRADIENT_DESCENT).iterations(1)
决定使用哪个最优算法(在这个例子中是随机梯度下降法)来调整权值以提高误差分数。你可能不需要对这个进行修改。
.learningRate(0.005)
当我们使用随机梯度下降法的时候,误差梯度就被计算出来了。在我们试图将误差值减到最小的过程中,权值也随之变化。SGD给我们一个让误差更小的方向,这个学习效率就决定了我们该在这个方向上迈多大的梯度。如果学习效率太高,你可能是超过了误差最小值;如果太低,你的训练可能将会永远进行。这是一个你需要调整的超参数。
求教pytorch的LSTM网络代码问题
input就是shape=(seq_length,batch_size,input_size)的张量
ht是shape=(num_layers*num_directions,batch_size,hidden_size)的张量,它包含了在当前这个batch_size中每个句子的初始隐藏状态。其中num_layers就是LSTM的层数。如果bidirectional=True,num_directions=2,否则就是1,表示只有一个方向。
ct和ht的形状相同,它包含的是在当前这个batch_size中的每个句子的初始细胞状态。
ht,ct如果不提供,那么默认是0。
至于为什么要定义ht和ct建议了解一下LSTM的网络结构和原理,会对你有很大的帮助。
LSTM神经网络输入输出究竟是怎样的?
输入输出都是向量,或者说是矩阵。LSTM用于分类的话,后面一般会接softmax层。个人浅薄理解,拿动作识别分类举例,每个动作帧放入LSTM中训练,还是根据task来训练每个LSTM单元的Weights。所以LSTM的单元数量跟输入和输出都没有关系,甚至还可以几层LSTM叠加起来用。分类的话,一般用最后一个单元接上softmax层。LSTM结构是传统的RNN结构扩展,解决了传统RNN梯度消失/爆炸的问题,从而使得深层次的网络更容易训练。从这个角度理解,可能会容易很多。今年的ResNet也是使传统的CNN更容易训练weights。看来deeplearning越来越深是趋势啊。如果说训练,就一个关键,所谓LSTMUnroll,将RNN展开成一个静态的“并行”网络,内部有“侧向连接”,实现长的短时记忆功能(状态“记忆”在LSTMCell里)。如果说预测,也就一个关键,要将Cell的h和C弄出来,作为当前状态(也就是所谓“记忆”)作为init参数输入,这样,携带了当前记忆状态的网络,预测得到的就是下一个输入了,所谓的recurrent了。那份代码里还包含了一个使用cudnn的实现(built-inRNNoperator),这是一个高性能的版本,可以真正干活的。原来我也尝试搞懂一些天书般的公式,很快发现从那里入手是个错误。强烈推荐:理解LSTM网络(翻译自UnderstandingLSTMNetworks)只要有一点点CNN基础+半个小时,就可以通过这篇文章理解LSTM的基础原理。回答你的问题:和神经元个数无关,不知道你是如何理解“神经元”这个概念的,输入输出层保证tensor的维数和输入输出一致就可以了。
如何在Python中用LSTM网络进行时间序列预测
时间序列模型
时间序列预测分析就是利用过去一段时间内某事件时间的特征来预测未来一段时间内该事件的特征。这是一类相对比较复杂的预测建模问题,和回归分析模型的预测不同,时间序列模型是依赖于事件发生的先后顺序的,同样大小的值改变顺序后输入模型产生的结果是不同的。
举个栗子:根据过去两年某股票的每天的股价数据推测之后一周的股价变化;根据过去2年某店铺每周想消费人数预测下周来店消费的人数等等
RNN 和 LSTM 模型
时间序列模型最常用最强大的的工具就是递归神经网络(recurrent neural network, RNN)。相比与普通神经网络的各计算结果之间相互独立的特点,RNN的每一次隐含层的计算结果都与当前输入以及上一次的隐含层结果相关。通过这种方法,RNN的计算结果便具备了记忆之前几次结果的特点。
典型的RNN网路结构如下:
右侧为计算时便于理解记忆而产开的结构。简单说,x为输入层,o为输出层,s为隐含层,而t指第几次的计算;V,W,U为权重,其中计算第t次的隐含层状态时为St = f(U*Xt + W*St-1),实现当前输入结果与之前的计算挂钩的目的。对RNN想要更深入的了解可以戳这里。
RNN的局限:
由于RNN模型如果需要实现长期记忆的话需要将当前的隐含态的计算与前n次的计算挂钩,即St = f(U*Xt + W1*St-1 + W2*St-2 + ... + Wn*St-n),那样的话计算量会呈指数式增长,导致模型训练的时间大幅增加,因此RNN模型一般直接用来进行长期记忆计算。
LSTM模型
LSTM(Long Short-Term Memory)模型是一种RNN的变型,最早由Juergen Schmidhuber提出的。经典的LSTM模型结构如下:
LSTM的特点就是在RNN结构以外添加了各层的阀门节点。阀门有3类:遗忘阀门(forget gate),输入阀门(input gate)和输出阀门(output gate)。这些阀门可以打开或关闭,用于将判断模型网络的记忆态(之前网络的状态)在该层输出的结果是否达到阈值从而加入到当前该层的计算中。如图中所示,阀门节点利用sigmoid函数将网络的记忆态作为输入计算;如果输出结果达到阈值则将该阀门输出与当前层的的计算结果相乘作为下一层的输入(PS:这里的相乘是在指矩阵中的逐元素相乘);如果没有达到阈值则将该输出结果遗忘掉。每一层包括阀门节点的权重都会在每一次模型反向传播训练过程中更新。更具体的LSTM的判断计算过程如下图所示:
LSTM模型的记忆功能就是由这些阀门节点实现的。当阀门打开的时候,前面模型的训练结果就会关联到当前的模型计算,而当阀门关闭的时候之前的计算结果就不再影响当前的计算。因此,通过调节阀门的开关我们就可以实现早期序列对最终结果的影响。而当你不不希望之前结果对之后产生影响,比如自然语言处理中的开始分析新段落或新章节,那么把阀门关掉即可。(对LSTM想要更具体的了解可以戳这里)
下图具体演示了阀门是如何工作的:通过阀门控制使序列第1的输入的变量影响到了序列第4,6的的变量计算结果。
黑色实心圆代表对该节点的计算结果输出到下一层或下一次计算;空心圆则表示该节点的计算结果没有输入到网络或者没有从上一次收到信号。
Python中实现LSTM模型搭建
Python中有不少包可以直接调用来构建LSTM模型,比如pybrain, kears, tensorflow, cikit-neuralnetwork等(更多戳这里)。这里我们选用keras。(PS:如果操作系统用的linux或者mac,强推Tensorflow!!!)
因为LSTM神经网络模型的训练可以通过调整很多参数来优化,例如activation函数,LSTM层数,输入输出的变量维度等,调节过程相当复杂。这里只举一个最简单的应用例子来描述LSTM的搭建过程。
应用实例
基于某家店的某顾客的历史消费的时间推测该顾客前下次来店的时间。具体数据如下所示:
消费时间
2015-05-15 14:03:512015-05-15 15:32:462015-06-28 18:00:172015-07-16 21:27:182015-07-16 22:04:512015-09-08 14:59:56..
..
具体操作:
1. 原始数据转化
首先需要将时间点数据进行数值化。将具体时间转化为时间段用于表示该用户相邻两次消费的时间间隔,然后再导入模型进行训练是比较常用的手段。转化后的数据如下:
消费间隔04418054..
..
2.生成模型训练数据集(确定训练集的窗口长度)
这里的窗口指需要几次消费间隔用来预测下一次的消费间隔。这里我们先采用窗口长度为3, 即用t-2, t-1,t次的消费间隔进行模型训练,然后用t+1次间隔对结果进行验证。数据集格式如下:X为训练数据,Y为验证数据。
PS: 这里说确定也不太合适,因为窗口长度需要根据模型验证结果进行调整的。
X1 X2 X3 Y0 44 18 044 18 0 54..
..
注:直接这样预测一般精度会比较差,可以把预测值Y根据数值bin到几类,然后用转换成one-hot标签再来训练会比较好。比如如果把Y按数值范围分到五类(1:0-20,2:20-40,3:40-60,4:60-80,5:80-100)上式可化为:
X1 X2 X3 Y0 44 18 044 18 0 4...
Y转化成one-hot以后则是(关于one-hot编码可以参考这里)
1 0 0 0 00 0 0 0 1...
3. 网络模型结构的确定和调整
这里我们使用python的keras库。(用java的同学可以参考下deeplearning4j这个库)。网络的训练过程设计到许多参数的调整:比如
需要确定LSTM模块的激活函数(activation fucntion)(keras中默认的是tanh);
确定接收LSTM输出的完全连接人工神经网络(fully-connected artificial neural network)的激活函数(keras中默认为linear);
确定每一层网络节点的舍弃率(为了防止过度拟合(overfit)),这里我们默认值设定为0.2;
确定误差的计算方式,这里我们使用均方误差(mean squared error);
确定权重参数的迭代更新方式,这里我们采用RMSprop算法,通常用于RNN网络。
确定模型训练的epoch和batch size(关于模型的这两个参数具体解释戳这里)
一般来说LSTM模块的层数越多(一般不超过3层,再多训练的时候就比较难收敛),对高级别的时间表示的学习能力越强;同时,最后会加一层普通的神经网路层用于输出结果的降维。典型结构如下:
如果需要将多个序列进行同一个模型的训练,可以将序列分别输入到独立的LSTM模块然后输出结果合并后输入到普通层。结构如下:
4. 模型训练和结果预测
将上述数据集按4:1的比例随机拆分为训练集和验证集,这是为了防止过度拟合。训练模型。然后将数据的X列作为参数导入模型便可得到预测值,与实际的Y值相比便可得到该模型的优劣。
实现代码
时间间隔序列格式化成所需的训练集格式
import pandas as pdimport numpy as npdef create_interval_dataset(dataset, look_back):
""" :param dataset: input array of time intervals :param look_back: each training set feature length :return: convert an array of values into a dataset matrix. """
dataX, dataY = [], [] for i in range(len(dataset) - look_back):
dataX.append(dataset[i:i+look_back])
dataY.append(dataset[i+look_back]) return np.asarray(dataX), np.asarray(dataY)
df = pd.read_csv("path-to-your-time-interval-file")
dataset_init = np.asarray(df) # if only 1 columndataX, dataY = create_interval_dataset(dataset, lookback=3) # look back if the training set sequence length
这里的输入数据来源是csv文件,如果输入数据是来自数据库的话可以参考这里
LSTM网络结构搭建
import pandas as pdimport numpy as npimport randomfrom keras.models import Sequential, model_from_jsonfrom keras.layers import Dense, LSTM, Dropoutclass NeuralNetwork():
def __init__(self, **kwargs):
""" :param **kwargs: output_dim=4: output dimension of LSTM layer; activation_lstm='tanh': activation function for LSTM layers; activation_dense='relu': activation function for Dense layer; activation_last='sigmoid': activation function for last layer; drop_out=0.2: fraction of input units to drop; np_epoch=10, the number of epoches to train the model. epoch is one forward pass and one backward pass of all the training examples; batch_size=32: number of samples per gradient update. The higher the batch size, the more memory space you'll need; loss='mean_square_error': loss function; optimizer='rmsprop' """
self.output_dim = kwargs.get('output_dim', 8) self.activation_lstm = kwargs.get('activation_lstm', 'relu') self.activation_dense = kwargs.get('activation_dense', 'relu') self.activation_last = kwargs.get('activation_last', 'softmax') # softmax for multiple output
self.dense_layer = kwargs.get('dense_layer', 2) # at least 2 layers
self.lstm_layer = kwargs.get('lstm_layer', 2) self.drop_out = kwargs.get('drop_out', 0.2) self.nb_epoch = kwargs.get('nb_epoch', 10) self.batch_size = kwargs.get('batch_size', 100) self.loss = kwargs.get('loss', 'categorical_crossentropy') self.optimizer = kwargs.get('optimizer', 'rmsprop') def NN_model(self, trainX, trainY, testX, testY):
""" :param trainX: training data set :param trainY: expect value of training data :param testX: test data set :param testY: epect value of test data :return: model after training """
print "Training model is LSTM network!"
input_dim = trainX[1].shape[1]
output_dim = trainY.shape[1] # one-hot label
# print predefined parameters of current model:
model = Sequential() # applying a LSTM layer with x dim output and y dim input. Use dropout parameter to avoid overfitting
model.add(LSTM(output_dim=self.output_dim,
input_dim=input_dim,
activation=self.activation_lstm,
dropout_U=self.drop_out,
return_sequences=True)) for i in range(self.lstm_layer-2):
model.add(LSTM(output_dim=self.output_dim,
input_dim=self.output_dim,
activation=self.activation_lstm,
dropout_U=self.drop_out,
return_sequences=True)) # argument return_sequences should be false in last lstm layer to avoid input dimension incompatibility with dense layer
model.add(LSTM(output_dim=self.output_dim,
input_dim=self.output_dim,
activation=self.activation_lstm,
dropout_U=self.drop_out)) for i in range(self.dense_layer-1):
model.add(Dense(output_dim=self.output_dim,
activation=self.activation_last))
model.add(Dense(output_dim=output_dim,
input_dim=self.output_dim,
activation=self.activation_last)) # configure the learning process
model.compile(loss=self.loss, optimizer=self.optimizer, metrics=['accuracy']) # train the model with fixed number of epoches
model.fit(x=trainX, y=trainY, nb_epoch=self.nb_epoch, batch_size=self.batch_size, validation_data=(testX, testY)) # store model to json file
model_json = model.to_json() with open(model_path, "w") as json_file:
json_file.write(model_json) # store model weights to hdf5 file
if model_weight_path: if os.path.exists(model_weight_path):
os.remove(model_weight_path)
model.save_weights(model_weight_path) # eg: model_weight.h5
return model
这里写的只涉及LSTM网络的结构搭建,至于如何把数据处理规范化成网络所需的结构以及把模型预测结果与实际值比较统计的可视化,就需要根据实际情况做调整了。
如何自定义LSTM的initial state
State 不是 Tuple 时,代码如下。一个epoch的最开始,我们要把一个 全零array,输入到 initial_state 中,然后输出 finial_state 覆盖到 state 中,然后执行下一个迭代。
但是当LSTM设置为 state is tuple, TensorFlow是返回一个LSTMStateTuple的,是不可以通过eval() 来得到参数的,而且也不能被feed!!
分享题目:lstm代码java lstm代码keras
文章源于:http://ybzwz.com/article/doscpge.html