官术网_书友最值得收藏!

第 1 章 深度學習和JavaScript

本章要點

● 深度學習的定義及其與人工智能和機器學習的關聯。

● 深度學習從各種機器學習技術中脫穎而出以及引發“深度學習革命”的原因。

● 使用JavaScript和TensorFlow.js進行深度學習的原因。

● 本書的整體結構。

人工智能(AI)的大熱不是偶然的,深度學習革命真的發生了。深度學習革命(deep-learning revolution)是指,自2012年以來深度神經網絡在運行速度和相關技術方面的疾速發展。自那時起,深度神經網絡被應用到了越來越多的問題上,這樣一來,相比以往,計算機能夠解決更多種類的問題,并極大地提高了現有解決方案的準確率(參見表1-1中的示例)。對AI方面的專家而言,神經網絡領域的很多突破是令人震驚的;對使用神經網絡的工程師而言,這一發展帶來的機遇是鼓舞人心的。

從傳統意義上講,JavaScript是一種用于創建Web瀏覽器UI和后端業務邏輯(通過Node.js)的編程語言,而深度學習革命似乎是Python、R和C++這些語言的專屬領域。因此,作為用JavaScript來表達想法和發揮創造力的人,你可能覺得自己有點脫離深度學習革命了。本書旨在通過叫作TensorFlow.js的JavaScript深度學習庫,將深度學習與JavaScript結合起來。如此一來,無須學習新的編程語言,JavaScript開發者就可以學習如何編寫深度神經網絡;更重要的是,我們相信深度學習和JavaScript本就該在一起。

這就如同異花授粉,把深度學習和JavaScript結合起來,將創造出任何其他編程語言所不具備的獨特功能。兩者結合相得益彰:有了JavaScript,深度學習應用程序可以在更多平臺上運行,接觸更多受眾,變得更加可視化且具有互動性;有了深度學習,JavaScript開發者可以讓他們的Web應用程序更加智能。本章隨后將展示如何實現這一點。

表1-1列出了目前這場深度學習革命中取得的一些令人興奮的成就,當然,未來深度學習會持續進步。本書中選擇了一些這樣的應用程序,并用TensorFlow.js創建一些示例來介紹它們的實現方式。這些示例有的是完整版,有的有所簡化,后面的章節會深度講解它們。因此,無須只是感嘆目前的這些成就,在本書中,你可以學習它們、理解它們,并使用JavaScript來實現它們。

但在開始學習這些令人興奮的深度學習實戰示例之前,我們需要先介紹關于AI、深度學習和神經網絡的一些上下文。

表1-1 自2012年深度學習革命開始以來,由于深度學習技術而使得準確率獲得極大提高的任務示例(節選) 1

1可以從圖靈社區本書主頁瀏覽并下載相關資源。——編者注

2convolutional neutral network,即convnet,卷積神經網絡。

3訪問Magenta.js網站的Demos界面,瀏覽更多示例。

a 參見何凱明等人在CVPR 2016(IEv模式識別會議)上發表的“Deep Residual Learning for Image Recognition”。

b 參見Christian Szegedy等人在CVPR 2015上發表的“Going Deeper with Convolutions”。

c 參見陳云鵬等人發表的“Dual Path Networks”。

d 參見吳永輝等人發表的“Google's Neural Machine Translation System: Bridging the Gap between Human and Machine Translation”。

e 參見Chung-Cheng Chiu等人發表的“State-of-the-Art Speech Recognition with Sequence-to-Sequence Models”。

f 參見Volodymyr Mnih等人發表的“Playing Atari with Deep Reinforcement Learning”。

g 參見David Silver等人發表的“Mastering Chess and Shogi by Self-Play with a General Reinforcement Learning Algorithm”。

h 參見Varun Gulshan等人發表的“Development and Validation of a Deep Learning Algorithm for Detection of Diabetic Retinopathy in Retinal Fundus Photographs”。

1.1 人工智能、機器學習、神經網絡和深度學習

人工智能機器學習神經網絡深度學習這些詞雖然意思上有一定關聯,但是分別代表不同的概念。為了系統而全面地掌握這些概念,需要理解它們各自的含義。下面先來定義這些術語和它們之間的關系。

1.1.1 人工智能

人工智能是一個非常寬泛的領域,它的簡潔定義是:試圖將通常需要人類主觀意識參與的任務自動化。正因如此,人工智能涵蓋了機器學習、神經網絡和深度學習,但又包含了其他很多和機器學習不同的策略。例如,早期的國際象棋軟件僅包含由程序員精心編寫的硬編碼規則,這些并不算是機器學習,因為機器只是通過明確編寫的程序來解決問題,而不是通過學習數據去探索解決問題的策略。在相當長的時間內,許多專家認為,人類級別的人工智能可以通過明確制定數量足夠龐大的規則集來實現,這些規則用于處理知識并做出決策。這種策略叫作符號人工智能(symbolic AI)4,它是20世紀50年代至80年代主要的人工智能范式。

4符號人工智能的一種重要類型是專家系統(expert system)。

如圖1-1所示,機器學習是人工智能的子領域。人工智能的一些領域采用了與機器學習不同的策略,如符號人工智能。神經網絡是機器學習的子領域。機器學習中也存在非神經網絡的技術,如決策樹。相較于淺層神經網絡(具有較少層的神經網絡),深度學習是創造與應用深層神經網絡(具有大量層的神經網絡)的科學與藝術。

圖1-1 人工智能、機器學習、神經網絡和深度學習之間的關系

1.1.2 機器學習:它和傳統編程有何不同

作為人工智能的子領域之一,機器學習與符號人工智能截然不同,它源于一個問題:計算機能否超越程序員的認知,通過自主學習來完成一項具體任務?如你所見,在所采取的策略方面,機器學習和符號人工智能是有本質區別的。符號人工智能依賴于硬編碼的知識和規則,而機器學習竭力避免這種硬編碼。如果沒有程序員精心編寫的硬編碼規則,機器怎樣去學習完成某項任務?答案就是從數據的例子中學習。

這種思路開啟了一扇通往新編程范式的大門,如圖1-2所示。現在舉例說明這種機器學習范式,假設你在開發一個Web應用程序,它能夠處理用戶上傳的照片。你想做的一個功能是自動區分包含人臉的照片和不包含人臉的照片,并且據此采取不同的動作。也就是說,新創建的這個程序能夠將所有輸入圖像(由像素數組構成)輸出為二元答案,即包含人臉和不包含人臉。

圖1-2 對比經典編程范式和機器學習范式

人類能夠在一瞬間完成這個任務:大腦里固有的遺傳因子和人生經驗賦予了我們這樣的能力。然而,要用編程語言(唯一可行的人機交流方式)寫一套明確的規則來準確判斷某個圖像中是否包含人臉,對任何程序員來說,無論他聰明與否或經驗多寡,這都是一件很難的事情。對于如何通過計算像素的RGB值5,來檢測那些看起來像臉部、眼睛、嘴巴的橢圓輪廓,你可以花很多天進行研究,也可以設計這些輪廓之間關系的經驗法則。但你會很快發現,這些嘗試充斥著隨意的邏輯和站不住腳的參數。更重要的是,這么做的效果還不太好6!現實中有眾多因素,比如臉部大小和形狀、面部表情和細節特征、發型、膚色、面部方向、有無遮擋、是否佩戴眼鏡、光照環境、畫面背景等,這些因素會影響判斷,因此面對圖像無窮的變化,你能想到的任何經驗法則都會顯得捉襟見肘。

5R、G、B分別代表紅、綠、藍這3種顏色。

6事實上,很多人確實嘗試過這類方法,效果并不理想。參見Erik Hjelm?s和Boon Kee Low所著的論文“Face Detection: A Survey”,其中提供了一些典型示例,即在深度學習出現之前,利用人工設計規則進行人臉識別。

在機器學習范式中,人工編寫一套判斷規則對于這樣的任務是徒勞的。相反,你要先找一些圖像,一部分包含人臉,一部分不包含人臉。然后為每一個圖像都寫下預期的正確答案,也就是包含人臉或不包含人臉,這些答案叫作標簽(label)。事實上,這是一個更可控也更簡單的任務。如果有很多圖像,標記全部圖像可能要花點時間,但是標記任務可以分發給多個人同時進行。一旦標記完畢,就可以利用機器學習技術,讓機器自己探索出一套規則。經過機器學習技術正確訓練的規則,執行判斷的準確率能超過99%,比通過人工編寫規則能取得的任何成果都要好得多。

從上面的例子可以看出,機器學習就是自動發現解決復雜問題的規則的過程。這種自動化對人臉檢測這類問題很有幫助,在這類問題中,人們能直觀地知道規則并很容易為數據建立標簽。對于其他問題,規則就不這么直觀了。比如,假設我們要預測用戶是否會點擊網頁上顯示的廣告,頁面內容、廣告內容以及其他信息(比如瀏覽時間和廣告位置)都是已知的。即使這樣,也沒有人可以對這類問題做出準確判斷。即使可以,這種規律也會隨著時間推移以及新的頁面和廣告內容的引入而發生改變。但也不用灰心,在提供廣告服務的服務器日志里,帶標簽的可用于訓練的數據是存在的,而且很容易找到。正是由于這些數據和標簽,機器學習非常擅長處理此類問題。

圖1-3中詳細列出了機器學習所包含的步驟,其中包含兩個重要階段。第一個是訓練階段(training phase)。這一階段的輸入是數據和答案,叫作訓練數據(training data)。每一對作為輸入的數據和預期的答案叫作樣例(example)。根據這些樣例,訓練流程就可以自動發現規則(rule)。盡管這些規則是自動發現的,但是它們并非憑空創造。換言之,機器學習算法并不是通過自由發揮得出這些規則,人類工程師在訓練之初就提供了這些規則的藍圖。這個藍圖封裝在模型(model)中,而模型又形成了機器潛在可學習的規則的假設空間(hypothesis space)。如果沒有這個假設空間,機器就會在一個完全無約束并且無限大的可能規則空間中尋找規則,對于在有限時間內找到較為完善的規則,這顯然是無益的。本書后面將具體描述可利用的模型的種類,以及如何根據具體問題選擇最佳的模型。現在只需知道,在深度學習中,根據神經網絡的組成層數、每一層的具體類型以及各層之間的連接關系,模型最終會有所不同。

圖1-3 比圖1-2更為詳細的機器學習范式示意圖。機器學習的工作流程由兩個階段構成:訓練階段和推斷階段。在訓練階段中,機器自動發現數據與對應答案之間的規則,這個過程中發現的規則會封裝在訓練好的模型中。它們是訓練階段的成果,并且為推斷階段奠定基礎。推斷階段指運用習得的模型為新的數據獲取答案

基于訓練數據和模型架構,在訓練階段中,機器可以習得數據與答案之間的轉換規則,并將其封裝在訓練好的模型(trained model)中。這個過程將規則的藍圖作為輸入,并且對其進行改變(或微調),讓模型輸出的結果越來越逼近預期結果。根據訓練數據的多少、模型架構的復雜度和硬件的快慢,這一訓練階段會持續幾毫秒到幾天。這種機器學習方式,也就是用帶標簽的樣例來逐步減小模型輸出誤差的方法,叫作監督式學習(supervised learning)7。本書中提到的絕大部分深度學習算法屬于監督式學習。一旦有了訓練好的模型,就可以將習得的規則應用到新數據上了(包括訓練階段沒有出現的數據)。以上就是第二階段,即推斷階段(inference phase),這一階段相較訓練階段計算量較少,主要有兩個原因:第一,推斷階段通常每次只針對一個輸入(比如圖像),而訓練階段則需要處理所有的訓練數據;第二,在推斷階段,模型自身不會有任何變化。

7另一種機器學習方法是無監督式學習(unsupervised learning),它使用無標簽數據。這方面的示例包括聚類和異常檢測,前者發現數據集中不同的樣例子集,后者判斷給定的樣例與訓練集中的樣例是否存在顯著不同。

學習數據的表示

機器學習就是要從數據中學習。但到底學習哪些內容呢?其實就是一種有效地轉換(transform)數據的方法,換言之,將數據從舊表示轉換為新表示,從而更有效地解決現階段的問題。

在進一步展開討論之前,先來看一下“表示”的概念。簡明來說,表示(representation)是一種處理數據的方式。通過不同的處理方式,同一組數據可以有不同的表示。比如,彩色圖像可以用RGB或者HSV8來編碼。這里,編碼(encoding)和表示實質上指的是同一個東西,它們可以交換使用。用這兩種方式編碼得到的代表圖像像素的數值是完全不同的,盡管編碼對象是同一個圖像。不同的表示適用于解決不同的問題。例如,要找出一個圖像中所有的紅色部分,使用RGB表示會比較簡單。但要找到同一個圖像中顏色飽和的部分,則HSV表示更有用。這實際上就是機器學習的本質:找到一種合適的方式把輸入數據的舊表示轉換成新表示,并且這一新表示適用于解決當下特定的任務,比如檢測圖像中車輛的位置或者判斷圖像中出現的是貓還是狗。

8H、S、V分別代表色相、飽和度、明度。

再看一個示例,圖1-4中展示了一些白點和黑點。假設我們想研發一種算法,這個算法能夠將某個點的二維坐標(x, y)作為輸入,預測該點是黑色還是白色。在這個場景中,主要涉及以下兩個方面。

● 輸入數據是某個點的二維坐標(橫坐標值和縱坐標值)。

● 輸出是該點的顏色的預測值(黑色或白色)。

實際數據展現出的規律如圖1-4a所示。給定xy的值后,機器如何判斷該位置的顏色呢?不能只是簡單地將x與某個數字進行比較,因為黑點和白點的橫坐標值域是重疊的!同理,也不能單純地取決于y。因此,可以得出這樣的結論:對黑白分類任務而言,坐標點原來的表示并不是很友好。

而我們需要的是能更簡單明了地區分兩種顏色的新表示。因此,此處將原來的笛卡兒坐標系表示轉換為極坐標系表示。換言之,用該點的角度和半徑來表示它。其中,角度由x坐標軸和點到原點的連線構成(見圖1-4a),半徑是指點到原點的距離。經過這一變換,我們得到了同一組數據的新表示,如圖1-4b所示。這一表示更適用于當前的任務,現在黑點和白點的角度值完全不會重疊。然而,這個新表示仍不夠理想,因為它還不能通過與一個閾值(比如0)的簡單比較得出顏色的分類。

圖1-4 示例:機器學習就是尋求有效的表示轉換。(a)平面上由黑點和白點組成的數據集的原表示。(b)(c) 兩次連續的轉換將原表示轉換成一個更適合顏色分類任務的表示

幸運的是,我們可以進行第二次變換來達到此目的。這一變換基于下面這個簡單的公式:

(角度的絕對值) - 135度

這次變換得到的表示,如圖1-4c所示,是一維的。與圖1-4b中的表示相比,這樣做可以將各點到原點的距離這一不相干的信息剔除。從顏色分類任務的角度而言,這個表示恰到好處,因為它讓決策過程變得極其簡單:

如果公式計算結果小于0,則點為白色;
    否則,點為黑色

在上面的示例中,我們為原表示人為地選擇了兩個轉換步驟。但是,如果能以顏色分類的準確率作為依據,實現自動搜索各種可能的坐標轉換,那就是機器學習了。解決實際機器學習問題所需的轉換步驟通常遠多于兩個。特別是在深度學習中,甚至可能達到上百個。同時,實際機器學習中涉及的表示轉換可能比這個簡單示例中的要復雜得多。深度學習領域的研究仍在不斷發現更復雜且強大的轉換,圖1-4正詮釋了“搜索更好的表示”這一本質。這一點適用于所有機器學習算法,包括神經網絡、決策樹、核方法以及其他算法等。

1.1.3 神經網絡和深度學習

神經網絡是機器學習的子領域,其中實現數據表示轉換的系統,其架構部分參考了人和動物大腦中神經元的連接方式。那么,大腦中的神經元是如何連接的呢?雖然連接方式會因物種和大腦區域而有所不同,但有一點是共通的,那就是層結構。哺乳動物大腦的很多部分展現了層的特征,比如視網膜、大腦皮層和小腦皮層。

至少表面上看來,這一特征和人工神經網絡9的結構大體相似,它們的數據都是通過多個可分離的步驟進行處理的。因此,將這些步驟稱為(layer)恰如其分。這些層通常彼此疊加,只有相鄰的層之間會建立連接。圖1-5展示了一個簡單的含有4層的神經網絡,這個神經網絡能夠對手寫數字的圖像進行分類,在層與層之間可以看到原數據的表示在轉換過程中形成的中間表示。輸入數據(此處是一個圖像)進入第1層(圖1-5的左側),然后按順序一層層流入,每一層都會對數據的表示進行一次轉換。隨著數據經過越來越多的層,表示會越發偏離原表示,而越發接近神經網絡的目標,那就是為輸入圖像打上正確的標簽。當數據經過最后一層(圖1-5的右側)后,就會產生神經網絡的最終輸出,即圖像分類任務的結果。

9artificial neural network,也可以簡稱為neural network,即神經網絡,在計算機領域這種說法并沒有歧義。

圖1-5 一個由層組成的神經網絡的示意圖,弗朗索瓦·肖萊版權所有10

10摘自弗朗索瓦·肖萊所著的《Python深度學習》一書。

神經網絡中的層和數學中的函數概念相似,它們都是從輸入值到輸出值的映射。然而它們又有所不同,這是因為神經網絡中的層是有狀態的(stateful)。換言之,它們在內部保留有記憶,這些記憶封裝在相應的權重中。權重(weight)就是一組屬于層的數值,這些數值決定了每一個輸入的表示如何轉換成輸出的表示。比如,常用的密集層(dense layer)在轉換輸入數據時,會將它乘以一個矩陣,然后讓該結果加上一個向量,這里的矩陣和向量就是密集層的權重。當神經網絡用數據進行訓練時,各層的權重會進行系統性修改,最終讓損失函數(loss function)的值趨于最小。第2章和第3章中會用具體的示例進行說明。

盡管神經網絡確實從人類大腦結構中汲取了部分靈感,但是我們不應將這兩者過度類比。神經網絡不是為了學習或模仿人類大腦的工作機制,它是完全不同的學術領域——神經科學的研究范疇,旨在讓機器能夠通過學習數據來執行有意義的實際任務。在結構和功能方面,雖然有些神經網絡和人類大腦的某些部分確實有不可思議的相似性11,但是關于這一點的可靠性超出了本書的討論范疇。無論怎樣,這種相似性不應被過度解讀。尤其是目前并沒有證據表明大腦通過任何形式的梯度下降優化進行學習,而這恰恰是神經網絡的主要訓練方式(參見第2章)。對于很多引領深度學習革命的重要的神經網絡技術,它們的發明和應用并不是因為有神經科學的理論支撐,而是因為能幫助神經網絡更好、更快地解決實際學習任務。

11第4章有一個關于功能相似性的示例較具說服力,其中展示了一些輸入如何最大限度地激活卷積神經網絡的各個層,這與人類視覺系統各部分的神經元感受野(neuronal receptive field)的功能非常相似。

了解神經網絡之后,接下來看一下深度學習(deep learning)的概念。深度學習就是關于深度神經網絡(deep neural network)的學習和應用。而深度神經網絡,簡單來說,就是有很多層(通常多達數十甚至上百層)的神經網絡。在這里,(deep)是指為數眾多的連續的表示層,數據模型擁有的層數叫作模型的深度(depth)。這一領域還有其他名稱,比如分層表示學習(layered representation learning)和層級表示學習(hierarchical representation learning)。現代深度學習通常包含數十至上百個連續的表示層,它們都是從訓練數據中自動學習的。與此相反,其他機器學習方法傾向于專注學習一到兩個表示層,因此,它們又叫作淺層學習(shallow learning)。

將深度學習中的“深”解讀為對數據的深刻理解是錯誤的。M. C. Escher畫作中自我指涉(self-reference)所造成的悖論可謂深刻,但這種深刻對AI研究者而言仍是不可企及的目標12。也許在未來,深度學習會讓我們更接近這樣的深刻,但它肯定沒有像給神經網絡添加層這樣容易量化和實現。

12參見Douglas Hofstadter發表的文章“The Shallowness of Google Translate”。

信息欄1-1 神經網絡不是唯一選擇:其他機器學習技術

回顧圖1-1,我們現在從“機器學習”的大圈進入了“神經網絡”的小圈。然而,在深入探索之前,大致了解一些非神經網絡機器學習技術是十分有益的。這不僅能幫助我們了解機器學習發展的歷史背景,而且可以在現有代碼中很好地理解它們的用法。

樸素貝葉斯分類器(naive Bayes classifier)是最早的機器學習方法之一。簡單地說,對于計算事件發生概率的貝葉斯定理,其實現過程基于兩個前提:第一,對已有事件發生可能性的先驗認知;第二,觀測到的數據,即特征(feature)。這一方法可以用觀測到的數據計算每個事件類別對應的概率,然后按照最高的概率(事件發生可能性),將觀測到的數據劃入一個已知的類別。該方法假設觀測到的數據之間是相互獨立的,這是一個非常強的假設,同時對現實中的現象有所簡化,名字中的“樸素”正是由此而來。

邏輯回歸(logistic regression)也是一種分類方法。由于其簡單和靈活多變的特性,它至今都非常流行,通常是數據科學家處理分類任務的首選方法。

核方法(kernel method)主要用于解決二分類問題,即共有兩種類別的問題。它將原數據映射到新的更高維空間,并尋找一種轉換方式,實現兩種類別示例之間距離(又稱margin,即間隔)的最大化,從而進行分類。支持向量機(SVM)是核方法最有代表性的例子。

決策樹(decision tree)的結構與流程圖類似。可以對輸入的數據進行分類,或者根據輸入的數值預測輸出。在流程圖的每一步,只需要簡單地回答一個答案為“是”或“否”的問題,比如“X特征的值是否大于特定閾值”。每一步的流程取決于所選答案,然后進入答案對應的路徑,在那里會出現另一個“是”或“否”的問題,以此類推。一旦到達了流程圖的終點,也就獲得了最終的答案。如你所見,對所有人而言,決策樹非常直觀且容易理解。

隨機森林(random forest)和梯度提升機(gradient-boosted machine)通過整合大量有特定功能的決策樹來提高整體的準確率。集成化(ensembling)又名集成學習(ensemble learning),這種方法會訓練一些機器學習模型的集合(集成),并在推斷階段將它們的整體輸出作為推斷結果。現在,梯度提升是用來處理非感知數據最好的算法之一,例如信用卡詐騙檢測中的信用數據。和深度學習一樣,它也是Kaggle這類數據科學競賽中較為常用的技巧。

神經網絡的崛起、隕落和回歸,以及這些現象背后的原因

神經網絡的核心思想早在20世紀50年代就成形了。訓練神經網絡的關鍵技術,包括反向傳播算法,在20世紀80年代就出現了。然而,20世紀80年代至21世紀前十年這一段漫長的時期里,神經網絡技術在研究社區里幾乎完全進入了蟄伏期。原因包括支持向量機等同類技術的流行,以及當時缺乏訓練深度神經網絡(非常多層)的能力。但是,在2010年前后,很多堅持奮戰在神經網絡領域的人們開始取得意義重大的突破,這些人包括:多倫多大學的Geoffrey Hinton研究小組、蒙特利爾大學的Yoshua Bengio、紐約大學的Yann LeCun和瑞士意大利語區高等專業學院Dalle Molle人工智能研究所(IDSIA)的研究者。這些團體取得了很多里程碑式的成果,包括第一次在GPU(圖形處理單元)上真正實現深度神經網絡,以及將ImageNet計算機視覺比賽中的錯誤率從25%降到不足5%等。

自2012年以來,深度卷積神經網絡已經成了所有計算機視覺任務的首選算法;說得更寬泛點兒,它們適用于所有感知性任務。語音識別就是非計算機視覺的感知性任務示例之一。在2015—2016年的大型計算機視覺會議中,幾乎所有的演講報告都和convnet有某種程度的關聯。同時,深度學習還應用到了其他一些問題上,比如自然語言處理。它在各種應用程序中取代了SVM和決策樹的地位,例如對于ATLAS探測器在大型強子對撞機上獲得的粒子數據,多年來歐洲核子研究組織(CERN)一直采用基于決策樹的方法進行分析。但是,考慮到神經網絡性能更佳,在大數據集上易于訓練,CERN最終還是轉向了深度神經網絡的陣營。

那么,為什么深度學習會從所有的機器學習算法中脫穎而出呢?(參見信息欄1-1中列出的一些流行的非深度神經網絡的機器學習方法。)深度學習快速崛起的主要原因是它能在很多問題上獲得更好的性能,但這并不是唯一的原因。深度學習還讓解決問題變得更簡單,因為它能實現特征工程(feature engineering)的自動化,這一度是機器學習流程中最重要、最困難的一步。

對于前面介紹的淺層學習,這種機器學習技術通常只需借助簡單的轉換方法,如非線性高維映射(核方法)或決策樹等,將輸入數據轉換成一個或兩個連續的表示空間。但是復雜問題所需的表示更為精細,這些技術無法實現。因此,人類工程師不得不在原始的輸入數據上耗費更多的精力,讓它們也能夠由這些技術處理。也就是說,工程師必須手動為數據設計合適的表示層,這就是特征工程。相對而言,深度學習可以自動實現這個過程。通過深度學習,可以借助程序一次性學習所有特征,無須手動設計。這極大地簡化了機器學習的流程,從而可以將復雜、精細的多步驟流水線替換成單個、簡單的端到端深度學習模型。通過實現特征工程自動化,深度學習減少了機器學習所需要的人力投入,模型本身變得更為穩健,可謂一箭雙雕。

在學習數據時,深度學習有兩個至關重要的特點:一是循序漸進、一層接一層地發展更為復雜的表示;二是在整個過程中,中間這些遞進的表示層同時是被學習的,每一層的更新都會同時兼顧上層和下層的表示需求。正是這兩個特點的結合,使深度學習相比之前的機器學習策略獲得了更大的成功。

1.1.4 進行深度學習的必要性

如果神經網絡的基本思想和核心技術早在20世紀80年代就已存在,為什么直到2012年后才發生深度學習革命呢?在中間的30多年里都發生了什么?總體來說,有3股技術力量推動了機器學習的發展:

● 硬件

● 數據集和基準

● 算法上的革新

接下來逐個看一下這些關鍵因素。

硬件

深度學習是由實驗發現而非理論引導的工程科學領域。只有當硬件條件允許嘗試新想法,或者是更為常見的放大舊想法的實驗規模時,才有可能實現算法上的革新。對計算機視覺和語音識別中應用的典型的深度學習模型而言,其所需要的算力超出了筆記本計算機算力幾個數量級。

在21世紀前十年里,為了滿足畫面日益逼真的電子游戲在圖像處理上的需求,英偉達(NVIDIA)和超威半導體(AMD)等公司投資了數十億美元來開發高速的、適用于并行計算的芯片(GPU),這些芯片其實是廉價且功能單一的、專用于在屏幕上實時渲染復雜三維圖像的超級計算機。2007年,NVIDIA發布了一種專為NVIDIA GPU設計的通用編程接口:CUDA(Compute Unified Device Architecture,計算統一設備體系結構)。這標志著GPU領域的投資真正開始推動科學研究社區的發展。從物理建模領域開始,小規模的GPU集群逐漸開始在適合高度并行計算的應用程序中取代傳統的大規模CPU集群。深度神經網絡所涉及的運算主要由矩陣乘法和矩陣加法構成,因此它們也具有高度的并行性。

在2011年前后,一些研究者開始編寫神經網絡的CUDA實現,Dan Ciresan和Alex Krizhevsky就是其中最早的一批。當下,在訓練深度神經網絡時,高端GPU可以提供的并行算力是一般CPU的上百倍。正是依靠現代GPU的驚人算力,很多頂尖的深度神經網絡的訓練才成為可能。
 

數據和基準

如果說硬件和算法之于深度學習革命就如同蒸汽機之于工業革命,那么數據就相當于“蒸汽機所燒的煤”。數據是這些智能機器的能量來源,沒有了它,一切皆無可能。談及數據,在過去20年,除了存儲硬件呈指數級發展(遵循摩爾定律),根本變化是互聯網的崛起。互聯網讓機器學習收集和分發大量的數據集成為可能,如果沒有互聯網,現在大型企業所用的圖像數據集、視頻數據集以及自然語言數據集都不可能存在。例如,用戶在Flickr平臺生成的帶水印的圖像就是計算機視覺研究的數據寶庫,YouTube平臺上的視頻也是如此。維基百科則是自然語言處理的一個關鍵數據集來源。

如果必須說哪個數據集是深度學習崛起的關鍵助力,那么一定是ImageNet了。這個大型視覺數據庫包含約1419萬個圖像,每張都有針對1000種圖像類型的手動注釋。ImageNet的特殊之處不僅在于其數據龐大,還在于和它相關的年度競賽13。正如ImageNet和Kaggle自2010年來所展示的那樣,公開的競賽是激勵研究者和工程師開拓領域疆界的絕佳方式。它們讓研究者競相超越一個共同的基準,從而極大地促進近來深度學習的崛起。
 

算法上的革新

除了硬件和數據上的進步,我們還缺少訓練深度神經網絡(具有非常多的層)的可靠方法,直到21世紀前十年后期,這種現象才有所好轉。結果就是:當時的神經網絡仍非常淺,僅使用一到兩層表示。因此,它們無法和其他更精細的淺層方法競爭,例如SVM和隨機森林。問題的關鍵在于穿越多層的梯度傳播,這是因為隨著所經過層數的增加,用于訓練神經網絡的反饋信號會逐漸消失。

這一點在2009—2010年發生了改變,其中的幾個簡單但意義重大的算法革新,讓梯度傳播變得更為有效。

● 更好的神經網絡層激活函數(activation function) ,例如線性整流函數(簡稱ReLU)。

● 更好的權重初始化方案(weight-initialization scheme),例如Glorot初始化方法。

● 更好的優化方案(optimization scheme),例如RMSProp和ADAM優化器。

只有當這些改進可以訓練10層或更多層的模型時,深度學習才會大放異彩。終于,2014—2016年出現了一些更為高級的幫助梯度傳播的方法,包括批標準化(batch normalization)、殘差連接(residual connection)和深度可分離卷積(depthwise separable convolution)。現在,我們已經可以從頭訓練有上千層的深度神經網絡模型了。

13ImageNet大規模視覺識別挑戰賽(ILSVRC)。——譯者注

1.2 為何要結合JavaScript和機器學習

與AI和數據科學的其他分支一樣,機器學習通常使用傳統的后端編程語言來實現,比如Python和R,這些編程語言在Web瀏覽器外部的服務器或工作站上運行14。通常普通瀏覽器頁面并不直接具備訓練深度神經網絡所需的多核計算和GPU加速計算能力,另外對于訓練這樣的模型,有時候所需的海量數據從后端獲取更為方便15,因此這種現象很正常。直到最近,很多人仍只是把“實現JavaScript深度學習”看作新奇的想法。這一節將詮釋為什么對很多應用程序而言,在瀏覽器環境中用JavaScript進行深度學習是一個明智之舉,同時還會介紹為什么結合深度學習和Web瀏覽器可以創造很多獨特的機會(特別是通過TensorFlow.js)。

14參見Srishti Deoras發表的文章“Top 10 Programming Languages for Data Scientists to Learn in 2018”。

15例如,可以直接從近乎無限大的原生文件系統中讀取。

一旦某個機器學習模型訓練完畢,必須將其部署到某種生產環境中,這樣才能開始基于真實數據進行預測,比如對圖像和文本進行分類、檢測音頻或視頻中發生的事件,等等。如果沒有部署環節,訓練模型只是在浪費算力。將Web前端作為部署的“某種生產環境”通常是人們所預期的,甚至可以說是必不可少的。你可能已經對Web瀏覽器的重要性深有體會,在臺式計算機和筆記本計算機上,Web瀏覽器是當今用戶獲取互聯網內容和服務絕對主流的方式,也是用戶在使用期間花費時間最多的地方,其使用頻率遠超第二名。同時,它還是用戶進行工作、社交和娛樂的主要陣地,其中運行的多種多樣的應用程序,為在客戶端上進行機器學習提供了豐富的機會。對移動端的前端而言,無論是在用戶參與度上,還是在用戶的使用時間上,Web瀏覽器都落后于原生移動應用程序。盡管如此,但移動端Web瀏覽器仍是不可小覷的力量,它們有更廣泛的受眾,可以隨時使用,并且有更快的開發周期16。事實上,正是因為Web瀏覽器的靈活性和易用性,很多移動應用程序會為某些內容類型嵌入啟用了JavaScript的Web頁面,包括推特和臉書。

16參見Rishabh Borde發表的文章“Internet Time Spend in Mobile Apps 2017–19: It's 8x than Mobile Web”。

正因為這種廣泛的影響力,模型所需的數據都可以從瀏覽器中獲得,所以Web瀏覽器成為部署深度學習模型的合理選擇。但瀏覽器可以獲得什么類型的數據呢?答案是“太多了”!深度學習較為流行的應用程序都可以當作示例,包括分類和檢測圖像以及視頻中的物體、轉錄音頻、翻譯自然語言和分析文本內容。可以說,Web瀏覽器擁有展示文本數據、圖像數據、音頻數據和視頻數據的最全面的技術和API。因此,通過TensorFlow.js和一些簡單的轉換流程等,可以直接在瀏覽器中使用強大的機器學習模型。至于在瀏覽器中部署深度學習模型,本書后面的章節中提供了很多具體示例。例如,在用網絡攝像頭捕獲了一些圖像后,可以用TensorFlow.js運行MobileNet模型來標記圖像中的物體,運行YOLO2模型將檢測到的物體用方框進行標注,運行Lipnet來讀取唇語,也可以運行CNN-LSTM模型為圖像添加字幕。

如果用瀏覽器的Web Audio API控制麥克風捕獲音頻,TensorFlow.js可以通過運行模型,對語音進行實時識別。還有很多關于文本數據的優秀的應用程序,比如對影評進行情感分析,判斷是否為正面評價(第9章)。除了這些數據形式,Web瀏覽器還可以從移動設備上獲取一系列傳感器數據,比如HTML5提供了API來訪問地理位置(包括緯度和經度)、運動信息(設備的朝向和加速度)和背景光(參見Mobile HTML5網站)。如果將這些傳感器數據和深度學習還有其他一些數據形式結合起來,它們可以使很多優秀的新應用程序成為可能。

基于瀏覽器的深度學習應用程序還有另外5個優勢:更少的服務器開銷、更低的推斷延遲、保護數據隱私、即時GPU加速和隨時使用。

服務器開銷通常是設計和伸縮網絡服務時的一個重要考量。通常,快速運行深度學習模型所需的算力是相當高的,這使GPU加速成了必選項。如果模型沒有在客戶端上部署,它們就需要部署到有GPU支持的機器上,比如由谷歌云平臺或亞馬遜Web服務(Amazon Web Services)提供的配有CUDA GPU的虛擬機。這樣的云端GPU機器通常開銷非常大,即使是最基本款的GPU機器,每小時大約也要花費0.5~1美元。隨著流量的增加,在云端運行GPU機器的開銷會越來越大,更別說服務器端在可擴展性和額外復雜度上隨之出現的挑戰了。如果將模型部署在客戶端上,所有的顧慮都會迎刃而解。客戶端下載模型大小不等,通常為幾兆字節(MB),這里的額外延遲可以通過瀏覽器的緩存和本地存儲能力緩解(參見12.3.1節)。

更低的推斷延遲。對于某些應用程序類型,可接受的最大延遲要求非常嚴格,因此在客戶端上運行深度學習模型成為必然。任何涉及實時音頻數據、圖像數據和視頻數據的應用程序都可以歸為這個范疇。如果圖像的每一幀都需要傳輸到服務器端進行推斷,會發生什么情況?假設網絡攝像頭以每幀400像素×400像素、每秒10幀的速率捕捉圖像,圖像的顏色使用三色通道(RGB),每個顏色通道都使用8位深度。即使采用JPEG壓縮,每一張圖片的大小也至少有150KB左右。在一個典型的有300kbit/s上傳帶寬的移動網絡中,上傳一張圖片可能要花費500毫秒以上的時間,這所導致的延遲是肉眼可見的,而這對于某些應用程序(比如游戲)是不可接受的。這一計算并沒有考慮網絡連接的波動情況(網絡連接有可能中斷)。用于下載推斷結果的額外時間,還有大量的移動數據用量,都可能終止這種情境下的服務器端推斷。

客戶端推斷會將數據和計算都放在設備上,這樣解決了潛在的延遲和網絡連接穩定性方面的問題。在客戶端上運行模型是實時機器學習應用程序的唯一選擇,比如標記物體和探測網絡攝像頭圖像中的動作。即使對于那些沒有延遲要求的應用程序,降低模型推斷延遲也可以增強應用程序的響應速度,從而提升用戶體驗。

保護數據隱私。將訓練數據和推斷數據放在客戶端的另一個好處是保護了用戶的隱私。數據隱私在當下的意義已經越來越重要。對某些類型的應用程序而言,數據隱私是一個強制要求,比如涉及健康和醫療數據的應用程序。假設有一個“皮膚病診斷助手”應用程序,它必須從網絡攝像頭收集關于病人皮膚的圖像,然后利用深度學習生成可能的皮膚情況診斷。很多國家及地區的健康信息隱私法規禁止在一個中心化的服務器上傳輸這樣的圖像進行推斷。但是通過在瀏覽器中使用模型進行推斷,數據根本無須離開用戶的手機,甚至無須存儲下來,這樣就確保了用戶健康數據的隱私。

現在考慮另外一個基于瀏覽器的應用程序場景,假設這個應用程序要使用深度學習來為用戶在其中所創造的文本內容提供改進意見。有些用戶可能會寫一些敏感內容,比如法律文件,那么用戶肯定不希望相關數據通過公共網絡傳輸到一個遠程服務器上。這時使用瀏覽器和JavaScript在客戶端運行模型就能有效地打消這種顧慮。

即時GPU加速。除了有數據這一前提條件,在Web瀏覽器中運行機器學習模型的另一個前提條件是通過GPU加速獲得足夠的算力。正如之前提到的,很多前沿的深度學習模型計算強度非常高,因此使用GPU上的并行計算進行加速成了一個必選項,當然,除非你愿意讓用戶為一個推斷結果等待數分鐘,但這在現實應用程序中幾乎不可能發生。幸運的是,現代Web瀏覽器都備有WebGL API,它的設計初衷是加速二維圖像和三維圖像的渲染,但也可以應用到加速神經網絡所需的并行計算中。TensorFlow.js的作者已經將基于WebGL的深度學習加速功能融入到了一個專用庫中。只需要一行JavaScript的import代碼,就可以獲取GPU加速。

基于WebGL的神經網絡加速可能不能完全和基于原生、特定的GPU加速17相提并論,但是它能將神經網絡的速度提升幾個數量級,并且讓像PoseNet從圖像中提取人體姿態這樣的實時推斷成為可能。

如果用預訓練模型進行推斷的開銷非常大,那么在該模型上進行訓練或遷移學習就更是如此了。訓練或遷移學習預訓練模型開啟了一系列令人興奮的應用程序,例如深度學習模型的個性化定制、深度學習的前端可視化以及聯邦學習(federated learning)18。借助啟用WebGL加速的TensorFlow.js,可以在Web瀏覽器中實現以足夠快的速度訓練或微調神經網絡。

隨時使用。一般來說,在瀏覽器中運行的應用程序有“無須安裝”的天然優勢:只需輸入URL或點擊某個鏈接就能獲取應用程序。這樣就避免了可能的煩瑣又易出錯的安裝步驟,以及在安裝新軟件時潛在的權限控制風險。對TensorFlow.js所提供的基于WebGL的神經網絡加速來說,在用瀏覽器進行機器學習的語境下,并不需要特殊的顯卡或為這些顯卡安裝驅動。后者通常也不是一個簡單的過程。絕大多數相對較新的臺式計算機、筆記本計算機和移動設備安裝了適用于瀏覽器和WebGL的顯卡。這些設備只要裝有和TensorFlow.js兼容的Web瀏覽器(這很容易實現),無須任何額外設置,就可以運行WebGL加速的神經網絡。對于易訪問性極其重要的場景,例如深度學習教育,這一特性尤其誘人。

17比如NVIDIA CUDA以及TensorFlow和PyTorch等Python深度學習庫所使用的CuDNN。

18聯邦學習就是在不同設備上訓練同一模型,然后匯總訓練結果,從而獲得一個不錯的模型。

信息欄1-2 使用GPU和WebGL加速計算

訓練機器學習模型和使用模型進行推斷需要大量的數學運算。例如,神經網絡中廣泛使用的密集層就需要將一個大矩陣和一個向量相乘,然后讓結果加上另一個向量。像這樣的常用運算通常涉及上千次至上百萬次浮點運算,這類運算有一個很重要的特性,那就是很多時候它們可以并行進行。

舉個例子,兩個向量的加法可以拆分成很多更小的運算,比如兩個數字相加。這些更小的運算互不依賴。例如計算兩個向量中索引1上元素的和,無須提前知道索引0上元素的和。因此,無論這些向量有多大,這些更小的運算都可以同時進行,而不是逐個地計算。

串行計算又叫作SISD,并行計算則叫作SIMD。前者即單指令流單數據流,比如用CPU實現的簡單向量加法;后者即單指令流多數據流,比如用GPU實現的并行向量加法。同樣進行單次運算,CPU所花的時間通常少于GPU所花的時間;但是從計算大量數據時所花的總時間來看,GPU的SIMD性能則要優于CPU的SISD。一個深度神經網絡可能包含上百萬個參數,對于給定的輸入,可能需要進行至少數十億次元素與逐元素的數學運算。從這個角度來看,GPU擅長的并行計算可以說是大放異彩。

WebGL加速利用GPU的并行計算實現比CPU更快的向量計算

準確地說,現代CPU也可以進行一定程度的SIMD運算,但相比之下,GPU擁有更多的計算單元,幾乎是前者的數百到數千倍,并且GPU可以在很多輸入數據切片上同時運行指令。向量加法是相對簡單的SIMD任務,其中每一步計算只涉及一個索引,并且每個索引對應的計算結果是相互獨立的。機器學習中其他常見的SIMD任務就復雜得多了。比如在矩陣乘法中,每一步計算會用到多個索引上的數據,并且這些索引之間互相依賴。盡管如此,但通過并行計算進行加速的基本原理是一樣的。

還有一點值得注意,那就是GPU設計的初衷并不是加速神經網絡。這一點也反映在它的名字上,即圖形處理單元。GPU的主要目的是處理二維圖像和三維圖像。在很多涉及圖像渲染的應用程序中,比如三維游戲,以最快的速度處理圖像非常重要。只有這樣,屏幕上圖像的更新頻率才能達到流暢的游戲體驗所需的高幀率,這也是GPU發明者利用SIMD并行計算的初衷。但是,GPU擅長的并行計算恰好滿足了機器學習的需求,這實屬意外的驚喜。

對于TensorFlow.js用來進行GPU加速的WebGL庫,其設計初衷是在Web瀏覽器中渲染三維物體的紋理(表面圖案)——本質上就是數字矩陣!因此,可以把這些數字當作神經網絡的權重或激活值,然后復用WebGL的SIMD紋理運算,讓它們來運行神經網絡。這正是TensorFlow.js在瀏覽器中加速神經網絡的方式。

除了上述優勢,基于機器學習的Web應用程序和不涉及機器學習的普通Web應用程序的優勢是共通的。

● 和原生應用程序開發不同,用TensorFlow.js編寫的JavaScript應用程序可以在各種生態的設備上運行,包括Mac、Windows和Linux的桌面端系統以及安卓和iOS的移動端系統。

● 得益于它高度優化的(二維和三維)圖形處理能力,Web瀏覽器是數據可視化和互動方面最豐富且最成熟的環境。對展示神經網絡的行為和內部構造這一應用場景而言,沒有什么能出瀏覽器其右。TensorFlow Playground就是很好的示例(參見TensorFlow Playground網站),它是一個非常流行的Web應用程序,可以通過它的圖形界面和神經網絡互動來解決分類問題,還可以用它微調神經網絡的結構和超參數,然后觀察其隱藏層和輸出對應的變化情況(見圖1-6)。如果你還沒有試過TensorFlow Playground,強烈建議你試用一下。許多人表示這是他們看過的關于神經網絡的最有指導意義和令人愉悅的教學素材之一。事實上,TensorFlow Playground是TensorFlow.js的重要先驅,因此,相比前者,后者的能力范圍要大得多,并且有更深度的性能優化。此外,TensorFlow.js還內置了專用于可視化深度學習模型的模塊(參見第7章)。無論是想構建像TensorFlow Playground這樣基本的教育性應用程序,還是想以引人入勝的直觀方式展示前沿深度學習研究,TensorFlow.js都可以幫助你朝目標邁進一大步(參見t分布隨機鄰域嵌入算法的實時可視化示例,即tSNE19)。

19參見Nicola Pezzotti在Google AI Blog發表的文章“Realtime tSNE Visualizations with TensorFlow.js”。

{%}

圖1-6 TensorFlow Playground網站截圖。它是一個非常流行的Web應用程序,由Daniel Smilkov及其同事共同制作,主要用于教授神經網絡的工作原理,同時也是TensorFlow.js項目的重要先驅

1.2.1 用Node.js進行深度學習

考慮到安全問題和性能問題,Web瀏覽器在設計時對可利用的資源進行了限制,具體體現在有限的內存和文件系統配額方面。但對訓練涉及大量數據的大型機器學習模型來說,這意味著瀏覽器并不是一個理想的環境。當然,對于很多其他類型的推斷,比如無須消耗大量資源的小規模模型訓練和遷移學習任務,Web瀏覽器仍然非常適用。但是,當Node.js出現后,JavaScript的地位就不可同日而語了。Node.js讓JavaScript脫離了Web瀏覽器的桎梏,使它能夠最大限度地利用系統的原生資源,比如內存和文件系統。TensorFlow.js包含了一個Node.js版本,叫作tfjs-node,可以與C++和CUDA代碼編譯而成的TensorFlow庫直接對接,這樣TensorFlow.js用戶也能夠受益于Python版TensorFlow所使用的CPU并行計算和GPU核函數計算。現實數據表明,tfjs-node中模型的訓練速度和Python中Keras的運行速度是相當的。因此,tfjs-node也可以用于訓練涉及大量數據的大型機器學習模型。本書會介紹使用tfjs-node來訓練超出瀏覽器能力極限的大型模型的一些示例,例如第5章的口令識別器、第9章的文本情感分析器。

但是在訓練機器學習模型時,為什么不選用更為成熟的Python環境而是選用Node.js呢?這主要有兩個原因:第一,Node.js的性能更好;第二,Node.js和現有的技術棧與開發者技能更匹配。

首先,就性能而言,目前行業頂尖的JavaScript解釋器,如Node.js使用的V8引擎,能夠利用即時編譯技術達到超過Python的性能。也正因如此,只要模型規模足夠小,其中編程語言的解釋性能可以決定訓練速度,這時用tfjs-node訓練模型通常比用Keras(Python)更快。

其次,Node.js本身也是一個非常流行的構建服務器端應用程序的生態。如果你當前的后端就是用Node.js編寫的,并且想將機器學習也囊括進你的技術棧中,那么相比Python,使用tfjs-node通常是更好的選擇。通過前后端使用同一種語言,可以直接復用代碼庫中的大部分代碼,包括那些用來加載和格式化數據的部分,從而更快地構建模型訓練的整個流程。此外,整個過程并沒有引入新的語言,這樣可以控制開發的復雜度和成本,也可以避免專門雇用Python程序員所耗費的精力和開銷。

最后,除了僅支持瀏覽器API或僅支持Node.js API的與數據相關的代碼,用TensorFlow.js編寫的機器學習代碼可以同時在瀏覽器環境和Node.js端運行。本書中絕大部分示例程序可以同時在兩種環境中運行。另外,本書將那些沒有環境依賴并與機器學習直接相關的核心代碼,同那些有環境依賴的數據獲取和UI代碼進行了分離。這樣有一個額外的優勢,那就是只需學習一個庫,就能同時學會如何在服務器端和客戶端進行深度學習。

1.2.2 JavaScript生態系統

在評估JavaScript是否適合深度學習這樣的應用程序時,一定不能忽視JavaScript背后極其強大的生態。多年來編程語言不斷地發展更新,但最受歡迎的一直是JavaScript。在GitHub上,無論是相關代碼倉庫的總量,還是提交代碼的活躍度,都可以證明這一點(參見GitHut網站)。npm是一種JavaScript包管理器,截至2018年7月,其中軟件包的數量已經高達60萬,比Python的包管理器PyPi上的數量高出不止4倍(參見Module Counts網站)。盡管Python和R在機器學習和數據科學方面有更為完善的社區,但是JavaScript社區也在積極地為構建基于JavaScript的機器學習流程而努力。

想從云存儲和數據庫接入數據嗎?谷歌云平臺和亞馬遜Web服務都提供了Node.js的API。當下最流行的數據庫系統也提供了對Node.js驅動的官方支持,比如MongoDB和RethinkDB。想要用JavaScript來整理數據嗎?如果想,那么可以閱讀Ashley Davis所著的Data Wrangling with JavaScript。想要實現數據可視化嗎?JavaScript社區擁有一些成熟且強大的庫,例如d3.js、vega.js和plotly.js等,它們在很多方面遠超Python可視化庫。數據準備就緒之后,就要展開介紹本書的主題了,即TensorFlow.js。它將幫助你完成從創建、訓練到執行深度學習模型的全流程,當然,還包括如何保存、讀取和可視化這些模型。

最后,JavaScript生態圈還在持續不斷地朝令人興奮的新領域和新方向演進,其影響力已經從Web瀏覽器和Node.js后端環境這些傳統強項,延伸到了桌面端應用程序(比如Electron)和原生移動端應用程序(比如React Native和Ionic)。在開發用戶界面和應用程序時,使用這些跨平臺框架通常比使用各個平臺專門的開發工具便捷得多。因此,在向各個主流計算平臺推廣深度學習方面,JavaScript是很有潛力的編程語言。表1-2中總結了將JavaScript和深度學習相結合的主要優勢。

表1-2 用JavaScript進行深度學習的優勢概覽

1.3 為何選用TensorFlow.js

工欲善其事,必先利其器。在開始用JavaScript進行深度學習前,應該先選擇一個正確的工具。本書選擇的是TensorFlow.js,本節會詳細介紹TensorFlow.js以及選擇它的原因。

1.3.1 TensorFlow、Keras和TensorFlow.js的前世今生

TensorFlow.js是JavaScript語言的深度學習庫。可以看到,TensorFlow.js在設計上是與TensorFlow(Python深度學習框架)保持一致且兼容的。要想真正理解TensorFlow.js,需要先簡單了解一下TensorFlow的發展歷程。

TensorFlow是由谷歌從事深度學習的團隊于2015年11月創造的開源資源,本書作者正是這個團隊的成員。從開源至今,TensorFlow獲得了巨大的成功,在谷歌以及更大的技術社區的各種工業應用程序和研究項目中得到了廣泛應用。另外,數據的表示又叫作張量(tensor),它會“流經”(flow)模型的每一層和其他數據處理節點,從而實現機器學習模型的推斷和訓練,因此“TensorFlow”這一名字暗指在該框架下編寫的典型程序中發生的事情。

什么是張量?這只不過是計算機科學家對“多維矩陣”更嚴謹的說法罷了。在神經網絡和深度學習中,每個數據和計算結果都會用張量表示。例如,一個灰度圖像可以表示為一個二維數組,這就是一個二維張量;同理,彩色圖像多出了一個維度,即顏色通道,因此可以表示為三維張量。音頻、視頻、文本以及其他任何類型的數據都可以用張量來表示。每個張量都由兩種基本屬性構成:數據的類型(比如float32或int32)和形狀。數據的形狀描述了張量各個維度的尺寸,例如二維張量的形狀可能是[128, 256],而三維張量的形狀則可能是[10, 20, 128]。一旦數據轉換成了某個特定的數據類型和形狀,無論它最初的意義是什么,都可以輸入到任何與其類型和形狀匹配的層。因此,張量其實就是深度學習模型賴以溝通的語言。

但為什么要用張量呢?上一節曾提到,運行深度神經網絡所需的大部分計算通常以并行化的方式在GPU上進行,這也意味著要對很多數據進行相同的運算。張量能夠將數據結構化,從而實現高效并行計算。如果將形狀為[128, 128]的張量A與形狀為[128, 128]的張量B相加,顯而易見,這將產生128×128個獨立的加法運算。

那TensorFlow中的“flow”又指什么呢?把張量想象成能夠承載數據的流體就明白了。只不過在TensorFlow中,張量流過的是(graph),即由各種數學運算(節點)互相連接而成的數據結構。如圖1-7所示,這些節點可以看作神經網絡中連續的層,每一個節點都將張量作為輸入,然后產生新的張量作為輸出。隨著張量“流經”TensorFlow圖的各個節點,它也轉換成不同的形狀和值。就像本章前面介紹的,這實際上就是表示的轉換,也正是神經網絡的關鍵。利用TensorFlow,機器學習工程師可以編寫各種不同的神經網絡,包括從淺層神經網絡到有相當深度的神經網絡,以及從用于計算機視覺的convnet到用于處理序列數據的循環神經網絡。TensorFlow的圖數據結構可以被序列化,并且被部署到包括大型機和手機在內的各種設備上。

圖1-7 TensorFlow和TensorFlow.js中的常見場景——張量“流經”各個層的示意圖

TensorFlow的核心部分在設計上是非常通用且靈活的:運算不限于神經網絡的層,可以是任意定義明確的數學函數,比如像張量加法和張量乘法這樣發生在神經網絡層內部的低階數學運算。這樣一來,當自定義一些有關深度學習的新運算時,深度學習工程師和研究者就有很大的發揮空間。盡管如此,但是對很大一部分深度學習從業者而言,花費精力來擺弄這些底層的操作并不值得,還可能造成更臃腫、更易出錯的代碼以及更長的開發周期。絕大多數深度學習工程師只需用到幾種固定的層類型20,幾乎不需要再創建新的層類型。這就和樂高積木的原理一樣,樂高積木只有很少的幾種基礎方塊類型,玩家在搭建模型時無須思考積木的制作方法。雖然搭建樂高模型可以帶來無數可能的組合和無窮的威力,但是TensorFlow的低階API其實更接近培樂多這樣的彩泥玩具。當然,樂高積木和培樂多彩泥都可以構建玩具小屋,但除非對小屋的尺寸、形狀、材質或原料有特殊要求,否則使用樂高來搭小屋一般更快捷、更方便。另外,對絕大多數人而言,用積木搭的小屋會比用彩泥搭的小屋更穩固、更養眼。

20比如卷積層、池化層、密集層等,后面的章節會具體介紹。

在TensorFlow中,與樂高積木對應的就是高階API,即Keras21。Keras提供了一系列較為常用的神經網絡層類型,每種類型都帶有配置參數。用戶還可以將這些層連接起來,形成完整的神經網絡。除此之外,Keras的API還可以完成以下操作。

21事實上,自TensorFlow推出以來出現了很多高階API,有些是谷歌工程師創建的,有些是開源社區創建的,其中較受歡迎的包括Keras、tf.Estimator、tf.contrib.slim和TensorLayers等。對本書讀者來說,目前與TensorFlow.js最相關的高階API是Keras。這是因為TensorFlow.js的高階API是以Keras為藍圖創建的,而且TensorFlow.js在保存模型和加載模型方面與Keras具有雙向兼容性。

● 指定神經網絡的訓練方式(損失函數、度量指標和優化器)。

● 向神經網絡注入數據,從而進行訓練、評估或使用模型進行推斷。

● 檢測正在進行的訓練過程(回調函數)。

● 保存和讀取模型。

● 打印或繪制模型架構。

借助Keras,用戶僅通過幾行代碼就能完成深度學習整個流程。另外,有了低階API的靈活性和高階API的易用性加持,TensorFlow和Keras形成了一個共同生態,這種生態在工業和學術研究中得到了廣泛應用。作為當下正在發生的深度學習革命的重要組成部分,它們在推廣深度學習方面有著不可小覷的貢獻。以TensorFlow框架和Keras框架為界,在它們出現之前,要想真正進行深度學習,必須擁有CUDA編程技能以及用C++編寫神經網絡的大量經驗;在它們出現之后,再創建具有GPU加速的深度神經網絡,整個流程所需的技能門檻和精力都大大下降。但是仍有一個問題懸而未決,那就是在JavaScript中或者直接在瀏覽器中運行TensorFlow模型或Keras模型,還缺少一種方法。要想在瀏覽器中使用訓練好的深度學習模型,必須通過HTTP請求在后端獲取推斷結果,這就是TensorFlow.js要解決的痛點。Nikhil Thorat和Daniel Smilkov是谷歌深度學習數據可視化和人機交互方面的專家,他們發起了TensorFlow.js22。正如前面提到的,非常流行的TensorFlow Playground率先在瀏覽器端演示了深度神經網絡的工作原理,它是TensorFlow.js的重要前驅。2017年9月,deeplearn.js庫發布了,它有著和TensorFlow的低階API高度類似的低階API。deeplearn.js率先實現了WebGL加速的神經網絡運算,從而能夠以低延遲在瀏覽器端運行真正的神經網絡。

22還有一個有趣的事實,這兩位專家對于TensorBoard的開發(非常流行的TensorFlow模型可視化工具)也起到了關鍵作用。

隨著deeplearn.js取得了初步成功,谷歌大腦團隊的更多成員加入了這一項目,項目也隨之更名為TensorFlow.js。自此,JavaScript API進行了大量的翻新工作,極大地增強了與TensorFlow在API方面的兼容性。除此之外,TensorFlow.js低階核心基礎上還構建了一個類Keras的高階API,方便用戶利用TensorFlow.js來定義、訓練和運行深度學習模型。前面介紹了Keras的強大功能和可用性,這些對于TensorFlow.js同樣適用。為了進一步增強不同生態之間的兼容性,我們還構建了模型轉換器,能夠讓TensorFlow.js導入在TensorFlow和Keras中保存的模型,或者向它們導出模型。自從在2018年春季TensorFlow開發者峰會和谷歌I/O大會上亮相以來,TensorFlow.js快速發展成一個高度流行的JavaScript深度學習庫,至今仍在GitHub上保有同類庫中最高星級和復制數量。

圖1-8是TensorFlow.js的架構概覽。架構的最底層負責快速數學運算所需的并行計算,盡管絕大多數用戶不太關注這一層,但是在這一層上保持高計算性能至關重要,這樣更高層的API才能盡可能快地進行訓練和推斷。在瀏覽器中,它利用WebGL實現GPU加速(參見信息欄1-2)。在Node.js中,它還可以直接利用多核CPU進行并行計算,或使用CUDA進行GPU加速,這跟Python中TensorFlow和Keras的數學運算所使用的技術是一樣的。在最底層之上是Core API層,這一層和TensorFlow的底層API有著非常好的兼容性,并支持加載TensorFlow中的SavedModel模型。圖1-8中的最上層是類Keras的Layers API。對絕大多數使用TensorFlow.js的程序員而言,Layers API通常是最正確的選擇,自然也是本書的焦點所在。另外,它支持和Keras進行雙向模型導入或導出。

圖1-8 TensorFlow.js架構概覽,以及它與Python中TensorFlow和Keras的關系

1.3.2 為何選用TensorFlow.js

TensorFlow.js既不是深度學習領域唯一的JavaScript庫,也不是這方面的第一個庫,比如brain.js和ConvNetJS就出現得比較早。那么,為什么TensorFlow.js會從這些類似的庫中脫穎而出呢?第一個原因是它的全面性。對于深度學習在生產環境中所涉及的所有關鍵流程,TensorFlow.js是目前唯一全部支持的庫,它包括以下特性。

● 支持訓練和推斷。

● 支持Web瀏覽器和Node.js兩種環境。

● 能夠利用GPU加速(在瀏覽器中使用WebGL,在Node.js中使用CUDA核函數)。

● 支持用JavaScript定義神經網絡模型架構。

● 支持模型的序列化和反序列化。

● 支持與Python深度學習框架間的雙向模型格式轉換。

● 兼容Python深度學習框架使用的API。

● 內置數據獲取和可視化所需的API。

第二個原因是生態圈。絕大部分JavaScript深度學習庫會定義風格迥異的專屬API,相較而言,TensorFlow.js與TensorFlow和Keras是深度集成的。你是否已有一個用Python中的TensorFlow或Keras訓練的模型,而且想在瀏覽器中使用它?沒問題!你是否在瀏覽器中創建了一個TensorFlow.js模型,然后想在Keras中使用它,從而實現更快的加速設備,比如谷歌的張量處理器(TPU)?沒問題!與非JavaScript框架的深度集成,這不僅意味著更好的相互兼容性,還意味著開發者能夠更好地在不同的編程語言環境和基礎設施棧間進行知識遷移。舉個例子,一旦你通過本書掌握了TensorFlow.js,再學習使用Python中的Keras會相當順利。同理,如果你對Keras有一定的了解,而且有足夠的JavaScript編程功底,那么學起TensorFlow.js來也會非常快。還有一點需要注意,那就是TensorFlow.js的流行度和它背后社區的力量。TensorFlow.js的開發者致力于長期維護和支持該庫,從GitHub上的星級和復制數量,到外部貢獻者的數量,從各種討論的活躍度,到Stack Overflow上相關提問和回答的數量,這些方面都能夠說明TensorFlow.js的無可替代性。

1.3.3 TensorFlow.js在全球的應用情況

若要證明某個庫的功能和流行度,沒有什么比它在真實應用程序中的使用情況更具說服力的了。以下是幾個名聲赫赫的關于TensorFlow.js的應用程序。

● 谷歌的Magenta項目使用TensorFlow.js來運行RNN和其他類型的深度神經網絡,從而在瀏覽器中自動生成樂譜和新穎的音律(參見Magenta網站的Demos界面)。

● Dan Shiffman和他在紐約大學的同事創造了ML5.js,它是可以直接在瀏覽器中調用各種深度學習模型的易學的高階API,實現了目標檢測和圖像風格遷移等功能。

● 開源軟件開發者Abhishek Singh基于瀏覽器創造了能將美式手語轉換成語音的交互界面,讓聾啞人也可以使用像亞馬遜Echo這類的智能音箱。

● Canvas Friends是一個基于TensorFlow.js的Web應用程序,可以通過游戲化的方式幫助用戶提高繪畫技能(參見Canvas Friends的網站)。

● MetaCar是在瀏覽器中實現的自動駕駛模擬器。其中,用TensorFlow.js實現的強化學習算法是成功模擬的關鍵。

● Clinic doctor是基于Node.js的服務器端性能監控應用程序,它用TensorFlow.js實現了隱馬爾可夫模型,并以此來探測CPU使用率的突然增加。

● 還可以在GitHub網站的TensorFlow頁面中找到更多由TensorFlow.js開源社區共同創造的優秀的應用程序。

1.3.4 本書中的TensorFlow.js知識

通過對本書的學習,你可以用TensorFlow.js構建以下應用程序。

● 對用戶上傳的圖像進行自動分類的網站。

● 能夠從瀏覽器調用傳感器獲取圖像和音頻數據,然后對其進行識別和遷移學習等實時機器學習任務的深度神經網絡。

● 位于客戶端的自然語言處理模型,例如有助于管理評論區言論的情緒分類器。

● 位于后端的、基于Node.js的機器學習模型訓練器,可以處理吉字節級的數據和GPU加速。

● 能完成小型控制和游戲任務的強化學習模型。

● 可以展示已訓練模型的內部構造和機器學習實驗結果的可視化界面。

更重要的是,你不僅能學會如何構建和運行這樣的應用程序,還會知曉其背后的工作原理。也就是說,通過閱讀本書,可以獲得深度學習模型構建過程中不同問題所涉及的策略和相關限制的實用知識,同時還可以了解訓練和部署這些模型的具體步驟以及重要注意事項。

機器學習涉及的領域非常廣,而TensorFlow.js是一個靈活且全面的庫。因此,盡管有些應用程序超出了本書的討論范疇,但是它們完全可以通過TensorFlow.js現已提供的技術來實現,比如下面這些示例。

● 在Node.js環境中,對涉及大量數據[太字節(TB)級數據]的深度神經網絡進行高性能、分布式訓練。

● 非神經網絡技術,比如SVM、決策樹和隨機森林算法。

● 高級深度學習應用程序,比如能將大量文本概括成幾個代表性句子的文本摘要引擎,能根據輸入圖像生成文本描述的圖像轉文本引擎,還有能夠增強輸入圖像分辨率的生成圖像模型。

但無論如何,本書提供了有關深度學習的基礎知識,可為你以后學習這些高級應用程序的代碼和技術文章做好知識儲備。

與其他技術一樣,TensorFlow.js也有局限性。有些任務確實超出了它的能力范圍,盡管未來的技術發展很可能會突破這些限制,但是現在了解一下這些限制也沒有壞處。

● 運行深度學習模型所需的內存超出瀏覽器上隨機存儲器(RAM)和WebGL的上限。也就是說,如果在瀏覽器中進行推斷,模型的尺寸需要控制在100MB左右;訓練階段通常需要更多的內存和算力,即使模型的尺寸沒達到上限,也有可能導致訓練過程過于緩慢。通常,訓練階段所涉及的數據量要比推斷階段大,因此在評估瀏覽器內訓練可行性時,還需要考慮這個限制因素。

● 創造高端強化學習模型,比如能夠在對弈系統中擊敗人類選手。

● 使用Node.js以分布式(多機器)的方式訓練深度學習模型。

1.4 練習

無論你是JavaScript前端開發者,還是Node.js開發者,基于本章介紹的內容,頭腦風暴一些你可以應用機器學習的場景,讓正在編寫的程序更為智能,表1-1、表1-2以及1.3.3節可以為你提供一些思路。也可以思考下面幾種場景。

(1) 一些經營墨鏡等配飾的時尚網站可以通過網絡攝像頭拍攝用戶的面部圖像,并使用基于TensorFlow.js的深度神經網絡檢測面部輪廓特征,然后利用這些關鍵信息將墨鏡圖像貼附在用戶面部圖像上,用戶可以通過合成的圖像進行試戴體驗。這種體驗是相對真實的,因為借助客戶端推斷,這種試戴可以在低延遲、高幀率的情況下進行。同時由于捕獲的圖像沒有離開過瀏覽器,因此用戶的隱私數據在這一過程中得到了充分保護。

(2) 使用React Native(基于JavaScript的跨平臺原生移動端應用程序開發框架)編寫的移動端體育應用程序可以記錄用戶的鍛煉信息。利用HTML5 API,應用程序可以從手機的陀螺儀和加速度計中獲取實時數據。然后基于TensorFlow.js的模型可以通過處理這些數據,判斷用戶當前的狀態,比如休息、散步、慢跑或者沖刺。

(3) 瀏覽器插件可以通過網絡攝像頭每5秒為用戶進行拍照,然后將這些數據傳至基于TensorFlow.js的模型,自動檢測當前用戶的年齡特征,從而判斷用戶對一些網站是否有訪問權限。

(4) 基于瀏覽器的編程環境可以使用基于TensorFlow.js的循環神經網絡來檢測代碼注釋中的低級錯誤。

(5) 基于Node.js的服務器端應用程序可以提供物流查詢服務,就是根據貨物的運送狀態、類型、數量、所屬地交通狀況等實時信息來確定預計到達時間(ETA)。整個訓練和推斷流程都可以用Node.js和TensorFlow.js編寫,這樣就簡化了服務器端的技術棧。

1.5 小結

● AI是實現認知性任務自動化的研究。機器學習是AI的子領域,旨在通過學習訓練數據,自動發現圖像分類這類任務背后的規則。

● 機器學習要解決的核心問題是如何轉換數據的表示,從而更好地解決當下的問題。

● 在機器學習中,神經網絡可以通過連續的數學運算步驟(層)來轉換數據的表示。深度學習領域涉及擁有一定“深度”的神經網絡,也就是擁有很多層的神經網絡。

● 得益于硬件性能的提升、帶標簽數據的增長以及算法上的革新,深度學習領域自2010年以來取得了一系列驚人的成就,解決了很多之前難以解決的問題,還創造了很多令人興奮的新機遇。

● 與其他語言一樣,JavaScript和Web瀏覽器同樣適用于訓練和部署深度神經網絡。

● TensorFlow.js是一個全面、靈活且強大的JavaScript開源深度學習庫,也是本書的重點。

主站蜘蛛池模板: 葫芦岛市| 资中县| 得荣县| 吕梁市| 陆良县| 阿瓦提县| 沈阳市| 温州市| 醴陵市| 濮阳县| 大英县| 德化县| 建德市| 平罗县| 黄平县| 金溪县| 固阳县| 观塘区| 栖霞市| 客服| 南阳市| 扎兰屯市| 平谷区| 色达县| 武平县| 阿拉善左旗| 昌图县| 团风县| 哈巴河县| 郧西县| 察雅县| 军事| 寻乌县| 大埔县| 慈利县| 桃江县| 什邡市| 墨脱县| 甘德县| 西城区| 乐至县|