數學不行還學AI-第4話-圖解張量(內有惡貓)
原文: Learning AI if You Suck at Math?—?P4?—?Tensors Illustrated (with Cats!)
在線運行代碼版:數學不行還學AI-第4話-圖解張量(內有惡貓) - 集智專欄
作者:Daniel Jeffries
翻譯/注釋:Kaiser(王司圖)
前言
昨天翻譯了一篇用Keras識別AV女優的文章,雖然反響很熱烈,但是很多朋友反映看不懂。其實那篇文章自身就不是特別完備,只是提供個大概思路,並不能逐步復現。所以今天來一篇相對簡單、通俗的。
讀者朋友們可能奇怪,為什麼一上來就是「第4話」。 這是一個連載中的系列文章,題為Learning AI if You Suck at Math,一聽就很喪。北郵陳老師(愛可可-愛生活)翻譯為「數學菜鳥的AI學習攻略」,這太正能量了不夠喪。所以我翻譯為「數學不行還學AI」。
此處的「還」字語氣應模仿周星馳在《功夫》里的「還踢球!」。
原作者Daniel Jeffries是一位科幻作家,他的新書見下圖微博中我的評論,為防「政治敏感」罪名,我就不翻譯了(當然,在我自己的網站上,我翻譯了)。看他寫作的風格(可以說是魔幻了)就可以理解,為什麼文章標題一定要翻譯的喪。
本系列的前三篇沒有翻譯的原因是這樣的:
第一篇:Learning AI if You Suck at Math 抒情居多,後面推薦了幾本數學方面的書籍。感興趣的朋友可以點擊原文查看,因為推薦的都是英文書,所以翻譯過來也沒有太大價值。
第二篇:Learning AI if You Suck at Math?—?Part Two?—?Practical Projects ,作家就是作家,仍然是抒情成分居多,然後介紹了一下Kaggle競賽以及Keras+TensorFlow框架。
第三篇:Learning AI if You Suck at Math?—?P3?—?Building an AI Dream Machine or Budget Friendly Special,終於不抒情了,這是一篇攢機和開發環境配置的攻略。硬體方面,作者的推薦與我國國情有一定偏差。開發環境配置方面,我已經在集智的後台做好了,讀者可以直接在網頁上運行Python代碼,免除了最麻煩的部分。
不管是知乎還是StackOverflow,幾乎所有編程版塊的問題,都有一大半是關於安裝、配置的。而雲計算已經很普及,實在想在本地搭建也可以用docker解決,我覺得沒有必要在繁瑣的配置上浪費太多時間。
以上三篇可以說是撩撥的前戲,本篇《圖解張量(內有惡貓!)》終於直奔主題頂到了花心。
正文
可能你已經下載TensorFlow並且準備好開始深度學習了。
但你可能會問:什麼他媽的叫他媽的Tensor? (What the hell is a tensor?)
或許你已經看過了維基百科頁面 ,然後你更加迷茫了。又可能你看過了了這個NASA tutorial但還是不知道這說了些什麼? 你像陳綺貞老師,收集書本里每一句你最愛的真理。
問題的關鍵在於,大多數教程在談及Tensor的時候,都預設你已經懂得了所有描述性的數學語言。
不要怕!
我想很多孩子一樣討厭數學,所以要是連我都能能懂,那你也可以!我們只需要用最簡單的方式來解釋一切。
所以到底什麼他媽的叫他媽的Tensor,它又怎麼就Flow了?
Tensors = Containers(張量是個筐)
張量(tensor)是現代機器學習的最基礎元素。
本質上來講,張量就是個數據容器。多數情況下盛的是數字,有時也會盛字元但比較少。
所以不妨把它想像成一筐數字 。(So think of it as a bucket of numbers. bucket原意是「桶」,但中文還是「筐」用的比較多。比如「國情是個筐」,而沒有說「國情是個桶」的。)
張量就像避孕套,有不同的型號(這個比喻是Kaiser自創的)。來一起認識一下你在深度學習中將會遇到的基本款——0維到5維。
我們可以把這些張量做如下可視化(貓??在後面!)
0維張量/標量
張量這個筐里的一個數字就叫標量(scalar)。
一個標量就是一個數字。
你可能會問,為什麼不直接叫數字?
我也不知道,可能數學家們覺得這樣挺起來比較屌?(並沒有)
實際上你可以擁有隻含一個數字的張量,這就是0維張量,好比一個筐里只有一滴水(已經好過「竹籃子打水一場空」了)。
在本教程中我們將使用Python, Keras和TensorFlow以及NumPy,這些環境已經在集智中搭建好了。
在Python中,張量一般表示為Numpy數組。 NumPy 是一個科學計算庫, 你球基本上所有AI框架都用到了NumPy。
在數據科學競賽網站Kaggle上,你經常可以看到Jupyter Notebooks(本站的在線開發環境也是基於Jupyter Notebooks)提到把數據轉換為Numpy數組。Jupyter Notebook集成了文檔與代碼功能,融講解和編程於一體。為什麼要把數據轉換為Numpy數組?
很簡單,因為我們需要應對各種各樣的輸入數據——字元、圖像、股價或者視頻——整合到一個標準下。這種情況下,我們把數據塞進「數字筐」(張量)里,才能通過TensorFlow操縱它們。其實就是把數據組織成一種可用的格式。在網路編程中,你可能用XML來呈現(微信就是),所以你可以快捷地定義和操縱數據。同樣的,深度學習中我們使用張量這個筐來作為樂高里最小的零件。1維張量/矢量
如果你是程序員,那你應該已經知道一種跟1維張量很接近的東西:數組。
每個編程語言都有數組,其實就是一行或一列數據。在深度學習中稱作1維張量,張量可以根據軸的數量來定義,1維張量就只有一個數軸。
1維張量是矢量(vector)。
我們可以把矢量可視化為一行或一列數字。
如果想在Numpy中查看,可執行如下操作:
也可以用Numpy的ndim輸出張量的維數。
2維張量
你大概已經想到了另一種張量:矩陣
2維向量是矩陣(matrix)。
不,不是基努里維斯那個電影,是類似Excel表格的這樣一個數據結構。
我們可以將其可視化為有行/列的數字網格。
行和列代表了兩個軸,矩陣是2維張量。在NumPy中我們可以如此表示:
我們可以把人物屬性存儲為2維張量。比如一個典型的郵件列表就很適用。
假設我們有10000個人,並且每個人又具有這些屬性:
- 姓
- 名
- 街道
- 市
- 省
- 國家
- 郵編
張量是有「形狀」的,「形狀」適合數據維度且定義了張量最大尺寸,我們可以把人物屬性放入一
個形狀為(10000, 7)的2維張量當中。
你可能想說這個張量有10000列和7行。
やめて。
張量的行與列之間是可以相互轉換的(所以不存在具體的「行」與「列」的定義)。
3維張量
其實到了3維,才是「張量」這個概念真正凸顯的時候。我們經常需要把2維張量再裝進另一個筐里,這就是3維張量。
在Numpy中,可以這樣表示:
以上面的郵件列表為例。假設現在有10個郵件列表,我們可以把2維張量存至另一個筐,構成3維張量。形狀如下:
(number_of_mailing_lists, number_of_people, number_of_characteristics_per_person)nn(10,10000,7)n
你可能已經猜到了, 3維張量是數字立方。
我們可以繼續堆砌立方體來構建越來越大的張量,以表現4維,5維乃至N維的張量。
實際上3維張量可以更好地用層級網格來表示:
常見張量型數據
有幾類常見的數據類型是以張量形式存儲的:
- 3D = 時間序列
- 4D = 圖像
- 5D = 視頻
一條貫穿所有這些張量的線索就是「樣本數量」。樣本數量就是數據集里的數據個數,可以是圖片的張數,視頻的段數,文件的份數或是微博的條數。
一般實際的數據維數都會比樣本數量小。
rest_of_dimensions - sample_size = actual_dimensions_of_datan
考慮到不同維數下的形狀(以不同的維度代表),我們要尋找能夠描述數據的最少維度。
所以4維張量通常存儲圖像,因為樣本數量就是張量的第4個維度。
比如一張圖片可以用3個維度來表徵:
(width, height, color_depth) = 3Dn
但在機器學習中,我們一般不是只跟單張圖片或單份文件打交道,而是一個數據集。我們可能有10000張鬱金香的照片,這就是一個4維張量:
(sample_size, width, height, color_depth) = 4Dn
下面來看幾個不同維度張量的例子。
時序數據
3維張量對於時序數據很有效。
醫學影像
我們可以把腦電波EEG信號編碼為3維張量,因為它可以用3個參數指代:
(time, frequency, channel)n
轉換過程大致如下:
現在如果我們有很多病人掃描了腦電波,那就變成個4維張量了。(sample_size, time, frequency, channel)n
股價
股價每分鐘都有高有低,有最終價。紐交所從上午9:30開到下午4:00,共計6個半小時,390分鐘。 股價的變化一般用K線圖表示:
我們可以把每分鐘的高價,低價,最終價存為2維張量。如果抓取一星期(5個交易日),就是3維張量,形狀如下:
(week_of_data, minutes, high_low_price)nn(5,390,3)n
如果有10支股票,則變成4維張量:
(10,5,390,3)n
假設現在有個互惠基金,由若干支股票組成,以4維張量形式表徵。我們可以持有25支互惠基金作為投資組合,於是就有一系列4維張量,等價於5維張量:
(25,10,5,390,3)n
文本數據
文本數據也可以存為3維張量,以Twitter為例。
Tweets由140字組成,基於UTF-8標準,可以呈現上百萬字,但實際上我們只對前128個感興趣,與ASCII編碼是一樣的。單條tweet可以裝載進一個(140,128)的2維矢量。
假如我們下載了100萬條Trump的tweets(我覺得他一個禮拜就發夠了。註:此條吐槽為原文),可以存為3維張量。(number_of_tweets_captured, tweet, character)nn(1000000,140,128)n
圖像
4維張量很適合存儲一系列圖像(如Jpeg格式)。如前所述,一張圖片可以存為三個參數:
- 寬
- 高
- 色彩深度
單張圖片是3維的,一系列圖片就是4維的了,第4維就是sample_size。
著名的MNIST數據集就是一系列手寫數字,曾經是困擾眾多數據科學家的難題,今天已經基本上是玩兒透了,機器已經能夠達到99%甚至更高的精度(單層CNN就差不多了)。 但是這個數據集仍然發揮著餘熱,就是用作新機器學習應用的樣板,或者練手的素材。
Keras甚至集成了MNIST數據集,只需要簡單的命令就可以導入。
from keras.datasets import mnistnn(train_images, train_labels), (test_images, test_labels) = mnist.load_data()n
數據集被分為兩份:
- 訓練集
- 測試集
每個圖片都有一個標籤,即該圖的真實數字,比如3,7或是9,這些標籤時人工手動添加的。
訓練集用來教會神經網路,測試集則是神經網路學習後試圖分類的目標。
MNIST都是灰度圖像,也就是說可以編碼為2維張量,但是所有圖片還是依照慣例編碼為3維張量,第三個軸代表色彩深度。
MNIST數據集中有60000張圖片,每張長寬皆為28像素,色彩深度為1,即灰度圖片。
TensorFlow是這樣存儲圖片的(與Theano格式有所不同):
(sample_size, height, width, color_depth).n
彩圖
彩色照片有著不同的色彩深度,這取決於解析度和編碼格式。典型的JPG圖像用RGB編碼,所以色彩深度為3,分別代表紅、綠、藍。
這是我家貓Dove的照片,解析度為750x750,這意味著我們會有個3維張量:
(750,750,3)n
假設我們有一堆各種貓的圖片(儘管他們都沒有Dove漂亮。註:原作者看來是個貓奴)。比如10000張別家貓的750x750照片。在Keras中,就這樣定義為4維張量:
(10000,750,750,3)n
5維張量
5維張量可以存視頻數據。在TensorFlow中視頻數據的編碼形式如下:
sample_size, frames, width, height, color_depth)n
一個5分鐘的視頻(300秒),1080p高清(1920x1080像素),每秒15個關鍵幀,色彩深度3,這是一個4維張量:
(4500,1920,1080,3)n
張量的第五個維度是視頻集中的視頻個數。所以如果有10個視頻,就有5維張量:
(10,4500,1920,1080,3)n
這個例子其實很瘋狂。
張量的體積可以大的不可思議, 超過1TB。在現實世界中,我們想要儘可能地下採樣視頻,否則模型可能永遠都訓練不完。
5維張量的值的個數為:
10 x 4500 x 1920 x 1080 x 3 = 279,936,000,000n
Keras允許使用32位或64位的浮點數(dtype):
float32nfloat64n
每個值都是一個32位的數字,這就意味著我們要把值的個數在撐32,轉換為比特數,再轉換為TB:
279,936,000,000 x 32 = 8,957,952,000,000n
我不覺得這適用於32位系統(我會再找人算算),所以還是需要下採樣。
實際上我用這個瘋狂的例子,是為了引出預處理和數據縮減。
你不能直接就把原始數據扔進AI模型中,你需要整理、壓縮數據使其更易於處理。
降低解析度、刪減冗餘數據、限制幀數等,這也是數據科學家的任務之一。
如果你不能把數據玩兒壞,那麼你也不能把它玩兒好。
結語
現在你應該對張量及相關的數據類型有了更好的理解。
再下一篇中,我們將學習如何用數學方法對張量進行變形。
換言之,我們要讓Tensor "flow" 起來。
推薦閱讀:
※Python數據分析之anaconda安裝和使用
※在Windows與MAC中同時安裝Python3.X與2.X的方法
※關於Python中參數傳遞和作用域的問題?
※Day 4-6, 列印、文件、函數
※如何用python解析json對象(基礎篇)