Function Computeコンソール、SDK、またはServerless Devsを使用して、GPU高速化インスタンスのベストプラクティスを実行できます。 このトピックでは、Serverless DevsとFunction Computeコンソールを使用して、関数コードを使用してスタイル合成とオブジェクト検出を実行してrawイメージを処理する方法について説明します。 このトピックでは、Pythonを例として使用します。
シナリオと利点
AIアプリケーションの従来のGPUインフラストラクチャでは、さまざまな問題がよく発生します。 これらの問題には、長い構築サイクル、高いO&M複雑性、低いクラスター使用率、および高いコストが含まれます。 Function ComputeのGPU高速化インスタンスは、ユーザーからクラウドベンダーに問題を引き継ぎます。 これにより、基盤となるGPUインフラストラクチャについて心配することなく、ビジネスに集中してビジネス目標を達成できます。
このセクションでは、Function ComputeにGPUアクセラレーションがないインスタンスと比較した、GPUアクセラレーションインスタンスの利点について説明します。
コスト優先AIアプリケーションシナリオ
ビジネス要件に基づいてGPU高速化インスタンスを予約します。 このように、Function ComputeのGPU高速化インスタンスは、自作GPUクラスターよりもはるかに高いコスト効率を提供します。
GPU仮想化テクノロジを使用して、1/2モードまたは排他モードでGPUリソースを使用します。 このようにして、GPU高速化インスタンスをきめ細かく構成できます。
効率優先AIアプリケーションシナリオ
ドライバーとCUDAのバージョン管理、マシンの運用管理、欠陥のあるGPU管理など、GPUクラスターでO&Mを実行することなく、コード開発とビジネス目標に焦点を当てます。
GPU高速化インスタンスの詳細については、「インスタンスタイプとインスタンスモード」をご参照ください。
ニューラルスタイル転送のチュートリアル
NST (Neural style transfer) は、2つの画像をブレンドするために使用される技術である。 このプロセスの間に、コンテンツが一方の画像から抽出され、スタイルが他方の画像から抽出されて、新しい画像が作成される。 次の例では、TensorFlow Hubプリセットモデルを使用して、画像の様式的な合成を完了します。
合成効果
コンテンツ画像 | スタイル画像 | 合成画像 |
あなたが始める前に
一般的な準備
ユーザーエクスペリエンスを最適にするには、DingTalkグループ (ID 11721331) に参加し、次の情報を提供します。
組織名 (会社の名前など) 。
Alibaba CloudアカウントのID。
GPUアクセラレーションインスタンスを使用するリージョン (中国 (深セン) など) 。
携帯電話番号、メールアドレス、DingTalkアカウントなどの連絡先情報。
処理するオーディオおよびビデオリソースを、GPUアクセラレーションインスタンスが配置されているリージョンのObject Storage Service (OSS) バケットにアップロードします。 バケット内のオブジェクトに対する読み取りおよび書き込み権限があることを確認してください。 オーディオおよびビデオリソースをアップロードする方法の詳細については、「オブジェクトのアップロード」をご参照ください。 権限の詳細については、「バケットのACLの変更」をご参照ください。
Serverless Devsを使用したGPUアプリケーションのデプロイ
GPUアクセラレーションインスタンスが存在するリージョンで、次の操作を実行します。
Container Registry Enterprise EditionインスタンスまたはPersonal Editionインスタンスを作成します。 Enterprise Editionインスタンスを作成することを推奨します。 詳細については、「手順1: Container Registry Enterprise Editionインスタンスの作成」をご参照ください。
名前空間とイメージリポジトリを作成します。 詳細については、「手順2: 名前空間の作成」および「手順3: イメージリポジトリの作成」をご参照ください。
Serverless Devsを使用したGPUアプリケーションのデプロイ
プロジェクトを作成します。
s init devsapp/start-fc-custom-container-event-python3.9 -d fc-gpu-prj
次のサンプルコードは、作成されたプロジェクトのディレクトリを示しています。
fc-gpu-prj ├── code │ ├── app.py # Function code. │ └── Dockerfile # Dockerfile: The image Dockerfile that contains the code. ├── README.md └── s.yaml # Project configurations, which specify how the image is deployed in Function Compute
でのイメージのデプロイ方法を指定するプロジェクト設定
プロジェクトディレクトリに移動します。
cd fc-gpu-prj
ビジネス要件に基づいてディレクトリファイルの設定を変更します。
を編集します。Edit thes.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_tf_service internetAccess: true function: name: tgpu_tf_func description: test gpu for tensorflow handler: not-used timeout: 600 caPort: 9000 instanceType: fc.gpu.tesla.1 gpuMemorySize: 8192 cpu: 4 memorySize: 16384 diskSize: 512 runtime: custom-container customContainerConfig: #1. Make sure that the namespace:demo namespace and the repo:gpu-tf-style-transfer_s repository are created in advance in Alibaba Cloud Container Registry. #2. Change the tag from v0.1 to v0.2 when you update the function and run s build && s deploy again. image: registry.cn-shenzhen.aliyuncs.com/demo/gpu-tf-style-transfer_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 from tensorflow import keras from tensorflow.keras import layers from tensorflow.keras.models import Sequential import json import sys import logging import os import matplotlib.pyplot as plt import matplotlib as mpl import numpy as np import os import PIL import tensorflow as tf import pathlib import urllib.request import random class Resquest(BaseHTTPRequestHandler): 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 tensor_to_image(self, tensor): tensor = tensor*255 tensor = np.array(tensor, dtype=np.uint8) if np.ndim(tensor)>3: assert tensor.shape[0] == 1 tensor = tensor[0] return PIL.Image.fromarray(tensor) def load_img(self, path_to_img): max_dim = 512 img = tf.io.read_file(path_to_img) img = tf.image.decode_image(img, channels=3) img = tf.image.convert_image_dtype(img, tf.float32) shape = tf.cast(tf.shape(img)[:-1], tf.float32) long_dim = max(shape) scale = max_dim / long_dim new_shape = tf.cast(shape * scale, tf.int32) img = tf.image.resize(img, new_shape) img = img[tf.newaxis, :] return img def do_style_transfer(self): mpl.rcParams['figure.figsize'] = (12,12) mpl.rcParams['axes.grid'] = False # Use the path of the Object Storage Service (OSS) object in your Alibaba Cloud account. You must have the read and write permissions on the object. # Read the content and style images from your OSS buckets. content_path = tf.keras.utils.get_file(str(random.randint(0,100000000)) + ".jpg", 'https://your_public_oss/c1.png') style_path = tf.keras.utils.get_file(str(random.randint(0,100000000)) + ".jpg",'https://your_public_oss/c2.png') content_image = self.load_img(content_path) style_image = self.load_img(style_path) print("load image ok") import tensorflow_hub as hub hub_model = hub.load('https://hub.tensorflow.google.cn/google/magenta/arbitrary-image-stylization-v1-256/2') # You can package the hub model into an image for loading to accelerate the processing. #hub_model = hub.load('/usr/src/app/style_transfer_model') stylized_image = hub_model(tf.constant(content_image), tf.constant(style_image))[0] print("load model ok") path = "/tmp/" + str(random.randint(0,100000000)) + ".png" self.tensor_to_image(stylized_image).save(path) print("generate stylized image ok") # Use the path of the Object Storage Service (OSS) object in your Alibaba Cloud account. You must have the read and write permissions on the object. # Save the synthesized images to the OSS bucket. self.upload("https://your_public_oss/stylized-image.png" ,path) return "transfer ok" def style_transfer(self): msg = self.do_style_transfer() 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 pong(self): data = {"function":"tf_style_transfer"} self.send_response(200) self.send_header('Content-type', 'application/json') self.end_headers() self.wfile.write(json.dumps(data).encode()) def dispatch(self): mode = self.headers.get('RUN-MODE') if mode == "ping": self.pong() elif mode == "normal": self.style_transfer() else: self.pong() def do_GET(self): self.dispatch() def do_POST(self): self.dispatch() if __name__ == "__main__": host = ("0.0.0.0", 9000) server = HTTPServer(host, Resquest) print("Starting server, listen at: %s:%s" % host) server.serve_forever()
Dockerfileファイルを編集します。
例:
FROM registry.cn-shanghai.aliyuncs.com/serverless_devs/tensorflow:2.7.0-gpu WORKDIR /usr/src/app RUN apt-get update RUN apt-get install -y python3 RUN apt-get install -y python3-pip RUN pip3 install matplotlib RUN pip install tensorflow_hub COPY . . CMD [ "python3", "-u", "/usr/src/app/app.py" ] EXPOSE 9000
イメージを作成します。
s build --dockerfile ./code/Dockerfile
コードをFunction Computeにデプロイします。
s deploy
説明上記のコマンドを繰り返し実行し、サービス名と関数名を変更しない場合は、
use local
コマンドを実行してローカル設定を使用します。プロビジョニング済みインスタンスの設定
s provision put --target 1 --qualifier LATEST
プロビジョニング済みインスタンスの準備ができているかどうかを確認します。
s provision get --qualifier LATEST
current
の値が1の場合、GPUアクセラレーションインスタンスのプロビジョニングモードは準備完了です。 例:[2022-06-21 11:53:19] [INFO] [FC] - Getting provision: tgpu_tf_service.LATEST/tgpu_tf_func helloworld: serviceName: tgpu_tf_service functionName: tgpu_tf_func qualifier: LATEST resource: 188077086902****#tgpu_tf_service#LATEST#tgpu_tf_func target: 1 current: 1 scheduledActions: (empty array) targetTrackingPolicies: (empty array) currentError: alwaysAllocateCPU: true
関数を呼び出します。
オンライン機能バージョンの表示
s invoke FC Invoke Result: {"function": "tf_style_transfer"}
ニューラルスタイルの転送を実行する
s invoke -e '{"method":"GET","headers":{"RUN-MODE":"normal"}}' generate stylized image ok enter upload: https://your_public_oss/stylized-image.png # You can download this file to view the synthesis effect. FC Invoke Result: {"result": "transfer ok"}
GPU高速化インスタンスをリリースします。
s provision put --target 0 --qualifier LATEST
Function Computeコンソールを使用したGPU高速化アプリケーションのデプロイ
イメージを展開します。
Container Registry Enterprise EditionインスタンスまたはContainer Registry Personal Editionインスタンスを作成します。
Enterprise Editionインスタンスを作成することを推奨します。 詳細については、「Container Registry Enterprise Editionインスタンスの作成」をご参照ください。
名前空間とイメージリポジトリを作成します。
詳細については、「Container Registry Enterprise Editionインスタンスを使用してイメージを構築する」トピックの「手順2: 名前空間の作成」および手順3: イメージリポジトリの作成」をご参照ください。
Container Registryコンソールのプロンプトに従って、Dockerで操作を実行します。 次に、前述のサンプルapp.pyとDockerfileをインスタンスイメージリポジトリにプッシュします。 ファイルの詳細については、Serverless Devsを使用してGPUアプリケーションをデプロイする場合、/codeディレクトリのapp.pyおよびDockerfileをご参照ください。
サービスを作成します。 詳細については、「サービスの管理」セクションの「サービスの作成」セクションをご参照ください。
関数を作成します。 詳細については、「カスタムコンテナー関数の作成」をご参照ください。
説明[インスタンスタイプ] に [GPUインスタンス] 、[リクエストハンドラタイプ] に [HTTPリクエストの処理] を選択します。
関数の実行タイムアウト時間を変更します。
管理する機能を見つけてクリックします設定で、アクション列を作成します。
では、環境変数セクションの値を変更します。実行タイムアウト期間をクリックし、保存をクリックします。
説明CPUを使用したトランスコード時間は、デフォルト値の60秒を超えています。 したがって、[実行タイムアウト期間] の値をより大きな値に設定することを推奨します。
プロビジョニングされたGPU高速化インスタンスを設定します。
関数の詳細ページで、自動スケーリングタブをクリックし、ルールの作成をクリックします。
表示されるページで、次のパラメーターを設定してGPUアクセラレーションインスタンスをプロビジョニングし、作成をクリックします。
プロビジョニング済みインスタンスの設定方法の詳細については、「プロビジョニング済みインスタンスと自動スケーリングルールの設定」をご参照ください。
設定が完了したら、プロビジョニングされたGPUアクセラレーションインスタンスの準備ができているかどうかをルールリストで確認できます。 具体的には、Current Reserved Instancesの値が指定されたプロビジョニング済みインスタンスの数であるかどうかを確認します。
cURLを使用して関数をテストします。
関数の詳細ページで、トリガータブでトリガー設定を表示し、トリガーエンドポイントを取得します。
CLIで次のコマンドを実行して、GPUアクセラレーション機能を呼び出します。
オンライン機能バージョンの表示
curl -v "https://tgpu-ff-console-tgpu-ff-console-ajezot****.cn-shenzhen.fcapp.run" {"function": "trans_gpu"}
ニューラルスタイルの転送を実行する
curl "https://tgpu-fu-console-tgpu-se-console-zpjido****.cn-shenzhen.fcapp.run" -H 'RUN-MODE: normal' {"result": "transfer ok"}
Verify the result
ブラウザで次のドメイン名にアクセスして、合成画像を表示できます。
https://cri-zbtsehbrr8******-registry.oss-cn-shenzhen.aliyuncs.com/stylized-image.png
このドメイン名は例として使用されます。 実際のドメイン名が優先されます。
オブジェクト検出のチュートリアル
オブジェクト検出テクノロジを使用して、目的のオブジェクトの長方形の境界線を作成し、複数のオブジェクトが同時に表示されたときにオブジェクトを追跡できます。 オブジェクト検出アプリケーションは、多数の異なるタイプのオブジェクトをマークし、識別するために使用される。 次の例では、OpenCV Deep Neural Network (DNN) を使用してマルチオブジェクト検出を実行します。
検出パフォーマンス
次の表に、検出するオブジェクトのソース画像 (左) と、OpenCV DNNを使用して検出したオブジェクト (右) を示します。 右の図には、検出されたオブジェクトの名前と検出精度も表示されます。
元の画像 | 検出されたオブジェクト |
あなたが始める前に
ユーザーエクスペリエンスを最適にするには、DingTalkグループ (ID 11721331) に参加し、次の情報を提供します。
組織名 (会社の名前など) 。
Alibaba CloudアカウントのID。
GPUアクセラレーションインスタンスを使用するリージョン (中国 (深セン) など) 。
携帯電話番号、メールアドレス、DingTalkアカウントなどの連絡先情報。
GPUアクセラレーションインスタンスが存在するリージョンで、次の操作を実行します。
Container Registry Enterprise EditionインスタンスまたはPersonal Editionインスタンスを作成します。 Enterprise Editionインスタンスを作成することを推奨します。 詳細については、「手順1: Container Registry Enterprise Editionインスタンスの作成」をご参照ください。
名前空間とイメージリポジトリを作成します。 詳細については、「手順2: 名前空間の作成」および「手順3: イメージリポジトリの作成」をご参照ください。
OpenCVをコンパイルします。
OpenCVは、GPUアクセラレーションを使用する前にコンパイルする必要があります。 次の項目では、OpenCVのコンパイル方法について説明します。
(推奨) Dockerを介してコンパイル済みOpenCVを使用します。 ダウンロードアドレス: opencv-cuda-dockerおよびcuda-opencv。
OpenCVを手動でコンパイルします。 詳細については、「コンパイルガイド」をご参照ください。
処理するオーディオおよびビデオリソースを、GPUアクセラレーションインスタンスが配置されているリージョンのObject Storage Service (OSS) バケットにアップロードします。 バケット内のオブジェクトに対する読み取りおよび書き込み権限があることを確認してください。 オーディオおよびビデオリソースをアップロードする方法の詳細については、「オブジェクトのアップロード」をご参照ください。 権限の詳細については、「バケットのACLの変更」をご参照ください。
手順
プロジェクトを作成します。
s init devsapp/start-fc-custom-container-event-python3.9 -d fc-gpu-prj
次のサンプルコードは、作成されたプロジェクトのディレクトリを示しています。
fc-gpu-prj ├── code │ ├── app.py # Function code. │ └── Dockerfile # Dockerfile: The image Dockerfile that contains the code. ├── README.md └── s.yaml # Project configurations, which specify how the image is deployed in Function Compute
でのイメージのデプロイ方法を指定するプロジェクト設定
プロジェクトディレクトリに移動します。
cd fc-gpu-prj
ビジネス要件に基づいて、ディレクトリ内のファイルの構成を変更します。
を編集します。Edit thes.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_object_detect_service internetAccess: true function: name: tgpu_object_detect_func description: test gpu for opencv handler: not-used timeout: 600 caPort: 9000 memorySize: 16384 gpuMemorySize: 8192 instanceType: fc.gpu.tesla.1 runtime: custom-container customContainerConfig: #1. Make sure that the namespace:demo namespace and the repo:gpu-transcoding_s repository are created in advance in Alibaba Cloud Container Registry. #2. Change the tag from v0.1 to v0.2 when you update the function and run s build && s deploy again. image: registry.cn-shenzhen.aliyuncs.com/demo/gpu-object-detect_s:v0.1 codeUri: ./code triggers: - name: httpTrigger type: http config: authType: anonymous methods: - GET
を編集します。Edit theapp.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 Resquest(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): CLASSES = ["background", "aeroplane", "bicycle", "bird", "boat", "bottle", "bus", "car", "cat", "chair", "cow", "diningtable", "dog", "horse", "motorbike", "person", "pottedplant", "sheep", "sofa", "train", "tvmonitor"] COLORS = np.random.uniform(0, 255, size=(len(CLASSES), 3)) print("[INFO] loading model...") prototxt = "/usr/src/app/m.prototxt.txt" model = "/usr/src/app/m.caffemodel" net = cv2.dnn.readNetFromCaffe(prototxt, model) msg = "" mode = "" if not cv2.cuda.getCudaEnabledDeviceCount(): msg = "No CUDA-capable device is detected |" else: msg = "CUDA-capable device supported |" net.setPreferableBackend(cv2.dnn.DNN_BACKEND_CUDA) net.setPreferableTarget(cv2.dnn.DNN_TARGET_CUDA) path = "/tmp/target.png" # Use the path of the OSS object in your Alibaba Cloud account. You must have the read and write permissions on the object. Read the image from your bucket. self.download("https://your_public_oss/a.png", path) image = cv2.imread(path) (h, w) = image.shape[:2] blob = cv2.dnn.blobFromImage(cv2.resize(image, (300, 300)), 0.007843, (300, 300), 127.5) print("[INFO] computing object detections...") net.setInput(blob) detections = net.forward() # loop over the detections for i in np.arange(0, detections.shape[2]): confidence = detections[0, 0, i, 2] if confidence > 0.2: idx = int(detections[0, 0, i, 1]) box = detections[0, 0, i, 3:7] * np.array([w, h, w, h]) (startX, startY, endX, endY) = box.astype("int") cv2.rectangle(image, (startX, startY), (endX, endY), COLORS[idx], 2) x = startX + 10 if startY - 15 < 15 else startX y = startY - 15 if startY - 15 > 15 else startY + 20 label = "{}: {:.2f}%".format(CLASSES[idx], confidence * 100) cv2.putText(image, label, (x, y), cv2.FONT_HERSHEY_SIMPLEX, 0.5, COLORS[idx], 2) print("[INFO] {}".format(label)) cv2.imwrite(path, image) # Use the path of the OSS object in your Alibaba Cloud account. You must have the read and write permissions on the object. Read the image from your bucket. self.upload("https://your_public_oss/target.jpg", 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 pong(self): data = {"function":"object-detection"} self.send_response(200) self.send_header('Content-type', 'application/json') self.end_headers() self.wfile.write(json.dumps(data).encode()) def dispatch(self): mode = self.headers.get('RUN-MODE') if mode == "ping": self.pong() elif mode == "normal": self.core() else: self.pong() def do_GET(self): self.dispatch() def do_POST(self): self.dispatch() if __name__ == '__main__': host = ('0.0.0.0', 9000) server = HTTPServer(host, Resquest) print("Starting server, listen at: %s:%s" % host) server.serve_forever()
Dockerfileファイルを編集します。
例:
FROM registry.cn-shanghai.aliyuncs.com/serverless_devs/opencv-cuda:cuda-10.2-opencv-4.2 WORKDIR /usr/src/app RUN sed -i s@/archive.ubuntu.com/@/mirrors.aliyun.com/@g /etc/apt/sources.list RUN apt-get clean RUN apt-get update --fix-missing RUN apt-get install -y build-essential RUN apt-get install -y python3 COPY . . CMD [ "python3", "-u", "/usr/src/app/app.py" ] EXPOSE 9000
次のファイルをダウンロードし、/codeディレクトリに保存します。
イメージを作成します。
s build --dockerfile ./code/Dockerfile
コードをFunction Computeにデプロイします。
s deploy
説明上記のコマンドを繰り返し実行し、サービス名と関数名を変更しない場合は、
use local
コマンドを実行してローカル設定を使用します。プロビジョニング済みインスタンスの設定
s provision put --target 1 --qualifier LATEST
プロビジョニング済みインスタンスの準備ができているかどうかを確認します。
s provision put --target 1 --qualifier LATEST
current
の値が1の場合、GPUアクセラレーションインスタンスのプロビジョニングモードは準備完了です。 例:[2021-12-07 02:20:55] [INFO] [S-CLI] - Start ... [2021-12-07 02:20:55] [INFO] [FC] - Getting provision: tgpu_object_detect_service.LATEST/tgpu_object_detect_func customContainer-demo: serviceName: tgpu_object_detect_service functionName: tgpu_object_detect_func qualifier: LATEST resource: 188077086902****#tgpu_object_detect_service#LATEST#tgpu_object_detect_func target: 1 current: 1 scheduledActions: (empty array) targetTrackingPolicies: (empty array)
関数を呼び出します。
オンライン機能バージョンの表示
s invoke FC Invoke Result: {"result": "CUDA-capable device supported | process image ok!"}
オブジェクトの検出
s invoke -e '{"method":"GET","headers":{"RUN-MODE":"normal"}}' enter upload: https://your_public_oss/target.jpg # You can download this file to view the inference results. FC Invoke Result: {"result": "CUDA-capable device supported | process image ok!"}
GPU高速化インスタンスをリリースします。
s provision put --target 0 --qualifier LATEST
Verify the result
ブラウザで次のドメイン名にアクセスすると、オブジェクトが検出された後に画像を表示できます。
https://cri-zbtsehbrr8******-registry.oss-cn-shenzhen.aliyuncs.com/target2.jpg
このドメイン名は例として使用されます。 実際のドメイン名が優先されます。