Azure Machine Learning ことはじめ（テキスト分析）

Azure の Cognitive Service のうち、テキスト分析を学びます。

Microsoft Learn では、次のコンテンツです。

https://learn.microsoft.com/ja-jp/training/modules/analyze-text-with-text-analytics-service/

Azure のテキスト分析では、次のようなことが可能です。

* 文章の言語 (フランス語や英語など) の検出
* 文章の感情分析を行い、肯定的または否定的かを検出
* 主な要点を示す可能性のあるキーフレーズを抽出
* 文章内のエンティティを識別して分類。 エンティティとは、人物、場所、組織、または日常的な項目 （日付、時刻、数量など)を指します

Microsoft アカウントと Azure のサブスクリプションを用意しておきます。

# 準備

Azure Portal で Cognitive Services のページを開きます。
Cognitive Services には、画像系だけでなく、音声や言語など、様々な認識サービスが用意されています。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/177616/0bde3003-9826-68f5-c42c-c6ae78a34691.png" width=600>

今回は、言語サービスを使用します。「＋作成」を押して、言語サービスを作成します。

作成できたら、左ペインの「キーとエンドポイント」をクリック、キーとエンドポイントページ内のキー１とエンドポイントのURLを控えておきます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/177616/fcf4b92f-807b-02fe-dcdc-266864bc8c49.png" width="600">

# Learn の演習を試す

Microsoft Learn を読み進めると、演習が用意されていますので、これをやってみます。

https://microsoftlearning.github.io/AI-900-AIFundamentals/instructions/04-module-04.html

PowerShell のターミナルを起動し、git コマンドで用意されたプログラムをダウンロードします。

```powershell:git でダウンロード
PS git clone https://github.com/MicrosoftLearning/AI-900-AIFundamentals ai-900
```

ちなみにこのフォルダには、テキスト分析用のサンプルだけでなく、AI-900 で扱うサンプル一式が含まれています。

今回は、「analyze-text.ps1」という Powershell スクリプトを使用します。

# エンドポイントとキーを埋め込む

先頭２行にある $key と $endopoint 変数の定義を書き換えます。

```powershell:analyze-text.ps1
$key="YOUR_KEY"               # ← ここに言語サービスのキー1を入力します
$endpoint="YOUR_ENDPOINT"     # ← ここに言語サービスのエンドポイントを入力します

# Code to call Text Analytics service to analyze sentiment in text
$txt_file = "review1.txt"
```

保存したら、さっそく実行してみます。

```powershell:実行
PS c:\ai-900> .\analyze-text.ps1
***Detecting Language***                                                                
  - Language: English
  - Code: en
  - Score: 0.99


***Finding Key Phrases***
  - Key Phrases: 
     The Royal Hotel
     Good Hotel
     good service
     great location
     Buckingham Palace
     Westminster Abbey
     same group
     West coast
     Michelin Star
     taster menu
     enormous bathroom
     Clean rooms
     staff
     London
     UK
     stay
     courtyard
     restaurant
     part
     plenty
     fish
     kitchen
     lounge
     bedroom


***Analyzing Sentiment***
  - A positive sentiment based on these scores:
    - Positive: 0.97
    - Neutral: 0.03
    - Negative: 0


***Identifying known entities***
  - GOOD Music : https://en.wikipedia.org/wiki/GOOD_Music
  - Hotel : https://en.wikipedia.org/wiki/Hotel
  - The Royal Hotel : https://en.wikipedia.org/wiki/The_Royal_Hotel
  - London : https://en.wikipedia.org/wiki/London
  - Buckingham Palace : https://en.wikipedia.org/wiki/Buckingham_Palace
  - Westminster Abbey : https://en.wikipedia.org/wiki/Westminster_Abbey
  - India : https://en.wikipedia.org/wiki/India
  - West Coast Main Line : https://en.wikipedia.org/wiki/West_Coast_Main_Line
  - Michelin Guide : https://en.wikipedia.org/wiki/Michelin_Guide
```

この analyze-text.ps1 では、１回の実行で言語の特定、フェーズの抽出、感情分析、エンティティの抽出を行います。

ちなみに分析の原文(review1.txt)はこちらです。

> Clean rooms, good service, great location near Buckingham Palace and Westminster Abbey, and so on. We thoroughly enjoyed our stay. The courtyard is very peaceful and we went to a restaurant which is part of the same group and is Indian ( West coast so plenty of fish) with a Michelin Star. We had the taster menu which was fabulous. The rooms were very well appointed with a kitchen, lounge, bedroom and enormous bathroom. Thoroughly recommended.

結果を順番に見ていきます。

> ***Detecting Language***                                                                
>  - Language: English
>  - Code: en
>  - Score: 0.99

言語検出では、英語（Code:en）で、Score は 0.99(=99%)となっていて正しく検出できています。

キーフレーズも、単語の検出がうまくできているようです。

感情分析では、ポジティブが 97% でした。原文は素晴らしい旅行の記録ですので適切といえます。

> ***Analyzing Sentiment***
>   - A positive sentiment based on these scores:
>     - Positive: 0.97
>     - Neutral: 0.03
>     - Negative: 0

エンティティとキーフレーズの違いがよく分かりませんが、エンティティの方が主に名詞がピックアップされているような気がします。

# 日本語文章でテキスト分析を試す

英語の実力は確認できましたので、日本語文章を試してみたいと思います。

## 言語検出

スクリプトを見てみると、10行目で URL を組み立てて、12行目で https://raw.githubusercontent.com に公開されているテキストをダウンロードし、変数 txt に格納しているのが分かります。

```powershell:analyze-text.ps1
05 $txt_file = "review1.txt"
06 if ($args.count -gt 0 -And $args[0] -in ("review1.txt", "review2.txt", "review3.txt", "review4.txt"))
07 {
08     $txt_file = $args[0]
09 }
10 $url = "https://raw.githubusercontent.com/MicrosoftLearning/AI-900-AIFundamentals/main/data/text/reviews/$txt_file"
11 
12 $txt =  (Invoke-webrequest -URI $url).Content
```
この txt 変数の中身が分析対象となっていますので、次のように書き換えます。
```powershell:analyze-text.ps1 改1
05 #$txt_file = "review1.txt"
06 #if ($args.count -gt 0 -And $args[0] -in ("review1.txt", "review2.txt", "review3.txt", "review4.txt"))
07 #{
08 #    $txt_file = $args[0]
09 #}
10 #$url = "https://raw.githubusercontent.com/MicrosoftLearning/AI-900-AIFundamentals/main/data/text/reviews/$txt_file"
11 
12 #$txt =  (Invoke-webrequest -URI $url).Content
13 $txt = "これは日本語文章のテストです。"
```

### 注意点

忘れてはならないのが、UTF-8 でのエンコードです。

Powershell では文字列を内部で UTF-16 で管理しています。変数 txt に代入した日本語も、格納されたタイミングで UTF-16 に変換されて管理されます。

txt を JSON にして変数 data に代入し、30 - 33 行目で Invoke-RestMethod を使って API をコールするのですが、API が受け付けてくれるのは UTF-8 ですので、UTF-16 では正しく受け取ってくれません。

```powershell:analyze-text.ps1
20 $data = @{
21     'documents' = @(
22         @{
23             "id" = "1"
24             "text" = "$txt"
25         }
26     )
27 } | ConvertTo-Json
28 
29 Write-Host("***Detecting Language***")
30 $result = Invoke-RestMethod -Method Post `
31           -Uri "$endpoint/text/analytics/v3.1/languages" `
32           -Headers $headers `
33           -Body $data | ConvertTo-Json -Depth 6
```

このため、下の 29行目のように送信データを UTF-8 でエンコードします。

あと、[Language の説明ページ](https://learn.microsoft.com/en-us/azure/cognitive-services/language-service/language-detection/language-support)にもありますが、現行のバージョンの推測エンジン(2022-10-01)では日本語がうまく検出できないそうです。なので、推測モデルのバージョンを2021-11-20 に指定して実行します。

```powershell:analyze-text.ps1 改2
20 $data = @{
21     'documents' = @(
22         @{
23             "id" = "1"
24             "text" = "$txt"
25         }
26     )
27 } | ConvertTo-Json
28 
29 $data= [System.Text.Encoding]::UTF8.GetBytes($data) # UTF-8 にコンバートする
30 
31 # Uri の文字列にモデルバージョンを指示するコマンドを追加する 
32 Write-Host("***Detecting Language***")
33 $result = Invoke-RestMethod -Method Post `
34           -Uri "$endpoint/text/analytics/v3.1/languages?model-version=2021-11-20" `
35           -Headers $headers `
36           -Body $data | ConvertTo-Json -Depth 6
```

変更ができたら保存して実行してみます。

```powershell:実行結果
PS C:\ai-900> .\analyze-text.ps1
***Detecting Language***
  - Language: Japanese
  - Code: ja
  - Score: 1
```

ちゃんと日本語であると検出できました。

## キーフレーズ検出

キーフレーズ検出でも、先ほどの要領で UTF-8 に変換して API をコールします。
あと、日本語であることを伝えるために、下のコードの 52 行目のように language コードを指定します。

```powershell:analyze-text.ps1 改3
45 # Key Phrases
46 
47 $data = @{
48     'documents' = @(
49         @{
50            "id" = "1"
51             "text" = "$txt"
52             "language" = "ja" # 言語を指定する
53         }
54     )
55 } | ConvertTo-Json
56 
57 $data= [System.Text.Encoding]::UTF8.GetBytes($data) # UTF-8 にコンバートする
58 
59 write-host "`n`n***Finding Key Phrases***"
60 $result = Invoke-RestMethod -Method Post `
61           -Uri "$endpoint/text/analytics/v3.1/keyPhrases" `
62          -Headers $headers `
63           -Body $data | ConvertTo-Json -Depth 6
64
65 $analysis = ($result | ConvertFrom-Json)
66 
67 $keyPhrases = $analysis.documents.keyPhrases
```

編集して保存したら実行します。

```powershell:実行結果
PS C:\ai-900> .\analyze-text.ps1
***Detecting Language***
  - Language: Japanese
  - Code: ja
  - Score: 1


***Finding Key Phrases***
  - Key Phrases: 
     日本語文章
     テスト
```

「日本語文章」と「テスト」が検出できました。

## 感情分析

キーフレーズと全く同じように、UTF-8 へのコンバート、language の指定を行います。

```実行結果（感情分析のみ）
***Analyzing Sentiment***
  - A neutral sentiment based on these scores:
    - Positive: 0.01
    - Neutral: 0.99
    - Negative: 0
```

ナチュラルが 99% となってます。

ポジティブさもネガティブさも検出されず、機能の確認ができません。
感情分析としてはサンプルがよくなかったかもしれません。

そこで変数 txt の値を「メロスは激怒した。」に変えて実行してみます。

```powershell:analyze-text.ps1 改1
10 #$url = "https://raw.githubusercontent.com/MicrosoftLearning/AI-900-AIFundamentals/main/data/text/reviews/$txt_file"
11 
12 #$txt =  (Invoke-webrequest -URI $url).Content
13 $txt = "メロスは激怒した。"
14 
15 $headers = @{}
16 $headers.Add( "Ocp-Apim-Subscription-Key", $key )
17 $headers.Add( "Content-Type","application/json" )
```

「激怒」は強いネガティブワードです。予想通りの結果になるでしょうか。

```実行結果（感情分析のみ）
***Analyzing Sentiment***
  - A negative sentiment based on these scores:
    - Positive: 0
    - Neutral: 0.01
    - Negative: 0.99
```

ネガティブが 99% になりました。

## エンティティ検出

エンティティ検出ですが、英文ならちゃんと検出できますが、日本語ではなにをやっても出力されませんでした。

```実行結果（エンティティのみ）
***Identifying known entities***
```

エンティティ検出は日本語には対応していないのかもしれません。

# 言語スタジオ

ここでは Powershell のサンプルから API を利用する方法を試しましたが、Azure ではテキスト分析用に言語スタジオというサイトが用意されています。

https://language.cognitive.azure.com/

言語検出やキーフレーズなどを、Web 上から試すことができます。
まずはどんなものか体験したい！という方は、こちらを最初に使用する方がいいかもしれません。

# 参考（テキスト分析）

* Language API の仕様
* * https://learn.microsoft.com/ja-jp/rest/api/cognitiveservices-textanalytics/3.0/languages/languages?tabs=HTTP
* 検出できる言語について
* * https://learn.microsoft.com/en-us/azure/cognitive-services/language-service/language-detection/language-support

# 関連記事

* [Azure Machine Learning ことはじめ（Custom Vision による画像分類）](https://qiita.com/tnishiki/items/26d1d3d31f2eeb8a1a2b)
* [Azure Machine Learning ことはじめ（Azure Machine Learning Studio を使ったデータ分類）](https://qiita.com/tnishiki/items/d4df523866683cd6ecf2)
* [Azure Machine Learning ことはじめ（Form Recognizer version 2.1）](https://qiita.com/tnishiki/items/a45d300072928505d9c3)
* [Azure Machine Learning ことはじめ（Form Recognizer version 3.0 2022-08-31版）](https://qiita.com/tnishiki/items/18872e8dc670958528f2)