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 是一个可以通过关键字搜索的图像数据库。 它还允许你选择一个关键字并下载与该关键字相关的图像 URL 列表,这对于我们接下来要做的事情非常有用。 我选择了“hotdog”、“chilidog”和“frankfurter”作为热狗的图像,选择了“pets”、“buildings”、“plants”和“pizza”作为非热狗的图像。 如果你不想自己查找图像 URL,你可以直接获取我的。
接下来,我们需要循环遍历 URL 并下载实际图像。 我们可以使用脚本自动执行此操作 - 我不会在此处详细解释,但你可以在 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 显示一个 UI 来浏览我们刚刚标记的数据集。
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 中的 woulda core 包一样使用。
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 插件中实现和利用机器学习。让我换句话说——我们将人工智能引入了设计工具,而且不仅仅是任何 AI。通过利用 Apple 的 Core ML 框架,我们在设备上运行最先进的机器学习模型时,可以获得最大的性能和效率——因此数据甚至不需要离开您的 MacBook 即可进行分析。
人工智能正在成为设计工具的一部分,而且发生的速度比任何人想象的都要快。从变异设计到建议您接下来可能想要在画板上放置哪些组件,机器学习在设计方面的潜力几乎是无限的。我迫不及待地想看看未来会怎样——希望它不仅仅是热狗。
如果您是一名开发人员,并且想构建这样的插件,请与我们联系。我们拥有一个充满活力的开发者社区和一个广阔的插件生态系统,我们希望您成为其中的一员。请通过 developer@sketch.com 与我们联系,或访问 www.sketchplugins.com 了解更多信息。