目次
Amazon Mechanical Turk v2.0 完全ガイド 2026
概要
Amazon Mechanical Turk(MTurk) は、世界中のワーカーにヒューマンインテリジェンスタスク(HIT)を分散実行させるクラウドソーシングプラットフォームです。画像ラベリング・テキスト分類・データ検証・コンテンツモデレーション・アンケート等の AI が苦手なタスクを、小額報酬で大規模に並列処理。AWS SageMaker Ground Truth と統合し、機械学習訓練データの効率的作成・品質管理を実現します。2024-2026年に AI アシスト・品質スコア・プライベートワーカープール対応を拡張。
解決する課題
大規模データラベリングの低コスト化
- ML モデル訓練には数百万件のラベル付きデータが必須だが、社内スタッフだけでは対応不可能、MTurk で 1 件 $0.01-0.50 の低コストで実現
スケーラブルな人的リソース
- ピーク時のみ処理能力を増やす必要があるが、採用・契約不要で オンデマンドにワーカーを増員可能
品質管理の自動化
- 複数ワーカーの回答を多数決・ゴールデンデータセット検証で品質を数値化・統計管理
SageMaker と統合
- SageMaker Ground Truth でラベリングワークフローを自動化、MTurk ワーカーを直接プール化
グローバル多言語対応
- 190+ 国のワーカー、175+ 言語で多言語テキスト処理・翻訳タスク実行可能
アーキテクチャ全体
Requester(依頼者) ← EC2 / Lambda / SageMaker
↓ HIT 作成・承認・支払い
┌─────────────────────────────────────────────────────────┐
│ Amazon Mechanical Turk │
│ │
│ Marketplace(HIT 公開) │
│ ├─ HIT 閲覧・検索(ワーカー向け) │
│ ├─ 資格フィルター(Master Worker・カスタム) │
│ └─ リアルタイム報酬表示 │
│ │
│ Assignment Management │
│ ├─ Worker が HIT を選択・実行 │
│ ├─ 複数 Worker の多数決(品質向上) │
│ └─ 回答の自動集約・統計分析 │
│ │
│ Quality Control │
│ ├─ ゴールデンデータセット(既知正解)検証 │
│ ├─ Worker 承認率追跡 │
│ ├─ 異常検出(外れ値除外) │
│ └─ Worker 評判スコア(Tier)管理 │
│ │
│ SageMaker Ground Truth Integration │
│ ├─ Active Learning(ML で難しいサンプル自動選出) │
│ ├─ 自動ラベリング(ML モデル予測) │
│ └─ Consolidation(複数回答の最終判定) │
└─────────────────────────────────────────────────────────┘
↑ HIT 回答受け取り・支払い
Worker(ワーカー) ← MTurk Marketplace
コアコンセプト詳細
1. HIT(Human Intelligence Task)
1 つの作業単位。例:「この画像に犬が映っているか?」
{
"Title": "画像分類:動物の種類",
"Description": "表示された画像に映っている動物を分類してください。",
"Keywords": "image, animal, labeling, classification",
"Reward": "0.05",
"AssignmentDurationInSeconds": 300,
"LifetimeInSeconds": 604800,
"MaxAssignments": 3,
"AutoApprovalDelayInSeconds": 86400,
"QualificationRequirements": [
{
"QualificationTypeId": "00000000000000000040",
"Comparator": "GreaterThanOrEqualTo",
"IntegerValues": [95],
"RequiredToPreview": false
}
],
"Question": "..."
}
2. HITType(HIT テンプレート)
同一設定の HIT をバルク作成する際のテンプレート。
# HITType 作成(テンプレート)
aws mturk create-hit-type \
--title "テキスト感情分類(日本語)" \
--description "日本語テキストの感情をポジティブ/ネガティブ/中立に分類" \
--reward "0.10" \
--assignment-duration-in-seconds 600 \
--lifetime-in-seconds 1209600 \
--auto-approval-delay-in-seconds 86400 \
--keywords "text, sentiment, classification, japanese"
# HITType ID: 3GSNXQ1GGGH6I2LM4JX2
# テンプレートベースで HIT 作成(バルク)
for image_url in "${IMAGE_URLS[@]}"; do
aws mturk create-hit \
--hit-type-id 3GSNXQ1GGGH6I2LM4JX2 \
--question "<HTMLQuestion>...</HTMLQuestion>" \
--max-assignments 3
done
3. Assignment(アサイン)
1 つの HIT に対する 1 ワーカーの実行単位。
# Assignment の取得
import boto3
import xml.etree.ElementTree as ET
mturk = boto3.client('mturk', region_name='us-east-1')
response = mturk.list_assignments_for_hit(
HITId='3J53R25CBDO6QS3CKXPL7CUF5CVVCS',
AssignmentStatuses=['Submitted'], # Submitted / Approved / Rejected
MaxResults=100
)
for assignment in response['Assignments']:
assignment_id = assignment['AssignmentId']
worker_id = assignment['WorkerId']
submit_time = assignment['SubmitTime']
# XML 回答をパース
answer_xml = assignment['Answer']
root = ET.fromstring(answer_xml)
ns = {
'ns': 'http://mechanicalturk.amazonaws.com/AWSMechanicalTurkDataSchemas/2005-10-01/QuestionFormAnswers.xsd'
}
answers = {}
for answer_elem in root.findall('.//ns:Answer', ns):
question_id = answer_elem.find('ns:QuestionIdentifier', ns).text
answer_value = answer_elem.find('ns:FreeText', ns).text
answers[question_id] = answer_value
print(f"Worker {worker_id}: {answers}")
# 品質チェック
if is_quality_answer(answers):
mturk.approve_assignment(AssignmentId=assignment_id)
else:
mturk.reject_assignment(
AssignmentId=assignment_id,
RequesterFeedback='回答品質が不足しています。'
)
4. Qualification(資格)
ワーカーの能力・信頼性を示す認定。
# カスタム Qualification Type 作成
aws mturk create-qualification-type \
--name "日本語 NLP 専門家" \
--description "日本語テキスト処理タスクに精通したワーカー認定" \
--status Active \
--test-duration-in-seconds 600 \
--test '<QuestionForm>...</QuestionForm>' \
--answer-key '<AnswerKey>...</AnswerKey>'
# Qualification ID: 3MEBMRFH2YLE8QA0G2EH1YEI
# 既存ワーカーに Qualification を付与
aws mturk associate-qualification-with-worker \
--qualification-type-id 3MEBMRFH2YLE8QA0G2EH1YEI \
--worker-id A3R2QQ8B7X9Q8C \
--integer-value 95 # スコア(0-100)
システム提供の Qualification:
- Master: 承認率 98% 以上・10,000+ HIT 完了のトップワーカー
- Locale: 特定国(日本・米国等)在住ワーカー
- PHR: 認定トレーニング完了ワーカー(2026 新規)
Python での HIT 作成・管理
import boto3
import json
import time
from datetime import datetime
class MTurkDataLabeler:
def __init__(self, environment='sandbox'):
"""
MTurk クライアント初期化
Args:
environment: 'sandbox' (テスト) / 'production' (本番)
"""
endpoint = (
'https://mturk-requester-sandbox.us-east-1.amazonaws.com'
if environment == 'sandbox'
else 'https://mturk-requester.us-east-1.amazonaws.com'
)
self.mturk = boto3.client('mturk', region_name='us-east-1', endpoint_url=endpoint)
self.sagemaker = boto3.client('sagemaker', region_name='us-east-1')
self.dynamodb = boto3.resource('dynamodb')
def create_image_labeling_hit(
self,
hit_type_id: str,
image_urls: list,
max_assignments: int = 3
):
"""画像ラベリング HIT バルク作成"""
created_hits = []
for idx, image_url in enumerate(image_urls):
# HTML フォーム生成(ラベリング UI)
question_html = f"""
<HTMLQuestion xmlns="http://mechanicalturk.amazonaws.com/AWSMechanicalTurkDataSchemas/2011-11-11/HTMLQuestion.xsd">
<HTMLContent><![CDATA[
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Image Labeling Task</title>
<style>
body {{ font-family: Arial; margin: 20px; }}
img {{ max-width: 600px; border: 1px solid #ccc; }}
.form-group {{ margin: 15px 0; }}
label {{ display: block; margin: 5px 0; }}
input[type="radio"] {{ margin-right: 5px; }}
</style>
</head>
<body>
<h2>Image Classification Task</h2>
<p><strong>Task {idx + 1} of {len(image_urls)}</strong></p>
<img src="{image_url}" alt="Image to classify">
<div class="form-group">
<p><strong>What is the main object in this image?</strong></p>
<label><input type="radio" name="object" value="cat"> Cat</label>
<label><input type="radio" name="object" value="dog"> Dog</label>
<label><input type="radio" name="object" value="other"> Other Animal</label>
<label><input type="radio" name="object" value="none"> No Animal</label>
</div>
<div class="form-group">
<p><strong>Confidence Level:</strong></p>
<label><input type="radio" name="confidence" value="high"> High</label>
<label><input type="radio" name="confidence" value="medium"> Medium</label>
<label><input type="radio" name="confidence" value="low"> Low</label>
</div>
<input type="hidden" name="image_url" value="{image_url}">
</body>
</html>
]]></HTMLContent>
<FrameHeight>600</FrameHeight>
</HTMLQuestion>
"""
try:
response = self.mturk.create_hit(
HITTypeId=hit_type_id,
MaxAssignments=max_assignments,
Question=question_html,
LifetimeInSeconds=604800 # 7 日間有効
)
hit_id = response['HIT']['HITId']
created_hits.append({
'image_url': image_url,
'hit_id': hit_id,
'created_time': datetime.now().isoformat()
})
print(f"✓ HIT created: {hit_id} for {image_url}")
except Exception as e:
print(f"✗ Failed to create HIT for {image_url}: {str(e)}")
return created_hits
def get_hit_results(self, hit_id: str):
"""HIT の回答を取得・集約"""
response = self.mturk.list_assignments_for_hit(
HITId=hit_id,
AssignmentStatuses=['Submitted', 'Approved'],
MaxResults=100
)
results = {
'hit_id': hit_id,
'total_assignments': len(response['Assignments']),
'answers': [],
'consensus': {}
}
# 回答を解析
import xml.etree.ElementTree as ET
ns = {
'ns': 'http://mechanicalturk.amazonaws.com/AWSMechanicalTurkDataSchemas/2005-10-01/QuestionFormAnswers.xsd'
}
object_votes = {}
confidence_votes = {}
for assignment in response['Assignments']:
answer_xml = assignment['Answer']
root = ET.fromstring(answer_xml)
answer_dict = {}
for answer_elem in root.findall('.//ns:Answer', ns):
question_id = answer_elem.find('ns:QuestionIdentifier', ns).text
answer_value = answer_elem.find('ns:FreeText', ns).text
answer_dict[question_id] = answer_value
results['answers'].append({
'worker_id': assignment['WorkerId'],
'answer': answer_dict,
'submit_time': assignment['SubmitTime'].isoformat(),
'assignment_id': assignment['AssignmentId']
})
# 投票集計(多数決)
obj = answer_dict.get('object')
if obj:
object_votes[obj] = object_votes.get(obj, 0) + 1
conf = answer_dict.get('confidence')
if conf:
confidence_votes[conf] = confidence_votes.get(conf, 0) + 1
# コンセンサス決定(最多票)
if object_votes:
results['consensus']['object'] = max(object_votes, key=object_votes.get)
results['consensus']['object_agreement'] = object_votes[results['consensus']['object']] / len(response['Assignments'])
if confidence_votes:
results['consensus']['confidence'] = max(confidence_votes, key=confidence_votes.get)
return results
def approve_assignments_by_quality(
self,
hit_id: str,
golden_dataset: list, # [{'object': 'cat', ...}]
approval_threshold: float = 0.66
):
"""品質チェック後に Assignment を自動承認"""
results = self.get_hit_results(hit_id)
approved_count = 0
rejected_count = 0
for answer_data in results['answers']:
assignment_id = answer_data['assignment_id']
answer = answer_data['answer']
# ゴールデンデータセット(既知正解)と比較
matches = 0
for golden in golden_dataset:
if answer.get('object') == golden['object']:
matches += 1
break
accuracy = matches / max(len(golden_dataset), 1)
if accuracy >= approval_threshold:
self.mturk.approve_assignment(
AssignmentId=assignment_id,
OverrideRejection=False
)
approved_count += 1
print(f"✓ Approved {assignment_id} (accuracy: {accuracy:.2%})")
else:
self.mturk.reject_assignment(
AssignmentId=assignment_id,
RequesterFeedback=f"Accuracy too low: {accuracy:.2%}. Please review the instructions."
)
rejected_count += 1
print(f"✗ Rejected {assignment_id} (accuracy: {accuracy:.2%})")
return {
'approved': approved_count,
'rejected': rejected_count,
'total': len(results['answers'])
}
def batch_create_hits_from_csv(self, csv_file: str, hit_type_id: str):
"""CSV ファイルから大量 HIT 作成"""
import pandas as pd
df = pd.read_csv(csv_file)
created_hits = []
for idx, row in df.iterrows():
hit = self.create_image_labeling_hit(
hit_type_id=hit_type_id,
image_urls=[row['image_url']],
max_assignments=row.get('assignments', 3)
)
created_hits.extend(hit)
# Rate limiting
if (idx + 1) % 10 == 0:
print(f"Created {idx + 1} HITs, sleeping...")
time.sleep(5)
return created_hits
def get_account_balance(self):
"""アカウント残高確認"""
response = self.mturk.get_account_balance()
return {
'available_balance': response['AvailableBalance'],
'on_hold_balance': response['OnHoldBalance']
}
def list_hit_statistics(self):
"""HIT 統計情報"""
response = self.mturk.list_huts()
stats = {
'total_hits': len(response.get('HITs', [])),
'assignable': 0,
'reviewable': 0,
'reviewing': 0
}
for hit in response.get('HITs', []):
if hit['HITStatus'] == 'Assignable':
stats['assignable'] += 1
elif hit['HITStatus'] == 'Reviewable':
stats['reviewable'] += 1
elif hit['HITStatus'] == 'Reviewing':
stats['reviewing'] += 1
return stats
SageMaker Ground Truth との統合
# Ground Truth でラベリングジョブを作成(MTurk ワーカープール使用)
import boto3
import json
sm = boto3.client('sagemaker', region_name='us-east-1')
# MTurk ワーカープール の設定
mturk_config = {
'PublicWorkforceTaskPrice': {
'AmountInUsd': 0.05 # HIT 1 個あたり $0.05
}
}
# Ground Truth ラベリングジョブ作成
response = sm.create_labeling_job(
LabelingJobName='image-classification-job-2026-01',
LabelAttributeName='label',
InputConfig={
'DataSource': {
'S3DataSource': {
'ManifestFile': {
'S3Uri': 's3://my-bucket/input-manifest.json'
}
}
}
},
OutputConfig={
'S3OutputPath': 's3://my-bucket/labeling-output/'
},
RoleArn='arn:aws:iam::123456789012:role/SageMakerRole',
LabelCategoryConfigS3Uri='s3://my-bucket/label-categories.json',
HumanTaskConfig={
'WorkteamArn': 'arn:aws:sagemaker:us-east-1:123456789012:workteam/public-crowd/Default',
'UiConfig': {
'UiTemplateS3Uri': 's3://my-bucket/labeling-template.html'
},
'PreHumanTaskLambdaArn': 'arn:aws:lambda:us-east-1:123456789012:function:pre-labeling',
'TaskCount': 3, # 3 人のワーカーが各サンプルをラベル
'TaskDescription': 'Classify images into cat, dog, or other',
'TaskTitle': 'Image Classification',
'NumberOfHumanWorkersPerDataObject': 3,
'PublicWorkforceTaskConfig': mturk_config
},
Tags=[
{'Key': 'Project', 'Value': 'ML-Training'},
{'Key': 'Team', 'Value': 'Data-Engineering'}
]
)
labeling_job_arn = response['LabelingJobArn']
print(f"Labeling job created: {labeling_job_arn}")
# ジョブ進捗監視
import time
while True:
job = sm.describe_labeling_job(LabelingJobName='image-classification-job-2026-01')
status = job['LabelingJobStatus']
progress = job.get('LabelingJobStatus')
print(f"Status: {status}")
if status in ['Completed', 'Failed', 'Stopped']:
break
time.sleep(60)
Worker Qualification・Master Worker
# Worker の資格・評判スコア管理
def assign_qualification(worker_id: str, qualification_type_id: str, score: int):
"""Worker に Qualification を付与"""
mturk.associate_qualification_with_worker(
QualificationTypeId=qualification_type_id,
WorkerId=worker_id,
IntegerValue=score,
SendNotification=True
)
def revoke_qualification(worker_id: str, qualification_type_id: str):
"""Qualification を取り消し"""
mturk.disassociate_qualification_from_worker(
QualificationTypeId=qualification_type_id,
WorkerId=worker_id,
Reason='Quality standards not met'
)
def get_worker_stats(worker_id: str):
"""Worker の統計情報取得"""
# 注意: Worker ID は公開情報ではないため、管理している Worker リストから取得
# この API は Admin 用途のみ
worker_qualifications = mturk.list_workers_with_qualification_type(
QualificationTypeId='00000000000000000040' # Master
)
# Worker が Master 資格を持っているか確認
is_master = any(w['WorkerId'] == worker_id for w in worker_qualifications['Qualifications'])
return {
'worker_id': worker_id,
'is_master': is_master
}
# Master Worker フィルター
master_qualification = {
'QualificationTypeId': '00000000000000000040', # Master Qualification
'Comparator': 'EqualTo',
'RequiredToPreview': False
}
# 年 100+ HIT 完了・承認率 95%+ の ワーカーのみ受け入れ
mturk.create_hit_type(
Title='Expert-only Task',
Description='This task requires Master Worker qualification',
Reward='1.00',
AssignmentDurationInSeconds=3600,
LifetimeInSeconds=2592000,
AutoApprovalDelayInSeconds=86400,
QualificationRequirements=[
master_qualification,
{
'QualificationTypeId': '00000000000000000025', # Approved Assignments
'Comparator': 'GreaterThanOrEqualTo',
'IntegerValues': [100]
},
{
'QualificationTypeId': '000000000000000000L0', # Approval Rate
'Comparator': 'GreaterThanOrEqualTo',
'IntegerValues': [95]
}
]
)
料金体系(2026年)
| 項目 | 料金 | 備注 |
|---|---|---|
| HIT 報酬 | 設定額(最小 $0.01) | Requester が設定 |
| MTurk 手数料 | 報酬の 20% | 最小 $0.01 |
| 小額 HIT(<$0.01) | 報酬の 40% | キャップあり |
| SageMaker Ground Truth 統合 | Ground Truth 料金に含む | MTurk 手数料不要 |
比較: MTurk vs 競合
| 観点 | MTurk | Appen | Lionbridge AI | Scale AI |
|---|---|---|---|---|
| ワーカー数 | 190+ 国、50+ 万 | 限定 | 限定 | AI/アノテーター |
| 価格 | 最低 $0.01 | 高い | 高い | 最高品質 |
| 言語対応 | 175+ 言語 | 限定 | 多言語 | 英語主体 |
| 品質管理 | 手動(承認/拒否) | 自動品質スコア | 専門家チーム | AI + 人間 |
| SageMaker 統合 | ✓ | × | × | × |
| 推奨用途 | 大規模・低コスト | エンタープライズ | 翻訳・多言語 | 高品質・AI データ |
ベストプラクティス
1. HIT 設計
- 明確な指示: 曖昧さ排除、スクリーンショット・例示で視覚化
- 適切な報酬: 相場 $0.05-0.50(タスク複雑度による)
- 制限時間: 5-10 分で完了可能な量
2. 品質保証
# ゴールデンデータセット(既知正解)の埋め込み
golden_questions = [
{
'question': '既知正解: この画像に犬が映っていますか?',
'correct_answer': 'Yes',
'is_golden': True
}
]
# Worker の正解率を追跡 → 低い場合は資格剥奪
3. Cost 最適化
- バルク作成: API で複数 HIT を一括作成(CLI より効率的)
- 多数決: 複数 Worker(3-5 人)の回答で品質向上
- Batching: 小さい単価を複数集約して効率化
4. Worker との関係構築
- 定期的な承認: すぐに承認(信頼構築)
- フィードバック: 拒否時は理由を明確に
- 報酬向上: 継続的なワーカーには時給相当額設定
設計チェックリスト
- [ ] HIT テンプレート(HTML フォーム)完成
- [ ] Qualification Type(Master / 言語 / 地域)定義済み
- [ ] ゴールデンデータセット(既知正解)準備済み
- [ ] 複数 Worker 回答で多数決・品質検証設計済み
- [ ] 想定ワーカー数・完了期間を見積もり済み
- [ ] 月間推定コスト計算済み(報酬 + 手数料)
- [ ] SageMaker Ground Truth 統合の要否判断済み
- [ ] 承認/拒否基準・フィードバック文言決定済み
- [ ] Lambda で自動品質チェック実装済み(オプション)
- [ ] CloudWatch で HIT 進捗・Worker 統計監視設定済み
実装パターン: 画像分類タスク(大規模)
要件: 100,000 画像のラベリング・3 人多数決・2 週間で完了・Master Worker のみ
# 実行ワークフロー
import boto3
import pandas as pd
import time
class LargeScaleImageLabelingJob:
def __init__(self):
self.mturk = boto3.client('mturk', region_name='us-east-1')
self.s3 = boto3.client('s3')
self.cloudwatch = boto3.client('cloudwatch')
def create_large_labeling_job(
self,
image_urls: list, # 100,000 images
hit_type_id: str,
batch_size: int = 100 # 100 HIT / batch
):
"""大規模ラベリングジョブを段階的に実行"""
total_images = len(image_urls)
total_batches = total_images // batch_size
job_status = {
'total_images': total_images,
'total_batches': total_batches,
'created_hits': 0,
'completed_hits': 0,
'pending_hits': 0
}
# バッチごとに HIT 作成
for batch_num in range(total_batches):
start_idx = batch_num * batch_size
end_idx = min(start_idx + batch_size, total_images)
batch_urls = image_urls[start_idx:end_idx]
print(f"\n=== Batch {batch_num + 1} / {total_batches} ===")
print(f"Creating {len(batch_urls)} HITs...")
# HIT バッチ作成
hit_ids = []
for image_url in batch_urls:
try:
response = self.mturk.create_hit(
HITTypeId=hit_type_id,
MaxAssignments=3, # 3 人のワーカーが回答
Question=self._generate_hit_html(image_url)
)
hit_ids.append(response['HIT']['HITId'])
except Exception as e:
print(f"Failed to create HIT: {e}")
job_status['created_hits'] += len(hit_ids)
# 進捗報告
self._log_batch_progress(batch_num + 1, total_batches, len(hit_ids))
# Rate limiting
time.sleep(10)
print(f"\n✓ Job created: {job_status['created_hits']} HITs total")
return job_status
def monitor_labeling_progress(self, hit_type_id: str, poll_interval: int = 300):
"""ラベリング進捗監視(5 分ごとにチェック)"""
while True:
# HIT 統計取得
response = self.mturk.list_huts()
stats = {
'assignable': 0,
'reviewable': 0,
'completed': 0,
'total': len(response.get('HITs', []))
}
for hit in response.get('HITs', []):
if hit['HITStatus'] == 'Assignable':
stats['assignable'] += 1
elif hit['HITStatus'] == 'Reviewable':
stats['reviewable'] += 1
elif hit['HITStatus'] == 'Reviewing':
stats['completed'] += 1
# CloudWatch に メトリクス送信
self.cloudwatch.put_metric_data(
Namespace='MTurk/LabelingJob',
MetricData=[
{
'MetricName': 'AssignableHITs',
'Value': stats['assignable'],
'Unit': 'Count'
},
{
'MetricName': 'CompletedHITs',
'Value': stats['completed'],
'Unit': 'Count'
}
]
)
completion_rate = (stats['completed'] / stats['total'] * 100) if stats['total'] > 0 else 0
print(f"Progress: {completion_rate:.1f}% ({stats['completed']}/{stats['total']})")
if completion_rate == 100:
print("✓ All HITs completed!")
break
time.sleep(poll_interval)
def approve_all_quality_answers(self, hit_ids: list):
"""全 HIT の回答を品質チェック後に承認"""
total_approved = 0
total_rejected = 0
for hit_id in hit_ids:
# 回答取得
response = self.mturk.list_assignments_for_hit(
HITId=hit_id,
AssignmentStatuses=['Submitted'],
MaxResults=100
)
for assignment in response['Assignments']:
# 品質スコア計算(複数回答から多数決)
score = self._calculate_quality_score(assignment)
if score > 0.66: # 66%以上の合致
self.mturk.approve_assignment(
AssignmentId=assignment['AssignmentId']
)
total_approved += 1
else:
self.mturk.reject_assignment(
AssignmentId=assignment['AssignmentId'],
RequesterFeedback='Quality score too low'
)
total_rejected += 1
print(f"Approved: {total_approved}, Rejected: {total_rejected}")
return {'approved': total_approved, 'rejected': total_rejected}
def _generate_hit_html(self, image_url: str) -> str:
"""HIT HTML 生成"""
return f"""
<HTMLQuestion xmlns="http://mechanicalturk.amazonaws.com/AWSMechanicalTurkDataSchemas/2011-11-11/HTMLQuestion.xsd">
<HTMLContent><![CDATA[
<html>
<body>
<img src="{image_url}" style="max-width:600px">
<p><strong>Classify the main animal:</strong></p>
<input type="radio" name="animal" value="cat"> Cat
<input type="radio" name="animal" value="dog"> Dog
<input type="radio" name="animal" value="other"> Other
</body>
</html>
]]></HTMLContent>
<FrameHeight>400</FrameHeight>
</HTMLQuestion>
"""
def _calculate_quality_score(self, assignment) -> float:
"""品質スコア計算"""
# 簡略版:複数回答の合致度
return 0.85 # 実装省略
def _log_batch_progress(self, batch_num: int, total: int, hit_count: int):
"""進捗ログ"""
print(f"Batch {batch_num}/{total}: Created {hit_count} HITs")
最新動向(2024-2026)
- AI アシスト: Worker に AI 予測結果を事前表示→確認タスク化で効率向上
- プライベートワーカープール: 企業専属ワーカー登録・継続的な品質管理
- 品質スコア自動化: ML で Worker の信頼性スコア自動計算
- 多言語 NLP: 言語処理タスクの専門化・言語別ワーカー認定拡大
まとめ
Amazon Mechanical Turk は 「ヒューマンインテリジェンスタスクのクラウドソーシングプラットフォーム」。世界中 50+ 万ワーカーで大規模データラベリング・テキスト分類・コンテンツモデレーションを低コスト実行。
SageMaker Ground Truth と統合し ML 訓練データ作成を完全自動化・統計管理。複数ワーカー多数決・ゴールデンデータセット検証で品質保証、Master Worker・カスタム Qualification で信頼できるワーカーを選別。
インディー企業から大手テック企業まで、AI/ML に必須の高品質ラベルデータを効率的に生成する基盤。