與 TensorFlow 的初次相遇
https://jorditorres.org/wp-content/uploads/2016/02/TensorFlowBookCover.png
譯者:飛龍
協(xié)議:CC BY-NC-SA 4.0
前言一
由于計(jì)算,海量數(shù)據(jù)存儲(chǔ)和互聯(lián)網(wǎng)技術(shù)等關(guān)鍵領(lǐng)域的共同發(fā)展墅冷,機(jī)器學(xué)習(xí)領(lǐng)域呈現(xiàn)了巨大的發(fā)展酒奶。許多人的日常生活中的許多技術(shù)和事件崎岂,直接或間接地受到自動(dòng)學(xué)習(xí)的影響瘦穆。語(yǔ)音識(shí)別抡柿,手機(jī)上的圖像分類(lèi)或垃圾郵件檢測(cè)等技術(shù)的例子,使得一些應(yīng)用成為可能爵赵,它們只出現(xiàn)在十年前科幻小說(shuō)中吝秕。股票市場(chǎng)模型或醫(yī)療模型中的學(xué)習(xí)的使用,對(duì)我們的社會(huì)產(chǎn)生了巨大的影響空幻。此外烁峭,具有巡航控制,無(wú)人機(jī)和各種機(jī)器人的汽車(chē)將在不久的將來(lái)影響社會(huì)秕铛。
深度學(xué)習(xí)是機(jī)器學(xué)習(xí)的一個(gè)子類(lèi)型约郁,自 2006 年重新發(fā)現(xiàn)以來(lái),無(wú)疑是爆發(fā)性擴(kuò)張的領(lǐng)域之一但两。事實(shí)上鬓梅,硅谷的許多創(chuàng)業(yè)公司都專(zhuān)注于此,而谷歌谨湘,F(xiàn)acebook绽快,微軟或 IBM 等大型科技公司都有開(kāi)發(fā)和研究團(tuán)隊(duì)芥丧。深度學(xué)習(xí)甚至引起了大學(xué)之外和研究領(lǐng)域的興趣:許多專(zhuān)業(yè)雜志(如 Wired)甚至是通用雜志(如紐約時(shí)報(bào),Bloomberg 或 BBC)為這個(gè)主題撰寫(xiě)了很多文章坊罢。
這種興趣促使許多學(xué)生娄柳,企業(yè)家和投資者加入深度學(xué)習(xí)。由于產(chǎn)生的所有興趣艘绍,幾個(gè)軟件包已被制作成“開(kāi)源”的赤拒。作為庫(kù)的主要推動(dòng)者之一,我們?cè)?2012 年作為博士生在伯克利(Caffe)開(kāi)發(fā)了它诱鞠。我可以說(shuō)挎挖,TensorFlow 將成為研究人員和中小企業(yè)公司用于實(shí)現(xiàn)他們的深度學(xué)習(xí)和機(jī)器學(xué)習(xí)的想法的主要工具之一,它出現(xiàn)在本書(shū)中并由 Google(加州)設(shè)計(jì)航夺,我自 2013 年以來(lái)一直在那里研究它蕉朵。對(duì)此的保證是參與該項(xiàng)目的工程師和頂尖研究人員的數(shù)量,它最終得到了開(kāi)源阳掐。
我希望這本入門(mén)書(shū)能夠幫助有興趣在這個(gè)非常有趣的領(lǐng)域開(kāi)始冒險(xiǎn)的讀者始衅。我要感謝作者,我很高興了解到它傳播這項(xiàng)技術(shù)的努力缭保。在開(kāi)源項(xiàng)目發(fā)布兩個(gè)月后汛闸,他在創(chuàng)紀(jì)錄的時(shí)間內(nèi)寫(xiě)了這本書(shū)(首先是西班牙語(yǔ)版本)侈净。這是巴塞羅那活力的另一個(gè)例子齐婴,它有興趣成為這一技術(shù)場(chǎng)景中的參與者之一,無(wú)疑將影響我們的未來(lái)宗雇。
Oriol Vinyals钳恕,Google Brain 的研究科學(xué)家
前言二
教育是你用來(lái)改變世界的最有力的武器别伏。
Nelson Mandela
本書(shū)的目的是有助于將這些知識(shí)轉(zhuǎn)播給工程師,它們希望在激動(dòng)人心的機(jī)器學(xué)習(xí)世界中擴(kuò)展智慧忧额。我相信任何具有工程背景的人都可能會(huì)發(fā)現(xiàn)厘肮,深度學(xué)習(xí)和機(jī)器學(xué)習(xí)的應(yīng)用對(duì)他們的工作很有價(jià)值。
鑒于我的背景睦番,讀者可能會(huì)想知道為什么我提出了編寫(xiě)這種新的深度學(xué)習(xí)技術(shù)的挑戰(zhàn)类茂。我的研究重點(diǎn)是逐步從超級(jí)計(jì)算架構(gòu)和運(yùn)行時(shí)轉(zhuǎn)向大數(shù)據(jù)工作負(fù)載的執(zhí)行中間件,最近轉(zhuǎn)向大規(guī)模數(shù)據(jù)的機(jī)器學(xué)習(xí)平臺(tái)抡砂。
正是作為一名工程師大咱,而不是數(shù)據(jù)科學(xué)家,我認(rèn)為我可以為這一主題貢獻(xiàn)這種介紹性的方法注益,并且它對(duì)早期階段的許多工程師都有幫助;然后他們會(huì)選擇深入了解他們的需求溯捆。
我希望這本書(shū)能為這個(gè)我非常喜愛(ài)的教育世界增添一些價(jià)值丑搔。我認(rèn)為知識(shí)就是解放厦瓢,應(yīng)該讓所有人都能獲得。因此啤月,本書(shū)的內(nèi)容將在網(wǎng)站 www.JordiTorres.eu/TensorFlow 上完全免費(fèi)提供煮仇。如果讀者發(fā)現(xiàn)內(nèi)容有用并認(rèn)為適當(dāng)補(bǔ)償作者的寫(xiě)作,網(wǎng)站上有一個(gè)標(biāo)簽可以用于捐贈(zèng)谎仲。另一方面浙垫,如果讀者更喜歡選擇紙質(zhì)副本,你可以通過(guò) Amazon.com 購(gòu)買(mǎi)該書(shū)郑诺。
本書(shū)還提供西班牙語(yǔ)版本夹姥。事實(shí)上,這本書(shū)是西班牙語(yǔ)的翻譯辙诞,該書(shū)于去年 1 月完成,并在 GEMLeB Meetup(Grup d'Estudi de Machine Learning de Barcelona)中展示曹铃,我是其中一個(gè)共同組織者忍坷。
感謝你閱讀本書(shū)旬薯!它使我感到安慰,并證明了我寫(xiě)作的努力娱挨。那些了解我的人碉碉,知道技術(shù)傳播是我的激情之一。它激勵(lì)我繼續(xù)學(xué)習(xí)蜡吧。
Jordi Torres,2016 年 2 月
一種實(shí)用的方法
告訴我返咱,我會(huì)忘記钥庇。教我,我會(huì)記得咖摹。讓我參與评姨,我會(huì)學(xué)習(xí)。
本杰明·富蘭克林
深度學(xué)習(xí)的一個(gè)常見(jiàn)應(yīng)用包括模式識(shí)別楞艾。因此参咙,當(dāng)你開(kāi)始編程時(shí)龄广,有個(gè)傳統(tǒng)是打印“Hello World”硫眯,與它相同蕴侧,在深度學(xué)習(xí)中,通常構(gòu)造用于識(shí)別手寫(xiě)數(shù)字的模型 [1]两入。我將提供的第一個(gè)神經(jīng)網(wǎng)絡(luò)示例净宵,也將允許我介紹這種名為 TensorFlow 的新技術(shù)。
但是裹纳,我不打算寫(xiě)一本關(guān)于機(jī)器學(xué)習(xí)或深度學(xué)習(xí)的研究書(shū)籍择葡,我只想盡快為每個(gè)人提供這個(gè)新的機(jī)器學(xué)習(xí)軟件包 TensorFlow。因此剃氧,我向我的數(shù)據(jù)科學(xué)家們道歉敏储,為了與普通讀者分享這些知識(shí),我允許自己進(jìn)行某些簡(jiǎn)化朋鞍。
讀者會(huì)在這里找到我在課堂上使用的常規(guī)結(jié)構(gòu)已添;這會(huì)邀請(qǐng)你在學(xué)習(xí)的同時(shí)使用計(jì)算機(jī)的鍵盤(pán)。我們稱(chēng)之為“從實(shí)踐中學(xué)習(xí)”滥酥,而我作為 UPC 教授的經(jīng)歷告訴我更舞,這種方法對(duì)于嘗試開(kāi)始新主題的工程師來(lái)說(shuō)非常有效。
出于這個(gè)原因坎吻,這本書(shū)具有實(shí)用性缆蝉,因此我盡可能地減少了理論部分。然而瘦真,當(dāng)學(xué)習(xí)過(guò)程需要時(shí)刊头,文本中已包含某些數(shù)學(xué)細(xì)節(jié)。
我假設(shè)讀者對(duì)機(jī)器學(xué)習(xí)有一些基本的理解诸尽,所以我將使用一些流行的算法逐步組織讀者在 TensorFlow 中的訓(xùn)練原杂。
在第一章中,除了介紹TensorFlow將扮演重要角色的場(chǎng)景之外弦讽,我還借此機(jī)會(huì)解釋TensorFlow程序的基本結(jié)構(gòu)污尉,并簡(jiǎn)要解釋它在內(nèi)部維護(hù)的數(shù)據(jù)。
在第二章中往产,通過(guò)線性回歸的一個(gè)例子被碗,我將介紹一些代碼基礎(chǔ)知識(shí),同時(shí)仿村,如何調(diào)用學(xué)習(xí)過(guò)程中的各種重要組件锐朴,如損失函數(shù)或梯度下降優(yōu)化算法。
在第三章中蔼囊,我展示了一個(gè)聚類(lèi)算法焚志,我將詳細(xì)介紹 TensorFlow 的基本數(shù)據(jù)結(jié)構(gòu)衣迷,稱(chēng)為tensor
(張量),以及 TensorFlow 包提供的用于創(chuàng)建和管理張量的不同類(lèi)和函數(shù)酱酬。
第四章詳細(xì)介紹了如何構(gòu)建識(shí)別手寫(xiě)數(shù)字的單層神經(jīng)網(wǎng)絡(luò)壶谒。這將允許我們歸納上面提出的所有概念,以及查看創(chuàng)建和測(cè)試模型的整個(gè)過(guò)程膳沽。
下一章首先介紹基于前一章中所見(jiàn)的神經(jīng)網(wǎng)絡(luò)概念汗菜,并介紹如何構(gòu)建多層神經(jīng)網(wǎng)絡(luò)來(lái)獲得更好的手寫(xiě)數(shù)字識(shí)別結(jié)果。它將更詳細(xì)地介紹所謂的卷積神經(jīng)網(wǎng)絡(luò)挑社。
在第六章中陨界,我們將討論一個(gè)更具體的問(wèn)題,利用 GPU 提供的計(jì)算能力痛阻,可能不是所有讀者都感興趣菌瘪。如第 1 章所述,GPU 在神經(jīng)網(wǎng)絡(luò)的訓(xùn)練過(guò)程中發(fā)揮著重要作用阱当。
本書(shū)以后記結(jié)束俏扩,其中我強(qiáng)調(diào)了一些結(jié)論。我想強(qiáng)調(diào)的是斗这,本書(shū)中的代碼示例可以從本書(shū) [2] 的 github 倉(cāng)庫(kù)下載动猬。
1. TensorFlow 基礎(chǔ)知識(shí)
在本章中,我將簡(jiǎn)要介紹 TensorFlow 的代碼及其編程模型表箭。在本章的最后赁咙,讀者可以在他們的個(gè)人計(jì)算機(jī)上安裝 TensorFlow 軟件包。
開(kāi)源軟件包
學(xué)術(shù)界已經(jīng)對(duì)機(jī)器學(xué)習(xí)進(jìn)行了數(shù)十年的調(diào)查免钻,但直到近幾年彼水,它的滲透率在企業(yè)中也有所增加。這要?dú)w功于它已經(jīng)擁有的大量數(shù)據(jù)以及現(xiàn)在可用的前所未有的計(jì)算能力极舔。
在這種情況下凤覆,毫無(wú)疑問(wèn),在 Alphabet 的支持下拆魏,谷歌是機(jī)器學(xué)習(xí)技術(shù)在其所有虛擬計(jì)劃和產(chǎn)品中發(fā)揮關(guān)鍵作用的最大公司之一盯桦。
去年10月,當(dāng) Alphabet 宣布那個(gè)季度谷歌的業(yè)績(jī)渤刃,銷(xiāo)售額和利潤(rùn)大幅增加時(shí)拥峦,首席執(zhí)行官桑達(dá)皮采清楚地說(shuō):“機(jī)器學(xué)習(xí)是一種核心的,變革性的方式卖子,我們正在重新思考我們正在做的一切”略号。
從技術(shù)上講,我們正面臨著谷歌不是唯一一個(gè)重要角色的時(shí)代變遷。其他技術(shù)公司玄柠,如微軟突梦,F(xiàn)acebook,亞馬遜和蘋(píng)果等眾多公司也在增加對(duì)這些領(lǐng)域的投資羽利。
在此背景下宫患,幾個(gè)月前谷歌在開(kāi)源許可證(Apache 2.0)下發(fā)布了 TensorFlow 引擎。想要將機(jī)器學(xué)習(xí)納入其項(xiàng)目和產(chǎn)品的開(kāi)發(fā)人員和研究人員可以使用 TensorFlow铐伴,就像 Google 在內(nèi)部使用 Gmail撮奏,Google 照片俏讹,搜索当宴,語(yǔ)音識(shí)別等不同的商業(yè)產(chǎn)品一樣。
TensorFlow 最初是由 Google Brain Team 開(kāi)發(fā)的泽疆,目的是進(jìn)行機(jī)器學(xué)習(xí)和深度神經(jīng)網(wǎng)絡(luò)研究户矢,但該系統(tǒng)足以應(yīng)用于各種其他機(jī)器學(xué)習(xí)問(wèn)題。
由于我是一名工程師殉疼,而且我正在與工程師交談梯浪,因此本書(shū)將深入了解數(shù)據(jù)流圖如何表示算法。TensorFlow 可以看作是使用數(shù)據(jù)流圖進(jìn)行數(shù)值計(jì)算的庫(kù)瓢娜。圖中的節(jié)點(diǎn)表示數(shù)學(xué)運(yùn)算挂洛,而圖的邊表示多維數(shù)據(jù)數(shù)組(張量),它們將節(jié)點(diǎn)互連眠砾。
TensorFlow 圍繞構(gòu)建和操作計(jì)算圖的基本思想構(gòu)建虏劲,象征性地表示要執(zhí)行的數(shù)值運(yùn)算。這使得 TensorFlow 現(xiàn)在可以從 Linux 64 位平臺(tái)(如 Mac OS X)以及 Android 或 iOS 等移動(dòng)平臺(tái)中利用 CPU 和 GPU褒颈。
這個(gè)新軟件包的另一個(gè)優(yōu)點(diǎn)是它的可視 TensorBoard 模塊柒巫,它提供了大量有關(guān)如何監(jiān)視和顯示算法運(yùn)行的信息。在創(chuàng)建更好的模型的過(guò)程中谷丸,能夠測(cè)量和顯示算法的行為是非常重要的堡掏。我感覺(jué)目前許多模型都是通過(guò)一個(gè)小型的盲目過(guò)程,通過(guò)試錯(cuò)來(lái)調(diào)優(yōu)刨疼,明顯浪費(fèi)資源泉唁,以及最重要時(shí)間。
TensorFlow 服務(wù)
最近 Google 推出了 TensorFlow 服務(wù) [3]揩慕,這有助于開(kāi)發(fā)人員將他們的 TensorFlow 機(jī)器學(xué)習(xí)模型(即使如此亭畜,也可以擴(kuò)展來(lái)服務(wù)其他類(lèi)型的模型)投入生產(chǎn)。TensorFlow 服務(wù)是一個(gè)開(kāi)源服務(wù)系統(tǒng)(用 C++ 編寫(xiě))漩绵,現(xiàn)在可以在 Apache 2.0 許可下在 GitHub 上獲得贱案。
TensorFlow 和 TensorFlow 服務(wù)有什么區(qū)別? 在 TensorFlow 中,開(kāi)發(fā)人員更容易構(gòu)建機(jī)器學(xué)習(xí)算法宝踪,并針對(duì)某些類(lèi)型的數(shù)據(jù)輸入進(jìn)行訓(xùn)練侨糟,TensorFlow 服務(wù)專(zhuān)門(mén)使這些模型可用于生產(chǎn)環(huán)境。我們的想法是開(kāi)發(fā)人員使用 TensorFlow 訓(xùn)練他們的模型瘩燥,然后他們使用 TensorFlow 服務(wù)的 API 來(lái)響應(yīng)來(lái)自客戶端的輸入秕重。
這允許開(kāi)發(fā)人員根據(jù)實(shí)際數(shù)據(jù)大規(guī)模試驗(yàn)不同的模型,并隨時(shí)間變化厉膀,保持穩(wěn)定的架構(gòu)和 API溶耘。
典型的流水線是將訓(xùn)練數(shù)據(jù)提供給學(xué)習(xí)器,學(xué)習(xí)器輸出模型服鹅,模型在被驗(yàn)證之后準(zhǔn)備好部署到 TensorFlow 服務(wù)系統(tǒng)凳兵。 隨著時(shí)間的推移和新數(shù)據(jù)的出現(xiàn)偷遗,改進(jìn)模型嗡靡,啟動(dòng)和迭代我們的模型是很常見(jiàn)的幅慌。事實(shí)上雀哨,在 Google 的博文中 [4] 中相速,他們提到在谷歌盗迟,許多流水線都在持續(xù)運(yùn)行延旧,隨著新數(shù)據(jù)的出現(xiàn)埋酬,產(chǎn)生了新的模型版本厌漂。
開(kāi)發(fā)人員用來(lái)與 TensorFlow 服務(wù)進(jìn)行通信的前端實(shí)現(xiàn)萨醒,基于 gRPC ,這是一種來(lái)自 Google 的高性能開(kāi)源RPC框架苇倡。
如果你有興趣了解 TensorFlow 服務(wù)的更多信息富纸,我建議你先閱讀服務(wù)架構(gòu)概述 [5] 部分,設(shè)置你的環(huán)境并開(kāi)始閱讀基礎(chǔ)教程 [6]雏节。
TensorFlow 的安裝
是時(shí)候做一些事情了胜嗓。從現(xiàn)在開(kāi)始,我建議你交替閱讀和在計(jì)算機(jī)上練習(xí)钩乍。
TensorFlow 有 Python API(以及 C/C++)辞州,需要安裝 Python 2.7(我假設(shè)任何閱讀本書(shū)的工程師都知道如何操作)。
通常寥粹,在使用 Python 時(shí)变过,應(yīng)使用虛擬環(huán)境virtualenv
。 virtualenv
是一種工具涝涤,用于在同一臺(tái)計(jì)算機(jī)的不同部分中保持不同項(xiàng)目所需的 Python 依賴關(guān)系媚狰。如果我們使用virtualenv
來(lái)安裝 TensorFlow,這將不會(huì)覆蓋需要 TensorFlow 的其他項(xiàng)目的現(xiàn)有 Python 包版本阔拳。
首先崭孤,如果尚未安裝pip
和virtualenv
,則應(yīng)安裝,如下面的腳本所示:
# Ubuntu/Linux 64-bit
$ sudo apt-get install python-pip python-dev python-virtualenv
# Mac OS X
$ sudo easy_install pip
$ sudo pip install --upgrade virtualenv
~/tensorflow
目錄中的環(huán)境virtualenv
:
$ virtualenv --system-site-packages ~/tensorflow
下一步是激活virtualenv
辨宠。這可以按如下方式完成:
$ source ~/tensorflow/bin/activate # with bash
$ source ~/tensorflow/bin/activate.csh # with csh
(tensorflow)$
我們工作的虛擬環(huán)境的名稱(chēng)遗锣,將從現(xiàn)在開(kāi)始顯示在每個(gè)命令行的開(kāi)頭。激活virtualenv
后嗤形,你可以使用pip
在其中安裝 TensorFlow:
# Ubuntu/Linux 64-bit, CPU only:
(tensorflow)$ sudo pip install --upgrade https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-0.7.1-cp27-none-linux_x86_64.whl
# Mac OS X, CPU only:
(tensorflow)$ sudo easy_install --upgrade six
(tensorflow)$ sudo pip install --upgrade https://storage.googleapis.com/tensorflow/mac/tensorflow-0.7.1-cp27-none-any.whl
我建議你訪問(wèn)此處提供的官方文檔精偿,來(lái)確保你安裝的是最新版本。
如果運(yùn)行代碼的平臺(tái)具有 GPU赋兵,要使用的包不同笔咽。我建議你訪問(wèn)官方文檔,了解你的 GPU 是否符合支持 Tensorflow 所需的規(guī)范霹期。運(yùn)行 Tensorflow GPU 需要安裝其他軟件叶组,所有信息都可以在下載和設(shè)置 TensorFlow [7] 網(wǎng)頁(yè)上找到。對(duì)于使用 GPU 的更多信息经伙,我建議閱讀第 6 章扶叉。
最后,當(dāng)你完成后帕膜,你應(yīng)該按如下方式禁用虛擬環(huán)境:
(tensorflow)$ deactivate
鑒于本書(shū)的介紹性質(zhì),我們建議讀者訪問(wèn)上述官方文檔頁(yè)面溢十,來(lái)查找安裝 Tensorflow 的其他方法的更多信息垮刹。
我在 TensorFlow 中的第一個(gè)代碼
正如我在開(kāi)始時(shí)提到的那樣,我們將通過(guò)很少的理論和大量練習(xí)來(lái)探索 TensorFlow 星球张弛。開(kāi)始吧荒典!
從現(xiàn)在開(kāi)始,最好使用任何文本編輯器編寫(xiě) python 代碼并使用擴(kuò)展名.py
保存(例如test.py
)吞鸭。要運(yùn)行代碼寺董,使用命令python test.py
就足夠了。
為了獲得 TensorFlow 程序的第一印象刻剥,我建議編寫(xiě)一個(gè)簡(jiǎn)單的乘法程序遮咖;代碼看起來(lái)像這樣:
import tensorflow as tf
a = tf.placeholder("float")
b = tf.placeholder("float")
y = tf.mul(a, b)
sess = tf.Session()
print sess.run(y, feed_dict={a: 3, b: 3})
在此代碼中,在導(dǎo)入 Python 模塊tensorflow
之后造虏,我們定義“符號(hào)”變量御吞,稱(chēng)為占位符,以便在程序執(zhí)行期間操作它們漓藕。然后陶珠,我們將這些變量作為參數(shù),調(diào)用 TensorFlow 提供的乘法函數(shù)享钞。tf.mul
是 TensorFlow 為操縱張量而提供的眾多數(shù)學(xué)運(yùn)算之一揍诽。在這個(gè)時(shí)候,張量可以認(rèn)為是動(dòng)態(tài)大小的多維數(shù)據(jù)數(shù)組。
主要運(yùn)算如下表所示:
運(yùn)算 | 描述 |
---|---|
tf.add |
加法 |
tf.sub |
減法 |
tf.mul |
乘法 |
tf.div |
除法 |
tf.mod |
模 |
tf.abs |
返回絕對(duì)值 |
tf.neg |
返回負(fù)值 |
tf.sign |
返回標(biāo)志 |
tf.inv |
返回倒數(shù) |
tf.square |
計(jì)算平方 |
tf.round |
返回最接近的整數(shù) |
tf.sqrt |
計(jì)算平方根 |
tf.pow |
計(jì)算指數(shù) |
tf.exp |
計(jì)算自然指數(shù) |
tf.log |
計(jì)算自然對(duì)數(shù) |
tf.maximum |
返回最大值 |
tf.minimum |
返回最小值 |
tf.cos |
計(jì)算余弦 |
tf.sin |
計(jì)算正弦 |
TensorFlow 還為程序員提供了許多函數(shù)暑脆,來(lái)對(duì)矩陣執(zhí)行數(shù)學(xué)運(yùn)算交排。一些列在下面:
運(yùn)算 | 描述 |
---|---|
tf.diag |
返回具有給定對(duì)角線值的對(duì)角張量 |
tf.transpose |
返回參數(shù)的轉(zhuǎn)置 |
tf.matmul |
返回由參數(shù)列出的兩個(gè)張量的張量積 |
tf.matrix_determinant |
返回由參數(shù)指定的方陣的行列式 |
tf.matrix_inverse |
返回由參數(shù)指定的方陣的逆 |
下一步,最重要的一步是創(chuàng)建一個(gè)會(huì)話來(lái)求解指定的符號(hào)表達(dá)式饵筑。實(shí)際上埃篓,到目前為止,這個(gè) TensorFlow 代碼尚未執(zhí)行任何操作根资。我要強(qiáng)調(diào)的是架专,TensorFlow 既是表達(dá)機(jī)器學(xué)習(xí)算法的接口,又是運(yùn)行它們的實(shí)現(xiàn)玄帕,這是一個(gè)很好的例子部脚。
程序通過(guò)使用Session()
創(chuàng)建會(huì)話來(lái)與 Tensorflow 庫(kù)交互;只有在我們調(diào)用run()
方法時(shí)才會(huì)創(chuàng)建這個(gè)會(huì)話裤纹,這就是它真正開(kāi)始運(yùn)行指定代碼的時(shí)候委刘。在此特定示例中,使用feed_dict
參數(shù)將變量的值傳給run()
方法鹰椒。這里锡移,相關(guān)代碼求解表達(dá)式,并且從顯示器返回 9 作為結(jié)果漆际。
通過(guò)這個(gè)簡(jiǎn)單的例子淆珊,我試圖介紹在 TensorFlow 中編程的常規(guī)方法,首先指定整個(gè)問(wèn)題奸汇,并最終創(chuàng)建一個(gè)可以運(yùn)行相關(guān)計(jì)算的會(huì)話施符。
然而,有時(shí)我們感興趣的是構(gòu)造代碼的更多的靈活性擂找,插入操作來(lái)構(gòu)建某個(gè)圖戳吝,這些操作運(yùn)行它的一部分。例如贯涎,當(dāng)我們使用 Python 的交互式環(huán)境時(shí)听哭,例如 IPython [8],就會(huì)發(fā)生這種情況柬采。為此欢唾,TesorFlow 提供了tf.InteractiveSession()
類(lèi)。
這種編程模型的動(dòng)機(jī)超出了本書(shū)的范圍粉捻。但是礁遣,為了繼續(xù)下一章,我們只需要知道所有信息都在內(nèi)部保存在圖結(jié)構(gòu)中肩刃,它包含所有操作和數(shù)據(jù)的信息祟霍。
該圖描述了數(shù)學(xué)運(yùn)算杏头。節(jié)點(diǎn)通常實(shí)現(xiàn)數(shù)學(xué)運(yùn)算,但它們也可以表示數(shù)據(jù)輸入沸呐,輸出結(jié)果或讀/寫(xiě)持久變量醇王。邊描述節(jié)點(diǎn)與其輸入和輸出之間的關(guān)系,同時(shí)攜帶張量崭添,即 TensorFlow 的基本數(shù)據(jù)結(jié)構(gòu)寓娩。
將信息表示為圖允許 TensorFlow 知道事務(wù)之間的依賴關(guān)系,并異步并行地將操作分配給設(shè)備呼渣,當(dāng)這些操作已經(jīng)具有可用的相關(guān)張量(在邊緣輸入中指示)時(shí)棘伴。
因此,并行性是使我們能夠加速一些計(jì)算昂貴的算法的執(zhí)行的因素之一屁置,但也因?yàn)?TensorFlow 已經(jīng)有效地實(shí)現(xiàn)了一組復(fù)雜的操作焊夸。此外,大多數(shù)這些操作都具有關(guān)聯(lián)的內(nèi)核蓝角,這些內(nèi)核是為特定設(shè)備(如 GPU)設(shè)計(jì)的操作的實(shí)現(xiàn)阱穗。下表總結(jié)了最重要的操作/內(nèi)核 [9]:
操作組 | 操作 |
---|---|
數(shù)學(xué) | 加,減使鹅,乘揪阶,除,指數(shù)并徘,對(duì)數(shù)遣钳,大于,小于麦乞,等于 |
排列 | 連接,切片劝评,分割姐直,常數(shù),階蒋畜,形狀声畏,打亂 |
矩陣 | MatMul,MatrixInverse姻成,MatrixDeterminant |
神經(jīng)網(wǎng)絡(luò) | SoftMax插龄,Sigmoid,ReLU科展,Convolution2D均牢,MaxPool |
檢查點(diǎn) | 保存,還原 |
隊(duì)列和同步 | Enqueue才睹,Dequeue徘跪,MutexAcquire甘邀,MutexRelease |
流量控制 | 合并,切換垮庐,進(jìn)入松邪,離開(kāi),NextIteration |
顯示面板 Tensorboard
為了使其更加全面哨查,TensorFlow 包含了名為 TensorBoard 的可視化工具來(lái)調(diào)試和優(yōu)化程序的功能逗抑。TensorBoard 可以以圖形方式查看計(jì)算圖任何部分的參數(shù)和細(xì)節(jié)的不同類(lèi)型的統(tǒng)計(jì)信息。
TensorBoard 模塊顯示的數(shù)據(jù)在 TensorFlow 執(zhí)行期間生成寒亥,并存儲(chǔ)在跟蹤文件中邮府,其數(shù)據(jù)來(lái)自摘要操作。在 TensorFlow 的文檔頁(yè)面 [10] 中护盈,你可以找到 Python API 的詳細(xì)說(shuō)明挟纱。
我們調(diào)用它的方式非常簡(jiǎn)單:從命令行中使用 Tensorflow 命令啟動(dòng)服務(wù),它包含要跟蹤的文件作為參數(shù)腐宋。
(tensorflow)$ tensorboard --logdir=
你只需要使用http//localhost:6006 /
從瀏覽器中 [11] 訪問(wèn)本地套接字 6006紊服。
名為 TensorBoard 的可視化工具超出了本書(shū)的范圍。對(duì)于 Tensorboard 如何工作的更多詳細(xì)信息胸竞,讀者可以訪問(wèn) TensorFlow 教程頁(yè)面中的 TensorBoard 圖形可視化 [12] 部分欺嗤。
2. TensorFlow 中的線性回歸
在本章中,我將開(kāi)始使用簡(jiǎn)單模型:線性回歸來(lái)探索 TensorFlow 編程卫枝〖灞基于這個(gè)例子,我將介紹一些代碼基礎(chǔ)知識(shí)校赤,以及吆玖,如何調(diào)用學(xué)習(xí)過(guò)程中的各種重要組件沾乘,如函數(shù)函數(shù)或算法梯度下降幅狮。
變量之間的關(guān)系模型
線性回歸是一種用于衡量變量之間關(guān)系的統(tǒng)計(jì)技術(shù)贤徒。它的有趣之處在于實(shí)現(xiàn)它的算法在概念上不復(fù)雜固阁,并且還可以適應(yīng)各種各樣的情況誉己。由于這些原因,我發(fā)現(xiàn)用線性回歸的例子開(kāi)始深入研究 TensorFlow 很有意思筹我。
請(qǐng)記住,在兩個(gè)變量(簡(jiǎn)單回歸)和兩個(gè)以上變量(多元回歸)的情況下哥谷,線性回歸擬合因變量和自變量之間的關(guān)系xi
和隨機(jī)項(xiàng)b
岸夯。
在本節(jié)中麻献,我將創(chuàng)建一個(gè)簡(jiǎn)單的示例來(lái)解釋 TensorFlow 如何工作,假設(shè)我們的數(shù)據(jù)模型對(duì)應(yīng)簡(jiǎn)單的線性回歸y = W * x + b
猜扮。為此奸攻,我使用一個(gè)簡(jiǎn)單的 Python 程序在二維空間中創(chuàng)建數(shù)據(jù)鳄哭,然后我會(huì)要求 TensorFlow 在這些點(diǎn)上尋找最適合的直線沦零。
首先要做的是導(dǎo)入我們將用于生成點(diǎn)的 NumPy 包默辨。我們創(chuàng)建的代碼如下:
import numpy as np
num_points = 1000
vectors_set = []
for i in xrange(num_points):
x1= np.random.normal(0.0, 0.55)
y1= x1 * 0.1 + 0.3 + np.random.normal(0.0, 0.03)
vectors_set.append([x1, y1])
x_data = [v[0] for v in vectors_set]
y_data = [v[1] for v in vectors_set]
從代碼中可以看出,我們根據(jù)關(guān)系y = 0.1 * x + 0.3
生成了點(diǎn)鲜漩,盡管有一些正態(tài)分布的變化源譬,因此這些點(diǎn)并不完全對(duì)應(yīng)一條線,讓我們編寫(xiě)一個(gè)更有趣的例子孕似。
在我們的例子中踩娘,所得到的點(diǎn)云是:
https://jorditorres.org/wp-content/uploads/2016/02/image014.png
讀者可以使用以下代碼查看它們(這里,我們需要導(dǎo)入matplotlib
包的一些函數(shù)喉祭,運(yùn)行pip install matplotlib
[13]):
import matplotlib.pyplot as plt
plt.plot(x_data, y_data, 'ro', label='Original data')
plt.legend()
plt.show()
這些點(diǎn)是我們將考慮的模型的訓(xùn)練數(shù)據(jù)集的數(shù)據(jù)养渴。
損失函數(shù)和梯度下降算法
下一步是訓(xùn)練我們的學(xué)習(xí)算法,以便能夠獲得從輸入數(shù)據(jù)x_data
估計(jì)的輸出值y
泛烙。在這種情況下理卑,正如我們事先所知,它是線性回歸蔽氨,我們只能用兩個(gè)參數(shù)表示我們的模型:W
和b
藐唠。
目標(biāo)是生成 TensorFlow 代碼,它能夠找到最佳的參數(shù)W
和b
鹉究,它來(lái)自輸入數(shù)據(jù)x_data
宇立,將其擬合到輸出數(shù)據(jù)y_data
,我們這里它是一條直線自赔,由y_data = W * x_data + b
定義妈嘹。讀者知道W
應(yīng)接近 0.1 且b
為 0.3,但 TensorFlow 不知道它绍妨,必須自己實(shí)現(xiàn)润脸。
解決此類(lèi)問(wèn)題的一種標(biāo)準(zhǔn)方法是,遍歷數(shù)據(jù)集的每個(gè)值并修改參數(shù)W
和b
他去,以便每次都能獲得更精確的答案津函。為了確定我們是否在這些迭代中有所改進(jìn),我們將定義一個(gè)損失函數(shù)(也稱(chēng)為“誤差函數(shù)”)來(lái)衡量某條線有多“好”(實(shí)際上是有多“壞”)孤页。
該函數(shù)接收參數(shù)W
和b
,并根據(jù)線與數(shù)據(jù)的擬合程度返回一個(gè)誤差值涩馆。在我們的例子中行施,我們可以使用均方誤差 [14] 作為損失函數(shù)允坚。利用均方誤差,我們得到“誤差”的平均值蛾号,基于實(shí)際值與算法每次迭代估計(jì)值之間距離稠项。
稍后,我將詳細(xì)介紹損失函數(shù)及其替代方法鲜结,但對(duì)于這個(gè)介紹性示例展运,均方誤差有助于我們一步一步向前推進(jìn)。
現(xiàn)在是時(shí)候用 TensorFlow 編寫(xiě)我 解釋過(guò)的所有內(nèi)容了精刷。為此拗胜,首先我們將使用以下語(yǔ)句創(chuàng)建三個(gè)變量:
W = tf.Variable(tf.random_uniform([1], -1.0, 1.0))
b = tf.Variable(tf.zeros([1]))
y = W * x_data + b
現(xiàn)在,我們可以繼續(xù)前進(jìn)怒允,只知道方法Variable
的調(diào)用定義了一個(gè)變量埂软,駐留在 TensorFlow 的內(nèi)部圖數(shù)據(jù)結(jié)構(gòu)中,我在上面已經(jīng)說(shuō)過(guò)了纫事。 稍后我們將回到方法參數(shù)的更多信息勘畔,但是現(xiàn)在我認(rèn)為最好繼續(xù)前進(jìn)來(lái)推進(jìn)第一種方法。
現(xiàn)在丽惶,通過(guò)定義這些變量炫七,我們可以基于每個(gè)點(diǎn)與函數(shù)y = W * x + b
計(jì)算的點(diǎn)之間的距離,來(lái)表示我們之前討論的損失函數(shù)钾唬。之后万哪,我們可以計(jì)算其平方和的平均值。 在 TensorFlow 中知纷,此損失函數(shù)表示如下:
loss = tf.reduce_mean(tf.square(y - y_data))
如我們所見(jiàn)壤圃,此表達(dá)式計(jì)算我們知道的y_data
點(diǎn)與從輸入x_data
計(jì)算的點(diǎn)y
之間的平方距離的平均值。
此時(shí)琅轧,讀者可能已經(jīng)懷疑最適合我們數(shù)據(jù)的直線是誤差值較小的直線伍绳。 因此,如果我們使誤差函數(shù)最小乍桂,我們將找到我們數(shù)據(jù)的最佳模型冲杀。
目前沒(méi)有太多細(xì)節(jié),這就是使函數(shù)最小的優(yōu)化算法睹酌,稱(chēng)為梯度下降 [15]权谁。 理論上,梯度下降是一種算法憋沿,它接受由一組參數(shù)定義的函數(shù)旺芽,它以一組初始參數(shù)值開(kāi)始,并迭代地移向一組使函數(shù)最小的值。 在函數(shù)梯度 [16] 的負(fù)方向上移動(dòng)來(lái)實(shí)現(xiàn)迭代式最小化采章。 通常計(jì)算距離平方來(lái)確保它是正的并且使誤差函數(shù)可微分以便計(jì)算梯度运嗜。
算法從一組參數(shù)的初始值開(kāi)始(在我們的例子中為W
和b
),然后算法以某種方式迭代地調(diào)整這些變量的值悯舟,在過(guò)程結(jié)束時(shí)担租,變量的值使成本函數(shù)最小。
要在 TensorFlow 中使用此算法抵怎,我們只需執(zhí)行以下兩個(gè)語(yǔ)句:
optimizer = tf.train.GradientDescentOptimizer(0.5)
train = optimizer.minimize(loss)
現(xiàn)在奋救,這足以讓 TensorFlow 在其內(nèi)部數(shù)據(jù)結(jié)構(gòu)中創(chuàng)建相關(guān)數(shù)據(jù),并且在這個(gè)結(jié)構(gòu)中也實(shí)現(xiàn)了一個(gè)可以由train
調(diào)用的優(yōu)化器反惕,它是針對(duì)定義的成本函數(shù)的梯度下降算法尝艘。稍后,我們將討論名為學(xué)習(xí)率的函數(shù)參數(shù)(在我們的示例中承璃,值為 0.5)利耍。
運(yùn)行算法
正如我們之前所見(jiàn),在代碼的這個(gè)位置上盔粹,特定于 TensorFlow 庫(kù)的調(diào)用隘梨,只向其內(nèi)部圖添加了信息,而 TensorFlow 的運(yùn)行時(shí)尚未運(yùn)行任何算法舷嗡。因此轴猎,與前一章的示例一樣,我們必須創(chuàng)建會(huì)話进萄,調(diào)用run
方法并傳遞train
作為參數(shù)捻脖。另外,因?yàn)樵诖a中我們已經(jīng)指定了變量中鼠,所以我們必須先使用以下調(diào)用對(duì)它們進(jìn)行初始化:
init = tf.initialize_all_variables()
sess = tf.Session()
sess.run(init)
現(xiàn)在我們可以開(kāi)始迭代過(guò)程可婶,這將允許我們找到W
和b
的值,它定義最適合輸入點(diǎn)的模型直線援雇。 訓(xùn)練過(guò)程一直持續(xù)到模型在訓(xùn)練數(shù)據(jù)上達(dá)到所需的準(zhǔn)確度矛渴。 在我們的特定示例中,如果我們假設(shè)只有 8 次迭代就足夠了惫搏,代碼可能是:
for step in xrange(8):
sess.run(train)
print step, sess.run(W), sess.run(b)
運(yùn)行此代碼的結(jié)果表明具温,W
和b
的值接近我們事先知道的值。 在我的例子中筐赔,print
的結(jié)果是:
(array([ 0.09150752], dtype=float32), array([ 0.30007562], dtype=float32))
并且铣猩,如果我們使用以下代碼以圖形方式顯示結(jié)果:
plt.plot(x_data, y_data, 'ro')
plt.plot(x_data, sess.run(W) * x_data + sess.run(b))
plt.legend()
plt.show()
我們可以用圖形方式,看到參數(shù)W = 0.0854
和b = 0.299
定義的直線茴丰,只需 8 次迭代:
https://jorditorres.org/wp-content/uploads/2016/02/image016.png
請(qǐng)注意达皿,我們只執(zhí)行了八次迭代來(lái)簡(jiǎn)化說(shuō)明天吓,但如果我們運(yùn)行更多,參數(shù)值會(huì)更接近預(yù)期值鳞绕。 我們可以使用以下語(yǔ)句來(lái)打印W
和b
的值:
print(step, sess.run(W), sess.run(b))
在我們的例子中失仁,print
輸出是:
(0, array([-0.04841119], dtype=float32), array([ 0.29720169], dtype=float32))
(1, array([-0.00449257], dtype=float32), array([ 0.29804006], dtype=float32))
(2, array([ 0.02618564], dtype=float32), array([ 0.29869056], dtype=float32))
(3, array([ 0.04761609], dtype=float32), array([ 0.29914495], dtype=float32))
(4, array([ 0.06258646], dtype=float32), array([ 0.29946238], dtype=float32))
(5, array([ 0.07304412], dtype=float32), array([ 0.29968411], dtype=float32))
(6, array([ 0.08034936], dtype=float32), array([ 0.29983902], dtype=float32))
(7, array([ 0.08545248], dtype=float32), array([ 0.29994723], dtype=float32))
你可以觀察到算法以W = -0.0484
和b = 0.2972
(在我們的例子中)的初始值開(kāi)始,然后算法以一種方式迭代調(diào)整變量的值使損失函數(shù)最小们何。
你還可以檢查損失函數(shù)是否隨之減少
print(step, sess.run(loss))
在這種情況下,print
輸出是:
(0, 0.015878126)
(1, 0.0079048825)
(2, 0.0041520335)
(3, 0.0023856456)
(4, 0.0015542418)
(5, 0.001162916)
(6, 0.00097872759)
(7, 0.00089203351)
我建議讀者在每次迭代時(shí)繪圖控轿,讓我們可以直觀地觀察算法如何調(diào)整參數(shù)值冤竹。 在我們的例子中,8 個(gè)截圖是:
https://jorditorres.org/wp-content/uploads/2016/02/image018.png
正如讀者可以看到的茬射,在算法的每次迭代中鹦蠕,直線更適合數(shù)據(jù)。 梯度下降算法如何更接近最小化損失函數(shù)的參數(shù)值在抛?
由于我們的誤差函數(shù)由兩個(gè)參數(shù)(W
和b
)組成钟病,我們可以將它可視化為二維表面。 該二維空間中的每個(gè)點(diǎn)代表一條直線刚梭。 每個(gè)點(diǎn)的函數(shù)高度是該直線的誤差值肠阱。 在該表面上,一些直線產(chǎn)生的誤差值小于其他直線朴读。 當(dāng) TensorFlow 運(yùn)行梯度下降搜索時(shí)屹徘,它將從該表面上的某個(gè)位置開(kāi)始(在我們的示例中,點(diǎn)W = -0.04841119
和b = 0.29720169
)并向下移動(dòng)來(lái)查找具有最小誤差的直線衅金。
要在此誤差函數(shù)上運(yùn)行梯度下降噪伊,TensorFlow 會(huì)計(jì)算其梯度。 梯度將像指南針一樣氮唯,總是引導(dǎo)我們向下走鉴吹。 為了計(jì)算它,TensorFlow 將對(duì)誤差函數(shù)微分惩琉,在我們的情況下意味著它需要計(jì)算W
和b
的偏導(dǎo)數(shù)豆励,它表明每次迭代中要移動(dòng)的方向。
之前提到的學(xué)習(xí)率參數(shù)控制每次迭代期間 TensorFlow 的每一步的下降程度琳水。 如果我們引入的參數(shù)太大肆糕,我們可能會(huì)越過(guò)最小值。 但是在孝,如果我們讓 TensorFlow 采取較小步驟诚啃,則需要多次迭代才能達(dá)到最小值。 因此私沮,使用良好的學(xué)習(xí)率至關(guān)重要始赎。 有不同的技術(shù)來(lái)調(diào)整學(xué)習(xí)率參數(shù)的值,但它超出了本入門(mén)書(shū)的范圍。 確保梯度下降算法正常工作的一種好方法造垛,是確保每次迭代中的誤差減小魔招。
請(qǐng)記住,為了便于讀者測(cè)試本章所述的代碼五辽,你可以從本書(shū)的 Github [17] 下載regression.py
办斑。 在這里,你將發(fā)現(xiàn)所有東西都在一起以便跟蹤:
import numpy as np
num_points = 1000
vectors_set = []
for i in xrange(num_points):
x1= np.random.normal(0.0, 0.55)
y1= x1 * 0.1 + 0.3 + np.random.normal(0.0, 0.03)
vectors_set.append([x1, y1])
x_data = [v[0] for v in vectors_set]
y_data = [v[1] for v in vectors_set]
import matplotlib.pyplot as plt
#Graphic display
plt.plot(x_data, y_data, 'ro')
plt.legend()
plt.show()
import tensorflow as tf
W = tf.Variable(tf.random_uniform([1], -1.0, 1.0))
b = tf.Variable(tf.zeros([1]))
y = W * x_data + b
loss = tf.reduce_mean(tf.square(y - y_data))
optimizer = tf.train.GradientDescentOptimizer(0.5)
train = optimizer.minimize(loss)
init = tf.initialize_all_variables()
sess = tf.Session()
sess.run(init)
for step in xrange(8):
sess.run(train)
print(step, sess.run(W), sess.run(b))
print(step, sess.run(loss))
#Graphic display
plt.plot(x_data, y_data, 'ro')
plt.plot(x_data, sess.run(W) * x_data + sess.run(b))
plt.xlabel('x')
plt.xlim(-2,2)
plt.ylim(0.1,0.6)
plt.ylabel('y')
plt.legend()
plt.show()
在本章中杆逗,我們已經(jīng)開(kāi)始探索 TensorFlow 軟件包的可能性乡翅,首先采用直觀方法處理兩個(gè)基本組件:損失函數(shù)和梯度下降算法,使用基本線性回歸算法來(lái)介紹罪郊。 在下一章中蠕蚜,我們將詳細(xì)介紹 TensorFlow 包使用的數(shù)據(jù)結(jié)構(gòu)。
3. TensorFlow 中的聚類(lèi)
前一章中介紹的線性回歸是一種監(jiān)督學(xué)習(xí)算法悔橄,我們使用數(shù)據(jù)和輸出值(或標(biāo)簽)來(lái)構(gòu)建適合它們的模型靶累。但我們并不總是擁有標(biāo)記數(shù)據(jù),盡管如此癣疟,我們也希望以某種方式分析它們挣柬。在這種情況下,我們可以使用無(wú)監(jiān)督學(xué)習(xí)算法争舞,例如聚類(lèi)凛忿。聚類(lèi)方法被廣泛使用,因?yàn)樗ǔJ菙?shù)據(jù)分析的初步篩選的好方法竞川。
在本章中店溢,我將介紹名為 K-means 的聚類(lèi)算法。它肯定是最受歡迎的委乌,廣泛用于自動(dòng)將數(shù)據(jù)分組到相關(guān)的子集中床牧,以便子集中的所有元素彼此更相似。在此算法中遭贸,我們沒(méi)有任何目標(biāo)或結(jié)果變量來(lái)預(yù)測(cè)估計(jì)值戈咳。
我還將使用本章來(lái)介紹 TensorFlow 的知識(shí),并在更詳細(xì)地介紹名為tensor
(張量)的基本數(shù)據(jù)結(jié)構(gòu)壕吹。我將首先解釋這種類(lèi)型的數(shù)據(jù)是什么樣的著蛙,并展示可以在其上執(zhí)行的轉(zhuǎn)換。然后耳贬,我將使用張量在案例研究中展示 K-means 算法的使用踏堡。
基本數(shù)據(jù)結(jié)構(gòu):張量
TensorFlow 程序使用稱(chēng)為張量的基本數(shù)據(jù)結(jié)構(gòu)來(lái)表示其所有數(shù)據(jù)。張量可以被認(rèn)為是動(dòng)態(tài)大小的多維數(shù)據(jù)數(shù)組咒劲,其具有靜態(tài)數(shù)據(jù)類(lèi)型的屬性顷蟆,可以從布爾值或字符串到各種數(shù)字類(lèi)型诫隅。下面是 Python 中的主要類(lèi)型及其等價(jià)物的表格截亦。
TensorFlow 中的類(lèi)型 | Python 中的類(lèi)型 | 描述 |
---|---|---|
DT_FLOAT |
tf.float32 |
32 位浮點(diǎn) |
DT_INT16 |
tf.int16 |
16 位整數(shù) |
DT_INT32 |
tf.int32 |
32 位整數(shù) |
DT_INT64 |
tf.int64 |
64 位整數(shù) |
DT_STRING |
tf.string |
字符串 |
DT_BOOL |
tf.bool |
布爾值 |
另外阐枣,每個(gè)張量擁有階(Rank)小渊,這是其維度的數(shù)量脏榆。例如,以下張量(在 Python 中定義為列表)的階為 2:
t = [[1,2,3]冤留,[4,5,6]譬巫,[7,8,9]]
張量可以有任何階捣鲸。二階張量通常被認(rèn)為是矩陣漫贞,一階張量將是向量沛硅。零階被認(rèn)為是標(biāo)量值。
TensorFlow 文檔使用三種類(lèi)型的命名約定來(lái)描述張量的維度:形狀(Shape)绕辖,階(Rank)和維數(shù)(Dimension Number)。下表顯示了它們之間的關(guān)系擂红,以便使跟蹤 TensorFlow 文檔更容易:
形狀 | 階 | 維數(shù) |
---|---|---|
[] |
0 | 0-D |
[D0] |
1 | 1-D |
[D0, D1] |
2 | 2-D |
[D0, D1, D2] |
3 | 3-D |
… | … | … |
[D0, D1, ... Dn] |
n | n-D |
這些張量可以通過(guò)一系列 TensorFlow 軟件包提供的轉(zhuǎn)換進(jìn)行操作仪际。 下面,我們將在下表中討論其中的一些內(nèi)容昵骤。
在本章中树碱,我們將詳細(xì)介紹其中一些內(nèi)容。 可以在 TensorFlow 的官方網(wǎng)站 [18] 上找到完整的轉(zhuǎn)換列表和詳細(xì)信息变秦。
| 操作 | 描述 |
| tf.shape | 獲取張量的形狀 |
| tf.size | 獲取張量的大小 |
| tf.rank | 獲取張量的階 |
| tf.reshape | 改變張量的形狀成榜,保持包含相同的元素 |
| tf.squeeze | 刪除大小為 1 的張量維度 |
| tf.expand_dims | 將維度插入張量 |
| tf.slice | 刪除部分張量 |
| tf.split | 將張量沿一個(gè)維度劃分為多個(gè)張量 |
| tf.tile | 將一個(gè)張量多次復(fù)制,并創(chuàng)建新的張量 |
| tf.concat | 在一個(gè)維度上連接張量 |
| tf.reverse | 反轉(zhuǎn)張量的特定維度 |
| tf.transpose | 轉(zhuǎn)置張量中的維度 |
| tf.gather | 根據(jù)索引收集部分 |
例如蹦玫,假設(shè)你要將2×2000
(2D 張量)的數(shù)組擴(kuò)展為立方體(3D 張量)赎婚。 我們可以使用tf.expand_ dims
函數(shù),它允許我們向張量插入一個(gè)維度:
vectors = tf.constant(conjunto_puntos)
extended_vectors = tf.expand_dims(vectors, 0)
在這種情況下樱溉,tf.expand_dims
將一個(gè)維度插入到由參數(shù)給定的一個(gè)張量中(維度從零開(kāi)始)挣输。
從視覺(jué)上看,上述轉(zhuǎn)變?nèi)缦拢?/p>
https://jorditorres.org/wp-content/uploads/2016/02/image023.gif
如你所見(jiàn)福贞,我們現(xiàn)在有了 3D 張量撩嚼,但我們無(wú)法根據(jù)函數(shù)參數(shù)確定新維度 D0 的大小。
如果我們使用get_shape()
操作獲得此tensor
的形狀挖帘,我們可以看到?jīng)]有關(guān)聯(lián)的大型昀觥:
print expanded_vectors.get_shape()
它可能會(huì)顯示:
TensorShape([Dimension(1), Dimension(2000), Dimension(2)])
在本章的后面,我們將看到拇舀,由于 TensorFlow 形狀廣播逻族, 張量的許多數(shù)學(xué)處理函數(shù)(如第一章所示),能夠發(fā)現(xiàn)大小未指定的維度的大小你稚,瓷耙,并為其分配這個(gè)推導(dǎo)出的值朱躺。
TensorFlow 中的數(shù)據(jù)存儲(chǔ)
在介紹 TensorFlow 的軟件包之后,從廣義上講搁痛,有三種主要方法可以在 TensorFlow 程序上獲取數(shù)據(jù):
- 來(lái)自數(shù)據(jù)文件长搀。
- 數(shù)據(jù)作為常量或變量預(yù)加載。
- 那些由 Python 代碼提供的鸡典。
下面源请,我簡(jiǎn)要介紹其中的每一個(gè)。
- 數(shù)據(jù)文件
通常彻况,從數(shù)據(jù)文件加載初始數(shù)據(jù)谁尸。這個(gè)過(guò)程并不復(fù)雜,鑒于本書(shū)的介紹性質(zhì)纽甘,我邀請(qǐng)讀者訪問(wèn)TensorFlow 的網(wǎng)站 [19]良蛮,了解如何從不同文件類(lèi)型加載數(shù)據(jù)。你還可以查看 Python 代碼input_data.py
[20](可在 Github 上找到)悍赢,它從文件中加載 MNIST 數(shù)據(jù)(我將在下面幾章使用它)决瞳。
- 變量和常量
當(dāng)談到小集合時(shí),也可以預(yù)先將數(shù)據(jù)加載到內(nèi)存中左权;創(chuàng)建它們有兩種基本方法皮胡,正如我們?cè)谇懊娴睦又锌吹降哪菢樱?/p>
-
constant(…)
用于常量 -
Variable(…)
用于變量
TensorFlow 包提供可用于生成常量的不同操作。在下表中赏迟,你可以找到最重要的操作的摘要:
操作 | 描述 |
---|---|
tf.zeros_like |
創(chuàng)建一個(gè)張量屡贺,所有元素都初始化為 0 |
tf.ones_like |
創(chuàng)建一個(gè)張量,所有元素都初始化為 1 |
tf.fill |
創(chuàng)建一個(gè)張量锌杀,其中所有元素都初始化為由參數(shù)給出的標(biāo)量值 |
tf.constant |
使用參數(shù)列出的元素創(chuàng)建常量張量 |
在 TensorFlow 中甩栈,在模型的訓(xùn)練過(guò)程中,參數(shù)作為變量保存在存儲(chǔ)器中抛丽。 創(chuàng)建變量時(shí)谤职,可以使用由函數(shù)參數(shù)定義的張量作為初始值,該值可以是常量值或隨機(jī)值亿鲜。 TensorFlow 提供了一系列操作允蜈,可生成具有不同分布的隨機(jī)張量:
操作 | 描述 |
---|---|
tf.random_normal |
具有正態(tài)分布的隨機(jī)值 |
tf.truncated_normal |
具有正態(tài)分布的隨機(jī)值,但消除那些幅度大于標(biāo)準(zhǔn)差 2 倍的值 |
tf.random_uniform |
具有均勻分布的隨機(jī)值 |
tf.random_shuffle |
在第一維中隨機(jī)打亂張量元素 |
tf.set_random_seed |
設(shè)置隨機(jī)種子 |
一個(gè)重要的細(xì)節(jié)是蒿柳,所有這些操作都需要特定形狀的張量作為函數(shù)的參數(shù)饶套,并且創(chuàng)建的變量具有相同的形狀。 通常垒探,變量具有固定的形狀妓蛮,但TensorFlow提供了在必要時(shí)對(duì)其進(jìn)行重塑的機(jī)制。
使用變量時(shí)圾叼,必須在構(gòu)造圖之后蛤克,在使用run()
函數(shù)執(zhí)行任何操作之前顯式初始化這些變量捺癞。 正如我們所看到的,為此可以使用tf.initialize_all_variables()
构挤。 通過(guò) TensorFlow 的tf.train.Saver()
類(lèi)髓介,可以在訓(xùn)練模型時(shí)和之后將變量保存到磁盤(pán)上,但是這個(gè)類(lèi)超出了本書(shū)的范圍筋现。
- 由Python代碼提供
最后唐础,我們可以使用我們所謂的“符號(hào)變量”或占位符來(lái)在程序執(zhí)行期間操作數(shù)據(jù)。調(diào)用是placeholder()
矾飞,參數(shù)為元素類(lèi)型和張量形狀一膨,以及可選的名稱(chēng)。
從 Python 代碼調(diào)用Session.run()
或Tensor.eval()
的同時(shí)洒沦,張量由feed_dict
參數(shù)中指定的數(shù)據(jù)填充豹绪。回想第 1 章中的第一個(gè)代碼:
import tensorflow as tf
a = tf.placeholder("float")
b = tf.placeholder("float")
y = tf.mul(a, b)
sess = tf.Session()
print sess.run(y, feed_dict={a: 3, b: 3})
在最后一行代碼中申眼,調(diào)用sess.run()
時(shí)森篷,我們傳遞兩個(gè)張量a
和b
的值到feed_dict
參數(shù)。
通過(guò)張量的簡(jiǎn)要介紹豺型,我希望從現(xiàn)在起讀者可以毫不費(fèi)力地讀懂下面幾章的代碼。
K-Means 算法
K-Means 是一種無(wú)監(jiān)督算法买乃,可以解決聚類(lèi)問(wèn)題姻氨。 它的過(guò)程遵循一種簡(jiǎn)單易行的方法,通過(guò)一定數(shù)量的簇(假設(shè)k
簇)對(duì)給定數(shù)據(jù)集進(jìn)行聚類(lèi)剪验。 簇內(nèi)的數(shù)據(jù)點(diǎn)是同構(gòu)的肴焊,不同簇的點(diǎn)是異構(gòu)的,這意味著子集中的所有元素與其余元素相比更為相似功戚。
算法的結(jié)果是一組K
個(gè)點(diǎn)娶眷,稱(chēng)為質(zhì)心,它們是所得的不同組的焦點(diǎn)啸臀,以及點(diǎn)集的標(biāo)簽届宠,這些點(diǎn)分配給其中一個(gè)簇。 簇內(nèi)的所有點(diǎn)與質(zhì)心的距離都比任何其他質(zhì)心更近乘粒。
如果我們想要直接最小化誤差函數(shù)(所謂的 NP-hard 問(wèn)題)豌注,那么簇的生成是一個(gè)計(jì)算上很昂貴的問(wèn)題。因此灯萍,已經(jīng)創(chuàng)建了一些算法轧铁,通過(guò)啟發(fā)式在局部最優(yōu)中快速收斂。 最常用的算法使用迭代優(yōu)化技術(shù)旦棉,它在幾次迭代中收斂齿风。
一般來(lái)講药薯,這種技術(shù)有三個(gè)步驟:
- 初始步驟(步驟 0):確定
K
個(gè)質(zhì)心的初始集合。 - 分配步驟(步驟 1):將每個(gè)觀測(cè)值分配到最近的組救斑。
- 更新步驟(步驟 2):計(jì)算每個(gè)新組的新質(zhì)心童本。
有幾種方法可以確定初始K
質(zhì)心。 其中一個(gè)是在數(shù)據(jù)集中隨機(jī)選擇K
個(gè)觀測(cè)值并將它們視為質(zhì)心系谐;這是我們將在我們的示例中使用的那個(gè)巾陕。
分配(步驟 1)和更新(步驟 2)的步驟在循環(huán)中交替,直到認(rèn)為算法已經(jīng)收斂為止纪他,這可以是鄙煤,例如,當(dāng)點(diǎn)到組的分配不再改變的時(shí)候茶袒。
由于這是一種啟發(fā)式算法梯刚,因此無(wú)法保證它收斂于全局最優(yōu),結(jié)果取決于初始組薪寓。 因此亡资,由于算法通常非常快向叉,通常使用不同的初始質(zhì)心值重復(fù)執(zhí)行多次锥腻,然后權(quán)衡結(jié)果。
要在 TensorFlow 中開(kāi)始編寫(xiě) K-means 的示例母谎,我建議首先生成一些數(shù)據(jù)作為測(cè)試平臺(tái)瘦黑。 我建議做一些簡(jiǎn)單的事情,比如在 2D 空間中隨機(jī)生成 2,000 個(gè)點(diǎn)奇唤,遵循二維正態(tài)分布來(lái)繪制一個(gè)空間幸斥,使我們能夠更好地理解結(jié)果。 例如咬扇,我建議使用以下代碼:
num_puntos = 2000
conjunto_puntos = []
for i in xrange(num_puntos):
if np.random.random() > 0.5:
conjunto_puntos.append([np.random.normal(0.0, 0.9), np.random.normal(0.0, 0.9)])
else:
conjunto_puntos.append([np.random.normal(3.0, 0.5), np.random.normal(1.0, 0.5)])
正如我們?cè)谇耙徽轮兴龅哪菢蛹自幔覀兛梢允褂靡恍?Python 圖形庫(kù)來(lái)繪制數(shù)據(jù)。 我建議像以前一樣使用 matplotlib懈贺,但這次我們還將使用基于 matplotlib 的可視化包 Seaborn 和數(shù)據(jù)操作包 pandas经窖,它允許我們使用更復(fù)雜的數(shù)據(jù)結(jié)構(gòu)。
如果未安裝這些軟件包梭灿,則必須先使用pip
執(zhí)行此操作钠至,然后才能運(yùn)行以下代碼。
要顯示隨機(jī)生成的點(diǎn)胎源,我建議使用以下代碼:
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns
df = pd.DataFrame({"x": [v[0] for v in conjunto_puntos],
"y": [v[1] for v in conjunto_puntos]})
sns.lmplot("x", "y", data=df, fit_reg=False, size=6)
plt.show()
此代碼生成二維空間中的點(diǎn)圖棉钧,如下面的截圖所示:
https://jorditorres.org/wp-content/uploads/2016/02/image024.png
在 TensorFlow 中實(shí)現(xiàn)的 k-means 算法將上述點(diǎn)分組,例如在四個(gè)簇中涕蚤,可能像這樣(基于 Shawn Simister 在他的博客中展示的模型 [21]):
import numpy as np
vectors = tf.constant(conjunto_puntos)
k = 4
centroides = tf.Variable(tf.slice(tf.random_shuffle(vectors),[0,0],[k,-1]))
expanded_vectors = tf.expand_dims(vectors, 0)
expanded_centroides = tf.expand_dims(centroides, 1)
assignments = tf.argmin(tf.reduce_sum(tf.square(tf.sub(expanded_vectors, expanded_centroides)), 2), 0)
means = tf.concat(0, [tf.reduce_mean(tf.gather(vectors, tf.reshape(tf.where( tf.equal(assignments, c)),[1,-1])), reduction_indices=[1]) for c in xrange(k)])
update_centroides = tf.assign(centroides, means)
init_op = tf.initialize_all_variables()
sess = tf.Session()
sess.run(init_op)
for step in xrange(100):
_, centroid_values, assignment_values = sess.run([update_centroides, centroides, assignments])
我建議讀者使用以下代碼檢查assignment_values
張量中的結(jié)果宪卿,該代碼生成像上面那樣的圖:
data = {"x": [], "y": [], "cluster": []}
for i in xrange(len(assignment_values)):
data["x"].append(conjunto_puntos[i][0])
data["y"].append(conjunto_puntos[i][1])
data["cluster"].append(assignment_values[i])
df = pd.DataFrame(data)
sns.lmplot("x", "y", data=df, fit_reg=False, size=6, hue="cluster", legend=False)
plt.show()
截圖以及我的代碼執(zhí)行結(jié)果如下圖所示:
https://jorditorres.org/wp-content/uploads/2016/02/image026.png
新的組
我假設(shè)讀者可能會(huì)對(duì)上一節(jié)中介紹的 K-means 代碼感到有些不知所措的诵。 好吧,我建議我們一步一步詳細(xì)分析它佑钾,特別是觀察涉及的張量以及它們?cè)诔绦蛑腥绾无D(zhuǎn)換西疤。
首先要做的是將所有數(shù)據(jù)移到張量。 在常數(shù)張量中休溶,我們使初始點(diǎn)保持隨機(jī)生成:
vectors = tf.constant(conjunto_vectors)
按照上一節(jié)中介紹的算法代赁,為了開(kāi)始我們必須確定初始質(zhì)心。 隨著我前進(jìn)兽掰,一個(gè)選項(xiàng)可能是芭碍,從輸入數(shù)據(jù)中隨機(jī)選擇K
個(gè)觀測(cè)值。 一種方法是使用以下代碼孽尽,它向 TensorFlow 表明窖壕,它必須隨機(jī)地打亂初始點(diǎn)并選擇前K
個(gè)點(diǎn)作為質(zhì)心:
k = 4
centroides = tf.Variable(tf.slice(tf.random_shuffle(vectors),[0,0],[k,-1]))
這K
個(gè)點(diǎn)存儲(chǔ)在 2D 張量中。 要知道這些張量的形狀杉女,我們可以使用tf.Tensor.get_shape()
:
print vectors.get_shape()
print centroides.get_shape()
TensorShape([Dimension(2000), Dimension(2)])
TensorShape([Dimension(4), Dimension(2)])
我們可以看到vectors
是一個(gè)數(shù)組瞻讽,D0 維包含 2000 個(gè)位置,每個(gè)位置一個(gè)向量熏挎,D1 的位置是每個(gè)點(diǎn)x, y
速勇。 相反,centroids
是一個(gè)矩陣坎拐,維度 D0 有四個(gè)位置快集,每個(gè)質(zhì)心一個(gè)位置,D1 和vectors
相同廉白。
接下來(lái),算法進(jìn)入循環(huán)乖寒。 第一步是為每個(gè)點(diǎn)計(jì)算其最接近的質(zhì)心猴蹂,根據(jù)平方歐幾里德距離 [22](只能在我們想要比較距離時(shí)使用):
https://jorditorres.org/wp-content/uploads/2016/02/image028.jpg
為了計(jì)算該值,使用tf.sub(vectors, centroides
楣嘁。 我們應(yīng)該注意到磅轻,雖然減法的兩個(gè)張量都有 2 個(gè)維度,但它們?cè)谝粋€(gè)維度上大小不同(維度 D0 為 2000 和 4)逐虚,實(shí)際上它們也代表不同的東西聋溜。
為了解決這個(gè)問(wèn)題,我們可以使用之前討論過(guò)的一些函數(shù)叭爱,例如tf.expand_dims
撮躁,以便在兩個(gè)張量中插入一個(gè)維度。 目的是將兩個(gè)張量從 2 維擴(kuò)展到 3 維來(lái)使尺寸匹配买雾,以便執(zhí)行減法:
expanded_vectors = tf.expand_dims(vectors, 0)
expanded_centroides = tf.expand_dims(centroides, 1)
tf.expand_dims
在每個(gè)張量中插入一個(gè)維度把曼;在vectors
張量的第一維(D0)杨帽,以及centroides
張量的第二維(D1)。 從圖形上看嗤军,我們可以看到注盈,在擴(kuò)展后的張量中浑侥,每個(gè)維度具有相同的含義:
https://jorditorres.org/wp-content/uploads/2016/02/image031.gif
它似乎得到了解決堆巧,但實(shí)際上,如果你仔細(xì)觀察(在插圖中概述)茵臭,在每種情況下都有大小無(wú)法確定的些維度震叮。 請(qǐng)記住胧砰,使用get_shape()
函數(shù)我們可以發(fā)現(xiàn):
print expanded_vectors.get_shape()
print expanded_centroides.get_shape()
輸出如下:
TensorShape([Dimension(1), Dimension(2000), Dimension(2)])
TensorShape([Dimension(4), Dimension(1), Dimension(2)])
使用 1 表示沒(méi)有指定大小。
但我已經(jīng)展示 TensorFlow 允許廣播冤荆,因此tf.sub
函數(shù)能夠自己發(fā)現(xiàn)如何在兩個(gè)張量之間將元素相減朴则。
直觀地,并且觀察先前的附圖钓简,我們看到兩個(gè)張量的形狀匹配乌妒,并且在這些情況下,兩個(gè)張量在一定維度上具有相同的尺寸外邓。 這些數(shù)學(xué)撤蚊,如 D2 維度所示。 相反损话,在維度 D0 中只有expanded_centroides
的定義大小侦啸。
在這種情況下,如果我們想要在此維度內(nèi)對(duì)元素執(zhí)行減法丧枪,則 TensorFlow 假定expanded_vectors
張量的維度 D0 必須是相同的大小光涂。
對(duì)于expended_centroides
張量的維度 D1 的大小也是如此,其中 TensorFlow 推導(dǎo)出expanded_vectors
張量的尺寸 D1 的大小拧烦。
因此忘闻,在分配步驟(步驟 1)中,算法可以用 TensorFlow 代碼的這四行表示恋博,它計(jì)算平方歐幾里德距離:
diff=tf.sub(expanded_vectors, expanded_centroides)
sqr= tf.square(diff)
distances = tf.reduce_sum(sqr, 2)
assignments = tf.argmin(distances, 0)
而且齐佳,如果我們看一下張量的形狀,我們會(huì)看到它們分別對(duì)應(yīng)diff
债沮,sqr
炼吴,distance
和assign
,如下所示:
TensorShape([Dimension(4), Dimension(2000), Dimension(2)])
TensorShape([Dimension(4), Dimension(2000), Dimension(2)])
TensorShape([Dimension(4), Dimension(2000)])
TensorShape([Dimension(2000)])
也就是說(shuō)疫衩,tf.sub
函數(shù)返回了張量dist
硅蹦,其中包含質(zhì)心和向量的坐標(biāo)的差(維度 D1 表示數(shù)據(jù)點(diǎn),D0 表示質(zhì)心,每個(gè)坐標(biāo)x, y
在維度 D2 中表示)提针。
sqr
張量包含它們的平方命爬。 在dist
張量中,我們可以看到它已經(jīng)減少了一個(gè)維度辐脖,它在tf.reduce_sum
函數(shù)中表示為一個(gè)參數(shù)饲宛。
我用這個(gè)例子來(lái)解釋 TensorFlow 提供的幾個(gè)操作,它們可以用來(lái)執(zhí)行減少?gòu)埩烤S數(shù)的數(shù)學(xué)運(yùn)算嗜价,如tf.reduce_sum
艇抠。在下表中,你可以找到最重要的操作摘要久锥。
操作 | 描述 |
---|---|
tf.reduce_sum | 沿一個(gè)維度計(jì)算元素總和 |
tf.reduce_prod | 沿一個(gè)維度計(jì)算元素的乘積 |
tf.reduce_min | 沿一個(gè)維度計(jì)算元素最小值 |
tf.reduce_max | 沿一個(gè)維度計(jì)算元素最大值 |
tf.reduce_mean | 沿一個(gè)維度計(jì)算元素平均值 |
最后家淤,使用tf.argmin
實(shí)現(xiàn)分配,它返回張量的某個(gè)維度的最小值的索引(在我們的例子中是 D0瑟由,記得它是質(zhì)心)絮重。 我們還有tf.argmax
操作:
手術(shù) | 描述 |
---|---|
tf.argmin | 沿某個(gè)維度返回最小值的索引 |
tf.argmax | 沿某個(gè)維度返回最大值的索引 |
事實(shí)上,上面提到的 4 條語(yǔ)句可以在一行代碼中匯總歹苦,正如我們?cè)谏弦还?jié)中看到的那樣:
assignments = tf.argmin(tf.reduce_sum(tf.square(tf.sub(expanded_vectors, expanded_centroides)), 2), 0)
但無(wú)論如何青伤,內(nèi)部的tensors
,以及它們定義為節(jié)點(diǎn)和執(zhí)行的內(nèi)部圖的操作殴瘦,就像我們之前描述的那樣狠角。
計(jì)算新的質(zhì)心
在那段代碼中,我們可以看到means
張量是k
張量的連接結(jié)果蚪腋,它們對(duì)應(yīng)屬于每個(gè)簇的每個(gè)點(diǎn)的平均值丰歌。
接下來(lái),我將評(píng)論每個(gè) TensorFlow 操作屉凯,這些操作涉及計(jì)算屬于每個(gè)簇的每個(gè)點(diǎn)的平均值 [23]立帖。
- 使用
equal
,我們可以得到布爾張量(Dimension(2000)
)悠砚,它(使用true
)表示assignments
張量K
個(gè)簇匹配的位置晓勇,當(dāng)時(shí)我們正在計(jì)算點(diǎn)的平均值。 - 使用
where
構(gòu)造一個(gè)張量(Dimension(1) x Dimension(2000)
)哩簿,帶有布爾張量中值為true
的位置,布爾張量作為參數(shù)接收的布爾張量酝静。 - 用
reshape
構(gòu)造張量(Dimension(2000) x Dimension(1)
)节榜,其中vectors
張量?jī)?nèi)的點(diǎn)的索引屬于簇c
。 - 用
gather
構(gòu)造張量(Dimension(1) x Dimension(2000)
)别智,它收集形成簇c
的點(diǎn)的坐標(biāo)宗苍。 - 使用
reduce_mean
,構(gòu)造張量(Dimension(1) x Dimension(2)
),其中包含屬于簇c
的所有點(diǎn)的平均值讳窟。
無(wú)論如何让歼,如果讀者想要深入研究代碼,正如我常說(shuō)的那樣丽啡,你可以在 TensorFlow API 頁(yè)面上找到有關(guān)這些操作的更多信息谋右,以及非常具有說(shuō)明性的示例 [24]。
圖表執(zhí)行
最后补箍,我們必須描述上述代碼中改执,與循環(huán)相對(duì)應(yīng)的部分,以及使用means
張量的新值更新質(zhì)心的部分坑雅。
為此辈挂,我們需要?jiǎng)?chuàng)建一個(gè)操作,它將means
張量的值分配到質(zhì)心中裹粤,而不是在執(zhí)行操作run()
時(shí)终蒂,更新的質(zhì)心的值在循環(huán)的下一次迭代中使用:
update_centroides = tf.assign(centroides, means)
在開(kāi)始運(yùn)行圖之前,我們還必須創(chuàng)建一個(gè)操作來(lái)初始化所有變量:
init_op = tf.initialize_all_variables()
此時(shí)一切準(zhǔn)備就緒遥诉。 我們可以開(kāi)始運(yùn)行圖了:
sess = tf.Session()
sess.run(init_op)
for step in xrange(num_steps):
_, centroid_values, assignment_values = sess.run([update_centroides, centroides, assignments])
在此代碼中拇泣,每次迭代中,更新每個(gè)初始點(diǎn)的質(zhì)心和新的簇分配突那。
請(qǐng)注意挫酿,代碼指定了三個(gè)操作,它必須查看run()
調(diào)用的執(zhí)行愕难,并按此順序運(yùn)行早龟。 由于要搜索三個(gè)值,sess.run()
會(huì)在訓(xùn)練過(guò)程中返回元素為三個(gè) numpy 數(shù)組的數(shù)據(jù)結(jié)構(gòu)猫缭,內(nèi)容為相應(yīng)張量葱弟。
由于update_centroides
是一個(gè)結(jié)果是不返回的參數(shù)的操作,因此返回元組中的相應(yīng)項(xiàng)不包含任何內(nèi)容猜丹,因此被排除芝加,用_
來(lái)表示 [25] 。
對(duì)于其他兩個(gè)值射窒,質(zhì)心和每個(gè)簇的分配點(diǎn)藏杖,我們有興趣在完成所有num_steps
次迭代后在屏幕上顯示它們。
我們可以使用簡(jiǎn)單的打印脉顿。 輸出如下:
print centroid_values
[[ 2.99835277e+00 9.89548564e-01]
[ -8.30736756e-01 4.07433510e-01]
[ 7.49640584e-01 4.99431938e-01]
[ 1.83571398e-03 -9.78474259e-01]]
我希望讀者的屏幕上有類(lèi)似的值蝌麸,因?yàn)檫@表明他已成功執(zhí)行了本書(shū)這一章中展示的代碼。
我建議讀者在繼續(xù)之前嘗試更改代碼中的任何值艾疟。 例如num_points
来吩,特別是k
的數(shù)量敢辩,并使用生成圖的先前代碼查看它如何更改assignment_values
張量中的結(jié)果。
請(qǐng)記住弟疆,為了便于測(cè)試本章所述的代碼戚长,可以從 Github [26] 下載。 包含此代碼的文件名是Kmeans.py
怠苔。
在本章中同廉,我們展示了 TensorFlow 的一些知識(shí),特別是基本數(shù)據(jù)結(jié)構(gòu)張量嘀略,它來(lái)自實(shí)現(xiàn) KMeans 聚類(lèi)算法的 TensorFlow 代碼示例恤溶。
有了這些知識(shí),我們就可以在下一章中逐步使用 TensorFlow 構(gòu)建單層神經(jīng)網(wǎng)絡(luò)帜羊。
4. TensorFlow 中的單層神經(jīng)網(wǎng)絡(luò)
在前言中咒程,我評(píng)論說(shuō)深度學(xué)習(xí)的一個(gè)常見(jiàn)用途包括模式識(shí)別。 考慮到這一點(diǎn)讼育,就像初學(xué)者通過(guò)在屏幕上打印“Hello World”開(kāi)始學(xué)習(xí)編程語(yǔ)言一樣帐姻,在深度學(xué)習(xí)中,我們首先要識(shí)別手寫(xiě)數(shù)字奶段。
在本章中饥瓷,我將介紹如何在 TensorFlow 中逐步構(gòu)建具有單個(gè)層的神經(jīng)網(wǎng)絡(luò)。 這個(gè)神經(jīng)網(wǎng)絡(luò)將識(shí)別手寫(xiě)數(shù)字痹籍,它基于 TensorFlow 的初學(xué)者教程 [27] 的不同示例之一呢铆。
鑒于本書(shū)的介紹風(fēng)格,我選擇引導(dǎo)讀者蹲缠,同時(shí)通過(guò)示例的某些步驟簡(jiǎn)化了一些概念和理論上的原因棺克。
如果讀者在閱讀本章后有興趣了解這個(gè)示例的理論概念,我建議閱讀神經(jīng)網(wǎng)絡(luò)和深度學(xué)習(xí) [28]线定,可在線獲取娜谊,它介紹了這個(gè)例子,但深入研究理論概念斤讥。
MNIST 數(shù)據(jù)集
MNIST 數(shù)據(jù)集由一組包含手寫(xiě)數(shù)字的黑白圖像組成纱皆,包含60,000 多個(gè)用于訓(xùn)練模型的示例,以及 10,000 個(gè)用于測(cè)試它的示例芭商。 MNIST 數(shù)據(jù)集可以在 MNIST 數(shù)據(jù)庫(kù) [29] 中找到派草。
這個(gè)數(shù)據(jù)集非常適合大多數(shù)開(kāi)始在實(shí)例上進(jìn)行模式識(shí)別的人,而不必花時(shí)間進(jìn)行數(shù)據(jù)預(yù)處理或格式化铛楣,這是處理圖像時(shí)的兩個(gè)非常重要的步驟近迁,但時(shí)間很長(zhǎng)。
黑白圖像(二值)已經(jīng)標(biāo)準(zhǔn)化為20×20
像的素圖像蛉艾,保留了寬高比钳踊。 對(duì)于這種情況,我們注意到圖像包含灰色像素 [30]勿侯,是歸一化算法的結(jié)果(將所有圖像的分辨率降低到最低級(jí)別之一)拓瞪。 之后,通過(guò)計(jì)算質(zhì)心并將其移動(dòng)到幀的中心助琐,圖像以28×28
像素幀為中心祭埂。 圖像類(lèi)似于此處顯示的圖像:
https://jorditorres.org/wp-content/uploads/2016/02/image034.png
此外,本例所需的學(xué)習(xí)類(lèi)型是監(jiān)督學(xué)習(xí)兵钮;圖像用它們代表的數(shù)字標(biāo)記蛆橡。 這是最常見(jiàn)的機(jī)器學(xué)習(xí)形式。
在這種情況下掘譬,我們首先收集數(shù)字圖像的大數(shù)據(jù)集泰演,每個(gè)數(shù)字都用其值標(biāo)記。 在訓(xùn)練期間葱轩,模型接受圖像并以得分向量的形式產(chǎn)生輸出睦焕,每個(gè)類(lèi)別一個(gè)得分。 我們希望所需類(lèi)別在所有類(lèi)別中得分最高靴拱,但這在訓(xùn)練之前不太可能發(fā)生垃喊。
我們計(jì)算一個(gè)目標(biāo)函數(shù)來(lái)衡量輸出分?jǐn)?shù)和所需分?jǐn)?shù)模式之間的誤差(正如我們?cè)谇懊嬲鹿?jié)中所做的那樣)。 然后袜炕,模型修改其內(nèi)部可調(diào)參數(shù)本谜,稱(chēng)為權(quán)重,來(lái)減少此誤差偎窘。 在典型的深度學(xué)習(xí)系統(tǒng)中乌助,可能存在數(shù)億個(gè)這樣的可調(diào)節(jié)權(quán)重,以及用于訓(xùn)練機(jī)器的數(shù)億個(gè)標(biāo)記示例评架。 我們將考慮一個(gè)較小的例子眷茁,來(lái)幫助理解這種模型的工作原理。
要輕松下載數(shù)據(jù)纵诞,你可以使用從 Google 的網(wǎng)站 [32] 獲取腳本input_data.py
[31]上祈,但它為你上傳到的這本書(shū)的 github 上。 只需將代碼input_data.py
下載到使用 TensorFlow 編寫(xiě)神經(jīng)網(wǎng)絡(luò)的同一工作目錄中浙芙。 在你的應(yīng)用程序中登刺,你只需要按以下方式導(dǎo)入和使用:
import input_data
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
執(zhí)行這兩條指令后,你將在mnist.train
中獲得完整的訓(xùn)練數(shù)據(jù)集嗡呼,并在mnist.test
中設(shè)置測(cè)試數(shù)據(jù)纸俭。 如前所述,每個(gè)元素由一個(gè)圖像組成南窗,標(biāo)記為xs
揍很,并且其對(duì)應(yīng)的標(biāo)簽ys
郎楼,以便更容易表達(dá)處理代碼。 請(qǐng)記住窒悔,所有數(shù)據(jù)集呜袁,訓(xùn)練和測(cè)試集都包含xs
和ys
;此外简珠,訓(xùn)練圖像通過(guò)mnist.train.images
引用阶界,訓(xùn)練標(biāo)簽通過(guò)mnist.train.labels
引用。
如前所述聋庵,圖像由28×28
像素形成膘融,并且可以表示為數(shù)字矩陣。 例如祭玉,數(shù)字 1 的圖像之一可以表示為:
https://jorditorres.org/wp-content/uploads/2016/02/image036-1000x388.png
其中每個(gè)位置表示 0 到 1 之間每個(gè)像素的缺失度氧映。 該矩陣可以表示為28×28 = 784
個(gè)數(shù)的數(shù)組。 實(shí)際上脱货,圖像已經(jīng)變換為 784 維度的向量空間中的一堆點(diǎn)中屯耸。 只是當(dāng)我們將結(jié)構(gòu)減少到 2 維時(shí),我們可能會(huì)丟失部分信息蹭劈,對(duì)于某些計(jì)算機(jī)視覺(jué)算法疗绣,這可能會(huì)影響他們的結(jié)果,但對(duì)于本教程中使用的最簡(jiǎn)單的方法铺韧,這不會(huì)是一個(gè)問(wèn)題锄禽。
總而言之捧存,我們?cè)?2D 中擁有張量mnist.train.images
静尼,其中調(diào)用函數(shù)get_shape()
表示其形狀:
TensorShape([Dimension(60000), Dimension(784)])
第一維索引每個(gè)圖像和第二維是每個(gè)像素挖炬。 張量的每個(gè)元素是 0 到 1 之間的每個(gè)像素的強(qiáng)度。
此外料仗,我們有 0 到 9 之間的數(shù)字形式的標(biāo)簽湾盗,表示每個(gè)圖像代表哪個(gè)數(shù)字。 在這個(gè)例子中立轧,我們將標(biāo)簽表示為 10 個(gè)位置的向量格粪,其中所表示數(shù)字的對(duì)應(yīng)位置是 1 而其余為 0。 所以mnist.train.labels es
是形如TensorShape([Dimension(60000), Dimension10)])
的張量氛改。
人造神經(jīng)元
雖然本書(shū)并未關(guān)注神經(jīng)網(wǎng)絡(luò)的理論概念帐萎,但簡(jiǎn)要而直觀地介紹神經(jīng)元如何學(xué)習(xí)訓(xùn)練數(shù)據(jù),將有助于讀者了解正在發(fā)生的事情胜卤。 那些已經(jīng)了解該理論并且只是尋求如何使用 TensorFlow 的讀者可以跳過(guò)本節(jié)疆导。
讓我們看一個(gè)神經(jīng)元如何學(xué)習(xí)的簡(jiǎn)單但說(shuō)明性的例子。 假設(shè)有一組標(biāo)記為“方形”和“圓形”的點(diǎn)葛躏。 給定一個(gè)新的點(diǎn)X
澈段,我們想知道對(duì)應(yīng)哪個(gè)標(biāo)簽:
https://jorditorres.org/wp-content/uploads/2016/02/Screen-Shot-2016-02-16-at-09.30.14.png
通常的近似可能是繪制一條劃分兩組的直線并將其用作分類(lèi)器:
https://jorditorres.org/wp-content/uploads/2016/02/Screen-Shot-2016-02-16-at-09.30.09.png
在這種情況下悠菜,輸入數(shù)據(jù)由形狀為(x, y)
的向量表示,表示此二維空間中的坐標(biāo)败富,并且我們的函數(shù)返回“0”或“1”(線上方或下方)來(lái)了解如何將其歸類(lèi)為“方形”或“圓形”李剖。 在數(shù)學(xué)上,正如我們?cè)诰€性回歸章節(jié)中所學(xué)到的囤耳,“直線”(分類(lèi)器)可以表示為y = W * x + b
。
推廣時(shí)偶芍,神經(jīng)元必須學(xué)習(xí)權(quán)重W
(與輸入數(shù)據(jù)X
維度相同)和偏移量b
(在神經(jīng)元中稱(chēng)為偏置)充择,來(lái)學(xué)習(xí)如何分類(lèi)這些值。 利用它們匪蟀,神經(jīng)元將計(jì)算權(quán)重輸入X
和W
的加權(quán)和椎麦,并添加偏移b
;最后神經(jīng)元將應(yīng)用非線性“激活”函數(shù)來(lái)產(chǎn)生“0”或“1”的結(jié)果材彪。
神經(jīng)元的功能可以更正式地表示為:
https://jorditorres.org/wp-content/uploads/2016/02/image043.png
在為我們的神經(jīng)元定義了這個(gè)函數(shù)后观挎,我們想知道神經(jīng)元如何從帶有“方塊”和“圓圈”的標(biāo)記數(shù)據(jù)中學(xué)習(xí)參數(shù)W
和b
,以便稍后標(biāo)記新點(diǎn)X
段化。
第一種方法可以類(lèi)似于我們對(duì)線性回歸所做的嘁捷,即用已知的標(biāo)記數(shù)據(jù)喂養(yǎng)神經(jīng)元,并將獲得的結(jié)果與真實(shí)的結(jié)果進(jìn)行比較显熏。 然后雄嚣,在迭代時(shí),調(diào)整W
和b
來(lái)使誤差最小化喘蟆,如第 2 章中線性回歸線所示缓升。
一旦我們得到W
和b
參數(shù),我們就可以計(jì)算加權(quán)和蕴轨,現(xiàn)在我們需要函數(shù)將存儲(chǔ)在z
中的結(jié)果轉(zhuǎn)換為0
或1
港谊。 有幾個(gè)可用的激活函數(shù),對(duì)于這個(gè)例子橙弱,我們可以使用一個(gè)名為 sigmoid [33] 的流行函數(shù)歧寺,返回 0 到 1 之間的實(shí)數(shù)值。
https://jorditorres.org/wp-content/uploads/2016/02/image046.png
看看公式棘脐,我們發(fā)現(xiàn)它將傾向于返回接近 0 或 1 的值成福。 如果輸入z
足夠大且為正,則exp(-z)
為零荆残,然后y
為 1奴艾。 如果輸入z
足夠大且為負(fù),則exp(-z)
也會(huì)變?yōu)榇笳龜?shù)内斯,因此分母變大蕴潦,最終y
變?yōu)?0像啼。 如果我們繪制函數(shù),它將如下所示:
https://jorditorres.org/wp-content/uploads/2016/02/image045.png
從這里我們已經(jīng)介紹了如何定義神經(jīng)元潭苞,但神經(jīng)網(wǎng)絡(luò)實(shí)際上是以不同方式互相連接忽冻,并使用不同激活函數(shù)的神經(jīng)元組合。 鑒于本書(shū)的范圍此疹,我不會(huì)涉及神經(jīng)網(wǎng)絡(luò)的所有擴(kuò)展僧诚,但我向你保證它真的令人興奮。
只是提到神經(jīng)網(wǎng)絡(luò)的一個(gè)特定情況(其中第 5 章基于)蝗碎,神經(jīng)元組織為層的形式湖笨,其中下層(輸入層)接收輸入,上層(輸出層)生成響應(yīng)值蹦骑。 神經(jīng)網(wǎng)絡(luò)可以有幾個(gè)中間層慈省,稱(chēng)為隱藏層。 表示這種情況的直觀方式是:
https://jorditorres.org/wp-content/uploads/2016/02/image049.gif
在這些網(wǎng)絡(luò)中眠菇,每層的神經(jīng)元與前一層的神經(jīng)元通信來(lái)接收信息边败,然后將其結(jié)果傳遞給下一層的神經(jīng)元。
如前所述捎废,除了Sigmoid之外還有更多的激活函數(shù)笑窜,每個(gè)激活函數(shù)具有不同的屬性。例如登疗,當(dāng)我們想要在輸出層將數(shù)據(jù)分類(lèi)為兩個(gè)以上的類(lèi)時(shí)怖侦,我們可以使用 Softmax [34] 激活函數(shù),它是 sigmoid 函數(shù)的泛化谜叹。 Softmax 能夠獲得每個(gè)類(lèi)的概率匾寝,因此它們的和為 1,最可能的結(jié)果是概率最高的結(jié)果荷腊。
一個(gè)簡(jiǎn)單的例子:Softmax
請(qǐng)記住艳悔,要解決的問(wèn)題是,給定輸入圖像女仰,我們得到它屬于某個(gè)數(shù)字的概率猜年。 例如,我們的模型可以預(yù)測(cè)疾忍,圖像 80% 是“9”乔外,但是有 5% 的機(jī)會(huì)為“8”(由于可疑性較低的痕跡),并且還給出一罩,一定的低概率為任何其他數(shù)字杨幼。 識(shí)別手寫(xiě)數(shù)字存在一些不確定性,我們無(wú)法以 100% 的置信度識(shí)別數(shù)字。 在這種情況下差购,概率分布使我們更好地了解我們對(duì)預(yù)測(cè)的信心四瘫。
因此,我們有一個(gè)輸出向量欲逃,其中包含不同輸出標(biāo)簽的概率分布找蜜,這是多余的。 這是一個(gè)具有 10 個(gè)概率值的向量稳析,每個(gè)概率值對(duì)應(yīng)于 0 到 9 的每個(gè)數(shù)字洗做,并且所有概率總和為 1。
如前所述彰居,我們通過(guò)使用激活函數(shù)為 softmax 的輸出層來(lái)實(shí)現(xiàn)此目的诚纸。 具有 softmax 函數(shù)的神經(jīng)元的輸出,取決于其層的其他神經(jīng)元的輸出裕菠,因?yàn)樗鼈兊乃休敵霰仨毧偤蜑?1。
softmax 函數(shù)有兩個(gè)主要步驟:首先闭专,計(jì)算屬于某個(gè)標(biāo)簽的圖像的“證據(jù)”奴潘,然后將證據(jù)轉(zhuǎn)換為每個(gè)可能標(biāo)簽的概率。
歸屬的證據(jù)
測(cè)量某個(gè)圖像屬于特定類(lèi)別/標(biāo)簽的證據(jù)影钉,通常的近似是計(jì)算像素強(qiáng)度的加權(quán)和画髓。 當(dāng)高強(qiáng)度的像素恰好不在給定類(lèi)中時(shí),該權(quán)重為負(fù)平委,如果該像素在該類(lèi)中頻繁出現(xiàn)奈虾,則該權(quán)重為正。
讓我們看一個(gè)圖形示例:假設(shè)一個(gè)數(shù)學(xué)“0”的學(xué)習(xí)模型(我們將看到以后如何學(xué)習(xí))廉赔。 此時(shí)肉微,我們將模型定義為“某事物”,其中包含了解數(shù)字是否屬于特定類(lèi)的信息蜡塌。 在這種情況下碉纳,我們選擇了如下所示的模型,其中紅色(或 b/n 版本的亮灰色)代表負(fù)例(也就是馏艾,減少對(duì)“0”中存在的那些像素的支持)劳曹,而藍(lán)色(b/n 版的深灰色)代表了正例±拍Γ看看它:
https://jorditorres.org/wp-content/uploads/2016/02/image050.png
想象一下28×28
像素的白紙铁孵,并畫(huà)上“0”。 通常我們的零將繪制在藍(lán)色區(qū)域中(請(qǐng)記住房资,我們?cè)?code>20×20繪圖區(qū)域周?chē)粝铝艘恍┛臻g蜕劝,稍后將其居中)。
很明顯,如果我們的繪圖穿過(guò)紅色區(qū)域熙宇,很可能我們沒(méi)有繪制零鳖擒。 因此,使用一種度量標(biāo)準(zhǔn)烫止,獎(jiǎng)勵(lì)那些踩到藍(lán)色區(qū)域的像素蒋荚,并懲罰那些踩到紅色區(qū)域的像素,似乎是合理的馆蠕。
現(xiàn)在考慮“3”:很明顯期升,我們的模型的“0”的紅色區(qū)域?qū)土P它為“0”的概率。 但是如果參考模型是下面的那個(gè)互躬,通常形成“3”的像素將遵循藍(lán)色區(qū)域播赁; “0”的繪制也會(huì)進(jìn)入紅色區(qū)域。
https://jorditorres.org/wp-content/uploads/2016/02/image052.png
我希望看到這兩個(gè)例子的讀者理解吼渡,所解釋的近似如何讓我們估計(jì)哪張圖代表哪個(gè)數(shù)字容为。
下圖顯示了從 MNIST 數(shù)據(jù)集中學(xué)習(xí)的十個(gè)不同標(biāo)簽/類(lèi)的示例(從 Tensorflow [35] 的示例中提取)寺酪。 請(qǐng)記住坎背,紅色(亮灰色)表示負(fù)權(quán)重,藍(lán)色(深灰色)表示正值寄雀。
https://jorditorres.org/wp-content/uploads/2016/02/image054.png
以更正式的方式得滤,我們可以說(shuō)給出輸入x
的類(lèi)i
的證據(jù)表示為:
https://jorditorres.org/wp-content/uploads/2016/02/image056.png
其中i
表示類(lèi)(在我們的情況下,介于 0 和 9 之間)盒犹,j
是對(duì)輸入圖像求和的索引懂更。 最后,Wi
表示上述權(quán)重急膀。
請(qǐng)記住沮协,一般來(lái)說(shuō),模型還包括一個(gè)表示偏置的額外參數(shù)卓嫂,增加了一些基本不確定性皂股。 在我們的情況下,公式最終就像這樣:
https://jorditorres.org/wp-content/uploads/2016/02/image058.png
對(duì)于每個(gè)i
(在 0 和 9 之間)命黔,我們得到 784 個(gè)元素(28×28
)的矩陣Wi
呜呐,其中每個(gè)元素j
乘以輸入圖像的相應(yīng)分量j
,共有 784 個(gè)分量悍募,然后加上bi
蘑辑。矩陣演算和索引的圖形視圖是這樣的:
https://jorditorres.org/wp-content/uploads/2016/02/image061.gif
歸屬概率
我們?cè)u(píng)論說(shuō),第二步是計(jì)算概率坠宴。 具體來(lái)說(shuō)洋魂,我們使用 softmax 函數(shù)將證據(jù)總和轉(zhuǎn)換為預(yù)測(cè)概率,表示為y
:
https://jorditorres.org/wp-content/uploads/2016/02/image062.png
請(qǐng)記住,輸出向量必須是和為 1 的概率函數(shù)副砍。 為了標(biāo)準(zhǔn)化每個(gè)成分衔肢,softmax 函數(shù)使用每個(gè)輸入的指數(shù)值,然后按如下方式對(duì)它們進(jìn)行標(biāo)準(zhǔn)化:
https://jorditorres.org/wp-content/uploads/2016/02/image064.png
使用指數(shù)時(shí)獲得的效果是權(quán)重的乘法效應(yīng)豁翎。 此外角骤,當(dāng)一個(gè)類(lèi)的證據(jù)很小時(shí),這個(gè)類(lèi)的支持由之前權(quán)重的一小部分減少心剥。 此外邦尊,softmax 對(duì)權(quán)重進(jìn)行歸一化,使它們總和為 1优烧,從而產(chǎn)生概率分布蝉揍。
這種函數(shù)的一個(gè)有趣的事實(shí)是,好的預(yù)測(cè)將有一個(gè)接近 1 的輸出值畦娄,而所有其他輸出將接近零又沾;在弱預(yù)測(cè)中,某些標(biāo)簽可能會(huì)顯示類(lèi)似的支持熙卡。
在 TensorFlow 中編程
在簡(jiǎn)要描述了算法做了什么來(lái)識(shí)別數(shù)字之后杖刷,我們可以在 TensorFlow 中實(shí)現(xiàn)它。 為此再膳,我們可以快速了解張量應(yīng)如何存儲(chǔ)我們的數(shù)據(jù)和模型參數(shù)挺勿。 為此曲横,下圖描述了數(shù)據(jù)結(jié)構(gòu)及其關(guān)系(來(lái)幫助讀者輕松回憶我們的每個(gè)問(wèn)題):
https://jorditorres.org/wp-content/uploads/2016/02/image066.png
首先喂柒,我們創(chuàng)建兩個(gè)變量來(lái)包含權(quán)重W
和偏置b
:
W = tf.Variable(tf.zeros([784,10]))
b = tf.Variable(tf.zeros([10]))
這些變量是使用tf.Variable
函數(shù)和變量的初始值創(chuàng)建的;在這種情況下禾嫉,我們用包含零的常數(shù)張量初始化張量灾杰。
我們看到W
的形狀為[Dimension(784), Dimension(10)]
,由其參數(shù)定義熙参,常數(shù)張量tf.zeros
和W
一樣為[784,10]
艳吠。偏置b
也是一樣,由其參數(shù)將形狀規(guī)定為[Dimension(10)]
孽椰。
矩陣W
具有該大小昭娩,因?yàn)槲覀兿胍獮?10 個(gè)可能的數(shù)字中的每一個(gè)乘以 784 個(gè)位置的圖像向量,并在與b
相加之后產(chǎn)生一定數(shù)量的證據(jù)黍匾。
在使用 MNIST 進(jìn)行研究的情況下栏渺,我們還創(chuàng)建了二維張量來(lái)保存x
點(diǎn)的信息,使用以下代碼行??:
x = tf.placeholder("float", [None, 784])
張量x
將用于存儲(chǔ) MNIST 圖像锐涯,作為 784 個(gè)浮點(diǎn)向量(我們使用None
指示維度可以是任何大锌恼铩;在我們的例子中它將等于學(xué)習(xí)過(guò)程中包含的元素?cái)?shù)量)。
現(xiàn)在我們定義了張量霎终,我們可以實(shí)現(xiàn)我們的模型滞磺。 為此,TensorFlow 提供了幾個(gè)操作莱褒,即tf.nn.softmax(logits, name=None)
击困。它是其中一個(gè)可用的操作,實(shí)現(xiàn)了前面描述的 softmax 函數(shù)保礼。 參數(shù)必須是張量沛励,并且名稱(chēng)可選。 該函數(shù)返回類(lèi)型和形狀與傳遞的參數(shù)張量相同的張量炮障。
在我們的例子中袭厂,我們?yōu)檫@個(gè)函數(shù)提供了圖像向量x
乘以權(quán)重矩陣W
加上b
的結(jié)果張量:
y = tf.nn.softmax(tf.matmul(x,W) + b)
一旦指定了模型實(shí)現(xiàn)乡数,我們就可以使用迭代訓(xùn)練算法,指定必要的代碼來(lái)獲得權(quán)重W
和偏置b
。 對(duì)于每次迭代颁虐,訓(xùn)練算法獲得訓(xùn)練數(shù)據(jù),應(yīng)用神經(jīng)網(wǎng)絡(luò)并將獲得的結(jié)果與預(yù)期結(jié)果進(jìn)行比較枫笛。
要確定模型何時(shí)足夠好法精,我們必須定義“足夠好”的含義。 正如在前面的章節(jié)中所看到的系馆,通常的方法是定義相反的東西:模型使用損失函數(shù)的“壞”的程度送漠。 在這種情況下,目標(biāo)是獲得使函數(shù)最小的W
和b
的值由蘑,它指示模型“壞”的程度闽寡。
結(jié)果輸出與訓(xùn)練數(shù)據(jù)的預(yù)期輸出之間的誤差有不同的度量標(biāo)準(zhǔn)。 一個(gè)常見(jiàn)的度量是均方誤差或平方歐幾里德距離尼酿,這是以前見(jiàn)過(guò)的爷狈。 盡管如此,一些研究在神經(jīng)網(wǎng)絡(luò)中為此目的提出了其他指標(biāo)裳擎,例如在我們的例子中使用的交叉熵誤差涎永。 此度量標(biāo)準(zhǔn)的計(jì)算方式如下:
https://jorditorres.org/wp-content/uploads/2016/02/image068.png
其中y
是概率的預(yù)測(cè)分布,y'
是從訓(xùn)練數(shù)據(jù)集的標(biāo)簽中獲得的實(shí)際分布鹿响。 我們不會(huì)詳細(xì)討論交叉熵背后的數(shù)學(xué)及其在神經(jīng)網(wǎng)絡(luò)中的位置羡微,因?yàn)樗h(yuǎn)比本書(shū)的預(yù)期范圍復(fù)雜得多;只是表明當(dāng)兩個(gè)分布相同時(shí)有最小值惶我。 同樣妈倔,如果讀者想要了解此函數(shù)的細(xì)節(jié),我們建議閱讀神經(jīng)網(wǎng)絡(luò)和深度學(xué)習(xí) [36]指孤。
要實(shí)現(xiàn)交叉熵度量启涯,我們需要一個(gè)新的占位符來(lái)表示正確的標(biāo)簽:
y_ = tf.placeholder("float", [None,10])
用這個(gè)占位符贬堵,我們可以使用以下代碼行實(shí)現(xiàn)交叉熵,代表我們的損失函數(shù):
cross_entropy = -tf.reduce_sum(y_*tf.log(y))
首先结洼,我們使用 TensorFlow 中的內(nèi)置函數(shù)tf.log()
計(jì)算每個(gè)元素y
的對(duì)數(shù)黎做,然后我們將它們乘以每個(gè)y_
元素。 最后松忍,使用tf.reduce_sum
蒸殿,我們對(duì)張量的所有元素求和(稍后我們將看到圖像以批量的形式訪問(wèn),在這種情況下鸣峭,交叉熵的值對(duì)應(yīng)于圖像批量y
而不是單個(gè)圖像)宏所。
在迭代中,一旦確定了樣本的誤差摊溶,我們必須更正模型(在我們的例子中是修改參數(shù)W
和b
)來(lái)減少下一次迭代中計(jì)算和預(yù)期輸出之間的差異爬骤。
最后,它仍然只是指定了這個(gè)迭代式最小化過(guò)程莫换。 在神經(jīng)網(wǎng)絡(luò)中有幾種用于此目的的算法霞玄;我們將使用反向傳播(誤差向后傳播)算法,并且如其名稱(chēng)所示拉岁,它向后傳播在輸出處獲得的誤差坷剧,來(lái)重新計(jì)算W
的權(quán)重,尤其是對(duì)于多層神經(jīng)網(wǎng)絡(luò)很重要喊暖。
該方法與先前看到的梯度下降方法一起使用惫企,該方法使用交叉熵?fù)p失函數(shù),允許我們計(jì)算每次迭代時(shí)參數(shù)必須改變多少陵叽,以便在每個(gè)時(shí)刻使用可用的本地信息來(lái)減少誤差狞尔。 在我們的例子中,直觀地說(shuō)咨跌,它包括在每次迭代時(shí)稍微改變權(quán)重W
(這一點(diǎn)由學(xué)習(xí)率超參數(shù)表示沪么,表示變化的速度)來(lái)減少錯(cuò)誤硼婿。
由于在我們的例子中我們只有一層神經(jīng)網(wǎng)絡(luò)锌半,我們不會(huì)進(jìn)入反向傳播方法。 只需記得 TensorFlow 知道整個(gè)計(jì)算圖寇漫,允許它應(yīng)用優(yōu)化算法來(lái)找到訓(xùn)練模型的訓(xùn)練函數(shù)的正確梯度刊殉。
因此,在我們使用 MNIST 圖像的示例中州胳,以下代碼行表明我們使用反向傳播算法和梯度下降算法來(lái)最小化交叉熵记焊,學(xué)習(xí)率為 0.01:
train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)
到這里之后,我們已經(jīng)指定了所有問(wèn)題栓撞,我們可以通過(guò)實(shí)例化tf.Session()
來(lái)開(kāi)始計(jì)算遍膜,它負(fù)責(zé)在系統(tǒng)碗硬,CPU 或 GPU 上的可用設(shè)備中執(zhí)行 TensorFlow 操作:
sess = tf.Session()
接下來(lái),我們可以執(zhí)行初始化所有變量的操作:
sess.run(tf.initialize_all_variables())
從現(xiàn)在開(kāi)始瓢颅,我們可以開(kāi)始訓(xùn)練我們的模型恩尾。 執(zhí)行時(shí),train_step
的返回參數(shù)將梯度下降應(yīng)用于所涉及的參數(shù)挽懦。 因此翰意,可以通過(guò)重復(fù)執(zhí)行train_step
來(lái)實(shí)現(xiàn)模型的訓(xùn)練。 假設(shè)我們要迭代 1000 次train_step
信柿;我們必須指定以下代碼行:
for i in range(1000):
batch_xs, batch_ys = mnist.train.next_batch(100)
sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys})
循環(huán)內(nèi)的第一行指定冀偶,對(duì)于每次迭代,挑選從訓(xùn)練數(shù)據(jù)集中隨機(jī)采樣的 100 個(gè)數(shù)據(jù)輸入的批量渔嚷。 我們可以在每次迭代時(shí)使用所有訓(xùn)練數(shù)據(jù)进鸠,但為了使第一個(gè)示例更加靈活,我們每次都使用一個(gè)小樣本形病。 第二行表示之前獲得的輸入必須提供給相應(yīng)的占位符堤如。
最后,基于梯度下降的機(jī)器學(xué)習(xí)算法可以利用 TensorFlow 自動(dòng)微分的功能窒朋。 TensorFlow 用戶只需定義預(yù)測(cè)模型的計(jì)算架構(gòu)搀罢,將其與目標(biāo)函數(shù)組合,然后只需添加數(shù)據(jù)即可侥猩。
TensorFlow 已經(jīng)管理了學(xué)習(xí)過(guò)程背后的相關(guān)微分榔至。 當(dāng)執(zhí)行minimize()
方法時(shí),TensorFlow 識(shí)別損失函數(shù)所依賴的變量集欺劳,并計(jì)算每個(gè)變量的梯度唧取。 如果你想知道如何實(shí)現(xiàn)微分,可以查看ops/gradients.py
文件 [37]划提。
模型評(píng)估
訓(xùn)練后必須評(píng)估模型枫弟,來(lái)查看有多“好”(或多“壞”)。 例如鹏往,我們可以計(jì)算預(yù)測(cè)中命中和未命中的百分比淡诗,看看哪些例子是正確預(yù)測(cè)的。 在前面的章節(jié)中伊履,我們看到tf.argmax(y, 1)
函數(shù)韩容,根據(jù)張量的給定軸返回最高值的索引。 實(shí)際上唐瀑,tf.argmax(y, 1)
是對(duì)于每個(gè)輸入的群凶,概率最高的標(biāo)簽,而 tf.argmax(y_, 1)
是正確標(biāo)簽哄辣。 使用tf.equal
方法请梢,我們可以比較我們的預(yù)測(cè)是否與正確的標(biāo)簽重合:
correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1))
指令返回布爾列表赠尾。 要確定哪些預(yù)測(cè)部分是正確的,我們可以將值轉(zhuǎn)換為數(shù)值變量(浮點(diǎn))并執(zhí)行以下操作:
accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
例如毅弧,[True, False, True, True]
將變?yōu)?code>[1, 0, 1, 1]萍虽,平均值將為 0.75,表示準(zhǔn)確率形真。 現(xiàn)在我們可以使用mnist.test
作為feed_dict參
數(shù)來(lái)查詢我們的測(cè)試數(shù)據(jù)集的準(zhǔn)確率:
print sess.run(accuracy, feed_dict={x: mnist.test.images, y_: mnist.test.labels})
我的大約為 91%杉编。 這些結(jié)果好嗎? 我認(rèn)為它們太棒了咆霜,因?yàn)檫@意味著讀者已經(jīng)能夠使用 TensorFlow 編程并執(zhí)行第一個(gè)神經(jīng)網(wǎng)絡(luò)邓馒。
另一個(gè)問(wèn)題是其他模型可能提供更好的準(zhǔn)確性,在下一章中介紹包含更多層的神經(jīng)網(wǎng)絡(luò)蛾坯。
讀者將在本書(shū) github [38] 的文件RedNeuronalSimple.py
中找到本章中使用的全部代碼光酣。 為了提供它的全局視圖,我將把它放在一起:
import input_data
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
import tensorflow as tf
x = tf.placeholder("float", [None, 784])
W = tf.Variable(tf.zeros([784,10]))
b = tf.Variable(tf.zeros([10]))
matm=tf.matmul(x,W)
y = tf.nn.softmax(tf.matmul(x,W) + b)
y_ = tf.placeholder("float", [None,10])
cross_entropy = -tf.reduce_sum(y_*tf.log(y))
train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)
sess = tf.Session()
sess.run(tf.initialize_all_variables())
for i in range(1000):
batch_xs, batch_ys = mnist.train.next_batch(100)
sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys})
correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
print sess.run(accuracy, feed_dict={x: mnist.test.images, y_: mnist.test.labels})
5. TensorFlow 中的多層神經(jīng)網(wǎng)絡(luò)
在本章中脉课,我將與讀者一起編寫(xiě)一個(gè)簡(jiǎn)單的深度學(xué)習(xí)神經(jīng)網(wǎng)絡(luò)救军,該網(wǎng)絡(luò)使用與前一章相同的 MNIST 數(shù)字識(shí)別問(wèn)題。
隨著我的前進(jìn)倘零,深度學(xué)習(xí)神經(jīng)網(wǎng)絡(luò)由疊在一起的多個(gè)層組成唱遭。 具體來(lái)說(shuō),在本章中我們將構(gòu)建一個(gè)卷積網(wǎng)絡(luò)呈驶,這是深度學(xué)習(xí)的典型例子拷泽。 卷?yè)P(yáng)神經(jīng)網(wǎng)絡(luò)由 Yann LeCunn 等人于 1998 年推出并推廣。 這些卷積網(wǎng)絡(luò)最近引領(lǐng)了圖像識(shí)別領(lǐng)域的最新技術(shù)袖瞻;例如:在我們的數(shù)字識(shí)別案例中司致,它們的準(zhǔn)確度高于 99%。
在本章的其余部分聋迎,我將以示例代碼為主脂矫,我將解釋這些網(wǎng)絡(luò)的兩個(gè)最重要的概念:卷積和池化,而不輸入?yún)?shù)的細(xì)節(jié)霉晕,鑒于本書(shū)的介紹性質(zhì)庭再。 但是,讀者將能夠運(yùn)行所有代碼娄昆,我希望它能讓你了解卷積網(wǎng)絡(luò)背后的通用思想佩微。
卷積神經(jīng)網(wǎng)絡(luò)
卷積神經(jīng)網(wǎng)絡(luò)(也稱(chēng)為 CNN 或 CovNets)是深度學(xué)習(xí)的一個(gè)特例缝彬,并且在計(jì)算機(jī)視覺(jué)領(lǐng)域產(chǎn)生了重大影響萌焰。
CNN 的典型特征是它們幾乎總是將圖像作為輸入,這產(chǎn)生了更有效的實(shí)現(xiàn)并且減少所需參數(shù)的數(shù)量谷浅。 讓我們看看我們的 MNIST 數(shù)字識(shí)別示例:在讀取 MNIST 數(shù)據(jù)并使用 TensorFlow 定義占位符之后扒俯,就像我們?cè)谏弦粋€(gè)示例中所做的那樣:
import input_data
mnist = input_data.read_data_sets('MNIST_data', one_hot=True)
import tensorflow as tf
x = tf.placeholder("float", shape=[None, 784])
y_ = tf.placeholder("float", shape=[None, 10])
我們可以重建輸入數(shù)據(jù)圖像的原始形狀奶卓。 我們可以這樣做:
x_image = tf.reshape(x, [-1,28,28,1])
這里我們將輸入形狀更改為 4D 張量,第二維和第三維對(duì)應(yīng)于圖像的寬度和高度撼玄,而最后一維對(duì)應(yīng)于顏色通道的數(shù)量夺姑,在這種情況下為 1。
通過(guò)這種方式掌猛,我們可以將神經(jīng)網(wǎng)絡(luò)的輸入視為大小為28×28
的二維空間盏浙,如圖所示:
https://jorditorres.org/wp-content/uploads/2016/02/image072-300x282.png
定義卷積神經(jīng)網(wǎng)絡(luò)有兩個(gè)基本原則:濾波器和特征映射。 這些原則可以表示為特定的神經(jīng)元分組荔茬,我們將很快看到废膘。 但首先,鑒于它們?cè)?CNN 中的重要性慕蔚,我們將簡(jiǎn)要介紹這兩個(gè)原則丐黄。
直覺(jué)上,我們可以說(shuō)卷積層的主要目的是檢測(cè)圖像中的特征或視覺(jué)特征孔飒,考慮邊緣灌闺,線條,顏色斑點(diǎn)等坏瞄。 這是由我們剛剛討論過(guò)的桂对,連接輸入層的隱藏層來(lái)處理的。 在我們感興趣的 CNN 的案例中鸠匀,輸入數(shù)據(jù)沒(méi)有完全連接到第一個(gè)隱藏層的神經(jīng)元接校;這只發(fā)生在輸入神經(jīng)元中的一個(gè)小型局部空間中,輸入神經(jīng)元存儲(chǔ)圖像像素值狮崩。 這可以看作:
https://jorditorres.org/wp-content/uploads/2016/02/image074.png
更確切地說(shuō)蛛勉,在給定的示例中,隱藏層的每個(gè)神經(jīng)元與輸入層的5×5
小區(qū)域(因此是 25 個(gè)神經(jīng)元)連接睦柴。
我們可以認(rèn)為這是一個(gè)大小為5×5
的窗口诽凌,它滑過(guò)包含輸入圖像的整個(gè)28×28
大小的輸入層。 窗口滑過(guò)整個(gè)神經(jīng)元層坦敌。 對(duì)于窗口的每個(gè)位置侣诵,隱藏層中都有一個(gè)處理該信息的神經(jīng)元。
我們可以通過(guò)假設(shè)窗口從圖像的左上角開(kāi)始來(lái)可視化狱窘;這將信息提供給隱藏層的第一個(gè)神經(jīng)元杜顺。 然后窗口向右滑動(dòng)一個(gè)像素;我們將這個(gè)5×5
區(qū)域與隱藏層中的第二個(gè)神經(jīng)元連接起來(lái)蘸炸。 我們繼續(xù)這樣躬络,直到整個(gè)空間從上到下,從左到右被窗口覆蓋搭儒。
https://jorditorres.org/wp-content/uploads/2016/02/image076.png
分析我們提出的具體案例穷当,我們觀察到提茁,給定一個(gè)大小為28×28
的輸入圖像和一個(gè)大小為5×5
的窗口,在第一個(gè)隱藏層中產(chǎn)生了24×24
的神經(jīng)元馁菜,因?yàn)槲覀冎荒苓@樣做茴扁,在觸及輸入圖像的右下邊緣之前,將窗口向下移動(dòng) 23 次汪疮,向右移動(dòng) 23 次峭火。 這假設(shè)窗口每次只移動(dòng) 1 個(gè)像素,因此新窗口與剛剛前進(jìn)的舊窗口重疊智嚷。
但是躲胳,可以在卷積層中一次移動(dòng)多于 1 個(gè)像素,該參數(shù)稱(chēng)為stride
(步長(zhǎng))纤勒。 另一個(gè)擴(kuò)展是用零(或其他值)填充邊緣坯苹,以便窗口可以在圖像的邊緣上滑動(dòng),這可以產(chǎn)生更好的結(jié)果摇天。 控制此功能的參數(shù)稱(chēng)為padding
(填充)[39]粹湃,你可以使用該參數(shù)確定填充的大小。 鑒于本書(shū)的介紹性質(zhì)泉坐,我們不會(huì)進(jìn)一步詳細(xì)介紹這兩個(gè)參數(shù)为鳄。
鑒于我們的研究案例,并遵循前一章的形式腕让,我們將需要一個(gè)偏置值b
和一個(gè)5×5
的權(quán)重矩陣W
來(lái)連接隱層和輸入層的神經(jīng)元孤钦。CNN的一個(gè)關(guān)鍵特性是,該權(quán)重矩陣W
和偏置b
在隱藏層中的所有神經(jīng)元之間共享纯丸;我們對(duì)隱藏層中的神經(jīng)元使用相同的W
和b
偏形。 在我們的情況下,這是24×24
(576)個(gè)神經(jīng)元觉鼻。 讀者應(yīng)該能夠看到俊扭,與完全連接的神經(jīng)網(wǎng)絡(luò)相比,這大大減少了人們需要的權(quán)重參數(shù)坠陈。 具體而言萨惑,由于共享權(quán)重矩陣W
,這從 14000(5x5x24x24
)減少到僅 25(5x5
)仇矾。
這個(gè)共享矩陣W
和偏置b
通常在 CNN 的上下文中稱(chēng)為核或過(guò)濾器庸蔼。 這些過(guò)濾器類(lèi)似于用于修飾圖像的圖像處理程序,在我們的例子中用于查找微分特征贮匕。 我建議查看 GIMP [40] 手冊(cè)中的示例姐仅,以便了解卷積過(guò)程的工作原理。
矩陣和偏置定義了核。 核只檢測(cè)圖像中的某個(gè)相關(guān)特征萍嬉,因此建議使用多個(gè)核乌昔,每個(gè)核對(duì)應(yīng)我們想要檢測(cè)的每個(gè)特征隙疚。 這意味著 CNN 中的完整卷積層由幾個(gè)核組成壤追。 表示幾個(gè)核的常用方法如下:
https://jorditorres.org/wp-content/uploads/2016/02/image078.png
第一個(gè)隱藏層由幾個(gè)核組成。 在我們的例子中供屉,我們使用 32 個(gè)核行冰,每個(gè)核由5×5
的權(quán)重矩陣W
和偏置b
定義,偏置b
也在隱層的神經(jīng)元之間共享伶丐。
為了簡(jiǎn)化代碼,我定義了以下兩個(gè)與權(quán)重矩陣W
和偏置b
相關(guān)的函數(shù):
def weight_variable(shape):
initial = tf.truncated_normal(shape, stddev=0.1)
return tf.Variable(initial)
def bias_variable(shape):
initial = tf.constant(0.1, shape=shape)
return tf.Variable(initial)
在沒(méi)有詳細(xì)說(shuō)明的情況下,習(xí)慣上用一些隨機(jī)噪聲初始化權(quán)重荆姆,偏置值略微為正忱嘹。
除了我們剛才描述的卷積層之外,通常卷積層后面跟著一個(gè)所謂的池化層录别。 池化層簡(jiǎn)單地壓縮來(lái)自卷積層的輸出朽色,并創(chuàng)建卷積層輸出的信息的緊湊版本。 在我們的示例中组题,我們將使用卷積層的2×2
區(qū)域葫男,我們使用池化將它的數(shù)據(jù)匯總到單個(gè)點(diǎn):
https://jorditorres.org/wp-content/uploads/2016/02/image080.png
有幾種方法可以執(zhí)行池化來(lái)壓縮信息;在我們的示例中崔列,我們將使用名為最大池化的方法梢褐。 通過(guò)僅保留所考慮的2×2
區(qū)域中的最大值來(lái)壓縮信息。
如上所述赵讯,卷積層由許多核組成盈咳,因此,我們將分別對(duì)每個(gè)核應(yīng)用最大池化边翼。 通常猪贪,可以有多層池化和卷積:
https://jorditorres.org/wp-content/uploads/2016/02/image082.png
這使24×24
的卷積層結(jié)果,被對(duì)應(yīng)12×12
的最大池化層轉(zhuǎn)換為12×12
的空間讯私,其中每個(gè)塊來(lái)源于2×2
的區(qū)域热押。 請(qǐng)注意,與卷積層不同斤寇,數(shù)據(jù)是平鋪的桶癣,而不是由滑動(dòng)窗口創(chuàng)建的。
直觀上娘锁,我們可以解釋最大池化牙寞,來(lái)確定特定特征是否存在于圖像中的任何位置,特征的確切位置不如對(duì)于其他特征的相對(duì)位置重要。
模型的實(shí)現(xiàn)
在本節(jié)中间雀,我將基于可在 TensorFlow [41] 網(wǎng)站上找到的高級(jí)示例(Deep MNIST for experts)悔详,提供編寫(xiě) CNN 的示例代碼。 正如我在開(kāi)始時(shí)所說(shuō)的那樣惹挟,參數(shù)的許多細(xì)節(jié)需要處理和理論方法茄螃,比本書(shū)中給出的更詳細(xì)。 因此连锯,我將僅概述代碼归苍,而不涉及 TensorFlow 參數(shù)的許多細(xì)節(jié)。
正如我們已經(jīng)看到的运怖,我們必須為卷積和池化層定義幾個(gè)參數(shù)拼弃。 我們將在每個(gè)維度中使用大小為 1 的步幅(這是滑動(dòng)窗口的步長(zhǎng))和零填充模型。 我們將應(yīng)用的池化是2×2
的最大池化摇展。 與上面類(lèi)似吻氧,我建議使用以下兩個(gè)通用函數(shù)來(lái)編寫(xiě)涉及卷積和最大池化的更清晰的代碼。
def conv2d(x, W):
return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME')
def max_pool_2x2(x):
return tf.nn.max_pool(x, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
現(xiàn)在是時(shí)候?qū)崿F(xiàn)第一個(gè)卷積層咏连,然后是池化層盯孙。 在我們的示例中,我們有 32 個(gè)過(guò)濾器捻勉,每個(gè)過(guò)濾器的窗口大小為5×5
镀梭。 我們必須定義一個(gè)張量,來(lái)保持這個(gè)權(quán)重矩陣W
的形狀為[5,5,1,32]
:前兩個(gè)維度是窗口的大小踱启,第三個(gè)是通道的數(shù)量报账,在我們的例子中為 1 。 最后一個(gè)定義了我們想要使用的過(guò)濾器數(shù)量埠偿。 此外透罢,我們還需要為 32 個(gè)權(quán)重矩陣中的每一個(gè)定義偏置。 使用先前定義的函數(shù)冠蒋,我們可以在 TensorFlow 中編寫(xiě)它羽圃,如下所示:
W_conv1 = weight_variable([5, 5, 1, 32])
b_conv1 = bias_variable([32])
ReLU(整流線性單元)激活函數(shù)最近成為深度神經(jīng)網(wǎng)絡(luò)隱藏層中使用的默認(rèn)激活函數(shù)。 這個(gè)簡(jiǎn)單的函數(shù)返回max(0, x)
抖剿,因此它為負(fù)值返回 0朽寞,否則返回x
。 在我們的示例中斩郎,我們將在卷積層之后的隱藏層中使用此激活函數(shù)脑融。
我們編寫(xiě)的代碼首先將卷積應(yīng)用于輸入圖像x_image
,它在 2D 張量W_conv1
中缩宜,返回圖像卷積的結(jié)果肘迎,然后加上偏置甥温,最終應(yīng)用 ReLU 激活函數(shù)。 最后一步妓布,我們將最大池化應(yīng)用于輸出:
h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)
h_pool1 = max_pool_2x2(h_conv1)
在構(gòu)建深度神經(jīng)網(wǎng)絡(luò)時(shí)姻蚓,我們可以將多個(gè)層疊在一起。 為了演示如何執(zhí)行此操作匣沼,我將創(chuàng)建一個(gè)帶有 64 個(gè)過(guò)濾器和5×5
窗口的輔助卷積層狰挡。 在這種情況下,我們必須傳遞 32 作為我們需要的通道數(shù)肛著,因?yàn)樗乔耙粚拥妮敵龃笮圆兵。?/p>
W_conv2 = weight_variable([5, 5, 32, 64])
b_conv2 = bias_variable([64])
h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2)
h_pool2 = max_pool_2x2(h_conv2)
由于我們將5×5
窗口應(yīng)用于步長(zhǎng)為 1 的12×12
空間跺讯,因此卷積的結(jié)果輸出具有8×8
的維數(shù)枢贿。 下一步是將一個(gè)全連接的層添加到8×8
輸出,然后將其輸入到最后的 softmax 層刀脏,就像我們?cè)谇耙徽轮兴龅哪菢印?/p>
我們將使用 1024 個(gè)神經(jīng)元的一層局荚,允許我們處理整個(gè)圖像。 權(quán)重和偏置的張量如下:
W_fc1 = weight_variable([8 * 8 * 64, 1024])
b_fc1 = bias_variable([1024])
請(qǐng)記住愈污,張量的第一個(gè)維度表示來(lái)自第二個(gè)卷積層的大小為8x8
的 64 個(gè)過(guò)濾器耀态,而第二個(gè)參數(shù)是層中神經(jīng)元的數(shù)量,我們可以自由選擇(在我們的例子中是 1024)暂雹。
現(xiàn)在首装,我們想將張量展開(kāi)為向量。 我們?cè)谇耙徽轮锌吹胶脊颍瑂oftmax 需要將向量形式的展開(kāi)圖像作為輸入仙逻。 這通過(guò)將權(quán)重矩陣W_fc1
與展開(kāi)向量相乘,加上偏置b_fc1
涧尿,再應(yīng)用 ReLU 激活函數(shù)來(lái)實(shí)現(xiàn):
h_pool2_flat = tf.reshape(h_pool2, [-1, 7*7*64])
h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1)
下一步將使用稱(chēng)為 dropout 的技術(shù)減少神經(jīng)網(wǎng)絡(luò)中的有效參數(shù)量系奉。 這包括刪除節(jié)點(diǎn)及其傳入和傳出連接。 丟棄和保留哪些神經(jīng)元是隨機(jī)決定的姑廉。 為了以一致的方式執(zhí)行此操作缺亮,我們將在代碼中為丟棄或保留的神經(jīng)元分配概率。
在沒(méi)有太多細(xì)節(jié)的情況下桥言,dropout 降低了模型的過(guò)擬合風(fēng)險(xiǎn)萌踱。 當(dāng)隱藏層具有大量神經(jīng)元并因此可以產(chǎn)生非常富有表現(xiàn)力的模型時(shí),這可能發(fā)生号阿;在這種情況下并鸵,可能會(huì)對(duì)隨機(jī)噪聲(或誤差)建模。 這被稱(chēng)為過(guò)擬合倦西,如果與輸入的維度相比能真,模型具有大量參數(shù),則更有可能。 最好是避免這種情況粉铐,因?yàn)檫^(guò)擬合的模型具有較差的預(yù)測(cè)表現(xiàn)疼约。
在我們的模型中,我們應(yīng)用 dropout蝙泼,它包括在最終的 softmax 層之前使用 dropout 函數(shù) tf.nn.dropout
程剥。 為此,我們構(gòu)造一個(gè)占位符來(lái)存儲(chǔ)在 dropout 期間保留神經(jīng)元的概率:
keep_prob = tf.placeholder("float")
h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)
最后汤踏,我們將 softmax 層添加到我們的模型中织鲸,就像前一章中所做的那樣。 請(qǐng)記住溪胶,sofmax 返回輸入屬于每個(gè)類(lèi)的概率(在我們的例子中為數(shù)字)搂擦,以便總概率加起來(lái)為 1。 softmax 層代碼如下:
W_fc2 = weight_variable([1024, 10])
b_fc2 = bias_variable([10])
y_conv=tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2) + b_fc2)
模型的訓(xùn)練和評(píng)估
我們現(xiàn)在通過(guò)調(diào)整卷積層和及全連接層中的所有權(quán)重哗脖,來(lái)準(zhǔn)備訓(xùn)練我們剛剛定義的模型瀑踢,并獲得我們的帶標(biāo)簽的圖像的預(yù)測(cè)。 如果我們想知道模型的執(zhí)行情況才避,我們必須遵循上一章中的示例橱夭。
以下代碼與前一章中的代碼非常相似,但有一個(gè)例外:我們用 ADAM 優(yōu)化器替換梯度下降優(yōu)化器桑逝,因?yàn)樵撍惴▽?shí)現(xiàn)了不同的優(yōu)化器棘劣,根據(jù)文獻(xiàn) [42],它具有某些優(yōu)點(diǎn)楞遏。
我們還需要在feed_dict
參數(shù)中包含附加參數(shù)keep_prob
茬暇,該參數(shù)控制我們之前討論過(guò)的 dropout 層的概率。
cross_entropy = -tf.reduce_sum(y_*tf.log(y_conv))
train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)
correct_prediction = tf.equal(tf.argmax(y_conv,1), tf.argmax(y_,1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
sess = tf.Session()
sess.run(tf.initialize_all_variables())
for i in range(20000):
batch = mnist.train.next_batch(50)
if i%100 == 0:
train_accuracy = sess.run( accuracy, feed_dict={x:batch[0], y_: batch[1], keep_prob: 1.0})
print("step %d, training accuracy %g"%(i, train_accuracy))
sess.run(train_step,feed_dict={x: batch[0], y_: batch[1], keep_prob: 0.5})
print("test accuracy %g"% sess.run(accuracy, feed_dict={ x: mnist.test.images, y_: mnist.test.labels, keep_prob: 1.0}))
與之前的模型一樣橱健,整個(gè)代碼可以在本書(shū)的 Github 頁(yè)面上找到而钞,可以驗(yàn)證該模型的準(zhǔn)確率達(dá)到 99.2%。
以下是使用 TensorFlow 構(gòu)建拘荡,訓(xùn)練和評(píng)估深度神經(jīng)網(wǎng)絡(luò)的簡(jiǎn)要介紹臼节。 如果讀者設(shè)法運(yùn)行提供的代碼,他或她已經(jīng)注意到該網(wǎng)絡(luò)的訓(xùn)練時(shí)間明顯長(zhǎng)于前幾章的訓(xùn)練時(shí)間珊皿;你可以想象网缝,擁有更多層的網(wǎng)絡(luò)需要花費(fèi)更長(zhǎng)的時(shí)間來(lái)訓(xùn)練。 我建議你閱讀下一章蟋定,其中解釋了如何使用 GPU 進(jìn)行訓(xùn)練粉臊,這將減少你的訓(xùn)練時(shí)間。
本章的代碼可以在本書(shū) github 頁(yè)面 [43] 的CNN.py
中找到驶兜,用于研究目的的代碼在下面:
import input_data
mnist = input_data.read_data_sets('MNIST_data', one_hot=True)
import tensorflow as tf
x = tf.placeholder("float", shape=[None, 784])
y_ = tf.placeholder("float", shape=[None, 10])
x_image = tf.reshape(x, [-1,28,28,1])
print "x_image="
print x_image
def weight_variable(shape):
initial = tf.truncated_normal(shape, stddev=0.1)
return tf.Variable(initial)
def bias_variable(shape):
initial = tf.constant(0.1, shape=shape)
return tf.Variable(initial)
def conv2d(x, W):
return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME')
def max_pool_2x2(x):
return tf.nn.max_pool(x, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
W_conv1 = weight_variable([5, 5, 1, 32])
b_conv1 = bias_variable([32])
h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)
h_pool1 = max_pool_2x2(h_conv1)
W_conv2 = weight_variable([5, 5, 32, 64])
b_conv2 = bias_variable([64])
h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2)
h_pool2 = max_pool_2x2(h_conv2)
W_fc1 = weight_variable([7 * 7 * 64, 1024])
b_fc1 = bias_variable([1024])
h_pool2_flat = tf.reshape(h_pool2, [-1, 7*7*64])
h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1)
keep_prob = tf.placeholder("float")
h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)
W_fc2 = weight_variable([1024, 10])
b_fc2 = bias_variable([10])
y_conv=tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2) + b_fc2)
cross_entropy = -tf.reduce_sum(y_*tf.log(y_conv))
train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)
correct_prediction = tf.equal(tf.argmax(y_conv,1), tf.argmax(y_,1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
sess = tf.Session()
sess.run(tf.initialize_all_variables())
for i in range(200):
batch = mnist.train.next_batch(50)
if i%10 == 0:
train_accuracy = sess.run( accuracy, feed_dict={ x:batch[0], y_: batch[1], keep_prob: 1.0})
print("step %d, training accuracy %g"%(i, train_accuracy))
sess.run(train_step,feed_dict={x: batch[0], y_: batch[1], keep_prob: 0.5})
print("test accuracy %g"% sess.run(accuracy, feed_dict={
x: mnist.test.images, y_: mnist.test.labels, keep_prob: 1.0}))
6. 并行
2015 年 11 月發(fā)布的第一個(gè) TensorFlow 軟件包扼仲,已準(zhǔn)備好在具有可用 GPU 的服務(wù)器上運(yùn)行远寸,并同時(shí)在其中執(zhí)行訓(xùn)練操作。 2016 年 2 月屠凶,更新添加了分布式和并行化處理的功能驰后。
在這個(gè)簡(jiǎn)短的章節(jié)中,我將介紹如何使用 GPU矗愧。 對(duì)于那些想要了解這些設(shè)備如何工作的讀者灶芝,有些參考文獻(xiàn)將在上一節(jié)中給出。但是唉韭,鑒于本書(shū)的介紹性夜涕,我不會(huì)詳細(xì)介紹分布式版本,但對(duì)于那些感興趣的讀者属愤,一些參考將在上一節(jié)中給出女器。
帶有 GPU 的執(zhí)行環(huán)境
支持 GPU 的 TensorFlow 軟件包需要 CudaToolkit 7.0 和 CUDNN 6.5 V2。 對(duì)于安裝環(huán)境春塌,我們建議訪問(wèn) cuda 安裝 [44] 網(wǎng)站晓避,為了不會(huì)深入細(xì)節(jié)簇捍,同時(shí)信息也是最新的只壳。
在 TensorFlow 中引用這些設(shè)備的方法如下:
-
/cpu:0
:引用服務(wù)器的 CPU。 -
/gpu:0
:服務(wù)器的 GPU(如果只有一個(gè)可用)暑塑。 -
/gpu:1
:服務(wù)器的第二個(gè) GPU吼句,依此類(lèi)推。
要知道我們的操作和張量分配在哪些設(shè)備中事格,我們需要?jiǎng)?chuàng)建一個(gè)sesion
惕艳,選項(xiàng)log_device_placement
為True
。 我們?cè)谙旅娴睦又锌吹剿?/p>
import tensorflow as tf
a = tf.constant([1.0, 2.0, 3.0, 4.0, 5.0, 6.0], shape=[2, 3], name='a')
b = tf.constant([1.0, 2.0, 3.0, 4.0, 5.0, 6.0], shape=[3, 2], name='b')
c = tf.matmul(a, b)
sess = tf.Session(config=tf.ConfigProto(log_device_placement=True))
printsess.run(c)
當(dāng)讀者在計(jì)算機(jī)中測(cè)試此代碼時(shí)驹愚,應(yīng)出現(xiàn)類(lèi)似的輸出:
. . .
Device mapping:
/job:localhost/replica:0/task:0/gpu:0 -> device: 0, name: Tesla K40c, pci bus id: 0000:08:00.0
. . .
b: /job:localhost/replica:0/task:0/gpu:0
a: /job:localhost/replica:0/task:0/gpu:0
MatMul: /job:localhost/replica:0/task:0/gpu:0
…
[[ 22.28.]
[ 49.64.]]
…
此外远搪,使用操作的結(jié)果,它通知我們每個(gè)部分的執(zhí)行位置逢捺。
如果我們想要在特定設(shè)備中執(zhí)行特定操作谁鳍,而不是讓系統(tǒng)自動(dòng)選擇設(shè)備,我們可以使用變量tf.device
來(lái)創(chuàng)建設(shè)備上下文劫瞳,因此所有操作都在上下文將分配相同的設(shè)備倘潜。
如果我們?cè)谙到y(tǒng)中擁有更多 GPU,則默認(rèn)情況下將選擇具有較低標(biāo)識(shí)符的 GPU志于。 如果我們想要在不同的 GPU 中執(zhí)行操作涮因,我們必須明確指定它。 例如伺绽,如果我們希望先前的代碼在 GPU#2 中執(zhí)行养泡,我們可以使用tf.device('/gpu:2')
嗜湃,如下所示:
import tensorflow as tf
with tf.device('/gpu:2'):
a = tf.constant([1.0, 2.0, 3.0, 4.0, 5.0, 6.0], shape=[2, 3], name='a')
b = tf.constant([1.0, 2.0, 3.0, 4.0, 5.0, 6.0], shape=[3, 2], name='b')
c = tf.matmul(a, b)
sess = tf.Session(config=tf.ConfigProto(log_device_placement=True))
printsess.run(c)
多個(gè) GPU 的并行
如果我們有更多的 GPU,通常我們希望一起使用它們來(lái)并行地解決同樣的問(wèn)題澜掩。 為此净蚤,我們可以構(gòu)建我們的模型,來(lái)在多個(gè) GPU 之間分配工作输硝。 我們?cè)谙乱粋€(gè)例子中看到它:
import tensorflow as tf
c = []
for d in ['/gpu:2', '/gpu:3']:
with tf.device(d):
a = tf.constant([1.0, 2.0, 3.0, 4.0, 5.0, 6.0], shape=[2, 3])
b = tf.constant([1.0, 2.0, 3.0, 4.0, 5.0, 6.0], shape=[3, 2])
c.append(tf.matmul(a, b))
with tf.device('/cpu:0'):
sum = tf.add_n(c)
# Creates a session with log_device_placement set to True.
sess = tf.Session(config=tf.ConfigProto(log_device_placement=True))
print sess.run(sum)
正如我們所看到的今瀑,代碼與前一代碼相同,但現(xiàn)在我們有 2 個(gè) GPU点把,由tf.device
指定橘荠,它們執(zhí)行乘法(兩個(gè) GPU 在這里都做同樣的操作,以便簡(jiǎn)化示例代碼)郎逃,稍后 CPU 執(zhí)行加法哥童。 假設(shè)我們將log_device_placement
設(shè)置為true
,我們可以在輸出中看到褒翰,操作如何分配給我們的設(shè)備 [45]贮懈。
. . .
Device mapping:
/job:localhost/replica:0/task:0/gpu:0 -> device: 0, name: Tesla K40c
/job:localhost/replica:0/task:0/gpu:1 -> device: 1, name: Tesla K40c
/job:localhost/replica:0/task:0/gpu:2 -> device: 2, name: Tesla K40c
/job:localhost/replica:0/task:0/gpu:3 -> device: 3, name: Tesla K40c
. . .
. . .
Const_3: /job:localhost/replica:0/task:0/gpu:3
I tensorflow/core/common_runtime/simple_placer.cc:289] Const_3: /job:localhost/replica:0/task:0/gpu:3
Const_2: /job:localhost/replica:0/task:0/gpu:3
I tensorflow/core/common_runtime/simple_placer.cc:289] Const_2: /job:localhost/replica:0/task:0/gpu:3
MatMul_1: /job:localhost/replica:0/task:0/gpu:3
I tensorflow/core/common_runtime/simple_placer.cc:289] MatMul_1: /job:localhost/replica:0/task:0/gpu:3
Const_1: /job:localhost/replica:0/task:0/gpu:2
I tensorflow/core/common_runtime/simple_placer.cc:289] Const_1: /job:localhost/replica:0/task:0/gpu:2
Const: /job:localhost/replica:0/task:0/gpu:2
I tensorflow/core/common_runtime/simple_placer.cc:289] Const: /job:localhost/replica:0/task:0/gpu:2
MatMul: /job:localhost/replica:0/task:0/gpu:2
I tensorflow/core/common_runtime/simple_placer.cc:289] MatMul: /job:localhost/replica:0/task:0/gpu:2
AddN: /job:localhost/replica:0/task:0/cpu:0
I tensorflow/core/common_runtime/simple_placer.cc:289] AddN: /job:localhost/replica:0/task:0/cpu:0
[[44.56.]
[98.128.]]
. . .
GPU 的代碼示例
為了總結(jié)這一簡(jiǎn)短的章節(jié),我們提供了一段代碼优训,其靈感來(lái)自 DamienAymeric 在 Github [46] 中共享的代碼朵你,計(jì)算An + Bn
,n=10
揣非,使用 Python datetime
包抡医,將 1 GPU 的執(zhí)行時(shí)間與 2 個(gè) GPU 進(jìn)行比較。
首先早敬,我們導(dǎo)入所需的庫(kù):
import numpy as np
import tensorflow as tf
import datetime
我們使用numpy
包創(chuàng)建兩個(gè)帶隨機(jī)值的矩陣:
A = np.random.rand(1e4, 1e4).astype('float32')
B = np.random.rand(1e4, 1e4).astype('float32')
n = 10
然后忌傻,我們創(chuàng)建兩個(gè)結(jié)構(gòu)來(lái)存儲(chǔ)結(jié)果:
c1 = []
c2 = []
接下來(lái),我們定義matpow()
函數(shù)搞监,如下所示:
defmatpow(M, n):
if n < 1: #Abstract cases where n < 1
return M
else:
return tf.matmul(M, matpow(M, n-1))
正如我們所見(jiàn)水孩,要在單個(gè) GPU 中執(zhí)行代碼,我們必須按如下方式指定:
with tf.device('/gpu:0'):
a = tf.constant(A)
b = tf.constant(B)
c1.append(matpow(a, n))
c1.append(matpow(b, n))
with tf.device('/cpu:0'):
sum = tf.add_n(c1)
t1_1 = datetime.datetime.now()
with tf.Session(config=tf.ConfigProto(log_device_placement=True)) as sess:
sess.run(sum)
t2_1 = datetime.datetime.now()
對(duì)于 2 個(gè) GPU 的情況琐驴,代碼如下:
with tf.device('/gpu:0'):
#compute A^n and store result in c2
a = tf.constant(A)
c2.append(matpow(a, n))
with tf.device('/gpu:1'):
#compute B^n and store result in c2
b = tf.constant(B)
c2.append(matpow(b, n))
with tf.device('/cpu:0'):
sum = tf.add_n(c2) #Addition of all elements in c2, i.e. A^n + B^n
t1_2 = datetime.datetime.now()
with tf.Session(config=tf.ConfigProto(log_device_placement=True)) as sess:
# Runs the op.
sess.run(sum)
t2_2 = datetime.datetime.now()
最后俘种,我們打印計(jì)算時(shí)間的結(jié)果:
print "Single GPU computation time: " + str(t2_1-t1_1)
print "Multi GPU computation time: " + str(t2_2-t1_2)
TensorFlow 的分布式版本
正如我之前在本章開(kāi)頭所說(shuō),2016 年 2 月棍矛,Google 發(fā)布了 TensorFlow 的分布式版本安疗,該版本由 gRPC 支持,這是一個(gè)用于進(jìn)程間通信的高性能開(kāi)源 RPC 框架(TensorFlow 服務(wù)使用的相同協(xié)議)够委。
對(duì)于它的用法荐类,必須構(gòu)建二進(jìn)制文件,因?yàn)榇藭r(shí)包只提供源代碼茁帽。 鑒于本書(shū)的介紹范圍玉罐,我不會(huì)在分布式版本中解釋它屈嗤,但如果讀者想要了解它,我建議從 TensorFlow 的分布式版本的官網(wǎng)開(kāi)始 [47]吊输。
與前面的章節(jié)一樣饶号,本書(shū)中使用的代碼可以在本書(shū)的 Github [48] 中找到。 我希望本章足以說(shuō)明如何使用 GPU 加速代碼季蚂。
后記
探索是促進(jìn)創(chuàng)新的引擎茫船。創(chuàng)新促進(jìn)經(jīng)濟(jì)增長(zhǎng)。讓我們一起去探索吧扭屁。
Edith Widder
在這里算谈,我提供了一個(gè)介紹性指南,解釋了如何使用 TensorFlow料滥,為這種技術(shù)提供熱身然眼,這無(wú)疑將在迫在眉睫的技術(shù)場(chǎng)景中發(fā)揮主導(dǎo)作用。 事實(shí)上葵腹,還有 TensorFlow 的其他替代方案高每,每個(gè)方案最適合特定問(wèn)題;我想邀請(qǐng)讀者探索 TensorFlow 包之外的內(nèi)容践宴。
這些包有很多不同之處鲸匿。 有些更專(zhuān)業(yè),有些更不專(zhuān)業(yè)浴井。 有些比其他更難安裝晒骇。 其中一些有很好的文檔,而另一些盡管運(yùn)作良好磺浙,但更難找到如何使用它們的詳細(xì)信息。
重要的是:之后的日子里归薛,TensorFlow 由谷歌發(fā)布辜荠,我在推文 [49] 中讀到了 2010-2014 期間无蜂,新的深度學(xué)習(xí)包每 47 天發(fā)布一次,2015 年每 22 天發(fā)布一次伦泥。 這很驚人,不是嗎锦溪? 正如我在本書(shū)的第一章中提出的那樣不脯,作為讀者的起點(diǎn),可以在 Awesome Deep Learning [50] 找到一個(gè)廣泛的列表刻诊。
毫無(wú)疑問(wèn)防楷,2015 年 11 月,隨著 Google TensorFlow 的發(fā)布则涯,深度學(xué)習(xí)的格局受到影響复局,現(xiàn)在它是 Github 上最受歡迎的開(kāi)源機(jī)器學(xué)習(xí)庫(kù) [51]冲簿。
請(qǐng)記住,Github 的第二個(gè)最著名的機(jī)器學(xué)習(xí)項(xiàng)目是 Scikit-learn [52]亿昏,事實(shí)上的 Python 官方的通用機(jī)器學(xué)習(xí)框架峦剔。 這些用戶可以通過(guò) Scikit Flow(skflow)[53] 使用 TensorFlow,這是來(lái)自 Google 的 TensorFlow 的簡(jiǎn)化接口角钩。
實(shí)際上吝沫,Scikit Flow 是 TensorFlow 庫(kù)的高級(jí)包裝,它允許使用熟悉的 Scikit-Learn 方法訓(xùn)練和擬合神經(jīng)網(wǎng)絡(luò)递礼。 該庫(kù)涵蓋了從線性模型到深度學(xué)習(xí)應(yīng)用的各種需求野舶。
在我看來(lái),在 TensorFlow 分布式宰衙,TensorFlow 服務(wù)和 Scikit Flow 發(fā)布后平道,TensorFlow 將成為事實(shí)上的主流深度學(xué)習(xí)庫(kù)。
深度學(xué)習(xí)大大提高了語(yǔ)音識(shí)別供炼,視覺(jué)對(duì)象識(shí)別一屋,對(duì)象檢測(cè)和許多其他領(lǐng)域的最新技術(shù)水平。 它的未來(lái)會(huì)是什么袋哼? 根據(jù) Yann LeCun冀墨,Yoshua Bengio 和 Geoffrey Hilton 在 Nature 雜志上的精彩評(píng)論,答案是無(wú)監(jiān)督學(xué)習(xí) [54]涛贯。 他們期望從長(zhǎng)遠(yuǎn)來(lái)看诽嘉,無(wú)監(jiān)督學(xué)習(xí)比監(jiān)督學(xué)習(xí)更重要。 正如他們所提到的弟翘,人類(lèi)和動(dòng)物的學(xué)習(xí)基本上沒(méi)有受到監(jiān)督:我們通過(guò)觀察世界來(lái)發(fā)現(xiàn)它的結(jié)構(gòu)虫腋,而不是通過(guò)被告知每個(gè)物體的名稱(chēng)。
他們對(duì)系統(tǒng)的未來(lái)進(jìn)展有很多期望稀余,系統(tǒng)將 CNN 與遞歸神經(jīng)網(wǎng)絡(luò)(RNN)相結(jié)合悦冀,并使用強(qiáng)化學(xué)習(xí)。 RNN 處理一個(gè)輸入睛琳,該輸入一次編碼一個(gè)元素盒蟆,在其隱藏單元中維護(hù)序列的所有過(guò)去元素的歷史的信息。 對(duì)于 TensorFlow 中 RNN 實(shí)現(xiàn)的介紹师骗,讀者可以查看 TensorFlow 教程中的循環(huán)神經(jīng)網(wǎng)絡(luò) [55] 部分历等。
此外,深度學(xué)習(xí)還面臨許多挑戰(zhàn)辟癌;訓(xùn)練它們的時(shí)間推動(dòng)了新型超級(jí)計(jì)算機(jī)系統(tǒng)的需求寒屯。 為了將最佳的知識(shí)分析與新的大數(shù)據(jù)技術(shù)和新興計(jì)算系統(tǒng)的強(qiáng)大功能相結(jié)合,以前所未有的速度解釋大量異構(gòu)數(shù)據(jù)愿待,仍然需要進(jìn)行大量研究浩螺。
科學(xué)進(jìn)步通常是大型社區(qū)的跨學(xué)科靴患,長(zhǎng)期和持續(xù)努力的結(jié)果,而不是突破要出,深度學(xué)習(xí)和機(jī)器學(xué)習(xí)一般也不例外鸳君。 我們正在進(jìn)入一個(gè)非常激動(dòng)人心的跨學(xué)科研究時(shí)期,其中像巴塞羅那那樣的生態(tài)系統(tǒng)患蹂,如 UPC 和 BSC-CNS或颊,在高性能計(jì)算和大數(shù)據(jù)技術(shù)方面具有豐富的知識(shí),將在這個(gè)新場(chǎng)景中發(fā)揮重要作用传于。
參考
[1] The MNIST database of handwritten digits. [Online]. Available at:http://yann.lecun.com/exdb/mnist [Accessed: 16/12/2015].
[2]_ Github_, (2016) Fist Contact with TensorFlow. Source code [Online]. Available at:https://github.com/jorditorresBCN/TutorialTensorFlow[Accessed: 16/12/2015].
[3]_ TensorFlow Serving_[Online]. Available at: http://tensorflow.github.io/serving/[Accessed: 24/02/2016].
[4] Google Research Blog [Online]. Available at: http://googleresearch.blogspot.com.es/2016/02/running-your-models-in-production-with.html?m=1[Accessed: 24/02/2016].
[5]_ TensorFlow Serving_-Architecture Overview[Online]. Available at: http://tensorflow.github.io/serving/[Accessed: 24/02/2016].
[6] TensorFlow Serving– Serving a TensorFlow Model [Online]. Available at:http://tensorflow.github.io/serving/serving_basic [Accessed: 24/02/2016].
[7] TensorFlow, (2016) Download & Setup [Online]. Available at: https://www.tensorflow.org/versions/master/get_started/os_setup.html#download-and-setup[Accessed: 16/12/2015].
[8] Wikipedia, (2016). IPython. [Online]. Available at: https://en.wikipedia.org/wiki/IPython [Accessed: 19/03/2016].
[9] TensorFlow: Large-scale machine learning on heterogeneous systems, (2015). [Online]. Available at:http://download.tensorflow.org/paper/whitepaper2015.pdf[Accessed: 20/12/2015].
[10] TensorFlow, (2016)Python API – Summary Operations. [Online]. Available at:https://www.tensorflow.org/versions/master/api_docs/python/train.html#summary-operations [Accessed: 03/01/2016].
[11] I recommend using Google Chrome to ensure proper display.
[12]TensorFlow, (2016) TensorBoard: Graph Visualization.[Online]. Available at:https://www.tensorflow.org/versions/master/how_tos/graph_viz/index.html[Accessed: 02/01/2016].
[13] One reviewer of this book has indicated that he also had to install the package_python-gi-cairo_.
[14] Wikipedia, (2016). Mean Square Error. [Online]. Available at: https://en.wikipedia.org/wiki/Mean_squared_error [Accessed: 9/01/2016].
[15] Wikipedia, (2016). Gradient descent. [Online]. Available at: https://en.wikipedia.org/wiki/Gradient_descent [Accessed: 9/01/2016].
[16] Wikipedia, (2016). Gradient. [Online]. Available at: https://en.wikipedia.org/wiki/Gradient[Accessed: 9/01/2016].
[17] Github, (2016) Book source code [Online]. Available at:https://github.com/jorditorresBCN/TutorialTensorFlow. [Accessed: 16/12/2015].
[18] TensorFlow, (2016) API de Python – Tensor Transformations [Online]. Available at:https://www.tensorflow.org/versions/master/api_docs/python/array_ops.html [Accessed: 16/12/2015].
[19] TensorFlow, (2016) Tutorial – Reading Data [Online]. Available at:https://www.tensorflow.org/versions/master/how_tos/reading_data[Accessed: 16/12/2015].
[20] Github, (2016) TensorFlow Book – Jordi Torres. [Online]. Available at:https://github.com/jorditorresBCN/LibroTensorFlow/blob/master/input_data.py[Accessed: 19/02/2016].
[21] Github, (2016) Shawn Simister. [Online]. Available at: https://gist.github.com/narphorium/d06b7ed234287e319f18 [Accessed: 9/01/2016].
[22] Wikipedia, (2016). Squared Euclidean distance. [Online]. Available at:https://en.wikipedia.org/wiki/Euclidean_distance#Squared_Euclidean_distance[Accessed: 9/01/2016].
[23] In my opinion, the level of explanation of each operation it’s enough for the purpose of this book.
[24] TensorFlow, (2016) Python API. [online]. Available in: https://www.tensorflow.org/versions/master/api_docs/index.html [Accessed: 19/02/2016].
[25]Actually “_” is like any other variable, but many Python users, by convention, we use it to discard results.
[26] Github, (2016) TensorFlow Book – Jordi Torres. [online]. Available at: https://github.com/jorditorresBCN/LibroTensorFlow [Accessed: 19/02/2016].
[27] TensorFlow, (2016) Tutorial MNIST beginners. [online]. Available at:https://www.tensorflow.org/versions/master/ tutorials/mnist/beginners[Accessed: 16/12/2015].
[28] Neural Networks and Deep Learning.Michael Nielsen. [online]. Available at: http://neuralnetworksanddeeplearning.com/index.html [Accessed: 6/12/2015].
[29] The MNIST database of handwritten digits.[online]. Available at:http://yann.lecun.com/exdb/mnist [Accessed: 16/12/2015].
[30] Wikipedia, (2016). Antialiasing [online]. Available at: https://en.wikipedia.org/wiki/Antialiasing[Accessed: 9/01/2016].
[31]_ Github_, (2016) Book TensorFlow – Jordi Torres. [online]. Available at:https://github.com/jorditorresBCN/LibroTensorFlow/blob/master/input_data.py [Accessed: 9/01/2016].
[32] Google (2016) TensorFlow. [online]. Available at: https://tensorflow.googlesource.com[Accessed: 9/01/2016].
[33] Wikipedia, (2016). Sigmoid function [online]. Avaliable at: https://en.wikipedia.org/wiki/Sigmoid_function [Accessed: 12/01/2016].
[34] Wikipedia, (2016). Softmax function [online]. Available at: https://en.wikipedia.org/wiki/Softmax_function [Accessed: 2/01/2016].
[35] TensorFlow, (2016) Tutorial MNIST beginners. [online]. Available at:https://www.tensorflow.org/versions/master/tutorials/mnist/beginners[Accessed: 16/12/2015].
[36] Neural Networks & Deep Learning.Michael Nielsen. [online]. Available at:http://neuralnetworksanddeeplearning.com/index.html[Accessed: 6/12/2015].
[37] TensorFlow Github: tensorflow/tensorflow/python/ops/gradients.py [Online]. Available at:https://github.com/tensorflow/tensorflow/blob/master/tensorflow/python/ops/gradients.py[Accessed: 16/03/2016].
[38]_ Github_, (2016) Libro TensorFlow – Jordi Torres. [online]. Available at:https://github.com/jorditorresBCN/LibroTensorFlow[Accessed: 9/01/2016].
[39] The reader can read more about the details of these parameters on the course website of CS231 –Convolutional Neural Networks for Visual Recognition(2015) [online]. Available at:http://cs231n.github.io/convolutional-networks[Accessed: 30/12/2015].
[40] GIMP –_Image processing software by GNU,_Convlution matrix documentation available at:https://docs.gimp.org/es/plug-in-convmatrix.html[Accessed: 5/1/2016].
[41] TensorFlow, (2016_) Tutorials: Deep MNIST for experts_. [on line]. Availbile at:https://www.tensorflow.org/versions/master/tutorials/mnist/pros/index.html [Consulted on: 2/1/2016]
[42] TensorFlow, (2016)Python API. ADAM Optimizer[on líne]. Available at:https://www.tensorflow.org/versions/master/ api_docs/python/train.html#AdamOptimizer[Accessed: 2/1/2016].
[43] Github, (2016) Source code of this book [on líne]. Availible at: https://github.com/jorditorresBCN/TutorialTensorFlow [Consulted on: 29/12/2015].
[44] TensorFlow, (2016) GPU-related issues. [online]. Available at: https://www.tensorflow.org/versions/master/get_started/os_setup.html#gpu-related-issues[Accessed: 16/12/2015].
[45] This output is result of using a server with 4 Tesla K40 GPUs from theBarcelona Supercomputing Center (BSC-CNS).
[46]_ Github_(2016) AymericDamien. [online]. Available at: https://github.com/aymericdamien/TensorFlow-Examples [Accessed: 9/1/2015].
[47] Distributed TensorFlow, (2016) [online]. Available at: https://github.com/tensorflow/tensorflow/tree/master/tensorflow/core/distributed_runtime[Accessed: 16/12/2015].
[48] Github, (2016) Source code of this book [on líne]. Availible at: https://github.com/jorditorresBCN/TutorialTensorFlow [Consulted on: 29/12/2015].
[49] Twitter (11/11/2015). Kyle McDonald:_2010-2014: new deep learning toolkit is released every 47 days._2015: every 22 days.[Online]. Available at:https://twitter.com/kcimc/status/664217437840257024[Accessed: 9/01/2016].
[50] GitHub,(2016)Awesome Deep Learning. [Online]. Available at: https://github.com/ChristosChristofidis/awesome-deep-learning[Accessed: 9/01/2016].
[51] Explore GitHub, Machine learning: [Online]. Available at:https://github.com/showcases/machine-learning [Accessed on: 2/01/2016]
[52] Scikit-Learn GitHub: [Online]. Available at:https://github.com/scikit-learn/scikit-learn[Accessed: 2/3/2016]
[53] Tensorflow/skflow GitHub: [Online]. Available at:https://github.com/tensorflow/skflow[Accessed: 2/1/2016]
[54] Yann LeCun, Yoshua Bengio and Geoffrey Hinton (2015). “Deep Learning”. Nature 521: 436–444 doi:10.1038/nature14539. Available at:http://www.nature.com/nature/journal/v521/n7553/full/nature14539.html [Accessed: 16/03/2016].
[55] TensorFlow, (2016) Tutorial – Recurrent Neural Networks [Online]. Available at:https://www.tensorflow.org/versions/r0.7/tutorials/recurrent/index.html[Accessed: 16/03/2016].
[56] Hello World en TensorFlow. Spanish version of this book [Online]. Available at:https://jorditorres.org/libro-hello-world-en-tensorflow/[Accessed: 16/03/2016].