使用函数 initializer 接口优化深度学习场景下模型加载的冷启动延时

本文涉及的产品
Serverless 应用引擎 SAE,800核*时 1600GiB*时
函数计算FC,每月免费额度15元,12个月
简介: 背景 深度学习场景使用函数计算典型案例 阿里云 函数计算 客户 码隆科技 是一家专注于深度学习与计算机视觉技术创新的公司。当码隆的客户上传大量图像数据后,需要尽快把图像按照客户指定的方式处理,包括商品识别,纺织面料等柔性材质识别分析,内容审查,以图搜图等等。

背景

深度学习场景使用函数计算典型案例

阿里云 函数计算 客户 码隆科技 是一家专注于深度学习与计算机视觉技术创新的公司。当码隆的客户上传大量图像数据后,需要尽快把图像按照客户指定的方式处理,包括商品识别,纺织面料等柔性材质识别分析,内容审查,以图搜图等等。图像处理基于码隆预先训练好的深度学习模型,要求在短时间内准备大量的计算资源进行大规模并行处理。客户将深度学习推理逻辑实现为函数,在函数中加载模型后对图像数据进行处理。通过函数计算提供的大规模计算能力,客户能够短时间处理大量图像,平稳应对峰值压力。更多详细案例请见 函数计算客户案例

深度学习场景的客户在使用函数计算服务中更希望平台做哪些改进?

深度学习场景下加载模型是主要的应用层冷启动开销,模型的规格多为 500MB+,应用层冷启动开销往往会导致毛刺的产生,为归避这类问题,函数计算引入了 initializer 接口来解决应用层冷启动开销带来的毛刺问题。

功能简介

Initializer 编程模式为用户提供了 initializer 入口定义,便于用户将业务逻辑分为initializer函数请求处理函数两部分。函数计算使用容器执行用户函数代码,这样的执行环境我们称之为函数实例。函数实例会在启动的时候能够自动执行 initializer 函数,进行业务层冷启动,成功之后,该实例收到用户的 Invoke 请求,就能够执行用户的请求处理函数了。

引入 initializer 接口的优势:

  • 分离初始化逻辑和请求处理逻辑,程序逻辑更清晰,让用户更易写出结构良好,性能更优的代码;
  • 用户函数代码更新时,系统能够保证用户函数的平滑升级,规避应用层初始化冷启动带来的性能损耗。新的函数实例启动后能够自动执行用户的初始化逻辑,在初始化完成后再处理请求;
  • 在应用负载上升,需要增加更多函数实例时,系统能够识别函数应用层初始化的开销,更精准的计算资源伸缩的时机和所需的资源量,让请求延时更加平稳;
  • 即使在用户有持续的请求且不更新函数的情况下,FC系统仍然有可能将已有容器回收或更新,这时没有平台方(FC)的冷启动,但是会有业务方冷启动,Initializer 的引入可以最大限度减少这种情况;

案例实践

本实践以 函数计算部署机器学习遇到的问题和解法 这篇文章为基础,做了进一步改造和优化。下文将按照以下几个步骤讲解如何利用函数计算以高性能、低延时玩转深度学习场景下的识别手写数字案例:

安装依赖

训练模型

首先需要训练预期的模型,模型的训练可参考 这篇文章。按照文章中的步骤下载 MINIST 数据库和相关代码并开始训练模型,训练时长持续半小时左右,训练成功后的结构目录如下,其中 model_data 目录下的文件便是通过训练得到的模型。

project root
├── main.py
├── grf.pb
└── model_data
    ├── checkpoint
    ├── model.data-00000-of-00001
    ├── model.index
    └── model.meta

应用依赖的安装

本案例需要安装的应用依赖有 tensorflowopencv-python,模型的训练和函数的处理逻辑都强依赖这两个库,训练模型可在本地直接操作,通过 pip 在本地安装两个依赖库即可,版本不限。由于函数运行在函数计算(FC)系统同样依赖这两个库,需要提前下载好依赖并打包上传到 OSS。推荐使用 fcli 工具的 sbox 命令,下面以 runtime 为 python2.7 进行操作:

目前 Pypi 上 tensorflow 最新版本为 1.11.0,为避免因版本问题影响您的实践,建议安装 1.8.0 版本。

cd <'此项目的根目录中'>
mkdir applib      // 创建存储所有应用依赖的目录
fcli shell        // fcli version >= 0.24
sbox -d applib -t python2.7
pip install -t $(pwd) tensorflow==1.8.0
pip install -t $(pwd) opencv-python

完成之后 exit 退出沙盒环境,并执行 exit 退出fcli。

上传依赖

依赖和模型下载成功后需要进行压缩并上传到 OSS 中,以便后面函数可以直接从 OSS 下载即可,在项目的根目录执行下面两条命令可以得到 applib.zipmodel_data.zip 两个 zip 压缩包。

cd applib && zip -r applib.zip * && mv applib.zip ../ ; cd ..
cd model_data && zip -r model_data.zip * && mv model_data.zip ../ ; cd ..

下面提供了一个简单的上传 zip 包到 OSS 的模版,上传成功后删除本地的依赖和模型目录即可。

# -*- coding: utf-8 -*-
import oss2

auth = oss2.Auth(<'Your access_key_id'>, <'Your access_key_secret'>)
bucket = oss2.Bucket(auth, <'Your endpoint'>, <'Your bucket'>)
bucket.put_object_from_file('applib.zip', <'Your applib.zip path'>)
bucket.put_object_from_file('model_data.zip', <'Your model_data.zip path'>)

将机器学习应用迁移至函数计算

如何将本地机器学习应用进行改造并迁移到函数计算的流程在 将机器学习应用迁移至函数计算 中有详细的步骤,这篇文章中的改造并没有 initializer 的概念,您只需要关注 index.py 和 loader.py 是如何产生的,详细代码链接,改造后的目录结构如下,其中 index.py 存放了机器学习相关逻辑的代码,loader.py 存放了函数入口和加载依赖逻辑的代码。

project root
└─── code
    ├── loader.py
    └── index.py
    └── pic
        └── e2.jpg

e2.jpg 只是文章中提供的一个简单的数字 2 图片,如做验证性测试需要更多的素材可以通过 keras.js 平台手动绘制生成。

30321e3e7b260c558ddae712ca13e293.png

引入 initializer 接口

经过应用迁移处理后得到了一个可以运行在函数计算服务上的函数,很明显可以看到函数入口 loader.handler 中首先需要从 OSS 加载应用依赖(tensorflow、opencv)和资源依赖(模型),加载的过程都属于应用层冷启动,冷启动所耗费的时间在一定程度上和所需依赖的大小规格成正比。为避免后续处理逻辑受到应用层冷启动延时的影响,这里将加载依赖逻辑放入 initializer 函数中。

其中 index.py 文件保持不变,loader.py 文件需要进行如下改造:

  • 添加 initializer 函数,initializer 入口便为 loader.initializer。
  • 将对 download_and_unzip_if_not_exist 的调用从 handler 中更换到 initializer 函数中。

loader.py 经过改造后的代码如下:

# -*- coding:utf-8 -*-
import sys
import zipfile
import os
import oss2
import imp
import time

app_lib_object = os.environ['AppLibObject']
app_lib_dir = os.environ['AppLibDir']
model_object = os.environ['ModelObject']
model_dir = os.environ['ModelDir']

local = bool(os.getenv('local', ""))
print 'local running: ' + str(local)

def download_and_unzip_if_not_exist(objectKey, path, context):
    creds = context.credentials
    if (local):
        print 'thank you for running function in local!!!!!'
        auth = oss2.Auth(creds.access_key_id,
                         creds.access_key_secret)
    else:
        auth = oss2.StsAuth(creds.access_key_id,
                            creds.access_key_secret,
                            creds.security_token)

    endpoint = os.environ['Endpoint']
    bucket = os.environ['Bucket']

    print 'objectKey: ' + objectKey
    print 'path: ' + path
    print 'endpoint: ' + endpoint
    print 'bucket: ' + bucket

    bucket = oss2.Bucket(auth, endpoint, bucket)

    zipName = '/tmp/tmp.zip'

    print 'before downloading ' + objectKey + ' ...'
    start_download_time = time.time()
    bucket.get_object_to_file(objectKey, zipName)
    print 'after downloading, used %s seconds...' % (time.time() - start_download_time)

    if not os.path.exists(path):
        os.mkdir(path)

    print 'before unzipping ' + objectKey + ' ...'
    start_unzip_time = time.time()
    with zipfile.ZipFile(zipName, "r") as z:
        z.extractall(path)
    print 'unzipping done, used %s seconds...' % (time.time() - start_unzip_time)

def initializer(context):
    if not local:
        download_and_unzip_if_not_exist(app_lib_object, app_lib_dir, context)
        download_and_unzip_if_not_exist(model_object, model_dir, context)
    sys.path.insert(1, app_lib_dir)

def handler(event, context):
    desc = None
    fn, modulePath, desc = imp.find_module('index')
    mod = imp.load_module('index', fn, modulePath, desc)
    request_handler = getattr(mod, 'handler')
    return request_handler(event, context)

部署

本地开发已经完成,下面借助阿里云函数计算的工具 fun 可以进行一键部署,Fun 是一个用于支持 Serverless 应用部署的工具,它通过一个资源配置文件(template.yml),协助您进行开发、构建、部署操作,步骤如下:

  • release 页面对应平台的 binary 版本,解压就可以使用。或者使用 npm install @alicloud/fun * -g 也可以直接使用。
  • 使用 fun config 配置 ak、region 等信息。
  • 编写 template.yml
  • fun deploy 部署

template.yml 文件如下:

ROSTemplateFormatVersion: '2015-09-01'
Transform: 'Aliyun::Serverless-2018-04-03'
Resources:
  tensorflow: # 服务名
    Type: 'Aliyun::Serverless::Service'
    Properties:
      Description: 'tensorflow demo'
      Policies:
        - AliyunOSSReadOnlyAccess
    initializer: # 函数名
      Type: 'Aliyun::Serverless::Function'
      Properties:
        Handler: loader.handler  # 处理函数入口
        Initializer: loader.initializer  # initializer 入口
        CodeUri: ./code/
        Description: 'tensorflow application!'
        Runtime: python2.7
        MemorySize: 1024
        Timeout: 300
        InitializationTimeout: 60
        EnvironmentVariables:
          Bucket: test-bucket # 替换为自己的 oss bucket
          Endpoint: 'https://oss-cn-hangzhou.aliyuncs.com' # 替换掉 OSS Endpoint
          AppLibObject: applib.zip
          AppLibDir: /tmp/applib
          ModelObject: model_data.zip
          ModelDir: /tmp/model
  • 执行 fun deploy 会显示如下信息,部署成功后可到对应 region 下查看部署是否生效。
    image.png

测试

功能测试

登陆函数计算 控制台 对应 region 下找到所创建的函数,连续执行两次查看执行结果如下。

  • 首次执行
    image.png
  • 第二次执行
    image.png

从以上图片可以看到首次函数执行时间为 3793ms,第二次函数执行时间为 810ms,执行结果都为 the predict is 2 ,从执行结果可以确认函数执行正确,但性能真的提高了吗?下面会有简单的性能测试做对比。

性能测试

这里对改造前的函数做同样的测试:

  • 首次执行
    image.png
  • 首次执行日志
    image.png
  • 第二次执行
    image.png

从以上图片可以看到首次函数执行时间为 17506ms,第二次函数执行时间为 815ms,通过日志可以发现首次触发函数执行大约 13s 花费在加载模型和依赖库上,函数的执行时间会随着模型和依赖库规格的增大而增大。由此可见,initializer 函数的引入会使得函数实例在首次启动时规避冷启动开销,降低函数执行时间,提高函数性能,并且不会对后续的请求产生任何影响。

总结

通过将深度学习场景下规格较大的模型、依赖库的加载等初始化逻辑进行提取放到 initializer 函数中可以极大的提升函数性能,规避用户系统/函数升级带来的冷启动开销,帮助用户实现业务系统的热升级。

最后欢迎大家通过扫码加入我们用户群中,使用过程中有问题或者有其他问题可以在群里提出来。函数计算官网客户群(11721331)。

参考文章:

1 :Tensorflow MINIST数据模型的训练,保存,恢复和手写字体识别
2:函数计算部署机器学习遇到的问题和解法

相关实践学习
基于函数计算一键部署掌上游戏机
本场景介绍如何使用阿里云计算服务命令快速搭建一个掌上游戏机。
建立 Serverless 思维
本课程包括: Serverless 应用引擎的概念, 为开发者带来的实际价值, 以及让您了解常见的 Serverless 架构模式
目录
相关文章
|
13天前
|
机器学习/深度学习 算法 网络架构
深度学习中的自动超参数优化技术探究
在深度学习模型的训练中,选择合适的超参数对模型性能至关重要。本文探讨了自动超参数优化技术在深度学习中的应用,分析了不同方法的优缺点,并着重讨论了基于贝叶斯优化和进化算法的最新进展。 【7月更文挑战第8天】
|
16天前
|
机器学习/深度学习 自然语言处理 监控
进阶技术分享:利用深度学习优化自然语言处理应用
在当今技术快速发展的背景下,深度学习作为一种强大的工具正在不断改进自然语言处理(NLP)应用的性能。本文探讨了如何利用深度学习模型,特别是Transformer架构,来优化和提升NLP应用的效果。通过详细的技术分析和实际案例,展示了这些先进技术如何应用于文本分类、情感分析和语言生成等领域,为读者提供了深入理解和实施的指导。【7月更文挑战第5天】
25 3
|
5天前
|
机器学习/深度学习 数据可视化 算法框架/工具
使用Python实现深度学习模型:视频处理与动作识别
【7月更文挑战第16天】 使用Python实现深度学习模型:视频处理与动作识别
38 17
|
6天前
|
机器学习/深度学习 自然语言处理 TensorFlow
使用Python实现深度学习模型:文本生成与自然语言处理
【7月更文挑战第14天】 使用Python实现深度学习模型:文本生成与自然语言处理
35 12
|
5天前
|
机器学习/深度学习 人工智能 自然语言处理
算法金 | 秒懂 AI - 深度学习五大模型:RNN、CNN、Transformer、BERT、GPT 简介
**RNN**,1986年提出,用于序列数据,如语言模型和语音识别,但原始模型有梯度消失问题。**LSTM**和**GRU**通过门控解决了此问题。 **CNN**,1989年引入,擅长图像处理,卷积层和池化层提取特征,经典应用包括图像分类和物体检测,如LeNet-5。 **Transformer**,2017年由Google推出,自注意力机制实现并行计算,优化了NLP效率,如机器翻译。 **BERT**,2018年Google的双向预训练模型,通过掩码语言模型改进上下文理解,适用于问答和文本分类。
37 9
|
7天前
|
机器学习/深度学习 PyTorch 算法框架/工具
图神经网络是一类用于处理图结构数据的神经网络。与传统的深度学习模型(如卷积神经网络CNN和循环神经网络RNN)不同,
图神经网络是一类用于处理图结构数据的神经网络。与传统的深度学习模型(如卷积神经网络CNN和循环神经网络RNN)不同,
|
3天前
|
机器学习/深度学习 编解码 算法框架/工具
使用Python实现深度学习模型:图像超分辨率与去噪
【7月更文挑战第17天】 使用Python实现深度学习模型:图像超分辨率与去噪
17 4
|
2天前
|
机器学习/深度学习 TensorFlow 语音技术
使用Python实现深度学习模型:语音合成与语音转换
【7月更文挑战第19天】 使用Python实现深度学习模型:语音合成与语音转换
17 1
|
3天前
|
机器学习/深度学习 监控 算法框架/工具
使用Python实现深度学习模型:人脸识别与人脸表情分析
【7月更文挑战第18天】 使用Python实现深度学习模型:人脸识别与人脸表情分析
14 2
|
6天前
|
机器学习/深度学习 数据可视化 TensorFlow
使用Python实现深度学习模型:图像语义分割与对象检测
【7月更文挑战第15天】 使用Python实现深度学习模型:图像语义分割与对象检测
27 2

热门文章

最新文章