HBO 電視劇《矽谷群英》中的「不是熱狗」應用程式已成為科技界最具代表性的笑話之一。在許多不同的平台上,都有許多真實的應用案例,但唯獨缺少一個,直到現在。我著手打造這個在設計師日常工作流程中缺失的 Sketch 插件,以下是我如何將其實現。
「如果我告訴你,市面上有一個 Sketch 插件可以判斷你的文件中的一個圖層是否是熱狗,你會怎麼說?它非常好用,而且我不想再繼續開發它了。你可以另請高明。」
這是 🌭 嗎?
事實證明,要建立一個可以判斷圖層是否是熱狗的 Sketch 插件並非難事,這要歸功於 Apple 工程師的辛勤工作。Sketch 插件可以使用 JavaScript 函式庫(因此你可以利用其他人的成果來做一些很酷的事情,例如 sketch-primitives 或 rough-sketch)和 macOS API。這表示我們可以兼得兩者的優點,最重要的是,我們可以利用 Apple 的新 Core ML 框架。
這個新的 macOS 框架讓開發者以前所未有的方式使用機器學習。事實上,「不是熱狗」插件是我第一次涉足機器學習領域,而且它比我想像的更容易上手 — 實際上,整個插件只有 100 行程式碼,其中一半是空白的(因為空白很重要,孩子們)。
想建立自己的機器學習 Sketch 插件嗎?你只需要一台筆電和一大堆熱狗的照片。讓我們開始吧。
要建立一個判斷圖層是否包含熱狗的插件,我們需要
- 訓練一個分類器
- 建立一個使用該分類器的 Sketch 插件
如果你正在跟著做,所有的程式碼都是開源的,可以在這裡找到:https://github.com/mathieudutour/sketch-hotdog。
訓練分類器
分類器是一個系統,它可以根據屬於這些集合的其他項目的範例,判斷一個項目最可能屬於哪個資料集。這些範例稱為「訓練集」,將這些資訊提供給分類器的過程稱為「訓練」。
在我們的例子中,我們想要訓練一個分類器來辨識圖像是否包含熱狗。
收集訓練集
我們需要做的第一件事是收集訓練集的圖像。最好的方法是成為史丹佛大學的教授,並給你的每個學生一個作業,為你收集食物的照片。我不知道你的情況,但我不是史丹佛大學的教授,所以我們需要用老方法來收集我們的圖像。
ImageNet 是一個可以透過關鍵字搜尋圖片的資料庫。它也允許您選擇一個關鍵字並下載與該關鍵字相關的圖片網址列表,這對我們接下來要做的事情非常有用。我選擇了關鍵字「hotdog」、「chilidog」和「frankfurter」來搜尋熱狗圖片,以及「pets」、「buildings」、「plants」和「pizza」來搜尋非熱狗圖片。如果您不想自己尋找圖片網址,您可以直接使用我的。
接下來,我們需要遍歷這些網址並下載實際的圖片。我們可以使用腳本來自動執行此操作——我不會在這裡詳細解釋,但您可以在Github 上找到這個腳本——只需按照檔案頂部的說明操作即可。此腳本會下載圖片並將它們儲存在兩個資料夾中:hotdog
和 not_hotdog
。

熱狗訓練集
建立模型
現在我們有了訓練集,我們需要訓練分類器(或建立模型)。訓練分類器通常是一項非常複雜的任務,涉及許多參數。幸運的是,Apple 建立了一個名為 Turi Create 的開源工具,它使這個過程變得更加容易,所以我們將使用它。
首先,您需要安裝 Turi Create。別擔心,我會在這裡等您。
安裝完成後,我們需要建立一個 Python 腳本來建構我們的模型。Turi Create 有一個方便的方法可以遞迴載入資料夾中的所有圖片。
import turicreate as tc
import osdata = tc.image_analysis.load_images(
'./datasets/',
with_path=True
)
您可能會看到一堆「不是 JPEG 檔案」的錯誤,因為我們下載的某些圖片已損毀,但您可以放心地忽略這些錯誤。參數 with_path=True
會在產生的資料框架中新增一個 path
欄位,其中包含每個圖片的絕對路徑。
由於該欄位,我們可以標記圖片——如果路徑包含 /hotdog/
,那麼它就是熱狗——很簡單,對吧?
data['label'] = data['path'].apply(
lambda path: 'hotdog' if '/hotdog/' in path else 'nothotdog'
)
此時,您可以要求 Turi Create 顯示一個使用者介面來瀏覽我們剛才標記的資料集。
data.explore()
現在是時候使用我們的訓練集來訓練我們的分類器了。感謝 Turi Create,我們只需要一個方法就可以做到。
model = tc.image_classifier.create(
data, # use the training set
target='label', # classify based on the label
model='squeezenet_v1.1',
max_iterations=50
)
它會自動將我們資料的 5% 作為「驗證集」,並檢查分類器的表現(先猜測,然後檢查標籤以查看是否正確)。您可以調整迭代次數,看看它如何影響準確性。如果您使用的數字太高,您會注意到準確性開始下降。這是由於一種稱為「過擬合」的現象,它導致模型對訓練資料的擬合程度過高,以至於變得過於特定。

我們快完成了——最後一件要做的事情是儲存模型,以便我們的 Sketch 外掛程式可以使用它。使用以下指令來執行此操作。
model.export_coreml('HotdogNotHotdog.mlmodel')
建立 Sketch 外掛程式
現在我們有了分類器,我們需要建立一個 Sketch 外掛程式,它將使用分類器來分類我們的圖片圖層。為了建立外掛程式,我們將使用一個名為 skpm 的開源工具。它自動化了開發和發佈外掛程式所涉及的許多任務,讓您可以專注於實際的程式碼。首先,您需要安裝 skpm。
設定外掛程式
現在我們可以建立外掛程式了。在終端機中,執行以下指令
skpm create sketch-hotdog && cd sketch-hotdog
這將會建立一個叫做 sketch-hotdog
的資料夾,安裝一些建置插件所需的依賴套件,並初始化幾個檔案來建立一個簡單的樣板插件。它應該會出現在 Sketch 的插件選單中。試著執行它吧!很厲害吧?
在深入研究程式碼之前,我們需要先做幾件事。首先,我們需要打開 Sketch,建立一個新的文件,插入一張圖片並選取該圖片。然後,我們需要將我們的分類器模型放到插件可以存取的位置。你會注意到 sketch-hotdog
資料夾中有一個 assets
資料夾。插件可以存取這個資料夾中的所有檔案,所以讓我們把我們的模型移到那裡。每次修改程式碼後,我們都需要重新建置插件,所以我們接下來需要做這件事。你可以在終端機中執行以下指令來完成:npm run watch
。
好了,我們都準備好了。你需要在你喜歡的程式碼編輯器中打開以下檔案 sketch-hotdog/src/my-command.js
。我們要寫的所有程式碼都將放在已經定義好的函式中。
與 Sketch 文件互動
首先,我們需要取得使用者選取的圖層,並檢查它是否是一個圖片圖層。如果你熟悉 JavaScript 和 NodeJS,這對你來說應該很熟悉。與 Sketch 互動的 API 可用於核心套件,就像在 NodeJS 中一樣。
var sketch = require('sketch')
如果你不完全熟悉 Sketch API,你可以查看文件。
讓我們從取得 Sketch 選取的第一個圖層開始。
const document = sketch.getSelectedDocument()
const selectedLayer = document.selectedLayers.layers[0]
然後,我們需要檢查我們是否真的有一個圖層,以及該圖層是否是一個圖片。如果不是,我們將顯示一個訊息,告訴使用者選取一個。
if (!selectedLayer || selectedLayer.type !== 'Image') {
sketch.UI.message('You need to select an image')
return
}
利用 macOS 架構
Sketch 插件在 Sketch 中執行,而 Sketch 是一個原生的 macOS 應用程式。這意味著它可以存取所有 macOS 架構。預設情況下,只有兩個架構可用:Foundation 和 AppKit。使用這兩個架構,你已經可以做很多事情了。但我們機器學習插件需要的是一個叫做 Vision 的架構。別擔心,我們可以在我們的插件中載入它。
framework('Vision')
現在我們可以存取 Vision 架構了,我們需要載入之前放在 assets
資料夾中的分類器模型。
我們需要的方法是 [MLModel compileModelAtURL:error:]
。我知道,這不是 JavaScript,而是 Objective-C。我們不能直接使用它,所以我們需要稍微改變一下語法。不過別擔心,這相當簡單。
- 首先,移除方括號。
- 然後,將類別和方法之間的空格替換為
.
。 - 將
:
替換為_
(你可以省略最後一個)。 - 然後像呼叫任何 JavaScript 函式一樣呼叫該方法。
所以 [MLModel compileModelAtURL:error:]
就變成了 MLModel.compileModelAtURL_error()
。
現在,讓我們來取得我們的模型。
// compile the model
const compiledModelURL = MLModel.compileModelAtURL_error(
context.plugin.urlForResourceNamed("HotdogNotHotdog.mlmodel"),
null
)
// load the compiled model
const model = MLModel.modelWithContentsOfURL_error(
compiledModelURL,
null
)
// transform our model into a Vision model
const vnModel = VNCoreMLModel.modelForMLModel_error(
model,
null
)
// create a an image analysis request that uses
// our Core ML model to process images
const request = VNCoreMLRequest
.alloc()
.initWithModel(vnModel)
我們現在需要建立一個「請求處理器」,它將接收我們剛剛建立的圖片分析請求,並將其應用於我們的圖片圖層。
// VNImageRequestHandler expects a "CIImage"
// Luckily, we can create one from our image layer
const ciImage = CIImage.imageWithData(
selectedLayer.image.nsdata
)
const handler = VNImageRequestHandler
.alloc()
.initWithCIImage_options(
ciImage,
null
)
我們快完成了——讓我們來執行我們的分類器!
const success = handler.performRequests_error(
[request],
null
)
最後一步是從分類器中取得結果,並向使用者顯示一個訊息。
if (success) {
const bestEstimation = request.results()[0]
const isAHotDog = String(bestEstimation.identifier()) === 'hotdog'
sketch.UI.message(
isAHotDog ? "Yep, it's a 🌭" : "Nope ❌"
);
} else {
sketch.UI.message('Something went wrong 😕')
}
完成了!現在你可以檢查一個圖層是否是熱狗了。我相信你一定很好奇在你學會這個之前你是怎麼工作的!
插件指令的程式碼可以在這裡找到:https://github.com/mathieudutour/sketch-hotdog/blob/master/src/is-it-a-hotdog.js。
結論
雖然這是一個相當愚蠢的例子,但我剛剛展示了如何在 Sketch 插件中實現和利用機器學習。讓我換一種說法——我們將人工智能引入了設計工具,而且不是隨便什麼人工智能。通過利用蘋果的 Core ML 框架,我們在運行設備上的最先進機器學習模型時,可以獲得最大的性能和效率——因此數據甚至不需要離開你的 MacBook 就可以進行分析。
人工智能正在成為設計工具的一部分,而且其發展速度比任何人想像的都要快。從突變設計到建議您接下來可能想在畫板上放置哪些組件,機器學習在設計領域的潛力幾乎是無限的。我迫不及待地想看看未來會是什麼樣子——希望它不僅僅是熱狗。
如果您是一名開發人員,並且想要構建這樣的插件,請與我們聯繫。我們有一個充滿活力的開發者社區和一個廣泛的插件生態系統,我們很樂意您成為其中的一份子。請通過 developer@sketch.com 與我們聯繫,或訪問 www.sketchplugins.com 了解更多信息。