AI-102の勉強のためにGitHubのHandsOnを実施します。
https://github.com/MicrosoftLearning/mslearn-ai-services
https://github.com/MicrosoftLearning/mslearn-ai-vision
https://github.com/MicrosoftLearning/mslearn-ai-language → 本記事はこれ
https://github.com/MicrosoftLearning/mslearn-ai-document-intelligence
https://github.com/MicrosoftLearning/mslearn-knowledge-mining
https://github.com/MicrosoftLearning/mslearn-openai
MSLearnのドキュメントはこちら。
Azure AI サービスを使用して自然言語処理のソリューションを開発する
できるのはこんなこと。
- Azure AI Language
- 概要作成
- テキストから言語を検出する
- テキストのセンチメントを分析する
- キー フレーズ、エンティティ、リンクされたエンティティを抽出する
- Azure AI Translator
- 翻訳
- Azure AI Speech
- 音声対応
等
基本的にそれぞれのサービスでポータルがあり、そこでトレーニングやモデルのデプロイができる感じ。
リソース作成 (Language)
- Question AnsweringにはAI Searchが必要。
- Custom Text ClassificationやSummarizationにはStorage Accountが必要。
Question Answering、質問応答ソリューションの構築
OpenAIを使わないRAGのようなものととらえればよいか。
質問と応答のFAQ集を元に自然言語で回答してくれる。昔のQnAサービスの進化版。
その他にもLUIS(Language Understanding)というのがあるが、LUISはもっと会話寄り。
Question Answer Pairs
Language Studioからプロジェクトを作成し、例えば、データソースにMicrosoft Learnを設定したFAQボットを作ってみる。
Language studioのCustom question answeringから。
データソースはURL、ファイル、おしゃべり(ChitChat)の3種類を選べる。
HandsOnでは、Microsoft LearnのFAQ集をソースに設定してみる。
おしゃべり、というのはMicrosoftがBotにキャラクターを与えるための事前定義済み質問集を指す。Witty、Enthsiastic、Caringとかを選べる。中身を見てみると、こんな感じ。年齢は?とか家族は?とかなんとなくBotに質問してしまいそうな内容がある。こちらも設定してみたところこんな感じになった。自分専用のキャラクターとかも作れそう。
Alternate Questionというので、言い回しが違うけど同じ回答というケースを定義できる。
Follow-up promptで回答に補足をつけることができる。
Follow-upを作ったらEditorialというのが裏にできていて、そこに保存されていた。
Test
テストをしてみると、Wittyに設定したおしゃべりやFollow-up promptが出てくる。
Deploy
このエンドポイントはカスタムアプリからも呼べるし、又はCreate a botボタンからクリック1つでAzure AI Bot Serviceと連携してWeb Botを簡単に作ることができる。
こんな感じで呼び出せる。
curl -X POST "https://{endpoint}.cognitiveservices.azure.com/language/:query-knowledgebases?projectName=LearnFAQ&api-version=2021-10-01&deploymentName=production"
-H "Ocp-Apim-Subscription-Key: {KEY}"
-H "Content-Type: application/json"
-d "{\"top\":3,
\"question\":\"YOUR_QUESTION_HERE\",
\"includeUnstructuredSources\":true,
\"confidenceScoreThreshold\":\"YOUR_SCORE_THRESHOLD_HERE\",
\"answerSpanRequest\":{\"enable\":true,\"topAnswersWithSpan\":1,
\"confidenceScoreThreshold\":\"YOUR_SCORE_THRESHOLD_HERE\"},
\"filters\":{\"metadataFilter\":{\"logicalOperation\":\"YOUR_LOGICAL_OPERATION_HERE\",
\"metadata\":[{\"key\":\"YOUR_ADDITIONAL_PROP_KEY_HERE\",
\"value\":\"YOUR_ADDITIONAL_PROP_VALUE_HERE\"}]}}}"
会話言語理解モデル (Conversational language understanding model)
最初に
AlexaやGoogleHomeのBotみたいに、会話からキーフレーズを抽出するための技術。GPTみたいに汎用的ではないから、会話理解というと言い過ぎな印象を受ける。
こういう流れらしい。GPTでもプロンプトでできそうではあるが、ちゃんとトレーニングできるのがいいところ。
1. アプリが、ユーザーから自然言語入力を受け入れます。
2. 言語モデルを使用してセマンティックの意味 (ユーザーの "意図") を特定します。
3. アプリが、適切なアクションを実行します。
Conversational language understandingを選択。
プロジェクト作成
※なんかこの辺でうまくプロジェクトが作成できないときがあったが、Storage AccountありでLanguageリソースを作り直すとうまくいった。
会話理解には以下の要素がある。
-
入力される会話内容である発話、Utterance
-
実際にやってほしい意図、Intent
-
その意図を理解して何を処理してほしいかを定義する、Entity Component
-
実際にトレーニングされたモデル
作業の順番
①Intentを作る
②IntentにEntityを紐づける
③ModelをDeployする
④IntentにUtteranceの例文を紐づける
Intent
Utterance
Data LabelingからIntentを要求する発話の例を定義してやる。(さっきのQnAに似ている)
GetTimeには"what time is it?"のように。
Model
Testする。意図を理解してくれるから、Utteranceが少し違ってもちゃんと返ってくる。
{
"query": "What time?\n",
"prediction": {
"topIntent": "GetTime",
"projectKind": "Conversation",
"intents": [
{
"category": "GetTime",
"confidenceScore": 0.96072626
},
{
"category": "GetDate",
"confidenceScore": 0.87814885
},
{
"category": "GetDay",
"confidenceScore": 0.79664844
},
{
"category": "None",
"confidenceScore": 0
}
],
"entities": []
}
}
Entity
上記でちゃんと正しいIntentが選択されることがわかった。それでは実際にEntityを紐づけて、データ抽出的なことができるようにしてみる。
Entityの種類は4種類。
- Learned
- List
- Prebuilt
- Regex
Learnedを作ってみる
Data LabelingからGetTimeのIntentに"What time is it in London?" のLondonを選択し、LocationのEntityを追加する。
Listを定義する
Prebuiltを選ぶ
Boolean, DateTime, Email, IPAddress等色々ある。
今回はDateTimeを選択。
※Microsoft Outlookとかで時間が本文に入っているときに会議を自動的に作る機能とかこういう処理が裏でされているのかなと思ったり。
動作確認
Entityを変更した後は、再度トレーニング、再デプロイする。
先ほどのEntityで定義した部分が抽出されている。
{
"query": "what time is it in Tokyo?\n",
"prediction": {
"topIntent": "GetTime",
"projectKind": "Conversation",
"intents": [
{
"category": "GetTime",
"confidenceScore": 0.87871605
},
{
"category": "GetDay",
"confidenceScore": 0.71863574
},
{
"category": "GetDate",
"confidenceScore": 0.7082026
},
{
"category": "None",
"confidenceScore": 0
}
],
"entities": [
{
"category": "Location ",
"text": "Tokyo",
"offset": 19,
"length": 5,
"confidenceScore": 1
}
]
}
}
{
"query": "what's the date on Weds?",
"prediction": {
"topIntent": "GetDate",
"projectKind": "Conversation",
"intents": [
{
"category": "GetDate",
"confidenceScore": 0.9679488
},
{
"category": "GetDay",
"confidenceScore": 0.95016205
},
{
"category": "GetTime",
"confidenceScore": 0.8293059
},
{
"category": "None",
"confidenceScore": 0
}
],
"entities": [
{
"category": "Weekday",
"text": "Weds",
"offset": 19,
"length": 4,
"confidenceScore": 1
},
{
"category": "Date",
"text": "Weds",
"offset": 19,
"length": 4,
"confidenceScore": 1,
"resolutions": [
{
"resolutionKind": "DateTimeResolution",
"dateTimeSubKind": "Date",
"timex": "XXXX-WXX-3",
"value": "2024-04-03"
},
{
"resolutionKind": "DateTimeResolution",
"dateTimeSubKind": "Date",
"timex": "XXXX-WXX-3",
"value": "2024-04-10"
}
],
"extraInformation": [
{
"extraInformationKind": "EntitySubtype",
"value": "datetime.date"
}
]
}
]
}
}
ちょっと面白かったのが、わざとUttenranceやSynonymで定義していない誤字を入れてみてもちゃんと抽出してくれた。ただし、当たり前だけど正しいものに訂正とかはしてくれないみたいだ。
{
"query": "what's the date on Wenedsday?",
"prediction": {
"topIntent": "GetDate",
"projectKind": "Conversation",
"intents": [
{
"category": "GetDate",
"confidenceScore": 0.9753281
},
{
"category": "GetDay",
"confidenceScore": 0.96795267
},
{
"category": "GetTime",
"confidenceScore": 0.8847069
},
{
"category": "None",
"confidenceScore": 0
}
],
"entities": [
{
"category": "Date",
"text": "Wenedsday",
"offset": 19,
"length": 9,
"confidenceScore": 1,
"extraInformation": [
{
"extraInformationKind": "EntitySubtype",
"value": "datetime.date"
}
]
}
]
}
}
アプリから呼び出し
HomeBotとかの開発だと、通信にはSDKを使うため詳細は省略。
curl -X POST "https://{endpoint}.cognitiveservices.azure.com/language/:analyze-conversations?api-version=2022-10-01-preview"
-H "Ocp-Apim-Subscription-Key: {Key}"
-H "Apim-Request-Id: {id}"
-H "Content-Type: application/json"
-d "{\"kind\":\"Conversation\",
\"analysisInput\":{
\"conversationItem\":{
\"id\":\"PARTICIPANT_ID_HERE\",
\"text\":\"YOUR_QUERY_HERE\",
\"modality\":\"text\",
\"language\":\"QUERY_LANGUAGE_HERE\",
\"participantId\":\"PARTICIPANT_ID_HERE\"}},
\"parameters\":{\"projectName\":\"Clock\",
\"verbose\":true,
\"deploymentName\":\"production\",
\"stringIndexType\":\"TextElement_V8\"}}"
流れ的にはIntentsからConfidenceScoreが一番高いものを選択し、それからEntitiesを抽出し、独自のカスタム処理を実施させていく感じになる。
テキストを分類する (Text Classification)
プロジェクト作成
Storage Accountに配置したファイルを分類するため、Storage Accountが必須。
分類先をSingle CategoryとMulti Categoryで選べる。
手動ラベリング
Storage Accountに配置したファイルが表示されるので自分でラベルをつける。この際に、データをテストデータにするかか、トレーニングデータにするかを選べる。
こちらはまだPreviewのようだが、OpenAIで自動的に分類させることもできるみたい。
Training
モデルの精度が表示される。テストデータを使っていて、100%ではない場合、手動でラベリングしたものとモデルの結果が異なるということ。
正しい分類とは、実際のラベルが x のときに、モデルでラベルが x と予測される場合です。 実際には、分類が正しくない場合のドキュメントのエラーにはさまざまな種類があります。
- 擬陽性 - モデルによる予測は x ですが、ファイルには x というラベルが付けられていません。
- 擬陰性 - モデルによる予測はラベル x ではありませんが、ファイルには実際には x というラベルが付けられています。
これらのメトリックは、Azure AI Language によって提供される 3 つのメジャーに変換されます。
-リコール - すべての実際のラベルのうち、識別された数。ラベル付けされたすべてのものに対する真陽性の割合。
-精度 - 予測されたラベルのうち正しいものの数。識別されたすべての陽性に対する真陽性の割合。
-F1 スコア - 各コンポーネントのバランスを最大化するために 1 つのスコアを提供することを目的とした、"リコール" と "精度" の関数
要はリコールは検出率、精度は検出して正確にラベル付けできた割合。
この辺をもとにテストデータを追加して精度を改善していく。
ちなみにTraining後にはStorage Accountにキャッシュ?が作成されていた。
Deploy
curl -X POST "https://{endpoint}.cognitiveservices.azure.com/language/analyze-text/jobs?api-version=2022-10-01-preview"
-H "Ocp-Apim-Subscription-Key: {key}"
-H "Content-Type: application/json"
-d "{\"tasks\":[{\"kind\":\"CustomSingleLabelClassification\",
\"parameters\":{\"projectName\":\"ClassifyLab\",
\"deploymentName\":\"articles\"}}],
\"displayName\":\"CustomTextPortal_CustomSingleLabelClassification\",
\"analysisInput\":{\"documents\":[{\"id\":\"document_CustomSingleLabelClassification\",
\"text\":\"YOUR_DOCUMENT_HERE\",
\"language\":\"YOUR_DOCUMENT_LANGUAGE_HERE\"}]}}"
Test
他のに比べて大分レスポンスがシンプル。
{
"classes": [
{
"category": "News",
"confidenceScore": 0.36
}
]
}
カスタム固有表現認識 (Custom named entity recognition)
テキスト ドキュメントからあらかじめ定義されたエンティティを抽出する。エンティティは、人、場所、物、イベント、スキル、または値。上でやった会話理解とかなり似ている気がする。。。
最初に
Data Labeling
ラベルを作成し、手動で文章の該当部分をピックアップ。
ここではItemForSale、Price、Locationの3つをラベリングしていく。
ちなみに1個だけ手動でやって、それ以外はGPTによるAuto-labelingを使ってみたところちゃんとラベリングされた。ただ結局手動でOKを確定しなくてはいけないらしく、ここをちゃんとしないとTrainingができない。
Training
たまたまかもしれないけどやたらと時間がかかった。。。
Model Performance
- Precision すべての試行された認識に対する成功した表現認識の比率。 高いスコアは、エンティティが認識されている限り、正しくラベル付けされることを意味します。
- Recall ドキュメントの実際のエンティティの数に対する成功した表現認識の比率。 高いスコアは、適切なラベルが割り当てられているかどうかに関係なく、エンティティを適切に検出できたことを意味します
- F1 スコア 単一のスコアリング メトリックを提供する精度とリコールの組み合わせ
要するに、Recallは検出できるかの指標、Precisionは検出できたものが正しくラベル付けされているかということらしい。
これはFalse Positiveとなっていて、普通に回答ミス。70 lbの重さとPriceを勘違いしてしまっている。
こういうデータを元に、必要なトレーニングデータを追加していく。
Deploy
curl -X POST "https://{endpoint}.cognitiveservices.azure.com/language/analyze-text/jobs?api-version=2022-10-01-preview"
-H "Ocp-Apim-Subscription-Key: {key}"
-H "Content-Type: application/json"
-d "{\"tasks\":[{
\"kind\":\"CustomEntityRecognition\",
\"parameters\":{
\"projectName\":\"CustomEntityLab\",
\"deploymentName\":\"AdEntities\",
\"stringIndexType\":\"TextElement_v8\"}}],
\"displayName\":\"CustomTextPortal_CustomEntityRecognition\",
\"analysisInput\":{\"documents\":[{\"id\":\"document_CustomEntityRecognition\",
\"text\":\"YOUR_DOCUMENT_HERE\",
\"language\":\"YOUR_DOCUMENT_LANGUAGE_HERE\"}]}}"
Test
文章を与えると、ItemForSale、Price、Locationを抽出してくれる。
{
"entities": [
{
"text": "Glass L Shaped desk",
"category": "ItemForSale",
"offset": 0,
"length": 19,
"confidenceScore": 0.99
},
{
"text": "$100",
"category": "Price",
"offset": 22,
"length": 4,
"confidenceScore": 1
},
{
"text": "downtown Detroit MI",
"category": "Location",
"offset": 177,
"length": 19,
"confidenceScore": 0.99
}
]
}
Azure AI 翻訳 (Azure AI Translator)
機能は3つ。音訳というのは中々面白い。
- 言語検出
[
{
"language": "ja",
"score": 1.0,
"isTranslationSupported": true,
"isTransliterationSupported": true
}
]
- 翻訳
[
{"translations":
[
{"text": "Hello", "to": "en"},
{"text": "Bonjour", "to": "fr"}
]
}
]
- 表記変換(音訳)
curl -X POST "https://api.cognitive.microsofttranslator.com/transliterate?api-version=3.0&fromScript=Jpan&toScript=Latn"
-H "Ocp-Apim-Subscription-Key: <your-key>"
-H "Ocp-Apim-Subscription-Region: <your-service-region>"
-H "Content-Type: application/json"
-d "[{ 'Text' : 'こんにちは' }]"
[
{
"script": "Latn",
"text": "Kon'nichiwa"
}
]
カスタム翻訳モデル
カスタム翻訳ツールポータルがあるので、こちらでWorkspace, Projectを作成。Domainというのを選べて、業界用語的なところに対応してくれるのかな?
HandsOnがAPIメインでつまらなかったので、こちらにQuickStartをやってみる。
トレーニング
人が翻訳した望ましい翻訳文を英語とドイツ語でアップロードする。その他辞書ファイルとかもアップできるらしい。
Trainingしてみる。
10,000 unique training sentences required.とあり、Trainingだけで60ドル近くかかってしまう、かつ数時間かかるらしい。。
ので、ここはドキュメントからスクショを拝借。BLEUスコアという翻訳の品質を測るスコアがあるらしい。
Deploy
あとはデプロイして、API経由で発行するだけ。
普通にただ翻訳したいだけならこうだが、
https://api.cognitive.microsofttranslator.com/translate?api-version=3.0
[
{"Text":"Where can I find my employee details?"}
]
カスタムモデルを利用して翻訳する場合はCategory IDを付与する必要がある。
Category ID は、WorkspaceID、プロジェクト ラベル、およびカテゴリ コードを連結して作成されます。
https://api.cognitive.microsofttranslator.com/translate?api-version=3.0&to=de&category=a2eb72f9-43a8-46bd-82fa-4693c8b64c3c-TECH
音声
- 音声テキスト変換
- テキスト読み上げ(音声合成)
- Speech Translation
- Speaker Recognition(音声に基づいて個々の話者を認識)
- 意図認識(音声入力の意味論的意味を判断する API)
ちょっと色々機能が多すぎるので、今は記載しない。後で別にまとめるかも。