Testverfahren
In diesem Abschnitt werden die Aufgaben beschrieben, die zum Abschließen der Validierung erforderlich sind.
Voraussetzungen
Um die in diesem Abschnitt beschriebenen Aufgaben auszuführen, müssen Sie auf einen Linux- oder macOS-Host zugreifen können, auf dem die folgenden Tools installiert und konfiguriert sind:
Szenario 1 – On-Demand-Inferenz in JupyterLab
-
Kubernetes-Namespace für KI/ML-Inferenz-Workloads erstellen
$ kubectl create namespace inference namespace/inference created
-
Verwenden Sie das NetApp DataOps Toolkit, um ein persistentes Volume für die Daten bereitzustellen, auf denen Sie die Inferenz ausführen.
$ netapp_dataops_k8s_cli.py create volume --namespace=inference --pvc-name=inference-data --size=50Gi Creating PersistentVolumeClaim (PVC) 'inference-data' in namespace 'inference'. PersistentVolumeClaim (PVC) 'inference-data' created. Waiting for Kubernetes to bind volume to PVC. Volume successfully created and bound to PersistentVolumeClaim (PVC) 'inference-data' in namespace 'inference'.
-
Verwenden Sie das NetApp DataOps Toolkit, um einen neuen JupyterLab Workspace zu erstellen. Mounten Sie das persistente Volume, das im vorherigen Schritt mit dem erstellt wurde
--mount- pvc
Option. Weisen Sie mit dem NVIDIA-GPUs dem Workspace nach Bedarf zu-- nvidia-gpu
Option.Im folgenden Beispiel wird das persistente Volume beschrieben
inference-data
Wird im JupyterLab-Workspace-Container unter installiert/home/jovyan/data
. Bei der Verwendung von offiziellen Projekt-Jupyter-Container-Images,/home/jovyan
Wird als oberes Verzeichnis innerhalb der JupyterLab-Weboberfläche dargestellt.$ netapp_dataops_k8s_cli.py create jupyterlab --namespace=inference --workspace-name=live-inference --size=50Gi --nvidia-gpu=2 --mount-pvc=inference-data:/home/jovyan/data Set workspace password (this password will be required in order to access the workspace): Re-enter password: Creating persistent volume for workspace... Creating PersistentVolumeClaim (PVC) 'ntap-dsutil-jupyterlab-live-inference' in namespace 'inference'. PersistentVolumeClaim (PVC) 'ntap-dsutil-jupyterlab-live-inference' created. Waiting for Kubernetes to bind volume to PVC. Volume successfully created and bound to PersistentVolumeClaim (PVC) 'ntap-dsutil-jupyterlab-live-inference' in namespace 'inference'. Creating Service 'ntap-dsutil-jupyterlab-live-inference' in namespace 'inference'. Service successfully created. Attaching Additional PVC: 'inference-data' at mount_path: '/home/jovyan/data'. Creating Deployment 'ntap-dsutil-jupyterlab-live-inference' in namespace 'inference'. Deployment 'ntap-dsutil-jupyterlab-live-inference' created. Waiting for Deployment 'ntap-dsutil-jupyterlab-live-inference' to reach Ready state. Deployment successfully created. Workspace successfully created. To access workspace, navigate to http://192.168.0.152:32721
-
Greifen Sie auf den JupyterLab-Arbeitsbereich über die URL zu, die in der Ausgabe des angegeben ist
create jupyterlab
Befehl. Das Datenverzeichnis stellt das persistente Volume dar, das in den Arbeitsbereich gemountet wurde. -
Öffnen Sie das
data
Verzeichnis erstellen und die Dateien hochladen, auf denen die Inferenz durchgeführt werden soll. Wenn Dateien in das Datenverzeichnis hochgeladen werden, werden sie automatisch auf dem persistenten Volume gespeichert, das in den Arbeitsbereich eingebunden wurde. Um Dateien hochzuladen, klicken Sie wie im folgenden Bild gezeigt auf das Symbol Dateien hochladen. -
Kehren Sie zum Verzeichnis der obersten Ebene zurück und erstellen Sie ein neues Notebook.
-
Fügen Sie dem Notebook den Inferenzcode hinzu. Im folgenden Beispiel wird der Inferenzcode für einen Anwendungsfall der Bilderkennung gezeigt.
-
Fügen Sie Protopia Obfuscation in Ihren Inferenzcode ein. Protopia arbeitet direkt mit Kunden zusammen, um eine anwendungsspezifische Dokumentation bereitzustellen und befindet sich außerhalb des Umfangs dieses technischen Berichts. Das folgende Beispiel zeigt den Inferenzcode für eine Bilderkennung, wobei Protopia obfuscation hinzugefügt wurde.
Szenario 2 – Batch-Inferenz auf Kubernetes
-
Kubernetes-Namespace für KI/ML-Inferenz-Workloads erstellen
$ kubectl create namespace inference namespace/inference created
-
Verwenden Sie das NetApp DataOps Toolkit, um ein persistentes Volume für die Daten bereitzustellen, auf denen Sie die Inferenz ausführen.
$ netapp_dataops_k8s_cli.py create volume --namespace=inference --pvc-name=inference-data --size=50Gi Creating PersistentVolumeClaim (PVC) 'inference-data' in namespace 'inference'. PersistentVolumeClaim (PVC) 'inference-data' created. Waiting for Kubernetes to bind volume to PVC. Volume successfully created and bound to PersistentVolumeClaim (PVC) 'inference-data' in namespace 'inference'.
-
Füllen Sie das neue persistente Volume mit den Daten, auf denen Sie die Inferenz durchführen möchten.
Es gibt verschiedene Methoden zum Laden von Daten auf ein PVC. Wenn Ihre Daten aktuell in einer S3-kompatiblen Objekt-Storage-Plattform wie NetApp StorageGRID oder Amazon S3 gespeichert sind, können Sie verwenden "Funktionen des NetApp DataOps Toolkit S3 Data Mover". Eine weitere einfache Methode ist es, einen JupyterLab-Arbeitsbereich zu erstellen und dann Dateien über die JupyterLab-Webschnittstelle hochzuladen, wie in den Schritten 3 bis 5 im Abschnitt “ beschriebenSzenario 1 – On-Demand-Inferenz in JupyterLab.“
-
Erstellen eines Kubernetes-Jobs für die Batch-Inferenz. Das folgende Beispiel zeigt einen Batch-Inferenzauftrag für einen Anwendungsfall zur Bilderkennung. Dieser Job führt die Inferenz auf jedem Bild in einem Satz von Bildern durch und schreibt Metriken zur Inferenzgenauigkeit.
$ vi inference-job-raw.yaml apiVersion: batch/v1 kind: Job metadata: name: netapp-inference-raw namespace: inference spec: backoffLimit: 5 template: spec: volumes: - name: data persistentVolumeClaim: claimName: inference-data - name: dshm emptyDir: medium: Memory containers: - name: inference image: netapp-protopia-inference:latest imagePullPolicy: IfNotPresent command: ["python3", "run-accuracy-measurement.py", "--dataset", "/data/netapp-face-detection/FDDB"] resources: limits: nvidia.com/gpu: 2 volumeMounts: - mountPath: /data name: data - mountPath: /dev/shm name: dshm restartPolicy: Never $ kubectl create -f inference-job-raw.yaml job.batch/netapp-inference-raw created
-
Bestätigen Sie, dass der Inferenzauftrag erfolgreich abgeschlossen wurde.
$ kubectl -n inference logs netapp-inference-raw-255sp 100%|██████████| 89/89 [00:52<00:00, 1.68it/s] Reading Predictions : 100%|██████████| 10/10 [00:01<00:00, 6.23it/s] Predicting ... : 100%|██████████| 10/10 [00:16<00:00, 1.64s/it] ==================== Results ==================== FDDB-fold-1 Val AP: 0.9491256561145955 FDDB-fold-2 Val AP: 0.9205024466101926 FDDB-fold-3 Val AP: 0.9253013871078468 FDDB-fold-4 Val AP: 0.9399781485863011 FDDB-fold-5 Val AP: 0.9504280149478732 FDDB-fold-6 Val AP: 0.9416473519339292 FDDB-fold-7 Val AP: 0.9241631566241117 FDDB-fold-8 Val AP: 0.9072663297546659 FDDB-fold-9 Val AP: 0.9339648715035469 FDDB-fold-10 Val AP: 0.9447707905560152 FDDB Dataset Average AP: 0.9337148153739079 ================================================= mAP: 0.9337148153739079
-
Fügen Sie Protopia Obfuscation zu Ihren Inferenz Job. Die anwendungsspezifische Anleitung zum Hinzufügen von Protopia-Obfuskation kann direkt aus Protopia gefunden werden, die nicht im Rahmen dieses technischen Berichts liegt. Das folgende Beispiel zeigt einen Batch-Inferenzauftrag für eine Gesichtserkennung Anwendungsfall mit Protopia-Obfuscation, die durch die Verwendung eines ALPHAWERTS von 0.8 hinzugefügt wurde. Bei diesem Job wird die Protopia-Obfuskation vor der Durchführung der Inferenz für jedes Bild in einer Reihe von Bildern angewendet und dann Kenngrößen für die Inferenzgenauigkeit geschrieben.
Wir haben diesen Schritt für ALPHA-Werte 0.05, 0.1, 0.2, 0.4, 0.6, wiederholt. 0.8, 0.9 und 0.95. Die Ergebnisse sehen Sie in "„Vergleich der Genauigkeit bei der Inferenzierung“."
$ vi inference-job-protopia-0.8.yaml apiVersion: batch/v1 kind: Job metadata: name: netapp-inference-protopia-0.8 namespace: inference spec: backoffLimit: 5 template: spec: volumes: - name: data persistentVolumeClaim: claimName: inference-data - name: dshm emptyDir: medium: Memory containers: - name: inference image: netapp-protopia-inference:latest imagePullPolicy: IfNotPresent env: - name: ALPHA value: "0.8" command: ["python3", "run-accuracy-measurement.py", "--dataset", "/data/netapp-face-detection/FDDB", "--alpha", "$(ALPHA)", "--noisy"] resources: limits: nvidia.com/gpu: 2 volumeMounts: - mountPath: /data name: data - mountPath: /dev/shm name: dshm restartPolicy: Never $ kubectl create -f inference-job-protopia-0.8.yaml job.batch/netapp-inference-protopia-0.8 created
-
Bestätigen Sie, dass der Inferenzauftrag erfolgreich abgeschlossen wurde.
$ kubectl -n inference logs netapp-inference-protopia-0.8-b4dkz 100%|██████████| 89/89 [01:05<00:00, 1.37it/s] Reading Predictions : 100%|██████████| 10/10 [00:02<00:00, 3.67it/s] Predicting ... : 100%|██████████| 10/10 [00:22<00:00, 2.24s/it] ==================== Results ==================== FDDB-fold-1 Val AP: 0.8953066115834589 FDDB-fold-2 Val AP: 0.8819580264029936 FDDB-fold-3 Val AP: 0.8781107458462862 FDDB-fold-4 Val AP: 0.9085731346308461 FDDB-fold-5 Val AP: 0.9166445508275378 FDDB-fold-6 Val AP: 0.9101178994188819 FDDB-fold-7 Val AP: 0.8383443678423771 FDDB-fold-8 Val AP: 0.8476311547659464 FDDB-fold-9 Val AP: 0.8739624502111121 FDDB-fold-10 Val AP: 0.8905468076424851 FDDB Dataset Average AP: 0.8841195749171925 ================================================= mAP: 0.8841195749171925
Szenario 3 – NVIDIA Triton Inferenz Server
-
Kubernetes-Namespace für KI/ML-Inferenz-Workloads erstellen
$ kubectl create namespace inference namespace/inference created
-
Verwenden Sie das NetApp DataOps Toolkit, um ein persistentes Volume bereitzustellen, das als Modell-Repository für den NVIDIA Triton Inference Server verwendet werden kann.
$ netapp_dataops_k8s_cli.py create volume --namespace=inference --pvc-name=triton-model-repo --size=100Gi Creating PersistentVolumeClaim (PVC) 'triton-model-repo' in namespace 'inference'. PersistentVolumeClaim (PVC) 'triton-model-repo' created. Waiting for Kubernetes to bind volume to PVC. Volume successfully created and bound to PersistentVolumeClaim (PVC) 'triton-model-repo' in namespace 'inference'.
-
Sie können Ihr Modell auf dem neuen persistenten Volume in einem speichern "Formatieren" Das wird vom NVIDIA Triton Inferenz Server erkannt.
Es gibt verschiedene Methoden zum Laden von Daten auf ein PVC. Eine einfache Methode ist es, einen JupyterLab-Arbeitsbereich zu erstellen und dann Dateien über die JupyterLab-Webschnittstelle hochzuladen, wie in den Schritten 3 bis 5 in “ beschriebenSzenario 1 – On-Demand-Inferenz in JupyterLab. „
-
Verwenden Sie das NetApp DataOps Toolkit, um eine neue NVIDIA Triton Inferenz Server-Instanz zu implementieren.
$ netapp_dataops_k8s_cli.py create triton-server --namespace=inference --server-name=netapp-inference --model-repo-pvc-name=triton-model-repo Creating Service 'ntap-dsutil-triton-netapp-inference' in namespace 'inference'. Service successfully created. Creating Deployment 'ntap-dsutil-triton-netapp-inference' in namespace 'inference'. Deployment 'ntap-dsutil-triton-netapp-inference' created. Waiting for Deployment 'ntap-dsutil-triton-netapp-inference' to reach Ready state. Deployment successfully created. Server successfully created. Server endpoints: http: 192.168.0.152: 31208 grpc: 192.168.0.152: 32736 metrics: 192.168.0.152: 30009/metrics
-
Verwenden Sie ein Triton Client SDK zur Durchführung einer Inferenz. Im folgenden Python-Code-Auszug wird das Triton Python-Client-SDK verwendet, um eine Inferenzaufgabe für einen Anwendungsfall zur Gesichtserkennung durchzuführen. Dieses Beispiel nennt die Triton API und führt ein Bild zur Inferenz durch. Der Triton Inference Server erhält dann die Anfrage, ruft das Modell auf und gibt die Inferenzausgabe als Teil der API-Ergebnisse zurück.
# get current frame frame = input_image # preprocess input preprocessed_input = preprocess_input(frame) preprocessed_input = torch.Tensor(preprocessed_input).to(device) # run forward pass clean_activation = clean_model_head(preprocessed_input) # runs the first few layers ###################################################################################### # pass clean image to Triton Inference Server API for inferencing # ###################################################################################### triton_client = httpclient.InferenceServerClient(url="192.168.0.152:31208", verbose=False) model_name = "face_detection_base" inputs = [] outputs = [] inputs.append(httpclient.InferInput("INPUT__0", [1, 128, 32, 32], "FP32")) inputs[0].set_data_from_numpy(clean_activation.detach().cpu().numpy(), binary_data=False) outputs.append(httpclient.InferRequestedOutput("OUTPUT__0", binary_data=False)) outputs.append(httpclient.InferRequestedOutput("OUTPUT__1", binary_data=False)) results = triton_client.infer( model_name, inputs, outputs=outputs, #query_params=query_params, headers=None, request_compression_algorithm=None, response_compression_algorithm=None) #print(results.get_response()) statistics = triton_client.get_inference_statistics(model_name=model_name, headers=None) print(statistics) if len(statistics["model_stats"]) != 1: print("FAILED: Inference Statistics") sys.exit(1) loc_numpy = results.as_numpy("OUTPUT__0") pred_numpy = results.as_numpy("OUTPUT__1") ###################################################################################### # postprocess output clean_pred = (loc_numpy, pred_numpy) clean_outputs = postprocess_outputs( clean_pred, [[input_image_width, input_image_height]], priors, THRESHOLD ) # draw rectangles clean_frame = copy.deepcopy(frame) # needs to be deep copy for (x1, y1, x2, y2, s) in clean_outputs[0]: x1, y1 = int(x1), int(y1) x2, y2 = int(x2), int(y2) cv2.rectangle(clean_frame, (x1, y1), (x2, y2), (0, 0, 255), 4)
-
Fügen Sie Protopia Obfuscation in Ihren Inferenzcode ein. Die anwendungsspezifische Anleitung zum Hinzufügen von Protopia-Obfuskation kann direkt aus Protopia gefunden werden; dieser Vorgang liegt jedoch außerhalb des Geltungsbereichs dieses technischen Berichts. Das folgende Beispiel zeigt denselben Python-Code, der im vorhergehenden Schritt 5, jedoch mit Protopia Obfuscation hinzugefügt wird.
Beachten Sie, dass die Protopia-Obfuskation auf das Bild angewendet wird, bevor es an die Triton-API übergeben wird. So verlässt das nicht-verschleierte Bild nie die lokale Maschine. Nur das obfuscated Image wird über das Netzwerk übertragen. Dieser Workflow eignet sich für Anwendungsfälle, in denen Daten in einer vertrauenswürdigen Zone erfasst und dann zur Inferenz außerhalb der vertrauenswürdigen Zone weitergeleitet werden müssen. Ohne Protopia Obfuscation ist es nicht möglich, diesen Workflow ohne sensible Daten zu implementieren, die jemals die vertrauenswürdige Zone verlassen.
# get current frame frame = input_image # preprocess input preprocessed_input = preprocess_input(frame) preprocessed_input = torch.Tensor(preprocessed_input).to(device) # run forward pass not_noisy_activation = noisy_model_head(preprocessed_input) # runs the first few layers ################################################################## # obfuscate image locally prior to inferencing # # SINGLE ADITIONAL LINE FOR PRIVATE INFERENCE # ################################################################## noisy_activation = noisy_model_noise(not_noisy_activation) ################################################################## ########################################################################################### # pass obfuscated image to Triton Inference Server API for inferencing # ########################################################################################### triton_client = httpclient.InferenceServerClient(url="192.168.0.152:31208", verbose=False) model_name = "face_detection_noisy" inputs = [] outputs = [] inputs.append(httpclient.InferInput("INPUT__0", [1, 128, 32, 32], "FP32")) inputs[0].set_data_from_numpy(noisy_activation.detach().cpu().numpy(), binary_data=False) outputs.append(httpclient.InferRequestedOutput("OUTPUT__0", binary_data=False)) outputs.append(httpclient.InferRequestedOutput("OUTPUT__1", binary_data=False)) results = triton_client.infer( model_name, inputs, outputs=outputs, #query_params=query_params, headers=None, request_compression_algorithm=None, response_compression_algorithm=None) #print(results.get_response()) statistics = triton_client.get_inference_statistics(model_name=model_name, headers=None) print(statistics) if len(statistics["model_stats"]) != 1: print("FAILED: Inference Statistics") sys.exit(1) loc_numpy = results.as_numpy("OUTPUT__0") pred_numpy = results.as_numpy("OUTPUT__1") ########################################################################################### # postprocess output noisy_pred = (loc_numpy, pred_numpy) noisy_outputs = postprocess_outputs( noisy_pred, [[input_image_width, input_image_height]], priors, THRESHOLD * 0.5 ) # get reconstruction of the noisy activation noisy_reconstruction = decoder_function(noisy_activation) noisy_reconstruction = noisy_reconstruction.detach().cpu().numpy()[0] noisy_reconstruction = unpreprocess_output( noisy_reconstruction, (input_image_width, input_image_height), True ).astype(np.uint8) # draw rectangles for (x1, y1, x2, y2, s) in noisy_outputs[0]: x1, y1 = int(x1), int(y1) x2, y2 = int(x2), int(y2) cv2.rectangle(noisy_reconstruction, (x1, y1), (x2, y2), (0, 0, 255), 4)