機(jī)器學(xué)習(xí)之TFiwS

本文章里關(guān)于 TFiwS 原理的部分摘自蓮叔的文章, 當(dāng)然, 也可以直接查看 TFiwS 的白皮書.
本文章包括 原理篇 和 實(shí)例篇.

Google在2018年3月底公布了 Swift for TensorFlow, 目前已經(jīng)開源. TensorFlow 在機(jī)器學(xué)習(xí)領(lǐng)域可以說是生態(tài)做的最好的, 已經(jīng)滿足了包括 Python, Java, Swift, Go, C等多種語言的支持.

一. 原理篇

為什么 TensorFlow 選擇 Swift ?

  • Swift 開源, 性能高, 本身是靜態(tài)語言, 比較安全, 而且它開發(fā)效率高.
  • Swift for TensorFlow 設(shè)計(jì)總覽這篇文章里, 詳細(xì)介紹了 TFiwS 的主要組成部分以及結(jié)合方式, TensorFlow 通過 Graph Program Extraction 算法, 可以讓開發(fā)者用 Eager Execution 式的編程模型來實(shí)現(xiàn)代碼唠椭,同時(shí)保留 TensorFlow 計(jì)算圖的高性能優(yōu)勢, 由于實(shí)現(xiàn)可靠的 Graph Program Extraction 算法對于編程語言的設(shè)計(jì)有很高的要求, 所以選擇了 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)

圖模式的一個(gè)重要特點(diǎn)是: Lazy Evaluation, 比如在執(zhí)行 xt = tf.transpose(x) 的時(shí)候服协,實(shí)際上并沒有觸發(fā)矩陣轉(zhuǎn)正的運(yùn)算榛臼,而是只是生成了一個(gè)名為”轉(zhuǎn)置”的運(yùn)算節(jié)點(diǎn)唬格,添加到了計(jì)算圖中偏陪。最后,當(dāng)執(zhí)行 sess.run(y)的時(shí)候瞧哟,所有計(jì)算才開始運(yùn)行并闲。

因此, 圖模式的性能很強(qiáng), 在計(jì)算時(shí)已經(jīng)知道了所有的計(jì)算節(jié)點(diǎn),可以做很多優(yōu)化, 但是, 可用性很差, 先建圖后計(jì)算的模式并不符合直覺八毯,而且只能使用節(jié)點(diǎn)支持的運(yùn)算來構(gòu)建計(jì)算圖. 在 Debug 的時(shí)候不能通過 print x 這樣的形式來 debug 一些中間變量(執(zhí)行到 print 的時(shí)候 x 還沒有 value)

  • 快速執(zhí)行模式(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 模式與圖相反搓侄,計(jì)算是立即發(fā)生的,整個(gè)過程并不會構(gòu)建圖话速。所以可以使用自然的流程控制讶踪,比如 if 語句來書寫模型,也可以在執(zhí)行的過程中插入 print x 來獲取中間值泊交,幫助我們 debug乳讥。

Eager 模式更符合直覺柱查,易于理解,易于 debug云石。但因?yàn)闆]有 lazy唉工,所以很難做優(yōu)化,性能并不好汹忠。

新增的 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 實(shí)現(xiàn)了一個(gè)改進(jìn)版的 Swift 編譯器淋硝,在編譯階段會自動(dòng)分析代碼中的 tensor 運(yùn)算,并翻譯成計(jì)算圖宽菜,最終由 TensorFlow Runtime 運(yùn)行計(jì)算圖.

既然是以圖的模式運(yùn)行, 為什么又能像 Eager 模式這種能獲取到中間值呢?

在上述代碼中,

  • 可以理解為與 Tensor 類相關(guān)的操作都是 tensor 邏輯, 最終會生成圖, 這一部分有 TensorFlow Runtime 執(zhí)行, (在顯存中計(jì)算)
  • 而代碼中非 tensor 邏輯 則是由 Swift Runtime 執(zhí)行.(本地計(jì)算)

這里的 Runtime 不是指的 OC里面runtime機(jī)制 這種, 他就是指的在運(yùn)行中.

那么這兩種運(yùn)行模式他們是怎么做數(shù)據(jù)交互的呢?

這里涉及到一個(gè)技術(shù), Program Slicing, 程序切片.
我們來看一下這份代碼, 在實(shí)際運(yùn)行中, 是怎么利用程序切片的呢.

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 部分
移除所有本地代碼谣膳,然后針對兩種情況做處理:

  • 如果本地代碼依賴圖代碼的結(jié)果,則插入 tfop(“send”, 用于指明這一步需要將結(jié)果發(fā)送給本地代碼铅乡;
  • 如果圖代碼依賴本地代碼继谚,則插入 tfop("receive"), 用于接受本地代碼發(fā)過來的結(jié)果

TensorFlow Runtime 運(yùn)行的部分變成這樣

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 邏輯部分

  • 刪除圖相關(guān)代碼,針對依賴/被依賴的部分插入 send/receive 操作阵幸,
  • 區(qū)別只是需要在開頭插入啟動(dòng)圖代碼花履,以及最終從圖的部分拿到結(jié)果返回。

Swift Runtime 運(yùn)行的部分變成這樣.

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 部分編譯成圖, 最終結(jié)果如圖.

image.png

整個(gè)執(zhí)行過程:

  1. 執(zhí)行本地 startTensorGraph挚赊,觸發(fā)圖開始計(jì)算诡壁;
  2. TensorFlow Runtime 開始計(jì)算圖;
  3. 計(jì)算完畢 wx + b 后荠割,發(fā)現(xiàn)有SEND 節(jié)點(diǎn)欢峰,于是將結(jié)果發(fā)給本地;
  4. 本地代碼收到結(jié)果涨共,如代碼所寫纽帖, 執(zhí)行 print;
  5. 本地代碼調(diào)用函數(shù),計(jì)算 magicNumber举反,并將結(jié)果發(fā)送給 TF Runtime懊直;
  6. TF Runtime 收到 magic 后,開始結(jié)算最終的結(jié)果 tmp3 火鼻,并發(fā)回到本地室囊;
  7. 本地收到 tmp3 ,返回結(jié)果魁索。

由此實(shí)現(xiàn)了: 寫 eager 的代碼融撞,但跑起來具備圖的性能,并且像 eager 模式一樣支持本地的控制流程和用 print 進(jìn)行 debug.

至于 SEND節(jié)點(diǎn) 和 RECV節(jié)點(diǎn), 這是讓TensorFlow 做分布式計(jì)算的, 在不同的機(jī)器上同步結(jié)果.

image.png

二. 實(shí)例篇

在 TensorFlow 的 Swift 項(xiàng)目里, 我們能看到關(guān)于 TFiwS 的全部內(nèi)容, 包括原理, 安裝方式, 運(yùn)行方式, 作為一個(gè)開源沒多久的項(xiàng)目, 在使用的過程中, 還是可能會出現(xiàn)各種奇怪的問題.

安裝 TFiwS

  • 這個(gè)界面, 下載最新的預(yù)編譯包, 如果你的顯卡是N卡, 帶有GPU的話, 可以選擇安裝 Xcode 10 (CUDA GPU), 為了簡便, 也可以只安裝普通版. 下面的步驟是針對普通版的.

  • 安裝成功后, 我們可在這個(gè)文件夾里看到我們安裝的 toolchain.
    /Library/Developer/Toolchains/

  • 這個(gè) toolchain 里包括 Swift 編譯器, lldb, 以及其他相關(guān)工具的副本, 可以用來運(yùn)行 TensorFlow 相關(guān)的項(xiàng)目.

  • 在 Xcode -> Preferences -> Components -> Toolchains, 可以看到我們安裝的 toolchain. 鼠標(biāo)右鍵對應(yīng)的 toolchain, 可以查看原目錄.


    image.png
  • 為了能在 Terminal 里能使用 Swift toolchain, 我們這樣做

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

上面是在添加環(huán)境變量, 使之能快速訪問到 Swift for TensorFlow toolchain.
到這里如果沒問題的話, 就可以使用 TFiwS.

  • 在 Terminal 中, 直接輸入 swift, 如果沒報(bào)錯(cuò), 就OK了.
image.png

如果報(bào)錯(cuò), 顯示 找不到 TensorFlow.
解決辦法:
swiftenv 環(huán)境管理工具看這里

1. 在 Terminal 中直接輸入
$ /Library/Developer/Toolchains/swift-tensorflow-DEVELOPMENT-2018-09-17-a.xctoolchain/usr/bin/swift
進(jìn)入 Swift 開發(fā)環(huán)境后, 輸入 import TensorFlow, 
如果沒報(bào)錯(cuò), 就說明是 環(huán)境變量 的問題.

2. 解決環(huán)境變量問題, 安裝 [swiftenv](https://swiftenv.fuller.li/en/latest/)
大部分人都應(yīng)該使用過 Homebrew, 
安裝, 以及 配置環(huán)境變量
$ brew install kylef/formulae/swiftenv
$ echo 'if which swiftenv > /dev/null; then eval "$(swiftenv init -)"; fi' >> ~/.bash_profile

3. 顯示本機(jī) Swift 版本
$ swiftenv versions

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

使用TFiwS
到這里我們基本上就可以使用 TFiwS 了, TFiwS官方提供了一個(gè)練手項(xiàng)目swift-models, 這里面有一個(gè) MNIST 項(xiàng)目可以體驗(yàn)一下.


一些注意點(diǎn)

  • 我們安裝的這個(gè) toolchain 只支持 macOS開發(fā), 不支持iOS/tvOS/watchOS.
  • 我們可以使用 Swift Playground 編寫代碼, 為了編譯不報(bào)錯(cuò), 我們需要切換 toolchain, 如果你使用的不是 Xcode 的默認(rèn) toolchain, 會有一個(gè)鎖鏈的圖標(biāo).


    image.png

    .

  • Playground 里面寫的代碼只會有代碼提示, 是不能直接運(yùn)行的. 我目前是這樣. 要運(yùn)行我們寫的代碼, 直接在對應(yīng)的文件目錄下
$ swift -O TFiwS_MNIST.swift
  • 如果你想在 Xcode 里面寫自己的 TensorFlow 代碼, 需要配置 Xcode 項(xiàng)目. 可以參考官方的 instructions
    有幾點(diǎn)需要注意:
  1. 你創(chuàng)建的是 macOS 的 Command Line Tool 項(xiàng)目, 不是 Cocoa App 項(xiàng)目.
  2. 配置對應(yīng)項(xiàng)目的編譯系統(tǒng), 進(jìn)入 Xcode , File -> Project Settings -> Build System -> 選擇 legacy Build System
  3. 在對應(yīng)項(xiàng)目的 target 里, 設(shè)置 Build Settings
    3.1. 設(shè)置 Optimization Level

Build Settings → Swift Compiler-Code Generation → Optimization Level


3.2. 添加 tensorflow 靜態(tài)庫.
在上面我們能找到新安裝的 toolchain 的文件目錄, 打開包內(nèi)容, 在這個(gè)目錄下, 直接拖 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. 設(shè)置 -lpython
Built Setting -> linking -> Other Linker Flags 添加 -lpython

設(shè)置完, 就可以 Xcode 編寫 TF 代碼, 有代碼提示.

swift -O xx.swift

如果直接使用 Playground 是不需要添加 libtensorflow.solibtensorflow_framework.so 這些操作的, 只需要修改 toolchain , 出現(xiàn) 一個(gè)藍(lán)色鐵索 的圖標(biāo)就可以保證編寫代碼時(shí)自帶提示了.

如果你需要在 jupyter notebook 里使用 TFiwS. 文檔請參考這里, 這里有幾點(diǎn)注意.

  • 目前只支持 python2 環(huán)境下運(yùn)行, 強(qiáng)烈建議安裝 Anaconda 大禮包, 很方便管理環(huán)境.
  • 創(chuàng)建完 python2 的環(huán)境后, 激活環(huán)境, source activate env_name
  • 按照前面的官方文檔安裝第三方庫, 包括 ipykernel pandas matplotlib numpy.
  • 將項(xiàng)目 clone 到本地后, 進(jìn)入到 register.py 所在目錄下. 執(zhí)行以下命令, register.py 里面是一些腳本指令
python register.py --sys-prefix --swift-toolchain <path to extracted swift toolchain directory>
image.png
  • 如果你一時(shí)找不到 toolchain 的目錄, 可以 直接在 Xcode 里偏好設(shè)置里面, 找到 Components里面 toolchain 一欄, 鼠標(biāo)右鍵可以查找 show in Finder.

詳解 人工神經(jīng)網(wǎng)絡(luò)

請看這里

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末粗蔚,一起剝皮案震驚了整個(gè)濱河市尝偎,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖致扯,帶你破解...
    沈念sama閱讀 218,036評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件肤寝,死亡現(xiàn)場離奇詭異,居然都是意外死亡抖僵,警方通過查閱死者的電腦和手機(jī)鲤看,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來耍群,“玉大人义桂,你說我怎么就攤上這事〉腹福” “怎么了澡刹?”我有些...
    開封第一講書人閱讀 164,411評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長耘婚。 經(jīng)常有香客問我,道長陆赋,這世上最難降的妖魔是什么沐祷? 我笑而不...
    開封第一講書人閱讀 58,622評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮攒岛,結(jié)果婚禮上赖临,老公的妹妹穿的比我還像新娘。我一直安慰自己灾锯,他們只是感情好兢榨,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,661評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著顺饮,像睡著了一般吵聪。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上兼雄,一...
    開封第一講書人閱讀 51,521評論 1 304
  • 那天吟逝,我揣著相機(jī)與錄音,去河邊找鬼赦肋。 笑死块攒,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的佃乘。 我是一名探鬼主播囱井,決...
    沈念sama閱讀 40,288評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼趣避!你這毒婦竟也來了庞呕?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,200評論 0 276
  • 序言:老撾萬榮一對情侶失蹤程帕,失蹤者是張志新(化名)和其女友劉穎千扶,沒想到半個(gè)月后料祠,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,644評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡澎羞,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,837評論 3 336
  • 正文 我和宋清朗相戀三年髓绽,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片妆绞。...
    茶點(diǎn)故事閱讀 39,953評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡顺呕,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出括饶,到底是詐尸還是另有隱情株茶,我是刑警寧澤,帶...
    沈念sama閱讀 35,673評論 5 346
  • 正文 年R本政府宣布图焰,位于F島的核電站启盛,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏技羔。R本人自食惡果不足惜僵闯,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,281評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望藤滥。 院中可真熱鬧鳖粟,春花似錦、人聲如沸拙绊。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽标沪。三九已至榄攀,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間金句,已是汗流浹背航攒。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留趴梢,地道東北人漠畜。 一個(gè)月前我還...
    沈念sama閱讀 48,119評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像坞靶,于是被迫代替她去往敵國和親憔狞。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,901評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 1彰阴、通過CocoaPods安裝項(xiàng)目名稱項(xiàng)目信息 AFNetworking網(wǎng)絡(luò)請求組件 FMDB本地?cái)?shù)據(jù)庫組件 SD...
    陽明先生_X自主閱讀 15,980評論 3 119
  • 老早老早以前瘾敢,版本更新代碼里有一個(gè) VersionManager 類,管理的所有的一切,也曾在那基礎(chǔ)上新增需求簇抵。只...
    進(jìn)擊的杰爺閱讀 403評論 0 0
  • 葡萄溝的葡萄熟了 路邊的高梁大豆熟了 棚里的黃瓜青椒熟了 架上的吊瓜熟了 收獲的季節(jié) 秋天的田野 已經(jīng)沸騰 沿著一...
    賈玉紅閱讀 495評論 0 2
  • 11月4號碟摆,星期六晃财,是全國中級經(jīng)濟(jì)師職稱考試的日子。晚上下了班之后典蜕,一路的到考點(diǎn)附近断盛,40分鐘,28公里愉舔。臨考前2...
    晚間一壺茶閱讀 133評論 0 2