机器学习之TFiwS

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

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

一. 原理篇

为什么 TensorFlow 选择 Swift ?

  • Swift 开源, 性能高, 本身是静态语言, 比较安全, 而且它开发效率高.
  • Swift for TensorFlow 设计总览这篇文章里, 详细介绍了 TFiwS 的主要组成部分以及结合方式, TensorFlow 通过 Graph Program Extraction 算法, 可以让开发者用 Eager Execution 式的编程模型来实现代码,同时保留 TensorFlow 计算图的高性能优势, 由于实现可靠的 Graph Program Extraction 算法对于编程语言的设计有很高的要求, 所以选择了 Swift.

Swift for TensorFLow 概览

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

TensorFlow 的两种模式.

  • 图模式(Graph Mode)
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)

  • 快速执行模式(Eager Execution)
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 模式这种能获取到中间值呢?

在上述代码中,

  • 可以理解为与 Tensor 类相关的操作都是 tensor 逻辑, 最终会生成图, 这一部分有 TensorFlow Runtime 执行, (在显存中计算)
  • 而代码中非 tensor 逻辑 则是由 Swift Runtime 执行.(本地计算)

这里的 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 部分
移除所有本地代码,然后针对两种情况做处理:

  • 如果本地代码依赖图代码的结果,则插入 tfop(“send”, 用于指明这一步需要将结果发送给本地代码;
  • 如果图代码依赖本地代码,则插入 tfop("receive"), 用于接受本地代码发过来的结果

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 逻辑部分

  • 删除图相关代码,针对依赖/被依赖的部分插入 send/receive 操作,
  • 区别只是需要在开头插入启动图代码,以及最终从图的部分拿到结果返回。

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

  • 这个界面, 下载最新的预编译包, 如果你的显卡是N卡, 带有GPU的话, 可以选择安装 Xcode 10 (CUDA GPU), 为了简便, 也可以只安装普通版. 下面的步骤是针对普通版的.

  • 安装成功后, 我们可在这个文件夹里看到我们安装的 toolchain.
    /Library/Developer/Toolchains/

  • 这个 toolchain 里包括 Swift 编译器, lldb, 以及其他相关工具的副本, 可以用来运行 TensorFlow 相关的项目.

  • 在 Xcode -> Preferences -> Components -> Toolchains, 可以看到我们安装的 toolchain. 鼠标右键对应的 toolchain, 可以查看原目录.


    image.png
  • 为了能在 Terminal 里能使用 Swift toolchain, 我们这样做

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

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

  • 在 Terminal 中, 直接输入 swift, 如果没报错, 就OK了.
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 项目可以体验一下.


一些注意点

  • 我们安装的这个 toolchain 只支持 macOS开发, 不支持iOS/tvOS/watchOS.
  • 我们可以使用 Swift Playground 编写代码, 为了编译不报错, 我们需要切换 toolchain, 如果你使用的不是 Xcode 的默认 toolchain, 会有一个锁链的图标.


    image.png

    .

  • Playground 里面写的代码只会有代码提示, 是不能直接运行的. 我目前是这样. 要运行我们写的代码, 直接在对应的文件目录下
$ swift -O TFiwS_MNIST.swift
  • 如果你想在 Xcode 里面写自己的 TensorFlow 代码, 需要配置 Xcode 项目. 可以参考官方的 instructions
    有几点需要注意:
  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. 文档请参考这里, 这里有几点注意.

  • 目前只支持 python2 环境下运行, 强烈建议安装 Anaconda 大礼包, 很方便管理环境.
  • 创建完 python2 的环境后, 激活环境, source activate env_name
  • 按照前面的官方文档安装第三方库, 包括 ipykernel pandas matplotlib numpy.
  • 将项目 clone 到本地后, 进入到 register.py 所在目录下. 执行以下命令, register.py 里面是一些脚本指令
python register.py --sys-prefix --swift-toolchain <path to extracted swift toolchain directory>
image.png
  • 如果你一时找不到 toolchain 的目录, 可以 直接在 Xcode 里偏好设置里面, 找到 Components里面 toolchain 一栏, 鼠标右键可以查找 show in Finder.

详解 人工神经网络

请看这里

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容

  • 1、通过CocoaPods安装项目名称项目信息 AFNetworking网络请求组件 FMDB本地数据库组件 SD...
    阳明先生x阅读 15,967评论 3 119
  • 老早老早以前,版本更新代码里有一个 VersionManager 类,管理的所有的一切,也曾在那基础上新增需求。只...
    进击的杰爷阅读 394评论 0 0
  • 葡萄沟的葡萄熟了 路边的高梁大豆熟了 棚里的黄瓜青椒熟了 架上的吊瓜熟了 收获的季节 秋天的田野 已经沸腾 沿着一...
    贾玉红阅读 485评论 0 2
  • 11月4号,星期六,是全国中级经济师职称考试的日子。晚上下了班之后,一路的到考点附近,40分钟,28公里。临考前2...
    晚间一壶茶阅读 129评论 0 2