Skip to content
Guides9 min read

Label Studio से Potato पर आना

Label Studio से Potato पर आइए, प्रोजेक्ट config, एनोटेशन स्कीमा और एक्सपोर्ट किया डेटा बदलिए, आम एनोटेशन प्रकारों को कवर करती इस क़दम-दर-क़दम गाइड के साथ।

Potato Team

यह गाइड बताती है कि मौजूदा Label Studio प्रोजेक्ट को Potato पर कैसे ले जाया जाए। पहले ही बता दें: कोई आधिकारिक माइग्रेशन टूल नहीं है। config आप हाथ से बदलते हैं और डेटा का आकार बदलने के लिए थोड़ा Python लिखते हैं, यानी दोनों प्लेटफ़ॉर्म की जानकारी होनी चाहिए।

फ़ीचर की आमने-सामने तुलना और Potato के अपने माइग्रेशन टूल के लिए स्रोत दस्तावेज़ और माइग्रेशन CLI का दस्तावेज़ देखें।

माइग्रेट क्यों करें?

कुछ प्रोजेक्ट पर Potato ज़्यादा फ़िट बैठता है। यह अकादमिक एनोटेशन अध्ययनों के लिए बना है, Prolific और MTurk का इंटीग्रेशन साथ लाता है, और YAML से कॉन्फ़िगर होता है, कोई डेटाबेस खड़ा करने की ज़रूरत नहीं। इसे Python में बढ़ाना आसान है, और चूँकि भंडारण सिर्फ़ फ़ाइलों में है, इसे तैनात करना भी आसान है।

माइग्रेशन का ख़ाका

पूरी प्रक्रिया हाथ से होती है और मोटे तौर पर ऐसी चलती है:

  1. Label Studio का XML टेम्पलेट हाथ से Potato के YAML कॉन्फ़िगरेशन में बदलिए
  2. डेटा प्रारूप बदलने के लिए Python स्क्रिप्ट लिखिए (JSON से JSONL)
  3. मौजूदा एनोटेशन (अगर हों) माइग्रेट करने के लिए स्क्रिप्ट लिखिए
  4. ठीक से जाँचिए और बदले हुए डेटा को सत्यापित कीजिए

टेम्पलेट बदलना

टेक्स्ट वर्गीकरण

Label Studio XML:

xml
<View>
  <Text name="text" value="$text"/>
  <Choices name="sentiment" toName="text" choice="single">
    <Choice value="Positive"/>
    <Choice value="Negative"/>
    <Choice value="Neutral"/>
  </Choices>
</View>

Potato YAML:

yaml
annotation_task_name: "Sentiment Classification"
 
data_files:
  - "data/items.jsonl"
 
item_properties:
  id_key: id
  text_key: text
 
annotation_schemes:
  - annotation_type: radio
    name: sentiment
    description: "What is the sentiment?"
    labels:
      - name: positive
        tooltip: "Positive sentiment"
      - name: negative
        tooltip: "Negative sentiment"
      - name: neutral
        tooltip: "Neutral sentiment"

बहु-लेबल वर्गीकरण

Label Studio XML:

xml
<View>
  <Text name="text" value="$text"/>
  <Choices name="topics" toName="text" choice="multiple">
    <Choice value="Politics"/>
    <Choice value="Sports"/>
    <Choice value="Technology"/>
    <Choice value="Entertainment"/>
  </Choices>
</View>

Potato YAML:

yaml
annotation_schemes:
  - annotation_type: multiselect
    name: topics
    description: "Select all relevant topics"
    labels:
      - name: politics
        tooltip: "Politics content"
      - name: sports
        tooltip: "Sports content"
      - name: technology
        tooltip: "Technology content"
      - name: entertainment
        tooltip: "Entertainment content"

नामित इकाई पहचान (NER)

Label Studio XML:

xml
<View>
  <Labels name="entities" toName="text">
    <Label value="PERSON" background="#FFC0CB"/>
    <Label value="ORG" background="#90EE90"/>
    <Label value="LOCATION" background="#ADD8E6"/>
  </Labels>
  <Text name="text" value="$text"/>
</View>

Potato YAML:

yaml
annotation_schemes:
  - annotation_type: span
    name: entities
    description: "Select entity spans in the text"
    labels:
      - name: PERSON
        tooltip: "Person names"
      - name: ORG
        tooltip: "Organization names"
      - name: LOCATION
        tooltip: "Location names"

ध्यान दें: Potato का span एनोटेशन हाइलाइटिंग के मामले में Label Studio से अलग हो सकता है। बदला हुआ config चलाकर देख लीजिए कि डिस्प्ले आपकी ज़रूरत पर खरा उतरता है या नहीं।

इमेज वर्गीकरण

Label Studio XML:

xml
<View>
  <Image name="image" value="$image_url"/>
  <Choices name="category" toName="image">
    <Choice value="Cat"/>
    <Choice value="Dog"/>
    <Choice value="Other"/>
  </Choices>
</View>

Potato YAML:

yaml
data_files:
  - "data/images.jsonl"
 
item_properties:
  id_key: id
  text_key: image_url
 
annotation_schemes:
  - annotation_type: radio
    name: category
    description: "What animal is in the image?"
    labels:
      - name: cat
        tooltip: "Cat"
      - name: dog
        tooltip: "Dog"
      - name: other
        tooltip: "Other animal"

Bounding box एनोटेशन

Label Studio XML:

xml
<View>
  <Image name="image" value="$image_url"/>
  <RectangleLabels name="objects" toName="image">
    <Label value="Car"/>
    <Label value="Person"/>
    <Label value="Bicycle"/>
  </RectangleLabels>
</View>

Potato YAML:

yaml
annotation_schemes:
  - annotation_type: image_annotation
    tools: [bbox]
    name: objects
    description: "Draw boxes around objects"
    labels:
      - name: car
        tooltip: "Car"
      - name: person
        tooltip: "Person"
      - name: bicycle
        tooltip: "Bicycle"

ध्यान दें: Potato में bounding box का समर्थन Label Studio से अलग हो सकता है। मौजूदा क्षमताओं के लिए दस्तावेज़ देख लीजिए।

रेटिंग पैमाने

Label Studio XML:

xml
<View>
  <Text name="text" value="$text"/>
  <Rating name="quality" toName="text" maxRating="5"/>
</View>

Potato YAML:

yaml
annotation_schemes:
  - annotation_type: likert
    name: quality
    description: "Rate the quality"
    size: 5
    labels:
      - name: "1"
        tooltip: "Poor"
      - name: "2"
        tooltip: "Below average"
      - name: "3"
        tooltip: "Average"
      - name: "4"
        tooltip: "Good"
      - name: "5"
        tooltip: "Excellent"

डेटा प्रारूप बदलना

Label Studio JSON से Potato JSONL

Label Studio का प्रारूप:

json
[
  {
    "id": 1,
    "data": {
      "text": "This is great!",
      "meta_info": "source1"
    }
  },
  {
    "id": 2,
    "data": {
      "text": "This is terrible.",
      "meta_info": "source2"
    }
  }
]

Potato का JSONL प्रारूप:

json
{"id": "1", "text": "This is great!", "metadata": {"source": "source1"}}
{"id": "2", "text": "This is terrible.", "metadata": {"source": "source2"}}

बदलने वाली स्क्रिप्ट

python
import json
 
def convert_label_studio_to_potato(ls_file, potato_file):
    """Convert Label Studio JSON to Potato JSONL"""
 
    with open(ls_file, 'r') as f:
        ls_data = json.load(f)
 
    with open(potato_file, 'w') as f:
        for item in ls_data:
            potato_item = {
                "id": str(item["id"]),
                "text": item["data"].get("text", ""),
            }
 
            # Convert nested data fields
            if "data" in item:
                for key, value in item["data"].items():
                    if key != "text":
                        if "metadata" not in potato_item:
                            potato_item["metadata"] = {}
                        potato_item["metadata"][key] = value
 
            # Handle image URLs
            if "image" in item.get("data", {}):
                potato_item["image_url"] = item["data"]["image"]
 
            f.write(json.dumps(potato_item) + "\n")
 
    print(f"Converted {len(ls_data)} items")
 
# Usage
convert_label_studio_to_potato("label_studio_export.json", "data/items.jsonl")

एनोटेशन का माइग्रेशन

मौजूदा एनोटेशन बदलना

python
def convert_annotations(ls_export, potato_output):
    """Convert Label Studio annotations to Potato format"""
 
    with open(ls_export, 'r') as f:
        ls_data = json.load(f)
 
    with open(potato_output, 'w') as f:
        for item in ls_data:
            if "annotations" not in item or not item["annotations"]:
                continue
 
            for annotation in item["annotations"]:
                potato_ann = {
                    "id": str(item["id"]),
                    "text": item["data"].get("text", ""),
                    "annotations": {},
                    "annotator": annotation.get("completed_by", {}).get("email", "unknown"),
                    "timestamp": annotation.get("created_at", "")
                }
 
                # Convert results
                for result in annotation.get("result", []):
                    scheme_name = result.get("from_name", "unknown")
 
                    if result["type"] == "choices":
                        # Classification
                        potato_ann["annotations"][scheme_name] = result["value"]["choices"][0]
 
                    elif result["type"] == "labels":
                        # NER spans
                        if scheme_name not in potato_ann["annotations"]:
                            potato_ann["annotations"][scheme_name] = []
 
                        potato_ann["annotations"][scheme_name].append({
                            "start": result["value"]["start"],
                            "end": result["value"]["end"],
                            "label": result["value"]["labels"][0],
                            "text": result["value"]["text"]
                        })
 
                    elif result["type"] == "rating":
                        potato_ann["annotations"][scheme_name] = result["value"]["rating"]
 
                f.write(json.dumps(potato_ann) + "\n")
 
# Usage
convert_annotations("ls_annotated_export.json", "annotations/migrated.jsonl")

Span एनोटेशन बदलना

Label Studio character offset इस्तेमाल करता है; Potato भी character offset ही इस्तेमाल करता है, इसलिए बदलना सीधा है:

python
def convert_spans(ls_spans):
    """Convert Label Studio span format to Potato format"""
    potato_spans = []
 
    for span in ls_spans:
        potato_spans.append({
            "start": span["value"]["start"],
            "end": span["value"]["end"],
            "label": span["value"]["labels"][0],
            "text": span["value"]["text"]
        })
 
    return potato_spans

फ़ीचर की मैपिंग

Label StudioPotato
Choices (एकल)radio
Choices (कई)multiselect
Labelsspan
Ratinglikert
TextAreatext
RectangleLabelsbounding_box
PolygonLabelspolygon
Taxonomy(nested multiselect इस्तेमाल करें)
Pairwisecomparison

गुणवत्ता नियंत्रण

माइग्रेशन का यही वह हिस्सा है जहाँ आप कुछ छोड़ते नहीं, कुछ पाते हैं। Label Studio के community संस्करण में सहमति के मेट्रिक बिलकुल नहीं आते, और ground truth चिह्नित करना, समीक्षक तय करना तथा गुणवत्ता डैशबोर्ड सशुल्क स्तरों में रहते हैं। Potato में ये config key हैं।

Attention check एक पूर्ण दर्जे की सुविधा है, ऐसी चीज़ नहीं जिसे डेटा फ़ाइल में चोरी-छिपे डालना पड़े। Potato उन्हें खुद बीच में डालता है और हिसाब रखता है कि कौन चूका:

yaml
attention_checks:
  enabled: true
  items_file: "attention_checks.json"
  frequency: 10              # one check every ten items
  min_response_time: 3.0     # also flag suspiciously fast answers

Gold standard भी इसी तरह चलते हैं, हर एनोटेटर को उन आइटम पर परखते हुए जिनका जवाब आप पहले से जानते हैं:

yaml
gold_standards:
  enabled: true
  items_file: "gold_standards.json"

इंटर-एनोटेटर सहमति आपके लिए निकाल दी जाती है। एनोटेटरों को एक साझा उपसमूह पर overlap कराइए और इसे चालू कर दीजिए। Krippendorff का alpha एडमिन डैशबोर्ड में दिखता है, यानी scikit-learn वाला कोई अलग offline चरण लिखने की ज़रूरत नहीं:

yaml
num_annotators_per_item: 3
 
agreement_metrics:
  enabled: true

लेबल की अनिश्चितता पर, अगर आप और आगे जाना चाहें, तो Label Studio के पास किसी भी स्तर पर इसका कोई समकक्ष नहीं है। Potato आपके एनोटेशन पर एक item response theory मॉडल फ़िट करता है और हर लेबल को posterior तथा confidence interval के साथ रिपोर्ट करता है, वोट गिनने के बजाय एनोटेटरों को उनकी साबित हुई भरोसेमंदी के हिसाब से तौलते हुए:

yaml
psychometrics:
  enabled: true
  schema: sentiment
  confidence_threshold: 0.95

पूरे विकल्पों के लिए गुणवत्ता नियंत्रण, इंटर-एनोटेटर सहमति, और psychometrics इंजन देखें।

उपयोगकर्ताओं का माइग्रेशन

Label Studio से उपयोगकर्ता निकालना

python
# Label Studio API call to get users
import requests
 
def export_ls_users(ls_url, api_key):
    response = requests.get(
        f"{ls_url}/api/users",
        headers={"Authorization": f"Token {api_key}"}
    )
    return response.json()

Potato का उपयोगकर्ता config बनाना

yaml
user_config:
  # Simple auth for migrated users
  auth_type: password
 
  user_config:
    - username: user1@example.com
      password_hash: "..."  # Generate new passwords
 
    - username: user2@example.com
      password_hash: "..."

माइग्रेशन की जाँच

सत्यापन स्क्रिप्ट

python
def validate_migration(original_ls, converted_potato):
    """Validate converted data matches original"""
 
    with open(original_ls) as f:
        ls_data = json.load(f)
 
    with open(converted_potato) as f:
        potato_data = [json.loads(line) for line in f]
 
    # Check item count
    assert len(ls_data) == len(potato_data), "Item count mismatch"
 
    # Check IDs preserved
    ls_ids = {str(item["id"]) for item in ls_data}
    potato_ids = {item["id"] for item in potato_data}
    assert ls_ids == potato_ids, "ID mismatch"
 
    # Check text content
    for ls_item, potato_item in zip(
        sorted(ls_data, key=lambda x: x["id"]),
        sorted(potato_data, key=lambda x: x["id"])
    ):
        assert ls_item["data"]["text"] == potato_item["text"], \
            f"Text mismatch for item {ls_item['id']}"
 
    print("Validation passed!")
 
validate_migration("label_studio_export.json", "data/items.jsonl")

माइग्रेशन की चेकलिस्ट

  • Label Studio से डेटा एक्सपोर्ट कीजिए (JSON प्रारूप)
  • टेम्पलेट XML को हाथ से Potato YAML में बदलिए
  • डेटा प्रारूप बदलने के लिए Python स्क्रिप्ट लिखकर चलाइए (JSON से JSONL)
  • मौजूदा एनोटेशन (अगर हों) बदलने के लिए स्क्रिप्ट लिखकर चलाइए
  • Potato प्रोजेक्ट का ढाँचा खड़ा कीजिए
  • नमूना डेटा पर जाँचिए
  • सत्यापित कीजिए कि बदला हुआ डेटा मूल से मेल खाता है
  • एनोटेटरों को नए इंटरफ़ेस पर प्रशिक्षित कीजिए
  • एनोटेशन का एक pilot बैच चलाइए

आम दिक़्क़तें

कुछ चीज़ें अक्सर पैर अटका देती हैं। दोनों टूल UTF-8 इस्तेमाल करते हैं, फिर भी अपने डेटा में encoding की गड़बड़ियाँ देख लेना ठीक रहता है। स्थानीय इमेज पाथ को आम तौर पर URL बनाना पड़ता है, या कम से कम उस प्रारूप में लाना पड़ता है जिसकी Potato को उम्मीद है। Label Studio में आपने जो भी custom component बनाए थे, उन्हें Potato के custom template के रूप में दोबारा बनाना होगा। और अगर आपने Label Studio API के लिए स्क्रिप्ट लिखी थीं, तो उन्हें अब Potato के API की तरफ़ मोड़ना होगा।


माइग्रेशन में मदद चाहिए? पूरा दस्तावेज़ देखें या GitHub पर संपर्क करें।