当前位置: 首页 > 科技观察

使用WebAssembly提高模型部署的速度和可移植性

时间:2023-03-18 20:25:44 科技观察

最近几个月,我们帮助许多公司在各种环境中部署他们的AI/ML模型。我们为医疗行业的模型部署做出了贡献,在过去的几个月里,我们帮助多家公司将经过训练的模型转移到不同类型的物联网设备上。特别是在物联网设备的情况下,要求通常很严格:计算周期数和可用内存通常都是有限的。在本文中,我阐明了如何确保使用PyTorch、Scikit-learn和Tensorflow等标准ML库训练的模型可以有效地部署在各种边缘设备上。为了使事情更实际,我们将研究一个简单的逻辑回归模型的训练和部署。然而,我们在这里讨论的大部分内容直接转移到更复杂的模型。模型训练为了说明模型训练和部署之间的区别,让我们首先模拟一些数据。下面的代码根据以下简单模型生成1000个观测值:imagereleaseimportnumpyasnpnp.random.seed(66)#Setseedforreplication#SimulateDataGeneratingProcessn=1000#1000observationsx1=np.random.uniform(-2,2,n)#x_1&x_2between-2and2x2=np.random.uniform(-2,2,n)p=1/(1+np.exp(-1*(.75+1.5*x1-.5*x2)))#ImplementDGPy=np.random.binomial(1,p,n)#Drawoutcomes#Createdatasetandprintfirstfewlines:data=np.column_stack((x1,x2,y))print(data[:10])生成数据后,我们就可以专注于拟合模型了。我们只是使用sklearn的LogisticRegression()函数:fromsklearn.linear_modelimportLogisticRegressionmod=LogisticRegression().fit(data[:,[0,1]],np.ravel(data[:,[2]]))仔细看看这个点,梳理并简要考虑引擎盖下发生的事情非常有用。与许多其他有趣的ML模型一样,逻辑回归模型是迭代训练的。为了训练模型,sklearn(或任何其他提供类似功能的包)将必须实现几个功能:1.某种评分功能,表明模型的拟合程度。这可能是误差函数或最大似然函数。2.此函数将拟合模型的参数从一次迭代更新到下一次迭代。训练过程将有效地重用这两个功能:最初,模型的参数是随机实例化的。接下来,检查模型的分数。如果分数被认为不足(通常是因为分数与之前的迭代相比有所提高),则会更新模型参数并重复该过程。即使对于这个简单的模型,sklearn仍然需要迭代数据集。下面的代码给出了迭代次数:#Printthenumberofiterationsprint(f'Thenumberofiterationsis:{mod.n_iter_}.'因此,为了训练模型,我们需要访问数据和几个工具函数,并且需要迭代/遍历数据集多次总的来说,这个训练过程对计算要求很高,这就解释了为什么对于复杂的模型,我们采用并行计算和GPU或NPU加速来在合理的时间内执行。幸运的是,在训练模型时,需要的相当复杂的逻辑已经被抽象掉了通过我们使用的各种ML库。生成预测将此与从已经拟合的模型生成预测进行比较(通常称为推理,但由于使用后者与后者不同,所以我觉得这个术语令人困惑,所以我坚持使用predict).当谈到模型拟合时,在这种情况下,我们实际上需要生成预测的只是逻辑回归函数(与上面示例中相同的数学函数化用于生成数据)和拟合模型的三个参数。这些很容易检索到:b=np.concatenate((mod.intercept_,mod.coef_.flatten()))print(b)参数最终相对接近我们用于数据生成的值:[0.845765631.39541631-0.47393112]。此外,在大多数部署情况下,我们通常最终只用一个输入来评估模型:在这种情况下,是一个长度为2的数字向量。如果我们不需要拟合函数,我们就不需要数据,并且我们不需要迭代来部署模型。要生成预测,我们只需要以简单有效的方式实现所涉及的数学。在边缘设备中部署模型你可能会问。当现代模型训练工具抽象出所有这些细节时,为什么还要关心训练和预测所涉及的细节?好吧,因为当你想高效地部署你的模型时(例如,当你需要你的模型在小型设备上快速运行时),你可以更好地利用设备差异。为了便于讨论,对比以下两种模型部署方法(即,将经过训练的模型投入生产,以便可以使用其预测):将sklearn作为REST服务部署在Docker容器上:这种方法简单且经常使用:我们启动一个包含python和用于训练的工具的docker镜像:上面示例逻辑回归模型的sklearn。接下来,我们创建一个RESTAPI服务,该服务使用拟合模型的mod.predict()函数来生成结果。ScalableWebAssemblyDeployment:除了上述方法之外,还可以将拟合模型转换为WebAssembly(使用类似于Scalable提供的服务)并部署仅包含最小WebAssembly运行时预测的.WASM二进制文件。需要的逻辑。自动生成的二进制文件将只包含必要的逻辑函数和估计参数。二进制文件可以部署在服务器上,因此可以通过REST调用类似地使用,但是,它与可用的运行时兼容,并且几乎可以在任何边缘设备上运行。显然,第一个部署过程接近于数据科学家的“我们所知道的”。直接使用我们习惯的工具非常方便,并且在很多方面都有效:我们可以使用对REST端点的调用来生成预测。第二种解决方案与我们的标准做法相去甚远,对模型训练毫无用处(即没有“用于训练模型的WebAssembly包……”)。然而,我们仍然认为它应该是首选:第二种设置利用了训练和预测之间的差异,以多种方式使模型部署更好:内存占用:上述两个选项中的第一个至少需要75Mb(它需要很多工程使容器变小,并且使容器的大小接近1Gb更为常见)。在这种情况下,存储的模型本身很小(~2Kb),因此容器占部署内存占用的最大块(请注意,对于大型神经网络等,这可能并非如此)。相比之下,WebAssembly运行时可以降到64Kb以下。WebAssembly二进制文件本身比存储的sklearn模型(~50kb)大,但现在它包含生成预测所需的所有内容。因此,虽然第一个部署选项至少占用75Mb,但第二个部署选项占用不到0.1Mb。速度:与高效的WebAssembly部署相比,使用在Docker容器中运行的REST端点不会产生执行时间优势,因为Docker容器会启动训练所需的一切。下面是不同模型的一些速度比较,但不用说,通过利用训练和预测之间的差异,并将预测的基本需求投入生产,可以更快地生成这些预测一个数量级。因此,内存占用更小,执行速度更快。有几个原因;一个原因是我们可能希望有效地部署模型,而不会在每次做出预测时都浪费能源。但内存占用小和执行速度快也很有吸引力,因为这正是我们即将将模型投入生产所需要的:祝你在ESP32MCU板上部署Docker容器(例如)好运。使用WebAssembly,这是小菜一碟。综上所述,你一定对WebAssembly很感兴趣,那么看看这段代码,它包含了本文的所有内容https://github.com/scailable/sclbl-tutorials/tree/master/sclbl-train-vs-部署