12.31 谷歌程序員帶娃開發機器人,只花了 200 美元

優質文章,第一時間送達!

谷歌程序员带娃开发机器人,只花了 200 美元

前年夏天,谷歌雲負責維護開發者關係的Kaz Sato帶著他的兒子,用一些傳感器和一個簡單的機器學習線性模型,開發了一個“猜拳機器”,能檢測石頭剪刀布的手勢。

他還根據這個過程寫了一份教程,詳細介紹了怎樣構建這個機器,以及怎樣用機器學習算法解決日常問題。

下面是教程譯文,適合有一定編程基礎的同學,需要大約200美元的硬件設備。

我們先來看一下這個機器:

上面視頻中,我們搭建的系統正在通過手套上的傳感器,藉助一個用Tensorflow編寫的簡單機器學習算法來檢測我兒子的手勢,然後選擇相應的選項:石頭、剪刀、布。

項目源代碼在此:https://github.com/kazunori279/ml-misc/tree/master/glove-sensor

具體是怎樣實現的呢?接下來我會一步一步地講。

第1步:製作手套傳感器

我們使用littleBits來構建硬件系統。這套設備對兒童很友好,包含各種各樣的組件,如LED燈、電機、開關、傳感器和控制器等,這些組件可以靠磁性鏈接,無需焊接。在這個實驗中,我們使用了三個

彎曲傳感器,將它們附在塑料手套上。

谷歌程序员带娃开发机器人,只花了 200 美元

littleBits彎曲傳感器

當你戴著手套、彎曲手指時,傳感器會輸出一個從0V到5V變化的電壓信號。為傳感器輸出加一個指示器,比如LED光柱,就能實時看到每個傳感器受到的壓力。

彎曲傳感器輸出0V-5V信號

第2步:安裝Arduino和伺服模塊

要讀取彎曲傳感器的輸出信號並控制機器的轉動幅度,我們使用了Arduino模塊和伺服模塊。Arduino模塊內部有一個微控制器芯片,且具有多個輸入和輸出端口。你可以在筆記本電腦上用Processing語言(和C語言比較像)編寫一個程序並編譯,然後通過USB線傳輸到該模塊中。

谷歌程序员带娃开发机器人,只花了 200 美元

littleBits Arduino模塊

谷歌程序员带娃开发机器人,只花了 200 美元

伺服模塊

谷歌程序员带娃开发机器人,只花了 200 美元

我兒子在畫轉盤指示圖

現在,用於構建猜拳機的所有硬件已經準確齊全,接下來,就該寫代碼了。

谷歌程序员带娃开发机器人,只花了 200 美元

猜拳機硬件部分

第3步:寫程序從彎曲傳感器讀取數據

在配置好硬件後,我們開始在Arduino模塊上編寫代碼,實現從彎曲傳感器讀取數據的功能。在Arduino的IDE中,設定為每隔0.1秒讀取傳感器數據,然後將其記錄在串行控制檯上,代碼如下。

谷歌程序员带娃开发机器人,只花了 200 美元

在Arduino IDE中編寫程序

運行這段代碼時,你會在控制檯上看到這樣的數字:

谷歌程序员带娃开发机器人,只花了 200 美元

其中,每行的三個數字表示彎曲傳感器輸出的三個數據。Arduino模塊將輸入信號電壓(0V - 5V)轉換成從0到1023變化的數字。

上圖是“石頭”手勢的數據,所有傳感器都是彎曲的。如果換成“布”的收拾,所有傳感器都不彎曲,則上圖的數據都會趨近於0。

第4步:使用Cloud Datalab可視化數據

該如何確定這三個數字的組合是代表著“石頭”、“布”還是“剪刀”?

最簡單的方法是編寫能判斷閾值和條件的IF語句。比如:

  • 當三個輸出數值都低於100時,則輸出“布”;

  • 當三個輸出數值都高於400時,則輸出“石頭”;

  • 若不滿足以上兩個條件,則輸出“剪刀”。

這個程序可能滿足當前任務的要求,但是很不靈活也不穩定。

如果我兒子要求我在手套上添加更多傳感器,來捕獲10個不同手勢,那該怎麼辦?或者,如何向緊身衣添加多個傳感器,來識別不同身體姿勢?顯然,上述程序無法處理這麼複雜的任務。

當然,主要是因為我比較懶,想編寫出更強大和更靈活的代碼,能在不改變基本設計的前提下,靈活處理善變的甲方(我兒子)可能提出的各種請求。

為了找到更好的數據處理方法,我對手套傳感器數據做了一些快速的分析。我使用的工具是Cloud Datalab,這是一個很受歡迎的Jupyter Notebook版本,並已集成到Google Cloud平臺,可提供基於雲數據分析的一站式服務。你可以在Web UI中編寫Python代碼,使用如NumPy、Scikit-learning和TensorFlow等函數庫,並將其與Google Cloud服務(如BigQuery、Cloud Dataflow和Cloud ML Engine)相結合

根據不同手勢,我把手套傳感器數據分開保存成三個CSV文件,每個文件包含800行數據。你可以在Cloud Datalab上編寫Python代碼,將它們讀取並轉換為NumPy數組,示例代碼如下:

谷歌程序员带娃开发机器人,只花了 200 美元

使用Cloud Datalab讀取CSV文件轉為NumPy數組

完整代碼:https://github.com/kazunori279/ml-misc/blob/master/glove-sensor/Rock-paper-scissors.ipynb

你也可以使用Matplotlib庫來可視化NumPy數組。下面代碼畫出了一個3D圖,其中每個軸對應著一個不同傳感器。

谷歌程序员带娃开发机器人,只花了 200 美元谷歌程序员带娃开发机器人,只花了 200 美元

用3D圖繪製傳感器數據,已縮放原始多維數據

通過觀察上面的3D圖,你可以更清楚地看到數據的空間分佈。

第5步:創建一個線性模型

接下來,我們要將這些原始傳感器數據劃分到三種不同手勢類別中。這裡會用到線性代數,你們在高中或者大學應該都學過了。

線性代數是一種可以將某個空間映射到另一空間的數學方法。例如,下面公式表示了一種從某個一維空間到另一個一維空間的線性映射。

谷歌程序员带娃开发机器人,只花了 200 美元

一元公式

其中,x和y分別為兩個一維空間中的變量,w為權重,b為偏差。利用這個公式,可以將一維空間“紐約市出租車的行駛距離”映射到另一個一維空間“出租車費用”,其中把2.5美元(每英里費用)作為權重,把3.3美元(初始費用)設置為偏差。

谷歌程序员带娃开发机器人,只花了 200 美元

“行駛距離”和“出租車費用”的映射函數

從圖中看出,權重和偏差(也叫參數)分別定義該直線的斜率和初始位置。你可以通過調整這些參數,來創建從一個一維空間到另一個一維空間的任何線性映射。

線性代數的優點在於,在從任意m維空間到任意n維空間進行線性映射時,可使用相同公式。例如,在將三維空間(x1,x2,x3)中的某個點映射到另一個三維空間(y1,y2,y3)中,均可使用以下公式。

谷歌程序员带娃开发机器人,只花了 200 美元

三維空間之間的映射函數

數學家認為上面公式寫得太冗長了,所以設計了一種更容易的表示方法:矩陣乘法。

三維映射關係也可以這麼表示:

谷歌程序员带娃开发机器人,只花了 200 美元

或者,更簡單寫成:

谷歌程序员带娃开发机器人,只花了 200 美元

其中,x和y為3維列向量,W為3×3的權重矩陣,b是3維偏置列向量。是的,它與一維空間的映射函數完全一樣。而且,該公式可應用於m維空間和n維空間之間的任何線性映射,這就是所謂的“線性模型”。

那麼,線性模型在本項目能起到什麼作用呢?我們可以利用它,將“手套傳感器數據”的3維空間轉換為“石頭剪刀布”的3維空間,如下所示:

谷歌程序员带娃开发机器人,只花了 200 美元

3維空間的動態轉換

在完成手套傳感器數據與“石頭剪刀布”3維空間的配對後,很容易寫出用於分類的IF語句,如下:

  • 當石頭方向值高於其他方向,則輸出“石頭”;

  • 當布方向值高於其他方向,則輸出“布”;

  • 當剪刀方向值高於其他方向,則輸出“剪刀”。

線性模型可以將原始輸入數據轉換到特徵空間中,在該空間中可為要捕獲的每個特徵設定不同方向,這樣更容易處理轉換後的數據。這就是為什麼我認為線性代數不僅是數據科學家的奇妙數學工具,對懶惰的程序員來說也是如此。

在輸入數據有多個維度或是有多個不同屬性時,線性模型尤為重要。

比如,當你將幾十個彎曲傳感器連接到緊身衣後,則可使用線性模型將來自傳感器的原始數據映射到用多個方向來表示不同身體姿勢的特徵空間(如站立、坐著或蹲下等),無須基於原始數據來編寫很多不穩定的IF語句。

當然,線性模型還可處理非結構化或稠密數據,以提取所需的特定特徵。這類數據的維度一般為數百個,甚至數千個,如圖像、音頻、自然語言和時間序列數據等。

但請注意,線性模型並不是萬能靈藥。

要在複雜的非結構化或稠密數據的分類任務中達到更高的正確率,可能要使用非線性模型,如神經網絡或支持向量機。這樣,你可以通過非線性變換來提取有用的特徵,這種非線性變換能以一種更靈活的方式來調整原始數據。

在剛開始處理複雜數據時,你可以先嚐試使用線性模型,如果不能提取滿足要求的所需特徵,可進一步嘗試非線性模型來獲得更好效果。

第6步:讓TensorFlow尋找參數

既然我們已經瞭解線性模型十分有用和強大,你可能想知道:

該如何確定最佳映射的參數(即權重和偏差)?

答案是:機器學習。

你可以利用機器學習,讓計算機根據測得的輸入數據來計算線性模型的最佳參數組合。利用TensorFlow能很容易地實現這些想法。在TensorFlow中,只需將線性模型的公式“y = Wx + b”公式定義為計算圖,如下:

谷歌程序员带娃开发机器人,只花了 200 美元

在上面代碼中,tf.Variable創建兩個初始化為0的變量,分別保存了3 x 3的權重矩陣和3維偏置列向量。此外,tf.placeholder創建一個佔位符,可接收任何數目的手套傳感器數據作為輸入;tf.matmul是手套傳感器數據和權重進行矩陣乘法的函數,並根據tf.matmul用法,將手套數據置於前者。

請注意,當你調用這些函數(TensorFlow中的低級API)時,不執行任何計算,只是建立一個計算圖,如下所示:

谷歌程序员带娃开发机器人,只花了 200 美元

計算圖

機器學習和TensorFlow的強大在於,可利用計算機尋找最佳參數(包括權重和偏差)。在上面例子中,我們輸入了手套的三個傳感器數據及其期望輸出(有石頭、剪刀或布)。TensorFlow可利用該數據,在圖中進行反向計算,尋找最佳的權重和偏差以得到期望的線性變換。這個過程叫做“訓練機器學習模型”。

利用機器學習,你只需設定輸入和輸出,即可利用計算機訓練得到最佳的映射函數,這就跟自動編程一樣。在21世紀,機器學習從某種程度上可看作是一種工程師的計算器。任何人都可以使用它來執行簡單任務,以減少編碼工作。

第7步:定義一個訓練“教練”

訓練線性模型時,需要一個監督“教練”。我們通過以下兩行代碼來引導模型訓練,以達到期望效果。

谷歌程序员带娃开发机器人,只花了 200 美元

rps_labels是用來接收每行手套傳感器數據標籤的佔位符,為每個手套傳感器數據按照一定格式來定義標籤,如下所示:

谷歌程序员带娃开发机器人,只花了 200 美元

其中,[1 0 0]表示石頭,[0 1 0]為布,[0 0 1]為剪刀,這叫做one-hot編碼,是在訓練分類模型中表示標籤的一種通俗方法。

在第二行,我們調用了tf.losses.softmax_cross_entropy來定義損失函數。關於softmax、交叉熵以及損失函數的詳細介紹,可參考維基百科。對於這三者,你只要瞭解以下內容:

  • Softmax能將rps_data中的數值對應壓縮到區間[0, 1],這樣可將其輸出作為石頭、布和剪刀的估計概率。

  • 交叉熵返回兩個概率分佈間的差異程度:rps_labels中的one-hot標籤(真實值)和softmax函數輸出的估計概率。

  • 損失函數是一個衡量模型實際準確程度的函數。因此,我們使用交叉熵作為損失函數。

谷歌程序员带娃开发机器人,只花了 200 美元

“交叉熵指出了實際標籤與計算概率間的差異度”

——Martin Gorner, TensorFlow and deep learning, without a PhD

在這種情況下,損失函數看作是softmax函數和交叉熵的組合體,指出當前參數在線性模型中對應的誤差值。該函數是TensorFlow中的“教練”,引導模型沿著正確方向尋找最佳參數。

順便提一下,線性模型和softmax函數的組合被叫做多元邏輯迴歸(multinomial logistic regression),或是softmax迴歸,這是在統計學和機器學習中一種常用的分類算法。

第8步:訓練線性模型

接下來,我們準備在TensorFlow中加入優化器來訓練模型。

谷歌程序员带娃开发机器人,只花了 200 美元

tf.train.GradientDescentOptimizer是TensorFlow中一種常用的優化器,通過梯度下降算法調整參數,來最小化損失函數返回的誤差。

在實際訓練中,你需要創建一個會話(Session)並將手套傳感器數據和標籤傳給優化器。由於優化器會以指定的學習速率逐漸地更改參數值,因此可能要運行多達數千次。觀察訓練過程中的損失值,你可以發現它在逐漸減小,這意味著模型的錯誤率越來越低。

谷歌程序员带娃开发机器人,只花了 200 美元

在訓練結束後,你將獲取一系列訓練好的權重和偏差,可利用softmax概率將手套傳感器數據映射到相應決策空間。在原始手套傳感器空間中繪製softmax概率分佈,如下所示。

谷歌程序员带娃开发机器人,只花了 200 美元

石頭、布和剪刀的估計概率分佈

第9步:在Arduino上運用線性模型

我們已經得到了一種能分類手套傳感器數據的實用方法,接下來完成對Arduino的編碼。

在Datalab上運行sess.run(weights),可輸出訓練好的權重值。複製這些權重值並寫入Arduino代碼中,對偏置也進行以下操作。

谷歌程序员带娃开发机器人,只花了 200 美元

最後,利用Arduino中的線性模型,可將手套傳感器數據映射到決策空間。你可以用下面的Arduino代碼來實現數據、權重和偏差間的矩陣乘法計算。

谷歌程序员带娃开发机器人,只花了 200 美元

然後,比較這些值並找到最大值。一旦確定了手套表示的手勢,Servo就可以正確控制機器手並贏得比賽。在這個例子中,你不需要計算出softmax值,只需比較下線性變換的三個輸出值,其中這三個值分別對應著石頭、布和剪刀。

谷歌程序员带娃开发机器人,只花了 200 美元

到這裡已經完成了,你可以使用機器學習來創建專屬於你的石頭布剪刀機器。

下一步計劃

正如這篇文章中提到的,線性模型是一個強大的工具,可以通過線性變換將任意的m維空間映射到n維空間。如果你覺得編寫多個if語句來校驗複雜條件下的原始輸入數據過於乏味,可以考慮這種工具。與直接處理原始數據不同,在處理能映射到特徵空間中的數據時,這種方法更為簡單。在這篇文章中,特徵空間指的是石頭、布和剪刀的決策空間。

這裡用到的關鍵技術是機器學習和TensorFlow,在構建線性模型可幫助你找到最佳參數。這些技術不僅只是針對深度學習和人工智能的工具,也可用於為各種編程任務構建出一個強大且靈活的代碼。

原文地址:https://cloud.google.com/blog/big-data/2017/10/my-summer-project-a-rock-paper-scissors-machine-built-on-tensorflow


分享到:


相關文章: