书画网站的建设目标,电脑网络连接不上怎么解决,莱芜网逃人员,文化传媒公司起名字大全免费原文#xff1a;TensorFlow 1.x Deep Learning Cookbook 协议#xff1a;CC BY-NC-SA 4.0 译者#xff1a;飞龙 本文来自【ApacheCN 深度学习 译文集】#xff0c;采用译后编辑#xff08;MTPE#xff09;流程来尽可能提升效率。 不要担心自己的形象#xff0c;只关心如… 原文TensorFlow 1.x Deep Learning Cookbook 协议CC BY-NC-SA 4.0 译者飞龙 本文来自【ApacheCN 深度学习 译文集】采用译后编辑MTPE流程来尽可能提升效率。 不要担心自己的形象只关心如何实现目标。——《原则》生活原则 2.3.c 六、循环神经网络
在本章中我们将介绍一些涵盖以下主题的秘籍
神经机器翻译-训练 seq2seq RNN神经机器翻译-推理 seq2seq RNN您只需要关注-seq2seq RNN 的另一个示例通过 RNN 学习写作莎士比亚学习使用 RNN 预测未来的比特币价值多对一和多对多 RNN 示例
介绍
在本章中我们将讨论循环神经网络RNN如何在保持顺序顺序重要的领域中用于深度学习。 我们的注意力将主要集中在文本分析和自然语言处理NLP上但我们还将看到用于预测比特币价值的序列示例。
通过采用基于时间序列的模型可以描述许多实时情况。 例如如果您考虑编写文档则单词的顺序很重要而当前单词肯定取决于先前的单词。 如果我们仍然专注于文本编写很明显单词中的下一个字符取决于前一个字符例如quick brown字符的下一个字母很有可能将会是字母fox如下图所示。 关键思想是在给定当前上下文的情况下生成下一个字符的分布然后从该分布中采样以生成下一个候选字符 用The quick brown fox句子进行预测的例子
一个简单的变体是存储多个预测因此创建一棵可能的扩展树如下图所示 The quick brown fox句子的预测树的示例
但是基于序列的模型可以在大量其他域中使用。 在音乐中乐曲中的下一个音符肯定取决于前一个音符而在视频中电影中的下一个帧必定与前一帧有关。 此外在某些情况下当前的视频帧单词字符或音符不仅取决于前一个而且还取决于后一个。
可以使用 RNN 描述基于时间序列的模型其中对于给定输入X[i]时间为i产生输出Y[i]将时间[0i-1]的以前状态的记忆反馈到网络。 反馈先前状态的想法由循环循环描述如下图所示 反馈示例
循环关系可以方便地通过展开网络来表示如下图所示 展开循环单元的例子
最简单的 RNN 单元由简单的 tanh 函数双曲正切函数组成如下图所示 个简单的 tanh 单元的例子
梯度消失和爆炸
训练 RNN 十分困难因为存在两个稳定性问题。 由于反馈回路的缘故梯度可能会迅速发散到无穷大或者它可能会迅速发散到 0。在两种情况下如下图所示网络将停止学习任何有用的东西。 可以使用基于梯度修剪的相对简单的解决方案来解决梯度爆炸的问题。 梯度消失的问题更难解决它涉及更复杂的 RNN 基本单元的定义例如长短期记忆LSTM或门控循环单元GRU。 让我们首先讨论梯度爆炸和梯度裁剪 梯度示例
梯度裁剪包括对梯度施加最大值以使其无法无限增长。 下图所示的简单解决方案为梯度爆炸问题提供了简单的解决方案 梯度裁剪的例子
解决梯度消失的问题需要一种更复杂的内存模型该模型可以选择性地忘记先前的状态只记住真正重要的状态。 考虑下图输入以[0,1]中的概率p写入存储器M中并乘以加权输入。
以类似的方式以[0,1]中的概率p读取输出将其乘以加权输出。 还有一种可能性用来决定要记住或忘记的事情 存储单元的一个例子
长短期记忆LSTM
LSTM 网络可以控制何时让输入进入神经元何时记住在上一个时间步中学到的内容以及何时让输出传递到下一个时间戳。 所有这些决定都是自调整的并且仅基于输入。 乍一看LSTM 看起来很难理解但事实并非如此。 让我们用下图来说明它是如何工作的 LSTM 单元的一个例子
首先我们需要一个逻辑函数σ请参见第 2 章“回归”来计算介于 0 和 1 之间的值并控制哪些信息流过 LSTM 门。 请记住逻辑函数是可微的因此允许反向传播。 然后我们需要一个运算符⊗它采用两个相同维的矩阵并生成另一个矩阵其中每个元素ij是原始两个矩阵的元素ij的乘积。 同样我们需要一个运算符⊕它采用两个相同维度的矩阵并生成另一个矩阵其中每个元素ij是原始两个矩阵的元素ij之和。 使用这些基本块我们考虑时间i处的输入X[i]并将其与上一步中的输出Y[i-1]并置。
方程f[t] σ(W[f] · [y[i-1], x[t]] b[f])实现了控制激活门⊗的逻辑回归并用于确定应从先前候选值C[i-1]获取多少信息。 传递给下一个候选值C[i]此处W[f]和b[f]矩阵和用于逻辑回归的偏差。如果 Sigmoid 输出为 1则表示不要忘记先前的单元格状态C[i-1]如果输出 0 这将意味着忘记先前的单元状态C[i-1]。(0, 1)中的任何数字都将表示要传递的信息量。
然后我们有两个方程s[i] σ(W[s] · [Y[i-1], x[i]] b[s])用于通过⊗控制由当前单元产生的多少信息Ĉ[i] tanh(W [C] · [Y[i-1] X[i] b[c])应该通过⊕运算符添加到下一个候选值C[i]中根据上图中表示的方案。
为了实现与运算符⊕和⊗所讨论的内容我们需要另一个方程其中进行实际的加法和乘法*C[i] f[t] * C[i-1] s[i] * Ĉ[i]
最后我们需要确定当前单元格的哪一部分应发送到Y[i]输出。 这很简单我们再进行一次逻辑回归方程然后通过⊗运算来控制应使用哪一部分候选值输出。 在这里有一点值得关注使用 tanh 函数将输出压缩为[-1, 1]。 最新的步骤由以下公式描述 现在我了解到这看起来像很多数学运算但有两个好消息。 首先如果您了解我们想要实现的目标那么数学部分并不是那么困难。 其次您可以将 LSTM 单元用作标准 RNN 单元的黑盒替代并立即获得解决梯度消失问题的好处。 因此您实际上不需要了解所有数学知识。 您只需从库中获取 TensorFlow LSTM 实现并使用它即可。
门控循环单元GRU和窥孔 LSTM
近年来提出了许多 LSTM 单元的变体。 其中两个真的很受欢迎。 窥孔 LSTM 允许栅极层查看单元状态如下图虚线所示而门控循环单元GRU将隐藏状态和单元状态和合并为一个单一的信息渠道。
同样GRU 和 Peephole LSTM 都可以用作标准 RNN 单元的黑盒插件而无需了解基础数学。 这两个单元都可用于解决梯度消失的问题并可用于构建深度神经网络 标准 LSTMPeepHole LSTM 和 GRU 的示例
向量序列的运算
使 RNN 真正强大的是能够对向量序列进行操作的能力其中 RNN 的输入和/或 RNN 的输出都可以是序列。 下图很好地表示了这一点其中最左边的示例是传统的非循环网络其后是带有输出序列的 RNN然后是带有输入序列的 RNN再是带有序列的 RNN 在不同步序列的输入和输出中然后是在序列同步的输入和输出中具有序列的 RNN RNN 序列的一个例子
机器翻译是输入和输出中不同步序列的一个示例网络将输入文本作为序列读取在读取全文之后会输出目标语言。
视频分类是输入和输出中同步序列的示例视频输入是帧序列并且对于每个帧输出中都提供了分类标签。
如果您想了解有关 RNN 有趣应用的更多信息则必须阅读 Andrej Karpathy 发布的博客。 他训练了网络以莎士比亚的风格撰写论文用 Karpathy 的话说几乎不能从实际的莎士比亚中识别出这些样本撰写有关虚构主题的现实 Wikipedia 文章撰写关于愚蠢和不现实问题的现实定理证明用 Karpathy 的话更多的幻觉代数几何并写出现实的 Linux 代码片段用 Karpathy 的话他首先建模逐个字符地列举 GNU 许可证其中包括一些示例然后生成一些宏然后深入研究代码。
以下示例摘自这个页面 用 RNN 生成的文本示例
神经机器翻译 – 训练 seq2seq RNN
序列到序列seq2seq是 RNN 的一种特殊类型已成功应用于神经机器翻译文本摘要和语音识别中。 在本秘籍中我们将讨论如何实现神经机器翻译其结果与 Google 神经机器翻译系统。 关键思想是输入整个文本序列理解整个含义然后将翻译输出为另一个序列。 读取整个序列的想法与以前的架构大不相同在先前的架构中将一组固定的单词从一种源语言翻译成目标语言。
本节的灵感来自 Minh-Thang Luong 的 2016 年博士学位论文《神经机器翻译》。 第一个关键概念是编码器-解码器架构的存在其中编码器将源句子转换为代表含义的向量。 然后此向量通过解码器以产生翻译。 编码器和解码器都是 RNN它们可以捕获语言中的长期依赖关系例如性别协议和语法结构而无需先验地了解它们并且不需要跨语言进行 11 映射。 这是一种强大的功能可实现非常流畅的翻译 编解码器的示例
让我们看一个 RNN 的示例该语句将She loves cute cats翻译成Elle Aime les chat Mignons。
有两种 RNN一种充当编码器另一种充当解码器。 源句She loves cute cats后跟一个分隔符-目标句是Elle aime les chats mignons。 这两个连接的句子在输入中提供给编码器进行训练并且解码器将生成目标目标。 当然我们需要像这样的多个示例来获得良好的训练 NMT 序列模型的示例
现在我们可以拥有许多 RNN 变体。 让我们看看其中的一些
RNN 可以是单向或双向的。 后者将捕捉双方的长期关系。RNN 可以具有多个隐藏层。 选择是关于优化的问题一方面更深的网络可以学到更多另一方面更深的网络可以学到更多。 另一方面可能需要很长的时间来训练并且可能会过头。RNN 可以具有一个嵌入层该层将单词映射到一个嵌入空间中在该空间中相似的单词恰好被映射得非常近。RNNs 可以使用简单的或者循环的单元或 LSTM或窥视孔 LSTM或越冬。
仍然参考博士学位论文《神经机器翻译》我们可以使用嵌入层来将输入语句放入嵌入空间。 然后有两个 RNN 粘在一起——源语言的编码器和目标语言的解码器。 如您所见存在多个隐藏层并且有两个流程前馈垂直方向连接这些隐藏层水平方向是将知识从上一步转移到下一层的循环部分 神经机器翻译的例子
在本秘籍中我们使用 NMT神经机器翻译这是一个可在 TensorFlow 顶部在线获得的翻译演示包。
准备
NMT 可在这个页面上找到并且代码在 GitHub 上。
操作步骤
我们按以下步骤进行
从 GitHub 克隆 NMT
git clone https://github.com/tensorflow/nmt/下载训练数据集。 在这种情况下我们将使用训练集将越南语翻译为英语。 其他数据集可从这里获取其他语言例如德语和捷克语
nmt/scripts/download_iwslt15.sh /tmp/nmt_data考虑这里我们将定义第一个嵌入层。 嵌入层接受输入词汇量 V 和输出嵌入空间的所需大小。 词汇量使得仅考虑 V 中最频繁的单词进行嵌入而所有其他单词都映射到一个常见的未知项。 在我们的例子中输入是主要时间的这意味着最大时间是第一个输入参数
# Embeddingembedding_encoder variable_scope.get_variable(embedding_encoder, [src_vocab_size, embedding_size], ...)# Look up embedding:# encoder_inputs: [max_time, batch_size]# encoder_emb_inp: [max_time, batch_size, embedding_size]encoder_emb_inp embedding_ops.embedding_lookup(embedding_encoder, encoder_inputs)仍然参考这里我们定义了一个简单的编码器它使用tf.nn.rnn_cell.BasicLSTMCell(num_units)作为基本 RNN 单元。 这非常简单但是要注意给定基本的 RNN 单元我们使用tf.nn.dynamic_rnn创建 RNN
# Build RNN cellencoder_cell tf.nn.rnn_cell.BasicLSTMCell(num_units)# Run Dynamic RNN# encoder_outpus: [max_time, batch_size, num_units]# encoder_state: [batch_size, num_units]encoder_outputs, encoder_state tf.nn.dynamic_rnn(encoder_cell, encoder_emb_inp,sequence_lengthsource_sequence_length, time_majorTrue)之后我们需要定义解码器。 因此第一件事是拥有一个带有tf.nn.rnn_cell.BasicLSTMCell的基本 RNN 单元然后将其用于创建一个基本采样解码器tf.contrib.seq2seq.BasicDecoder该基本采样解码器将用于与解码器tf.contrib.seq2seq.dynamic_decode进行动态解码
# Build RNN celldecoder_cell tf.nn.rnn_cell.BasicLSTMCell(num_units)
# Helperhelper tf.contrib.seq2seq.TrainingHelper(decoder_emb_inp, decoder_lengths, time_majorTrue)# Decoderdecoder tf.contrib.seq2seq.BasicDecoder(decoder_cell, helper, encoder_state,output_layerprojection_layer)# Dynamic decodingoutputs, _ tf.contrib.seq2seq.dynamic_decode(decoder, ...)logits outputs.rnn_output网络的最后一个阶段是 softmax 密集阶段用于将顶部隐藏状态转换为对率向量
projection_layer layers_core.Dense(tgt_vocab_size, use_biasFalse)当然我们需要定义交叉熵函数和训练阶段使用的损失
crossent tf.nn.sparse_softmax_cross_entropy_with_logits(labelsdecoder_outputs, logitslogits)train_loss (tf.reduce_sum(crossent * target_weights) /batch_size)下一步是定义反向传播所需的步骤并使用适当的优化器在本例中为 Adam。 请注意梯度已被裁剪Adam 使用预定义的学习率
# Calculate and clip gradientsparams tf.trainable_variables()gradients tf.gradients(train_loss, params)clipped_gradients, _ tf.clip_by_global_norm(gradients, max_gradient_norm)
# Optimizationoptimizer tf.train.AdamOptimizer(learning_rate)update_step optimizer.apply_gradients(zip(clipped_gradients, params))现在我们可以运行代码并了解不同的执行步骤。 首先创建训练图。 然后训练迭代开始。 用于评估的度量标准是双语评估研究BLEU。 此度量标准是评估已从一种自然语言机器翻译成另一种自然语言的文本质量的标准。 质量被认为是机器与人工输出之间的对应关系。 如您所见该值随时间增长
python -m nmt.nmt --srcvi --tgten --vocab_prefix/tmp/nmt_data/vocab --train_prefix/tmp/nmt_data/train --dev_prefix/tmp/nmt_data/tst2012 --test_prefix/tmp/nmt_data/tst2013 --out_dir/tmp/nmt_model --num_train_steps12000 --steps_per_stats100 --num_layers2 --num_units128 --dropout0.2 --metricsbleu
# Job id 0
[...]
# creating train graph ...
num_layers 2, num_residual_layers0
cell 0 LSTM, forget_bias1 DropoutWrapper, dropout0.2 DeviceWrapper, device/gpu:0
cell 1 LSTM, forget_bias1 DropoutWrapper, dropout0.2 DeviceWrapper, device/gpu:0
cell 0 LSTM, forget_bias1 DropoutWrapper, dropout0.2 DeviceWrapper, device/gpu:0
cell 1 LSTM, forget_bias1 DropoutWrapper, dropout0.2 DeviceWrapper, device/gpu:0
start_decay_step0, learning_rate1, decay_steps 10000,decay_factor 0.98
[...]
# Start step 0, lr 1, Thu Sep 21 12:57:18 2017
# Init train iterator, skipping 0 elements
global step 100 lr 1 step-time 1.65s wps 3.42K ppl 1931.59 bleu 0.00
global step 200 lr 1 step-time 1.56s wps 3.59K ppl 690.66 bleu 0.00
[...]
global step 9100 lr 1 step-time 1.52s wps 3.69K ppl 39.73 bleu 4.89
global step 9200 lr 1 step-time 1.52s wps 3.72K ppl 40.47 bleu 4.89
global step 9300 lr 1 step-time 1.55s wps 3.62K ppl 40.59 bleu 4.89
[...]
# External evaluation, global step 9000
decoding to output /tmp/nmt_model/output_dev.
done, num sentences 1553, time 17s, Thu Sep 21 17:32:49 2017.
bleu dev: 4.9
saving hparams to /tmp/nmt_model/hparams
# External evaluation, global step 9000
decoding to output /tmp/nmt_model/output_test.
done, num sentences 1268, time 15s, Thu Sep 21 17:33:06 2017.
bleu test: 3.9
saving hparams to /tmp/nmt_model/hparams
[...]
global step 9700 lr 1 step-time 1.52s wps 3.71K ppl 38.01 bleu 4.89工作原理
所有上述代码已在这个页面中定义。 关键思想是将两个 RNN 打包在一起。 第一个是编码器它在嵌入空间中工作非常紧密地映射相似的单词。 编码器理解训练示例的含义并产生张量作为输出。 然后只需将编码器的最后一个隐藏层连接到解码器的初始层即可将该张量传递给解码器。 注意力学习是由于我们基于与labelsdecoder_outputs的交叉熵的损失函数而发生的。
该代码学习如何翻译并通过 BLEU 度量标准通过迭代跟踪进度如下图所示 Tensorboard 中的 BLEU 指标示例
神经机器翻译 – 用 seq2seq RNN 推理
在此秘籍中我们使用先前秘籍的结果将源语言转换为目标语言。 这个想法非常简单给源语句提供两个组合的 RNN编码器解码器作为输入。 句子一结束解码器将产生对率值我们贪婪地产生与最大值关联的单词。 例如从解码器产生单词moi作为第一个令牌因为该单词具有最大对率值。 之后会产生单词suis依此类推 具有概率的 NM 序列模型的示例
使用解码器的输出有多种策略
贪婪产生对应最大对率的字采样通过对产生的对率进行采样来产生单词集束搜索一个以上的预测因此创建了可能的扩展树
操作步骤
我们按以下步骤进行
定义用于对解码器进行采样的贪婪策略。 这很容易因为我们可以使用tf.contrib.seq2seq.GreedyEmbeddingHelper中定义的库。 由于我们不知道目标句子的确切长度因此我们将启发式方法限制为最大长度为源句子长度的两倍
# Helperhelper tf.contrib.seq2seq.GreedyEmbeddingHelper(embedding_decoder,tf.fill([batch_size], tgt_sos_id), tgt_eos_id)# Decoderdecoder tf.contrib.seq2seq.BasicDecoder(decoder_cell, helper, encoder_state,output_layerprojection_layer)# Dynamic decodingoutputs, _ tf.contrib.seq2seq.dynamic_decode(decoder, maximum_iterationsmaximum_iterations)translations outputs.sample_id
maximum_iterations tf.round(tf.reduce_max(source_sequence_length) * 2)现在我们可以运行网络输入一个从未见过的句子inference_input_file/tmp/my_infer_file然后让网络翻译结果inference_output_file/tmp/nmt_model/output_infer
python -m nmt.nmt \--out_dir/tmp/nmt_model \--inference_input_file/tmp/my_infer_file.vi \--inference_output_file/tmp/nmt_model/output_infer工作原理
将两个 RNN 打包在一起以形成编码器-解码器 RNN 网络。 解码器产生对率然后将其贪婪地转换为目标语言的单词。 例如此处显示了从越南语到英语的自动翻译
用英语输入的句子小时候我认为朝鲜是世界上最好的国家我经常唱歌。 我们没有什么可嫉妒的。翻译成英语的输出句子当我非常好时我将去了解最重要的事情而我不确定该说些什么。
您只需要注意力 – seq2seq RNN 的另一个示例
在本秘籍中我们介绍了注意力方法Dzmitry BahdanauKyunghyun Cho 和 Yoshua BengioICLR 2015这是神经网络翻译的最新解决方案。 它包括在编码器和解码器 RNN 之间添加其他连接。 实际上仅将解码器与编码器的最新层连接会带来信息瓶颈并且不一定允许通过先前的编码器层获取的信息通过。 下图说明了采用的解决方案 NMT 注意力模型的示例
需要考虑三个方面
首先将当前目标隐藏状态与所有先前的源状态一起使用以得出注意力权重该注意力权重用于或多或少地关注序列中先前看到的标记其次创建上下文向量以汇总注意力权重的结果第三将上下文向量与当前目标隐藏状态组合以获得注意力向量
操作步骤
我们按以下步骤进行
使用库tf.contrib.seq2seq.LuongAttention定义注意力机制该库实现了 Minh-Thang LuongHieu Pham 和 Christopher D. Manning2015 年在《基于注意力的神经机器翻译有效方法》中定义的注意力模型
# attention_states: [batch_size, max_time, num_units]attention_states tf.transpose(encoder_outputs, [1, 0, 2])# Create an attention mechanismattention_mechanism tf.contrib.seq2seq.LuongAttention(num_units, attention_states,memory_sequence_lengthsource_sequence_length)通过注意力包装器将定义的注意力机制用作解码器单元周围的包装器
decoder_cell tf.contrib.seq2seq.AttentionWrapper(decoder_cell, attention_mechanism,attention_layer_sizenum_units)运行代码以查看结果。 我们立即注意到注意力机制在 BLEU 得分方面产生了显着改善
python -m nmt.nmt \--attentionscaled_luong \--srcvi --tgten \--vocab_prefix/tmp/nmt_data/vocab \--train_prefix/tmp/nmt_data/train \--dev_prefix/tmp/nmt_data/tst2012 \--test_prefix/tmp/nmt_data/tst2013 \--out_dir/tmp/nmt_attention_model \--num_train_steps12000 \--steps_per_stats100 \--num_layers2 \--num_units128 \--dropout0.2 \--metricsbleu
[...]
# Start step 0, lr 1, Fri Sep 22 22:49:12 2017
# Init train iterator, skipping 0 elements
global step 100 lr 1 step-time 1.71s wps 3.23K ppl 15193.44 bleu 0.00
[...]
# Final, step 12000 lr 0.98 step-time 1.67 wps 3.37K ppl 14.64, dev ppl 14.01, dev bleu 15.9, test ppl 12.58, test bleu 17.5, Sat Sep 23 04:35:42 2017
# Done training!, time 20790s, Sat Sep 23 04:35:42 2017.
# Start evaluating saved best models.
[..]
loaded infer model parameters from /tmp/nmt_attention_model/best_bleu/translate.ckpt-12000, time 0.06s
# 608
src: nhưng bạn biết điều gì không ?
ref: But you know what ?
nmt: But what do you know ?
[...]
# Best bleu, step 12000 step-time 1.67 wps 3.37K, dev ppl 14.01, dev bleu 15.9, test ppl 12.58, test bleu 17.5, Sat Sep 23 04:36:35 2017工作原理
注意是一种机制该机制使用由编码器 RNN 的内部状态获取的信息并将该信息与解码器的最终状态进行组合。 关键思想是通过这种方式有可能或多或少地关注源序列中的某些标记。 下图显示了 BLEU 得分引起了关注。
我们注意到相对于我们第一个秘籍中未使用任何注意力的图表而言它具有明显的优势 Tensorboard 中注意力的 BLEU 指标示例
更多
值得记住的是 seq2seq 不仅可以用于机器翻译。 让我们看一些例子
Lukasz Kaiser 在作为外语的语法中使用 seq2seq 模型来构建选区解析器。 选区分析树将文本分为多个子短语。 树中的非终结符是短语的类型终结符是句子中的单词并且边缘未标记。seq2seq 的另一个应用是 SyntaxNet又名 Parsey McParserFace语法分析器它是许多 NLU 系统中的关键第一组件。 给定一个句子作为输入它将使用描述单词的句法特征的词性POS标签标记每个单词并确定句子中单词之间的句法关系在依存关系分析树中表示。 这些句法关系与所讨论句子的潜在含义直接相关。
下图使我们对该概念有了一个很好的了解 SyntaxNet 的一个例子
通过 RNN 学习写作莎士比亚
在本秘籍中我们将学习如何生成与威廉·莎士比亚William Shakespeare相似的文本。 关键思想很简单我们将莎士比亚写的真实文本作为输入并将其作为输入 RNN 的输入该 RNN 将学习序列。 然后将这种学习用于生成新文本该文本看起来像最伟大的作家用英语撰写的文本。
为了简单起见我们将使用框架 TFLearn它在 TensorFlow 上运行。 此示例是标准分发版的一部分可从以下位置获得。开发的模型是 RNN 字符级语言模型其中考虑的序列是字符序列而不是单词序列。
操作步骤
我们按以下步骤进行
使用pip安装 TFLearn
pip install -I tflearn导入许多有用的模块并下载一个由莎士比亚撰写的文本示例。 在这种情况下我们使用这个页面中提供的一种
import os
import pickle
from six.moves import urllib
import tflearn
from tflearn.data_utils import *
path shakespeare_input.txt
char_idx_file char_idx.pickle
if not os.path.isfile(path): urllib.request.urlretrieve(https://raw.githubusercontent.com/tflearn/tflearn.github.io/master/resources/shakespeare_input.txt, path)使用string_to_semi_redundant_sequences()将输入的文本转换为向量并返回解析的序列和目标以及相关的字典该函数将返回一个元组输入目标字典
maxlen 25
char_idx None
if os.path.isfile(char_idx_file):
print(Loading previous char_idx)
char_idx pickle.load(open(char_idx_file, rb))
X, Y, char_idx \
textfile_to_semi_redundant_sequences(path, seq_maxlenmaxlen, redun_step3,
pre_defined_char_idxchar_idx)
pickle.dump(char_idx, open(char_idx_file,wb))定义一个由三个 LSTM 组成的 RNN每个 LSTM 都有 512 个节点并返回完整序列而不是仅返回最后一个序列输出。 请注意我们使用掉线模块连接 LSTM 模块的可能性为 50%。 最后一层是密集层其应用 softmax 的长度等于字典大小。 损失函数为categorical_crossentropy优化器为 Adam
g tflearn.input_data([None, maxlen, len(char_idx)])
g tflearn.lstm(g, 512, return_seqTrue)
g tflearn.dropout(g, 0.5)
g tflearn.lstm(g, 512, return_seqTrue)
g tflearn.dropout(g, 0.5)
g tflearn.lstm(g, 512)
g tflearn.dropout(g, 0.5)
g tflearn.fully_connected(g, len(char_idx), activationsoftmax)
g tflearn.regression(g, optimizeradam, losscategorical_crossentropy,
learning_rate0.001)给定步骤 4 中定义的网络我们现在可以使用库flearn.models.generator.SequenceGeneratornetworkdictionarychar_idx, seq_maxlenmaxle和clip_gradients5.0, checkpoint_pathmodel_shakespeare生成序列
m tflearn.SequenceGenerator(g, dictionarychar_idx,
seq_maxlenmaxlen,
clip_gradients5.0,
checkpoint_pathmodel_shakespeare)对于 50 次迭代我们从输入文本中获取随机序列然后生成一个新文本。 温度正在控制所创建序列的新颖性 温度接近 0 看起来像用于训练的样本而温度越高新颖性越强
for i in range(50):
seed random_sequence_from_textfile(path, maxlen)
m.fit(X, Y, validation_set0.1, batch_size128,
n_epoch1, run_idshakespeare)
print(-- TESTING...)
print(-- Test with temperature of 1.0 --)
print(m.generate(600, temperature1.0, seq_seedseed))
print(-- Test with temperature of 0.5 --)
print(m.generate(600, temperature0.5, seq_seedseed))工作原理
当新的未知或被遗忘的艺术品要归功于作者时有著名的学者将其与作者的其他作品进行比较。 学者们要做的是在著名作品的文本序列中找到共同的模式希望在未知作品中找到相似的模式。
这种方法的工作方式相似RNN 了解莎士比亚作品中最特殊的模式是什么然后将这些模式用于生成新的从未见过的文本这些文本很好地代表了最伟大的英语作者的风格。
让我们看一些执行示例
python shakespeare.py
Loading previous char_idx
Vectorizing text...
Text total length: 4,573,338
Distinct chars : 67
Total sequences : 1,524,438
---------------------------------
Run id: shakespeare
Log directory: /tmp/tflearn_logs/第一次迭代
在这里网络正在学习一些基本结构包括需要建立有关虚构字符DIASURYONTHRNTLGIPRMAR和ARILEN的对话。 但是英语仍然很差很多单词不是真正的英语
---------------------------------
Training samples: 1371994
Validation samples: 152444
--
Training Step: 10719 | total loss: 2.22092 | time: 22082.057s
| Adam | epoch: 001 | loss: 2.22092 | val_loss: 2.12443 -- iter: 1371994/1371994
-- TESTING...
-- Test with temperature of 1.0 --
st thou, malice?
If thou caseghough memet oud mame meardke. Afs weke wteak, Dy ny wold as to of my tho gtroy ard has seve, hor then that wordith gole hie, succ, caight fom?
DIA:
A gruos ceen, I peey
by my
Wiouse rat Sebine would.
waw-this afeean.
SURYONT:
Teeve nourterong a oultoncime buciceis furtutun
Ame my sorivass; a mut my peant?
Am:
Fe, that lercom ther the nome, me, paatuy corns wrazen meas ghomnge const pheale,
As yered math thy vans:
I im foat worepoug and thit mije woml!
HRNTLGIPRMAR:
Id derfomquesf thiy of doed ilasghele hanckol, my corire-hougangle!
Kiguw troll! you eelerd tham my fom Inow lith a
-- Test with temperature of 0.5 --
st thou, malice?
If thou prall sit I har, with and the sortafe the nothint of the fore the fir with with the ceme at the ind the couther hit yet of the sonsee in solles and that not of hear fore the hath bur.
ARILEN:
More you a to the mare me peod sore,
And fore string the reouck and and fer to the so has the theat end the dore; of mall the sist he the bot courd wite be the thoule the to nenge ape and this not the the ball bool me the some that dears,
The be to the thes the let the with the thear tould fame boors and not to not the deane fere the womour hit muth so thand the e meentt my to the treers and woth and wi经过几次迭代
在这里网络开始学习对话的正确结构并且使用Well, there shall the things to need the offer to our heart和There is not that be so then to the death To make the body and all the mind这样的句子书面英语看起来更正确
---------------------------------
Training samples: 1371994
Validation samples: 152444
--
Training Step: 64314 | total loss: 1.44823 | time: 21842.362s
| Adam | epoch: 006 | loss: 1.44823 | val_loss: 1.40140 -- iter: 1371994/1371994
--
-- Test with temperature of 0.5 --
in this kind.
THESEUS:
There is not that be so then to the death
To make the body and all the mind.
BENEDICK:
Well, there shall the things to need the offer to our heart,
To not are he with him: I have see the hands are to true of him that I am not,
The whom in some the fortunes,
Which she were better not to do him?
KING HENRY VI:
I have some a starter, and and seen the more to be the boy, and be such a plock and love so say, and I will be his entire,
And when my masters are a good virtues,
That see the crown of our worse,
This made a called grace to hear him and an ass,
And the provest and stand,更多
博客文章循环神经网络的不合理有效性描述了一组引人入胜的示例 RNN 字符级语言模型包括以下内容
莎士比亚文本生成类似于此示例Wikipedia 文本生成类似于此示例但是基于不同的训练文本代数几何LaTex文本生成类似于此示例但基于不同的训练文本Linux 源代码文本的生成与此示例相似但是基于不同的训练文本婴儿命名文本的生成与此示例类似但是基于不同的训练文本
学习使用 RNN 预测未来的比特币价值
在本秘籍中我们将学习如何使用 RNN 预测未来的比特币价值。 关键思想是过去观察到的值的时间顺序可以很好地预测未来的值。 对于此秘籍我们将使用 MIT 许可下的这个页面上提供的代码。 给定时间间隔的比特币值通过 API 从这里下载。 这是 API 文档的一部分
We offer historical data from our Bitcoin Price Index through the following endpoint: https://api.coindesk.com/v1/bpi/historical/close.json By default, this will return the previous 31 days worth of data. This endpoint accepts the following optional parameters: ?index[USD/CNY]The index to return data for. Defaults to USD. ?currencyVALUEThe currency to return the data in, specified in ISO 4217 format. Defaults to USD. ?startVALUEendVALUE Allows data to be returned for a specific date range. Must be listed as a pair of start and end parameters, with dates supplied in the YYYY-MM-DD format, e.g. 2013-09-01 for September 1st, 2013. ?foryesterday Specifying this will return a single value for the previous day. Overrides the start/end parameter. Sample Request: https://api.coindesk.com/v1/bpi/historical/close.json?start2013-09-01end2013-09-05 Sample JSON Response: {bpi:{2013-09-01:128.2597,2013-09-02:127.3648,2013-09-03:127.5915,2013-09-04:120.5738,2013-09-05:120.5333},disclaimer:This data was produced from the CoinDesk Bitcoin Price Index. BPI value data returned as USD.,time:{updated:Sep 6, 2013 00:03:00 UTC,updatedISO:2013-09-06T00:03:0000:00}}操作步骤
这是我们进行秘籍的方法
克隆以下 GitHub 存储库。 这是一个鼓励用户尝试使用 seq2seq 神经网络架构的项目
git clone https://github.com/guillaume-chevalier/seq2seq-signal-prediction.git给定前面的存储库请考虑以下函数这些函数可加载和标准化 USD 或 EUR 比特币值的比特币历史数据。 这些特征在dataset.py中定义。 训练和测试数据根据 80/20 规则分开。 因此测试数据的 20% 是最新的历史比特币值。 每个示例在特征轴/维度中包含 40 个 USD 数据点然后包含 EUR 数据。 根据平均值和标准差对数据进行归一化。 函数generate_x_y_data_v4生成大小为batch_size的训练数据分别是测试数据的随机样本
def loadCurrency(curr, window_size):Return the historical data for the USD or EUR bitcoin value. Is done with an web API call.curr USD | EUR# For more info on the URL call, it is inspired by :# https://github.com/Levino/coindesk-api-noder requests.get(http://api.coindesk.com/v1/bpi/historical/close.json?start2010-07-17end2017-03-03currency{}.format(curr))data r.json()time_to_values sorted(data[bpi].items())values [val for key, val in time_to_values]kept_values values[1000:]X []Y []for i in range(len(kept_values) - window_size * 2):X.append(kept_values[i:i window_size])Y.append(kept_values[i window_size:i window_size * 2])# To be able to concat on inner dimension later on:X np.expand_dims(X, axis2)Y np.expand_dims(Y, axis2)return X, Y
def normalize(X, YNone):Normalise X and Y according to the mean and standard
deviation of the X values only.# # It would be possible to normalize with last rather than mean, such as:# lasts np.expand_dims(X[:, -1, :], axis1)# assert (lasts[:, :] X[:, -1, :]).all(), {}, {}, {}. {}.format(lasts[:, :].shape, X[:, -1, :].shape, lasts[:, :], X[:, -1, :])mean np.expand_dims(np.average(X, axis1) 0.00001, axis1)stddev np.expand_dims(np.std(X, axis1) 0.00001, axis1)# print (mean.shape, stddev.shape)# print (X.shape, Y.shape)X X - meanX X / (2.5 * stddev)if Y is not None:assert Y.shape X.shape, (Y.shape, X.shape)Y Y - meanY Y / (2.5 * stddev)return X, Yreturn Xdef fetch_batch_size_random(X, Y, batch_size):Returns randomly an aligned batch_size of X and Y among all examples.The external dimension of X and Y must be the batch size
(eg: 1 column 1 example).X and Y can be N-dimensional.assert X.shape Y.shape, (X.shape, Y.shape)idxes np.random.randint(X.shape[0], sizebatch_size)X_out np.array(X[idxes]).transpose((1, 0, 2))Y_out np.array(Y[idxes]).transpose((1, 0, 2))return X_out, Y_out
X_train []
Y_train []
X_test []
Y_test []def generate_x_y_data_v4(isTrain, batch_size):Return financial data for the bitcoin.Features are USD and EUR, in the internal dimension.We normalize X and Y data according to the X only to notspoil the predictions we ask for.For every window (window or seq_length), Y is the prediction following X.Train and test data are separated according to the 80/20
rule.Therefore, the 20 percent of the test data are the mostrecent historical bitcoin values. Every example in X contains40 points of USD and then EUR data in the feature axis/dimension.It is to be noted that the returned X and Y has the same shapeand are in a tuple.# 40 pas values for encoder, 40 after for decoders predictions.seq_length 40global Y_trainglobal X_trainglobal X_testglobal Y_test# First load, with memoization:if len(Y_test) 0:# API call:X_usd, Y_usd loadCurrency(USD,
window_sizeseq_length)X_eur, Y_eur loadCurrency(EUR,
window_sizeseq_length)# All data, aligned:X np.concatenate((X_usd, X_eur), axis2)Y np.concatenate((Y_usd, Y_eur), axis2)X, Y normalize(X, Y)# Split 80-20:X_train X[:int(len(X) * 0.8)]Y_train Y[:int(len(Y) * 0.8)]X_test X[int(len(X) * 0.8):]Y_test Y[int(len(Y) * 0.8):]if isTrain:return fetch_batch_size_random(X_train, Y_train, batch_size)else:return fetch_batch_size_random(X_test, Y_test, batch_size)生成训练验证和测试数据并定义许多超参数例如batch_sizehidden_dimRNN 中隐藏的神经元的数量和layers_stacked_count栈式循环单元的数量。 此外定义一些参数以微调优化器例如优化器的学习率迭代次数用于优化器模拟退火的lr_decay优化器的动量以及避免过拟合的 L2 正则化。 请注意GitHub 存储库具有默认的batch_size 5和nb_iters 150但使用batch_size 1000和nb_iters 100000获得了更好的结果
from datasets import generate_x_y_data_v4
generate_x_y_data generate_x_y_data_v4
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
sample_x, sample_y generate_x_y_data(isTrainTrue, batch_size3)
print(Dimensions of the dataset for 3 X and 3 Y training
examples : )
print(sample_x.shape)
print(sample_y.shape)
print((seq_length, batch_size, output_dim))
print sample_x, sample_y
# Internal neural network parameters
seq_length sample_x.shape[0] # Time series will have the same past and future (to be predicted) lenght.
batch_size 5 # Low value used for live demo purposes - 100 and 1000 would be possible too, crank that up!
output_dim input_dim sample_x.shape[-1] # Output dimension (e.g.: multiple signals at once, tied in time)
hidden_dim 12 # Count of hidden neurons in the recurrent units.
layers_stacked_count 2 # Number of stacked recurrent cells, on the neural depth axis.
# Optmizer:
learning_rate 0.007 # Small lr helps not to diverge during training.
nb_iters 150 # How many times we perform a training step (therefore how many times we show a batch).
lr_decay 0.92 # default: 0.9 . Simulated annealing.
momentum 0.5 # default: 0.0 . Momentum technique in weights update
lambda_l2_reg 0.003 # L2 regularization of weights - avoids overfitting将网络定义为由基本 GRU 单元组成的编码器/解码器。 该网络由layers_stacked_count2 RNN 组成我们将使用 TensorBoard 可视化该网络。 请注意hidden_dim 12是循环单元中的隐藏神经元
tf.nn.seq2seq tf.contrib.legacy_seq2seq
tf.nn.rnn_cell tf.contrib.rnn
tf.nn.rnn_cell.GRUCell tf.contrib.rnn.GRUCell
tf.reset_default_graph()
# sess.close()
sess tf.InteractiveSession()
with tf.variable_scope(Seq2seq):# Encoder: inputsenc_inp [tf.placeholder(tf.float32, shape(None, input_dim), nameinp_{}.format(t))for t in range(seq_length)]# Decoder: expected outputsexpected_sparse_output [tf.placeholder(tf.float32, shape(None, output_dim), nameexpected_sparse_output_.format(t))for t in range(seq_length)]# Give a GO token to the decoder.# You might want to revise what is the appended value enc_inp[:-1].dec_inp [ tf.zeros_like(enc_inp[0], dtypenp.float32, nameGO) ] enc_inp[:-1]# Create a layers_stacked_count of stacked RNNs (GRU cells here).cells []for i in range(layers_stacked_count):with tf.variable_scope(RNN_{}.format(i)):cells.append(tf.nn.rnn_cell.GRUCell(hidden_dim))# cells.append(tf.nn.rnn_cell.BasicLSTMCell(...))cell tf.nn.rnn_cell.MultiRNNCell(cells) # For reshaping the input and output dimensions of the seq2seq RNN:w_in tf.Variable(tf.random_normal([input_dim, hidden_dim]))b_in tf.Variable(tf.random_normal([hidden_dim], mean1.0))w_out tf.Variable(tf.random_normal([hidden_dim, output_dim]))b_out tf.Variable(tf.random_normal([output_dim]))
reshaped_inputs [tf.nn.relu(tf.matmul(i, w_in) b_in) for i in enc_inp]
# Here, the encoder and the decoder uses the same cell, HOWEVER,# the weights arent shared among the encoder and decoder, we have two# sets of weights created under the hood according to that functions def.dec_outputs, dec_memory tf.nn.seq2seq.basic_rnn_seq2seq(enc_inp,dec_inp,cell) output_scale_factor tf.Variable(1.0, nameOutput_ScaleFactor)# Final outputs: with linear rescaling similar to batch norm,# but without the norm part of batch normalization hehe.reshaped_outputs [output_scale_factor*(tf.matmul(i, w_out) b_out) for i in dec_outputs] # Merge all the summaries and write them out to /tmp/bitcoin_logs (by default)merged tf.summary.merge_all()train_writer tf.summary.FileWriter(/tmp/bitcoin_logs, sess.graph)现在让我们运行 TensorBoard 并可视化由 RNN 编码器和 RNN 解码器组成的网络
tensorboard --logdir/tmp/bitcoin_logs以下是代码流程 Tensorboard 中的比特币价值预测代码示例
现在让我们将损失函数定义为具有正则化的 L2 损失以避免过拟合并获得更好的泛化。 选择的优化器是 RMSprop其值为learning_rate衰减和动量如步骤 3 所定义
# Training loss and optimizer
with tf.variable_scope(Loss):# L2 lossoutput_loss 0for _y, _Y in zip(reshaped_outputs, expected_sparse_output):output_loss tf.reduce_mean(tf.nn.l2_loss(_y - _Y)) # L2 regularization (to avoid overfitting and to have a better generalization capacity)reg_loss 0for tf_var in tf.trainable_variables():if not (Bias in tf_var.name or Output_ in tf_var.name):reg_loss tf.reduce_mean(tf.nn.l2_loss(tf_var))loss output_loss lambda_l2_reg * reg_losswith tf.variable_scope(Optimizer):optimizer tf.train.RMSPropOptimizer(learning_rate, decaylr_decay, momentummomentum)train_op optimizer.minimize(loss)通过生成训练数据并在数据集中的batch_size示例上运行优化器来为批量训练做准备。 同样通过从数据集中的batch_size示例生成测试数据来准备测试。 训练针对nb_iters1迭代进行每十个迭代中的一个用于测试结果
def train_batch(batch_size):Training step that optimizes the weightsprovided some batch_size X and Y examples from the dataset.X, Y generate_x_y_data(isTrainTrue, batch_sizebatch_size)feed_dict {enc_inp[t]: X[t] for t in range(len(enc_inp))}feed_dict.update({expected_sparse_output[t]: Y[t] for t in range(len(expected_sparse_output))})_, loss_t sess.run([train_op, loss], feed_dict)return loss_tdef test_batch(batch_size):Test step, does NOT optimizes. Weights are frozen by notdoing sess.run on the train_op.X, Y generate_x_y_data(isTrainFalse, batch_sizebatch_size)feed_dict {enc_inp[t]: X[t] for t in range(len(enc_inp))}feed_dict.update({expected_sparse_output[t]: Y[t] for t in range(len(expected_sparse_output))})loss_t sess.run([loss], feed_dict)return loss_t[0]# Training
train_losses []
test_losses []
sess.run(tf.global_variables_initializer())for t in range(nb_iters1):train_loss train_batch(batch_size)train_losses.append(train_loss) if t % 10 0:# Testertest_loss test_batch(batch_size)test_losses.append(test_loss)print(Step {}/{}, train loss: {}, \tTEST loss: {}.format(t, nb_iters, train_loss, test_loss))
print(Fin. train loss: {}, \tTEST loss: {}.format(train_loss, test_loss))可视化n_predictions结果。 我们将以黄色形象化nb_predictions 5预测以x形象化蓝色的实际值ix。 请注意预测从直方图中的最后一个蓝点开始从视觉上您可以观察到即使这个简单的模型也相当准确
# Test
nb_predictions 5
print(Lets visualize {} predictions with our signals:.format(nb_predictions))
X, Y generate_x_y_data(isTrainFalse, batch_sizenb_predictions)
feed_dict {enc_inp[t]: X[t] for t in range(seq_length)}
outputs np.array(sess.run([reshaped_outputs], feed_dict)[0])
for j in range(nb_predictions):plt.figure(figsize(12, 3)) for k in range(output_dim):past X[:,j,k]expected Y[:,j,k]pred outputs[:,j,k] label1 Seen (past) values if k0 else _nolegend_label2 True future values if k0 else _nolegend_label3 Predictions if k0 else _nolegend_plt.plot(range(len(past)), past, o--b, labellabel1)plt.plot(range(len(past), len(expected)len(past)), expected, x--b, labellabel2)plt.plot(range(len(past), len(pred)len(past)), pred, o--y, labellabel3) plt.legend(locbest)plt.title(Predictions v.s. true values)plt.show()我们得到的结果如下 比特币价值预测的一个例子
工作原理
带有 GRU 基本单元的编码器-解码器层堆叠 RNN 用于预测比特币值。 RNN 非常擅长学习序列即使使用基于 2 层和 12 个 GRU 单元的简单模型比特币的预测确实相当准确。 当然此预测代码并非鼓励您投资比特币而只是讨论深度学习方法。 而且需要更多的实验来验证我们是否存在数据过拟合的情况。
更多
预测股市价值是一个不错的 RNN 应用并且有许多方便的包例如
Drnns-prediction 使用来自 Kaggle 的《股票市场每日新闻》数据集上的 Keras 神经网络库实现了深度 RNN。 数据集任务是使用当前和前一天的新闻头条作为特征来预测 DJIA 的未来走势。 开源代码可从这里获得。迈克尔·卢克Michael Luk撰写了一篇有趣的博客文章内容涉及如何基于 RNN 预测可口可乐的库存量。Jakob Aungiers 写了另一篇有趣的博客文章 LSTM 神经网络时间序列预测。
多对一和多对多 RNN 示例
在本秘籍中我们通过提供 RNN 映射的各种示例来总结与 RNN 讨论过的内容。 为了简单起见我们将采用 Keras 并演示如何编写一对一一对多多对一和多对多映射如下图所示 RNN 序列的一个例子
操作步骤
我们按以下步骤进行
如果要创建一对一映射则这不是 RNN而是密集层。 假设已经定义了一个模型并且您想添加一个密集网络。 然后可以在 Keras 中轻松实现
model Sequential()
model.add(Dense(output_size, input_shapeinput_shape))如果要创建一对多选项可以使用RepeatVector(...)实现。 请注意return_sequences是一个布尔值用于决定是返回输出序列中的最后一个输出还是完整序列
model Sequential()
model.add(RepeatVector(number_of_times,input_shapeinput_shape))
model.add(LSTM(output_size, return_sequencesTrue))如果要创建多对一选项则可以使用以下 LSTM 代码段实现
model Sequential()
model.add(LSTM(1, input_shape(timesteps, data_dim)))如果要创建多对多选项当输入和输出的长度与循环步数匹配时可以使用以下 LSTM 代码段来实现
model Sequential()
model.add(LSTM(1, input_shape(timesteps, data_dim), return_sequencesTrue))工作原理
Keras 使您可以轻松编写各种形状的 RNN包括一对一一对多多对一和多对多映射。 上面的示例说明了用 Keras 实现它们有多么容易。
七、无监督学习
到目前为止我们在本书中涵盖的所有模型都是基于监督学习范式的。 训练数据集包括输入和该输入的所需标签。 相反本章重点介绍无监督的学习范式。 本章将包括以下主题
主成分分析K 均值聚类自组织图受限玻尔兹曼机使用 RBM 的推荐系统用于情感检测的 DBN
介绍
在机器学习中存在三种不同的学习范式监督学习无监督学习和强化学习。
在监督学习也称为与老师一起学习中向网络提供输入和各自所需的输出。 例如在 MNIST 数据集中手写数字的每个图像都有一个标签表示与之关联的数字值。
在强化学习也称为与批评家学习中没有为网络提供所需的输出 相反环境会提供奖励或惩罚方面的反馈。 当其输出正确时环境奖励网络而当输出不正确时环境对其进行惩罚。
在无监督学习也称为无老师学习中没有向网络提供有关其输出的信息。 网络接收输入但是既不提供期望的输出也不提供来自环境的奖励 网络自己学习输入的隐藏结构。 无监督学习非常有用因为正常情况下可用的数据没有标签。 它可以用于模式识别特征提取数据聚类和降维等任务。 在本章和下一章中您将学习基于无监督学习的不同机器学习和 NN 技术。
主成分分析
主成分分析PCA是用于降维的最流行的多元统计技术。 它分析了由几个因变量组成的训练数据这些因变量通常是相互关联的并以一组称为主成分的新正交变量的形式从训练数据中提取重要信息。 我们可以使用两种方法执行 PCA – 特征值分解或奇异值分解SVD。
准备
PCA 将n维输入数据还原为r维输入数据其中r n。 简单来说PCA 涉及平移原点并执行轴的旋转以使其中一个轴主轴与数据点的差异最小。 通过执行此变换然后以高方差落下删除正交轴可以从原始数据集中获得降维数据集。 在这里我们采用 SVD 方法降低 PCA 尺寸。 考虑Xn维数据具有p个点X[p,n]。 任何实数p × n矩阵都可以分解为
X U ∑ V^T
在这里 U和V是正交矩阵即U · U^T V^T · V E大小分别为p × n和n × n。 ∑是大小为n × n的对角矩阵。 接下来将∑矩阵切成r列得到∑[r] 使用U和V我们找到了降维数据点Y[r]
Y[r] U ∑[r]
此处提供的代码已从以下 GitHub 链接进行改编
操作步骤
我们按以下步骤进行操作
导入所需的模块。 我们肯定会使用 TensorFlow; 我们还需要numpy进行一些基本矩阵计算并需要matplotlibmpl_toolkit和seaborn进行绘图
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import seaborn as sns
%matplotlib inline我们加载数据集-我们将使用我们最喜欢的 MNIST 数据集
from tensorflow.examples.tutorials.mnist import input_data
mnist input_data.read_data_sets(MNIST_data/)我们定义了一个TF_PCA类它将实现我们的所有工作。 该类的初始化如下
def __init__(self, data, dtypetf.float32):self._data dataself._dtype dtypeself._graph Noneself._X Noneself._u Noneself._singular_values Noneself._sigma None)给定输入数据的 SVD 用fit方法计算。 该方法定义了计算图并执行该计算图以计算奇异值和正交矩阵U。需要self.data来输入占位符self._X。 tf.svd以降序返回形状[..., p]的ssingular_values。 我们使用tf.diag将其转换为对角矩阵
def fit(self):self._graph tf.Graph()with self._graph.as_default():self._X tf.placeholder(self._dtype, shapeself._data.shape)# Perform SVDsingular_values, u, _ tf.svd(self._X)# Create sigma matrixsigma tf.diag(singular_values)with tf.Session(graphself._graph) as session:self._u, self._singular_values, self._sigma session.run([u, singular_values, sigma], feed_dict{self._X: self._data})现在我们有了sigma矩阵正交U矩阵和奇异值我们通过定义reduce方法来计算降维数据。 该方法需要两个输入参数之一n_dimensions或keep_info。 n_dimensions参数表示我们要保留在降维数据集中的维数。 另一方面keep_info参数确定我们要保留的信息的百分比值为 0.8 表示我们要保留 80% 的原始数据。 该方法创建一个切片 Sigma 矩阵的图并计算降维数据集Y[r]
def reduce(self, n_dimensionsNone, keep_infoNone):if keep_info:# Normalize singular valuesnormalized_singular_values self._singular_values / sum(self._singular_values)# information per dimensioninfo np.cumsum(normalized_singular_values) # Get the first index which is above the given information thresholdit iter(idx for idx, value in enumerate(info) if value keep_info)n_dimensions next(it) 1 with self.graph.as_default():# Cut out the relevant part from sigmasigma tf.slice(self._sigma, [0, 0], [self._data.shape[1], n_dimensions])# PCApca tf.matmul(self._u, sigma)with tf.Session(graphself._graph) as session:return session.run(pca, feed_dict{self._X: self._data})我们的TF_PCA类已准备就绪。 现在我们将使用它来将 MNIST 数据从尺寸为 78428 x 28的每个输入减少为尺寸为 3 的每个点的新数据。这里我们仅保留了 10% 的信息以便于查看但是通常需要保留大约 80% 的信息
tf_pca.fit()
pca tf_pca.reduce(keep_info0.1) # The reduced dimensions dependent upon the % of information
print(original data shape, mnist.train.images.shape)
print(reduced data shape, pca.shape) 以下是以下代码的输出 现在让我们在三维空间中绘制 55,000 个数据点
Set sns.color_palette(Set2, 10)
color_mapping {key:value for (key,value) in enumerate(Set)}
colors list(map(lambda x: color_mapping[x], mnist.train.labels))
fig plt.figure()
ax Axes3D(fig)
ax.scatter(pca[:, 0], pca[:, 1],pca[:, 2], ccolors)工作原理
前面的代码对 MNIST 图像执行降维。 每个原始图像的尺寸为28 x 28 使用 PCA 方法我们可以将其减小到较小的尺寸。 通常对于图像数据降维是必要的。 之所以如此是因为图像很大并且包含大量的冗余数据。
更多
TensorFlow 提供了一种称为嵌入的技术该技术是将对象映射到向量中。 TensorBoard 的嵌入式投影仪允许我们以交互方式可视化模型中的嵌入。 嵌入式投影仪提供了三种降低尺寸的方法PCAt-SNE 和自定义。 我们可以使用 TensorBoard 的嵌入投影器实现与上一个类似的结果。 我们需要从tensorflow.contrib.tensorboard.plugins导入projector类以从tensorflow.contrib.tensorboard.plugins导入projector进行相同的操作。 我们可以通过三个简单的步骤来做到这一点
加载要探索其嵌入的数据
mnist input_data.read_data_sets(MNIST_data)
images tf.Variable(mnist.test.images, nameimages)创建一个metadata文件metadata文件是制表符分隔的.tsv文件
with open(metadata, w) as metadata_file:for row in mnist.test.labels:metadata_file.write(%d\n % row)将嵌入内容保存在所需的Log_DIR中
with tf.Session() as sess:saver tf.train.Saver([images])sess.run(images.initializer)saver.save(sess, os.path.join(LOG_DIR, images.ckpt))config projector.ProjectorConfig()# One can add multiple embeddings.embedding config.embeddings.add()embedding.tensor_name images.name# Link this tensor to its metadata file (e.g. labels).embedding.metadata_path metadata# Saves a config file that TensorBoard will read during startup.projector.visualize_embeddings(tf.summary.FileWriter(LOG_DIR), config)嵌入已准备就绪现在可以使用 TensorBoard 看到。 通过 CLI tensorboard --logdirlog启动 TensorBoard在 Web 浏览器中打开 TensorBoard然后转到EMBEDDINGS选项卡。 这是使用 PCA 的 TensorBoard 投影前三个主要成分为轴 另见
https://arxiv.org/abs/1404.1100http://www.cs.otago.ac.nz/cosc453/student_tutorials/principal_components.pdfhttp://mplab.ucsd.edu/tutorials/pca.pdfhttp://projector.tensorflow.org/
K 均值聚类
顾名思义K 均值聚类是一种对数据进行聚类的技术即将数据划分为指定数量的数据点。 这是一种无监督的学习技术。 它通过识别给定数据中的模式来工作。 还记得哈利波特成名的分拣帽子吗 书中的工作是聚类-将新生未标记的学生分成四个不同的类格兰芬多拉文克劳赫奇帕奇和斯莱特林。
人类非常擅长将对象分组在一起。 聚类算法试图为计算机提供类似的功能。 有许多可用的聚类技术例如“层次”“贝叶斯”或“局部”。 K 均值聚类属于部分聚类 它将数据划分为k簇。 每个簇都有一个中心称为重心。 簇数k必须由用户指定。
K 均值算法以以下方式工作
随机选择k个数据点作为初始质心集群中心将每个数据点分配给最接近的质心 可以找到接近度的不同方法最常见的是欧几里得距离使用当前簇成员资格重新计算质心以使平方和的距离减小重复最后两个步骤直到达到收敛
准备
我们将使用 TensorFlow KmeansClustering估计器类来实现 K 均值。 它在这个链接中定义。它创建一个模型来运行 K 均值和推理。 根据 TensorFlow 文档一旦创建了KmeansClustering类对象就可以使用以下__init__方法实例化该对象
__init__(
num_clusters,
model_dirNone,
initial_clustersRANDOM_INIT,
distance_metricSQUARED_EUCLIDEAN_DISTANCE,
random_seed0,
use_mini_batchTrue,
mini_batch_steps_per_iteration1,
kmeans_plus_plus_num_retries2,
relative_toleranceNone,
configNone
)TensorFlow 文档对这些参数的定义如下
Args: num_clusters: The number of clusters to train. model_dir: The directory to save the model results and log files. initial_clusters: Specifies how to initialize the clusters for training. See clustering_ops.kmeans for the possible values. distance_metric: The distance metric used for clustering. See clustering_ops.kmeans for the possible values. random_seed: Python integer. Seed for PRNG used to initialize centers. use_mini_batch: If true, use the mini-batch k-means algorithm. Or else assume full batch. mini_batch_steps_per_iteration: The number of steps after which the updated cluster centers are synced back to a master copy. See clustering_ops.py for more details. kmeans_plus_plus_num_retries: For each point that is sampled during kmeans initialization, this parameter specifies the number of additional points to draw from the current distribution before selecting the best. If a negative value is specified, a heuristic is used to sample O(log(num_to_sample)) additional points. relative_tolerance: A relative tolerance of change in the loss between iterations. Stops learning if the loss changes less than this amount. Note that this may not work correctly if use_mini_batchTrue. config: See Estimator.
TensorFlow 支持欧几里得距离和余弦距离作为质心的量度。 TensorFlow KmeansClustering提供了各种与KmeansClustering对象进行交互的方法。 在本秘籍中我们将使用fit()clusters()和predict_clusters_idx()方法
fit(xNone,yNone,input_fnNone,stepsNone,batch_sizeNone,monitorsNone,max_stepsNone
)根据 TensorFlow 文档对于KmeansClustering估计器我们需要向fit()提供input_fn()。 cluster方法返回聚类中心predict_cluster_idx方法返回预测的聚类索引。
操作步骤
这是我们进行秘籍的方法
和以前一样我们从加载必要的模块开始。 我们将像往常一样需要 TensorFlowNumPy 和 Matplotlib。 在本秘籍中我们使用的是鸢尾花数据集该数据集包含三个类别每个类别有 50 个实例其中每个类别都代表一种鸢尾花植物。 我们可以从这里下载数据作为.csv文件也可以使用 sklearn 的数据集模块scikit-learn 做任务
import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap
# dataset Iris
from sklearn import datasets%matplotlib inline我们加载数据集
# import some data to play with
iris datasets.load_iris()
x iris.data[:, :2] # we only take the first two features.
y iris.target让我们看看该数据集的外观
# original data without clustering
plt.scatter(hw_frame[:,0], hw_frame[:,1])
plt.xlabel(Sepia Length)
plt.ylabel(Sepia Width)以下是以下代码的输出 我们可以看到在数据中没有明显可见的聚类。 现在我们定义input_fn它将用于提供fit方法。 我们的输入函数返回一个 TensorFlow 常数该常数被分配了x的值和形状并且类型为float
def input_fn():return tf.constant(np.array(x), tf.float32, x.shape),None现在我们使用KmeansClustering类 在这里我们已经知道类的数量为 3因此我们将num_clusters3设置为。 通常我们不知道集群的数量。 在这种情况下常用的方法是肘部法则
kmeans tf.contrib.learn.KMeansClustering(num_clusters3, relative_tolerance0.0001, random_seed2)
kmeans.fit(input_fninput_fn)我们使用clusters()方法找到聚类并使用predict_cluster_idx()方法为每个输入点分配聚类索引
clusters kmeans.clusters()
assignments list(kmeans.predict_cluster_idex(input_fninput_fn))现在让我们可视化由 K 均值创建的聚类。 为此我们创建一个包装器函数ScatterPlot该函数将X和Y值以及每个数据点的簇和簇索引一起使用
def ScatterPlot(X, Y, assignmentsNone, centersNone):if assignments is None:assignments [0] * len(X)fig plt.figure(figsize(14,8))cmap ListedColormap([red, green, blue])plt.scatter(X, Y, cassignments, cmapcmap)if centers is not None:plt.scatter(centers[:, 0], centers[:, 1], crange(len(centers)), marker, s400, cmapcmap) plt.xlabel(Sepia Length)plt.ylabel(Sepia Width)我们用它来绘制我们的clusters
ScatterPlot(x[:,0], x[:,1], assignments, clusters)情节如下 标记是三个簇的质心。
工作原理
前面的秘籍使用 TensorFlow 的 K 均值聚类估计器将给定数据聚类为聚类。 在这里由于我们知道集群的数量我们决定保留num_clusters3但是在大多数情况下如果使用未标记的数据则永远无法确定存在多少集群。 可以使用弯头法确定最佳簇数。 该方法基于以下原则我们应选择能减少平方误差和SSE距离的簇数。 如果k是簇数则随着k增加SSE 减少SSE 0 当k等于数据点数时每个点都是其自己的簇。 我们想要一个k较低的值以使 SSE 也较低。 在 TensorFlow 中我们可以使用KmeansClustering类中定义的score()方法找到 SSE 该方法将距离的总和返回到最近的聚类
sum_distances kmeans.score(input_fninput_fn, steps100)对于鸢尾数据如果我们针对不同的k值绘制 SSE则可以看到对于k 3而言SSE 的方差最高 之后它开始减小因此肘点为k 3 更多
K 均值聚类非常流行因为它快速简单且健壮。 它还有一些缺点最大的缺点是用户必须指定簇的数量。 其次该算法不能保证全局最优。 第三它对异常值非常敏感。
另见 Kanungo, Tapas, et al. An efficient k-means clustering algorithm: Analysis and implementation. IEEE transactions on pattern analysis and machine intelligence 24.7 (2002): 881-892. Ortega, Joaquín Pérez, et al. Research issues on k-means algorithm: An experimental trial using matlab. CEUR Workshop Proceedings: Semantic Web and New Technologies. http://home.deib.polimi.it/matteucc/Clustering/tutorial_html/kmeans.html Chen, Ke. On coresets for k-median and k-means clustering in metric and euclidean spaces and their applications. SIAM Journal on Computing 39.3 (2009): 923-947. https://en.wikipedia.org/wiki/Determining_the_number_of_clusters_in_a_data_set
自组织图
自组织映射SOM有时也称为 Kohonen 网络或胜者通吃单元WTU是一种非常特殊的神经网络受人脑的独特特征驱动。 在我们的大脑中不同的感觉输入以拓扑有序的方式表示。 与其他神经网络不同神经元并非都通过权重相互连接而是会影响彼此的学习。 SOM 的最重要方面是神经元以拓扑方式表示学习的输入。
在 SOM 中神经元通常放置在1D 或 2D晶格的节点上。 更大的尺寸也是可能的但实际上很少使用。 晶格中的每个神经元都通过权重矩阵连接到所有输入单元。 在这里您可以看到一个具有3 x 412 个神经元和七个输入的 SOM。 为了清楚起见仅显示将所有输入连接到一个神经元的权重向量。 在这种情况下每个神经元将具有七个元素从而形成大小为12 x 7的组合权重矩阵 SOM 通过竞争性学习来学习。 可以将其视为 PCA 的非线性概括因此像 PCA 一样可以用于降维。
准备
为了实现 SOM让我们首先了解它是如何工作的。 第一步将网络的权重初始化为某个随机值或者通过从输入中获取随机样本进行初始化。 占据晶格中空间的每个神经元将被分配特定的位置。 现在作为输入出现与输入距离最小的神经元被宣布为 WinnerWTU。 这是通过测量所有神经元的权重向量W和输入向量X之间的距离来完成的 在此d[j]是神经元j的权重与输入X的距离。 最小d值的神经元是赢家。
接下来以一种方式调整获胜神经元及其相邻神经元的权重以确保如果下次出现相同的输入则相同的神经元将成为获胜者。 为了确定哪些相邻神经元需要修改网络使用邻域函数Λ(r) 通常选择高斯墨西哥帽函数作为邻域函数。 邻域函数在数学上表示如下 在这里σ是神经元的时间依赖性半径d是其与获胜神经元的距离 邻域函数的另一个重要属性是其半径随时间减小。 结果一开始许多相邻神经元的权重被修改但是随着网络的学习最终在学习过程中一些神经元的权重有时只有一个或没有被修改。 权重变化由以下公式给出
dW η * Λ(X - W)
我们继续所有输入的过程并重复给定的迭代次数。 随着迭代的进行我们将学习率和半径减小一个取决于迭代次数的因素。
操作步骤
我们按以下步骤进行
与往常一样我们从导入必要的模块开始
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline接下来我们声明一个类 WTU它将执行所有任务。 用m x n 2D SOM 格的大小dim输入数据中的维数以及迭代总数来实例化该类
def __init__(self, m, n, dim, num_iterations, eta 0.5, sigma None):m x n : The dimension of 2D lattice in which neurons are arrangeddim : Dimension of input training datanum_iterations: Total number of training iterationseta : Learning ratesigma: The radius of neighbourhood function.self._m mself._n nself._neighbourhood []self._topography []self._num_iterations int(num_iterations) self._learned False在__init__本身中我们定义了计算图和会话。如果网络未提供任何sigma值它将采用默认值该值通常是 SOM 晶格最大尺寸的一半
if sigma is None:sigma max(m,n)/2.0 # Constant radius
else:sigma float(sigma)接下来在图中我们声明权重矩阵的变量输入的占位符以及计算获胜者并更新其及其邻居权重的计算步骤。 由于 SOM 提供了地形图因此我们还添加了操作以获得神经元的地形位置
self._graph tf.Graph()# Build Computation Graph of SOMwith self._graph.as_default():
# Weight Matrix and the topography of neuronsself._W tf.Variable(tf.random_normal([m*n, dim], seed 0))self._topography tf.constant(np.array(list(self._neuron_location(m, n))))# Placeholders for training dataself._X tf.placeholder(float, [dim])# Placeholder to keep track of number of iterationsself._iter tf.placeholder(float)# Finding the Winner and its locationd tf.sqrt(tf.reduce_sum(tf.pow(self._W - tf.stack([self._X for i in range(m*n)]),2),1))self.WTU_idx tf.argmin(d,0)slice_start tf.pad(tf.reshape(self.WTU_idx, [1]),np.array([[0,1]]))self.WTU_loc tf.reshape(tf.slice(self._topography, slice_start, [1,2]), [2])# Change learning rate and radius as a function of iterationslearning_rate 1 - self._iter/self._num_iterations_eta_new eta * learning_rate_sigma_new sigma * learning_rate# Calculating Neighbourhood functiondistance_square tf.reduce_sum(tf.pow(tf.subtract(self._topography, tf.stack([self.WTU_loc for i in range(m * n)])), 2), 1)neighbourhood_func tf.exp(tf.negative(tf.div(tf.cast(
distance_square, float32), tf.pow(_sigma_new, 2))))# multiply learning rate with neighbourhood funceta_into_Gamma tf.multiply(_eta_new, neighbourhood_func)# Shape it so that it can be multiplied to calculate dWweight_multiplier tf.stack([tf.tile(tf.slice(
eta_into_Gamma, np.array([i]), np.array([1])), [dim])
for i in range(m * n)])delta_W tf.multiply(weight_multiplier,
tf.subtract(tf.stack([self._X for i in range(m * n)]),self._W))new_W self._W delta_Wself._training tf.assign(self._W,new_W)# Initialize All variablesinit tf.global_variables_initializer()self._sess tf.Session()self._sess.run(init)我们为该类定义一个fit方法该方法执行在该类的默认图中声明的训练操作。 该方法还计算质心网格
def fit(self, X):Function to carry out trainingfor i in range(self._num_iterations):for x in X:self._sess.run(self._training, feed_dict {self._X:x, self._iter: i})# Store a centroid grid for easy retreivalcentroid_grid [[] for i in range(self._m)]self._Wts list(self._sess.run(self._W))self._locations list(self._sess.run(self._topography))for i, loc in enumerate(self._locations):centroid_grid[loc[0]].append(self._Wts[i])self._centroid_grid centroid_gridself._learned True我们定义一个函数来确定获胜神经元在 2D 晶格中的索引和位置
def winner(self, x):idx self._sess.run([self.WTU_idx,self.WTU_loc], feed_dict {self._X:x})return idx我们定义一些更多的辅助函数以执行晶格中神经元的 2D 映射并将输入向量映射到 2D 晶格中的相关神经元
def _neuron_location(self,m,n):Function to generate the 2D lattice of neuronsfor i in range(m):for j in range(n):yield np.array([i,j])def get_centroids(self):Function to return a list of m lists, with each inner list containing the n corresponding centroid locations as 1-D NumPy arrays.if not self._learned:raise ValueError(SOM not trained yet)return self._centroid_griddef map_vects(self, X):Function to map each input vector to the relevant neuron in the latticeif not self._learned:raise ValueError(SOM not trained yet)to_return []for vect in X:min_index min([i for i in range(len(self._Wts))],keylambda x: np.linalg.norm(vect -
self._Wts[x]))to_return.append(self._locations[min_index])
return to_return现在我们的 WTU 类已经准备好我们从.csv文件中读取数据并对其进行规范化
def normalize(df):result df.copy()for feature_name in df.columns:max_value df[feature_name].max()min_value df[feature_name].min()result[feature_name] (df[feature_name] - min_value) / (max_value - min_value)return result# Reading input data from file
import pandas as pd
df pd.read_csv(colors.csv) # The last column of data file is a label
data normalize(df[[R, G, B]]).values
name df[Color-Name].values
n_dim len(df.columns) - 1# Data for Training
colors data
color_names name最后我们使用我们的类执行降维并将其布置在美丽的地形图中
som WTU(30, 30, n_dim, 400, sigma10.0)
som.fit(colors)# Get output grid
image_grid som.get_centroids()# Map colours to their closest neurons
mapped som.map_vects(colors)# Plot
plt.imshow(image_grid)
plt.title(Color Grid SOM)
for i, m in enumerate(mapped):plt.text(m[1], m[0], color_names[i], hacenter, vacenter, bboxdict(facecolorwhite, alpha0.5, lw0))情节如下 工作原理
SOM 在计算上很昂贵因此对于非常大的数据集并没有真正的用处。 尽管如此它们仍然易于理解并且可以很好地找到输入数据之间的相似性。 因此它们已被用于图像分割和确定 NLP 中的单词相似度图。
另见
这是一篇非常不错的博客文章用简单的语言解释了 SOM关于 SOM 的简要介绍Kohonen 关于 SOM 的开创性论文“自组织图”。 神经计算 21.119981-6
受限玻尔兹曼机
受限玻尔兹曼机RBM是两层神经网络第一层称为可见层第二层称为隐藏层。 它们被称为浅层神经网络因为它们只有两层深。 它们最初是由 1986 年由保罗·斯莫伦斯基Paul Smolensky提出的他称其为 Harmony Networks后来由 Geoffrey Hinton 提出于 2006 年提出了对比发散CD作为训练他们的方法。 可见层中的所有神经元都与隐藏层中的所有神经元相连但是存在限制-同一层中没有神经元可以连接。 所有神经元本质上都是二进制的 资料来源Qwertyus 自己的作品CC BY-SA 3.0
RBM 可用于降维特征提取和协作过滤。 RBM 中的训练可分为三个部分前进后退和比较。
准备
让我们看看制作 RBM 所需的表达式
正向传递可见单元V上的信息通过权重W和偏差c传递给隐藏的对象单元h[0]。 隐藏单元是否可以触发取决于随机概率σ是随机概率
p(h[i]|v[0]) σ(V^T · W c)[i]
向后传递隐藏的单元表示h[0]然后通过相同的权重W但不同的偏置c传递回可见单元它们在其中重构输入。 再次对输入进行采样
p(v[i]|h[0]) σ(W^T · h[0] b)[i]*
将这两个遍重复 k 步或直到达到收敛。 根据研究人员的说法k 1给出了很好的结果因此我们将保持k 1。
可见向量V和隐藏向量的联合构型具有如下能量 自由能还与每个可见向量V相关为与具有V的所有构型具有相同概率的单个配置所需的能量 使用对比度发散目标函数即Mean(F(Voriginal))- Mean(F(Vreconstructed))权重的变化由此给出 在此η是学习率。 对于偏差b和c存在相似的表达式。
操作步骤
我们按以下步骤进行
导入模块
import tensorflow as tf
import numpy as np
from tensorflow.examples.tutorials.mnist import input_data
import matplotlib.pyplot as plt
%matplotlib inline声明 RBM 类它将完成主要任务。 __init__将建立完整的图正向和反向传递以及目标函数 我们将使用 TensorFlow 内置的优化器来更新权重和偏差
class RBM(object):def __init__(self, m, n):m: Number of neurons in visible layern: number of neurons in hidden layerself._m mself._n n# Create the Computational graph# Weights and biasesself._W tf.Variable(tf.random_normal(shape(self._m,self._n)))self._c tf.Variable(np.zeros(self._n).astype(np.float32)) #bias for hidden layerself._b tf.Variable(np.zeros(self._m).astype(np.float32)) #bias for Visible layer# Placeholder for inputsself._X tf.placeholder(float, [None, self._m])# Forward Pass_h tf.nn.sigmoid(tf.matmul(self._X, self._W) self._c)self.h tf.nn.relu(tf.sign(_h - tf.random_uniform(tf.shape(_h))))#Backward pass_v tf.nn.sigmoid(tf.matmul(self.h, tf.transpose(self._W)) self._b)self.V tf.nn.relu(tf.sign(_v - tf.random_uniform(tf.shape(_v))))# Objective Functionobjective tf.reduce_mean(self.free_energy(self._X)) - tf.reduce_mean(
self.free_energy(self.V))self._train_op tf.train.GradientDescentOptimizer(1e-3).minimize(objective)# Cross entropy costreconstructed_input self.one_pass(self._X)self.cost tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(
labelsself._X, logitsreconstructed_input))我们在RBM类中定义fit()方法。 在__init__中声明了所有操作后训练只是在会话中调用train_op。 我们使用批量训练 def fit(self, X, epochs 1, batch_size 100):N, D X.shapenum_batches N // batch_sizeobj []for i in range(epochs):#X shuffle(X)for j in range(num_batches):batch X[j * batch_size: (j * batch_size batch_size)]_, ob self.session.run([self._train_op,self.cost ], feed_dict{self._X: batch})if j % 10 0:print(training epoch {0} cost {1}.format(j,ob)) obj.append(ob)return obj还有其他辅助函数可计算对率误差并从网络返回重建的图像
def set_session(self, session):self.session sessiondef free_energy(self, V):b tf.reshape(self._b, (self._m, 1))term_1 -tf.matmul(V,b)term_1 tf.reshape(term_1, (-1,))term_2 -tf.reduce_sum(tf.nn.softplus(tf.matmul(V,self._W) self._c))return term_1 term_2def one_pass(self, X):h tf.nn.sigmoid(tf.matmul(X, self._W) self._c)return tf.matmul(h, tf.transpose(self._W)) self._bdef reconstruct(self,X):x tf.nn.sigmoid(self.one_pass(X))return self.session.run(x, feed_dict{self._X: X})
我们加载 MNIST 数据集
mnist input_data.read_data_sets(MNIST_data/, one_hotTrue)
trX, trY, teX, teY mnist.train.images, mnist.train.labels, mnist.test.images, mnist.test.labels接下来我们在 MNIST 数据集上训练RBM
Xtrain trX.astype(np.float32)
Xtest teX.astype(np.float32)
_, m Xtrain.shape
rbm RBM(m, 100)
#Initialize all variables
init tf.global_variables_initializer()
with tf.Session() as sess:sess.run(init)rbm.set_session(sess)err rbm.fit(Xtrain)out rbm.reconstruct(Xest[0:100]) # Let us reconstruct Test Data不同周期的函数误差 工作原理
由于其具有重建图像的能力RBM 可用于从现有数据中生成更多数据。 通过制作一个小的助手绘图代码我们可以看到原始和重建的 MNIST 图像
row, col 2, 8
idx np.random.randint(0, 100, row * col // 2)
f, axarr plt.subplots(row, col, sharexTrue, shareyTrue, figsize(20,4))
for fig, row in zip([Xtest_noisy,out], axarr):for i,ax in zip(idx,row):ax.imshow(fig[i].reshape((28, 28)), cmapGreys_r)ax.get_xaxis().set_visible(False)ax.get_yaxis().set_visible(False)我们得到的结果如下 另见 Smolensky, Paul. Information processing in dynamical systems: Foundations of harmony theory. No. CU-CS-321-86. COLORADO UNIV AT BOULDER DEPT OF COMPUTER SCIENCE, 1986. http://stanford.edu/~jlmcc/papers/PDP/Volume 1/Chap6_PDP86.pdf Salakhutdinov, Ruslan, Andriy Mnih, and Geoffrey Hinton. Restricted Boltzmann machines for collaborative filtering. Proceedings of the 24th international conference on Machine learning. ACM, 2007. http://machinelearning.wustl.edu/mlpapers/paper_files/icml2007_SalakhutdinovMH07.pdf Hinton, Geoffrey. A practical guide to training restricted Boltzmann machines. Momentum 9.1 (2010): 926. http://www.csri.utoronto.ca/~hinton/absps/guideTR.pdf) 如果您对数学感兴趣这是一个很好的教程
使用 RBM 的推荐系统
网上零售商广泛使用推荐系统向客户推荐产品。 例如亚马逊会告诉您购买此商品的其他客户对什么感兴趣或者 Netflix 根据您所观看的内容以及有相同兴趣的其他 Netflix 用户所观看的内容推荐电视连续剧和电影。 这些推荐器系统在协作筛选的基础上工作。 在协作过滤中系统根据用户的过去行为来构建模型。 我们将使用上一个秘籍中的 RBM 构建一个使用协作过滤来推荐电影的推荐器系统。 这项工作中的一个重要挑战是大多数用户不会对所有产品/电影进行评分因此大多数数据都将丢失。 如果有 M 个产品和 N 个用户则我们需要构建一个数组N x M其中包含用户的已知等级并将所有未知值设为零。
准备
为了使用协作过滤创建推荐系统我们需要修改数据。 作为说明我们将使用来自这里的电影数据集。 数据由两个.dat文件组成movies.dat和ratings.dat。 movies.dat文件包含 3 列3883 个电影的 MovieIDTitle 和 Genre。 ratings.dat文件包含四列UserIDMovieIDRating 和 Time。 我们需要合并这两个数据文件以便能够构建一个数组其中对于每个用户我们对所有 3,883 部电影都有一个评分。 问题在于用户通常不会对所有电影进行评级因此我们仅对某些电影进行非零标准化评级。 其余部分设为零因此不会对隐藏层有所贡献。
操作步骤
我们将使用在先前秘籍中创建的RBM类。 让我们定义我们的 RBM 网络 可见单元的数量将是电影的数量在我们的示例中为 3883movies_df是包含movies.dat文件中的数据的数据帧
m len(movies_df) # Number of visible units
n 20 # Number of Hidden units
recommender rbm.RBM(m,n)我们使用 Pandas 合并和groupby命令创建了一个列表trX该列表包含大约 1,000 个用户的规范化电影评分。 列表的大小为1000 x 3883。我们使用它来训练我们的 RBM
Xtrain np.array(trX)
init tf.global_variables_initializer()
with tf.Session() as sess:sess.run(init)recommender.set_session(sess)err recommender.fit(Xtrain, epochs10)每个周期的跨逻辑误差减少 网络现已接受训练 我们使用它为索引为 150 的随机用户可能是任何现有用户获得推荐
user_index 150
x np.array([Xtrain[user_index, :]])
init tf.global_variables_initializer()
with tf.Session() as sess:sess.run(init)recommender.set_session(sess)out recommender.reconstruct(x.astype(np.float32))结果与现有数据帧合并我们可以看到该用户的推荐分数 更多
杰弗里·欣顿Geoffrey Hinton教授领导的多伦多大学团队赢得了 Netflix 最佳协作过滤竞赛的冠军该协作过滤使用 RBM 来预测电影的用户收视率。 可以从他们的论文中获取其工作的详细信息。
一个 RBM 的隐藏单元的输出可以馈送到另一个 RBM 的可见单元可以重复此过程以形成 RBM 的栈。 这导致栈式 RBM 。 假定不存在其他堆叠式 RBM则对其进行独立训练。 大量栈式 RBM 构成了深度信念网络DBN。 可以使用有监督或无监督的训练来训练 DBN。 您将在下一个秘籍中了解有关它们的更多信息。
用于情感检测的 DBN
在本秘籍中我们将学习如何首先堆叠 RBM 来制作 DBN然后训练它来检测情感。 秘籍中有趣的部分是我们采用了两种不同的学习范例首先我们使用无监督学习对 RBM 进行了预训练最后我们有了一个 MLP 层该层是使用监督学习进行了训练的。
准备
我们使用已经在秘籍受限玻尔兹曼机中创建的 RBM 类只需进行一次更改即可现在无需在训练后重建图像。 取而代之的是我们栈式 RBM 将仅将数据转发至 DBN 的最后一个 MLP 层。 这是通过从类中删除reconstruct()函数并将其替换为rbm_output()函数来实现的
def rbm_output(self,X):x tf.nn.sigmoid(tf.matmul(X, self._W) self._c)return self.session.run(x, feed_dict{self._X: X})对于数据我们考虑了 Kaggle 面部表情识别数据该数据可从这里获得。 此处给出的数据描述为
数据由48 x 48像素的面部灰度图像组成。 面部已自动注册因此面部或多或少居中并且在每个图像中占据大约相同的空间量。 任务是根据面部表情中显示的情感将每个面孔分类为七个类别之一0 为愤怒1 恶心2 为恐惧3 为快乐4 为悲伤5 为惊奇6 为中性 。
train.csv包含两列“情感”和“像素”。 “情感”列包含图像中存在的情感的数字代码范围从 0 到 6含。 “像素”列包含每个图像用引号引起来的字符串。 该字符串的内容是按行主要顺序分隔的像素值。 test.csv仅包含“像素”列您的任务是预测情感列。
训练集包含 28,709 个示例。 用于排行榜的公共测试集包含 3,589 个示例。 最终测试集用于确定比赛的获胜者另外还有 3,589 个示例。
该数据集由 Pierre-Luc Carrier 和 Aaron Courville 进行是正在进行的研究项目的一部分。 他们为研讨会的组织者提供了他们数据集的初步版本供比赛使用。
完整的数据合而为一。 名为fer2013.csv的csv文件。 我们从中分离出训练验证和测试数据
data pd.read_csv(data/fer2013.csv)
tr_data data[data.Usage Training]
test_data data[data.Usage PublicTest]
mask np.random.rand(len(tr_data)) 0.8
train_data tr_data[mask]
val_data tr_data[~mask]我们将需要预处理数据即将像素和情感标签分开。 为此我们制作了两个函数dense_to_one_hot ()它对标签执行了单热编码。 第二个函数是preprocess_data()它将单个像素分离为一个数组。 在这两个函数的帮助下我们生成了训练验证和测试数据集的输入特征和标签
def dense_to_one_hot(labels_dense, num_classes):num_labels labels_dense.shape[0]index_offset np.arange(num_labels) * num_classeslabels_one_hot np.zeros((num_labels, num_classes))labels_one_hot.flat[index_offset labels_dense.ravel()] 1return labels_one_hot
def preprocess_data(dataframe):pixels_values dataframe.pixels.str.split( ).tolist()pixels_values pd.DataFrame(pixels_values, dtypeint)images pixels_values.valuesimages images.astype(np.float32)images np.multiply(images, 1.0/255.0)labels_flat dataframe[emotion].values.ravel()labels_count np.unique(labels_flat).shape[0]labels dense_to_one_hot(labels_flat, labels_count)labels labels.astype(np.uint8)return images, labels使用前面代码中定义的函数我们以训练所需的格式获取数据。 基于本文针对 MNIST 提到的相似原理我们构建了情感检测 DBN。
操作步骤
我们按以下步骤进行
我们需要导入标准模块 TensorFlowNumPy 和 Pandas以读取.csv文件和 Matplolib
import tensorflow as tf
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt训练验证和测试数据是使用辅助函数获得的
X_train, Y_train preprocess_data(train_data)
X_val, Y_val preprocess_data(val_data)
X_test, Y_test preprocess_data(test_data)让我们来探讨一下我们的数据。 我们绘制平均图像并找到每个训练验证和测试数据集中的图像数量
# Explore Data
mean_image X_train.mean(axis0)
std_image np.std(X_train, axis0)
print(Training Data set has {} images.format(len(X_train)))
print(Validation Data set has {} images.format(len(X_val)))
print(Test Data set has {} images.format(len(X_test)))
plt.imshow(mean_image.reshape(48,48), cmapgray)我们得到的结果如下 我们还会看到训练样本中的图像及其各自的标签
classes [angry,disgust,fear,happy,sad,surprise,neutral]
num_classes len(classes)
samples_per_class 7
for y,cls in enumerate(classes):idxs np.flatnonzero(np.argmax(Y_train, axis 1) y)idxs np.random.choice(idxs, samples_per_class, replaceFalse)for i, idx in enumerate(idxs):plt_idx i * num_classes y 1plt.subplot(samples_per_class, num_classes, plt_idx)plt.imshow(X_train[idx].reshape(48,48), cmapgray) #pixel height and widthplt.axis(off)if i 0:plt.title(cls)
plt.show()情节如下 接下来我们定义 RBM 栈 每个 RBM 都将先前 RBM 的输出作为其输入
RBM_hidden_sizes [1500, 700, 400] #create 4 layers of RBM with size 1500, 700, 400 and 100
#Set input as training data
inpX X_train
#Create list to hold our RBMs
rbm_list []
#Size of inputs is the number of inputs in the training set
input_size inpX.shape[1]
#For each RBM we want to generate
for i, size in enumerate(RBM_hidden_sizes):print (RBM: ,i, ,input_size,-, size)rbm_list.append(RBM(input_size, size))input_size size这将生成三个 RBM第一个 RBM 具有 230448×48个输入和 1500 个隐藏单元第二个 RBM 具有 1500 个输入和 700 个隐藏单元最后第三个 RBM 具有 700 个输入和 400 个隐藏单元。
我们逐一训练每个 RBM。 该技术也称为贪婪训练。 在原始论文中用于在 MNIST 上训练每个 RBM 的周期数是 30因此在这里增加周期也应会改善网络的表现
# Greedy wise training of RBMs
init tf.global_variables_initializer()
for rbm in rbm_list:print (New RBM:)#Train a new onewith tf.Session() as sess:sess.run(init)rbm.set_session(sess)err rbm.fit(inpX, 5)inpX_n rbm.rbm_output(inpX)print(inpX_n.shape)inpX inpX_n我们定义一个DBN类。 在类中我们用三层 RBM 和另外两层 MLP 构建完整的 DBN。 从预训练的 RBM 中加载 RBM 层的权重。 我们还声明了训练和预测 DBN 的方法 为了进行微调网络尝试最小化均方损失函数
class DBN(object):def __init__(self, sizes, X, Y, eta 0.001, momentum 0.0, epochs 10, batch_size 100):#Initialize hyperparametersself._sizes sizesprint(self._sizes)self._sizes.append(1000) # size of the first FC layerself._X Xself._Y Yself.N len(X)self.w_list []self.c_list []self._learning_rate etaself._momentum momentumself._epochs epochsself._batchsize batch_sizeinput_size X.shape[1]#initialization loopfor size in self._sizes [Y.shape[1]]:#Define upper limit for the uniform distribution rangemax_range 4 * math.sqrt(6\. / (input_size size))#Initialize weights through a random uniform distributionself.w_list.append(np.random.uniform( -max_range, max_range, [input_size, size]).astype(np.float32))#Initialize bias as zeroesself.c_list.append(np.zeros([size], np.float32))input_size size# Build DBN#Create placeholders for input, weights, biases, outputself._a [None] * (len(self._sizes) 2)self._w [None] * (len(self._sizes) 1)self._c [None] * (len(self._sizes) 1)self._a[0] tf.placeholder(float, [None, self._X.shape[1]])self.y tf.placeholder(float, [None, self._Y.shape[1]])#Define variables and activation functionfor i in range(len(self._sizes) 1):self._w[i] tf.Variable(self.w_list[i])self._c[i] tf.Variable(self.c_list[i])for i in range(1, len(self._sizes) 2):self._a[i] tf.nn.sigmoid(tf.matmul(self._a[i - 1], self._w[i - 1]) self._c[i - 1])#Define the cost functioncost tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labelsself.y, logits self._a[-1]))#cost tf.reduce_mean(tf.square(self._a[-1] - self.y))#Define the training operation (Momentum Optimizer minimizing the Cost function)self.train_op tf.train.AdamOptimizer(learning_rateself._learning_rate).minimize(cost)#Prediction operationself.predict_op tf.argmax(self._a[-1], 1)#load data from rbmdef load_from_rbms(self, dbn_sizes,rbm_list):#Check if expected sizes are correctassert len(dbn_sizes) len(self._sizes)for i in range(len(self._sizes)):#Check if for each RBN the expected sizes are correctassert dbn_sizes[i] self._sizes[i]#If everything is correct, bring over the weights and biasesfor i in range(len(self._sizes)-1):self.w_list[i] rbm_list[i]._Wself.c_list[i] rbm_list[i]._cdef set_session(self, session):self.session session#Training methoddef train(self, val_x, val_y):#For each epochnum_batches self.N // self._batchsizebatch_size self._batchsizefor i in range(self._epochs):#For each stepfor j in range(num_batches):batch self._X[j * batch_size: (j * batch_size batch_size)]batch_label self._Y[j * batch_size: (j * batch_size batch_size)]self.session.run(self.train_op, feed_dict{self._a[0]: batch, self.y: batch_label})for j in range(len(self._sizes) 1):#Retrieve weights and biasesself.w_list[j] sess.run(self._w[j])self.c_list[j] sess.run(self._c[j])train_acc np.mean(np.argmax(self._Y, axis1) self.session.run(self.predict_op, feed_dict{self._a[0]: self._X, self.y: self._Y}))val_acc np.mean(np.argmax(val_y, axis1) self.session.run(self.predict_op, feed_dict{self._a[0]: val_x, self.y: val_y}))print ( epoch str(i) / str(self._epochs) Training Accuracy: str(train_acc) Validation Accuracy: str(val_acc))def predict(self, X):return self.session.run(self.predict_op, feed_dict{self._a[0]: X})现在我们训练实例化DBN对象并对其进行训练。 并预测测试数据的标签
nNet DBN(RBM_hidden_sizes, X_train, Y_train, epochs 80)
with tf.Session() as sess:#Initialize Variablessess.run(tf.global_variables_initializer())nNet.set_session(sess)nNet.load_from_rbms(RBM_hidden_sizes,rbm_list)nNet.train(X_val, Y_val)y_pred nNet.predict(X_test)工作原理
RBM 使用无监督学习来学习模型的隐藏表示/特征然后对与预训练 RBM 一起添加的全连接层进行微调。
这里的精度在很大程度上取决于图像表示。 在前面的秘籍中我们没有使用图像处理仅使用了 0 到 1 之间缩放的灰度图像。但是如果我们按照以下论文所述添加图像处理则会进一步提高精度。 因此我们在preprocess_data函数中将每个图像乘以 100.0/255.0然后将以下几行代码添加到主代码中
std_image np.std(X_train, axis0)
X_train np.divide(np.subtract(X_train,mean_image), std_image)
X_val np.divide(np.subtract(X_val,mean_image), std_image)
X_test np.divide(np.subtract(X_test,mean_image), std_image)更多
在前面的示例中没有进行预处理这三个数据集的准确率大约为 40%。 但是当我们添加预处理时训练数据的准确率将提高到 90%但是对于验证和测试我们仍然可以获得约 45% 的准确率。
可以引入许多更改来改善结果。 首先我们在秘籍中使用的数据集是只有 22,000 张图像的 Kaggle 数据集。 如果观察这些图像则会发现仅过滤面部的步骤会改善结果。 如下文所述另一种策略是增加隐藏层的大小而不是减小它们的大小。
在识别情感方面确实非常成功的另一个更改是使用面部关键点而不是整个面部训练。
使用前面的秘籍您可以尝试这些更改并探索表现如何提高。 愿 GPU 力量与您同在
八、自编码器
自编码器是前馈非循环神经网络可通过无监督学习来学习。 他们具有学习数据的紧凑表示的固有能力。 它们是深度信念网络的中心可在图像重建聚类机器翻译等领域找到应用。 在本章中您将学习和实现自编码器的不同变体并最终学习如何堆叠自编码器。 本章包括以下主题
普通自编码器稀疏自编码器去噪自编码器卷积自编码器栈式自编码器
介绍
自编码器也称为空竹网络或自动关联器最初由 Hinton 和 PDP 小组于 1980 年代提出。 它们是前馈网络没有任何反馈并且它们是通过无监督学习来学习的。 像第 3 章的多人感知机神经网络感知机一样它们使用反向传播算法进行学习但有一个主要区别-目标与输入相同。
我们可以认为自编码器由两个级联网络组成-第一个网络是编码器它接受输入x然后使用变换h将其编码为编码信号y
y h(x)
第二网络使用编码信号y作为其输入并执行另一个变换f以获得重构信号r
r f(y) f(h(x))
我们将误差e定义为原始输入x与重构信号r之间的差e x - r。然后网络通过减少均方误差MSE进行学习并且像 MLP 一样该误差会传播回隐藏层。 下图显示了自编码器其中编码器和解码器分别突出显示。 自编码器可以具有权重分配也就是说解码器和编码器的权重只是彼此的换位这可以在训练参数数量较少时帮助网络更快地学习但同时会降低编码器的自由度。 网络。 它们与第 7 章“无监督学习”的 RBM 非常相似但有一个很大的区别-自编码器中神经元的状态是确定性的而在 RBM 中神经元是概率性的 根据隐藏层的大小自编码器分为不完整隐藏层的神经元少于输入层或过完整隐藏层的神经元多于输入层。 。 根据对损失施加的限制/约束我们有多种类型的自编码器稀疏自编码器降噪自编码器和卷积自编码器。 在本章中您将了解自编码器中的这些变体并使用 TensorFlow 实现它们。
自编码器的明显应用之一是在降维领域[2]。 结果表明与 PCA 相比自编码器产生了更好的结果。 自编码器还可以用于特征提取[3]文档检索[2]分类和异常检测。
另见 Rumelhart, David E., Geoffrey E. Hinton, and Ronald J. Williams. Learning internal representations by error propagation. No. ICS-8506. California Univ San Diego La Jolla Inst for Cognitive Science, 1985. (http://www.cs.toronto.edu/~fritz/absps/pdp8.pdf) Hinton, Geoffrey E., and Ruslan R. Salakhutdinov. Reducing the dimensionality of data with neural networks, science 313.5786 (2006): 504-507. (https://pdfs.semanticscholar.org/7d76/b71b700846901ac4ac119403aa737a285e36.pdf) Masci, Jonathan, et al. Stacked convolutional auto-encoders for hierarchical feature extraction. Artificial Neural Networks and Machine Learning–ICANN 2011 (2011): 52-59. (https://www.researchgate.net/profile/Jonathan_Masci/publication/221078713_Stacked_Convolutional_Auto-Encoders_for_Hierarchical_Feature_Extraction/links/0deec518b9c6ed4634000000/Stacked-Convolutional-Auto-Encoders-for-Hierarchical-Feature-Extraction.pdf) Japkowicz, Nathalie, Catherine Myers, and Mark Gluck. A novelty detection approach to classification. IJCAI. Vol. 1. 1995. (http://www.ijcai.org/Proceedings/95-1/Papers/068.pdf)
普通自编码器
Hinton 提出的普通自编码器仅包含一个隐藏层。 隐藏层中神经元的数量少于输入或输出层中神经元的数量。 这导致对网络中信息流产生瓶颈效应因此我们可以将隐藏层视为瓶颈层从而限制了要存储的信息。 自编码器中的学习包括在隐藏层上开发输入信号的紧凑表示以便输出层可以忠实地再现原始输入 具有单个隐藏层的自编码器
准备
此秘籍将使用自编码器进行图像重建 我们将在 MNIST 数据库上训练自编码器并将其用于重建测试图像。
操作步骤
我们按以下步骤进行
与往常一样第一步是导入所有必需的模块
import tensorflow as tf
import numpy as np
from tensorflow.examples.tutorials.mnist import input_data
import matplotlib.pyplot as plt
%matplotlib inline接下来我们从 TensorFlow 示例中获取 MNIST 数据-这里要注意的重要一点是标签不是一次性编码的仅仅是因为我们没有使用标签来训练网络。 自编码器通过无监督学习来学习
mnist input_data.read_data_sets(MNIST_data/)
trX, trY, teX, teY mnist.train.images, mnist.train.labels, mnist.test.images, mnist.test.labels接下来我们声明一个类AutoEncoder 该类具有init方法来为自编码器初始化权重偏差和占位符。 我们还可以使用init方法构建完整的图。 该类还具有用于encoderdecoder设置会话set_session和fit的方法。 我们在此处构建的自编码器使用简单的 MSE 作为loss函数我们尝试使用AdamOptimizer对其进行优化
class AutoEncoder(object):
def __init__(self, m, n, eta 0.01):m: Number of neurons in input/output layer
n: number of neurons in hidden layerself._m m
self._n n
self.learning_rate eta# Create the Computational graph# Weights and biases
self._W1 tf.Variable(tf.random_normal(shape(self._m,self._n)))
self._W2 tf.Variable(tf.random_normal(shape(self._n,self._m)))
self._b1 tf.Variable(np.zeros(self._n).astype(np.float32)) #bias for hidden layer
self._b2 tf.Variable(np.zeros(self._m).astype(np.float32)) #bias for output layer# Placeholder for inputs
self._X tf.placeholder(float, [None, self._m])self.y self.encoder(self._X)
self.r self.decoder(self.y)
error self._X - self.rself._loss tf.reduce_mean(tf.pow(error, 2))
self._opt tf.train.AdamOptimizer(self.learning_rate).minimize(self._loss)def encoder(self, x):
h tf.matmul(x, self._W1) self._b1
return tf.nn.sigmoid(h)def decoder(self, x):
h tf.matmul(x, self._W2) self._b2
return tf.nn.sigmoid(h)def set_session(self, session):
self.session sessiondef reduced_dimension(self, x):
h self.encoder(x)
return self.session.run(h, feed_dict{self._X: x})def reconstruct(self,x):
h self.encoder(x)
r self.decoder(h)
return self.session.run(r, feed_dict{self._X: x})def fit(self, X, epochs 1, batch_size 100):
N, D X.shape
num_batches N // batch_sizeobj []
for i in range(epochs):
#X shuffle(X)
for j in range(num_batches):batch X[j * batch_size: (j * batch_size batch_size)]_, ob self.session.run([self._opt,self._loss], feed_dict{self._X: batch})if j % 100 0 and i % 100 0:print(training epoch {0} batch {2} cost {1}.format(i,ob, j))
obj.append(ob)
return obj为了能够在训练后使用自编码器我们还定义了两个工具函数reduced_dimension提供编码器网络的输出reconstruct重构最终图像。
我们将输入数据转换为float进行训练初始化所有变量然后开始计算会话。 在计算中我们目前仅测试自编码器的重构能力
Xtrain trX.astype(np.float32)
Xtest teX.astype(np.float32)
_, m Xtrain.shapeautoEncoder AutoEncoder(m, 256)#Initialize all variables
init tf.global_variables_initializer()
with tf.Session() as sess:sess.run(init)autoEncoder.set_session(sess)err autoEncoder.fit(Xtrain, epochs10)out autoEncoder.reconstruct(Xtest[0:100])我们可以通过绘制误差与周期的关系图来验证我们的网络在训练时是否确实优化了 MSE。 为了获得良好的训练应该使用epochs来减少误差
plt.plot(err)
plt.xlabel(epochs)
plt.ylabel(cost)该图如下所示 我们可以看到随着网络的学习损耗/成本正在降低到我们达到 5,000 个周期时损耗/成本几乎在一条线上振荡。 这意味着进一步增加周期将是无用的。 如果现在要改善训练则应该更改超参数例如学习率批量大小和使用的优化程序。
现在让我们看一下重建的图像。 在这里您可以同时看到由我们的自编码器生成的原始图像和重建图像
# Plotting original and reconstructed images
row, col 2, 8
idx np.random.randint(0, 100, row * col // 2)
f, axarr plt.subplots(row, col, sharexTrue, shareyTrue, figsize(20,4))
for fig, row in zip([Xtest,out], axarr):for i,ax in zip(idx,row):ax.imshow(fig[i].reshape((28, 28)), cmapGreys_r)ax.get_xaxis().set_visible(False)ax.get_yaxis().set_visible(False)我们得到以下结果 工作原理
有趣的是在前面的代码中我们将输入的尺寸从 784 减少到 256并且我们的网络仍可以重建原始图像。 让我们比较一下具有相同隐藏层尺寸的 RBM第 7 章无监督学习的表现 我们可以看到自编码器重建的图像比 RBM 重建的图像更清晰。 原因是在自编码器中还有其他权重从隐藏层到解码器输出层的权重需要训练因此保留了学习知识。 随着自编码器了解更多即使两者都将信息压缩到相同的尺寸它的表现也比 RBM 更好。
更多
诸如 PCA 之类的自编码器可以用于降维但是 PCA 仅可以表示线性变换但是我们可以在自编码器中使用非线性激活函数从而在编码中引入非线性。 这是从 Hinton 论文复制的结果该结果使用神经网络降低了数据的维数。 该结果将 PCAA的结果与栈式 RBM 作为具有 784-1000-500-250-2 架构的自编码器的结果进行了比较 正如我们稍后将看到的当使用栈式自编码器制作自编码器时每个自编码器最初都经过单独的预训练然后对整个网络进行微调以获得更好的表现。
稀疏自编码器
我们在前面的秘籍中看到的自编码器的工作方式更像是一个身份网络-它们只是重构输入。 重点是在像素级别重建图像唯一的限制是瓶颈层中的单元数 有趣的是像素级重建不能确保网络将从数据集中学习抽象特征。 通过添加更多约束我们可以确保网络从数据集中学习抽象特征。
在稀疏自编码器中将稀疏惩罚项添加到重构误差中以确保在任何给定时间触发瓶颈层中较少的单元。 如果m是输入模式的总数那么我们可以定义一个数量ρ_hat您可以在 Andrew Ng 的讲座中检查数学细节它测量每个隐藏层单元的净活动平均触发多少次。 基本思想是放置一个约束ρ_hat使其等于稀疏性参数ρ。这导致损失函数中添加了稀疏性的正则项因此现在loss函数如下
loss Mean squared error Regularization for sparsity parameter如果ρ_hat偏离ρ则此正则化项将对网络造成不利影响做到这一点的一种标准方法是使用ρ和ρ_hat之间的 Kullback-Leiber KL差异。
准备
在开始秘籍之前让我们进一步探讨 KL 的差异D[KL]。 它是两个分布之间差异的非对称度量在我们的情况下为ρ和ρ_hat。当ρ和ρ_hat相等时则为零否则当ρ_hat与ρ分叉时它单调增加。在数学上它表示为 这是固定ρ 0.3时D[KL]的图我们可以看到当ρ_hat 0.3时D[KL] 0否则在两端单调增长 操作步骤
我们按以下步骤进行
我们导入必要的模块
import tensorflow as tf
import numpy as np
from tensorflow.examples.tutorials.mnist import input_data
import matplotlib.pyplot as plt
%matplotlib inline从 TensorFlow 示例中加载 MNIST 数据集
mnist input_data.read_data_sets(MNIST_data/)
trX, trY, teX, teY mnist.train.images, mnist.train.labels, mnist.test.images, mnist.test.labels定义SparseAutoEncoder类它与前面的秘籍中的AutoEncoder类非常相似除了引入了 KL 散度损失之外
def kl_div(self, rho, rho_hat):term2_num tf.constant(1.)- rhoterm2_den tf.constant(1.) - rho_hatkl self.logfunc(rho,rho_hat) self.logfunc(term2_num, term2_den)return kldef logfunc(self, x1, x2):return tf.multiply( x1, tf.log(tf.div(x1,x2)))
我们将 KL 约束添加到损失中如下所示
alpha 7.5e-5
kl_div_loss tf.reduce_sum(self.kl_div(0.02, tf.reduce_mean(self.y,0)))
loss self._loss alpha * kl_div_loss在此alpha是赋予稀疏性约束的权重。 该类的完整代码如下
class SparseAutoEncoder(object):def __init__(self, m, n, eta 0.01):m: Number of neurons in input/output layern: number of neurons in hidden layerself._m mself._n nself.learning_rate eta# Create the Computational graph# Weights and biasesself._W1 tf.Variable(tf.random_normal(shape(self._m,self._n)))self._W2 tf.Variable(tf.random_normal(shape(self._n,self._m)))self._b1 tf.Variable(np.zeros(self._n).astype(np.float32)) #bias for hidden layerself._b2 tf.Variable(np.zeros(self._m).astype(np.float32)) #bias for output layer# Placeholder for inputsself._X tf.placeholder(float, [None, self._m])self.y self.encoder(self._X)self.r self.decoder(self.y)error self._X - self.rself._loss tf.reduce_mean(tf.pow(error, 2))alpha 7.5e-5kl_div_loss tf.reduce_sum(self.kl_div(0.02, tf.reduce_mean(self.y,0)))loss self._loss alpha * kl_div_loss self._opt tf.train.AdamOptimizer(self.learning_rate).minimize(loss)def encoder(self, x):h tf.matmul(x, self._W1) self._b1return tf.nn.sigmoid(h)def decoder(self, x):h tf.matmul(x, self._W2) self._b2return tf.nn.sigmoid(h)def set_session(self, session):self.session sessiondef reduced_dimension(self, x):h self.encoder(x)return self.session.run(h, feed_dict{self._X: x})def reconstruct(self,x):h self.encoder(x)r self.decoder(h)return self.session.run(r, feed_dict{self._X: x})def kl_div(self, rho, rho_hat):term2_num tf.constant(1.)- rhoterm2_den tf.constant(1.) - rho_hatkl self.logfunc(rho,rho_hat) self.logfunc(term2_num, term2_den)return kldef logfunc(self, x1, x2):return tf.multiply( x1, tf.log(tf.div(x1,x2)))def fit(self, X, epochs 1, batch_size 100):N, D X.shapenum_batches N // batch_sizeobj []for i in range(epochs):#X shuffle(X)for j in range(num_batches):batch X[j * batch_size: (j * batch_size batch_size)]_, ob self.session.run([self._opt,self._loss], feed_dict{self._X: batch})if j % 100 0:print(training epoch {0} batch {2} cost {1}.format(i,ob, j))
obj.append(ob)return obj接下来我们声明SparseAutoEncoder类的对象对训练数据进行拟合并计算重建的图像
Xtrain trX.astype(np.float32)
Xtest teX.astype(np.float32)
_, m Xtrain.shape
sae SparseAutoEncoder(m, 256)
#Initialize all variables
init tf.global_variables_initializer()
with tf.Session() as sess:sess.run(init)sae.set_session(sess)err sae.fit(Xtrain, epochs10)out sae.reconstruct(Xtest[0:100])让我们看看随着网络学习均方重构损失的变化
plt.plot(err)
plt.xlabel(epochs)
plt.ylabel(Reconstruction Loss (MSE))情节如下 让我们看一下重建的图像
# Plotting original and reconstructed images
row, col 2, 8
idx np.random.randint(0, 100, row * col // 2)
f, axarr plt.subplots(row, col, sharexTrue, shareyTrue, figsize(20,4))
for fig, row in zip([Xtest,out], axarr):for i,ax in zip(idx,row):ax.imshow(fig[i].reshape((28, 28)), cmapGreys_r)ax.get_xaxis().set_visible(False)ax.get_yaxis().set_visible(False)我们得到以下结果 工作原理
您必须已经注意到稀疏自编码器的主要代码与普通自编码器的主要代码完全相同这是因为稀疏自编码器只有一个主要变化-增加了 KL 发散损耗以确保稀疏性。 隐藏的瓶颈层。 但是如果比较这两个重构则可以发现即使在隐藏层中具有相同数量的单元稀疏自编码器也比标准编码器好得多 训练 MNIST 数据集的原始自编码器后的重建损失为 0.022而稀疏自编码器则为 0.006。 因此添加约束会迫使网络学习数据的隐藏表示。
更多
输入的紧凑表示形式以权重存储 让我们可视化网络学习到的权重。 这分别是标准自编码器和稀疏自编码器的编码器层的权重。 我们可以看到在标准自编码器中许多隐藏单元的权重非常大表明它们工作过度 另见
http://web.engr.illinois.edu/~hanj/cs412/bk3/KL-divergence.pdfhttps://en.wikipedia.org/wiki/Kullback–Leibler_divergence
去噪自编码器
我们在前两个秘籍中探讨过的两个自编码器是未完成的自编码器的示例因为与输入输出层相比它们中的隐藏层具有较低的尺寸。 去噪自编码器属于过完整自编码器的类别因为当隐藏层的尺寸大于输入层的尺寸时它会更好地工作。
去噪自编码器从损坏的嘈杂的输入中学习 它为编码器网络提供噪声输入然后将来自解码器的重建图像与原始输入进行比较。 这个想法是这将帮助网络学习如何去噪输入。 它不再只是按像素进行比较而是为了进行去噪还将学习相邻像素的信息。
准备
去噪自编码器还将具有 KL 散度惩罚项 它在两个主要方面与先前秘籍的稀疏自编码器有所不同。 首先n_hidden m瓶颈层中的隐藏单元数大于输入层m中的单元数n_hidden m。 其次编码器的输入已损坏。 为了在 TensorFlow 中做到这一点我们添加了invalid函数这给输入增加了噪音
def corruption(x, noise_factor 0.3): #corruption of the inputnoisy_imgs x noise_factor * np.random.randn(*x.shape)noisy_imgs np.clip(noisy_imgs, 0., 1.)return noisy_imgs操作步骤
像往常一样第一步是导入必要的模块-TensorFlownumpy 来操纵输入数据matplotlib 来进行绘制等等
import tensorflow as tf
import numpy as np
from tensorflow.examples.tutorials.mnist import input_data
import matplotlib.pyplot as plt
import math
%matplotlib inline从 TensorFlow 示例中加载数据。 在本章的所有秘籍中我们都使用标准的 MNIST 数据库进行说明以便为您提供不同自编码器之间的基准。
mnist input_data.read_data_sets(MNIST_data/)
trX, trY, teX, teY mnist.train.images, mnist.train.labels, mnist.test.images, mnist.test.labels接下来我们定义此秘籍的主要组成部分DenoisingAutoEncoder类。 该类与我们在前面的秘籍中创建的SparseAutoEncoder类非常相似。 在这里我们为噪点图像添加了一个占位符 该噪声输入被馈送到编码器。 现在当输入的是噪点图像时重构误差就是原始清晰图像与解码器输出之间的差。 我们在此保留稀疏惩罚条款。 因此拟合函数将原始图像和噪声图像都作为其参数。
class DenoisingAutoEncoder(object):
def __init__(self, m, n, eta 0.01):m: Number of neurons in input/output layer
n: number of neurons in hidden layerself._m m
self._n n
self.learning_rate eta# Create the Computational graph# Weights and biases
self._W1 tf.Variable(tf.random_normal(shape(self._m,self._n)))
self._W2 tf.Variable(tf.random_normal(shape(self._n,self._m)))
self._b1 tf.Variable(np.zeros(self._n).astype(np.float32)) #bias for hidden layer
self._b2 tf.Variable(np.zeros(self._m).astype(np.float32)) #bias for output layer# Placeholder for inputs
self._X tf.placeholder(float, [None, self._m])self._X_noisy tf.placeholder(float, [None, self._m])self.y self.encoder(self._X_noisy)
self.r self.decoder(self.y)
error self._X - self.rself._loss tf.reduce_mean(tf.pow(error, 2))
#self._loss tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(labels self._X, logits self.r))
alpha 0.05
kl_div_loss tf.reduce_sum(self.kl_div(0.02, tf.reduce_mean(self.y,0)))
loss self._loss alpha * kl_div_loss
self._opt tf.train.AdamOptimizer(self.learning_rate).minimize(loss)def encoder(self, x):
h tf.matmul(x, self._W1) self._b1
return tf.nn.sigmoid(h)def decoder(self, x):
h tf.matmul(x, self._W2) self._b2
return tf.nn.sigmoid(h)def set_session(self, session):
self.session sessiondef reconstruct(self,x):
h self.encoder(x)
r self.decoder(h)
return self.session.run(r, feed_dict{self._X: x})def kl_div(self, rho, rho_hat):
term2_num tf.constant(1.)- rho
term2_den tf.constant(1.) - rho_hat
kl self.logfunc(rho,rho_hat) self.logfunc(term2_num, term2_den)
return kldef logfunc(self, x1, x2):
return tf.multiply( x1, tf.log(tf.div(x1,x2)))def corrupt(self,x):
return x * tf.cast(tf.random_uniform(shapetf.shape(x), minval0,maxval2),tf.float32)def getWeights(self):
return self.session.run([self._W1, self._W2,self._b1, self._b2])def fit(self, X, Xorg, epochs 1, batch_size 100):
N, D X.shape
num_batches N // batch_sizeobj []
for i in range(epochs):
#X shuffle(X)
for j in range(num_batches):
batch X[j * batch_size: (j * batch_size batch_size)]
batchO Xorg[j * batch_size: (j * batch_size batch_size)]
_, ob self.session.run([self._opt,self._loss], feed_dict{self._X: batchO, self._X_noisy: batch})
if j % 100 0:
print(training epoch {0} batch {2} cost {1}.format(i,ob, j))
obj.append(ob)
return obj也可以向自编码器对象添加噪声。 在这种情况下您将使用类self._X_noisy self.corrupt(self._X) * 0.3 self._X * (1 - 0.3)中定义的损坏方法并且fit方法也将更改为以下内容
def fit(self, X, epochs 1, batch_size 100):N, D X.shapenum_batches N // batch_sizeobj []for i in range(epochs):#X shuffle(X)for j in range(num_batches):batch X[j * batch_size: (j * batch_size batch_size)]_, ob self.session.run([self._opt,self._loss], feed_dict{self._X: batch})if j % 100 0:print(training epoch {0} batch {2} cost {1}.format(i,ob, j)) obj.append(ob)return obj现在我们使用前面定义的损坏函数来生成一个嘈杂的图像并将其提供给会话
n_hidden 800
Xtrain trX.astype(np.float32)
Xtrain_noisy corruption(Xtrain).astype(np.float32)
Xtest teX.astype(np.float32)
#noise Xtest * np.random.randint(0, 2, Xtest.shape).astype(np.float32)
Xtest_noisy corruption(Xtest).astype(np.float32) #Xtest * (1-0.3) noise *(0.3)
_, m Xtrain.shapedae DenoisingAutoEncoder(m, n_hidden)#Initialize all variables
init tf.global_variables_initializer()
with tf.Session() as sess:sess.run(init)dae.set_session(sess)err dae.fit(Xtrain_noisy, Xtrain, epochs10)out dae.reconstruct(Xtest_noisy[0:100])W1, W2, b1, b2 dae.getWeights()red dae.reduced_dimension(Xtrain)随着网络的学习重建损失减少
plt.plot(err)
plt.xlabel(epochs)
plt.ylabel(Reconstruction Loss (MSE))情节如下 当来自测试数据集的嘈杂图像呈现给训练网络时重建图像如下
# Plotting original and reconstructed images
row, col 2, 8
idx np.random.randint(0, 100, row * col // 2)
f, axarr plt.subplots(row, col, sharexTrue, shareyTrue, figsize(20,4))
for fig, row in zip([Xtest_noisy,out], axarr):for i,ax in zip(idx,row):ax.imshow(fig[i].reshape((28, 28)), cmapGreys_r)ax.get_xaxis().set_visible(False)ax.get_yaxis().set_visible(False)我们得到以下结果 另见
https://cs.stanford.edu/people/karpathy/convnetjs/demo/autoencoder.htmlhttp://blackecho.github.io/blog/machine-learning/2016/02/29/denoising-autoencoder-tensorflow.html
卷积自编码器
研究人员发现卷积神经网络CNN与图像效果最佳因为它们可以提取隐藏在图像中的空间信息。 因此很自然地假设如果编码器和解码器网络由 CNN 组成它将比其余的自编码器更好地工作因此我们有了卷积自编码器CAE。 在第 4 章“卷积神经网络”中说明了卷积和最大池化的过程我们将以此为基础来了解卷积自编码器的工作原理。
CAE 是其中编码器和解码器均为 CNN 网络的一种 CAE。 编码器的卷积网络学习将输入编码为一组信号然后解码器 CNN 尝试从中重建输入。 它们充当通用特征提取器并学习从输入捕获特征所需的最佳过滤器。
准备
从第 4 章“卷积神经网络”中您了解到随着添加卷积层传递到下一层的信息在空间范围上会减少但是在自编码器中重建的图像应该有输入图像的相同的大小和深度。 这意味着解码器应以某种方式对图像进行大小调整和卷积以重建原始图像。 与卷积一起增加空间范围的一种方法是借助转置的卷积层。 通过tf.nn.conv2d_transpose可以轻松地在 TensorFlow 中实现这些功能但是发现转置的卷积层会在最终图像中产生伪像。 奥古斯都·奥德纳Augustus Odena等。 [1]在他们的工作中表明可以通过使用最近邻或双线性插值上采样再加上卷积层来调整层的大小来避免这些伪像。 他们通过tf.image.resize_images实现了最近邻插值取得了最佳结果 我们将在此处采用相同的方法。
操作步骤
与往常一样第一步包括必要的模块
import tensorflow as tf
import numpy as np
from tensorflow.examples.tutorials.mnist import input_data
import matplotlib.pyplot as plt
import math
%matplotlib inline加载输入数据
mnist input_data.read_data_sets(MNIST_data/)
trX, trY, teX, teY mnist.train.images, mnist.train.labels, mnist.test.images, mnist.test.labels定义网络参数。 在这里我们还计算每个最大池层的输出的空间尺寸。 我们需要以下信息来对解码器网络中的图像进行升采样
# Network Parameters
h_in, w_in 28, 28 # Image size height and width
k 3 # Kernel size
p 2 # pool
s 2 # Strides in maxpool
filters {1:32,2:32,3:16}
activation_fntf.nn.relu
# Change in dimensions of image after each MaxPool
h_l2, w_l2 int(np.ceil(float(h_in)/float(s))) , int(np.ceil(float(w_in)/float(s))) # Height and width: second encoder/decoder layer
h_l3, w_l3 int(np.ceil(float(h_l2)/float(s))) , int(np.ceil(float(w_l2)/float(s))) # Height and width: third encoder/decoder layer为输入嘈杂的图像和目标对应的清晰图像创建占位符
X_noisy tf.placeholder(tf.float32, (None, h_in, w_in, 1), nameinputs)
X tf.placeholder(tf.float32, (None, h_in, w_in, 1), nametargets)建立编码器和解码器网络
### Encoder
conv1 tf.layers.conv2d(X_noisy, filters[1], (k,k), paddingsame, activationactivation_fn)
# Output size h_in x w_in x filters[1]
maxpool1 tf.layers.max_pooling2d(conv1, (p,p), (s,s), paddingsame)
# Output size h_l2 x w_l2 x filters[1]
conv2 tf.layers.conv2d(maxpool1, filters[2], (k,k), paddingsame, activationactivation_fn)
# Output size h_l2 x w_l2 x filters[2]
maxpool2 tf.layers.max_pooling2d(conv2,(p,p), (s,s), paddingsame)
# Output size h_l3 x w_l3 x filters[2]
conv3 tf.layers.conv2d(maxpool2,filters[3], (k,k), paddingsame, activationactivation_fn)
# Output size h_l3 x w_l3 x filters[3]
encoded tf.layers.max_pooling2d(conv3, (p,p), (s,s), paddingsame)
# Output size h_l3/s x w_l3/s x filters[3] Now 4x4x16### Decoder
upsample1 tf.image.resize_nearest_neighbor(encoded, (h_l3,w_l3))
# Output size h_l3 x w_l3 x filters[3]
conv4 tf.layers.conv2d(upsample1, filters[3], (k,k), paddingsame, activationactivation_fn)
# Output size h_l3 x w_l3 x filters[3]
upsample2 tf.image.resize_nearest_neighbor(conv4, (h_l2,w_l2))
# Output size h_l2 x w_l2 x filters[3]
conv5 tf.layers.conv2d(upsample2, filters[2], (k,k), paddingsame, activationactivation_fn)
# Output size h_l2 x w_l2 x filters[2]
upsample3 tf.image.resize_nearest_neighbor(conv5, (h_in,w_in))
# Output size h_in x w_in x filters[2]
conv6 tf.layers.conv2d(upsample3, filters[1], (k,k), paddingsame, activationactivation_fn)
# Output size h_in x w_in x filters[1]logits tf.layers.conv2d(conv6, 1, (k,k) , paddingsame, activationNone)# Output size h_in x w_in x 1
decoded tf.nn.sigmoid(logits, namedecoded)loss tf.nn.sigmoid_cross_entropy_with_logits(labelsX, logitslogits)
cost tf.reduce_mean(loss)
opt tf.train.AdamOptimizer(0.001).minimize(cost)启动会话
sess tf.Session()将模型拟合给定输入
epochs 10
batch_size 100
# Sets how much noise were adding to the MNIST images
noise_factor 0.5
sess.run(tf.global_variables_initializer())
err []
for i in range(epochs):for ii in range(mnist.train.num_examples//batch_size):batch mnist.train.next_batch(batch_size)# Get images from the batchimgs batch[0].reshape((-1, h_in, w_in, 1))# Add random noise to the input imagesnoisy_imgs imgs noise_factor * np.random.randn(*imgs.shape)# Clip the images to be between 0 and 1noisy_imgs np.clip(noisy_imgs, 0., 1.)# Noisy images as inputs, original images as targetsbatch_cost, _ sess.run([cost, opt], feed_dict{X_noisy: noisy_imgs,X: imgs})err.append(batch_cost)if ii%100 0:print(Epoch: {0}/{1}... Training loss {2}.format(i, epochs, batch_cost))网络学习到的误差如下
plt.plot(err)
plt.xlabel(epochs)
plt.ylabel(Cross Entropy Loss)绘图如下 最后让我们看一下重建的图像
fig, axes plt.subplots(rows2, cols10, sharexTrue, shareyTrue, figsize(20,4))
in_imgs mnist.test.images[:10]
noisy_imgs in_imgs noise_factor * np.random.randn(*in_imgs.shape)
noisy_imgs np.clip(noisy_imgs, 0., 1.)
reconstructed sess.run(decoded, feed_dict{X_noisy: noisy_imgs.reshape((10, 28, 28, 1))})
for images, row in zip([noisy_imgs, reconstructed], axes):for img, ax in zip(images, row):ax.imshow(img.reshape((28, 28)), cmapGreys_r)ax.get_xaxis().set_visible(False)ax.get_yaxis().set_visible(False)这是前面代码的输出 关闭会话
sess.close()工作原理
前面的 CAE 是降噪 CAE与仅由一个瓶颈层组成的简单降噪自编码器相比我们可以看到它在降噪图像方面更好。
更多
研究人员已将 CAE 用于语义分割。 有趣的读物是 Badrinayanan 等人在 2015 年发表的论文 Segnet一种用于图像分割的深度卷积编码器-解码器架构。 该网络使用 VGG16 的卷积层作为其编码器网络并包含一层解码器每个解码器对应一个解码器层次作为其解码器网络。 解码器使用从相应的编码器接收的最大池索引并对输入特征图执行非线性上采样。 本文的链接在本秘籍的另请参见部分以及 GitHub 链接中给出。
另见
https://distill.pub/2016/deconv-checkerboard/https://pgaleone.eu/neural-networks/2016/11/24/convolutional-autoencoders/https://arxiv.org/pdf/1511.00561.pdfhttps://github.com/arahusky/Tensorflow-Segmentation
栈式自编码器
到目前为止涵盖的自编码器CAE 除外仅由单层编码器和单层解码器组成。 但是我们可能在编码器和解码器网络中具有多层 使用更深的编码器和解码器网络可以使自编码器表示复杂的特征。 这样获得的结构称为栈式自编码器深度自编码器 由一个编码器提取的特征将作为输入传递到下一个编码器。 可以将栈式自编码器作为一个整体网络进行训练以最大程度地减少重构误差或者可以首先使用您先前学习的无监督方法对每个单独的编码器/解码器网络进行预训练然后对整个网络进行微调。 已经指出通过预训练也称为贪婪分层训练效果更好。
准备
在秘籍中我们将使用贪婪分层方法来训练栈式自编码器 为了简化任务我们将使用共享权重因此相应的编码器/解码器权重将相互转换。
操作步骤
我们按以下步骤进行
第一步是导入所有必要的模块
import tensorflow as tf
import numpy as np
from tensorflow.examples.tutorials.mnist import input_data
import matplotlib.pyplot as plt
%matplotlib inline加载数据集
mnist input_data.read_data_sets(MNIST_data/)
trX, trY, teX, teY mnist.train.images, mnist.train.labels, mnist.test.images, mnist.test.labels接下来我们定义类StackedAutoencoder。 __init__类方法包含一个列表该列表包含从第一个输入自编码器和学习率开始的每个自编码器中的许多神经元。 由于每一层的输入和输出都有不同的尺寸因此我们选择字典数据结构来表示每一层的权重偏差和输入
class StackedAutoEncoder(object):def __init__(self, list1, eta 0.02):list1: [input_dimension, hidden_layer_1, ....,hidden_layer_n]N len(list1)-1self._m list1[0]self.learning_rate eta# Create the Computational graphself._W {}self._b {}self._X {}self._X[0] tf.placeholder(float, [None, list1[0]])for i in range(N):layer {0}.format(i1)print(AutoEncoder Layer {0}: {1} -- {2}.format(layer, list1[i], list1[i1]))self._W[E layer] tf.Variable(tf.random_normal(shape(list1[i], list1[i1])),nameWtsEncoderlayer)self._b[E layer] tf.Variable(np.zeros(list1[i1]).astype(np.float32),nameBiasEncoderlayer)self._X[layer] tf.placeholder(float, [None, list1[i1]])self._W[D layer] tf.transpose(self._W[E layer]) # Shared weightsself._b[D layer] tf.Variable(np.zeros(list1[i]).astype(np.float32),nameBiasDecoder layer)# Placeholder for inputsself._X_noisy tf.placeholder(float, [None, self._m])我们建立一个计算图来定义每个自编码器的优化参数同时进行预训练。 当先前的自编码器的编码器的输出为其输入时它涉及为每个自编码器定义重建损耗。 为此我们定义类方法pretrain和one_pass它们分别为每个栈式自编码器返回训练操作器和编码器的输出 self.train_ops {}self.out {}for i in range(N):layer {0}.format(i1)prev_layer {0}.format(i)opt self.pretrain(self._X[prev_layer], layer)self.train_ops[layer] optself.out[layer] self.one_pass(self._X[prev_layer], self._W[Elayer], self._b[Elayer], self._b[Dlayer])我们建立计算图以对整个栈式自编码器进行微调。 为此我们使用类方法encoder和decoder
self.y self.encoder(self._X_noisy,N) #Encoder output
self.r self.decoder(self.y,N) # Decoder ouputoptimizer tf.train.AdamOptimizer(self.learning_rate)
error self._X[0] - self.r # Reconstruction Errorself._loss tf.reduce_mean(tf.pow(error, 2))
self._opt optimizer.minimize(self._loss)最后我们定义类方法fit以执行每个自编码器的分批预训练然后进行微调。 在进行预训练时我们使用未损坏的输入而对于微调我们使用损坏的输入。 这使我们能够使用栈式自编码器甚至从嘈杂的输入中进行重构
def fit(self, Xtrain, Xtr_noisy, layers, epochs 1, batch_size 100):N, D Xtrain.shapenum_batches N // batch_sizeX_noisy {}X {}X_noisy [0] Xtr_noisyX[0] Xtrainfor i in range(layers):Xin X[str(i)]print(Pretraining Layer , i1)for e in range(5):for j in range(num_batches):batch Xin[j * batch_size: (j * batch_size batch_size)]self.session.run(self.train_ops[str(i1)], feed_dict {self._X[str(i)]: batch})print(Pretraining Finished)X[str(i1)] self.session.run(self.out[str(i1)], feed_dict {self._X[str(i)]: Xin})obj []for i in range(epochs):for j in range(num_batches):batch Xtrain[j * batch_size: (j * batch_size batch_size)]batch_noisy Xtr_noisy[j * batch_size: (j * batch_size batch_size)]_, ob self.session.run([self._opt,self._loss], feed_dict{self._X[0]: batch, self._X_noisy: batch_noisy})if j % 100 0 :print(training epoch {0} batch {2} cost {1}.format(i,ob, j)) obj.append(ob)return obj不同的类方法如下
def encoder(self, X, N):x Xfor i in range(N):layer {0}.format(i1)hiddenE tf.nn.sigmoid(tf.matmul(x, self._W[Elayer]) self._b[Elayer])x hiddenEreturn xdef decoder(self, X, N):x Xfor i in range(N,0,-1):layer {0}.format(i)hiddenD tf.nn.sigmoid(tf.matmul(x, self._W[Dlayer]) self._b[Dlayer])x hiddenDreturn xdef set_session(self, session):self.session sessiondef reconstruct(self,x, n_layers):h self.encoder(x, n_layers)r self.decoder(h, n_layers)return self.session.run(r, feed_dict{self._X[0]: x})def pretrain(self, X, layer ):y tf.nn.sigmoid(tf.matmul(X, self._W[Elayer]) self._b[Elayer])r tf.nn.sigmoid(tf.matmul(y, self._W[Dlayer]) self._b[Dlayer])# Objective Functionerror X - r # Reconstruction Errorloss tf.reduce_mean(tf.pow(error, 2))opt tf.train.AdamOptimizer(.001).minimize(loss, var_list [self._W[Elayer],self._b[Elayer],self._b[Dlayer]])return optdef one_pass(self, X, W, b, c):h tf.nn.sigmoid(tf.matmul(X, W) b)return h我们使用降噪自编码器秘籍中定义的破坏函数来破坏图像最后创建一个StackAutoencoder并对其进行训练
Xtrain trX.astype(np.float32)
Xtrain_noisy corruption(Xtrain).astype(np.float32)
Xtest teX.astype(np.float32)
Xtest_noisy corruption(Xtest).astype(np.float32)
_, m Xtrain.shapelist1 [m, 500, 50] # List with number of neurons in Each hidden layer, starting from input layer
n_layers len(list1)-1
autoEncoder StackedAutoEncoder(list1)#Initialize all variables
init tf.global_variables_initializer()with tf.Session() as sess:sess.run(init)autoEncoder.set_session(sess)err autoEncoder.fit(Xtrain, Xtrain_noisy, n_layers, epochs30)out autoEncoder.reconstruct(Xtest_noisy[0:100],n_layers)这里给出了随着堆叠自编码器的微调重建误差与历时的关系。 您可以看到由于进行了预训练我们已经从非常低的重建损失开始了
plt.plot(err)
plt.xlabel(epochs)
plt.ylabel(Fine Tuning Reconstruction Error)情节如下 现在让我们检查网络的表现。 当网络中出现嘈杂的测试图像时这是去噪后的手写图像 工作原理
在栈式自编码器上进行的实验表明应以较低的学习率值进行预训练。 这样可以确保在微调期间具有更好的收敛性和表现。
更多
整章都是关于自编码器的尽管目前它们仅用于降维和信息检索但它们引起了很多兴趣。 首先因为它们不受监督其次因为它们可以与 FCN 一起使用。 它们可以帮助我们应对维度的诅咒。 研究人员已经证明它们也可以用于分类和异常检测。
另见
关于栈式自编码器的一个不错的教程。Schwenk, Holger. The diabolo classifier. Neural Computation 10.8 (1998): 2175-2200.Sakurada, Mayu, and Takehisa Yairi. Anomaly detection using autoencoders with nonlinear dimensionality reduction. Proceedings of the MLSDA 2014 2nd Workshop on Machine Learning for Sensory Data Analysis. ACM, 2014.栈式自编码器的酷 TensorBoard 可视化和实现
九、强化学习
本章介绍强化学习RL-学习最少但最有前途的学习范例。 本章包括以下主题
了解 OpenAI Gym实现神经网络智能体来玩吃豆人用 Q 学习平衡推车深度 Q 网络和 Atari 游戏用策略梯度玩 Pong 游戏
介绍
2016 年 3 月由 Google DeepMind 制作的程序 AlphaGo 以 4 比 1 击败了世界上最好的围棋选手十八届世界冠军李·塞多尔Lee Sedol。 具有
208,168,199,381,979,984,699,478,633,344,862,770,286,522,
453,884,530,548,425,639,456,820,927,419,612,738,015,378,
525,648,451,698,519,643,907,259,916,015,628,128,546,089,
888,314,427, 129,715,319,317,557,736,620,397,247,064,840,935可能的法律委员会职位。 玩和赢得围棋无法通过简单的蛮力完成。 它需要技巧创造力以及专业围棋选手所说的直觉。
AlphaGo 在基于 RL 算法的深度神经网络与最先进的树搜索算法相结合的帮助下实现了这一非凡的成就。 本章介绍 RL 和我们用于执行 RL 的一些算法。
因此出现的第一个问题是什么是 RL它与我们在前几章中探讨的有监督和无监督学习有何不同
拥有宠物的任何人都知道训练宠物的最佳策略是奖励其期望的行为并惩罚其不良行为。 RL 也称为与批评者进行的学习它是一种学习范例其中智能体以相同的方式进行学习。 这里的智能体对应我们的网络程序 它可以执行一组动作a这会导致环境的状态s发生变化。 则智能体会感知其是否获得奖励或惩罚。
例如在狗的情况下狗是我们的智能体狗的自愿肌肉运动是动作地面是环境。 狗给我们骨头作为奖励从而感觉到我们对其动作的反应 改编自强化学习萨顿Sutton和巴托Barto的引言即使我们的大脑在前脑底部有一组称为“基底神经节”的皮层下核根据神经科学它们负责选择动作即帮助 我们决定在任何给定时间执行几个可能的动作中的哪一个。
智能体的目的是使报酬最大化并减少惩罚。 做出此决策涉及各种挑战最重要的挑战是如何最大化未来的回报也称为临时得分分配问题。 智能体根据某些策略π决定其操作 智能体根据其与环境的交互来学习此策略π。 有各种策略学习算法 我们将在本章中探索其中的一些。 智能体通过反复试验的过程来推断最优策略π*并且要学习最优策略智能体需要与之交互的环境 我们将使用提供不同环境的 OpenAI Gym。
在这里我们仅对 RL 中涉及的基本概念进行了回顾 我们假设您熟悉马尔可夫概念的决策过程折现因子和值函数状态值和动作值。
在本章以及随后的秘籍中我们将一集定义为游戏的一次运行例如解决一个数独游戏。 通常智能体会播放许多剧集以学习一种最佳策略该策略可使奖励最大化。
看到 RL 特工在没有任何游戏隐性知识的情况下如何在这些游戏中学会玩游戏不仅玩游戏甚至击败人类真是太神奇了。
了解 OpenAI Gym
我们将使用 OpenAI Gym 为我们的智能体提供一个环境。 OpenAI Gym 是一个开源工具包用于开发和比较 RL 算法。 它包含各种模拟环境可用于训练智能体和开发新的 RL 算法。
准备
首先要做的是安装 OpenAI Gym 使用pip install gym可以完成最少的安装。 OpenAI 运动场提供了多种环境例如 Atari棋盘游戏以及 2D 或 3D 物理引擎。 最小安装可在 Windows 上运行并且仅支持基本环境-算法toy_text和classic_control-但如果您要探索其他环境则它们将需要更多的依赖项。 OSX 和 Ubuntu 支持完整版本。 可以在 OpenAI Gym 的 GitHub 链接上阅读详细说明。
操作步骤
让我们从秘籍开始
OpenAI Gym 提供的核心接口是统一环境接口。 智能体可以使用三种基本方法与环境进行交互即重置逐步和渲染。 reset方法重置环境并返回观察值。 step方法将环境步进一个时间步并返回观察奖励完成和信息。 render方法呈现一帧环境例如弹出一个窗口。要使用 OpenAI Gym您需要先将其导入
import gym接下来我们创建我们的第一个环境
env_name Breakout-v3
env gym.make(env_name)我们使用reset方法启动环境
obs env.reset()让我们检查一下环境的形状
print(obs.shape)可以使用命令actions env.action_space检查可能的操作数量。 从此结果可以看出对于 Breakout-v4我们有四个可能的动作NoOpFireLeft和Right。 可以通过调用env.action_space.n命令获得操作总数。让我们定义一个具有随机策略的智能体。 智能体会随机选择四个可能的动作中的任何一个
def random_policy(n):action np.random.randint(0,n)return action接下来我们使用obs, reward, done, info env.step(action)允许我们的随机智能体播放 1,000 步
for step in range(1000): # 1000 steps maxaction random_policy(env.action_space.n)obs, reward, done, info env.step(action)env.render()if done:img env.render(modergb_array)plt.imshow(img)plt.show()print(The game is over in {} steps.format(step))breakobs告诉智能体程序环境是什么样的 对于我们的环境它对应于大小为210 x 160 x 3的 RGB 图像。在每个步骤中智能体将获得 0 或 1 奖励根据 OpenAI Gym Wiki其reward为[-inf, inf]。 游戏结束后环境将done返回为True。 info可用于调试但智能体不使用。 env.render()命令弹出一个窗口显示环境的当前状态。 当包含此命令时您可以通过弹出窗口查看座席如何尝试玩耍和学习。 最好在座席接受训练时对此进行评论以节省时间。
最后关闭环境
env.close()工作原理
前面的代码实现了一个随机智能体 智能体会随机选择以下四个动作之一 要观察的另一件重要事情是在这种环境中动作空间是离散的而观察空间是盒子类型的。 OpenAI 中关于空间动作/观察的术语“离散”和“框”是指允许的值。 离散空间允许固定范围的非负数在我们的情况下为0,1,2,3。 另一方面盒子空间表示一个n维盒子因此对于吃豆人来说任何有效观察结果都是210×160×3数字的数组。
更多
OpenAI Gym 由许多不同的环境组成其活跃的贡献社区在其中添加了许多环境。 要获取所有现有环境的列表可以运行以下简单代码
from gym import envs
env_ids [spec.id for spec in envs.registry.all()]
print(Total Number of environments are, len(env_ids))
for env_id in sorted(env_ids):print(env_id)目前OpenAI Gym 共有 777 个环境。 这是吃豆人使用与之前相同的随机智能体的图像 另见
可以从这里获取有关不同环境的详细信息。在这个链接中为某些环境维护了 Wiki 页面可以从这个链接获得有关安装说明和依赖项的详细信息。
实现神经网络智能体来玩吃豆人
让我们首先构建一个简单的神经网络智能体来玩“吃豆人”游戏。 我们将创建具有一组随机权重和偏差的智能体。 然后这些特工将尝试玩游戏 我们选择能够发挥最长平均持续时间的特工并假设他们是最佳策略。
准备
此秘籍中的智能体没有学习任何策略 他们根据初始权重固定策略做出决策。 智能体根据神经网络给出的概率来选择动作。 每个智能体做出的决定仅基于对环境的当前观察。
我们通过完全连接的神经网络来实现。 NN 的输入由环境的观察空间决定 输出神经元的数量由可能的离散动作的数量决定。 吃豆人游戏有九种可能的离散动作-无操作右转左转上转向下转左移右移上移和下移-因此我们的 NN 具有九个输出神经元。
操作步骤
让我们从秘籍开始
与往常一样第一步是导入模块。 在这种情况下除了通常的模块之外我们还将导入gym以便我们可以使用它提供的不同环境
import gym
import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt接下来我们创建一个RlAgent类。 该类由三种方法组成-__init__方法初始化 NN 大小并创建计算图。 在这里我们使用了 TensorFlow 函数tf.multinomial来决定采取的可能措施。 该函数根据我们网络的 9 个输出神经元的 Sigmoid 值返回操作。 这样可以确保网络根据概率选择最终操作。 predict方法返回由 NN 预测的动作。 get_weights方法可帮助我们获得获胜者智能体的权重和偏置
class RlAgent(object):def __init__(self,m,n,iniFalse,WNone, bNone ):self._graph tf.Graph()with self._graph.as_default():self._X tf.placeholder(tf.float32,shape(1,m))if iniFalse:self.W tf.Variable(tf.random_normal([m,n]), trainableFalse)self.bias tf.Variable(tf.random_normal([1,n]),trainableFalse)else:self.W Wself.bias bout tf.nn.sigmoid(tf.matmul(self._X,self.W) self.bias)self._result tf.multinomial(out,1)init tf.global_variables_initializer()self._sess tf.Session()self._sess.run(init)def predict(self, X):action self._sess.run(self._result, feed_dict {self._X: X})return actiondef get_weights(self):W, b self._sess.run([self.W, self.bias])return W, b我们定义了一些辅助函数来玩一个完整的游戏play_one_episode
def play_one_episode(env, agent):obs env.reset()img_pre preprocess_image(obs)done Falset 0while not done and t 10000:env.render() # This can be commented to speed up t 1action agent.predict(img_pre)#print(t,action)obs, reward, done, info env.step(action)img_pre preprocess_image(obs)if done:breakreturn tplay_multiple_episodes函数创建智能体的一个实例并使用该智能体进行许多游戏并返回其平均游戏时间
def play_multiple_episodes(env, T,iniFalse, WNone, bNone):episode_lengths np.empty(T)obs env.reset()img_pre preprocess_image(obs)if ini False:agent RlAgent(img_pre.shape[1],env.action_space.n)else:agent RlAgent(img_pre.shape[1],env.action_space.n,ini, W, b)for i in range(T):episode_lengths[i] play_one_episode(env, agent)avg_length episode_lengths.mean()print(avg length:, avg_length)if ini False:W, b agent.get_weights()return avg_length, W, brandom_search函数调用play_multiple_episodes 每次调用play_multiple_episodes时都会使用一组新的随机权重和偏差来实例化新智能体。 这些随机创建的 NN 智能体之一将胜过其他智能体这将是我们最终选择的智能体
def random_search(env):episode_lengths []best 0for t in range(10):print(Agent {} reporting.format(t))avg_length, wts, bias play_multiple_episodes(env, 10)episode_lengths.append(avg_length)if avg_length best:best_wt wtsbest_bias biasbest avg_lengthreturn episode_lengths, best_wt, best_bias每次执行步骤时环境都会返回一个观察场。 该观察具有三个颜色通道。 为了将其馈送到 NN需要对观测值进行预处理目前我们唯一要做的预处理是将其转换为灰度增加对比度并将其整形为行向量
def preprocess_image(img):img img.mean(axis 2) # to grayscaleimg[img150] 0 # Bring about a better contrastimg (img - 128)/128 - 1 # Normalize image from -1 to 1m,n img.shapereturn img.reshape(1,m*n)NN 智能体一一实例化然后选择最佳智能体。 为了提高计算效率我们目前仅搜索 10 个智能体每个智能体玩 10 场比赛。 玩得最长的游戏被认为是最好的
if __name__ __main__:env_name Breakout-v0#env_name MsPacman-v0env gym.make(env_name)episode_lengths, W, b random_search(env)plt.plot(episode_lengths)plt.show()print(Final Run with best Agent)play_multiple_episodes(env,10, iniTrue, WW, bb)结果如下 我们可以看到我们的随机智能体也可以平均 615.5 的长度玩游戏。 不错
用 Q 学习平衡推车
如导言所述我们有一个由状态ss ∈ S其中S是所有可能状态的集合描述的环境可以执行动作aa ∈ A其中A由所有可能的动作组成从而导致主体从一种状态移动到另一种状态 。 智能体因其行为而受到奖励智能体的目标是使奖励最大化。 在 Q 学习中智能体通过计算最大化报酬的状态-动作组合的数量R来学习要采取的动作策略π。 在选择行动时智能体不仅要考虑现在的奖励而且要考虑未来的折扣。
Q: S × A → R
智能体以Q的任意初始值开头并且随着智能体选择动作a并获得奖励r它会更新状态s取决于过去状态s和动作a和Q值
Q(s, a) (1 - α) · Q(s, a) α(r γ · max[a]Q(s, a))
在此α是学习率γ是折扣因子。 第一项保留Q的旧值第二项提供Q值的改进估计值它包括当前奖励和未来行动的折现奖励。 当结果状态不理想时这将降低Q值从而确保智能体在下次遇到此状态时不会选择相同的动作。 类似地当期望结果状态时相应的Q值将增加。
Q 学习的最简单实现涉及维护和更新状态-作用值查找表 表的大小将为N×M其中N是所有可能状态的数量M是所有可能动作的数量。 对于大多数环境此表将很大。 表越大搜索所需的时间就越多并且存储表所需的内存也就越多因此这不是可行的解决方案。 在本秘籍中我们将使用 Q 学习的 NN 实现。 在此将神经网络用作函数逼近器来预测值函数Q。 NN 具有等于可能动作数的输出节点并且它们的输出表示相应动作的值函数。
准备
我们将训练一个线性神经网络来解决CartPole-v0环境。 目的是平衡手推车上的杆。 观测状态由四个连续值参数组成推车位置[-2.4, 2.4]推车速度[-∞, ∞]极角[~-41.8º, ~41.8º]和极限速度[-∞, ∞]。 可以通过向左或向右推推车来实现平衡因此动作空间由两个可能的动作组成。 您可以看到CartPole-v0环境空间 现在对于 Q 学习我们需要找到一种量化连续值观测状态的方法。 这是使用类FeatureTransform实现的 该类首先生成 20,000 个观察空间示例的随机样本。 随机生成的观察空间示例使用 scikit StandardScaler类进行了标准化。 然后以不同的方差使用 scikit 的RBFSampler来覆盖观察空间的不同部分。 FeatureTransformer类由随机观察空间示例实例化该示例用于使用fit_transform函数方法训练RBFSampler。
后来使用transform方法将连续观察空间转换为这种特征化表示
class FeatureTransformer:def __init__(self, env):obs_examples np.random.random((20000, 4))print(obs_examples.shape)scaler StandardScaler()scaler.fit(obs_examples)# Used to converte a state to a featurizes represenation.# We use RBF kernels with different variances to cover different parts of the spacefeaturizer FeatureUnion([(cart_position, RBFSampler(gamma0.02, n_components500)),(cart_velocity, RBFSampler(gamma1.0, n_components500)),(pole_angle, RBFSampler(gamma0.5, n_components500)),(pole_velocity, RBFSampler(gamma0.1, n_components500))])feature_examples featurizer.fit_transform(scaler.transform(obs_examples))print(feature_examples.shape)self.dimensions feature_examples.shape[1]self.scaler scalerself.featurizer featurizerdef transform(self, observations):scaled self.scaler.transform(observations)return self.featurizer.transform(scaled)操作步骤
我们按以下步骤进行
第一步是导入必要的模块。 这次除了我们通常的 TensorFlowNumpy 和 Matplotlib我们还将从 scikit 导入 Gym 和一些类
import numpy as np
import tensorflow as tf
import gym
import matplotlib.pyplot as plt
from sklearn.pipeline import FeatureUnion
from sklearn.preprocessing import StandardScaler
from sklearn.kernel_approximation import RBFSampler在 Q 学习中我们使用 NN 作为函数逼近器来估计值函数。 我们定义一个线性NeuralNetwork类 NN 将把变换后的观测空间作为输入并预测估计的Q值。 由于我们有两个可能的动作因此我们需要两个不同的神经网络对象来获取预测的状态动作值。 该类包括训练单个 NN 和预测输出的方法
class NeuralNetwork:def __init__(self, D):eta 0.1self.W tf.Variable(tf.random_normal(shape(D, 1)), namew)self.X tf.placeholder(tf.float32, shape(None, D), nameX)self.Y tf.placeholder(tf.float32, shape(None,), nameY)# make prediction and costY_hat tf.reshape(tf.matmul(self.X, self.W), [-1])err self.Y - Y_hatcost tf.reduce_sum(tf.pow(err,2))# ops we want to call laterself.train_op tf.train.GradientDescentOptimizer(eta).minimize(cost)self.predict_op Y_hat# start the session and initialize paramsinit tf.global_variables_initializer()self.session tf.Session()self.session.run(init)def train(self, X, Y):self.session.run(self.train_op, feed_dict{self.X: X, self.Y: Y})def predict(self, X):return self.session.run(self.predict_op, feed_dict{self.X: X})下一个重要的类是Agent类它使用NeuralNetwork类来创建学习智能体。 实例化类创建具有两个线性 NN 的智能体每个线性 NN 具有 2,000 个输入神经元和 1 个输出神经元。 从本质上讲这意味着该智能体具有 2 个神经元每个神经元具有 2,000 个输入因为 NN 的输入层不执行任何处理。 Agent类具有定义为预测两个 NN 的输出并更新两个 NN 权重的方法。 此处的智能体在训练阶段使用 Epsilon 贪婪策略进行探索。 在每个步骤中智能体程序会根据 epsiloneps的值选择具有最高Q值的操作或随机操作。 epsilon 在训练过程中经过退火处理因此最初智能体会采取许多随机动作探索但随着训练的进行会采取具有最大Q值的动作探索。 这称为探索与开发的权衡取舍我们允许智能体在被利用的操作过程中探索随机操作这使智能体可以尝试新的随机操作并从中学习
class Agent:def __init__(self, env, feature_transformer):self.env envself.agent []self.feature_transformer feature_transformerfor i in range(env.action_space.n):model NeuralNetwork(feature_transformer.dimensions)self.agent.append(model)def predict(self, s):X self.feature_transformer.transform([s])return np.array([m.predict(X)[0] for m in self.agent])def update(self, s, a, G):X self.feature_transformer.transform([s])self.agent[a].train(X, [G])def sample_action(self, s, eps):if np.random.random() eps:return self.env.action_space.sample()else:return np.argmax(self.predict(s))接下来我们定义一个函数来播放一集 它类似于我们先前使用的play_one函数但现在我们使用 Q 学习来更新智能体的权重。 我们首先使用env.reset()重置环境然后开始游戏直到完成游戏为止并进行了最大迭代以确保程序结束。 像以前一样智能体为当前观察状态选择一个动作并在环境上执行该动作env.step(action)。 现在的区别在于根据先前状态和采取操作后的状态使用G r γ · max[a]Q(s, a)更新 NN 权重以便它可以预测与某个动作相对应的准确期望值。 为了获得更好的稳定性我们修改了奖励-杆位下降时座席会获得 -400 的奖励否则每一步都会获得 1 的奖励
def play_one(env, model, eps, gamma):obs env.reset()done Falsetotalreward 0iters 0while not done and iters 2000:action model.sample_action(obs, eps)prev_obs obsobs, reward, done, info env.step(action)env.render() # Can comment it to speed up.if done:reward -400# update the modelnext model.predict(obs)assert(len(next.shape) 1)G reward gamma*np.max(next)model.update(prev_obs, action, G)if reward 1:totalreward reward
iters 1现在所有函数和类均已就绪我们定义了智能体和环境在本例中为CartPole-v0。 该智能体总共播放 1000 集并通过使用值函数与环境交互来学习
if __name__ __main__:env_name CartPole-v0env gym.make(env_name)ft FeatureTransformer(env)agent Agent(env, ft)gamma 0.97N 1000totalrewards np.empty(N)running_avg np.empty(N)for n in range(N):eps 1.0 / np.sqrt(n 1)totalreward play_one(env, agent, eps, gamma)totalrewards[n] totalrewardrunning_avg[n] totalrewards[max(0, n - 100):(n 1)].mean()if n % 100 0:print(episode: {0}, total reward: {1} eps: {2} avg reward (last 100): {3}.format(n, totalreward, eps,running_avg[n]), )print(avg reward for last 100 episodes:, totalrewards[-100:].mean())print(total steps:, totalrewards.sum())plt.plot(totalrewards)plt.xlabel(episodes)plt.ylabel(Total Rewards)plt.show()plt.plot(running_avg)plt.xlabel(episodes)plt.ylabel(Running Average)plt.show()env.close()以下是智能体通过游戏获悉的总奖励和移动平均奖励的图。 根据 Cart-Pole Wiki 的说法奖励 200 分表示该特工在接受 1,000 次训练后赢得了该剧集。 我们的特工播放 100 集时平均获得 195.7 的平均奖励这是一项了不起的壮举 更多
可以使用相同的逻辑为 OpenAI 的其他环境创建智能体。 但是对于诸如 Breakout 或 Pac-Man 之类的 Atari 游戏观察空间并不只是由四个数字组成的数组。 相反它非常大210×160 33,600 像素具有 3 个 RGB 值 如果没有某种形式的量化则这种简单的 NN 可能的状态是无限的并且不会产生良好的结果。 我们将在深度 Q 学习秘籍中使用 CNN 解决此问题。
另见
尽管有很多有关 Q 学习的 Web 链接但一些有用的链接如下
https://zh.wikipedia.org/wiki/Q-Learninghttp://mnemstudio.org/path-finding-q-learning-tutorial.htmhttp://artint.info/html/ArtInt_265.htmlhttps://medium.com/emergent-future/simple-reinforcement-learning-with-tensorflow-part-0-q-learning-with-tables-and-neural-networks-d195264329d0
深度 Q 网络和 Atari 游戏
深度 Q 网络DQN是 Q 学习与卷积神经网络CNN的结合。 由 Mnih 等人在 2013 年提出。 CNN 网络具有提取空间信息的能力因此能够从原始像素数据中学习成功的控制策略。 我们已经在第 4 章“卷积神经网络”中使用了 CNN因此我们直接从这里开始。
此秘籍基于 DeepMind 的原始 DQN 论文《使用深度强化学习玩 Atari》。 在本文中他们使用了一种称为“经验重放”的概念该概念涉及随机采样先前的游戏动作状态动作奖励下一状态。位于前脑底部的核称为“基底神经节” 根据神经科学它们负责选择动作即帮助我们确定在任何给定时间执行几种可能动作中的哪一种。
准备
如先前的秘籍所述“用 Q 学习平衡 CartPole”对于像《吃豆人》或 Breakout 之类的 Atari 游戏我们需要预处理观察状态空间该状态空间由 33,600 个像素组成具有 3 个 RGB 值。 这些像素中的每个像素都可以采用 0 到 255 之间的任何值。我们的preprocess函数应该能够量化像素的可能值同时减少观察状态空间。
我们利用 Scipy 的imresize函数对图像进行下采样。 以下函数preprocess在将图像馈送到 DQN 之前
def preprocess(img):img_temp img[31:195] # Choose the important area of the imageimg_temp img_temp.mean(axis2) # Convert to Grayscale## Downsample image using nearest neighbour interpolationimg_temp imresize(img_temp, size(IM_SIZE, IM_SIZE), interpnearest)return img_temp
IM_SIZE是一个全局参数-在代码中我们将其值为 80。该函数具有描述每个过程的注释。 在这里您可以看到预处理前后的观察空间 要注意的另一重要事项是当前的观察空间不能完全显示游戏情况。 例如参见上图您无法确定桨叶是向左还是向右移动。 因此为了完全理解游戏的当前状态我们需要考虑动作和观察的顺序。 在秘籍中我们考虑了四个动作和观察序列以确定当前情况并训练智能体。 这是借助state_update函数完成的该函数将当前的观察状态附加到先前的状态从而生成一系列状态
def update_state(state, obs):obs_small preprocess(obs)return np.append(state[1:], np.expand_dims(obs_small, 0), axis0)最后为了解决训练时的稳定性问题我们使用了target_network的概念它是 DQN 的副本但更新频率不高。 我们使用目标网络来生成 DQN 网络的目标值函数而 DQN 在每个步骤/片段都进行更新并且target_network在固定间隔后进行更新与 DQN 相同。 由于所有更新都在 TensorFlow 会话中进行因此我们使用名称范围来区分target_network和 DQN 网络。
操作步骤
我们导入必要的模块。 我们正在使用sys模块的stdout.flush()来帮助我们强制 Python 刷新标准输出在我们的情况下为计算机监视器中的数据。 random模块用于从经验重放缓冲区我们存储过去经验的缓冲区中获取随机样本。 datetime模块用于跟踪训练时间
import gym
import sys
import random
import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt
from datetime import datetime
from scipy.misc import imresize我们定义训练的超参数 您可以通过更改它们进行试验。 这些参数定义了经验重放缓冲区的最小和最大大小以及更新目标网络之后的情节数量
MAX_EXPERIENCES 500000
MIN_EXPERIENCES 50000
TARGET_UPDATE_PERIOD 10000
IM_SIZE 80
K 4定义了类DQN 其构造器使用tf.contrib.layers.conv2d函数构建 CNN 网络并定义成本和训练操作
class DQN:def __init__(self, K, scope, save_path models/atari.ckpt):self.K Kself.scope scopeself.save_path save_pathwith tf.variable_scope(scope):# inputs and targetsself.X tf.placeholder(tf.float32, shape(None, 4, IM_SIZE, IM_SIZE), nameX)# tensorflow convolution needs the order to be:# (num_samples, height, width, color)# so we need to tranpose laterself.G tf.placeholder(tf.float32, shape(None,), nameG)self.actions tf.placeholder(tf.int32, shape(None,), nameactions)# calculate output and cost# convolutional layersZ self.X / 255.0Z tf.transpose(Z, [0, 2, 3, 1])cnn1 tf.contrib.layers.conv2d(Z, 32, 8, 4, activation_fntf.nn.relu)cnn2 tf.contrib.layers.conv2d(cnn1, 64, 4, 2, activation_fntf.nn.relu)cnn3 tf.contrib.layers.conv2d(cnn2, 64, 3, 1, activation_fntf.nn.relu)# fully connected layersfc0 tf.contrib.layers.flatten(cnn3)fc1 tf.contrib.layers.fully_connected(fc0, 512)# final output layerself.predict_op tf.contrib.layers.fully_connected(fc1, K)selected_action_values tf.reduce_sum(self.predict_op * tf.one_hot(self.actions, K),reduction_indices[1])self.cost tf.reduce_mean(tf.square(self.G - selected_action_values))self.train_op tf.train.RMSPropOptimizer(0.00025, 0.99, 0.0, 1e-6).minimize(self.cost)该类具有设置会话set_session()预测动作值函数predict()更新网络update()以及使用 Epsilon 贪婪算法sample_action()选择动作的方法
def set_session(self, session):self.session sessiondef predict(self, states):return self.session.run(self.predict_op, feed_dict{self.X: states})def update(self, states, actions, targets):c, _ self.session.run([self.cost, self.train_op],feed_dict{self.X: states,self.G: targets,self.actions: actions})return cdef sample_action(self, x, eps):Implements epsilon greedy algorithmif np.random.random() eps:return np.random.choice(self.K)else:return np.argmax(self.predict([x])[0])我们还定义了加载和保存网络的方法因为训练可能会花费一些时间
def load(self):self.saver tf.train.Saver(tf.global_variables())load_was_success Truetry:save_dir /.join(self.save_path.split(/)[:-1])ckpt tf.train.get_checkpoint_state(save_dir)load_path ckpt.model_checkpoint_pathself.saver.restore(self.session, load_path)except:print(no saved model to load. starting new session)load_was_success Falseelse:print(loaded model: {}.format(load_path))saver tf.train.Saver(tf.global_variables())episode_number int(load_path.split(-)[-1])def save(self, n):self.saver.save(self.session, self.save_path, global_stepn)print(SAVED MODEL #{}.format(n))将主 DQN 网络的参数复制到目标网络的方法如下
def copy_from(self, other):mine [t for t in tf.trainable_variables() if t.name.startswith(self.scope)]mine sorted(mine, keylambda v: v.name)others [t for t in tf.trainable_variables() if t.name.startswith(other.scope)]others sorted(others, keylambda v: v.name)ops []for p, q in zip(mine, others):actual self.session.run(q)op p.assign(actual)ops.append(op)self.session.run(ops)我们定义一个函数learn()它预测值函数并更新原始 DQN 网络
def learn(model, target_model, experience_replay_buffer, gamma, batch_size):# Sample experiencessamples random.sample(experience_replay_buffer, batch_size)states, actions, rewards, next_states, dones map(np.array, zip(*samples))# Calculate targetsnext_Qs target_model.predict(next_states)next_Q np.amax(next_Qs, axis1)targets rewards np.invert(dones).astype(np.float32) * gamma * next_Q# Update modelloss model.update(states, actions, targets)return loss既然我们已经在主代码中定义了所有特征我们就可以使用它们来构建和训练 DQN 网络以玩 Atari 游戏。 该代码经过了很好的注释并且是对先前 Q 学习代码的扩展并增加了经验重放缓冲区因此您应该不难理解它
if __name__ __main__:# hyperparametersgamma 0.99batch_sz 32num_episodes 500total_t 0experience_replay_buffer []episode_rewards np.zeros(num_episodes)last_100_avgs []# epsilon for Epsilon Greedy Algorithmepsilon 1.0epsilon_min 0.1epsilon_change (epsilon - epsilon_min) / 500000# Create Atari Environmentenv gym.envs.make(Breakout-v0)# Create original and target Networksmodel DQN(KK, gammagamma, scopemodel)target_model DQN(KK, gammagamma, scopetarget_model)with tf.Session() as sess:model.set_session(sess)target_model.set_session(sess)sess.run(tf.global_variables_initializer())model.load()print(Filling experience replay buffer...)obs env.reset()obs_small preprocess(obs)state np.stack([obs_small] * 4, axis0)# Fill experience replay bufferfor i in range(MIN_EXPERIENCES):action np.random.randint(0,K)obs, reward, done, _ env.step(action)next_state update_state(state, obs)experience_replay_buffer.append((state, action, reward, next_state, done))if done:obs env.reset()obs_small preprocess(obs)state np.stack([obs_small] * 4, axis0)else:state next_state# Play a number of episodes and learnfor i in range(num_episodes):t0 datetime.now()# Reset the environmentobs env.reset()obs_small preprocess(obs)state np.stack([obs_small] * 4, axis0)assert (state.shape (4, 80, 80))loss Nonetotal_time_training 0num_steps_in_episode 0episode_reward 0done Falsewhile not done:# Update target networkif total_t % TARGET_UPDATE_PERIOD 0:target_model.copy_from(model)print(Copied model parameters to target network. total_t %s, period %s % (total_t, TARGET_UPDATE_PERIOD))# Take actionaction model.sample_action(state, epsilon)obs, reward, done, _ env.step(action)obs_small preprocess(obs)next_state np.append(state[1:], np.expand_dims(obs_small, 0), axis0)episode_reward reward# Remove oldest experience if replay buffer is fullif len(experience_replay_buffer) MAX_EXPERIENCES:experience_replay_buffer.pop(0)# Save the recent experienceexperience_replay_buffer.append((state, action, reward, next_state, done))# Train the model and keep measure of timet0_2 datetime.now()loss learn(model, target_model, experience_replay_buffer, gamma, batch_sz)dt datetime.now() - t0_2total_time_training dt.total_seconds()num_steps_in_episode 1state next_statetotal_t 1epsilon max(epsilon - epsilon_change, epsilon_min)duration datetime.now() - t0episode_rewards[i] episode_rewardtime_per_step total_time_training / num_steps_in_episodelast_100_avg episode_rewards[max(0, i - 100):i 1].mean()last_100_avgs.append(last_100_avg)print(Episode:, i,Duration:, duration, Num steps:, num_steps_in_episode,Reward:, episode_reward, Training time per step:, %.3f % time_per_step,Avg Reward (Last 100):, %.3f % last_100_avg,Epsilon:, %.3f % epsilon)if i % 50 0:model.save(i)sys.stdout.flush()#Plotsplt.plot(last_100_avgs)plt.xlabel(episodes)plt.ylabel(Average Rewards)plt.show()env.close()从上图中我们可以看到特工通过训练获得了更高的报酬并且通过每 100 集的平均报酬图可以清楚地看到情况 这只是在训练的前 500 集之后 为了获得更好的效果您将需要训练更长的时间约 10,000 集。
更多
训练智能体需要花费很多时间这既浪费时间又消耗内存。 OpenAI Gym 提供了一个包装器来将游戏另存为视频因此除了使用渲染之外您还可以使用包装器来保存视频并随后监视智能体的学习方式。 AI 工程师和发烧友可以上传这些视频以显示结果。 为此我们需要首先导入包装器然后创建环境最后使用监视器。 默认情况下它将存储 1、8、27、64 等视频然后每第 1000 集带有完美立方体的情节编号存储 默认情况下每项训练都保存在一个文件夹中。 为此要添加的代码如下
import gym
from gym import wrappers
env gym.make(Breakout-v0)
env wrappers.Monitor(env, /save-path)如果您想在下一个训练中使用相同的文件夹可以将forceTrue添加到监视器。
另见
Mnih, Volodymyr, and others, Playing Atari with deep reinforcement learning, arXiv preprint arXiv:1312.5602 (2013) (https://arxiv.org/pdf/1312.5602.pdf)Mnih, Volodymyr, et al. Human-level control through deep reinforcement learning, Nature 518.7540 (2015): 529-533玩 Atari 的 DQN 的一个很酷的实现
使用策略梯度玩 Pong 游戏
到目前为止策略梯度是最常用的 RL 算法之一。 研究表明经过适当调优后它们的表现要优于 DQN同时不会遭受过多的内存和计算缺点。 与 Q 学习不同策略梯度使用参数化策略该策略可以选择操作而不咨询值函数。 在策略梯度中我们讨论了表现度量η(θ[p]) 目标是最大程度地提高表现因此根据梯度上升算法更新 NN 的权重。 但是TensorFlow 没有maximum优化器因此我们使用表现梯度的负值-∇η(θ[p])并将其最小化。
准备
Pong 的游戏是一个两人游戏目标是将球弹回另一位玩家。 智能体可以上下移动操纵杆是的是标准NoOp。 OpenAI 环境中的一名玩家是一位体面的 AI 玩家他知道如何很好地玩游戏。 我们的目标是使用策略梯度来训练第二个智能体。 我们的经纪人精通所玩的每款游戏。 虽然代码已构建为只能运行 500 集但我们应该添加一条规定以将智能体状态保存在指定的检查点并且在下一次运行时首先加载上一个检查点。 为此我们首先声明一个保护程序然后使用 TensorFlow saver.save方法保存当前的网络状态检查点最后从最后保存的检查点加载网络。 为完成本秘籍的部分在“操作步骤”一节中定义的以下PolicyNetwork类方法可以执行此工作
def load(self):self.saver tf.train.Saver(tf.global_variables())load_was_success True # yes, Im being optimistictry:save_dir /.join(self.save_path.split(/)[:-1])ckpt tf.train.get_checkpoint_state(save_dir)load_path ckpt.model_checkpoint_pathself.saver.restore(self.session, load_path)except:print(no saved model to load. starting new session)load_was_success Falseelse:print(loaded model: {}.format(load_path))saver tf.train.Saver(tf.global_variables())episode_number int(load_path.split(-)[-1])为了每 50 集保存一次模型我们使用以下方法
def save(self):self.saver.save(self.session, self.save_path, global_stepn)print(SAVED MODEL #{}.format(n))操作步骤
此秘籍的代码基于 Andrej Karpathy 博客并且其中一部分已由 Sam Greydanus 的代码进行了改编。我们有通常的导入
import numpy as np
import gym
import matplotlib.pyplot as plt
import tensorflow as tf我们定义我们的PolicyNetwork类。 在类构建期间还将初始化模型超参数。 __init__方法定义输入状态self.tf_x的占位符 预测作用self.tf.y 相应的奖励self.tf_epr 网络权重 并预测行动值训练和更新。 您可以看到该类构造还启动了一个交互式 TensorFlow 会话
class PolicyNetwork(object):def __init__(self, N_SIZE, h200, gamma0.99, eta1e-3, decay0.99, save_path models2/pong.ckpt ):self.gamma gammaself.save_path save_path# Placeholders for passing state....self.tf_x tf.placeholder(dtypetf.float32, shape[None, N_SIZE * N_SIZE], nametf_x)self.tf_y tf.placeholder(dtypetf.float32, shape[None, n_actions], nametf_y)self.tf_epr tf.placeholder(dtypetf.float32, shape[None, 1], nametf_epr)# Weightsxavier_l1 tf.truncated_normal_initializer(mean0, stddev1\. / N_SIZE, dtypetf.float32)self.W1 tf.get_variable(W1, [N_SIZE * N_SIZE, h], initializerxavier_l1)xavier_l2 tf.truncated_normal_initializer(mean0, stddev1\. / np.sqrt(h), dtypetf.float32)self.W2 tf.get_variable(W2, [h, n_actions], initializerxavier_l2)# Build Computation# tf reward processing (need tf_discounted_epr for policy gradient wizardry)tf_discounted_epr self.tf_discount_rewards(self.tf_epr)tf_mean, tf_variance tf.nn.moments(tf_discounted_epr, [0], shiftNone, namereward_moments)tf_discounted_epr - tf_meantf_discounted_epr / tf.sqrt(tf_variance 1e-6)# Define Optimizer, compute and apply gradientsself.tf_aprob self.tf_policy_forward(self.tf_x)loss tf.nn.l2_loss(self.tf_y - self.tf_aprob)optimizer tf.train.RMSPropOptimizer(eta, decaydecay)tf_grads optimizer.compute_gradients(loss, var_listtf.trainable_variables(), grad_losstf_discounted_epr)self.train_op optimizer.apply_gradients(tf_grads)# Initialize Variablesinit tf.global_variables_initializer()self.session tf.InteractiveSession()self.session.run(init)self.load()我们定义了一种计算折现奖励的方法。 这确保智能体不仅考虑当前奖励而且考虑未来奖励。 任意时间t的折现奖励为R[t] ∑γ[k]r[t k]其中总和超过k∈[0, ∞]并且γ是贴现因子值在 0 到 1 之间。在我们的代码中我们使用了gamma 0.99
def tf_discount_rewards(self, tf_r): # tf_r ~ [game_steps,1]discount_f lambda a, v: a * self.gamma v;tf_r_reverse tf.scan(discount_f, tf.reverse(tf_r, [0]))tf_discounted_r tf.reverse(tf_r_reverse, [0])return tf_discounted_r在给定输入观察状态的情况下我们定义了tf_policy_forward方法来提供将桨向上移动的概率。 我们使用两层神经网络实现它。 网络获取处理过的游戏状态图像并生成一个数字表示将球拍向上移动的可能性。 在 TensorFlow 中由于仅在 TensorFlow 会话中计算网络图因此我们定义了另一种方法predict_UP来计算概率
def tf_policy_forward(self, x): #x ~ [1,D]h tf.matmul(x, self.W1)h tf.nn.relu(h)logp tf.matmul(h, self.W2)p tf.nn.softmax(logp)return pdef predict_UP(self,x):feed {self.tf_x: np.reshape(x, (1, -1))}aprob self.session.run(self.tf_aprob, feed);return aprobPolicyNetwork智能体使用update方法更新权重
def update(self, feed):return self.session.run(self.train_op, feed)我们定义一个辅助函数来预处理观察状态空间
# downsampling
def preprocess(I): prepro 210x160x3 uint8 frame into 6400 (80x80) 1D float vector I I[35:195] # cropI I[::2,::2,0] # downsample by factor of 2I[I 144] 0 # erase background (background type 1)I[I 109] 0 # erase background (background type 2)I[I ! 0] 1 # everything else (paddles, ball) just set to 1return I.astype(np.float).ravel()
其余的很简单-我们创建一个游戏环境定义要持有的数组状态动作奖励状态并使智能体学习大量情节休息或连续不断这完全取决于您的计算能力和资源。 这里要注意的重要一点是智能体没有按动作步骤学习。 相反智能体使用一个情节的完整状态动作奖励状态集来纠正其策略。 这可能会占用大量内存
if __name__ __main__:# Create Game Environmentenv_name Pong-v0env gym.make(env_name)env wrappers.Monitor(env, /tmp/pong, forceTrue)n_actions env.action_space.n # Number of possible actions# Initializing Game and State(t-1), action, reward, state(t)xs, rs, ys [], [], []obs env.reset()prev_x Nonerunning_reward Nonerunning_rewards []reward_sum 0n 0done Falsen_size 80num_episodes 500#Create Agentagent PolicyNetwork(n_size)# training loopwhile not done and n num_episodes:# Preprocess the observationcur_x preprocess(obs)x cur_x - prev_x if prev_x is not None else np.zeros(n_size*n_size)prev_x cur_x#Predict the actionaprob agent.predict_UP(x) ; aprob aprob[0,:]action np.random.choice(n_actions, paprob)#print(action)label np.zeros_like(aprob) ; label[action] 1# Step the environment and get new measurementsobs, reward, done, info env.step(action)env.render()reward_sum reward# record game historyxs.append(x) ; ys.append(label) ; rs.append(reward)if done:# update running rewardrunning_reward reward_sum if running_reward is None else running_reward * 0.99 reward_sum * 0.01running_rewards.append(running_reward)feed {agent.tf_x: np.vstack(xs), agent.tf_epr: np.vstack(rs), agent.tf_y: np.vstack(ys)}agent.update(feed)# print progress consoleif n % 10 0:print (ep {}: reward: {}, mean reward: {:3f}.format(n, reward_sum, running_reward))else:print (\tep {}: reward: {}.format(n, reward_sum))# Start next episode and save modelxs, rs, ys [], [], []obs env.reset()n 1 # the Next Episodereward_sum 0if n % 50 0:agent.save()done Falseplt.plot(running_rewards)plt.xlabel(episodes)plt.ylabel(Running Averge)plt.show()env.close()下图显示了智能体在前 500 个情节中学习时的平均运行奖励 工作原理
权重使用 Xavier 初始化进行了初始化这确保了我们的权重既不会太大也不会太小。 两种情况都阻碍了网络的学习。 在 Xavier 初始化中为权重分配一个具有零均值和特定方差2/(ninnout)的值其中nin和nout该层的输入和输出数。 要了解有关 Xavier 初始化的更多信息请参阅 Glorot 和 Bengio 在 2009 年发表的论文。 有关详细信息请参见“另见”部分。
更多
看到智能体第一次学习演奏的任何人都会对此感到惊讶-看起来很像人。 最初的举动总是很笨拙。 缓慢地坐席会学习走哪条路尽管速度很慢并且经常会错过球。 但是随着学习的继续智能体将成为专家。
但这与我们很不一样。 一旦学会玩游戏我们便可以在其他任何类似情况下轻松使用该知识。 RL 智能体将无法执行此操作-即使是简单的事情例如更改环境空间的大小也会将其恢复为零。 迁移学习是研究人员正在研究的一种技术它可以帮助主体在另一环境空间中的一个环境中使用它所学到的知识也许有一天可以为真正的人工智能奠定基础。
AlphaGo Zero
最近DeepMind 发表了有关 AlphaGo ZeroAlphaGo 的最新版本的文章。 根据他们发布的结果AlphaGo Zero 甚至更强大并且是历史上最强大的围棋选手。 AlphaGo 从表格状态开始即从空白状态开始并且仅使用棋盘状态和与其对抗的游戏来调整神经网络并预测正确的动作。
AlphaGo Zero 使用深层神经网络该网络将原始板表示形式当前和历史作为输入并输出移动概率和值。 因此该神经网络结合了策略网络和值网络的作用。 该网络是通过自玩游戏进行训练的这与以前的 AlphaGo 版本不同它们是使用监督学习进行训练的。 在每个位置上由神经网络指导执行蒙特卡洛树搜索MCTS。 通过使用 MCTS 播放每个动作的自演强化学习算法来训练神经网络。
最初神经网络的权重是随机初始化的。 在每个迭代步骤中都会生成许多自玩游戏。 在每个时间步使用神经网络的先前迭代对可能的策略执行 MCTS 搜索然后通过对搜索概率进行采样来进行移动。 重复此过程直到该特定游戏终止。 存储游戏状态采取的策略以及游戏每个时间步骤的奖励。 并行地根据自播放的先前迭代的所有时间步长之间均匀采样的数据训练神经网络。 调整神经网络的权重以最小化预测值和自赢者之间的误差并使神经网络移动概率与搜索概率的相似性最大化。
在配备 4 个 TPU 的单台机器上仅进行了 3 天的训练AlphaGo Zero 以 100-0 击败 AlphaGo。 AlphaGo Zero 完全基于 RL。 可以在 2017 年 10 月发表于《自然》上的论文《掌握无人掌握的围棋游戏》中阅读其实现的详细信息。
另见
https://arxiv.org/pdf/1602.01783.pdfhttp://ufal.mff.cuni.cz/~straka/courses/npfl114/2016/sutton-bookdraft2016sep.pdfhttp://karpathy.github.io/2016/05/31/rl/Xavier Glorot and Yoshua Bengio, Understanding the difficulty of training deep feedforward neural networks, Proceedings of the Thirteenth International Conference on Artificial Intelligence and Statistics, 2010, http://proceedings.mlr.press/v9/glorot10a/glorot10a.pdf
十、移动计算
在本章中我们将讨论在移动设备上使用深度学习的问题并为以下内容提供一些方法
安装适用于 macOS 和 Android 的 TensorFlow Mobile玩转 TensorFlow 和 Android 示例为 MacOS 和 iPhone 安装 TensorFlow Mobile为移动设备优化 TensorFlow 图转换移动设备的 TensorFlow 图
介绍
在本节中我们将介绍移动深度学习的一些用例。 这与台式机或云深度学习的情况大不相同在台式机或云深度学习中GPU 和电力通常可用。 实际上在移动设备上保存电池非常重要并且 GPU 经常不可用。 但是深度学习在许多情况下可能非常有用。 让我们回顾一下 图像识别现代手机具有功能强大的摄像头用户热衷于尝试对图像和图片产生效果。 通常了解图片中的内容也很重要并且有多种适用于此的预训练模型如专用于 CNN 的章节所述。 这里给出了用于图像识别的模型的一个很好的例子。 对象定位识别运动对象是一项关键操作对于视频和图像处理是必需的。 例如可以想象如果在图像中识别出多个人那么相机将使用多个对焦点。 这里提供了对象本地化示例的集合。 光学字符识别在许多活动例如文本分类和推荐中识别手写字符都是至关重要的。 深度学习可以为开展这些活动提供根本帮助。 在专用于 CNN 的章节中我们研究了 MNIST 识别的一些示例。 关于 MNIST 的信息也可以在这个页面中找到。 语音识别语音识别是访问现代电话的常用界面。 因此深度学习用于识别语音和口头命令。 在过去的几年中这方面的进展令人印象深刻。 翻译处理多种语言是现代多元文化世界的一部分。 手机在各种语言之间进行即时翻译的准确率越来越高深度学习帮助打破了障碍而这在几年前是无法想象的。 在专门针对 RNN 的一章中我们研究了一些机器翻译示例。 手势识别电话开始使用手势作为接收命令的界面。 当然有一些模型。 压缩压缩是手机的关键方面。 可以想象在通过网络发送图像或视频之前减少空间是有益的。 同样在本地存储在设备上之前压缩数据可能会很方便。 在所有这些情况下深度学习都可以提供帮助。 使用 RNNS 进行压缩的模型位于这里。
TensorFlow移动和云
如上所述电话通常没有 GPU因此节省电池电量非常重要。 为了减轻成本需要将许多昂贵的计算卸载到云中。 当然要折衷考虑各种因素包括在移动设备上执行深度学习模型的成本将数据移至云的成本用于此传输的电池成本以及云计算的成本。 没有单一的解决方案最佳策略取决于您的具体情况。
安装适用于 macOS 和 Android 的 TensorFlow Mobile
在本秘籍中我们将学习如何为移动环境设置 TensorFlow。 我的环境是 macOS我为 Android 开发。 但是在以下秘籍中将描述其他配置。
准备
我们将使用 Android Studio这是适用于 Google Android 操作系统的官方集成开发环境IDE。
操作步骤
我们继续按以下步骤安装适用于 macOS 和 Android 的 TensorFlow mobile 从这里安装 Android Studio。 创建一个新的项目名称AndroidExampleTensorflow如以下屏幕截图所示 在 AndroidStudio 中创建 TensorFlow 移动应用的示例第一步如下图所示选择电话和表格选项 在 AndroidStudio 中创建 TensorFlow 移动应用的示例第二步并选择一个空活动如下图所示 在 AndroidStudio 中创建 TensorFlow 移动应用的示例第三步然后自定义MainActivity如下图所示 在 AndroidStudio 中创建 TensorFlow 移动应用的示例第四步称为“基础神经节”根据神经科学它负责选择动作即帮助我们确定在任何给定时间执行几个可能动作中的哪个。
将以下行插入build.gradle应用中如以下代码所示
// added for automatically connect to TensorFlow via maven
repositories {
jcenter()
maven {
url https://google.bintray.com/TensorFlow
}
}
dependencies {
compile fileTree(dir: libs, include: [*.jar])
androidTestCompile(com.android.support.test.espresso:espresso-core:2.2.2, {
exclude group: com.android.support, module: support-annotations
})
compile com.android.support:appcompat-v7:26.
compile com.android.support.constraint:constraint-layout:1.0.2
// added for automatically compile TensorFlow
compile org.TensorFlow:TensorFlow-android:
testCompile junit:junit:4.12
}以下屏幕截图显示了插入的代码 运行项目并获得结果 使用 AndroidStudio 进行编译的示例其中显示了连接的设备。 在 AndroidStudio 中创建 TensorFlow 移动应用的示例。 一个简单的Hello World应用
工作原理
使用 Android Studio 设置 Android TensorFlow 非常简单。 您只需要在应用的build.gradle文件中添加一些配置行Android Studio 就会代表您执行所有操作。
更多
如果要直接从 TensorFlow 源构建则需要安装 Bazel 和 TensorFlow。 Bazel 是一个快速可扩展多语言和可扩展的构建系统。 Google 内部使用了构建工具 Blaze并将 Blaze 工具的开源部分称为 Bazel。 名称是 Blaze 的字谜。
此页面将指导您完成该过程。
如果您正在运行 macOS则过程非常简单
按照这个页面上的说明安装 Bazel。 对于 macOS我们将使用 Homebrew
/usr/bin/ruby -e $(curl -fsSL \https://raw.githubusercontent.com/Homebrew/install/master/install)
brew install bazel
bazel version
brew upgrade bazel从 GitHub 克隆 TensorFlow 发行版。
git clone https://github.com/TensorFlow/TensorFlow.git玩转 TensorFlow 和 Android 示例
在本秘籍中我们将考虑 TensorFlow 发行版中提供的标准 Android 示例并将其安装在我们的移动设备上。
准备
TensorFlow 移动 Android 应用可在 GitHub 上的以下地址获得。 2017 年 10 月该页面包含以下示例
TF 分类使用 Google Inception 模型实时对相机帧进行分类并在相机图像上以重叠显示顶部结果。TF 检测演示使用 TensorFlow 对象检测 API 训练的 SSD-Mobilenet 模型。 这是在现代卷积目标检测器的速度/精度折衷中引入的以实时定位和跟踪摄像机预览中的目标来自 80 个类别。TF 风格化使用基于艺术风格的学习表示的模型将相机预览图像重新设置为许多不同艺术风格的图像。TF 语音运行在音频训练教程中构建的简单语音识别模型。 监听一小部分单词并在识别它们时在 UI 中突出显示它们。
操作步骤
我们按以下步骤进行
安装包的最佳方法是使用每晚创建的预构建 APK。 将浏览器指向这里并下载TensorFlow_demo.apk如以下屏幕截图所示 在您的设备上安装应用。 在我的示例中我将使用 Android Studio 中可用的 Pixel XL 仿真设备。 这是直接从 Android Studio 内部模拟的终端设备。 命令adb devices列出所有连接的设备。 在这种情况下我有一个 Pixel XL 模拟器可以安装TensorFlow_demo apk。
adb devices
List of devices attached
emulator-5554 device
adb install -r TensorFlow_demo.apk安装后仿真器将具有一组新的 TensorFlow 应用可供使用如下图所示。 运行您喜欢的应用。 例如以下图像是 TF Stylize 的示例用于通过 Transfer Learning 将相机预览图像重新设置为多种不同艺术风格的图像 下图是 TF 语音的示例请记住为仿真器激活麦克风 工作原理
如果您使用夜间构建演示和adb工具在设备上安装 APK则安装 Android 的 TensorFlow 示例非常容易。
为 MacOS 和 iPhone 安装 TensorFlow Mobile
在本秘籍中我们将学习如何在移动环境中设置 TensorFlow。 我的环境是 macOS这里的想法是为 iOS 和 iPhone 开发。
准备
我们将使用 Xcode 开发环境和 CocoaPods 来预安装 TensorFlow。 我将假定您的环境中已经安装了 Xcode。 如果没有请从这里下载。
操作步骤
我们将按照以下步骤进行操作
使用以下命令安装 CocoaPods
sudo gem install cocoapods
pod setup
Setting up CocoaPods master repo
$ /usr/local/git/current/bin/git clone https://github.com/CocoaPods/Specs.git master --progress
Cloning into master...
remote: Counting objects: 1602077, done.
remote: Compressing objects: 100% (243/243), done.
remote: Total 1602077 (delta 125), reused 172 (delta 74), pack-reused 1601747
Receiving objects: 100% (1602077/1602077), 432.12 MiB | 1.83 MiB/s, done.
Resolving deltas: 100% (849517/849517), done.
Checking out files: 100% (188907/188907), done.使用 CocoaPods 安装 TensorFlow 发行版
cd TensorFlow/TensorFlow/examples/ios/benchmark
pod install
Analyzing dependencies
Downloading dependencies
Installing TensorFlow-experimental (1.1.1)
Generating Pods project
Integrating client project
[!] Please close any current Xcode sessions and use tf_benchmark_example.xcworkspace for this project from now on.
Sending stats
Pod installation complete! There is 1 dependency from the Podfile and 1 total pod installed.从 Inception v1 下载一些样本数据。 将标签和图文件提取到simple和camera文件夹内的数据文件夹中
mkdir -p ~/graphscurl -o ~/graphs/inception5h.zip \https://storage.googleapis.com/download.TensorFlow.org/models/inception5h.zip \ unzip ~/graphs/inception5h.zip -d ~/graphs/inception5hcp ~/graphs/inception5h/* TensorFlow/examples/ios/benchmark/data/cp ~/graphs/inception5h/* TensorFlow/examples/ios/camera/data/cp ~/graphs/inception5h/* TensorFlow/examples/ios/simple/data/从中下载用作测试的图像并将其复制到基准目录
https://upload.wikimedia.org/wikipedia/commons/5/55/Grace_Hopper.jpg
cp grace_hopper.jpg ../../benchmark/data/Grace Hopper 的图片
打开以前使用的示例项目。 以下命令将打开已经可用的 TensorFlow 的 Xcode 之后运行编译如以下代码和图像所示
open tf_benchmark_example.xcworkspace在 iPhone 模拟器中查看结果。 根据 Inception v1 类别将步骤 4 中使用的图像识别为军服的图像 用于 Tensorflow 计算的 Iphone 应用示例
工作原理
Xcode 和 CocoaPods 用于编译 TensorFlow 应用该应用用于对不同 Inception 类别中的图像进行分类。 结果使用 iPhone 模拟器可视化。
更多
您可以直接在应用中使用 TensorFlow。 可在此处获得更多信息。
为移动设备优化 TensorFlow 图
在本秘籍中我们将考虑不同的选项来优化在移动设备上运行的 TensorFlow 代码。 从减小模型的大小到量化分析了不同的选项。
准备
我们将使用 Bazel 构建 TensorFlow 的不同组件。 因此第一步是确保同时安装了 Bazel 和 TensorFlow。
操作步骤
我们按以下步骤进行优化 从这里安装 Android Studio。 按照这个页面上的说明安装 Bazel。 对于 macOS我们将使用 Homebrew
/usr/bin/ruby -e $(curl -fsSL \https://raw.githubusercontent.com/Homebrew/install/master/install)
brew install bazel
bazel version
brew upgrade bazel从 GitHub 克隆 TensorFlow 发行版
git clone https://github.com/TensorFlow/TensorFlow.git构建一个图转换器汇总一下图本身
cd ~/TensorFlow/
bazel build TensorFlow/tools/graph_transforms:summarize_graph
[2,326 / 2,531] Compiling TensorFlow/core/kernels/cwise_op_greater.cc
INFO: From Linking TensorFlow/tools/graph_transforms/summarize_graph:
clang: warning: argument unused during compilation: -pthread [-Wunused-command-line-argument]
Target //TensorFlow/tools/graph_transforms:summarize_graph up-to-date:
bazel-bin/TensorFlow/tools/graph_transforms/summarize_graph
INFO: Elapsed time: 1521.260s, Critical Path: 103.87s下载 TensorFlow 图以用作示例。 在这种情况下我们将使用 Inception v1 TensorFlow 图
mkdir -p ~/graphscurl -o ~/graphs/inception5h.zip \https://storage.googleapis.com/download.TensorFlow.org/models/inception5h.zip \ unzip ~/graphs/inception5h.zip -d ~/graphs/inception5h汇总 Inception 图并注意常参数的数量1,346 万。 它们每个都存储有 32 位浮点数这非常昂贵
bazel-bin/TensorFlow/tools/graph_transforms/summarize_graph --in_graph/Users/gulli/graphs/TensorFlow_inception_graph.pb
Found 1 possible inputs: (nameinput, typefloat(1), shape[])
No variables spotted.
Found 3 possible outputs: (nameoutput, opIdentity) (nameoutput1, opIdentity) (nameoutput2, opIdentity)
Found 13462015 (13.46M) const parameters, 0 (0) variable parameters, and 0 control_edges
370 nodes assigned to device /cpu:0Op types used: 142 Const, 64 BiasAdd, 61 Relu, 59 Conv2D, 13 MaxPool, 9 Concat, 5 Reshape, 5 MatMul, 3 Softmax, 3 Identity, 3 AvgPool, 2 LRN, 1 Placeholder
To use with TensorFlow/tools/benchmark:benchmark_model try these arguments:
bazel run TensorFlow/tools/benchmark:benchmark_model -- --graph/Users/gulli/graphs/TensorFlow_inception_graph.pb --show_flops --input_layerinput --input_layer_typefloat --input_layer_shape --output_layeroutput,output1,output2编译该工具以将常量操作截断至 8 位
bazel build TensorFlow/tools/graph_transforms:transform_graph
INFO: From Linking TensorFlow/tools/graph_transforms/transform_graph:
clang: warning: argument unused during compilation: -pthread [-Wunused-command-line-argument]
Target //TensorFlow/tools/graph_transforms:transform_graph up-to-date:
bazel-bin/TensorFlow/tools/graph_transforms/transform_graph
INFO: Elapsed time: 294.421s, Critical Path: 28.83s运行该工具以量化 Inception V1 图
bazel-bin/TensorFlow/tools/graph_transforms/transform_graph --in_graph/Users/gulli/graphs/inception5h/TensorFlow_inception_graph.pb --out_graph/tmp/TensorFlow_inception_quantized.pb --inputsMul:0 --outputssoftmax:0 --transformsquantize_weights
2017-10-15 18:56:01.192498: I TensorFlow/tools/graph_transforms/transform_graph.cc:264] Applying quantize_weights比较两个模型
ls -lah /Users/gulli/graphs/inception5h/TensorFlow_inception_graph.pb
-rw-r----- 1 gulli 5001 51M Nov 19 2015 /Users/gulli/graphs/inception5h/TensorFlow_inception_graph.pb
ls -lah /tmp/TensorFlow_inception_quantized.pb
-rw-r--r-- 1 gulli wheel 13M Oct 15 18:56 /tmp/TensorFlow_inception_quantized.pb工作原理
量化通过将常量操作从 32 位缩减为 8 位来帮助减小模型的大小。 通常该模型不会遭受表现的显着降低。 但是这必须根据具体情况进行验证。
为移动设备分析 TensorFlow 图
在本秘籍中我们将考虑不同的选项来优化 TensorFlow 代码以在移动设备上运行。 从减小模型的大小到量化分析了不同的选项。
准备
我们将使用 Bazel 构建 TensorFlow 的不同组件。 因此第一步是确保同时安装了 Bazel 和 TensorFlow。
操作步骤
我们进行如下分析 从这里安装 Android Studio。 按照这个页面上的说明安装 Bazel。 对于 macOS我们将使用 Homebrew
/usr/bin/ruby -e $(curl -fsSL \https://raw.githubusercontent.com/Homebrew/install/master/install)
brew install bazel
bazel version
brew upgrade bazel从 GitHub 克隆 TensorFlow 发行版
git clone https://github.com/TensorFlow/TensorFlow.git构建图变压器该图变压器对图本身进行配置
cd ~/TensorFlow/
bazel build -c opt TensorFlow/tools/benchmark:benchmark_model
INFO: Found 1 target...
Target //TensorFlow/tools/benchmark:benchmark_model up-to-date:
bazel-bin/TensorFlow/tools/benchmark/benchmark_model
INFO: Elapsed time: 0.493s, Critical Path: 0.01s通过在桌面上运行以下命令来对模型进行基准测试
bazel-bin/TensorFlow/tools/benchmark/benchmark_model --graph/Users/gulli/graphs/TensorFlow_inception_graph.pb --show_run_orderfalse --show_timefalse --show_memoryfalse --show_summarytrue --show_flopstrue
Graph: [/Users/gulli/graphs/TensorFlow_inception_graph.pb]
Input layers: [input:0]
Input shapes: [1,224,224,3]
Input types: [float]
Output layers: [output:0]
Num runs: [1000]
Inter-inference delay (seconds): [-1.0]
Inter-benchmark delay (seconds): [-1.0]
Num threads: [-1]
Benchmark name: []
Output prefix: []
Show sizes: [0]
Warmup runs: [2]
Loading TensorFlow.
Got config, 0 devices
Running benchmark for max 2 iterations, max -1 seconds without detailed stat logging, with -1s sleep between inferences
count2 first279182 curr41827 min41827 max279182 avg160504 std118677
Running benchmark for max 1000 iterations, max 10 seconds without detailed stat logging, with -1s sleep between inferences
count259 first39945 curr44189 min36539 max51743 avg38651.1 std1886
Running benchmark for max 1000 iterations, max 10 seconds with detailed stat logging, with -1s sleep between inferences
count241 first40794 curr39178 min37634 max153345 avg41644.8 std8092
Average inference timings in us: Warmup: 160504, no stats: 38651, with stats: 41644通过在运行 64 位 ARM 处理器的目标 android 设备上运行以下命令来对模型进行基准测试。 请注意以下命令将初始图推送到设备上并运行可在其中执行基准测试的外壳程序
bazel build -c opt --configandroid_arm64 \ TensorFlow/tools/benchmark:benchmark_model
adb push bazel-bin/TensorFlow/tools/benchmark/benchmark_model \ /data/local/tmp
adb push /tmp/TensorFlow_inception_graph.pb /data/local/tmp/
adb push ~gulli/graphs/inception5h/TensorFlow_inception_graph.pb /data/local/tmp/
/Users/gulli/graphs/inception5h/TensorFlow_inception_graph.pb: 1 file pushed. 83.2 MB/s (53884595 bytes in 0.618s)
adb shell
generic_x86:/ $
/data/local/tmp/benchmark_model --graph/data/local/tmp/TensorFlow_inception_graph.pb --show_run_orderfalse --show_timefalse --show_memoryfalse --show_summarytrue工作原理
正如预期的那样该模型在 Conv2D 操作上花费了大量时间。 总体而言这大约占我台式机平均时间的 77.5%。 如果在移动设备上运行此程序那么花时间执行神经网络中的每一层并确保它们处于受控状态至关重要。 要考虑的另一个方面是内存占用。 在这种情况下桌面执行约为 10 Mb。
转换移动设备的 TensorFlow 图
在本秘籍中我们将学习如何转换 TensorFlow 图以便删除所有仅训练节点。 这将减小图的大小使其更适合于移动设备。
What is a graph transform tool? According to https://github.com/tensorflow/tensorflow/blob/master/tensorflow/tools/graph_transforms/README.md “When you have finished training a model and want to deploy it in production, you’ll often want to modify it to better run in its final environment. For example if you’re targeting a phone you might want to shrink the file size by quantizing the weights, or optimize away batch normalization or other training-only features. The Graph Transform framework offers a suite of tools for modifying computational graphs, and a framework to make it easy to write your own modifications”.
准备
我们将使用 Bazel 构建 TensorFlow 的不同组件。 因此第一步是确保同时安装了 Bazel 和 TensorFlow。
操作步骤
这是我们如何转换 TensorFlow 的方法 从这里安装 Android Studio。 按照这个页面上的说明安装 Bazel。 对于 macOS我们将使用 Homebrew
/usr/bin/ruby -e $(curl -fsSL \https://raw.githubusercontent.com/Homebrew/install/master/install)
brew install bazel
bazel version
brew upgrade bazel从 GitHub 克隆 TensorFlow 发行版
git clone https://github.com/TensorFlow/TensorFlow.git构建一个图转换器它汇总了图本身
bazel run TensorFlow/tools/graph_transforms:summarize_graph -- --in_graph/Users/gulli/graphs/inception5h/TensorFlow_inception_graph.pb
WARNING: /Users/gulli/TensorFlow/TensorFlow/core/BUILD:1783:1: in includes attribute of cc_library rule //TensorFlow/core:framework_headers_lib: ../../external/nsync/public resolves to external/nsync/public not below the relative path of its package TensorFlow/core. This will be an error in the future. Since this rule was created by the macro cc_header_only_library, the error might have been caused by the macro implementation in /Users/gulli/TensorFlow/TensorFlow/TensorFlow.bzl:1054:30.
INFO: Found 1 target...
Target //TensorFlow/tools/graph_transforms:summarize_graph up-to-date:
bazel-bin/TensorFlow/tools/graph_transforms/summarize_graph
INFO: Elapsed time: 0.395s, Critical Path: 0.01s
INFO: Running command line: bazel-bin/TensorFlow/tools/graph_transforms/summarize_graph --in_graph/Users/gulli/graphs/inception5h/TensorFlow_inception_graph.pb
Found 1 possible inputs: (nameinput, typefloat(1), shape[])
No variables spotted.
Found 3 possible outputs: (nameoutput, opIdentity) (nameoutput1, opIdentity) (nameoutput2, opIdentity)
Found 13462015 (13.46M) const parameters, 0 (0) variable parameters, and 0 control_edges
370 nodes assigned to device /cpu:0Op types used: 142 Const, 64 BiasAdd, 61 Relu, 59 Conv2D, 13 MaxPool, 9 Concat, 5 Reshape, 5 MatMul, 3 Softmax, 3 Identity, 3 AvgPool, 2 LRN, 1 Placeholder
To use with TensorFlow/tools/benchmark:benchmark_model try these arguments:
bazel run TensorFlow/tools/benchmark:benchmark_model -- --graph/Users/gulli/graphs/inception5h/TensorFlow_inception_graph.pb --show_flops --input_layerinput --input_layer_typefloat --input_layer_shape --output_layeroutput,output1,output2剥去用于训练的所有节点当在移动设备上使用图进行推理时不需要这些节点
bazel run TensorFlow/tools/graph_transforms:transform_graph -- --in_graph/Users/gulli/graphs/inception5h/TensorFlow_inception_graph.pb --out_graph/tmp/optimized_inception_graph.pb --transformsstrip_unused_nodes fold_constants(ignore_errorstrue) fold_batch_norms fold_old_batch_norms
WARNING: /Users/gulli/TensorFlow/TensorFlow/core/BUILD:1783:1: in includes attribute of cc_library rule //TensorFlow/core:framework_headers_lib: ../../external/nsync/public resolves to external/nsync/public not below the relative path of its package TensorFlow/core. This will be an error in the future. Since this rule was created by the macro cc_header_only_library, the error might have been caused by the macro implementation in /Users/gulli/TensorFlow/TensorFlow/TensorFlow.bzl:1054:30.
INFO: Found 1 target...
Target //TensorFlow/tools/graph_transforms:transform_graph up-to-date:
bazel-bin/TensorFlow/tools/graph_transforms/transform_graph
INFO: Elapsed time: 0.578s, Critical Path: 0.01s
INFO: Running command line: bazel-bin/TensorFlow/tools/graph_transforms/transform_graph --in_graph/Users/gulli/graphs/inception5h/TensorFlow_inception_graph.pb --out_graph/tmp/optimized_inception_graph.pb --transformsstrip_unused_nodes fold_constants(ignore_errorstrue) fold_batch_norms fold_old_batch_norms
2017-10-15 22:26:59.357129: I TensorFlow/tools/graph_transforms/transform_graph.cc:264] Applying strip_unused_nodes
2017-10-15 22:26:59.367997: I TensorFlow/tools/graph_transforms/transform_graph.cc:264] Applying fold_constants
2017-10-15 22:26:59.387800: I TensorFlow/core/platform/cpu_feature_guard.cc:137] Your CPU supports instructions that this TensorFlow binary was not compiled to use: SSE4.2 AVX AVX2 FMA
2017-10-15 22:26:59.388676: E TensorFlow/tools/graph_transforms/transform_graph.cc:279] fold_constants: Ignoring error Must specify at least one target to fetch or execute.
2017-10-15 22:26:59.388695: I TensorFlow/tools/graph_transforms/transform_graph.cc:264] Applying fold_batch_norms
2017-10-15 22:26:59.388721: I TensorFlow/tools/graph_transforms/transform_graph.cc:264] Applying fold_old_batch_norms工作原理
为了创建可以在设备上加载的更轻的模型我们使用了图变换工具应用的strip_unused_nodes规则删除了所有不需要的节点。 该操作将删除用于学习的所有操作并保留用于推理的操作。 文章转载自: http://www.morning.flxqm.cn.gov.cn.flxqm.cn http://www.morning.cjqqj.cn.gov.cn.cjqqj.cn http://www.morning.qwbls.cn.gov.cn.qwbls.cn http://www.morning.kkysz.cn.gov.cn.kkysz.cn http://www.morning.rhjhy.cn.gov.cn.rhjhy.cn http://www.morning.srmpc.cn.gov.cn.srmpc.cn http://www.morning.nkjnr.cn.gov.cn.nkjnr.cn http://www.morning.dktyc.cn.gov.cn.dktyc.cn http://www.morning.qbwtb.cn.gov.cn.qbwtb.cn http://www.morning.qwzpd.cn.gov.cn.qwzpd.cn http://www.morning.phxdc.cn.gov.cn.phxdc.cn http://www.morning.xmttd.cn.gov.cn.xmttd.cn http://www.morning.wsyq.cn.gov.cn.wsyq.cn http://www.morning.dhqyh.cn.gov.cn.dhqyh.cn http://www.morning.dfdhx.cn.gov.cn.dfdhx.cn http://www.morning.trrpb.cn.gov.cn.trrpb.cn http://www.morning.buyid.com.cn.gov.cn.buyid.com.cn http://www.morning.bdzps.cn.gov.cn.bdzps.cn http://www.morning.ydrfl.cn.gov.cn.ydrfl.cn http://www.morning.xlndf.cn.gov.cn.xlndf.cn http://www.morning.gjmbk.cn.gov.cn.gjmbk.cn http://www.morning.jzsgn.cn.gov.cn.jzsgn.cn http://www.morning.cnyqj.cn.gov.cn.cnyqj.cn http://www.morning.gbfck.cn.gov.cn.gbfck.cn http://www.morning.leboju.com.gov.cn.leboju.com http://www.morning.rwqj.cn.gov.cn.rwqj.cn http://www.morning.litao4.cn.gov.cn.litao4.cn http://www.morning.kcfnp.cn.gov.cn.kcfnp.cn http://www.morning.ljbm.cn.gov.cn.ljbm.cn http://www.morning.pqppj.cn.gov.cn.pqppj.cn http://www.morning.kqzxk.cn.gov.cn.kqzxk.cn http://www.morning.nytpt.cn.gov.cn.nytpt.cn http://www.morning.srndk.cn.gov.cn.srndk.cn http://www.morning.jfbbq.cn.gov.cn.jfbbq.cn http://www.morning.ftzll.cn.gov.cn.ftzll.cn http://www.morning.psyrz.cn.gov.cn.psyrz.cn http://www.morning.vuref.cn.gov.cn.vuref.cn http://www.morning.yqgbw.cn.gov.cn.yqgbw.cn http://www.morning.ylzdx.cn.gov.cn.ylzdx.cn http://www.morning.gidmag.com.gov.cn.gidmag.com http://www.morning.xbmwh.cn.gov.cn.xbmwh.cn http://www.morning.jcfdk.cn.gov.cn.jcfdk.cn http://www.morning.qfnrx.cn.gov.cn.qfnrx.cn http://www.morning.wpmlp.cn.gov.cn.wpmlp.cn http://www.morning.ybqlb.cn.gov.cn.ybqlb.cn http://www.morning.brbmf.cn.gov.cn.brbmf.cn http://www.morning.pljxz.cn.gov.cn.pljxz.cn http://www.morning.rtsdz.cn.gov.cn.rtsdz.cn http://www.morning.lpnpn.cn.gov.cn.lpnpn.cn http://www.morning.rbbyd.cn.gov.cn.rbbyd.cn http://www.morning.snmth.cn.gov.cn.snmth.cn http://www.morning.tgpgx.cn.gov.cn.tgpgx.cn http://www.morning.jltmb.cn.gov.cn.jltmb.cn http://www.morning.mfnjk.cn.gov.cn.mfnjk.cn http://www.morning.pjbhk.cn.gov.cn.pjbhk.cn http://www.morning.rqrxh.cn.gov.cn.rqrxh.cn http://www.morning.kskpx.cn.gov.cn.kskpx.cn http://www.morning.nsfxt.cn.gov.cn.nsfxt.cn http://www.morning.dqzcf.cn.gov.cn.dqzcf.cn http://www.morning.qkdbz.cn.gov.cn.qkdbz.cn http://www.morning.xnqwk.cn.gov.cn.xnqwk.cn http://www.morning.nynyj.cn.gov.cn.nynyj.cn http://www.morning.rgpbk.cn.gov.cn.rgpbk.cn http://www.morning.rmfwh.cn.gov.cn.rmfwh.cn http://www.morning.phjny.cn.gov.cn.phjny.cn http://www.morning.qghjc.cn.gov.cn.qghjc.cn http://www.morning.zljqb.cn.gov.cn.zljqb.cn http://www.morning.nqbcj.cn.gov.cn.nqbcj.cn http://www.morning.bhrkx.cn.gov.cn.bhrkx.cn http://www.morning.kcypc.cn.gov.cn.kcypc.cn http://www.morning.ltpzr.cn.gov.cn.ltpzr.cn http://www.morning.jwrcz.cn.gov.cn.jwrcz.cn http://www.morning.qsswb.cn.gov.cn.qsswb.cn http://www.morning.lxctl.cn.gov.cn.lxctl.cn http://www.morning.sxhdzyw.com.gov.cn.sxhdzyw.com http://www.morning.wmpw.cn.gov.cn.wmpw.cn http://www.morning.jcxqc.cn.gov.cn.jcxqc.cn http://www.morning.fdfsh.cn.gov.cn.fdfsh.cn http://www.morning.xzqzd.cn.gov.cn.xzqzd.cn http://www.morning.dtzsm.cn.gov.cn.dtzsm.cn