机器学习之TFiwS

2018-10-02  本文已影响92人  Lin__Chuan

本文章里关于 TFiwS 原理的部分摘自莲叔的文章, 当然, 也可以直接查看 TFiwS 的白皮书.
本文章包括 原理篇 和 实例篇.

Google在2018年3月底公布了 Swift for TensorFlow, 目前已经开源. TensorFlow 在机器学习领域可以说是生态做的最好的, 已经满足了包括 Python, Java, Swift, Go, C等多种语言的支持.

一. 原理篇

为什么 TensorFlow 选择 Swift ?

Swift for TensorFLow 概览

Swift for TensorFlow 简称 TFiwS, 倒过来念就是 SwiFT.

TensorFlow 的两种模式.

import tensorflow as tf

x = tf.constant([[1,2,3], [4,5,6]])
xt = tf.transpose(x)
y = tf.matmul(x, xt)

with tf.Session() as sess:
    print sess.run(y)

图模式的一个重要特点是: Lazy Evaluation, 比如在执行 xt = tf.transpose(x) 的时候,实际上并没有触发矩阵转正的运算,而是只是生成了一个名为”转置”的运算节点,添加到了计算图中。最后,当执行 sess.run(y)的时候,所有计算才开始运行。

因此, 图模式的性能很强, 在计算时已经知道了所有的计算节点,可以做很多优化, 但是, 可用性很差, 先建图后计算的模式并不符合直觉,而且只能使用节点支持的运算来构建计算图. 在 Debug 的时候不能通过 print x 这样的形式来 debug 一些中间变量(执行到 print 的时候 x 还没有 value)

import tensorflow as tf
tf.enable_eager_execution()

x = tf.constant([[1,2,3],[4,5,6]])
y = tf.matmul(x, tf.transpose(x))
print(y)

Eager 模式与图相反,计算是立即发生的,整个过程并不会构建图。所以可以使用自然的流程控制,比如 if 语句来书写模型,也可以在执行的过程中插入 print x 来获取中间值,帮助我们 debug。

Eager 模式更符合直觉,易于理解,易于 debug。但因为没有 lazy,所以很难做优化,性能并不好。

新增的 TFiwS 模式

let x : Tensor<Float> = [[1,2,3], [4,5,6]]
var y = Tensor<Float>(zeros: x.shape)

print(y)
if x.sum() > 100{
    y = x
}else{
    y = x • x
}
print(y)

TFiwS 实现了一个改进版的 Swift 编译器,在编译阶段会自动分析代码中的 tensor 运算,并翻译成计算图,最终由 TensorFlow Runtime 运行计算图.

既然是以图的模式运行, 为什么又能像 Eager 模式这种能获取到中间值呢?

在上述代码中,

这里的 Runtime 不是指的 OC里面runtime机制 这种, 他就是指的在运行中.

那么这两种运行模式他们是怎么做数据交互的呢?

这里涉及到一个技术, Program Slicing, 程序切片.
我们来看一下这份代码, 在实际运行中, 是怎么利用程序切片的呢.

func linear(x : FloatTensor, w : FloatTensor, b : FloatTensor) -> FloatTensor
{
    let tmp = matmul(x, w)
    let tmp2 = tmp + b
    print(tmp2)
    let tmp3 = tmp2 * magicNumberGenerateFromTensor(x: tmp2)
    return tmp3
}

对于 Graph 部分
移除所有本地代码,然后针对两种情况做处理:

TensorFlow Runtime 运行的部分变成这样

func linear(x : FloatTensor, w : FloatTensor, b : FloatTensor) -> FloatTensor
{
    let tmp = matmul(x, w)
    let tmp2 = tmp + b
    //REMOVED: print(tmp2)
    tfop("send", tmp2)
    let result = tfop("receive")
    // REMOVED: magicNumberGenerateFromTensor(x: tmp2)
    let tmp3 = tmp2 * result
    return tmp3
}

对于非 tensor 逻辑部分

Swift Runtime 运行的部分变成这样.

func linear(x : FloatTensor, w : FloatTensor, b : FloatTensor) -> FloatTensor
{
    let tensorProgram = startTensorGraph(graphName: "GeneratedGraphName")
    //REMOVED: let tmp = matmul(x, w)
    //REMOVED: let tmp2 = tmp + b
    let tmp2 = receivedFromTensorFlow(tensorProgram)
    print(tmp2)
    let result = magicNumberGenerateFromTensor(x: tmp2)
    sendToTensorFlow(tensorProgram, result)
    let tmp3 = finishTensorGraph(handle: tensorProgram)
    //REMOVED: let tmp3 = tmp2 * magicNumberGenerateFromTensor(x: tmp2)
    return tmp3
}

从一份代码, 切片成两份, 将 graph 部分编译成图, 最终结果如图.

image.png

整个执行过程:

  1. 执行本地 startTensorGraph,触发图开始计算;
  2. TensorFlow Runtime 开始计算图;
  3. 计算完毕 wx + b 后,发现有SEND 节点,于是将结果发给本地;
  4. 本地代码收到结果,如代码所写, 执行 print;
  5. 本地代码调用函数,计算 magicNumber,并将结果发送给 TF Runtime;
  6. TF Runtime 收到 magic 后,开始结算最终的结果 tmp3 ,并发回到本地;
  7. 本地收到 tmp3 ,返回结果。

由此实现了: 写 eager 的代码,但跑起来具备图的性能,并且像 eager 模式一样支持本地的控制流程和用 print 进行 debug.

至于 SEND节点 和 RECV节点, 这是让TensorFlow 做分布式计算的, 在不同的机器上同步结果.

image.png

二. 实例篇

在 TensorFlow 的 Swift 项目里, 我们能看到关于 TFiwS 的全部内容, 包括原理, 安装方式, 运行方式, 作为一个开源没多久的项目, 在使用的过程中, 还是可能会出现各种奇怪的问题.

安装 TFiwS

$ export PATH=/Library/Developer/Toolchains/swift-latest/usr/bin:"${PATH}"

上面是在添加环境变量, 使之能快速访问到 Swift for TensorFlow toolchain.
到这里如果没问题的话, 就可以使用 TFiwS.

image.png

如果报错, 显示 找不到 TensorFlow.
解决办法:
swiftenv 环境管理工具看这里

1. 在 Terminal 中直接输入
$ /Library/Developer/Toolchains/swift-tensorflow-DEVELOPMENT-2018-09-17-a.xctoolchain/usr/bin/swift
进入 Swift 开发环境后, 输入 import TensorFlow, 
如果没报错, 就说明是 环境变量 的问题.

2. 解决环境变量问题, 安装 [swiftenv](https://swiftenv.fuller.li/en/latest/)
大部分人都应该使用过 Homebrew, 
安装, 以及 配置环境变量
$ brew install kylef/formulae/swiftenv
$ echo 'if which swiftenv > /dev/null; then eval "$(swiftenv init -)"; fi' >> ~/.bash_profile

3. 显示本机 Swift 版本
$ swiftenv versions

4. 添加我们新安装的 toolchain 全局可用.
$ swiftenv global tensorflow-DEVELOPMENT-2018-09-17-a 
如果以后想切换Swift版本也是同理

使用TFiwS
到这里我们基本上就可以使用 TFiwS 了, TFiwS官方提供了一个练手项目swift-models, 这里面有一个 MNIST 项目可以体验一下.


一些注意点

$ swift -O TFiwS_MNIST.swift
  1. 你创建的是 macOS 的 Command Line Tool 项目, 不是 Cocoa App 项目.
  2. 配置对应项目的编译系统, 进入 Xcode , File -> Project Settings -> Build System -> 选择 legacy Build System
  3. 在对应项目的 target 里, 设置 Build Settings
    3.1. 设置 Optimization Level

Build Settings → Swift Compiler-Code Generation → Optimization Level


3.2. 添加 tensorflow 静态库.
在上面我们能找到新安装的 toolchain 的文件目录, 打开包内容, 在这个目录下, 直接拖 libtensorflow.solibtensorflow_framework.soLinked Frameworks and Libraries

General -> Linked Frameworks and Libraries

/Library/Developer/Toolchains/xxxxx.xctoolchain/usr/lib/swift/macosx

3.3. 改变 Runtime Search Paths

Build Settings → Linking → Runpath Search Path:
这里我们可以直接添加

/Library/Developer/Toolchains/swift-latest/usr/lib/swift/macosx

2.4. 设置 -lpython
Built Setting -> linking -> Other Linker Flags 添加 -lpython

设置完, 就可以 Xcode 编写 TF 代码, 有代码提示.

swift -O xx.swift

如果直接使用 Playground 是不需要添加 libtensorflow.solibtensorflow_framework.so 这些操作的, 只需要修改 toolchain , 出现 一个蓝色铁索 的图标就可以保证编写代码时自带提示了.

如果你需要在 jupyter notebook 里使用 TFiwS. 文档请参考这里, 这里有几点注意.

python register.py --sys-prefix --swift-toolchain <path to extracted swift toolchain directory>
image.png

详解 人工神经网络

请看这里

上一篇 下一篇

猜你喜欢

热点阅读