Image for post
Image for post
Photo by Corinne Kutz on Unsplash

如果你在學機器學習,應該會聽過「邏輯斯迴歸」。邏輯斯迴歸是個好用的分類器演算法,而想在 scikit-learn 中匯入、訓練和使用它也相當簡單。然而,邏輯斯迴歸是如何分類資料的,就需要一點技巧來解釋了。

很多人會從數學式子切入,但對如在下我這種數學不好的人來說,抽象的方程式永遠非常難懂。而有些書或網站會附上邏輯斯函數的圖表,但它們通常跟後面的程式範例沒有直接關係(此外這些書或網站經常也只是抄襲其他人的範例)。最後,已嚴然成為 Python 機器學習代名詞的 scikit-learn 儘管在其網站上有很多視覺化範例,但它們大多極其複雜,要拿來應用實在是有難度。

而這就是這篇文章的出發點:記錄我對於 scikit-learn 幾種模型之視覺化的簡單研究成果。將機器學習模型視覺化,對於教學其實有很大的好處 — — 這能讓人們從更直覺的方式來理解模型是如何分類資料,而不必只能從抽象的數學式子去想像,還能跟資料產生連結。此外,我也需要找個地方來記錄這些程式碼,以後就不必花時間重寫了。

我會稍微解釋一下某些東西,但這畢竟不是新手教學文,我仍假設你對其他套件(NumPy, matplotlib 等)有些基礎概念。

Image for post
Image for post
Photo by Glenn Carstens-Peters on Unsplash

準備(以及釐清)資料

首先,我們自然需要資料。而為了能夠在二維平面上繪圖,這個資料必須只有 2 個特徵(自變數)和 2 個標籤(分類)。然而,我並不想用 scikit-learn 的隨機資料產生功能(例如 make_blobs() 或 make_moons())。

剛好,scikit-learn 內建的乳癌資料集雖有 30 個特徵,但實際用 PCA(principal component analysis,主成分分析)來篩選後,可發現變異度最大的 2 個就能解釋原資料的 99.8% 變異:


Image for post
Image for post
Photo by Andrew Le on Unsplash

The sole goal of this is to use (or abuse) one new feature comes with Python 3.9: Relaxing Grammar Restrictions On Decorators (PEP 614). Since almost no one mentioned about it before, I decided to write a little article here.

Of course, the way I use it is very probably not “Pythonic”, and maybe shouldn’t be used at all in your work, but we can still have some fun here, right?

Apparently, PEP 614 is mainly designed for PyQt5, which you can attach a button clicking method as a decorator to another function to create button events. But the PEP also says “The decision to allow any valid expression”. …


Image for post
Image for post
Photo by Austin Neill on Unsplash

前陣子筆者買了本書 TinyML,這本書是講如何在(特定的,咳咳)開發板上佈署 Tensorflow Lite 神經網路模型。我個人雖然對 Tensorflow 幾乎一竅不通,但對於如何在微控制器或開發板應用它,倒是相當有興趣。

(其實廣義來說,TinyML 可以泛指將機器學習用在微控制器的領域。不過,這邊主要以 Tensorflow Lite 為主。)

不過讀一讀就發現就發現,佈署模型的過程似乎相當繁雜,且並不是在 Windows 環境下進行,對筆者這樣的初學者來說實在不友善。此外,若打開 Arduino IDE 內的 Tensorflow 範例,一口氣就跳出 8 個檔案,程式碼也密密麻麻的,看了真教人心驚驚。

這就好像有人介紹給你一個很酷的東西,結果講到重要的實作細節,你就卡住難以前進了,有苦難言。想要玩 TinyML,真的得這麼痛苦嗎?

Image for post
Image for post
Photo by Annie Spratt on Unsplash

結果,當我在 Arduino IDE 的函式庫裡亂搜尋時,意外找到一個叫做 EloquentTinyML 的函示庫。一看它的範例不得了,就只有一個主程式檔和記錄模型的 header 檔而已,後者以陣列形式記錄了產生好的模型。

然後,我在網路上也找到了別人寫的程式,可以把訓練出來的 Tenworflow Lite 模型直接轉成 C++ 文字格式,不需要再很麻煩的去系統命令列用 xxd 轉換它。這麼一來,想把模型上傳到開發板的過程,突然就簡化很多了。

因此,下面我們就來看看你怎麼用 EloquentTinyML 讓你的人生變得更加好過。請注意筆者自己也是 Tensorflow 超級菜鳥,因此下面很多東西就沒法多加解釋囉。

訓練 Tensorflow 模型

當然,神經網路是比較複雜的玩意,第一步必定是從你的電腦上開始訓練。正如 TinyML 書上的第一個範例,下面的模型的原始資料只是用三角函數來產生、然後加些隨機噪訊而已。筆者做了點變化,目標值是 sin(x) 和 con(x) 相乘的結果,並稍微加大噪訊:

你的 Python 環境必須為 64 位元並有安裝 Tensorflow 2.0 以上版本,外加 NumPy 及 scikit-learn 等。留意 Tensorflow 只能使用特定的 NumPy 版本。

此外,TF Lite 的功能可能沒有標準 Tensorflow 完整,例如激勵函數只有 ReLU,ReLU6 和…


Image for post
Image for post
Photo by fabio on Unsplash

筆者是個坦白說數學不怎麼樣,也沒什麼興致做純學術研究的人。不過,在大約三個月前,網路上有人分享一個叫做 SEFR 的演算法,由伊朗塔比阿特莫達勒斯大學和美國波士頓大學的研究者提出。該演算法的設計對象居然是 Arduino Uno 這類低耗能嵌入式裝置,而且可直接在開發板上進行模型訓練 — — 可想而知,這讓筆者相當感興趣。最近剛好有些時間,便決定來鑽研一下。

你可在此閱讀這篇論文:SEFR: A Fast Linear-Time Classifier for Ultra-Low Power Devices

SEFR 名稱其實來自自 2012 的一篇論文 A semi-supervised feature ranking method with ensemble learning(使用集成學習的半監督式特徵選取)。不過,感覺跟現在的演算法沒啥關係就是。以下提到的 SEFR 都是以新論文的內容為主。

正如論文所說,在開發板上使用機器學習分類器,最大的挑戰是訓練及預測時間:有些諸如 KNN(K 近鄰)這類演算法完全不需訓練,但預測時非常耗時;Naïve Bayes(單純貝氏分類器)只適合特徵完全獨立的資料;而 SVM(支援向量機)這類強大的演算法不僅耗時,對小樣本的效果也較差。

此外,目前設計來在開發板跑機器學習模型的工具並不多,最著名的大概是 TinyML(即 Tensorflow Lite),在電腦訓練模型後上載到開發板上使用,而這個過程相當繁雜。除此以外,筆者唯一一個看過能在開發板上進行「訓練」的,就只有一個 KNN 顏色識別應用而已。

現在,SEFR 也許可提供我們另一個選擇 — — 讓我們以簡單許多的方式,在低耗能裝置上直接訓練並使用分類器模型。

不過有個問題:論文提出的 SEFR 是個二元分類器。意即,它只能用來預測 label 為正或負的資料而已。不過論文結尾也說,這個原理可套用到多元預測上。因此,筆者在這篇試圖做的事,就是拿網路上的既有程式碼改寫一個多元分類器版本出來 — — 首先用 Python 實作,並檢視其運作效率,接著將這個多元模型連同資料移植到 Arduino Uno 與其他開發板上,證明它的可行性。

SEFR 如何預測分類

Image for post
Image for post
Photo by Clem Onojeghuo on Unsplash

即使和 KNN 相比,SEFR…


Image for post
Image for post
Photo by Lorenzo Herrera on Unsplash

MakeCode 編輯器是微軟投身程式教育領域所打造出來的一系列圖形編輯器 — — 它們的主要語言為 TypeScript(相容 JavaScript),但透過特殊方式將之轉換成可拖拉和拼接的「積木」(這源自 Google 的 Blockly,在早期時兩者風格是一樣的)。這些編輯器可在網頁上開啟,編譯後下載的程式檔可下載到支援的硬體上。

除了搭配 BBC micro:bit 的最知名、最積極發展的版本外,MakeCode 還有提供給 Adafruit Circuit Playground、Lego Mindstorm EV3、Minecraft 之類的對象。不過,近年來有另一個 MakeCode 編輯器開始獲得更多注意,並逐漸出現在坊間的兒童程式課程裡 — — 以打造復古風遊戲為主軸的 MakeCode Arcade

Image for post
Image for post
https://arcade.makecode.com/


Image for post
Image for post
Photo by Nong Vang on Unsplash

好吧,這篇其實跟工作有一點點關係,但關係不大。但是既然已經做了些研究,不如把心得整理一下。

說實在,網路上(包括 Medium 這兒)已經有太多太多關於各種套件跟機器學習的文章。然而身為一個入門者,筆者更關心的是 KMeans 能拿來做什麼?很多文章跟書籍並沒有明確展示這個部分,只將技術交代交代後就收工。許多 Python 資料科學套件已經夠難搞懂其 API 了,而如何將 scikit-learn 應用到真實世界,更是一直有著難以跨越的斷層。

Image for post
Image for post
Photo by engin akyurt on Unsplash

就筆者目前的理解,KMeans 的用途是在分組/分群狀況不明的資料中找出 K 個類型,並藉此給資料加上 labels(目標值標籤),以便用於其他預測模型做分類。

當然,也有可能你已經知道、或者並不關心目標值的數量,而是要用 KMeans 來把資料中近似的部分簡化成同一類。換言之,KMeans 能像 PCA 一樣當成「降維」工具。在後面我們會看到,你能利用這點來壓縮圖片。

所以,本篇與其像別人一樣鉅細靡遺的介紹 KMeans,筆者想做的是用程式示範一下(至少是就我所知)它能做些什麼事,從視覺上看來又是什麼樣子。這也算是一個實驗和記錄。

我假設你對 matplotlib 和 pandas 等套件有粗淺了解 — — 粗淺就夠了,畢竟我也只懂這樣。

先來看第一個例子:


Image for post
Image for post
Photo by Ramiro Mendes on Unsplash

120 底片,相較於更便宜也更容易使用的 135 底片,總帶有一股更古老又崇高的氣息。這麼說或許也並非毫無根據,畢竟它起源自柯達公司 1901 年開發的 Brownie No. 2 傻瓜相機。差不多 120 年過去了,120 底片依然有在生產。此外,也許是因為它(以及使用它的相機)更貴、更難使用、犯錯的代價更高,用起來更讓人戰戰兢兢。

我從 2014 年開始重新拍底片(相較於那些從未接觸過底片的千禧年世代,我直到高中還在用即可拍拋棄式底片機),然後在 2015 年才買了第一台中片幅相機。

Image for post
Image for post
我的中片幅相機們:以 Polaroid SX-70 Sonar 與 Impossible Project 黑白底片拍攝

這四年來拍中片幅的次數雖然沒有 135 多,但仍留下了不少作品。我的底片都是在家附近的老相館沖洗和掃描的,但最後幾次老闆做得有點隨意,框沒對齊、白平衡也常怪怪的,所以那時砸錢買了一台 Epson V600 自己掃看看。

總之,今年稍早得知那間相館關門了,得換地方洗底片了。新相館其實掃描品質好太多了,只是要跑遠一點而已。既然如此,就藉著這個機會,把過去的底片用 V600 重掃吧,順便將底片重新整理一下,只有最喜歡的才保留和重掃。

本篇放的便是這四年來的精華,算是一個回顧。

Yashica Mat-124G (1970, 6x6)

這是我的第一台中片幅相機。買它的最主要理由,就是因為它有測光表。後來才知道測光表完好的機型不多哩。不過算是誤打誤撞,這台仿 Rolleiflex 的相機本身也蠻有名氣的。只可惜 Bay 1 接環遮光罩太貴了,一直買不下手。

但我這台的測光表電池有點接觸不良,且最大的問題是捲片距離不時會出包(裡面用一個轉輪來測量轉到下一張底片的距離)造成疊片,而且 TLR(雙眼相機)的快門位置又很不好按,必須非常努力穩住機身。最後則是有次發現鏡頭起霧,送去清理後拍照的銳利度就下降了,抗耀光的效果也很差,後來便很少再用。儘管如此,此機還是替我留下不少珍貴回憶。

Image for post
Image for post
Image for post
Image for post
寶藏巖
Image for post
Image for post
寶藏巖
Image for post
Image for post
猴硐煤礦博物館園區
Image for post
Image for post
猴硐
Image for post
Image for post
工地
Image for post
Image for post
有次在板橋辦的老相機展
Image for post
Image for post
松菸
Image for post
Image for post
內灣線合興車站
Image for post
Image for post
野柳
Image for post
Image for post
苗栗鐵道文物展示館
Image for post
Image for post
彰化扇形車庫
Image for post
Image for post
彰化扇形車庫
Image for post
Image for post
彰化扇形車庫

Zeiss Ikon Ikonta 520/2 (1929, 6x9)

從捷克籍的叔叔手上借來的寶物,是他爺爺傳給他的超古老德製相機,表妹來台灣念書時把它帶來借我。

從機身序號可確認生產於 1929 年,也就是此機型生產的第一年。可想而知,當我發現這台使用 120 底片時有多興奮了吧。當然一開始機身嚴重漏光,鏡頭也有點髒,但整理過後(我在機身內側周圍貼了很多電工膠帶)就能正常使用了。測光部分,我則是靠一個手機 app,大致上還蠻準的。

這台相機有個豐富的歷史意義,但構造上極其簡單,只能人工判斷距離,連取景窗都很簡略,所以用起來反而相當困難。後來在表妹返國時把相機還給他們了,希望他們能繼續好好的當成傳家寶留下去啊。

Image for post
Image for post
Image for post
Image for post
寶藏巖
Image for post
Image for post
華山文創園區
Image for post
Image for post
彰化扇形車庫
Image for post
Image for post
彰化扇形車庫

VEB Zeiss Ikon Ercona (1948, 6x9)

在把 Ikonta 520/2 還回去後,偶然在市集看到很便宜的這台,買來算是半收藏用,根據序號可能產自 1950 年代初。此乃戰後東德拿戰前 Ikonta 521/2 來重新生產的版本,所以等於是 520/2 的後繼機。此機用起來跟 520/2 幾乎一樣難用,但鏡頭規格跟機身的整潔度卻是神奇的少見。有時賣家不識貨,也是一種可利用的好處。

這台比較好一點的是有可彈出的機身觀景窗,此外觀景窗跟機身都有切到 6x6 格式的功能,只是我沒有 6x6 檔板,大概得自己用黑色厚紙板做吧。

當然正因不太好用(比如沒有可靠的對焦方式,且也很容易手晃),所以用的次數極少。

Image for post
Image for post
Image for post
Image for post
淡水漁人碼頭
Image for post
Image for post
淡水漁人碼頭
Image for post
Image for post
瑞芳車站。這其實是在 2020 年拍的,不過就湊一下吧!
Image for post
Image for post
八斗子車站。同上,攝於 2020 年

Mamiya Six IV (1947, 6x6)

在確認 Yashica Mat-124G 有疊片問題且修了幾次都無法解決後,我就開始尋找下一台主力 120 相機,那時本想找用純手動方式過片(靠背後小紅窗對齊數字的方式)的機種。結果在買 Mat-124G 的那家店(同時也是相機修理店)裡找到這台剛上架的,感覺很適合就帶回家了。

不太確定生產時間,但既然機身沒有「日本占領區」(1952 年結束)的字樣,所以可能產自 1952 或 53 年。它最大的特色是藉由移動底片框本身而不是鏡頭來對焦。據我所知,唯一另一個使用機背對焦方式的就只有 Contax AX 了吧。

這系列有很多型號,有的能在 6x4.5 跟 6x6 格式切換,我這台只有 6x6。不過,這台倒是有自動計算捲片距離的功能(用捲片軸的轉動距離而不是底片本身),因此只要上片時在小紅窗對到第一張,後面的就可以直接捲了。由於捲片和鏡頭快門上弦是分離的,所以機身還內建了警告重曝用的小紅旗。

這台現在是我的主要用機,手持很穩、RF 對焦方便而且一樣能計算過片距離,但方式比 Mat-124G 可靠許多。上頭的 Olympus 鏡頭散景有點不好看,但整體上蠻銳利的,75mm 相當於 135 的 40mm,是個相當實用的焦段。此外只要記住上片跟過片的順序,就不太會遇到意外重曝的問題了。

Image for post
Image for post
Image for post
Image for post
台北動物園。這台已經拖走了。
Image for post
Image for post
台北動物園
Image for post
Image for post
艋舺龍山寺
Image for post
Image for post
艋舺龍山寺
Image for post
Image for post
象山。這張就是有背紙轉印的痕跡,有些還可以看到背紙的數字。這就是為何你得把沒拍的底片冰在冰箱裡。
Image for post
Image for post
寶藏巖
Image for post
Image for post
寶藏巖
Image for post
Image for post
華山文創園區旁高架橋下的滑板場
Image for post
Image for post
內湖內溝溪
Image for post
Image for post
內湖內溝溪,名叫ビール(啤酒)的狗狗
Image for post
Image for post
福壽山
Image for post
Image for post
福壽山
Image for post
Image for post
圓山兒童樂園遺跡
Image for post
Image for post
圓山兒童樂園遺跡
Image for post
Image for post
平溪線的嶺腳
Image for post
Image for post
嶺腳
Image for post
Image for post
十分瀑布旁
Image for post
Image for post
十分瀑布旁

花了一兩星期重掃底片,接下來就看之後什麼時候有精神來整理更龐大的 135 底片了。

說起來 V600 的自動掃描效果大致蠻不錯的,雖然偶爾還是得照自己的喜好修一下對比度。其實幾年前還曾帶著 Mamiya Six IV 去日本九州拍櫻花哩,但這就等下次有機會再分享了。

我用的 120 底片幾乎是 Kodak Ektar 100,沒別的理由,就因它最便宜。但 2020 年因新冠肺炎疫情,底片的價格在台灣水漲船高,便宜款的底片也大多斷貨。前陣子終於開始重新出門走走,把冰箱裡的最後兩捲底片用掉了,但不曉得下次再買會是什麼時候呢?

Image for post
Image for post
攝於台灣疫情高峰那段時間…在家裡待了很久沒出門。

Image for post
Image for post
Photo by sergio souza on Unsplash

ESP-01 這塊極其迷你的 ESP8266 開發板,曾經風靡一時,因為它讓 Arduino Uno 這類簡單的開發板突然多了能連上網路的能力。事實上,這種使用外部 WiFi 晶片的架構仍沿用在許多產品中,例如 Arduino MKR 1010 和 Nano 33 IoT,或是設計給 Arduino 的 ESP 擴充板。

ESP-01(以及記憶體加大的 ESP-01S)出廠時會安裝安可信(Espressif)的 AT 韌體,這韌體讓外部裝置能以序列埠指令(或 AT 指令)來控制此模組的行為,如連上 WiFi、傳送資料等等。

Image for post
Image for post

但問題就在於,ESP-01 模組的接線和供電有點麻煩,想燒錄新韌體就更麻煩了。此外,若想在電腦上用終端機監看 ESP-01 的回應訊息,不僅得買個 USB 轉 TTL 模組,接線複雜度也會進一步增加。對初學者而言,光是對硬體除錯可能就把耐心磨光了。

Image for post
Image for post
外接 ESP-01 模組的方式(包含外部電源,但不含除錯用的 USB-TTL 模組)

相較之下,直接使用正規 ESP8266 開發板(如 NodeMCU 或 WeMos D1 mini)來做 IoT 專案不僅夠便宜,也有 Arduino C++ 或 MicroPython 語言可選。可是回過頭來,BBC micro:bit 這類板子還是很麻煩,因為它非得倚賴外部 WiFi 晶片不可 — — 若不是外接一個 ESP-01,就是去購買某些廠商推出的 ESP-01 擴充板。

筆者以前曾針對 BBC micro:bit 和 ESP-01 模組寫過一些 IoT 應用,近來發現越來越多人詢問,但對於對方遇到的軟硬體問題總是愛莫能助。ESP-01 用起來就是麻煩,軟硬體會出錯的地方多得是,若沒有實際監看其序列埠回應,大概也很難判斷問題究竟在哪。

有鑑於此,筆者在這系列文章提出一個新解法──使用全尺寸、已經內建有 USB 介面晶片的 ESP8266 開發板來燒錄 AT 韌體,並把它當成其他開發板的外部 WiFi 晶片。這麼做有以下好處:

  1. 現在 ESP8266 開發板容易取得且仍相對便宜;
  2. 接線和供電只要 1 至 2 條 USB 線和 3 條杜邦線;
  3. 如果 ESP8266 的 USB 線接在電腦上的話,還可順便監看 ESP8266 AT 韌體的回應。

只要安裝好 AT 韌體,這塊板子也能重複使用。當然由於 AT…


Image for post
Image for post
Photo by Yasmine Arfaoui on Unsplash

2013 年,澳洲程式設計師兼物理學家 Damien George 靠集資推出了 MicroPython,以及第一個用來跑這種嵌入式系統語言的 PyBoard。簡單地說,MicroPython 是 Python 3.4 的瘦身版,它擁有自己的 Python 直譯器,在保留絕大部分Python 語言的核心特色同時縮減周邊模組(函式庫),好讓 Python 這種出了名的…吃記憶體的語言也能在微控制板上運行。

和 C++(Arduino)相比,MicroPython 有其優點與缺點。C++ 擁護者最喜歡攻擊 MicroPython 的乃是其執行效率,而 MicroPython 在記憶體的使用上也遜色得多(因此它的設計對象多半是記憶體跟儲存空間較大的硬體,但即使如此還是很容易不小心用光記憶體)。然而 Python 身為直譯器語言,你可以直接在板子的直譯器執行草稿碼而不需等待編譯/上傳,這加上 Python 語言寫起來相對簡單的特性,反而使 MicroPython 很適合快速打造或實驗一些嵌入式應用。等到開發結束後,再移植到 C++ 就行了。

MicroPython 有幾個衍生版本,包括 2015 年專為 BBC micro:bit 設計的極簡版(因為它記憶體相對實在過小),2019 年還有給樂高 Mindstorm EV3 的版本。本文要介紹的,是 MicroPython 在 2017 年衍生出來的一個近親,叫做 CircuitPython

CircuitPython:給 SAMD21/51 及 nRF52 處理器的 Python

Image for post
Image for post

CircuitPython 乃美國 Adafruit 公司為了自家及其他公司相關產品所寫的 MicroPython 版(如果你去看它的 Github repo,其實是從 MicroPython 分支出來再修改的),主要目的為讓這種語言能用在該公司以 SAMD21 處理器為主力的產品上,這後來也擴展到其 SAMD51 和 nRF52 處理器板子上。

相較於「標準」MicroPython 對不同板子提供不同程式模組的作法,CircuitPython 的目的是統一語言功能,可以用一樣的語法套用在不同板子上。(當然,不同硬體需要不同的韌體,且不知為何 Adafruit 產品的腳位也彼此有些差異,所以這種軟體上的一致究竟有多大的實用性,筆者目前是持保留態度。)

既然「標準」MicroPython 最主要支援的板子之一為低價、性能不錯的 ESP8266/ESP32,東方世界的我們比較容易接觸到標準 MicroPython。相對的,Adafruit 和 Sparkfun 等國外公司主流的 SAMD21/51 系列開發板因得進口的因素,幾乎看不到有人在玩或討論…

About

Alan Wang

Former translator and currently a tech-book editor based in Taiwan. https://krantasblog.blogspot.com

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store