标签归档:TensorFlow

开发者注意啦,谷歌宣布开源 Swift for TensorFlow

雷锋网 AI 研习社按,今年三月,谷歌在 TensorFlow 开发者峰会上公开演示了 Swift for TensorFlow,近日,TensorFlow 官网宣布 Swift for TensorFlow 已在 GitHub 上开源,地址如下:

https://github.com/tensorflow/swift

关于 Swift for TensorFlow

Swift for TensorFlow 为 TensorFlow 提供了一种新的编程模型,将 TensorFlow 计算图与 Eager Execution 的灵活性和表达能力结合在了一起,同时还注重提高整个软件架构每一层的可用性。

设计的基础是一个称之为「Graph Program Extraction」的算法,它可以让大家用 Eager Execution 式的编程模型来轻松地实现代码,同时还保留 TensorFlow 计算图的高性能优势。

实现可靠的 Graph Program Extraction 算法对于编程语言的设计有很高的要求,经过分析和讨论,谷歌选择了 Swift 作为主语言。他们将高级的自动微分功能直接集成在了 Swift 语言和编译器里面。下面是使用 Swift 作为 TensorFlow 编程语言的详情:

https://github.com/tensorflow/swift/blob/master/docs/WhySwiftForTensorFlow.md

谷歌也编写了一些文档,详细介绍了理论和实现。地址如下:

https://github.com/tensorflow/swift/blob/master/README.md

「Swift for TensorFlow 设计总览」文档里介绍了项目的主要组成部分以及结合方式。谷歌还深入介绍了 Python 与 Swift 的集成,大家可以直接通过 Swift 代码使用任意 Python API。

目前该项目有 macOS 和 Linux 的安装包,以及教大家如何获取源代码的开发指南。目前这一项目还处于早期开发阶段,大家可以参与到他们设计方案的讨论中,一起促进这一项目的发展。大家如果遇到困难,可以在 TensorFlow 中文社区论坛的 “TensorFlow 建议和反馈” 板块联系开发人员:

https://www.tensorflowers.cn/b/issues

雷锋网

Google 和 Nvidia 强强联手,带来优化版 TensorFlow 1.7


雷锋网 AI 研习社按,日前,谷歌和英伟达宣布将 NVIDIA TensorRT 集成到 TensorFlow 1.7 中。在谷歌开发者博客中,他们介绍了此次合作的详细信息以及整合之后的性能,雷锋网 AI 研习社编译整理如下:

TensorRT 是一个可以用于优化深度学习模型,以进行推理,并为生产环境中的 GPU 创建运行环境的库。它能优化 TensorFlow 中的 FP16 浮点数和 INT8 整型数,并能自动选择针对特定平台的内核,以最大化吞吐量,并最大限度的降低 GPU 推理期间的延迟。全新的集成工作流程简化了在 TensorFlow 中使用 TensorRT 的步骤,同时使得 TensorFlow 达到了世界一流的性能水平。

经测试,在 NVIDIA Volta Tensor 核心上,集成了 TensorRT 的 TensorFlow 运行 ResNet-50 比没有集成 TensorRT 的 TensorFlow 执行速度提高了 8 倍。

优化 TensorFlow 中的子图

在 TensorFlow 1.7 中,TensorRT 可以用于优化子图,而 TensorFlow 执行其余未优化的部分。这个方法使得开发者既能够使用 TensorFlow 的众多功能来快速构建模型,同时也可以在执行推理时使用 TensorRT 获得强大的优化能力。如果你尝试过在之前的 TensorFlow 模型中使用 TensorRT,你应该知道,要想使用某些不受支持的 TensorFlow 层,必须手动导入,这在某些情况下可能会耗费大量时间。

从工作流程的角度来看,开发者可以使用 TensorRT 来优化 TensorFlow 的每个子图。

在推断过程中,TensorFlow 先将执行所有支持区域的图,之后调用 TensorRT 去执行那些经过 TensorRT 优化过的节点。举个例子,如果你的图包含 A,B,C 三段,其中 B 段被 TensorRT 优化过,B 将被一个节点代替。那么在推理过程中,TensorFlow 将先执行 A,之后调用 TensorRT 执行 B,最后 TensorFlow 执行 C。

这个用于优化 TensorRT 的新加入的 TensorFlow API,以冻结的 TensorFlow 图为输入,针对该子图进行优化,最后将优化过的推理子图发送回 TensorFlow 中。

下面为一段示例代码:

# Reserve memory for TensorRT inference engine

gpu_options = tf.GPUOptions(per_process_gpu_memory_fraction = number_between_0_and_1)

… 

trt_graph = trt.create_inference_graph(

                 input_graph_def = frozen_graph_def,

                 outputs = output_node_name,

                 max_batch_size=batch_size,

                 max_workspace_size_bytes=workspace_size,

                 precision_mode=precision)  # Get optimized graph

per_process_gpu_memory_fraction 这个参数定义了 TensorFlow 允许使用的 GPU 显存的比例,剩余的显存将分配给 TensorRT。这个参数应该在 TensorFlow-TensorRT 进程第一次启动的时候设定好。比如,per_process_gpu_fraction=0.67,那么 67% 的显存会被分配给 TensorFlow,其余的 33% 会被分配给 TensorRT 引擎。

Create_inference_graph 函数将冻结住的 TensorFlow 图作为输入,返回一个经过 TensorRT 节点优化过的图。我们看看这个函数的参数:

  • Input_graph_def:冻结住的 TensorFlow 图

  • Outputs:输出节点名字的字符串列表,比如:[“resnet_v1_50/predictions/Resape_1”]

  • Max_batch_size:整数,输入的 batch size,比如,16

  • Max_workspace_size_bytes:整数,能分配给 TensorRT 的最大 GPU 显存大小

  • Precision_mode:字符串,可选的值为「FP32」, 「FP16」, 「INT8」

举个例子,如果 GPU 有 12GB 显存,想要给 TensorRT 引擎分配 4GB 显存,那么应该设置 per_process_gpu_memory_fraction 为(12-4)/12=0.67,max_workspace_size_bytes=4,000,000,000.

我们来试着将这个新的 API 应用在 ResNet-50 上,看看经过优化后的模型在 TensorBoard 中看起来是什么样的。左侧的图像是没有经过 TensorRT 优化的 ResNet-50,右侧是经过优化的。在这个设定下,大部分图被 TensorRT 优化,并用一个单一节点代替了(图中高亮部分)。

经过优化的INT8推理性能

TensorRT 兼容单精度(FP32)和半精度(FP16)训练的模型(也可以将它们量化为 INT8),同时能尽可能减少由精度降低而导致的准确率降低。INT8 模型能够更快的计算,同时对带宽的需求也会降低,但是因为可用的动态范围降低了,这也对神经网络的权重和激活表示提出了很大的挑战。

为了解决这个问题,TensorRT 使用了一个校正过程,以尽可能减小将 FP32 网络近似成 8-bit 整型表示时的信息损失。在使用 TensorRT 优化 TensorFlow 图之后,可以使用下面的命令将图传递给 TensorRT 进行校准,如下:

trt_graph=trt.calib_graph_to_infer_graph(calibGraph)

除此之外的网络推理流程都没有变化。这一步的输出为一个可以被 TensorFlow 执行的冻结图。

在NVIDIA Volta GPU上自动使用Tensor核心

在 NVIDIA Volta GPU 的 Tensor 核心上通过 TensorRT 进行半精度 TensorFlow 模型推理,能够提供相较于单精度模型八倍的吞吐量。相较于更高精度的 FP32 或者 FP64,半精度数据(FP16)能够减少神经网络的显存使用量,这使得开发者能够训练和部署更大规模的神经网络,同时 FP16 相比 FP32 和 FP64 有更少的传输时间。

如果每个 Tensor 核心执行的是 D=A*B+C,其中 A 和 B 为半精度 4*4 矩阵,D 和 C 是单精度或者半精度 4*4 矩阵,那么 V100 上此时 Tensor 核心的峰值性能是双精度(FP64)性能的 10 倍,是单精度(FP32)性能的 4 倍。

Google 目前已经发布了 TensorFlow 1.7,同时也将跟 NVIDIA 更紧密地合作。希望这个新的解决方案额能够在提供最强性能的同时,保持 TensorFlow 的易用性和灵活性。随着 TensorRT 支持越来越多的网络结构,大家只要更新就可以享受到这些好处,而无须改写代码。

使用标准pip install即可更新到 TensorFlow 1.7:

pip install tensorflow-gpu r1.7

详细的安装说明可在下面找到:

https://github.com/tensorflow/tensorflow/tree/r1.7/tensorflow/contrib/tensorrt

via: Google Develop Blog

雷锋网 AI 研习社编译整理。

雷锋网

谷歌正式开源 Hinton 胶囊理论代码,即刻用 TensorFlow 实现吧

雷锋网 AI 研习社消息,相信大家对于「深度学习教父」Geoffery Hinton 在去年年底发表的胶囊网络还记忆犹新,在论文 Dynamic Routing between Capsules 中,Hinton 团队提出了一种全新的网络结构。为了避免网络结构的杂乱无章,他们提出把关注同一个类别或者同一个属性的神经元打包集合在一起,好像胶囊一样。在神经网络工作时,这些胶囊间的通路形成稀疏激活的树状结构(整个树中只有部分路径上的胶囊被激活)。这样一来,Capsule 也就具有更好的解释性。

在实验结果上,CapsNet 在数字识别和健壮性上都取得了不错的效果。详情可以参见终于盼来了Hinton的Capsule新论文,它能开启深度神经网络的新时代吗?

日前,该论文的第一作者 Sara Sabour 在 GitHub 上公布了论文代码,大家可以马上动手实践起来。雷锋网 AI 研习社将教程编译整理如下:

所需配置:

执行 test 程序,来验证安装是否正确,诸如:

python layers_test.py

快速 MNIST 测试:

python experiment.py –data_dir=$ DATA_DIR/mnist_data/ –train=false \
–summary_dir=/tmp/ –checkpoint=$ CKPT_DIR/mnist_checkpoint/model.ckpt-1

快速 CIFAR10 ensemble 测试:

python experiment.py –data_dir=$ DATA_DIR –train=false –dataset=cifar10 \
–hparams_override=num_prime_capsules=64,padding=SAME,leaky=true,remake=false \
–summary_dir=/tmp/ –checkpoint=$ CKPT_DIR/cifar/cifar{}/model.ckpt-600000 \
–num_trials=7

 CIFAR10 训练指令:

python experiment.py –data_dir=$ DATA_DIR –dataset=cifar10 –max_steps=600000\
–hparams_override=num_prime_capsules=64,padding=SAME,leaky=true,remake=false \
–summary_dir=/tmp/

MNIST full 训练指令:

  • 也可以执行–validate=true as well 在训练-测试集上训练

  • 执行 –num_gpus=NUM_GPUS 在多块GPU上训练

python experiment.py –data_dir=$ DATA_DIR/mnist_data/ –max_steps=300000\
–summary_dir=/tmp/attempt0/

 MNIST baseline 训练指令:

python experiment.py –data_dir=$ DATA_DIR/mnist_data/ –max_steps=300000\
–summary_dir=/tmp/attempt1/ –model=baseline

To test on validation during training of the above model:

训练如上模型时,在验证集上进行测试(记住,在训练过程中会持续执行指令):

  • 在训练时执行 –validate=true 也一样

  • 可能需要两块 GPU,一块用于训练集,一块用于验证集

  • 如果所有的测试都在一台机器上,你需要对训练集、验证集的测试中限制 RAM 消耗。如果不这样,TensorFlow 会在一开始占用所有的 RAM,这样就不能执行其他工作了

python experiment.py –data_dir=$ DATA_DIR/mnist_data/ –max_steps=300000\
–summary_dir=/tmp/attempt0/ –train=false –validate=true

大家可以通过 –num_targets=2 和 –data_dir=$ DATA_DIR/multitest_6shifted_mnist.tfrecords@10 在 MultiMNIST 上进行测试或训练,生成 multiMNIST/MNIST 记录的代码在 input_data/mnist/mnist_shift.py 目录下。

multiMNIST 测试代码:

python mnist_shift.py –data_dir=$ DATA_DIR/mnist_data/ –split=test –shift=6
–pad=4 –num_pairs=1000 –max_shard=100000 –multi_targets=true

可以通过 –shift=6 –pad=6 来构造 affNIST expanded_mnist

论文地址:https://arxiv.org/pdf/1710.09829.pdf 

GitHub 地址:https://github.com/Sarasra/models/tree/master/research/capsules

雷锋网 AI 研习社编译整理。

(完)

雷锋网

谷歌发布 TensorFlow 1.5,全面支持动态图机制和 TensorFlow Lite

雷锋网 AI 科技评论消息,日前,谷歌发布 TensorFlow 1.5,TensorFlow 又一次迎来更新。

在此前的版本中,TensorFlow 迎来三大重大变化:Keras 位于 TensorFlow core 中,Dataset API 支持更多功能,引入效用函数 tf.estimator.train_and_evaluate 等等。而在这次的更新中,谷歌宣布 TensorFlow 将全面支持 Eager execution 动态图机制和 TensorFlow Lite,除此之外,还将支持 CUDA 9 和 cuDNN 7。

雷锋网 AI 科技评论将此次的更新编译整理如下:

重大改变:

基于 CUDA 9 和 cuDNN 7 来构建预建的二进制文件;

Linux 二进制文件是在 ubuntu 16 容器环境下构建的,这可能会导致与用 ubuntu 14 构建的文件不兼容;

从 1.6 版本开始,预建二进制文件中将会使用 AVX 指令集,如果老版本不支持 AVX 指令集,将会引发问题。

主要的更新:

支持 Eager execution 预览版本

TensorFlow Eager Execution 是一个命令式、由运行定义的接口,可以在即时的运行错误下进行快速调试,与 Python 工具进行整合,一旦从 Python 被调用可立即执行操作。这可以使得 TensorFlow 的入门学习变得更简单,也使得研发工作变得更直观。

支持 TensorFlow Lite 开发者版本

TensorFlow Lite 针对移动和嵌入式设备等。具备如下三点特征:

  • 轻量级:支持机器学习模型的推理在较小二进制数下进行,能快速初始化/启动。

  • 跨平台:可以在许多不同的平台上运行,现在支持 Android 和 iOS。

  • 快速:针对移动设备进行了优化,包括大大减少了模型加载时间、支持硬件加速。

支持 CUDA 9 和 cuDNN 7

Bug 修复和其他改变:

将 auto_correlation 加入 tf.contrib.distributions 中

引入 DenseFlipout 概率层

将 DenseVariational 标准化,作为其他概率层的简单模板

tf.contrib.distributions QuadratureCompound 类支持 batch

Stream::BlockHostUntilDone 现在 return 到 Status,而不是 bool

GCS 文件系统中的定制化请求超时

via:GitHub

雷锋网 AI 科技评论编辑整理。

雷锋网

腾讯发现者揭秘:怎么应对这次曝光的谷歌 TensorFlow 的安全风险,修复有多难

使用谷歌人工智能开源框架 TensorFlow 的人都要瑟瑟发抖了,这次是该框架本身的问题。

12 月 15 日,雷锋网报道,腾讯安全平台部预研团队发现谷歌人工智能学习系统 TensorFlow 存在自身安全风险,可被黑客利用带来安全威胁。这次威胁还不小,攻击者可以生成 Tensorflow 的恶意模型文件,对 AI 研究者进行攻击,对受害者自身的 AI 应用进行窃取或篡改、破坏。该框架在谷歌、ebay、airbnb、twitter、uber、小米、中兴等公司均有使用,这意味着,影响范围不小。

12 月 16 日,雷锋网宅客频道(微信公众号:letshome)与发现此次安全威胁的腾讯安全平台预研团队取得联系,探寻此次威胁发现的始末以及修复难度。

以下是雷锋网宅客频道与腾讯安全平台预研团队的问答实录:

1.到底问题在哪里,是什么问题?

腾讯安全平台预研团队:漏洞发生在 Tensorflow 处理AI模型的时候,属于逻辑型的漏洞。

2.影响到底多大?

腾讯安全平台预研团队:所有 Tensorflow 版本,包括最新的移动版 Tensorflow lite。

成功的攻击(让 AI 研发或者开发人员使用有漏洞利用代码的 AI 模型)可以完整控制整个 AI 。危害取决于 AI 本身用于什么工作。如果是自动驾驶的 AI,就可以导致车毁人亡;如果是人脸验证的 AI,就可以误导验证逻辑。

引用一个第三方的观点。上海信息安全行业协会专委会副主任张威认为,此次发现的漏洞由于可以使他人获得人工智能应用场景里的系统权限,这也意味着其可以拿到很多顶层数据。而当前参与人工智能开发的企业多是算法和数据相结合,有关数据可能涉及核心秘密,因此风险较高。

他建议,政府应尽快组织筛查使用该套平台编程的部门,确定影响范围,尤其是涉及国家安全和国家秘密的敏感部门是否也使用过该套平台,同时在人工智能的编程平台上加强审查。

3.12 月初,有消息称 TensorFlow、Caffe、Torch 这三大深度学习框架所使用的大量第三方开源基础库存在不少网络安全漏洞。你们这次的发现和前面这种安全风险有什么明显区别?

腾讯安全平台预研团队:以前其他团队发现的 TensorFlow 漏洞是 TensorFlow 使用的外部组件的问题(可以理解为手机使用的其他厂商的内存有问题而不是手机厂商自身的问题),这次我们发现的这个是 TensorFlow自身的问题,是 TensorFlow 第一个官方承认的安全漏洞,官方也意识到 TensorFlow 的安全问题可能带来的危害,所以计划像其他大量使用的软件一样专门开辟一个安全公告页面。

4.修复需要多久?修复难度在哪里?在这段“时间差”里,使用者怎么办?

腾讯安全平台预研团队:Google TensorFlow 工程师团队还在讨论修复方案,目前看需要重新设计 AI 模型输入处理机制,因为这本身可以算是处理机制的问题。对于 TensorFlow 使用者,等待 TensorFlow 版本更新即可。我觉得如果短期速成修复倒是可以比较快,长期来看还是要在处理 AI 框架的机制上有规避这一类风险的措施才行。

使用这个开源框架的人可能会遭到攻击,因为这是个尚未公开的漏洞,存在较大安全风险。这个漏洞出问题的点是在处理 AI 模型的时候,一个攻击场景是,黑客在网上提供一个AI 模型给大家用,大家下载回来一运行就中招了。或者黑客能够控制某个系统的 AI 模型就能实施攻击。所以,使用 TensorFlow 的系统要注意不要使用有问题/被黑客修改过的 AI 模型,最终防范还是要升级新版本。

虽然利用这个漏洞进行攻击成本很低,但发现难度还是有的,而且我们是首先发现这个漏洞,我们判断,已经掌握这个漏洞的人应该很少或者没有。一般来说是跟随下一个版本修复,谷歌现在的想法是,想从机制上解决(会涉及到 Tensorflow 一些 API 的调整),所以,可能会慢一些,时间点也没有给。对 Tensorflow 的使用者来说,目前安心等官方出新版本升级比较好。

5.谷歌怎么回应的?

腾讯安全平台预研团队: 提交报告后,谷歌第一反应是跟我们讨论,是否要在官网建立一个类似 Google android那样的安全页面,做安全致谢以及给研发人员的安全指引,目前这个安全页面已经在制作中。

谷歌与安全研究员的关系来说是很好的,他们是很有安全意识的,对安全研究者挺好,腾讯的安全漏洞奖励计划也参考了谷歌漏洞奖励计划。TensorFlow 这个漏洞应该还没有纳入谷歌漏洞奖励计划,相信未来会纳入。之前我们也给谷歌的安卓报过漏洞,拿过奖金。

这次比较特殊的地方是,这次是谷歌旗下 TensorFlow 的首个漏洞,官方没有处理过类似事件,可能还没有建立这个流程,这块我们也在和官方探讨,推动他们建立安全漏洞报告处理流程,更好地与安全研究团队协作。

6.你们还想强调的点。

腾讯安全平台预研团队:AI 框架近两年被用得很多,但是都没有关注其安全性,这肯定会带来安全风险,我们也会持续关注这里。目前已知的公开发现 AI 框架漏洞有两个,一个是之前 360 发现的三个 AI 框架引入的第三方组件带来的漏洞,另一个是此次我们发现的框架本身的漏洞。经过这两次普及,安全研究员会持续关注,未来这里肯定还有更多的漏洞被发掘出来,当然好的一面是漏洞会减少,也会提高大家对这里的安全意识。

比如,这次如果我们能让谷歌把 TensorFlow 加入到漏洞奖励计划 /  TensorFlow 建立安全漏洞处理机制,安全性肯定会大大提升。

雷锋网

腾讯:谷歌 AI 开源框架 TensorFlow 存在自身安全风险

12月15日,雷锋网从腾讯了解到,腾讯安全平台部预研团队发现谷歌人工智能学习系统 TensorFlow 存在自身安全风险,可被黑客利用带来安全威胁,其已向谷歌报告这一风险并获得致谢。

腾讯安全平台部预研团队发现,攻击者可以生成 Tensorflow 的恶意模型文件,对 AI 研究者进行攻击,对受害者自身的 AI 应用进行窃取或篡改、破坏。腾讯方面认为,该风险危害面非常大,一方面攻击成本低,普通攻击者即可实施攻击;另一方面迷惑性强,大部分 AI 研究者可能毫无防备;同时因为利用了 TensorFlow 自身的机制,其在 PC 端和移动端的最新版本均会受到影响。

Google 的 TensorFlow 作为开源框架被互联网广泛使用,该框架在谷歌、ebay、airbnb、twitter、uber、小米、中兴等公司均有使用。在TensorFlow中,AI 研究者可以复用他人建好的模型来进行AI训练,或直接提供 AI 服务。

这是安全研究员最近发现的第二起 TensorFlow 相关安全风险事件。 

12月初,雷锋网了解到,奇虎 360 安全研究实验室的 Qixue Xiao 和 Deyue Zhang,美国佐治亚大学的 Kang Li,以及美国弗吉尼亚大学的 Weilin Xu 在分析了 TensorFlow,Caffe,Torch 这三大深度学习框架所使用的大量第三方开源基础库后,发现它们存在不少的网络安全漏洞,容易受到拒绝服务攻击、逃逸攻击、系统损害攻击的影响。

雷锋网

用 TensorFlow 让你的机器人唱首原创给你听

雷锋网按:这篇文章会用一个简单的模型在 TensorFlow 上来实现一个音频生成器。原文作者杨熹,载于作者的个人博客,雷锋网经授权发布。

今天想来看看 AI 是怎样作曲的。

本文会用 TensorFlow 来写一个音乐生成器。

当你对一个机器人说:我想要一种能够表达出希望和奇迹的歌曲时,发生了什么呢?

计算机会首先把你的语音转化成文字,并且提取出关键字,转化成词向量。

然后会用一些打过标签的音乐的数据,这些标签就是人类的各种情感。接着通过在这些数据上面训练一个模型,模型训练好后就可以生成符合要求关键词的音乐。

程序最终的输出结果就是一些和弦,他会选择最贴近主人所要求的情感关键词的一些和弦来输出。

当然你不只是可以听,也可以作为创作的参考,这样就可以很容易地创作音乐,即使你还没有做到刻意练习1万小时。

机器学习其实是为了扩展我们的大脑,扩展我们的能力。

DeepMind 发表了一篇论文,叫做 WaveNet, 这篇论文介绍了音乐生成和文字转语音的艺术。

通常来讲,语音生成模型是串联。这意味着如果我们想从一些文字的样本中来生成语音的话,是需要非常大量的语音片段的数据库,通过截取它们的一部分,并且再重新组装到一起,来组成一个完整的句子。

生成音乐也是同样的道理,但是它有一个很大的难点:就是当你把一些静止的组件组合到一起的时候,生成声音需要很自然,并且还要有情感,这一点是非常难的。

一种理想的方式是,我们可以把所有生成音乐所需要的信息存到模型的参数里面。也就是那篇论文里讲的事情。

我们并不需要把输出结果传给信号处理算法来得到语音信号,而是直接处理语音信号的波。

他们用的模型是 CNN。这个模型的每一个隐藏层中,每个扩张因子,可以互联,并呈指数型的增长。每一步生成的样本,都会被重新投入网络中,并且用于产生下一步。

我们可以来看一下这个模型的图。输入的数据,是一个单独的节点,它作为粗糙的音波,首先需要进行一下预处理,以便于进行下面的操作。

接着我们对它进行编码,来产生一个 Tensor,这个 Tensor 有一些 sample 和 channel。

然后把它投入到 CNN 网络的第一层中。这一层会产生 channel 的数量,为了进行更简单地处理。

然后把所有输出的结果组合在一起,并且增加它的维度。再把维度增加到原来的 channel 的数量。

把这个结果投入到损失函数中,来衡量我们的模型训练的如何。

最后,这个结果会被再次投入到网络中,来生成下一个时间点所需要的音波数据。

重复这个过程就可以生成更多的语音。

这个网络很大,在他们的 GPU 集群上需要花费九十分钟,并且仅仅只能生成一秒的音频。

接下来我们会用一个更简单的模型在 TensorFlow 上来实现一个音频生成器。

  1.引入packages:

数据科学包 Numpy ,数据分析包 Pandas,tqdm 可以生成一个进度条,显示训练时的进度。

import numpy as np
import pandas as pd
import msgpackimport glob
import tensorflow as tf 
from tensorflow.python.ops import control_flow_ops
from tqdm import tqdm
import midi_manipulation

我们会用到一种神经网络的模型 RBM-Restricted Boltzmann Machine 作为生成模型。 

它是一个两层网络:第一层是可见的,第二层是隐藏层。同一层的节点之间没有联系,不同层之间的节点相互连接。每一个节点都要决定它是否需要将已经接收到的数据发送到下一层,而这个决定是随机的。

  2.定义超参数:

先定义需要模型生成的 note 的 range

lowest_note = midi_manipulation.lowerBound #the indexof the lowest note on the piano roll
highest_note = midi_manipulation.upperBound #the indexof the highest note on the piano roll
note_range = highest_note-lowest_note #the note range

接着需要定义 timestep ,可见层和隐藏层的大小。

num_timesteps = 15 #This is the number of timesteps that we will createat a time
n_visible = 2*note_range*num_timesteps #This is the sizeof the visible layer.
n_hidden = 50 #This is the sizeof the hidden layer123123

训练次数,批量处理的大小,还有学习率。

num_epochs = 200 #The number of training epochs that we are going to run. For each epoch we go through the entire data set.


batch_size = 100 #The numberof training examples that we are going to send through the RBM at a time.


lr = tf.constant(0.005, tf.float32) #The learning rate of our model

  3.定义变量:

x 是投入网络的数据
w 用来存储权重矩阵,或者叫做两层之间的关系
此外还需要两种 bias,一个是隐藏层的 bh,一个是可见层的 bv

x  = tf.placeholder(tf.float32, [None, n_visible], name="x") #The placeholder variable that holds our data
W  = tf.Variable(tf.random_normal([n_visible, n_hidden], 0.01), name="W") #The weight matrix that stores the edge weights
bh = tf.Variable(tf.zeros([1, n_hidden],  tf.float32, name="bh")) #The bias vector for the hidden layer
bv = tf.Variable(tf.zeros([1, n_visible],  tf.float32, name="bv")) #The bias vector for the visible layer

接着,用辅助方法 gibbs_sample 从输入数据 x 中建立样本,以及隐藏层的样本:

gibbs_sample 是一种可以从多重概率分布中提取样本的算法。

它可以生成一个统计模型,其中,每一个状态都依赖于前一个状态,并且随机地生成符合分布的样本。

#The sample of x
x_sample = gibbs_sample(1)
#The sample of the hidden nodes, starting from the visible state of x
h = sample(tf.sigmoid(tf.matmul(x, W) + bh)) 
#The sample of the hidden nodes, starting from the visible state of x_sample
h_sample = sample(tf.sigmoid(tf.matmul(x_sample, W) + bh))

  4.更新变量:

size_bt = tf.cast(tf.shape(x)[0], tf.float32)


 W_adder  = tf.mul(lr/size_bt, tf.sub(tf.matmul(tf.transpose(x), h), tf.matmul(tf.transpose(x_sample), h_sample))) 


bv_adder = tf.mul(lr/size_bt, tf.reduce_sum(tf.sub(x, x_sample), 0, True)) 

bh_adder = tf.mul(lr/size_bt, tf.reduce_sum(tf.sub(h, h_sample), 0, True))
#When we do sess.run(updt), TensorFlow will run all 3 update steps
updt = [W.assign_add(W_adder), bv.assign_add(bv_adder), bh.assign_add(bh_adder)]

  5.接下来,运行 Graph 算法图:

    5.1先初始化变量
with tf.Session() as sess:    
   #First, we train the model
   #initialize the variables of the model    
   init = tf.initialize_all_variables()    
   sess.run(init)

    首先需要 reshape 每首歌,以便于相应的向量表示可以更好地被用于训练模型。

for epoch in tqdm(range(num_epochs)):        
   for song in songs:            
       #The songs are stored in a time x notes format. The size of each song is timesteps_in_song x 2*note_range            
       #Here we reshape the songs so that each training example is a vector with num_timesteps x 2*note_range elements            
       song = np.array(song)            
       song = song[:np.floor(song.shape[0]/num_timesteps)*num_timesteps]            
       song = np.reshape(song, [song.shape[0]/num_timesteps, song.shape[1]*num_timesteps])

    5.2接下来就来训练 RBM 模型,一次训练一个样本
for i in range(1, len(song), batch_size):                 
   tr_x = song[i:i+batch_size]                
   sess.run(updt, feed_dict={x: tr_x})

    模型完全训练好后,就可以用来生成 music 了。

    5.3需要训练 Gibbs chain

    其中的 visible nodes 先初始化为0,来生成一些样本。
    然后把向量 reshape 成更好的格式来 playback。

sample = gibbs_sample(1).eval(session=sess, feed_dict={x: np.zeros((10, n_visible))})    
for i in range(sample.shape[0]):        
   if not any(sample[i,:]):           
       continue
    #Here we reshape the vector to be time x notes, and then save the vector as a midi file        
     S = np.reshape(sample[i,:], (num_timesteps, 2*note_range))

    5.4最后,打印出生成的和弦
midi_manipulation.noteStateMatrixToMidi(S, "generated_chord_{}".format(i))

    综上,就是用 CNN 来参数化地生成音波,
    用 RBM 可以很容易地根据训练数据生成音频样本,
    Gibbs 算法可以基于概率分布帮我们得到训练样本。

 

本文基于Siraj 的视频编写,此处提供视频链接以及github源码供参考。

雷锋网

手把手教你用 TensorFlow 实现文本分类(上)

雷锋网按:本文作者张庆恒,原文载于作者个人博客,雷锋网已获授权。

由于需要学习语音识别,期间接触了深度学习的算法。利用空闲时间,想用神经网络做一个文本分类的应用, 目的是从头到尾完成一次机器学习的应用,学习模型的优化方法,同时学会使用主流的深度学习框架(这里选择tensorflow)。

文章分为两部分,本文仅实现流程,用简单的softmax回归对文本进行分类,后面一篇文章再从流程的各个方面对模型进行优化,达到比较好的效果。

  收集数据

该部分不是这里的重点,数据从各大新闻网站爬取新闻文本,分十类保存到本地,包括科技、生活、体育、娱乐等。文本分别保存到training_set和testing_set目录下,如:

$ tree -L 1 training_set/

training_set/

├── 10_hel

├── 1_ent

├── 2_fin

├── 3_spo

├── 4_tec

├── 5_mil

├── 6_soc

├── 7_lif

├── 8_cul

└── 9_car

文本以text_id.txt的格式保存在不同类的目录下(如text_1234.txt)。本例保存了共113673个训练文本和等数量的测试文本(暂时按1:1的比例)。

  预处理文本

step0

为方便后面处理,预处理文本首先要分别针对训练文本和测试文本生成唯一的文本ID, 这里用 {class_id}{text_type}{text_id}.txt 来标示唯一文本,class_id为类的id,这里为1-10;text_type为数据类型包括train和test;text_id为类文件夹下的文本id,实现函数:

def get_unique_id(self, data_dir):

        """

            get flie unique id famate as {class_id}_type_{text_id}.txt.

            data_dir is the full path of file

              e.g ./training_set/4_tec/4_tec_text/text_2001.txt

            where "training" is type, "4" is file class, and "2001" is text id.

            modify this function to adapt your data dir fomate

        """


        dir_list = data_dir.split("/")

        class_id = dir_list[2].split("_")[0]

        text_id = dir_list[4].split(".")[0]

        type_id = dir_list[1].split("_")[0]

        return class_id + "_" + type_id + "_" + text_id

step1: 分词

通俗来讲,文本分类的主要思想,是构建各类文本的汉语词典,通过对文本进行分析,观察文本中哪类词汇比较多,由此判断文本所属类别。因此,文本分类需要对文本进行分词操作,可以选择的分词工具很多,这里选择Python编写的jieba开源库对文本进行分词,并以行为单位,将文本保存到输出文件,该部分实现比较简单:

def splitwords(self, data_dir, data_type):


        if os.path.exists(data_type+".txt"):

            os.remove(data_type+".txt")


        list_dirs = os.walk(data_dir)

        for root, _, files in list_dirs:

            print root

            # get all files under data_dir

            for fp in files:

                file_path = os.path.join(root, fp)

                file_id = self.get_unique_id(file_path)

                #split words for f, save in file ./data_type.txt

                with nested(open(file_path), open(data_type+".txt", "a+")) as (f1, f2):

                    data = f1.read()

                    #print data

                    seg_list = jieba.cut(data, cut_all=False)

                    f2.write(file_id + " " + " ".join(seg_list).replace("\n", " ")+"\n")


        print "split word for %s file end." % data_type

        return

函数传入参数为数据集目录路径,以及数据集类型(train or test)。结果文件保存形如train.txt,后续的操作在该输出文件基础之上。输出文件格式为:<class_{data_type}_id> < words >

step2: 去除停用词

这部分主要删去文本中的停用词,停用词包括一些对于文本分类无用,而且出经常出现的词汇或符号,如“因此”、“关于”、“嘿嘿”、标点符号等。去除停用词需根据停用词典,去除上面经过分词操作的文本中的停用词。停用词典可以根据自己需要生成或在网络上获得,这里后面源码链接中会给出使用的停用词词典。

def rm_stopwords(self, file_path, word_dict):


        #read stop word dict and save in stop_dict

        stop_dict = {}

        with open(word_dict) as d:

            for word in d:

                stop_dict[word.strip("\n")] = 1


        # remove tmp file if exists

        if os.path.exists(file_path+".tmp"):

            os.remove(file_path+".tmp")


        print "now remove stop words in %s." % file_path

        # read source file and rm stop word for each line.

        with nested(open(file_path), open(file_path+".tmp", "a+"))  as (f1, f2):

            for line in f1:

                tmp_list = [] # save words not in stop dict

                words = line.split()

                for word in words[1:]:

                    if word not in stop_dict:

                        tmp_list.append(word)

                words_without_stop =  " ".join(tmp_list)

                f2.write(words[0] + " " + words_without_stop + "\n")


        # overwrite origin file with file been removed stop words

        shutil.move(file_path+".tmp", file_path)

        print "stop words in %s has been removed." % file_path

        return

代码中经过简单的按行读文本,然后搜索停用词典,如果文本中的词汇在词典中,则跳过,否则保存。这里每行对应数据集中的一个文本。

  step3: 生成词典

上面提到文本分类需要得到能表征各类文本的汉语词典,这部分的主要思路是实现tf_idf算法自动提取关键词,根据词频(TF)和逆文档频率(IDF)来衡量词汇在文章中的重要程度。这里词频的计算采用公式:

由于是衡量某类文本的关键词,公式中的“文章”为某类所有文本的总和。逆文档频率计算采用公式:

上面的文档总数为train数据集所有文本的数目。tf-idf为两个指标的乘积,计算各类文本中所有词汇的tf-idf,由小到大排序,默认取前500个词汇作为该类的关键词保存到词典。最终生成大小为5000的词典。简洁考虑,该部分的关键代码(gen_dict方法中):

        for k, text_info in class_dict.items():

            #print "class %s has %d words" % (k, text_info.file_num)

            # get tf in words of class k

            for w in text_info.wordmap:

                text_info.tf_idf(w, word_in_files[w], text_num)


            main_words = []

            with open(save_path, "a+") as f:

                main_words = text_info.get_mainwords()

                print "class %s : main words num: %d" % (k, len(main_words))

                f.write("\n".join(main_words) + "\n")

class_dict是类id到该类文本信息(text_info)的字典,text_info.wordmap保存了该类文本的所有不重复的词汇,text_info.tf_idf方法计算该类文本某词的tf-idf,输入参数为词汇,词汇在整个语料库出现的文本数和语料库的文本数。text_info.get_mainwords方法得到该类本前500个关键词。完整的定义与实现参考源码

step4: 生成词袋

该部分实现向量化文本,利用生成的词典,以行为单位将去停用词后的文本转换为向量,这里向量为5000维。如果文本出现词典中的某词汇,则文本向量对应词典中该词汇的位置的计数累加。最终生成文件,行数为文本数,列为5000。此外生成对应的label文件,行数为文本数,对应于文本向量文件行,列为1,对应某文本的类别(1-10)。该部分代码比较简单,实现在gen_wordbag方法中。

到此完成了文本的预处理,接下来针对不同分类算法,将有不同的处理,这里参考tensotflow处理MNIST数据集,读取预处理后的文本到系统,进行线性回归。

  读取训练数据

该部分主要包括两部分,一是从磁盘读取向量化后的文本保存到numpy数组,将数据和类别分别存储,数据保存为二维(text_line_num, 5000)的数组,text_line_num为数据集的文本数,5000为词典的维度,也是后面模型输入参数的个数。类别保存为标签向量(label_line_num, 1),label_line_num,同样为数据集的大小。

为方便处理,将类别10的标签保存为0,并对label进行“one_hot”处理,这部分解释可参考上个tensotflow链接。该部分在datasets类中实现。需要注意的是这里train部分数据最为cv(cross validation)数据,这里暂时不会用到。此外,由于数据较多,为节省内存,提高整体运算速度,分别读取train数据集和test数据集。dataset类中保存不同类型的数据集,并实现next_batch方法,获取指定数目的数据。

  训练数据

该部分利用softmax回归对数据进行训练,对于tensorflow的使用这里不作介绍。完整代码如下:

#!/usr/bin/python

#-*-coding:utf-8-*-


import tensorflow as tf

from datasets import datasets


data_sets = datasets()

data_sets.read_train_data(".", True)


sess = tf.InteractiveSession()


x = tf.placeholder(tf.float32, [None, 5000])

W = tf.Variable(tf.zeros([5000, 10]))

b = tf.Variable(tf.zeros([10]))

y = tf.nn.softmax(tf.matmul(x, W) + b)


y_ = tf.placeholder(tf.float32, [None, 10])

cross_entropy = -tf.reduce_sum(y_ * tf.log(y + 1e-10))

train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)


#training

tf.global_variables_initializer().run()


saver = tf.train.Saver()

for i in range(1000):

    batch_xs, batch_ys = data_sets.train.next_batch(100)

    train_step.run({x: batch_xs, y_: batch_ys})


print W.eval()

print b.eval()


path = saver.save(sess, "./model2/model.md")

代码中:

● x : 对于输入数据,None占位符标示输入样本的数量,5000为单个样本的输入维度,对应字典维度。

● W :权重矩阵,行为输入维度,列为输出维度,这里为类别的数目10。

● b : 偏重为10对应输出的维度

● y : 定义训练输出结果,使用softmax作为激励函数,tf.matmul(x, W) + b为输入参数,tf.matmul为矩阵乘。

● y_ : 真实样本的类别,从数据集读入,None占位符标示输入样本的数量,10为输出的维度。

● cross_entropy: 交叉熵,衡量真实值与预测值的偏差程度,训练过程中目的是最小化该值。

训练对cross_entropy进行梯度下降算法更新参数,学习率为0.01。迭代1000次,每次使用100个训练集。最后保存训练的模型到指定目录。

  测试模型

这部分主要读取上面保存的模型参数,对测试数据集进行预测,并打印准确率。

!/usr/bin/python

#-*-coding:utf-8-*-


import tensorflow as tf

from datasets import datasets


data_sets = datasets()

data_sets.read_test_data(".", True)


sess = tf.InteractiveSession()


x = tf.placeholder(tf.float32, [None, 5000])

W = tf.Variable(tf.zeros([5000, 10]))

b = tf.Variable(tf.zeros([10]))

y = tf.nn.softmax(tf.matmul(x, W) + b)

y_ = tf.placeholder(tf.float32, [None, 10])


saver = tf.train.Saver()

saver.restore(sess, "./model2/model.md")


# test

correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))

acc = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))

print(acc.eval({x: data_sets.test.text, y_: data_sets.test.label}))

  小结

直接通过上面过程训练模型,得到的准确率大概为65%,虽然比10%高出许多,仍然属于比较低的准确率。在后面一篇文章重点对上面的过程进行改进,提高预测的准确性。

此外,值得一提的是,一开始,直接参考tensorflow官网给的例子进行训练会出现准确率为0的现象,观察TensorBord,发现权重和偏重一直不更新,打印W和b发现值为Nan,最后找到问题所在:

使用交叉熵作为cost function,由于文本矩阵为严重稀疏矩阵,导致出现y_ tf.log(y)结果为0log0的现象。导致训练参数为Nan,给预测值加一个极小的值,防止与测试为0。

雷锋网相关阅读:

一文详解如何用 TensorFlow 实现基于 LSTM 的文本分类(附源码)

手把手教你如何用 TensorFlow 实现基于 DNN 的文本分类


雷锋网

简单实用的 TensorFlow 实现 RNN 入门教程

雷锋网按:本文作者刘冲,原文载于作者个人博客,雷锋网已获授权。

最近在看RNN模型,为简单起见,本篇就以简单的二进制序列作为训练数据,而不实现具体的论文仿真,主要目的是理解RNN的原理和如何在TensorFlow中构造一个简单基础的模型架构。其中代码参考了这篇博客。

数据集

首先我们看一下实验数据的构造:

输入数据X:在时间t,Xt的值有50%的概率为1,50%的概率为0; 

输出数据Y:在实践t,Yt的值有50%的概率为1,50%的概率为0,除此之外,如果`Xt-3 == 1`,Yt为1的概率增加50%, 如果`Xt-8 == 1`,则Yt为1的概率减少25%, 如果上述两个条件同时满足,则Yt为1的概率为75%。

可知,Y与X有两个依赖关系,一个是t-3,一个是t-8。我们实验的目的就是检验RNN能否捕捉到Y与X之间的这两个依赖关系。实验使用交叉熵作为评价标准,则有下面三条理想的实验结果:

如果RNN没有学习到任何一条依赖,那么Yt为1的概率就是0.625(0.5+0.5*0.5-0.5*0.25),所以所获得的交叉熵应该是0.66(-(0.625 * np.log(0.625) + 0.375 * np.log(0.375)))。

如果RNN学习到第一条依赖关系,即Xt-3为1时Yt一定为1。那么,所以最终的交叉熵应该是0.52(-0.5 * (0.875 * np.log(0.875) + 0.125 * np.log(0.125)) -0.5 * (0.625 * np.log(0.625) + 0.375 * np.log(0.375)))。

如果RNN学习到了两条依赖, 那么有0.25的概率全对,0.5的概率正确率是75%,还有0.25的概率正确率是0.5。所以其交叉熵为0.45(-0.50 * (0.75 * np.log(0.75) + 0.25 * np.log(0.25)) – 0.25 * (2 * 0.50 * np.log (0.50)) – 0.25 * (0))。

数据预处理

这部分主要是生成实验数据,并将其按照RNN模型的输入格式进行切分和batch化。代码入下: 

1,生成实验数据:

def gen_data(size=100000):

    X = np.array(np.random.choice(2, size=(size,)))

    Y = []

    for i in range(size):

        threshold = 0.5

        #判断X[i-3]和X[i-8]是否为1,修改阈值

        if X[i-3] == 1:

            threshold += 0.5

        if X[i-8] == 1:

            threshold -= 0.25

        #生成随机数,以threshold为阈值给Yi赋值

        if np.random.rand() > threshold:

            Y.append(0)

        else:

            Y.append(1)

    return X, np.array(Y)

接下来将生成的数据按照模型参数设置进行切分,这里需要用得到的参数主要包括:batch_size和num_steps,分别是批量数据大小和RNN每层rnn_cell循环的次数,也就是下图中Sn中n的大小。代码入下:

def gen_batch(raw_data, batch_size, num_steps):

    #raw_data是使用gen_data()函数生成的数据,分别是X和Y

    raw_x, raw_y = raw_data

    data_length = len(raw_x)


    # 首先将数据切分成batch_size份,0-batch_size,batch_size-2*batch_size。。。

    batch_partition_length = data_length // batch_size

    data_x = np.zeros([batch_size, batch_partition_length], dtype=np.int32)

    data_y = np.zeros([batch_size, batch_partition_length], dtype=np.int32)

    for i in range(batch_size):

        data_x[i] = raw_x[batch_partition_length * i:batch_partition_length * (i + 1)]

        data_y[i] = raw_y[batch_partition_length * i:batch_partition_length * (i + 1)]


    #因为RNN模型一次只处理num_steps个数据,所以将每个batch_size在进行切分成epoch_size份,每份num_steps个数据。注意这里的epoch_size和模型训练过程中的epoch不同。 

    epoch_size = batch_partition_length // num_steps


    #x是0-num_steps, batch_partition_length -batch_partition_length +num_steps。。。共batch_size个

    for i in range(epoch_size):

        x = data_x[:, i * num_steps:(i + 1) * num_steps]

        y = data_y[:, i * num_steps:(i + 1) * num_steps]

        yield (x, y)


#这里的n就是训练过程中用的epoch,即在样本规模上循环的次数

def gen_epochs(n, num_steps):

    for i in range(n):

        yield gen_batch(gen_data(), batch_size, num_steps)

根据上面的代码我们可以看出来,这里的数据划分并没有将数据完全的按照原先的数据顺序,而是每隔一段取num_steps个数据,这样组成的batch进行训练==这里是为了省事还是另有原因还有待后面学习中考证。

模型构建

RNN的具体原理我们就不再进行赘述,主要是隐层状态和输入连接后计算新的隐层状态和输出。这里用的是单层的RNN。公式和原理图如下所示:

St=tanh(W(Xt @ St−1)+bs) 

Pt=softmax(USt+bp)

至于使用TensorFlow构建RNN模型,主要就是定义rnn_cell类型,然后将其复用即可。代码如下所示:

x = tf.placeholder(tf.int32, [batch_size, num_steps], name='input_placeholder')

y = tf.placeholder(tf.int32, [batch_size, num_steps], name='labels_placeholder')

#RNN的初始化状态,全设为零。注意state是与input保持一致,接下来会有concat操作,所以这里要有batch的维度。即每个样本都要有隐层状态

init_state = tf.zeros([batch_size, state_size])


#将输入转化为one-hot编码,两个类别。[batch_size, num_steps, num_classes]

x_one_hot = tf.one_hot(x, num_classes)

#将输入unstack,即在num_steps上解绑,方便给每个循环单元输入。这里可以看出RNN每个cell都处理一个batch的输入(即batch个二进制样本输入)

rnn_inputs = tf.unstack(x_one_hot, axis=1)


#定义rnn_cell的权重参数,

with tf.variable_scope('rnn_cell'):

    W = tf.get_variable('W', [num_classes + state_size, state_size])

    b = tf.get_variable('b', [state_size], initializer=tf.constant_initializer(0.0))

#使之定义为reuse模式,循环使用,保持参数相同

def rnn_cell(rnn_input, state):

    with tf.variable_scope('rnn_cell', reuse=True):

        W = tf.get_variable('W', [num_classes + state_size, state_size])

        b = tf.get_variable('b', [state_size], initializer=tf.constant_initializer(0.0))

    #定义rnn_cell具体的操作,这里使用的是最简单的rnn,不是LSTM

    return tf.tanh(tf.matmul(tf.concat([rnn_input, state], 1), W) + b)


state = init_state

rnn_outputs = []

#循环num_steps次,即将一个序列输入RNN模型

for rnn_input in rnn_inputs:

    state = rnn_cell(rnn_input, state)

    rnn_outputs.append(state)

final_state = rnn_outputs[-1]


#定义softmax层

with tf.variable_scope('softmax'):

    W = tf.get_variable('W', [state_size, num_classes])

    b = tf.get_variable('b', [num_classes], initializer=tf.constant_initializer(0.0))

#注意,这里要将num_steps个输出全部分别进行计算其输出,然后使用softmax预测

logits = [tf.matmul(rnn_output, W) + b for rnn_output in rnn_outputs]

predictions = [tf.nn.softmax(logit) for logit in logits]


# Turn our y placeholder into a list of labels

y_as_list = tf.unstack(y, num=num_steps, axis=1)


#losses and train_step

losses = [tf.nn.sparse_softmax_cross_entropy_with_logits(labels=label, logits=logit) for \

          logit, label in zip(logits, y_as_list)]

total_loss = tf.reduce_mean(losses)

train_step = tf.train.AdagradOptimizer(learning_rate).minimize(total_loss)

模型训练

定义好我们的模型之后,接下来就是将数据传入,然后进行训练,代码入下:

def train_network(num_epochs, num_steps, state_size=4, verbose=True):

    with tf.Session() as sess:

        sess.run(tf.global_variables_initializer())

        training_losses = []

        #得到数据,因为num_epochs==1,所以外循环只执行一次

        for idx, epoch in enumerate(gen_epochs(num_epochs, num_steps)):

            training_loss = 0

            #保存每次执行后的最后状态,然后赋给下一次执行

            training_state = np.zeros((batch_size, state_size))

            if verbose:

                print("\nEPOCH", idx)

            #这是具体获得数据的部分,应该会执行1000000//200//5 = 1000次,即每次执行传入的数据是batch_size*num_steps个(1000),共1000000个,所以每个num_epochs需要执行1000次。

            for step, (X, Y) in enumerate(epoch):

                tr_losses, training_loss_, training_state, _ = \

                    sess.run([losses,

                              total_loss,

                              final_state,

                              train_step],

                                  feed_dict={x:X, y:Y, init_state:training_state})

                training_loss += training_loss_

                if step % 100 == 0 and step > 0:

                    if verbose:

                        print("Average loss at step", step,

                              "for last 250 steps:", training_loss/100)

                    training_losses.append(training_loss/100)

                    training_loss = 0


    return training_losses

training_losses = train_network(1,num_steps)

plt.plot(training_losses)

plt.show()

实验结果如下所示: 

从上图可以看出交叉熵最终稳定在0。52,按照我们上面的分析可以知道:RNN模型成功的学习到了第一条依赖关系,因为我们的循环步长选择的是5,所以他只能学习到t-3的第一条依赖关系,而无法学习到t-8的第二条依赖。 
接下来可以尝试num_steps==10,区捕捉第二条依赖关系。最终的结果图如下所示: 

从上图可以看出,我们的RNN模型成功的学习到了两条依赖关系。最终的交叉熵未定在0.46附近。

几点改进

1,首先上面的代码中,为了尽可能详细的解释TensorFlow中RNN模型的构造方法,将rnn_cell的定义写的很详细,其实这些工作tf已经封装好了,我们只需要一行命令就可以实现,所以第一个要改进的地方就是将rnn_cell的定义和循环使用部分的代码简化:

#定义rnn_cell的权重参数,

with tf.variable_scope('rnn_cell'):

    W = tf.get_variable('W', [num_classes + state_size, state_size])

    b = tf.get_variable('b', [state_size], initializer=tf.constant_initializer(0.0))

#使之定义为reuse模式,循环使用,保持参数相同

def rnn_cell(rnn_input, state):

    with tf.variable_scope('rnn_cell', reuse=True):

        W = tf.get_variable('W', [num_classes + state_size, state_size])

        b = tf.get_variable('b', [state_size], initializer=tf.constant_initializer(0.0))

    #定义rnn_cell具体的操作,这里使用的是最简单的rnn,不是LSTM

    return tf.tanh(tf.matmul(tf.concat([rnn_input, state], 1), W) + b)


state = init_state

rnn_outputs = []

#循环num_steps次,即将一个序列输入RNN模型

for rnn_input in rnn_inputs:

    state = rnn_cell(rnn_input, state)

    rnn_outputs.append(state)

final_state = rnn_outputs[-1]


#———————-上面是原始代码,定义了rnn_cell,然后使用循环的方式对其进行复用,简化之后我们可以直接调用BasicRNNCell和static_rnn两个函数实现————————


cell = tf.contrib.rnn.BasicRNNCell(state_size)

rnn_outputs, final_state = tf.contrib.rnn.static_rnn(cell, rnn_inputs, initial_state=init_state)

2,使用动态rnn模型,上面的模型中,我们将输入表示成列表的形式,即rnn_inputs是一个长度为num_steps的列表,其中每个元素是[batch_size, features]的tensor(即每个rnn_cell要处理的数据),这样做事比较麻烦的,我们还可以使用tf提供的dynamic_rnn函数,这样做不仅会使编程更加简单,还可以提高计算效率。使用dynamic_rnn 时,我们直接将输入表示成[batch_size, num_steps, features]的三维Tensor即可。最终的动态RNN模型代码如下所示:

x = tf.placeholder(tf.int32, [batch_size, num_steps], name='input_placeholder')

y = tf.placeholder(tf.int32, [batch_size, num_steps], name='labels_placeholder')

init_state = tf.zeros([batch_size, state_size])


rnn_inputs = tf.one_hot(x, num_classes)

#注意这里去掉了这行代码,因为我们不需要将其表示成列表的形式在使用循环去做。

#rnn_inputs = tf.unstack(x_one_hot, axis=1)


cell = tf.contrib.rnn.BasicRNNCell(state_size)

#使用dynamic_rnn函数,动态构建RNN模型

rnn_outputs, final_state = tf.nn.dynamic_rnn(cell, rnn_inputs, initial_state=init_state)


with tf.variable_scope('softmax'):

    W = tf.get_variable('W', [state_size, num_classes])

    b = tf.get_variable('b', [num_classes], initializer=tf.constant_initializer(0.0))

logits = tf.reshape(

            tf.matmul(tf.reshape(rnn_outputs, [-1, state_size]), W) + b,

            [batch_size, num_steps, num_classes])

predictions = tf.nn.softmax(logits)


losses = tf.nn.sparse_softmax_cross_entropy_with_logits(labels=y, logits=logits)

total_loss = tf.reduce_mean(losses)

train_step = tf.train.AdagradOptimizer(learning_rate).minimize(total_loss)

至此,我们就实现了一个很简单的RNN模型的构造,在这个过程中,我们需要注意的主要有以下三点:

  • 如何将数据转化成rnn所能接受的输入格式,需要注意batch_size和num_steps之间的关系。

  • 定义rnn_cell,这里使用的是下面这条命令:cell = tf.contrib.rnn.BasicRNNCell(state_size)

  • 定义RNN模型,可以使用下面这两条命令分别静态和动态构建:

rnn_outputs, final_state = tf.contrib.rnn.static_rnn(cell, rnn_inputs, initial_state=init_state)

rnn_outputs, final_state = tf.nn.dynamic_rnn(cell, rnn_inputs, initial_state=init_state)

雷锋网(公众号:雷锋网)相关阅读:

从原理到实战 英伟达教你用PyTorch搭建RNN(上)

从原理到实战 英伟达教你用PyTorch搭建RNN(下)

雷锋网

微软发起 Minecraft AI 挑战赛;无缝支持 TensorFlow 的 Keras 2 等| AI 研习社周刊

又到周末。

休息之余,为大家奉上过去一周引发 AI 开发者圈子关注的那些事儿。大伙儿泡杯茶,坐在摇椅上,一起来看看在埋头工作的这个星期,外面的世界又有哪些变化。

 微软发起 Minecraft AI 挑战赛

本周,基于 Minecraft 上的知名 AI 技术研究测试平台 Project Malmo,微软发起了一项 AI 协作挑战赛:The Malmo Collaborative AI Challenge,目前已经开始注册报名。

比赛要求每支参赛队伍(最多 3 名队员)开发并训练一个 AI 软件产品。然后通过该软件产品参加一个名为 Pig Chase (小猪快跑)的小游戏。该游戏在 Minecraft 环境中展开,每局游戏有两名参赛者,一方为参赛队伍开发的 AI 软件产品,另一方为系统随机分配的队友,有可能是人类选手,也有可能是另一个队伍开发的 AI 软件。游戏一开始,参赛双方都有 25 分的原始积分,比赛要求双方在 25 步之内将一只小猪抓住,每走一步会减掉 1 分,最终抓住小猪双方各得 25 分,每轮比赛 10 局,最终累计得分高者获胜。

目前,关于 Pig Chase 的样例代码和详细说明已经公开在 GitHub 上:

https://github.com/Microsoft/malmo-challenge/blob/master/ai_challenge/pig_chase/README.md 

详情:http://www.leiphone.com/news/201703/yFsaEbO7oAoODl9g.html?type=preview 

 Keras 2 发布,无缝支持 TensorFlow 

在本次版本更新中,最重要的一项内容就是增强了 Keras 与 TensorFlow 的逻辑一致性。按照 Keras 在博客中的说法:“这是将 Keras API 整合到 TensorFlow 核心的一个重要的准备步骤”。

实际上,从 2015 年 12 月的版本开始,Keras 就已经支持用户将 TensorFlow 作为运行后端(runtime backend),但此前,Keras 的 API 与 TensorFlow 的代码库尚处于相互隔离的状态。未来,从 TensorFlow 1.2 版本开始,Keras 2 API 将作为 TensorFlow 框架的一部分直接向用户提供支持,Keras 在博客中表示:“这是 TensorFlow 实现下一个百万用户级目标的关键”。

详情:http://www.leiphone.com/news/201703/qjvnXzgYryMxs2xK.html 

 谷歌升级语义理解框架 SyntaxNet

这是 SyntaxNet 自诞生以来的最重大升级。这建立在谷歌对各语言的语义理解研究基础之上。此次升级的核心是一项新技术:能对输入语句的多层表示进行很好的学习。具体来讲,它延伸了 TensorFlow,能对多层语言结构进行合成建模,还能够在语句或文件处理过程中,动态地生成神经网络架构。

谷歌同时发布了新的预训练过的模型 ParseySaurus。它使用了基于字母的输入表示,因此极大提升了预测新词语含义的能力。这是基于两个方面来实现:词汇的拼写和在语境中的使用方式。雷锋网了解到,ParseySaurus 的准确率远远超出 Parsey's Cousins,错误率降低了 25%。由于语言的形态特性和其他属性,新模型在俄语、土耳其语、匈牙利语上的效果尤其好——这些语言中,同一个词汇有多种不同形态,其中许多形态从未在训练阶段出现过(即便是大型语料库)。

详情:http://www.leiphone.com/news/201703/9mP1ewE1EWivGPyc.html 

█ Cloudera 发布自助式数据开发工具

在圣何塞举行的 Strata+Hadoop World 大会上,美国大数据服务商 Cloudera 发布了 Cloudera Data Science Workbench —— 一个运行于 Cloudera Enterprise,自助式的数据科学开发环境。目前该全新研发的软件尚在 beta 内测阶段。

雷锋网获知,其相关技术来自于 Cloudera 去年收购的数据科学初创公司 Sense.io。该产品的最大特点是原生支持 Apache Spark、Hadoop 和 R、Python、Scala 等开发语言。 开发者能在 Cloudera 的企业平台上同时使用这些工具和语言,这将加速数据分析项目从研发到最终产品的过程。

详情:http://www.leiphone.com/news/201703/YTpa23qzTQBepxl5.html 

推荐深度阅读

█ 用数据说话:把自拍照变成毕加索名画 哪种算法最高效?

有位外国开发者根据 fast.ai 平台开设的深度学习代码实践课程,亲手实现了一个照片风格转换器,并对几种常见的优化算法的性能进行了综合对比,最终以图表加博客的方式记录下来。

作者比较了基于 CNN 的六种优化算法:梯度下降、Adadel、RMSProp、Adam、L-BFGS 和 Adagrad。雷锋网对全文进行了编译。

详情:http://www.leiphone.com/news/201703/Isacz6x6dDNQPDVW.html?type=preview 

雷锋网