LSTM缓解了RNN中梯度消失的问题,使其可以处理长短时序列,但是需要注意的是LSTM并没有彻底解决梯度消失的问题。LSTM被各大科技公司应用在文字翻译,语音识别等方向,因为其相比RNN,在各个应用场景上带来了比较大的效果提升。
LSTM经过千锤百炼才有了现在的形态,so,让我们开始一睹芳容吧!
以下所有内容,如有侵权,请联系删除~
由于RNN和LSTM都是循环神经网络,二者具有一定的相似,所以几乎所有的教程都会从RNN过渡到LSTM。在这里我们将简单看一下RNN的原理,然后快速过渡到LSTM。如需详细了解RNN,请点击:RNN原理介绍。
这是RNN经典的结构图,上图左边表示的是只有一层隐层的RNN网络,在时间轴上展开后得到右图。所谓RNN循环神经网络就是在时间轴上A的权值共享和循环利用。没错,在时间步上所有的A都是同一个东西,记住这一点!
时间轴可以是不同的对象,比如音频t秒为一帧,一帧就是一个时间步,RNN就是利用相同的权重去计算一段音频的不同帧,然后再输出;再比如视频t秒提取一个特征,同样这一个特征也是一个时间步,一段视频的多个特征组合成一个时间步序列;再比如一个样本提取一个特征,指定n个样本作为时间序列,那这个时间步的长度就为n……
只要合理,可以指定任何维度为时间步。
相比RNN,LSTM增加了一个单元状态\(C^t\) (cell state),此外还有和NN名义上一样的隐状态变量\(h^t\) (hidden state);并且LSTM对节点A进行了优化升级,在A里面增加了输入门,遗忘门,输出门这三个门机制,处理流程相比RNN复杂了很多。可以看出LSTM只是对隐层节点A做了改进,并增加了一个输入。但时间步循环的整体思路和结构不变,与RNN类似。
可以通过图片直观的感受不同时间步的网络状态,下图表示包含2个隐藏层的LSTM/RNN网络,也就是两个LSTM/RNN进行堆叠。在T=1时刻看,它是一个普通的BP网络,在T=2时刻看也是一个普通的BP网络。但是T时刻训练的隐藏层信息H,C会被传递到下一个时刻T+1。这是LSTM和RNN循环的原理,也是与常规卷积网络的不同之处。
从下图直观感受,LSTM或者RNN在循环时变成了一个网络矩阵,但实际上这个网络只有最左边这一排的东西,右边三排是为了更容易理解时间步循环而画出来的。也就是说不同时间步上的网络都是同一组权重。比如下图中的T=1,T=2,….时的网络都是相同的,只不过不同时刻的输入和输出不相同。
了解LSTM时间步循环的原理后,就开始看一下LSTM内部的处理流程,整个LSTM内部流程可以分为三步:
LSTM相当于一个工厂,里面包含了各种组件,各种组件支撑着LSTM的运行。这一小节将讲一下LSTM的各种组件。
首先想一下,为什么要在LSTM里面大费周章添加门机制呢?
这是因为门机制极大的减轻了梯度消失问题,简化了我们的调参复杂度。同时门机制提供了特征过滤,将有用的特征保存,没用的特征丢弃,这极大的丰富了向量的表示信息。至于为什么减轻了梯度消失问题,后面将讲到,在此之前先看一下各个关键的组件。
首先解释一下用到的符号
\(H_{t}\):t 时刻的隐状态。在 \(0-t\)时刻的全局信息的影响下, 当前时刻的上下文表示。
\(X_t\):t 时刻的输入向量。
\(C_t\):t 时刻的记忆。本质上是 \(0-t\) 时刻的全局信息。
下图是比较经典的LSTM内部原理图,将以下图作为基础进行逐步拆解。下图 ’按元素运算符‘ 的意思是矩阵中对应的元素相乘,因此要求两个相乘矩阵是同型的
遗忘门
作用:控制保留多少过去的\(C_{t-1}\)记忆。选择性忘记,记住重要的,忘记不重要的
\(F_t=\sigma(W_f·[H_{t-1},X_{t}]+b_f) \qquad(1)\)
输入门
作用:选择记忆。采用多少来自tanh(\(\widetilde C_t\))的数据,选择一部分记忆,并把这部分加入到新的记忆中去,完成记忆的更新。
\(I_t=\sigma(W_i·[H_{t-1},X_{t}]+b_i) \qquad(2)\)
\(I_t\)和\(F_t\)的作用类似,都是对一段记忆进行选择性的提取,并更新为新的记忆。不同的是\(F_t\)是对历史记忆进行选择;\(I_t\)是对当前信息进行选择,选择的信息成为记忆中的一部分。
输出门
作用:决定\(C^t\)中哪些会被当成当前状态输出。在对\(C_t\)进行输出选择之前,\(C_t\)首先经过tanh变换进行缩放。
\(O_t=\sigma(W_o·[H_{t-1},X_t]+b_o) \qquad(3)\)
候选记忆\(C_t\)
候选记忆是对两个输入非线性变换获得。
\(C_t=tanh(W_c[H_{t-1},X_t]+b_c) \qquad(4)\)
当前单元状态
作为下一时间步的输入,保存了1-t所有的记忆
\(C_t=F_{t}\ \omicron \ C_{t-1}+I_t\ \omicron \ tanh(W_c·[H_{t-1},X_t]+b_c)\qquad(5)\)
输出隐藏层
每一个时间步的最后一层LSTM都将作为最终结果输出。
\(H_t=tanh(C_t)\ \omicron\ O_t \qquad(6)\)
以上一些关键组件和步骤都介绍完了,可能你还有疑问,比如上一时刻的隐状态信息\(H_{t-1}\)和样本输入\(X_t\)利用中括号括在一起是什么意思?为什么有的激活函数用sigmod,有的激活函数用tanh,这其中有什么讲究吗?LSTM内部可以使用正则化吗?还有是如何缓解了RNN的梯度消失?
对于第一个问题,其实是比较简单的。上一时刻的隐状态信息\(H_{t-1}\)和样本输入\(X_t\)利用中括号括在一起,是表示这两个信息拼接在一起,如何拼接?就是串接在一起。
在LSTM中,遗忘门、输入门和输出门使用 Sigmoid函数作为激活函数;在生成候选记忆时,使用双曲正切函数tanh作为激活函数。
为什么使用sigmod或者tanh?
门控信号越接近1,代表”记忆“下来的数据越多;而越接近0则代表”遗忘“的越多。Sigmoid的输出在0-1之同,符合门控的物理定义,且当输入较大或较小时,其输出会非常接近1或0,从而保证该门开或关,在生成候选记亿时;相比于relu,relu为0-+inf,无法表示记住的大小。
使用tanh函数,是因为其输出在-1,1之间,这与大多数场景下特征分布是0中心的吻合。此外,tanh函数在输入为0近相比 Sigmoid函数有更大的梯度,通常使模型收敛更快。
根据RNN梯度消失的原因可以知道会存在中间状态的连乘。
类似RNN,研究一下\(\partial C_t \over \partial C_{t-1}\):
根据链式求导法则以及上面六个公式可以进行展开:
\({\partial C_t \over \partial C_{t-1}} = {\partial C_t \over \partial f_t}·{\partial f_t \over \partial H_{t-1}}·{\partial H_{t-1} \over \partial C_{t-1}}+{\partial C_t \over \partial i_t}·{\partial i_t \over \partial H_{t-1}}·{\partial H_{t-1} \over \partial C_{t-1}}+{\partial C_t \over \partial \widetilde C_t}·{\partial \widetilde C_t\over \partial H_{t-1}}·{\partial H_{t-1} \over \partial C_{t-1}}+{\partial C_t \over \partial C_{t-1}}\)
\({\partial C_t \over \partial C_{t-1}} = C_{t-1}·\sigma'·W_f·tanh'(C_{t-1})·O_{t-1}+\widetilde C_t·\sigma'·W_i·O_{t-1}tanh'(C_{t-1})+i_t·tanh'(·)·W_c·O_{t-1}·tanh'(C_{t-1})+f_t\)
从上述推导中可以看出,Cell连乘部分是个加项,而\(f_t,i_t,o_t,\widetilde C_t\)都是神经网网络自己学到的,因此可以通过学习改变门控的值,使梯度维持在合理的范围内。加项使得梯度传递更为恰当。当然梯度可以大于1也可以小于1,至于到底取什么值,这完全由神经网络根据自己学到的门控权值决定。
总结来说就是,RNN的前一个记忆对后一个记忆的导数是常数,这样RNN的某个偏导数一直都是大于1或者在[0,1]之间,这样会导致梯度消失或者爆炸。而LSTM的导数是可以改变的,在每个时刻都是可以大于1或者在[0,1]区间之内的。
但是LSTM并没有彻底解决梯度的问题,文献记载,在序列过长的情况下,仍然可能会出现梯度消失的问题。
LSTM(100, dropout=0.2, recurrent_dropout=0.2)
Dropout(0.5)
第一个dropout是LSTM层与层之间的dropout,控制输入神经元断开比例。
第二个recurrent_dropout是循环层之间的dropout
第三个Dropout是层与层之间的dropout
TF版本的LSTM有两个dropout,分别控制循环和非循环上的dropout。recurrent_dropout是控制前一时刻隐层状态的断开比例。由于隐层状态不是携带记忆的主体,只是当前节点的上下文表示,所以对其采用dropout,理论上来说不影响长序列的记忆。
一个不太重要的知识点
\(C^t\)在传递的过程中改变的很慢,而\(h^t\)在不同的节点往往区别很大。
由于\(C^t\)作为主线,主要保存节点传递下来的数据并加入当前节点的内容,改变相对较小。
\(h^t\)主要是利用输出门控信号和当前记忆状态获得,对于不同的输入获得的输出门控信号差别很大,因而不同时刻的\(h^t\)也会有较大的差别。
这是一张很经典的图,可以根据此图学习一下LSTM的各种shape。此图画了两个LSTM单元,只看最下面这个单元即可。如果未特别说明,以下符号代表的意义均相同。
这个和LSTM单元输入shape是不一样的,LSTM有单元三个输入,而在网络训练时,我们只需要将样本特征输入即可。
训练时输入数据x的shape: [batch_size, seq_length, dims]
batch_size为批大小,
seq_length为帧数,一般为时间维度,即常说的时间步的数量;
dims为样本提取特征的维数。
在网络计算时,可以理解为每次取出一个sequence进行前向推理,因此在训练时,每个LSTM网络在某个时间步接受[batch_size, dims]的数据,一共循环计算seq_length次。
对于LSTM单元来讲共三个输入:隐状态\(H_{t-1}\),单元状态的输入\(C_{t-1}\),还有网络输入的样本特征\(X_t\)。其中样本特征和隐状态这两个输入通过串联拼接的方式,变成一个输入。其维度为:[batch_size,seq_length,Hidden_size + dims],其中Hidden_size为隐藏层的输出,也是隐藏层神经元的个数。
LSTM神经元内有四组权重,分别为输入门,输出门,遗忘门,生成候选记忆这四组权重。这四组权重其实就是四个全连接层的权重。
每组权重的shape为:[dims + Hidden_size,Hidden_size]
因为LSTM内只有四组权重,因此LSTM参数量总数为:Number_of_weight = 4 * Hidden_size * (Input_size + 1 + Hidden_size),也就是四个全连接层所有权重的数量,也可以写成:4(Hidden_size(dims+Hidden_size) + Hidden_size)。最后一个Hidden_size的意义是神经网络的偏置(bias)。
所有时刻的隐层状态的shape都是相同的,shape为 [batch_size, Hidden_size]
\(C_t\)的shape:[batch_size, Hidden_size]
由下图可以看出LSTM网络有三个输出,分别为output,H,C
output是每个时间步最后一层LSTM的隐状态:\(output=\{H_1,H_2,...,H_T\}\)。
假设只有一层LSTM的网络,t时刻进行了一次前向推理,获得\(H_t\)和\(C_t\),将此刻的\(H_t\)加入结果集中。如果有两层LSTM单元,那么就将第二层的隐层输出加到结果集合中去。
由于每一个时刻都会有一个隐藏状态,这样就会有seq_length个隐藏状态,所以输出的维度为[batch_size,seq_length,Hidden_size]
所以输出output是个具有seq_length长度的向量。如果是双向,那么LSTM的output输出维度为 [batch_szie, seq, Hidden_size*num_directions]。
在LSTM层的维度还有两个输出,那就是层的隐状态集合H和记忆状态集合C。有人就问了,前面不是有隐层状态集合output了,怎么又有隐层状态的集合输出?
前面说的隐层状态输出是在时间序列上的输出,而这个隐层状态集合H为层的维度上最后一个时间步的输出。可以参考上图进行理解。每一个LSTM会输出一个隐层状态\(H_t\)和记忆状态\(C_t\),如果LSTM单元堆叠了三个,那就有三个隐层状态和三个记忆状态。所以这两个输出为最后一个时间步所有LSTM层的输出。
这两个输出的维度均为: [batch_size,num_layer*num_directions,Hidden_size],num_layer是网络的层数,也就是堆叠了几个LSTM;num_directions表示双向或者单向;
由此可以推导出一个性质,那就是\(H[-1]\) == output[:- 1:],即最H的最后一个时间步的最后一层的隐藏层状态与output的最后一个时间步的结果相等。
以上就是LSTM的基本原理与框架,那么在搭建网络时,该用几层LSTM,每个LSTM的权重应该设置多少呢?
隐藏层大小设置,是计算力与表达能力的权衡。越多的hidden_size可以包含更多的细节,以及更丰富的表达能力,但是同时也会带来过拟合以及耗时长等缺点。当神经元足够多时,网络会具有足够多的weights去拟合当前问题,但是换来的可能是过拟合和训练速度严重下降。
从经验来看,很少有人在rnn的层里面加很大的unit数量上去,计算量是很恐怖的,而且获得的效率提高可能只是一点点(比如tensorflow的官方教程里ptb的例子,虽然有1500个hidden unit,但是实际提升相比较于200的并不是很明显)。所以一般128或者256的就已经足够了,单纯RNN的学习能力很一般,需要组合其它手段去提高准确率。
可以想一下,四个全连接层,如果输入维度本身就很大了,再乘以神经元的数量,那这个参数总量是恐怖如斯~
本人曾经将hidden_size设置为很大尝试过,不光训练速度慢,模型的占用空间也是大的惊人…
目前查到的资料一般是1、2、3、4层,大部分是一层双向或者两层双向,很少见到更多层数的堆叠。
了解了LSTM原理,那么双向LSTM自然也不在话下。双向 LSTM 不仅利用了历史信息,也利用了未来信息
其原理是在时间序列上正向和反向调用LSTM。输入在时间维度上反转,得到反向的输出,再将输出按时间维度反转,这样就和正向的输出保持一致。就得到了最终结果。
假设输入为[\(x_1,x_2,x_3\)]得到输出:[\(h_1,h_2,h_3\)]
将输入反转,[\(x_3,x_2,x_1\)]得到输出:[\(h_1',h_2',h_3'\)],将得到的输出反转,得到[\(h_3',h_2',h_1'\)]
将两个输出进行拼接得到:[\(h_1,h_3'\)],[\(h_2,h_2'\)],[\(h_3,h_1'\)]
情感分类任务,常常使用[\(h_1,h_3'\)],因为其包含前向和反向所有的信息。
TF有三个可以控制输出的参数:return_sequence,return_state,这两个参数均是bool值。
这两个开关对应5中情况:
默认情况下,这两个参数都是False。这样就只输出最后一层最后一个时间步的隐藏状态\(h_n\),输出维度为[batch_size,Hidden_size*num_directions]
return_sequence=True时输出整个序列最后一层的隐藏状态[\(h_1,h_2,...,h_n\)],因此输出维度为[batch_size,seq_length,Hidden_size*num_directions]。
return_state=True,return_sequence=False时,输出结果有三个:output,h_n,c_n。
output和h_n是相同的,均是最后一个时刻的隐层状态。
c_n则是最后一个时间步的Cell state。他们三个的shape均为[batch_size,Hidden_size*num_directions]
pytorch结果返回结果有三个:output,(h_n,c_n)。
output:[seq_length,batch_size,Hidden_size*num_directions],pytorch的seq_length和batch_size的位置与TF有所不同
h_n:[num_directions* num_layers,batch_size,Hidden_size],其中输出的维度还可以指定’proj_size‘参数,从而可以从Hidden_size变换成proj_size。
c_n:[num_directions* num_layers,batch_size,Hidden_size]
最后输出的结果
LSTM自有其先天不足,比如:
参考:
http://arxiv.org/pdf/1409.2329.pdf
http://yongqianxiao.github.io/2020/03/29/LSTM详解及TF手动实现/
http://zhuanlan.zhihu.com/p/42717426
http://zh.d2l.ai/chapter_recurrent-modern/lstm.html
http://www.zhihu.com/question/268394748
http://zhuanlan.zhihu.com/p/139617364
WebPServer这是一个基于Golang的服务器,允许您动态提供WebP图像,在不改变图片URL路径的情况下,自动将JPEG、PNG、BMP、GIF等图像转换为WebP格式,从而减小图片体积,降低流量消耗和提高加载速度。什么是WebP?WebP是一种同时提供了有损压缩与无损压缩(可逆压缩)的图片文件格式,由Google推出,WEBP的格式压缩率非常高,在同质量的情况下.webp格式的图片体积会小很多。主流的FireFox/Chrome浏览器已经支持webp图像,但目前Safari还不支持。WebPServer的作用WebPServer相当于一个旁路的WEB服务器,管理员配置好WebPServer后,可以自动将JPEG、PNG、BMP、GIF等图像转换为WebP格式,同时URL地址不会发生改变,对于FireFox/Chrome支持webp图像的浏览器,直接返回webp格式给用户,对于Safari不支持webp的浏览器则输出原图,做到用户无感知访问。配置WebPServer这篇文章我们以WordPress站点为例来实际操作一下,xiaoz的环境如下:操作系统:CentOS7站点程序:W
思路使用前序遍历序列化,遍历的元素往链表末尾添加,根节点先添加,再左子节点,右子节点。所以根节点在链表头部,有了这个信息就好做了,毕竟二叉树的遍历就是找到根节点+做点啥+递归。使用前序遍历反序列化,需要先得出根节点,在链表的头部,将其抛出。再找出左子节点,还是链表的头部,将其抛出,继续寻找左子节点的左子节点。。。中序遍历无法反序列化,因为根节点不在链表头部or尾部,所以无法定位根节点。拼接字符串时使用StringBuilder,性能,内存占用都好很多。使用String解答成功: 执行耗时:22ms,击败了34.30%的Java用户 内存消耗:41.5MB,击败了8.19%的Java用户复制使用StringBuilder解答成功: 执行耗时:10ms,击败了78.18%的Java用户 内存消耗:39.8MB,击败了93.36%的Java用户复制题目序列化是将一个数据结构或者对象转换为连续的比特位的操作,进而可以将转换后的数据存储在一个文件或者内存中,同时也可以通过网络传输到另一个计算机环境,采取相反方式重构得到原数据。请设计一个算法来实现二叉树的序列化与反序列化。这里不限定你的序列/反序
生产者把消息发送到消息队列中以后,并不期望被立即消费,而是等待指定时间后才可以被消费者消费,这类消息通常被称为延迟消息。延迟消息的应用场景其实是非常的广泛,比如以下的场景:网上直播授课时,在课程开始前15分钟通知所有学生准备上课。订单提交成功后1个小时内未支付,订单需要及时关闭并且释放对应商品的库存。用户超过15天未登录时,给该用户发送召回推送。工单提交后超过24小时未处理,向相关责任人发送催促处理的提醒。针对延迟消息,本文向大家分享五种实现方案,下面我们就来逐一讨论各种方案的大致实现和优缺点。一、Redis在Redis中,有一种有序集合(SortedSet)的数据结构,在有序集合中,所有元素是按照其Score进行排序的。我们可以把消息被消费的预期时间戳作为Score,定时任务不断读取Score大于当前时间的元素即可。基本流程如下:调用API,传入执行时间、消息体等数据。生成唯一key,把消息体数据序列化后存入Redis的String结构中。把key和执行时间的时间戳存入Redis的有序集合结构中,有序集合中不存储具体的消息体数据,而是存储唯一的key。定时任务不断读取时间戳最小的消息
目前EasyGBS视频管理平台已经在官网更新到了1.5.0的最新版本,大家可以下载测试。在上线官网之前,我们已经对新的版本进行了测试,测试期间发现,接入的webrtc的打洞程序stun老是容易打洞失败,导致webrtc无法播放。经过调研决定在easygbs中集成turn打洞程序,但是遇到一个问题就是接入的新的打洞程序中需要添加用户名和密码,然而目前的程序中是不包含的,因此需要对此处做一下优化。我们的处理方式是在EasyGBS的ini配置文件中添加如下配置,然后再建立打洞程序的时候传入给打洞服务,参考代码如下:eturn&ConfigST{mutex:sync.RWMutex{},Server:ServerST{HTTPPort:"",ICEServers:iceservers,WebRTCPortMin:uint16(conf.GetIniConf().Rtc_udp_min),WebRTCPortMax:uint16(conf.GetIniConf().Rtc_udp_max),WebRTCUserName:conf.GetIniConf().Rtc_us
原创|Java2020超神之路,很肝~ 中文详细注释的开源项目 RPC框架Dubbo源码解析网络应用框架Netty源码解析 消息中间件RocketMQ源码解析 数据库中间件Sharding-JDBC和MyCAT源码解析作业调度中间件Elastic-Job源码解析分布式事务中间件TCC-Transaction源码解析Eureka和Hystrix源码解析Java并发源码1、下面一段代码将注释和代码混在了一起,不认真看还真不知道。高亮显示后:2、看到这种多层嵌套恶心到头大。3、据说某俄国特工经过九死一生偷到了NASA的太空火箭发射程序的源代码的最后一页,代码是:))))))))))))))))))))))))))))))))))))))) ))))))))))))))))))))))))))))))))))))))))))))) )))))))))))))))))))))))))))))))))))))))))))))) ))))))))))))))))))))))))))))))))))))))))))))))))) ))))))))))))))))))))))))))))))))))))
前言部分大家可以关注我的公众号,公众号里的排版更好,阅读更舒适。正文部分ThesememoryIDscanbeaccessedinthedebugger,buttheoptionisn'taccessiblebydefaultinthe"new"Debugger.Todisplaythemyouhavetwooptions:InthenewDebugger,changeoneofthetoolsyou'reusing.Dothisbyclickingthe"NewTool"or"ReplaceTool"thatyoucanseeatthetopoftheverticalbuttoncolumnontherightofeachsubwindow.OpentheSpecialToolsfolderinthetreeandselect"SystemAreas(InternalOnly)".Inthesecondtabofthistoolyoucannowseealistofareas.Doub
可直接通过切换环境来实现多个环境中的参数切换。常用功能:环境地址切换、全局变量使用环境请求地址切换在"百度"下,新增”Cnblos随笔“文件夹开发环境地址http://www.xxx.dev/test.html测试环境地址http://www.xxx.pro/test.html选择“ManageEnvironments--Add”,在页面中设置环境信息:Environment(开发)->key(URL)->Value(http://www.xxx.dev),选择Submit再添加测试环境:Environment(测试)->key(URL)->Value(http://www.xxx.pro)在“Cnblogs随笔”文件夹内,添加请求“打开个人中心页面”:http://www.xxx.dev,修改“http://xxx.dev/”为"{{URL}}"实操选择Environment中的“测试”,点击“send”发送请求。即执行测试环境的请求选择Environment中的“开发”,点击“send”发送请求。即执行开发环境的请求全
mysql常见问题记录。1.最近迁移数据库和服务器,升级了使用的MYSQL的版本,由5.6升级到了5.7,之后同步了数据。本来感觉应该没啥问题,但是访问项目,突然发现居然有很多报错??报错的内容如下所示:1055Expression#8ofSELECTlistisnotinGROUPBYclauseandcontainsnonaggregatedcolumn复制一番查找以后,发现原来是因为mysql5.7默认使用的sql_mode与5.6有所变化。mysql5.7默认要求groupby中的列一定要出现在select中。 建议修改sql_mode,写入数据库配置my.cnf中。vim/etc/my.cnf #[mysqld]段中添加以下内容,重启mysql sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION :wq复制2.1292-Incorrectdatetimevalue:‘’for
“ 天下苦「假照」久矣。 ” AI科技评论按:天下苦「假照」久矣,作为世上闻名的「亚洲四大邪术」之一,中国PS术让人人皆可化身大片主人翁,与此同时也给现代社会带来了不少的困惑与恐慌——如今网上充斥大量的「移花接木」虚假内容,正冲击着数字媒体在普罗大众心中的信任感。鉴于此,Adobe公司的研究员与自加州大学伯克利分校的科学家合作开发出了一款可用于识别PS软件「液化」效果的工具。 PS软件的「液化」工具究竟有什么样神奇的魔力呢?雷锋网AI科技评论给大家从网上找来一个教学样板: 原来的照片 该照片被导入PS软件后,经历了一系列「向前变形」、「擦漏光」、「缩小」等「液化」工程后,最终生成的效果图如下: 是否很难相信这是同一个人? 近期很流行的老照片修复工作,虽然有人表示林徽因被整出了一张「网红脸」…… 为了破除这种由PS「液化」工具制造出来的「幻术」,Adobe与伯克利研究团队训练了一种可用于识别人像变化的卷积神经网络(CNN)。简单来说,这个工具最终要能回答以下三个问题: 我们能否创造出一款比人工识别更可靠的人像识别工具?该工具是否能识别出人像具体经历了哪些更改?我们可以撤消这些更改以恢复
1.固定保留指定位数的小数(非四舍五入) functionformatDecimal(num,decimal){ num=num.toString() letindex=num.indexOf('.') if(index!==-1){ num=num.substring(0,decimal+index+1) }else{ num=num.substring(0) } returnparseFloat(num).toFixed(decimal) }复制 2.获取ulr参数 functiongetUrlParam(name){ varreg=newRegExp("(^|&)"+name+"=([^&]*)(&|$)"); varr=window.location.search.substr(1).match(reg); if(r!=null)returnr[2]; returnnull; };复制
Kafka2.6引入的新功能:消费者能够主动触发Rebalance。一直以来,Rebalance的触发都是由Coordinator来执行的,但有些场景下消费者端能够主动触发Rebalance会很有必要。举个例子,在ConsumerPartitionAssignor接口中有个subscriptionUserData方法可以实现自定义的用户数据。之后在进行Rebalance时,Leader消费者可以根据这些自定义的用户数据执行特定逻辑的分区消费分配方案的制定。目前,倘若这些用户数据发生了变更,Kafka是不会开启Rebalance的。如果这些自定义数据非常影响分配方案的制定,那么唯一的做法就是调用KafkaConsumer的unsubscribe方法,显式地告知Coordinator成员要退出组。这样做的弊端在于,unsubscribe方法会回收当前已分配的分区。 针对这种场景,如果消费者能用“不退出组”的方式主动地发起Rebalance去刷新或提交最新的自定义用户数据,那么就可以解决这个场景中碰到的问题了。基于这些考量,社区于2.6引入了这个功能。主要体现在KafkaCon
/**压缩流 *按照完整文件目录压缩文件并下载,包含目录 *@dirs所有下载文件的完整路径名称集合 *@response *@zipname下载时的压缩文件命名 */ publicstaticbooleanfileAndDirToZip(List<String>dirs,Stringzipname,HttpServletResponseresponse){ booleanflag=false; ZipOutputStreamzos=null; ByteArrayOutputStreambyteTest=newByteArrayOutputStream(10*1024); byte[]b; try{ zos=newZipOutputStream(byteTest); for(inta=0;a<dirs.size();a++){ //将指定目录下的文件转换成数组流 //判断文件是否存在 if(!newFile(dirs.get(a)).exists()){ continue; } b=getBytes(dir
为什么使用Python 假设我们有这么一项任务:简单测试局域网中的电脑是否连通.这些电脑的ip范围从192.168.0.101到192.168.0.200. 思路:用shell编程.(Linux通常是bash而Windows是批处理脚本).例如,在Windows上用pingip的命令依次测试各个机器并得到控制台输出.由于ping通的时候控制台文本通常是"Replyfrom..."而不通的时候文本是"timeout...",所以,在结果中进行字符串查找,即可知道该机器是否连通.实现:Java代码如下: Stringcmd="cmd.exeping ";Stringipprefix="192.168.10.";int begin=101;int end=200;Processp=null;for(int i=begin;i<end;i++){p= Runtime.getRuntime().exec(cmd+i);Stringline = null;BufferedReaderreader =&n
我们知道,java提供了一种语言特性:内部类。一开始接触内部类,感觉这种机制确实很神奇,但是转念一想似乎这种机制又有些多余。因为我们完全可以用外部类的形式去实现和内部类相同的功能,比如我的上一篇文章中的工厂模式(http://blog.csdn.net/hmzdbql/article/details/7691055)。那么内部类到底有什么好处呢? 我们设想这样一种情形,如果有一个类A,一个类B他们分别实现了不同的功能(注意这个时候的A,B类都是实体类而不是抽象类或者接口)。现在我们需要写一个类C,它需要使用类A类B中的全部功能,也就是我们通过类C可以直接使用类A和类B中的方法。想想应该如何去实现呢?你或许想到了继承,的确继承是一个很好的方式。但是很快你就会发现悲剧:java不支持多继承...类C不可能以继承的方式去使用类A和类B中的所有方法。似乎没辙了...其实不然,这个时候内部类就派上了用场。看下面的代码: classA { publicvoidf() { //方法内容 } } classB { publicvoidg() { //方法内容 } } classCextendsA
1. cdk文档 https://material.angular.io/cdk/categories 2. platform模块提供获取平台信息,以及平台支持的功能 (1)在使用之前的先importPlatformModule模块到我们工程里面来(这也是使用cdk里面Platform里面功能的前提),比如咱们可以在app.module.ts文件里面引入。引入方式如下: import{PlatformModule}from'@angular/cdk/platform'; @NgModule({ ... imports:[ ..., PlatformModule, ... ], ... }) exportclassAppModule{ }复制 (2)有一个Service Platform类,用法也是非常的简单,就一些属性的使用。属性解释如下: Platform类属性类型解释 ANDROID boolean 当前平台是否android系统 IOS boolean 当前平台是否IOS系统 isBrowser boolean 当
最近开发了一套资讯相关的web页面,嵌套在微信中,可支持点赞、评论等...在文章详情中,图片需要点击放大,随手势放大缩小,左右可滑动切换,总之类似于微信公众号效果。 开始想的方案是用轮播插件、或者在img外面套一层a标签,a标签的链接放图片链接。 那么我来总结一下这两种方案的优缺点: 使用轮播插件: 1、效果酷炫; 2、可支持多种操作,如:手势缩放、旋转、滑动切换...; 3、缺点则是,插件无疑加大的移动端加载效率; 4、安卓设备下支持性不佳,出现卡顿。 使用a标签方法: 1、使用简单; 2、也是调用微信自带的照片浏览器,加载效果高、同样支持缩放手势操作; 3、界面简陋~low; 4、新开链接,有明显跳走效果。 有没有一种解决方案可以取长补短的?要求不高只要跟公众号打开图片浏览效果一样就可以了。 答案是:有,使用previewImage。 那么这是个什么鬼呢?(微信开发-预览图片接口) http://mp.weixin.qq.com/wiki/11/74ad127c
created(){ //添加快捷键 document.addEventListener('keyup',this.handleKeyUp) }, destroyed(){ //删除快捷键 document.removeEventListener('keyup',this.handleKeyUp) }, methods:{ //添加快捷键的事件处理 handleKeyUp(e){ e.preventDefault(); e.stopPropagation(); //点击Delete键 if(e.keyCode==46){ this.deleteCurContent();//删除组件或模板 } } } 复制