您可以通过函数计算控制台、SDK或Serverless Devs来体验GPU实例的最佳实践。本文以Python语言为例,说明如何使用Serverless Devs开发工具,将原始图像经过函数代码处理,实现边缘检测。

应用场景与优势

在不同的应用场景下,函数计算提供的GPU实例与CPU相比所具备的优势如下:

  • 实时、准实时的应用场景
    • 提供数倍于CPU的图形图像处理效率,从而快速将生产内容推向终端用户。
  • 成本优先的图像处理场景
    • 提供弹性预留模式,从而按需为客户保留GPU工作实例,对比自建GPU集群拥有较大成本优势。
    • 提供GPU共享虚拟化,支持以1/2、独占方式使用GPU,允许业务以更精细化的方式配置GPU实例。
  • 效率优先的图像处理场景
    • 屏蔽运维GPU集群的繁重负担(驱动/CUDA版本管理、机器运行管理、GPU坏卡管理),使得开发者专注于代码开发、聚焦业务目标的达成。

GPU实例的更多信息,请参见实例类型及使用模式

教程示例说明

如下表所示,左列为原图,右列是经过部署在函数计算的边缘检测函数代码处理后,所生成的图片。

原始图像 边缘检测结果
image_processing_example image_processing_result_example

前提条件

  • 诚邀您参与测试GPU实例。请提交工单申请参与测试,并在工单中附上以下信息:
    • 组织名称,例如您所在的公司名称。
    • 您的阿里云账号ID。
    • 您期望使用GPU实例的地域,例如华南1(深圳)。
    • 联系方式,例如您的手机号、邮箱或钉钉账号等。
    • 您的镜像大小。
  • 在GPU实例所在地域,完成以下操作:
  • 安装Serverless Devs和Docker
  • 配置Serverless Devs
  • 编译OpenCV。
    OpenCV需要自行编译以使用GPU加速,编译方式如下:
  • 将需处理的音视频资源上传至在GPU实例所在地域的OSS Bucket中,且您对该Bucket中的文件有读写权限。具体步骤,请参见上传文件。权限相关说明,请参见修改存储空间读写权限

操作步骤

  1. 创建项目。
    s init devsapp/start-fc-custom-container-event-python3.9 -d fc-gpu-prj

    创建的项目目录如下所示。

    fc-gpu-prj
    ├── code
    │   ├── app.py        # 函数代码
    │   └── Dockerfile    # Dockerfile:将代码打包成镜像的Dockerfile
    ├── README.md
    └── s.yaml            # 项目配置:包含了镜像如何部署在函数计算
  2. 进入项目所在目录。
    cd fc-gpu-prj
  3. 按实际情况修改目录文件的参数配置。
    • 编辑s.yaml文件。

      YAML文件的参数详解,请参见YAML规范

      edition: 1.0.0
      name: container-demo
      access: default
      vars:
        region: cn-shenzhen
      services:
        customContainer-demo:
          component: devsapp/fc
          props:
            region: ${vars.region}
            service:
              name: tgpu_opencv_service
              internetAccess: true
            function:
              name: tgpu_opencv_func
              description: test gpu for opencv
              handler: not-used
              timeout: 600
              caPort: 9000
              memorySize: 16384
              gpuMemorySize: 8192
              instanceType: g1
              initializationTimeout: 30
              initializer: not-used
              runtime: custom-container
              customContainerConfig:
                image: registry.cn-zhenshen.aliyuncs.com/demo/gpu-opencv_s:v0.1
              codeUri: ./code
            triggers:
              - name: httpTrigger
                type: http
                config:
                  authType: anonymous
                  methods:
                    - GET
    • 编辑app.py文件。

      示例如下:

      # -*- coding: utf-8 -*-
      # python2 and python3
      
      from __future__ import print_function
      from http.server import HTTPServer, BaseHTTPRequestHandler
      import json
      import sys
      import logging
      import os
      import numpy as np
      import cv2
      import urllib.request
      
      class MyRequest(BaseHTTPRequestHandler):
          def download(self, url, path):
              print("enter download:", url)
              f = urllib.request.urlopen(url)
              with open(path, "wb") as local_file:
                  local_file.write(f.read())
      
          def upload(self, url, path):
              print("enter upload:", url)
              headers = {
                  'Content-Type': 'application/octet-stream',
                  'Content-Length': os.stat(path).st_size,
              }
              req = urllib.request.Request(url, open(path, 'rb'), headers=headers, method='PUT')
              urllib.request.urlopen(req)
      
          def core(self):
              msg = ""
              mode = ""
              if not cv2.cuda.getCudaEnabledDeviceCount():
                  msg = "No CUDA-capable device is detected |"
                  mode = "Mat"
              else:
                  msg = "CUDA-capable device supported |"
                  mode = "UMat"
      
              # 需替换为您个人账号下的OSS,且您有可读写的权限。
              # 此处是从OSS Bucket中下载您已存储的原始图片。
              path = "/tmp/target.jpg"
              self.download("https://cri-zfen7xhps******-registry.oss-cn-shenzhen.aliyuncs.com/cats.png", path)
      
              img = cv2.imread(path)
      
              if mode=='UMat':
                  img = cv2.UMat(img)
              img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
              img = cv2.GaussianBlur(img, (7, 7), 1.5)
              img = cv2.Canny(img, 0, 50)
              if type(img) == 'cv2.UMat':
                  img = cv2.UMat.get(img)
              cv2.imwrite(path, img)
              # 需替换为您个人账号下的OSS,且您有可读写的权限。
              # 此处是向OSS Bucket中上传经过处理后的边缘检测结果图片,请注意图片名称与原图名称不能重合。
              self.upload("https://cri-zfen7xhpsx******-registry.oss-cn-shenzhen.aliyuncs.com/cats2.png", path)
      
              msg = msg + " process image ok!"
              data = {'result': msg}
              self.send_response(200)
              self.send_header('Content-type', 'application/json')
              self.end_headers()
              self.wfile.write(json.dumps(data).encode())
      
          def do_GET(self):
              self.core()
      
          def do_POST(self):
              self.core()
      
      if __name__ == '__main__':
          host = ('0.0.0.0', 9000)
          server = HTTPServer(host, MyRequest)
          print("Starting server, listen at: %s:%s" % host)
          server.serve_forever()
    • 编辑Dockerfile文件。

      示例如下:

      FROM julianassmann/opencv-cuda:cuda-10.2-opencv-4.2
      WORKDIR /usr/src/app
      RUN apt-get clean
      RUN apt-get update
      RUN apt-get install -y build-essential
      RUN apt-get install -y python3
      COPY . .
      CMD [ "python3", "-u", "/usr/src/app/app.py" ]
      EXPOSE 9000
  4. 构建镜像。
    s build --dockerfile ./code/Dockerfile
  5. 部署代码至函数计算
    s deploy
  6. 配置预留模式的实例。
    s provision put --target 1 --qualifier LATEST
  7. 查询预留模式的实例是否就绪。
    s provision get --qualifier LATEST

    如果查询到current参数为1,则说明GPU实例的预留模式已就绪,示例如下。

    [2021-11-01T13:43:28.308] [INFO ] [S-CLI] - Start ...
    [2021-11-01T13:43:28.521] [INFO ] [FC] - Getting provision: tgpu_opencv_service.LATEST/tgpu_opencv_func
    customContainer-demo:
      serviceName: tgpu_opencv_service
      functionName: tgpu_opencv_func
      qualifier: LATEST
      resource: 188077086902****#tgpu_opencv_service#LATEST#tgpu_opencv_func
      target: 1
      current: 1
      scheduledActions: []
      targetTrackingPolicies: []
  8. 调用函数。
    s invoke

    调用成功后,预期的返回结果如下。

    [2021-11-01T16:39:59.680] [INFO ] [S-CLI] - Start ...
    Request url: https://188077086902****.cn-shenzhen.fc.aliyuncs.com/2016-08-15/proxy/tgpu_opencv_service/tgpu_opencv_func/
    ========= FC invoke Logs begin =========
    ...
    ========= FC invoke Logs end =========
    
    FC Invoke Result[code: ${resp.code}]:
    { result: 'CUDA-capable device supported | process image ok!' }
    
    
    End of method: invoke

执行结果

您可通过在浏览器中访问以下域名,查看经过边缘检测处理后的图片:
https://cri-zfen7xhpsx******-registry.oss-cn-shenzhen.aliyuncs.com/cats2.png

本域名仅为示例,需以实际情况为准。