你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

快速入门:使用多变量异常检测器客户端库

重要

从 2023 年 9 月 20 日开始,将无法创建新的异常检测器资源。 异常检测器服务将于 2026 年 10 月 1 日停用。

开始使用适用于 C# 的异常检测器多变量客户端库。 请按照以下步骤安装软件包并开始使用服务提供的算法。 新的多变量异常检测器 API 使开发人员能够轻松地集成高级 AI 来检测指标组中的异常,且无需机器学习知识或标记的数据。 不同信号之间的依赖关系和相互关联会自动计为关键因素。 这可以帮助你主动防范复杂系统发生故障。

使用适用于 C# 的异常检测器多变量客户端库,以便:

  • 检测一组时序中的系统级异常。
  • 当任何单独的时序都不能告知太多信息时,而你不得不查看所有信号来检测问题。
  • 使用数十到数百种不同类型的传感器对昂贵的物理资产进行预测维护,以测量系统运行状况的各个方面。

库参考文档 | 库源代码 | 包 (NuGet)

先决条件

  • Azure 订阅 - 免费创建订阅
  • .NET Core 的当前版本
  • 拥有 Azure 订阅后,可在 Azure 门户中创建异常检测器资源来获取密钥和终结点。 等待其部署并选择“转到资源”按钮。
    • 需要从创建的资源获取密钥和终结点,以便将应用程序连接到异常检测器 API。 稍后在快速入门中将密钥和终结点粘贴到下方的代码中。 可以使用免费定价层 (F0) 试用该服务,然后再升级到付费层进行生产。

设置

创建存储帐户

多变量异常检测器要求将示例文件存储在 Azure Blob 存储中。

  1. 创建 Azure 存储帐户
  2. 转到“访问控制(标识和访问管理)”,然后选择“添加”以添加角色分配。
  3. 搜索“存储 Blob 数据读取者”角色,突出显示此帐户类型,然后选择“下一步”。
  4. 依次选择“分配对托管标识的访问权限”、“成员”、之前创建的“异常检测器资源”、“查看 + 分配”。

此配置有时可能会有点令人困惑,如果遇到问题,建议查阅我们的 多变量 Jupyter Notebook 示例,该示例更深入地介绍了此过程。

下载示例数据

本快速入门对示例数据 sample_data_5_3000.csv 使用一个文件。 此文件可以从 GitHub 示例数据中下载

还可以通过运行以下命令来下载示例数据:

curl "https://github.com/Azure-Samples/AnomalyDetector/blob/master/sampledata/multivariate/sample_data_5_3000.csv" --output sample_data_5_3000_.csv

将示例数据上传到存储帐户

  1. 转到存储帐户,选择“容器”并新建容器。
  2. 选择“上传”并上传 sample_data_5_3000.csv
  3. 选择上传的数据,并根据需要复制 Blob URL,从而通过几个步骤将其添加到代码示例。

检索密钥和终结点

要成功对异常检测器服务发出调用,需要以下值:

变量名称
ANOMALY_DETECTOR_ENDPOINT 从 Azure 门户检查资源时,可在“密钥和终结点”部分中找到此值。 终结点示例:https://YOUR_RESOURCE_NAME.cognitiveservices.azure.com/
ANOMALY_DETECTOR_API_KEY 从 Azure 门户检查资源时,可在“密钥和终结点”部分中找到 API 密钥值。 可以使用 KEY1KEY2

在 Azure 门户中转到你的资源。 可以在“资源管理”部分找到“终结点和密钥”。 复制终结点和访问密钥,因为在对 API 调用进行身份验证时需要这两项。 可以使用 KEY1KEY2。 始终准备好两个密钥可以安全地轮换和重新生成密钥,而不会导致服务中断。

创建环境变量

为密钥和终结点创建和分配持久环境变量。

setx ANOMALY_DETECTOR_API_KEY "REPLACE_WITH_YOUR_KEY_VALUE_HERE"
setx ANOMALY_DETECTOR_ENDPOINT "REPLACE_WITH_YOUR_ENDPOINT_HERE"

创建新的 .NET Core 应用程序

在控制台窗口(例如 cmd、PowerShell 或 Bash)中,使用 dotnet new 命令创建名为 anomaly-detector-quickstart-multivariate 的新控制台应用。 此命令将创建包含单个 C# 源文件的简单“Hello World”项目:Program.cs

dotnet new console -n anomaly-detector-quickstart-multivariate

将目录更改为新创建的应用文件夹。 可使用以下代码生成应用程序:

dotnet build

生成输出不应包含警告或错误。

...
Build succeeded.
 0 Warning(s)
 0 Error(s)
...

安装客户端库

在应用程序目录中,使用以下命令安装适用于 .NET 的异常检测器客户端库:

dotnet add package Azure.AI.AnomalyDetector --prerelease

从项目目录中,打开 Program.cs 文件,并将其内容替换为以下代码:

using Azure.AI.AnomalyDetector;
using Azure;
using static System.Environment;

internal class Program
{
    private static void Main(string[] args)
    {
        string endpoint = GetEnvironmentVariable("ANOMALY_DETECTOR_ENDPOINT"); 
        string apiKey = GetEnvironmentVariable("ANOMALY_DETECTOR_API_KEY");
        string datasource = "Path-to-sample-file-in-your-storage-account";  // example path:https://docstest001.blob.core.windows.net/test/sample_data_5_3000.csv
        Console.WriteLine(endpoint);
        var endpointUri = new Uri(endpoint);
        var credential = new AzureKeyCredential(apiKey);

        //create client
        AnomalyDetectorClient client = new AnomalyDetectorClient(endpointUri, credential);

        // train
        TimeSpan offset = new TimeSpan(0);
        DateTimeOffset start_time = new DateTimeOffset(2021, 1, 2, 0, 0, 0, offset);
        DateTimeOffset end_time = new DateTimeOffset(2021, 1, 2, 5, 0, 0, offset);
        string model_id = null;
        try
        {
            model_id = TrainModel(client, datasource, start_time, end_time);

            // detect
            end_time = new DateTimeOffset(2021, 1, 2, 1, 0, 0, offset);
            MultivariateDetectionResult result = BatchDetect(client, datasource, model_id, start_time, end_time);
            if (result != null)
            {
                Console.WriteLine(string.Format("Result ID: {0}", result.ResultId.ToString()));
                Console.WriteLine(string.Format("Result summary: {0}", result.Summary.ToString()));
                Console.WriteLine(string.Format("Result length: {0}", result.Results.Count));
                Console.WriteLine(string.Format("Anomalies found: {0}", result.Results.Where(r => r.Value.IsAnomaly).Count()));
            }

            // delete
            DeleteModel(client, model_id);
        }
        catch (Exception e)
        {
            string msg = string.Format("Multivariate error. {0}", e.Message);
            Console.WriteLine(msg);
            throw;
        }

        int GetModelNumber(AnomalyDetectorClient client)
        {
            int model_number = 0;
            foreach (var multivariateModel in client.GetMultivariateModels())
            {
                model_number++;
            }
            return model_number;
        }

        string TrainModel(AnomalyDetectorClient client, string datasource, DateTimeOffset start_time, DateTimeOffset end_time, int max_tryout = 500)
        {
            try
            {
                Console.WriteLine("Training new model...");

                Console.WriteLine(string.Format("{0} available models before training.", GetModelNumber(client)));

                ModelInfo request = new ModelInfo(datasource, start_time, end_time);
                request.SlidingWindow = 200;

                Console.WriteLine("Training new model...(it may take a few minutes)");
                AnomalyDetectionModel response = client.TrainMultivariateModel(request);
                string trained_model_id = response.ModelId;
                Console.WriteLine(string.Format("Training model id is {0}", trained_model_id));

                // Wait until the model is ready. It usually takes several minutes
                ModelStatus? model_status = null;
                int tryout_count = 1;
                response = client.GetMultivariateModel(trained_model_id);
                while (tryout_count < max_tryout & model_status != ModelStatus.Ready & model_status != ModelStatus.Failed)
                {
                    Thread.Sleep(1000);
                    response = client.GetMultivariateModel(trained_model_id);
                    model_status = response.ModelInfo.Status;
                    Console.WriteLine(string.Format("try {0}, model_id: {1}, status: {2}.", tryout_count, trained_model_id, model_status));
                    tryout_count += 1;
                };

                if (model_status == ModelStatus.Ready)
                {
                    Console.WriteLine("Creating model succeeds.");
                    Console.WriteLine(string.Format("{0} available models after training.", GetModelNumber(client)));
                    return trained_model_id;
                }

                if (model_status == ModelStatus.Failed)
                {
                    Console.WriteLine("Creating model failed.");
                    Console.WriteLine("Errors:");
                    try
                    {
                        Console.WriteLine(string.Format("Error code: {0}, Message: {1}", response.ModelInfo.Errors[0].Code.ToString(), response.ModelInfo.Errors[0].Message.ToString()));
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine(string.Format("Get error message fail: {0}", e.Message));
                    }
                }
                return null;
            }
            catch (Exception e)
            {
                Console.WriteLine(string.Format("Train error. {0}", e.Message));
                throw;
            }
        }

        MultivariateDetectionResult BatchDetect(AnomalyDetectorClient client, string datasource, string model_id, DateTimeOffset start_time, DateTimeOffset end_time, int max_tryout = 500)
        {
            try
            {
                Console.WriteLine("Start batch detect...");
                MultivariateBatchDetectionOptions request = new MultivariateBatchDetectionOptions(datasource, 10, start_time, end_time);

                Console.WriteLine("Start batch detection, this might take a few minutes...");
                MultivariateDetectionResult response = client.DetectMultivariateBatchAnomaly(model_id, request);
                string result_id = response.ResultId;
                Console.WriteLine(string.Format("result id is: {0}", result_id));

                // get detection result
                MultivariateDetectionResult resultResponse = client.GetMultivariateBatchDetectionResult(result_id);
                MultivariateBatchDetectionStatus result_status = resultResponse.Summary.Status;
                int tryout_count = 0;
                while (tryout_count < max_tryout & result_status != MultivariateBatchDetectionStatus.Ready & result_status != MultivariateBatchDetectionStatus.Failed)
                {
                    Thread.Sleep(1000);
                    resultResponse = client.GetMultivariateBatchDetectionResult(result_id);
                    result_status = resultResponse.Summary.Status;
                    Console.WriteLine(string.Format("try: {0}, result id: {1} Detection status is {2}", tryout_count, result_id, result_status.ToString()));
                    Console.Out.Flush();
                }

                if (result_status == MultivariateBatchDetectionStatus.Failed)
                {
                    Console.WriteLine("Detection failed.");
                    Console.WriteLine("Errors:");
                    try
                    {
                        Console.WriteLine(string.Format("Error code: {}. Message: {}", resultResponse.Summary.Errors[0].Code.ToString(), resultResponse.Summary.Errors[0].Message.ToString()));
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine(string.Format("Get error message fail: {0}", e.Message));
                    }
                    return null;
                }
                return resultResponse;
            }
            catch (Exception e)
            {
                Console.WriteLine(string.Format("Detection error. {0}", e.Message));
                throw;
            }
        }

        void DeleteModel(AnomalyDetectorClient client, string model_id)
        {
            client.DeleteMultivariateModel(model_id);
            int model_number = GetModelNumber(client);
            Console.WriteLine(string.Format("{0} available models after deletion.", model_number));
        }
 
    }
}

运行应用程序

从应用程序目录使用 dotnet run 命令运行应用程序。

dotnet run

清理资源

如果想要清理并移除 Azure AI 服务订阅,则可以删除资源或资源组。 删除资源组同时也会删除与资源组相关联的任何其他资源。

后续步骤

开始使用适用于 JavaScript 的异常检测器多变量客户端库。 请按照以下步骤安装软件包并开始使用服务提供的算法。 新的多变量异常检测器 API 使开发人员能够轻松地集成高级 AI 来检测指标组中的异常,且无需机器学习知识或标记的数据。 不同信号之间的依赖关系和相互关联会自动计为关键因素。 这可以帮助你主动防范复杂系统发生故障。

使用适用于 JavaScript 的异常检测器多变量客户端库,以便:

  • 检测一组时序中的系统级异常。
  • 当任何单独的时序都不能告知太多信息时,而你不得不查看所有信号来检测问题。
  • 使用数十到数百种不同类型的传感器对昂贵的物理资产进行预测维护,以测量系统运行状况的各个方面。

库参考文档 | 库源代码 | 包 (npm) | 示例代码

先决条件

  • Azure 订阅 - 免费创建订阅
  • 最新版本的 Node.js
  • 拥有 Azure 订阅后,可在 Azure 门户中创建异常检测器资源来获取密钥和终结点。 等待其部署并选择“转到资源”按钮。
    • 需要从创建的资源获取密钥和终结点,以便将应用程序连接到异常检测器 API。 你稍后会在快速入门中将密钥和终结点粘贴到下方的代码中。 可以使用免费定价层 (F0) 试用该服务,然后再升级到付费层进行生产。

设置

创建新的 Node.js 应用程序

在控制台窗口(例如 cmd、PowerShell 或 Bash)中,为应用创建一个新目录并导航到该目录。

mkdir myapp && cd myapp

运行 npm init 命令以使用 package.json 文件创建一个 node 应用程序。

npm init

创建一个名为 index.js 的文件,并导入以下库:`

'use strict'

const fs = require('fs');
const parse = require("csv-parse/lib/sync");
const { AnomalyDetectorClient } = require('@azure/ai-anomaly-detector');
const { AzureKeyCredential } = require('@azure/core-auth');

为资源的 Azure 终结点和密钥创建变量。 为示例数据文件创建另一个变量。

注意

始终可以在两个密钥之间选择一个使用。 这是为了实现安全的密钥轮换。 在本快速入门中,使用第一个密钥。

const apiKey = "YOUR_API_KEY";
const endpoint = "YOUR_ENDPOINT";
const data_source = "YOUR_SAMPLE_ZIP_FILE_LOCATED_IN_AZURE_BLOB_STORAGE_WITH_SAS";

重要

完成后,请记住将密钥从代码中删除,并且永远不要公开发布该密钥。 对于生产来说,请使用安全的方式存储和访问凭据,例如 Azure Key Vault。 有关详细信息,请参阅 Azure AI 服务安全性一文。

若要使用异常检测器多变量 API,需要先训练你自己的模型。 训练数据是一组满足以下要求的多个时间序列:

每个时间序列都应是一个 CSV 文件,该文件有 2 列(且仅有 2 列),“timestamp”和“value”(全部小写)作为标题行。 “timestamp”值应符合 ISO 8601 标准;“value”可为整数,也可为带有任意小数位的小数。 例如:

timestamp
2019-04-01T00:00:00Z 5
2019-04-01T00:01:00Z 3.6
2019-04-01T00:02:00Z 4
... ...

每个 CSV 文件应根据要用于模型训练的不同变量进行命名。 例如,“temperature.csv”和“humidity.csv”。 所有 CSV 文件都应压缩到一个没有任何子文件夹的 zip 文件中。 zip 文件可采用任何所需名称。 zip 文件应上传到 Azure Blob 存储。 为 zip 文件生成 Blob SAS(共享访问签名)URL 后,可使用该 URL 进行训练。 请查看此文档,了解如何从 Azure Blob 存储生成 SAS URL。

安装客户端库

安装 ms-rest-azureazure-ai-anomalydetector NPM 包。 此快速入门中也使用了 csv-parse 库:

npm install @azure/ai-anomaly-detector csv-parse

应用的 package.json 文件将使用依赖项进行更新。

代码示例

这些代码片段展示如何使用适用于 Node.js 的异常检测器客户端库执行以下操作:

验证客户端

使用终结点和凭据实例化 AnomalyDetectorClient 对象。

const client = new AnomalyDetectorClient(endpoint, new AzureKeyCredential(apiKey));

训练模型

构造模型结果

首先,我们需要构造模型请求。 请确保开始时间和结束时间与数据源一致。

const Modelrequest = {
  source: data_source,
  startTime: new Date(2021,0,1,0,0,0),
  endTime: new Date(2021,0,2,12,0,0),
  slidingWindow:200
};

训练新模型

将模型请求传递给异常检测器客户端 trainMultivariateModel 方法。

console.log("Training a new model...")
const train_response = await client.trainMultivariateModel(Modelrequest)
const model_id = train_response.location?.split("/").pop() ?? ""
console.log("New model ID: " + model_id)

若要检查模型训练是否完成,可以跟踪模型的状态:

let model_response = await client.getMultivariateModel(model_id);
let model_status = model_response.modelInfo.status;

while (model_status != 'READY' && model_status != 'FAILED'){
  await sleep(10000).then(() => {});
  model_response = await client.getMultivariateModel(model_id);
  model_status = model_response.modelInfo.status;
}

if (model_status == 'FAILED') {
  console.log("Training failed.\nErrors:");
  for (let error of model_response.modelInfo?.errors ?? []) {
    console.log("Error code: " + error.code + ". Message: " + error.message);
  }
}

console.log("TRAINING FINISHED.");

检测异常

使用 detectAnomalygetDectectionResult 函数确定数据源中是否存在异常。

console.log("Start detecting...");
const detect_request = {
  source: data_source,
  startTime: new Date(2021,0,2,12,0,0),
  endTime: new Date(2021,0,3,0,0,0)
};
const result_header = await client.detectAnomaly(model_id, detect_request);
const result_id = result_header.location?.split("/").pop() ?? "";
let result = await client.getDetectionResult(result_id);
let result_status = result.summary.status;

while (result_status != 'READY' && result_status != 'FAILED'){
  await sleep(2000).then(() => {});
  result = await client.getDetectionResult(result_id);
  result_status = result.summary.status;
}

if (result_status == 'FAILED') {
  console.log("Detection failed.\nErrors:");
  for (let error of result.summary.errors ?? []) {
    console.log("Error code: " + error.code + ". Message: " + error.message)
  }
}
console.log("Result status: " + result_status);
console.log("Result Id: " + result.resultId);

导出模型

注意

Export 命令的作用在于使容器化环境中能够运行 Anomaly Detector 多变量模型。 目前不支持多变量,但将来会添加相关支持。

若要导出训练的模型,请使用 exportModel 函数。

const export_result = await client.exportModel(model_id)
const model_path = "model.zip"
const destination = fs.createWriteStream(model_path)
export_result.readableStreamBody?.pipe(destination)
console.log("New model has been exported to "+model_path+".")

删除模型

若要删除可用于当前资源的现有模型,请使用 deleteMultivariateModel 函数。

client.deleteMultivariateModel(model_id)
console.log("New model has been deleted.")

运行应用程序

在运行应用程序之前,对照完整示例代码检查你的代码,这会很有帮助

在快速入门文件中使用 node 命令运行应用程序。

node index.js

清理资源

如果想要清理并移除 Azure AI 服务订阅,则可以删除资源或资源组。 删除资源组同时也会删除与资源组相关联的任何其他资源。

后续步骤

库参考文档 |库源代码 | 包 (PyPi) |在 GitHub 上查找示例代码

开始使用适用于 Python 的异常检测器多变量客户端库。 请按照以下步骤安装软件包并开始使用服务提供的算法。 新的多变量异常检测器 API 使开发人员能够轻松地集成高级 AI 来检测指标组中的异常,且无需机器学习知识或标记的数据。 不同信号之间的依赖关系和相互关联会自动计为关键因素。 这可以帮助你主动防范复杂系统发生故障。

使用适用于 Python 的异常检测器多变量客户端库,以便:

  • 检测一组时序中的系统级异常。
  • 当任何单独的时序都不能告知太多信息时,而你不得不查看所有信号来检测问题。
  • 使用数十到数百种不同类型的传感器对昂贵的物理资产进行预测维护,以测量系统运行状况的各个方面。

先决条件

设置

安装客户端库。 可使用以下方式安装客户端库:

pip install --upgrade azure.ai.anomalydetector

创建存储帐户

多变量异常检测器要求将示例文件存储在 Azure Blob 存储中。

  1. 创建 Azure 存储帐户
  2. 转到“访问控制(标识和访问管理)”,然后选择“添加”以添加角色分配。
  3. 搜索“存储 Blob 数据读取者”角色,突出显示此帐户类型,然后选择“下一步”。
  4. 依次选择“分配对托管标识的访问权限”、“成员”、之前创建的“异常检测器资源”、“查看 + 分配”。

此配置有时可能会有点令人困惑,如果遇到问题,建议查阅我们的 多变量 Jupyter Notebook 示例,该示例更深入地介绍了此过程。

下载示例数据

本快速入门对示例数据 sample_data_5_3000.csv 使用一个文件。 此文件可以从 GitHub 示例数据中下载

还可以通过运行以下命令来下载示例数据:

curl "https://github.com/Azure-Samples/AnomalyDetector/blob/master/sampledata/multivariate/sample_data_5_3000.csv" --output sample_data_5_3000_.csv

将示例数据上传到存储帐户

  1. 转到存储帐户,选择“容器”并新建容器。
  2. 选择“上传”并上传 sample_data_5_3000.csv
  3. 选择上传的数据,并根据需要复制 Blob URL,从而通过几个步骤将其添加到代码示例。

检索密钥和终结点

要成功对异常检测器服务发出调用,需要以下值:

变量名称
ANOMALY_DETECTOR_ENDPOINT 从 Azure 门户检查资源时,可在“密钥和终结点”部分中找到此值。 终结点示例:https://YOUR_RESOURCE_NAME.cognitiveservices.azure.com/
ANOMALY_DETECTOR_API_KEY 从 Azure 门户检查资源时,可在“密钥和终结点”部分中找到 API 密钥值。 可以使用 KEY1KEY2

在 Azure 门户中转到你的资源。 可以在“资源管理”部分找到“终结点和密钥”。 复制终结点和访问密钥,因为在对 API 调用进行身份验证时需要这两项。 可以使用 KEY1KEY2。 始终准备好两个密钥可以安全地轮换和重新生成密钥,而不会导致服务中断。

创建环境变量

为密钥和终结点创建和分配持久环境变量。

setx ANOMALY_DETECTOR_API_KEY "REPLACE_WITH_YOUR_KEY_VALUE_HERE"
setx ANOMALY_DETECTOR_ENDPOINT "REPLACE_WITH_YOUR_ENDPOINT_HERE"

创建新的 Python 应用程序

  1. 新建名为 sample_multivariate_detect.py 的Python 文件。 然后在你偏好的编辑器或 IDE 中打开该文件。

  2. 将 sample_multivariate_detect.py 的内容替换为以下代码。 需要修改变量 blob_url 的路径。

import time
from datetime import datetime, timezone
from azure.ai.anomalydetector import AnomalyDetectorClient
from azure.core.credentials import AzureKeyCredential
from azure.ai.anomalydetector.models import *

SUBSCRIPTION_KEY =  os.environ['ANOMALY_DETECTOR_API_KEY']
ANOMALY_DETECTOR_ENDPOINT = os.environ['ANOMALY_DETECTOR_ENDPOINT']

ad_client = AnomalyDetectorClient(ANOMALY_DETECTOR_ENDPOINT, AzureKeyCredential(SUBSCRIPTION_KEY))

time_format = "%Y-%m-%dT%H:%M:%SZ"
blob_url = "Path-to-sample-file-in-your-storage-account"  # example path: https://docstest001.blob.core.windows.net/test/sample_data_5_3000.csv

train_body = ModelInfo(
    data_source=blob_url,
    start_time=datetime.strptime("2021-01-02T00:00:00Z", time_format),
    end_time=datetime.strptime("2021-01-02T05:00:00Z", time_format),
    data_schema="OneTable",
    display_name="sample",
    sliding_window=200,
    align_policy=AlignPolicy(
        align_mode=AlignMode.OUTER,
        fill_n_a_method=FillNAMethod.LINEAR,
        padding_value=0,
    ),
)

batch_inference_body = MultivariateBatchDetectionOptions(
       data_source=blob_url,
       top_contributor_count=10,
       start_time=datetime.strptime("2021-01-02T00:00:00Z", time_format),
       end_time=datetime.strptime("2021-01-02T05:00:00Z", time_format),
   )


print("Training new model...(it may take a few minutes)")
model = ad_client.train_multivariate_model(train_body)
model_id = model.model_id
print("Training model id is {}".format(model_id))

## Wait until the model is ready. It usually takes several minutes
model_status = None
model = None

while model_status != ModelStatus.READY and model_status != ModelStatus.FAILED:
    model = ad_client.get_multivariate_model(model_id)
    print(model)
    model_status = model.model_info.status
    print("Model is {}".format(model_status))
    time.sleep(30)
if model_status == ModelStatus.READY:
    print("Done.\n--------------------")
    # Return the latest model id

# Detect anomaly in the same data source (but a different interval)
result = ad_client.detect_multivariate_batch_anomaly(model_id, batch_inference_body)
result_id = result.result_id

# Get results (may need a few seconds)
r = ad_client.get_multivariate_batch_detection_result(result_id)
print("Get detection result...(it may take a few seconds)")

while r.summary.status != MultivariateBatchDetectionStatus.READY and r.summary.status != MultivariateBatchDetectionStatus.FAILED and r.summary.status !=MultivariateBatchDetectionStatus.CREATED:
    anomaly_results = ad_client.get_multivariate_batch_detection_result(result_id)
    print("Detection is {}".format(r.summary.status))
    time.sleep(5)
    
   
print("Result ID:\t", anomaly_results.result_id)
print("Result status:\t", anomaly_results.summary.status)
print("Result length:\t", len(anomaly_results.results))

# See detailed inference result
for r in anomaly_results.results:
    print(
        "timestamp: {}, is_anomaly: {:<5}, anomaly score: {:.4f}, severity: {:.4f}, contributor count: {:<4d}".format(
            r.timestamp,
            r.value.is_anomaly,
            r.value.score,
            r.value.severity,
            len(r.value.interpretation) if r.value.is_anomaly else 0,
        )
    )
    if r.value.interpretation:
        for contributor in r.value.interpretation:
            print(
                "\tcontributor variable: {:<10}, contributor score: {:.4f}".format(
                    contributor.variable, contributor.contribution_score
                )
            )

运行应用程序

在快速入门文件中使用 python 命令运行应用程序。

python sample_multivariate_detect.py

输出

10 available models before training.
Training new model...(it may take a few minutes)
Training model id is 3a695878-a88f-11ed-a16c-b290e72010e0
{'modelId': '3a695878-a88f-11ed-a16c-b290e72010e0', 'createdTime': '2023-02-09T15:34:23Z', 'lastUpdatedTime': '2023-02-09T15:34:23Z', 'modelInfo': {'dataSource': 'https://docstest001.blob.core.windows.net/test/sample_data_5_3000 (1).csv', 'dataSchema': 'OneTable', 'startTime': '2021-01-02T00:00:00Z', 'endTime': '2021-01-02T05:00:00Z', 'displayName': 'sample', 'slidingWindow': 200, 'alignPolicy': {'alignMode': 'Outer', 'fillNAMethod': 'Linear', 'paddingValue': 0.0}, 'status': 'CREATED', 'errors': [], 'diagnosticsInfo': {'modelState': {'epochIds': [], 'trainLosses': [], 'validationLosses': [], 'latenciesInSeconds': []}, 'variableStates': []}}}
Model is CREATED
{'modelId': '3a695878-a88f-11ed-a16c-b290e72010e0', 'createdTime': '2023-02-09T15:34:23Z', 'lastUpdatedTime': '2023-02-09T15:34:55Z', 'modelInfo': {'dataSource': 'https://docstest001.blob.core.windows.net/test/sample_data_5_3000 (1).csv', 'dataSchema': 'OneTable', 'startTime': '2021-01-02T00:00:00Z', 'endTime': '2021-01-02T05:00:00Z', 'displayName': 'sample', 'slidingWindow': 200, 'alignPolicy': {'alignMode': 'Outer', 'fillNAMethod': 'Linear', 'paddingValue': 0.0}, 'status': 'READY', 'errors': [], 'diagnosticsInfo': {'modelState': {'epochIds': [10, 20, 30, 40, 50, 60, 70, 80, 90, 100], 'trainLosses': [1.0493712276220322, 0.5454281121492386, 0.42524269968271255, 0.38019897043704987, 0.3472398854792118, 0.34301353991031647, 0.3219067454338074, 0.3108387663960457, 0.30357857793569565, 0.29986055195331573], 'validationLosses': [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], 'latenciesInSeconds': [0.3412797451019287, 0.25798678398132324, 0.2556419372558594, 0.3165152072906494, 0.2748451232910156, 0.26111531257629395, 0.2571413516998291, 0.257282018661499, 0.2549862861633301, 0.25806593894958496]}, 'variableStates': [{'variable': 'series_0', 'filledNARatio': 0.0, 'effectiveCount': 301, 'firstTimestamp': '2021-01-02T00:00:00Z', 'lastTimestamp': '2021-01-02T05:00:00Z'}, {'variable': 'series_1', 'filledNARatio': 0.0, 'effectiveCount': 301, 'firstTimestamp': '2021-01-02T00:00:00Z', 'lastTimestamp': '2021-01-02T05:00:00Z'}, {'variable': 'series_2', 'filledNARatio': 0.0, 'effectiveCount': 301, 'firstTimestamp': '2021-01-02T00:00:00Z', 'lastTimestamp': '2021-01-02T05:00:00Z'}, {'variable': 'series_3', 'filledNARatio': 0.0, 'effectiveCount': 301, 'firstTimestamp': '2021-01-02T00:00:00Z', 'lastTimestamp': '2021-01-02T05:00:00Z'}, {'variable': 'series_4', 'filledNARatio': 0.0, 'effectiveCount': 301, 'firstTimestamp': '2021-01-02T00:00:00Z', 'lastTimestamp': '2021-01-02T05:00:00Z'}]}}}
Model is READY
Done.
--------------------
10 available models after training.
Get detection result...(it may take a few seconds)
Detection is CREATED
Detection is READY
Result ID:	 70a6cdf8-a88f-11ed-a461-928899e62c38
Result status:	 READY
Result length:	 301
timestamp: 2021-01-02 00:00:00+00:00, is_anomaly: 0    , anomaly score: 0.1770, severity: 0.0000, contributor count: 0   
timestamp: 2021-01-02 00:01:00+00:00, is_anomaly: 0    , anomaly score: 0.3446, severity: 0.0000, contributor count: 0   
timestamp: 2021-01-02 00:02:00+00:00, is_anomaly: 0    , anomaly score: 0.2397, severity: 0.0000, contributor count: 0   
timestamp: 2021-01-02 00:03:00+00:00, is_anomaly: 0    , anomaly score: 0.1270, severity: 0.0000, contributor count: 0   
timestamp: 2021-01-02 00:04:00+00:00, is_anomaly: 0    , anomaly score: 0.3321, severity: 0.0000, contributor count: 0   
timestamp: 2021-01-02 00:05:00+00:00, is_anomaly: 0    , anomaly score: 0.4053, severity: 0.0000, contributor count: 0   
timestamp: 2021-01-02 00:06:00+00:00, is_anomaly: 0    , anomaly score: 0.4371, severity: 0.0000, contributor count: 0   
timestamp: 2021-01-02 00:07:00+00:00, is_anomaly: 1    , anomaly score: 0.6615, severity: 0.3850, contributor count: 5   
	contributor variable: series_3  , contributor score: 0.2939
	contributor variable: series_1  , contributor score: 0.2834
	contributor variable: series_4  , contributor score: 0.2329
	contributor variable: series_0  , contributor score: 0.1543
	contributor variable: series_2  , contributor score: 0.0354

为简洁起见,输出结果已截断。

清理资源

如果你想要清理和删除异常检测器资源,可以删除资源或资源组。 删除资源组同时也会删除与之相关联的任何其他资源。 如果你不再打算使用已创建的环境变量,可能还需要考虑删除环境变量

开始使用适用于 Java 的异常检测器多变量客户端库。 请按照以下步骤操作,以使用服务提供的算法安装软件包。 新的多变量异常检测器 API 使开发人员能够轻松地集成高级 AI 来检测指标组中的异常,且无需机器学习知识或标记的数据。 不同信号之间的依赖关系和相互关联会自动计为关键因素。 这可以帮助你主动防范复杂系统发生故障。

使用适用于 Java 的异常检测器多变量客户端库,以便:

  • 检测一组时序中的系统级异常。
  • 当任何单独的时序都不能告知太多信息时,而你不得不查看所有信号来检测问题。
  • 使用数十到数百种不同类型的传感器对昂贵的物理资产进行预测维护,以测量系统运行状况的各个方面。

库参考文档 | 库源代码 | 包 (Maven) | 示例代码

先决条件

  • Azure 订阅 - 免费创建订阅
  • 最新版本的 Java 开发工具包 (JDK)
  • Gradle 生成工具,或其他依赖项管理器。
  • 拥有 Azure 订阅后,可在 Azure 门户中创建异常检测器资源来获取密钥和终结点。 等待其部署并选择“转到资源”按钮。
    • 需要从创建的资源获取密钥和终结点,以便将应用程序连接到异常检测器 API。 你稍后会在快速入门中将密钥和终结点粘贴到下方的代码中。 可以使用免费定价层 (F0) 试用该服务,然后再升级到付费层进行生产。

设置

创建新的 Gradle 项目

本快速入门使用 Gradle 依赖项管理器。 可在 Maven 中央存储库中找到有关客户端库的详细信息。

在控制台窗口(例如 cmd、PowerShell 或 Bash)中,为应用创建一个新目录并导航到该目录。

mkdir myapp && cd myapp

从工作目录运行 gradle init 命令。 此命令创建 Gradle 的基本生成文件,其中包括 build.gradle.kts,在运行时将使用该文件创建并配置应用程序。

gradle init --type basic

当提示你选择一个 DSL 时,选择 Kotlin

安装客户端库

找到 build.gradle.kts,并使用喜好的 IDE 或文本编辑器将其打开。 然后将以下生成配置复制到其中。 请确保包含项目依赖项。

dependencies {
    compile("com.azure:azure-ai-anomalydetector")
}

创建 Java 文件

为示例应用创建一个文件夹。 在工作目录中运行以下命令:

mkdir -p src/main/java

导航到新文件夹,并创建名为 MetricsAdvisorQuickstarts.java 的文件。 在喜好的编辑器或 IDE 中打开该文件并添加以下 import 语句:

package com.azure.ai.anomalydetector;

import com.azure.ai.anomalydetector.models.*;
import com.azure.core.credential.AzureKeyCredential;
import com.azure.core.http.*;
import com.azure.core.http.policy.*;
import com.azure.core.http.rest.PagedIterable;
import com.azure.core.http.rest.PagedResponse;
import com.azure.core.http.rest.Response;
import com.azure.core.http.rest.StreamResponse;
import com.azure.core.util.Context;
import reactor.core.publisher.Flux;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.ByteBuffer;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

为资源的 Azure 终结点和密钥创建变量。 为示例数据文件创建另一个变量。

注意

始终可以在两个密钥之间选择一个使用。 这是为了实现安全的密钥轮换。 在本快速入门中,使用第一个密钥。

String key = "YOUR_API_KEY";
String endpoint = "YOUR_ENDPOINT";

重要

完成后,请记住将密钥从代码中删除,并且永远不要公开发布该密钥。 对于生产来说,请使用安全的方式存储和访问凭据,例如 Azure Key Vault。 有关详细信息,请参阅 Azure AI 服务安全性一文。

若要使用异常检测器多变量 API,需要先训练你自己的模型。 训练数据是一组满足以下要求的多个时间序列:

每个时间序列都应是一个 CSV 文件,该文件有 2 列(且仅有 2 列),“timestamp”和“value”(全部小写)作为标题行。 “timestamp”值应符合 ISO 8601 标准;“value”可为整数,也可为带有任意小数位的小数。 例如:

timestamp
2019-04-01T00:00:00Z 5
2019-04-01T00:01:00Z 3.6
2019-04-01T00:02:00Z 4
... ...

每个 CSV 文件应根据要用于模型训练的不同变量进行命名。 例如,“temperature.csv”和“humidity.csv”。 所有 CSV 文件都应压缩到一个没有任何子文件夹的 zip 文件中。 zip 文件可采用任何所需名称。 zip 文件应上传到 Azure Blob 存储。 为 zip 文件生成 Blob SAS(共享访问签名)URL 后,可使用该 URL 进行训练。 请查看此文档,了解如何从 Azure Blob 存储生成 SAS URL。

代码示例

这些代码片段展示如何使用适用于 Node.js 的异常检测器客户端库执行以下操作:

验证客户端

使用终结点和凭据实例化 anomalyDetectorClient 对象。

HttpHeaders headers = new HttpHeaders()
    .put("Accept", ContentType.APPLICATION_JSON);

HttpPipelinePolicy authPolicy = new AzureKeyCredentialPolicy("Ocp-Apim-Subscription-Key",
 new AzureKeyCredential(key));
AddHeadersPolicy addHeadersPolicy = new AddHeadersPolicy(headers);

HttpPipeline httpPipeline = new HttpPipelineBuilder().httpClient(HttpClient.createDefault())
    .policies(authPolicy, addHeadersPolicy).build();
// Instantiate a client that will be used to call the service.
HttpLogOptions httpLogOptions = new HttpLogOptions();
httpLogOptions.setLogLevel(HttpLogDetailLevel.BODY_AND_HEADERS);

AnomalyDetectorClient anomalyDetectorClient = new AnomalyDetectorClientBuilder()
    .pipeline(httpPipeline)
    .endpoint(endpoint)
    .httpLogOptions(httpLogOptions)
    .buildClient();

训练模型

构造模型结果和训练模型

首先,我们需要构造模型请求。 请确保开始时间和结束时间与数据源一致。

若要使用异常检测器多变量 API,我们需要在使用检测之前先训练自己的模型。 用于训练的数据是一批时序,每个时序应采用 CSV 文件格式,其中仅包含两列,即“时间戳”和“值”(列名应完全相同) 。 每个 CSV 文件都应该以时序的每个变量命名。 所有时序都应压缩为一个 zip 文件并上传到 Azure Blob 存储,但对于 zip 文件名没有要求。 或者,如果你希望变量名称与 .zip 文件名不同,也可以在 zip 文件中包含一个额外的 meta.json 文件。 当我们生成 blob SAS(共享访问签名)URL 后,就可以使用 zip 文件的 URL 进行训练了。

Path path = Paths.get("test-data.csv");
List<String> requestData = Files.readAllLines(path);
List<TimeSeriesPoint> series = requestData.stream()
    .map(line -> line.trim())
    .filter(line -> line.length() > 0)
    .map(line -> line.split(",", 2))
    .filter(splits -> splits.length == 2)
    .map(splits -> {
        TimeSeriesPoint timeSeriesPoint = new TimeSeriesPoint();
        timeSeriesPoint.setTimestamp(OffsetDateTime.parse(splits[0]));
        timeSeriesPoint.setValue(Float.parseFloat(splits[1]));
        return timeSeriesPoint;
    })
    .collect(Collectors.toList());

Integer window = 28;
AlignMode alignMode = AlignMode.OUTER;
FillNAMethod fillNAMethod = FillNAMethod.LINEAR;
Integer paddingValue = 0;
AlignPolicy alignPolicy = new AlignPolicy()
                                .setAlignMode(alignMode)
                                .setFillNAMethod(fillNAMethod)
                                .setPaddingValue(paddingValue);
String source = "YOUR_SAMPLE_ZIP_FILE_LOCATED_IN_AZURE_BLOB_STORAGE_WITH_SAS";
OffsetDateTime startTime = OffsetDateTime.of(2021, 1, 2, 0, 0, 0, 0, ZoneOffset.UTC);
OffsetDateTime endTime = OffsetDateTime.of(2021, 1, 3, 0, 0, 0, 0, ZoneOffset.UTC);
String displayName = "Devops-MultiAD";

ModelInfo request = new ModelInfo()
                        .setSlidingWindow(window)
                        .setAlignPolicy(alignPolicy)
                        .setSource(source)
                        .setStartTime(startTime)
                        .setEndTime(endTime)
                        .setDisplayName(displayName);
TrainMultivariateModelResponse trainMultivariateModelResponse = anomalyDetectorClient.trainMultivariateModelWithResponse(request, Context.NONE);
String header = trainMultivariateModelResponse.getDeserializedHeaders().getLocation();
String[] substring = header.split("/");
UUID modelId = UUID.fromString(substring[substring.length - 1]);
System.out.println(modelId);

//Check model status until the model is ready
Response<Model> trainResponse;
while (true) {
    trainResponse = anomalyDetectorClient.getMultivariateModelWithResponse(modelId, Context.NONE);
    ModelStatus modelStatus = trainResponse.getValue().getModelInfo().getStatus();
    if (modelStatus == ModelStatus.READY || modelStatus == ModelStatus.FAILED) {
        break;
    }
    TimeUnit.SECONDS.sleep(10);
}

if (trainResponse.getValue().getModelInfo().getStatus() != ModelStatus.READY){
    System.out.println("Training failed.");
    List<ErrorResponse> errorMessages = trainResponse.getValue().getModelInfo().getErrors();
    for (ErrorResponse errorMessage : errorMessages) {
        System.out.println("Error code:  " + errorMessage.getCode());
        System.out.println("Error message:  " + errorMessage.getMessage());
    }
}

检测异常

DetectionRequest detectionRequest = new DetectionRequest().setSource(source).setStartTime(startTime).setEndTime(endTime);
DetectAnomalyResponse detectAnomalyResponse = anomalyDetectorClient.detectAnomalyWithResponse(modelId, detectionRequest, Context.NONE);
String location = detectAnomalyResponse.getDeserializedHeaders().getLocation();
String[] substring = location.split("/");
UUID resultId = UUID.fromString(substring[substring.length - 1]);

DetectionResult detectionResult;
while (true) {
    detectionResult = anomalyDetectorClient.getDetectionResult(resultId);
    DetectionStatus detectionStatus = detectionResult.getSummary().getStatus();;
    if (detectionStatus == DetectionStatus.READY || detectionStatus == DetectionStatus.FAILED) {
        break;
    }
    TimeUnit.SECONDS.sleep(10);
}

if (detectionResult.getSummary().getStatus() != DetectionStatus.READY){
    System.out.println("Inference failed");
    List<ErrorResponse> detectErrorMessages = detectionResult.getSummary().getErrors();
    for (ErrorResponse errorMessage : detectErrorMessages) {
        System.out.println("Error code:  " + errorMessage.getCode());
        System.out.println("Error message:  " + errorMessage.getMessage());
    }
}

导出模型

注意

Export 命令的作用在于使容器化环境中能够运行 Anomaly Detector 多变量模型。 目前不支持多变量,但将来会添加相关支持。

若要导出训练的模型,请使用 exportModelWithResponse

StreamResponse response_export = anomalyDetectorClient.exportModelWithResponse(model_id, Context.NONE);
Flux<ByteBuffer> value = response_export.getValue();
FileOutputStream bw = new FileOutputStream("result.zip");
value.subscribe(s -> write(bw, s), (e) -> close(bw), () -> close(bw));

删除模型

若要删除可用于当前资源的现有模型,请使用 deleteMultivariateModelWithResponse 函数。

Response<Void> deleteMultivariateModelWithResponse = anomalyDetectorClient.deleteMultivariateModelWithResponse(model_id, Context.NONE);

运行应用程序

可使用以下命令生成应用:

gradle build

运行应用程序

在运行它之前,请针对完整的示例代码检查你的代码,这会很有帮助。

使用 run 目标运行应用程序:

gradle run

清理资源

如果想要清理并移除 Azure AI 服务订阅,则可以删除资源或资源组。 删除资源组同时也会删除与资源组相关联的任何其他资源。

后续步骤