[料理佳餚] 用 Azure Cognitive Services(認知服務)的 Custom Text Classification(自訂文字分類)來辨識色情廣告

客戶的網站有提供部落格的功能,讓會員可以在上面寫一些文章,經營得算是頗有流量,有流量就容易吸引一些蹭流量的人,色情廣告就是其中之一,目前客戶在色情廣告上的處理仍然是採用人工封鎖的方式,成本高又反應慢,所以打算引入 Azure Cognitive Services(認知服務)的 Custom Text Classification(自訂文字分類),來讓阻擋色情廣告這件事情可以更有效率一些。

原本是想要嘗試用 Content Moderator(內容仲裁)當中的文字分類功能,看看效果好不好?它預設就能偵測三種分類:明顯色情或成人內容具性暗示或成人內容具冒犯性的內容,可惜目前只支援英文,所以改用 Custom Text Classification 自己做資料標記來訓練 AI,產生屬於自己的模型。

建立自訂文字分類服務

首先把資源建立起來,在 Azure 的「AI + 機器學習服務」當中,找到「認知服務」。

點擊進去之後,我們可以看到認知服務底下的各類子服務,找到語言服務後,點擊「建立

在右邊「自訂功能」這一區塊,選取「自訂文字分類和自訂命名實體辨識」,然後點擊「繼續建立您的資源」。

在資源建立的畫面中,必填的欄位有以下這些:

  • 訂用帳戶
  • 資源群組
  • 區域:目前支援自訂文字分類服務的區域只有 10 個,大都在美洲地區,少數在歐洲,澳洲及亞洲地區則各有一個區域。
  • 名稱
  • 定價層
  • 新的/現有的儲存體帳戶:儲存體帳戶是用來存放樣本資料,可以用現有的或是新建一個,我這邊是新建一個給自訂文字分類服務來使用。
  • 核取此方塊代表本人確認已詳閱並知悉「負責任 AI 注意事項」中的相關條款:關於負責任 AI,在 2021 iThome 鐵人賽有一篇文章有做介紹,大家可以移駕過去看一下。

其他頁籤的設定就暫時保持預設值即可,重新檢視一下設定值,沒問題就按下「建立」。

準備資料

再來,我們要來準備餵給 AI 的樣本資料,我們在使用這種內容分類工具的時候,要先有一個認知,就是說我們要分類的內容要有一定的鑑別度,這樣子訓練出來的模型,跑出來的信賴度會比較高。

反之,比如說最近求職詐騙很猖獗,如果我們本身是做求職刊登服務的網站,那我們要訓練 AI 分類出求職詐騙的刊登內容,那個訓練出來的模型的信賴度就不會太漂亮,誤判率會提高,因為正常的刊登內容與詐騙的刊登內容差別不大,所以說我們要讓 AI 訓練出來的模型是可信的,那麼在一開始的資料整理跟分析就不能隨便。

我從客戶那邊針對色情廣告及正常文章各整理了 100 個樣本,我們在儲存體帳戶建立容器之後,就把這些樣本上傳到容器內。

Language Studio

Azure 有一個工具 - Language Studio,它提供了 GUI 的介面,方便我們使用語言相關的認知服務,我們用 Azure 的帳號就可以直接登入了。

登入之後,先要連結一個語言資源,這邊就選擇我們剛剛建立的語言資源。

將畫面往下捲,我們可以看到一個「Custom text classification」,點進去之後我們要先建立一個「Project」。

建立專案的步驟其實就是一直下一步,把必填的欄位填一填就能建立成功了,其中要特別說明的是在「Select project type」這個步驟,我要訓練的模型是要能分類出來色情廣告跟正常文章,就這兩個類別而已,所以我選擇「Single label classification」,一份資料一個類別。

如果我們訓練出來的模型要能針對一份資料分類出來多個類別,就要選擇「Multi label classification」,但是相對地,在做資料標記的時候就會比較辛苦一些。

資料標記(Data labeling)

專案建立好後,接下來要進入的是資料標記(Data labeling)的階段,從下面的畫面已經可以看到我們上傳的樣本資料,我們先點擊「Add class」建立類別,這邊要注意的是,樣本資料至少要 10 份,類別至少要 2 組。

標記資料的方式就是把資料選取起來,然後點選一個右手邊的類別,最後按下「Save labels」,過程中我們還可以透過關鍵字過濾器來篩選樣本資料。

訓練模型(Training)

資料都標記好分類之後,下一步是要訓練 AI 產生我們要的模型,其中 Data splitting 的部分,就是說要拿樣本資料的多少比例來訓練模型?多少比例來做模型的測試?微軟也已經設好建議的預設值 80% for traning20% for testing,那當然我們也可以按照需求自己來調整,在所有參數都設定完後,按下「Train」就開始了。

部署模型(Deploying)

模型訓練完成後,再來就是要進行部署,點擊「Add deployment」,填入部署名稱,選擇剛剛訓練好的模型,按下「Deploy」就可以了。

測試模型(Testing)

模型部署後,我們就可以再拿樣本資料以外的資料,來測試看看模型的信賴度如何?那這邊我拿一篇色情廣告來跑跑看,選擇我們剛剛部署的模型,貼上要測試的資料內容,按下「Run the test」,結果顯示分類是 porn,可信度 100%。

我再拿一篇正常文章來測試,結果顯示分類是 normal,可信度 95%。

這樣的結果其實還算可以,後續要再多拿一些資料來測試,看誤判率高不高?可信度能不能接受?如果不滿意的話,就從準備資料開始,重新跑一次訓練模型的流程,直到滿意為止。

REST API

除了 Language Studio 提供的介面讓我們用來分析資料之外,還有其他兩種方式,第一種是呼叫 REST API,在部署模型的介面當中,選取其中一個部署,點擊「Get prediction URL」,可以找到 curl 的範例,從範例中我們就能知道發送 HTTP Request 需要的資訊。

下面我就用 C# 搭配 HttpClient,來撰寫發送資料分析的程式,其中有幾個參數需要說明一下。

  • Ocp-Apim-Subscription-Key:這個是我們的金鑰,在資源管理介面中的金鑰與端點裡面可以找得到,就連端點也在裡面。
  • api-version:API 的版本關乎到有支援的服務,這個在官方文件 Model lifecycle 裡面找得到,而自訂文字分類服務的 API 版本是 2022-05-01
  • Language:這個要填入 Language Code,繁體中文是 zh-hant

完整程式碼如下:

var client = new HttpClient
             {
                 BaseAddress = new Uri("https://cog-ctc-mytest.cognitiveservices.azure.com")
             };

client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", "my-subscription-key");

var analysisRequest = new HttpRequestMessage(HttpMethod.Post, "/language/analyze-text/jobs?api-version=2022-05-01");

var content = JsonSerializer.Serialize(
    new
    {
        DisplayName = "my-display-name",
        AnalysisInput = new { Documents = new[] { new { Id = "my-id", Language = "zh-Hant", Text = File.ReadAllText(@"D:\Downloads\my-data\test\268763.txt") } } },
        Tasks = new[]
                {
                    new
                    {
                        Kind = "CustomSingleLabelClassification",
                        Parameters = new { ProjectName = "porn-classification", DeploymentName = "article-classification" }
                    }
                }
    },
    new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase });

analysisRequest.Content = new StringContent(content, Encoding.UTF8, "application/json");

var analysisResponse = await client.SendAsync(analysisRequest);

然後,我們就會發現收到的 Response 的 Status Code 是 202,而不是我們常見的 200,Content 也是空的,這是因為整個分析作業是非同步的,我們必須藉由 Response Headers 中的 operation-location 來取得分析結果。

var operationLocation = new Uri(analysisResponse.Headers.GetValues("operation-location").First());

var resultRequest = new HttpRequestMessage(HttpMethod.Get, operationLocation.PathAndQuery);

var resultResponse = await client.SendAsync(resultRequest);

var resultContent = await resultResponse.Content.ReadAsStringAsync();

由於是非同步作業的關係,沒有人知道它何時會分析好?所以我們必須輪詢 operation-location,直到看到 statussucceeded 時,才會得到我們要的分析結果。

Azure.AI.TextAnalytics

第二種分析資料的方式是使用 Azure.AI.TextAnalytics 這個套件,但是要注意的是目前這個時間點必須使用 beta 版本才有支援 SingleLabelClassifyAction,對於這點如果有顧慮的朋友就自行斟酌。

var client = new TextAnalyticsClient(new Uri("https://cog-ctc-mytest.cognitiveservices.azure.com"), new AzureKeyCredential("my-subscription-key"));

var documents = new List<TextDocumentInput>
                {
                    new TextDocumentInput("my-id", File.ReadAllText(@"D:\Downloads\my-data\test\268786.txt"))
                    {
                        Language = "zh-hant"
                    }
                };

var singleLabelClassifyAction = new SingleLabelClassifyAction("porn-classification", "article-classification");

var actions = new TextAnalyticsActions()
              {
                  SingleLabelClassifyActions = new List<SingleLabelClassifyAction> { singleLabelClassifyAction }
              };

var operation = await client.StartAnalyzeActionsAsync(documents, actions);

await operation.WaitForCompletionAsync();

await foreach (AnalyzeActionsResult operationResults in operation.Value)
{
    var actionResults = operationResults.SingleLabelClassifyResults;

    foreach (var actionResult in actionResults)
    {
        foreach (var documentResult in actionResult.DocumentsResults)
        {
            var classification = documentResult.ClassificationCategories.First();

            Console.WriteLine($"Category: \"{classification.Category}\", Confidence {classification.ConfidenceScore:P}.");
        }
    }
}

身處在這個科技時代,不知道是幸或不幸,我們常聽到一句俗話「做自己力所能及的事」,在 30 年前要用 AI 做這種文字分析的工作,不是一件容易的事情,但是時序到了現在,只要滑鼠點一點,再寫個幾行程式碼就有了,事情變得容易了,力所能及的事也跟著變多了,想要跟其他人競爭,就不能說不會了,那麼以上的內容就分享給大家,希望對有需求的朋友能夠有一點幫助。

參考資料

相關資源

C# 指南
ASP.NET 教學
ASP.NET MVC 指引
Azure SQL Database 教學
SQL Server 教學
Xamarin.Forms 教學