рдореБрдЦреНрдп рд╕рд╛рдордЧреНрд░реА рдкрд░ рдЬрд╛рдПрдБ

рдмреНрд░реЗрди MRI рдбреЗрдЯрд╛рд╕реЗрдЯ рдкрд░ MedGemma рдХрд╛ рдлрд╛рдЗрди-рдЯреНрдпреВрдирд┐рдВрдЧ

рдкрд░реНрдпрд╛рд╡рд░рдг рд╕реЗрдЯрдЕрдк, MRI рдбреЗрдЯрд╛рд╕реЗрдЯ рдкреНрд░реЛрд╕реЗрд╕рд┐рдВрдЧ, рдореЙрдбрд▓ рдлрд╛рдЗрди-рдЯреНрдпреВрдирд┐рдВрдЧ, рдФрд░ рдкреНрд░рджрд░реНрд╢рди рдореВрд▓реНрдпрд╛рдВрдХрди рдХреА рдЪрд░рдг-рджрд░-рдЪрд░рдг рдорд╛рд░реНрдЧрджрд░реНрд╢рд┐рдХрд╛ред

AI рдХреЗ рд╕рд╛рде рдЦреЛрдЬреЗрдВ

MedGemma рдЪрд┐рдХрд┐рддреНрд╕рд╛ рдкрд╛рда рдФрд░ рдЫрд╡рд┐ рд╕рдордЭ рдореЗрдВ рдЙрддреНрдХреГрд╖реНрдЯрддрд╛ рдХреЗ рд▓рд┐рдП рдбрд┐рдЬрд╝рд╛рдЗрди рдХрд┐рдП рдЧрдП Gemma 3 рд╡реЗрд░рд┐рдПрдВрдЯреНрд╕ рдХрд╛ рдПрдХ рд╕рдВрдЧреНрд░рд╣ рд╣реИред рдЗрд╕ рд╕рдВрдЧреНрд░рд╣ рдореЗрдВ рд╡рд░реНрддрдорд╛рди рдореЗрдВ рджреЛ рд╢рдХреНрддрд┐рд╢рд╛рд▓реА рд╡реЗрд░рд┐рдПрдВрдЯ рд╢рд╛рдорд┐рд▓ рд╣реИрдВ: рдПрдХ 4B рдорд▓реНрдЯреАрдореЙрдбрд▓ рд╕рдВрд╕реНрдХрд░рдг рдФрд░ рдПрдХ 27B рдХреЗрд╡рд▓-рдкрд╛рда рд╕рдВрд╕реНрдХрд░рдгред┬а

MedGemma 4B рдореЙрдбрд▓ SigLIP рдЗрдореЗрдЬ рдПрдиреНрдХреЛрдбрд░тАФрдЬреЛ рдЫрд╛рддреА рдХреЗ рдПрдХреНрд╕-рд░реЗ, рддреНрд╡рдЪрд╛ рд░реЛрдЧ, рдиреЗрддреНрд░-рд╡рд┐рдЬреНрдЮрд╛рди рдЫрд╡рд┐рдпрд╛рдБ рдФрд░ рд╣рд┐рд╕реНрдЯреЛрдкреИрдереЛрд▓реЙрдЬреА рд╕реНрд▓рд╛рдЗрдб рдЬреИрд╕реА рд╡рд┐рд╡рд┐рдз, рдбреА-рдЖрдЗрдбреЗрдВрдЯрд┐рдлрд╛рдЗрдб рдореЗрдбрд┐рдХрд▓ рдбреЗрдЯрд╛рд╕реЗрдЯреНрд╕ рдкрд░ рдкреНрд░реА-рдЯреНрд░реЗрдВрдб рд╣реИтАФрдХреЛ рдПрдХ рдмрдбрд╝реЗ рднрд╛рд╖рд╛ рдореЙрдбрд▓ (LLM) рдХреЗ рд╕рд╛рде рдЬреЛрдбрд╝рддрд╛ рд╣реИ, рдЬрд┐рд╕реЗ рд╡реНрдпрд╛рдкрдХ рдЪрд┐рдХрд┐рддреНрд╕рд╛ рдбреЗрдЯрд╛ рдкрд░ рдкреНрд░рд╢рд┐рдХреНрд╖рд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИред

рдЗрд╕ рдЯреНрдпреВрдЯреЛрд░рд┐рдпрд▓ рдореЗрдВ, рд╣рдо рд╕реАрдЦреЗрдВрдЧреЗ рдХрд┐ рдмреНрд░реЗрди MRI рдбреЗрдЯрд╛рд╕реЗрдЯ рдкрд░ рдЗрдореЗрдЬ рдХреНрд▓рд╛рд╕рд┐рдлрд┐рдХреЗрд╢рди рдХрд╛рд░реНрдп рдХреЗ рд▓рд┐рдП MedGemma 4B рдореЙрдбрд▓ рдХреЛ рдХреИрд╕реЗ рдлрд╛рдЗрди-рдЯреНрдпреВрди рдХрд┐рдпрд╛ рдЬрд╛рдПред рдЙрджреНрджреЗрд╢реНрдп рдЫреЛрдЯреЗ MedGemma 4B рдореЙрдбрд▓ рдХреЛ рдЗрд╕ рддрд░рд╣ рдЕрдиреБрдХреВрд▓рд┐рдд рдХрд░рдирд╛ рд╣реИ рдХрд┐ рд╡рд╣ рдмреНрд░реЗрди MRI рд╕реНрдХреИрди рдХреЛ рдкреНрд░рднрд╛рд╡реА рд░реВрдк рд╕реЗ рд╡рд░реНрдЧреАрдХреГрдд рдХрд░ рд╕рдХреЗ рдФрд░ рдмреНрд░реЗрди рдХреИрдВрд╕рд░ рдХреА рднрд╡рд┐рд╖реНрдпрд╡рд╛рдгреА рдЕрдзрд┐рдХ рд╕рдЯреАрдХрддрд╛ рдФрд░ рджрдХреНрд╖рддрд╛ рдХреЗ рд╕рд╛рде рдХрд░ рд╕рдХреЗред

рдкрд░реНрдпрд╛рд╡рд░рдг рд╕реЗрдЯрдЕрдк

RunPod GPU-рдЖрдзрд╛рд░рд┐рдд рд╡рд░реНрдХрд▓реЛрдб рдЪрд▓рд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдЙрддреНрдХреГрд╖реНрдЯ рдкреНрд▓реЗрдЯрдлрд╝реЙрд░реНрдо рд╣реИ, рдЬреЛ JupyterLab рд╕рдкреЛрд░реНрдЯ рдХреЗ рд╕рд╛рде рдкреНрд░реА-рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реНрдб рд╡рд╛рддрд╛рд╡рд░рдг рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИред рдЗрд╕рд╕реЗ рдЖрдк рдПрдХ рдкреЙрдб рд▓реЙрдиреНрдЪ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдФрд░ рдЕрдкрдиреЗ рдкрд╕рдВрджреАрджрд╛ рдПрдбрд┐рдЯрд░ рд╕реЗ рддреБрд░рдВрдд рдХреЛрдбрд┐рдВрдЧ рд╢реБрд░реВ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдпрд╣рд╛рдБ рдмрддрд╛рдпрд╛ рдЧрдпрд╛ рд╣реИ рдХрд┐ рдЕрдкрдирд╛ рд╡рд╛рддрд╛рд╡рд░рдг рдХреИрд╕реЗ рд╕реЗрдЯ рдХрд░реЗрдВ:

1. RunPod рд╕реЗрдЯ рдХрд░рдирд╛

RunPod рдореЗрдВ рд▓реЙрдЧ рдЗрди рдХрд░реЗрдВ рдФрд░ A100 GPU рддрдерд╛ рдирд╡реАрдирддрдо PyTorch рдЗрдореЗрдЬ рдХреЗ рд╕рд╛рде рдПрдХ рдкреЙрдб рдмрдирд╛рдПрдБред рдлрд┐рд░ рдкреЙрдб рд▓реЙрдиреНрдЪ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП "Deploy On-Demand" рдмрдЯрди рдкрд░ рдХреНрд▓рд┐рдХ рдХрд░реЗрдВред

Runpod рд╕реЗрдЯ рдХрд░рдирд╛

рдкреЙрдб рдХреЛ рд╕рдВрдкрд╛рджрд┐рдд рдХрд░реЗрдВ рдФрд░ Hugging Face рддрдерд╛ Kaggle рдЗрдВрдЯреАрдЧреНрд░реЗрд╢рди рдХреЗ рд▓рд┐рдП рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд environment variables рдЬреЛрдбрд╝реЗрдВ:

  • HF_TOKEN
  • KAGGLE_USERNAME
  • KAGGLE_KEY

рдбреЗрдЯрд╛рд╕реЗрдЯреНрд╕ рдФрд░ рдореЙрдбрд▓ рдЪреЗрдХрдкреЙрдЗрдВрдЯреНрд╕ рдХреЗ рд▓рд┐рдП рд╕реНрдЯреЛрд░реЗрдЬ рдХреНрд╖рдорддрд╛ рдХреЛ 100GB рддрдХ рдмрдврд╝рд╛рдПрдБ

2. Python рдкреИрдХреЗрдЬ рдЗрдВрд╕реНрдЯреЙрд▓ рдХрд░рдирд╛

рдкреЙрдб рдЪрд▓рдиреЗ рдХреЗ рдмрд╛рдж, "Connect" рдмрдЯрди рдкрд░ рдХреНрд▓рд┐рдХ рдХрд░рдХреЗ JupyterLab рдЗрдВрд╕реНрдЯреЗрдВрд╕ рд▓реЙрдиреНрдЪ рдХрд░реЗрдВред рдПрдХ рдирдпрд╛ Python рдиреЛрдЯрдмреБрдХ рдмрдирд╛рдПрдБ рдФрд░ рдирд┐рдореНрди рдХрдорд╛рдВрдб рдЪрд▓рд╛рдХрд░ рдЖрд╡рд╢реНрдпрдХ Python рдкреИрдХреЗрдЬ рдЗрдВрд╕реНрдЯреЙрд▓ рдХрд░реЗрдВ:

! pip install --upgrade --quiet transformers bitsandbytes datasets evaluate peft trl scikit-learn kaggle

рдбреЗрдЯрд╛рд╕реЗрдЯ рд▓реЛрдб рдХрд░рдирд╛ рдФрд░ рдкреНрд░реЛрд╕реЗрд╕ рдХрд░рдирд╛

рд╣рдо Kaggle рд╕реЗ Brain Cancer MRI рдбреЗрдЯрд╛рд╕реЗрдЯ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗред┬а

3. рдбреЗрдЯрд╛рд╕реЗрдЯ рдбрд╛рдЙрдирд▓реЛрдб рдХрд░рдирд╛

Kaggle CLI рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдбреЗрдЯрд╛рд╕реЗрдЯ рдбрд╛рдЙрдирд▓реЛрдб рдФрд░ рдЕрдирдЬрд╝рд┐рдк рдХрд░реЗрдВ:

!kaggle datasets download -d orvile/brain-cancer-mri-dataset --unzip
Dataset URL: https://www.kaggle.com/datasets/orvile/brain-cancer-mri-dataset
License(s): CC-BY-SA-4.0
Downloading brain-cancer-mri-dataset.zip to /workspace
 90%|тЦИтЦИтЦИтЦИтЦИтЦИтЦИтЦИтЦИтЦИтЦИтЦИтЦИтЦИтЦИтЦИтЦИтЦИтЦИтЦИтЦИтЦИтЦИтЦИтЦИтЦИтЦИтЦИтЦИтЦИтЦИтЦИтЦИтЦИтЦИтЦИтЦЙ    | 130M/144M [00:00<00:00, 231MB/s]
100%|тЦИтЦИтЦИтЦИтЦИтЦИтЦИтЦИтЦИтЦИтЦИтЦИтЦИтЦИтЦИтЦИтЦИтЦИтЦИтЦИтЦИтЦИтЦИтЦИтЦИтЦИтЦИтЦИтЦИтЦИтЦИтЦИтЦИтЦИтЦИтЦИтЦИтЦИтЦИтЦИтЦИ| 144M/144M [00:01<00:00, 108MB/s]

4. рдбреЗрдЯрд╛рд╕реЗрдЯ рд▓реЛрдб рдХрд░рдирд╛

рдбреЗрдЯрд╛рд╕реЗрдЯ рдХреЛ Hugging Face рдбреЗрдЯрд╛рд╕реЗрдЯ рдХреЗ рд░реВрдк рдореЗрдВ рд▓реЛрдб рдХрд░реЗрдВ, рдЙрд╕реЗ рдкреНрд░рд╢рд┐рдХреНрд╖рдг рдФрд░ рд╡реИрд▓рд┐рдбреЗрд╢рди рд╕реЗрдЯ рдореЗрдВ рд╡рд┐рднрд╛рдЬрд┐рдд рдХрд░реЗрдВ, рдФрд░ рдЙрд╕рдХреА рд╕рдВрд░рдЪрдирд╛ рджрд┐рдЦрд╛рдПрдБ:

from datasets import load_dataset

data_dir = "./Brain_Cancer raw MRI data/Brain_Cancer"

# Define proportions for train and validation splits
train_size = 0.8  
validation_size = 0.2  


data = load_dataset("imagefolder", data_dir=data_dir, split="train")

# Split the dataset into train and validation sets
data = data.train_test_split(
    train_size=train_size,
    test_size=validation_size,
    shuffle=True,
    seed=42,
)

# Rename the 'test' split to 'validation'
data["validation"] = data.pop("test")

# Display dataset details
print(data)

рдЖрдЙрдЯрдкреБрдЯ:

DatasetDict({
    train: Dataset({
        features: ['image', 'label'],
        num_rows: 4844
    })
    validation: Dataset({
        features: ['image', 'label'],
        num_rows: 1212
    })
})

рдкреНрд░рд╢рд┐рдХреНрд╖рдг рд╕реЗрдЯ рд╕реЗ рдкрд╣рд▓реА рдЫрд╡рд┐ рдФрд░ рдЙрд╕рдХрд╛ рд▓реЗрдмрд▓ рдЬрд╛рдБрдЪреЗрдВ:

data["train"][0]["image"]

рдмреНрд░реЗрди рдХреИрдВрд╕рд░ рдХреА MRI рдЫрд╡рд┐

print(data["train"][0]["label"])
1

5. рдбреЗрдЯрд╛рд╕реЗрдЯ рдкреНрд░реЛрд╕реЗрд╕ рдХрд░рдирд╛

рдбреЗрдЯрд╛рд╕реЗрдЯ рдкреНрд░реЛрд╕реЗрд╕ рдХрд░рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ, рд╡рд░реНрдЧреАрдХрд░рдг рдХрд╛рд░реНрдп рдХреЗ рдЙрдЪрд┐рдд рдкреНрд░рдмрдВрдзрди рдХреЗ рд▓рд┐рдП рд▓реЗрдмрд▓ рдХреЗ рдирд╛рдореЛрдВ рдХреА рдЬрд╛рдБрдЪ рдХрд░рдирд╛ рдорд╣рддреНрд╡рдкреВрд░реНрдг рд╣реИред

BRAIN_CANCER_CLASSES = data["train"].features["label"].names
print("Detected classes:", BRAIN_CANCER_CLASSES)

рдкрддрд╛ рд▓рдЧрд╛рдП рдЧрдП рдХреНрд▓рд╛рд╕ рд╣реИрдВ: ['brain_glioma', 'brain_menin', 'brain_tumor'].

Detected classes: ['brain_glioma', 'brain_menin', 'brain_tumor']

рд╡рд░реНрдЧреАрдХрд░рдг рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХреЛ рдмреЗрд╣рддрд░ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо рдЗрди рдХреНрд▓рд╛рд╕ рд▓реЗрдмрд▓реНрд╕ рдореЗрдВ рдкреНрд░реАрдлрд┐рдХреНрд╕ (A, B, C) рдЬреЛрдбрд╝рдХрд░ рд╕рдВрд╢реЛрдзрд┐рдд рдХрд░реЗрдВрдЧреЗ, рддрд╛рдХрд┐ рдмреЗрд╣рддрд░ рд╕рдВрдЧрдарди рд╣реЛ рдФрд░ рдХрд╕реНрдЯрдо рдкреНрд░реЙрдореНрдкреНрдЯ рдлрд╝реЙрд░реНрдореЗрдЯ рдХреЗ рд╕рд╛рде рд╕рдВрд░реЗрдЦрдг рд╣реЛ рд╕рдХреЗред┬а

BRAIN_CANCER_CLASSES = ['A: brain glioma', 'B: brain menin', 'C: brain tumor']

рдЕрдЧрд▓реЗ рдЪрд░рдг рдореЗрдВ, рд╣рдо рдПрдХ рдХрд╕реНрдЯрдо рдкреНрд░реЙрдореНрдкреНрдЯ рдмрдирд╛рдПрдБрдЧреЗ рдЬрд┐рд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдлрд╛рдЗрди-рдЯреНрдпреВрдирд┐рдВрдЧ рдХреЗ рджреМрд░рд╛рди рдореЙрдбрд▓ рдХреЛ рдирд┐рд░реНрджреЗрд╢рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред рдкреНрд░реЙрдореНрдкреНрдЯ рдореЗрдВ рдЕрдкрдбреЗрдЯреЗрдб рдХреНрд▓рд╛рд╕ рд▓реЗрдмрд▓ рд╢рд╛рдорд┐рд▓ рд╣реЛрдВрдЧреЗред

options = "\n".join(BRAIN_CANCER_CLASSES)
PROMPT = f"What is the most likely type of brain cancer shown in the MRI image?\n{options}"

рдлрд╛рдЗрди-рдЯреНрдпреВрдирд┐рдВрдЧ рдХреЗ рд▓рд┐рдП рдбреЗрдЯрд╛рд╕реЗрдЯ рддреИрдпрд╛рд░ рдХрд░рдиреЗ рд╣реЗрддреБ, рд╣рдо "messages" рдирд╛рдо рдХрд╛ рдПрдХ рдирдпрд╛ рдХреЙрд▓рдо рдмрдирд╛рдПрдБрдЧреЗред рдЗрд╕ рдХреЙрд▓рдо рдореЗрдВ рдпреВрдЬрд╝рд░ рдХреНрд╡реЗрд░реА (рдкреНрд░реЙрдореНрдкреНрдЯ) рдФрд░ рдЕрд╕рд┐рд╕реНрдЯреЗрдВрдЯ рдХреЗ рдЙрддреНрддрд░ (рд╕рд╣реА рд▓реЗрдмрд▓) рдХрд╛ рд╕рдВрд░рдЪрд┐рдд рдбреЗрдЯрд╛ рд╣реЛрдЧрд╛ред┬а

def format_data(example: dict[str, any]) -> dict[str, any]:
    example["messages"] = [
        {
            "role": "user",
            "content": [
                {
                    "type": "image",
                },
                {
                    "type": "text",
                    "text": PROMPT,
                },
            ],
        },
        {
            "role": "assistant",
            "content": [
                {
                    "type": "text",
                    "text": BRAIN_CANCER_CLASSES[example["label"]],
                },
            ],
        },
    ]
    return example

# Apply the formatting to the dataset
formatted_data = data.map(format_data)

рдлрд╝реЙрд░реНрдореИрдЯрд┐рдВрдЧ рд╕рддреНрдпрд╛рдкрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо рдкрд╣рд▓реЗ рд╕реИрдВрдкрд▓ рдХреЗ message рдХреЙрд▓рдо рдХрд╛ рдирд┐рд░реАрдХреНрд╖рдг рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ:

formatted_data["train"][0]["messages"]

рдкрд░рд┐рдгрд╛рдореА рдлрд╝реЙрд░реНрдореИрдЯреЗрдб рдбреЗрдЯрд╛ рдмрд┐рдВрджреБ рдЗрд╕ рдкреНрд░рдХрд╛рд░ рджрд┐рдЦрддрд╛ рд╣реИ:

[{'content': [{'text': None, 'type': 'image'},
   {'text': 'What is the most likely type of brain cancer shown in the MRI image?\nA: brain glioma\nB: brain menin\nC: brain tumor',
    'type': 'text'}],
  'role': 'user'},
 {'content': [{'text': 'B: brain menin', 'type': 'text'}],
  'role': 'assistant'}]

рдмреНрд░реЗрди MRI рдбреЗрдЯрд╛рд╕реЗрдЯ рдкрд░ MedGemma рдХрд╛ рдлрд╛рдЗрди-рдЯреНрдпреВрдирд┐рдВрдЧ

рдЗрд╕ рдЦрдВрдб рдореЗрдВ, рд╣рдо MedGemma 4B Instruct рдореЙрдбрд▓ рдХреЛ рдмреНрд░реЗрди MRI рдбреЗрдЯрд╛рд╕реЗрдЯ рдкрд░ рдлрд╛рдЗрди-рдЯреНрдпреВрди рдХрд░реЗрдВрдЧреЗред рдЗрд╕рдореЗрдВ рдореЙрдбрд▓ рдФрд░ рдкреНрд░реЛрд╕реЗрд╕рд░ рдбрд╛рдЙрдирд▓реЛрдб рдХрд░рдирд╛, LoRA рдПрдбреЗрдкреНрдЯрд░ рд╕реЗрдЯ рдХрд░рдирд╛, рдЯреНрд░реЗрдирд░ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░рдирд╛, рдФрд░ рдЯреНрд░реЗрдирд┐рдВрдЧ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рд╢реБрд░реВ рдХрд░рдирд╛ рд╢рд╛рдорд┐рд▓ рд╣реИред

6. рдореЙрдбрд▓ рдФрд░ рдЯреЛрдХрдирд╛рдЗрдЬрд╝рд░ рд▓реЛрдб рдХрд░рдирд╛

рдХреНрдпреЛрдВрдХрд┐ MedGemma рдПрдХ gated рдореЙрдбрд▓ рд╣реИ, рдЖрдкрдХреЛ рдЕрдкрдиреА API рдХреБрдВрдЬреА рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ Hugging Face CLI рдореЗрдВ рд▓реЙрдЧ рдЗрди рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред рдЗрд╕рд╕реЗ рдЖрдк рдЕрдкрдиреЗ рдлрд╛рдЗрди-рдЯреНрдпреВрди рдХрд┐рдП рдЧрдП рдореЙрдбрд▓ рдХреЛ Hugging Face Hub рдкрд░ рд╕реЗрд╡ рднреА рдХрд░ рдкрд╛рдПрдБрдЧреЗред рдпрджрд┐ рдЖрдкрдХреЛ рдкреБрдирд░реНрд╕реНрдорд░рдг рдЪрд╛рд╣рд┐рдП, рддреЛ рд╣рдорд╛рд░рд╛ рдХреЛрд░реНрд╕ Working with Hugging Face: Your Guide to the Hub рджреЗрдЦреЗрдВред┬а

from huggingface_hub import login
import os

hf_token = os.environ.get("HF_TOKEN")
login(hf_token)

рд╣рдо Transformers рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ MedGemma 4B Instruct рдореЙрдбрд▓ рдФрд░ рдЙрд╕рдХреЗ рдкреНрд░реЛрд╕реЗрд╕рд░ рдХреЛ рд▓реЛрдб рдХрд░реЗрдВрдЧреЗред рдореЙрдбрд▓ рдХреЛ GPU рдкрд░ рдХреБрд╢рд▓ рдЧрдгрдирд╛ рдХреЗ рд▓рд┐рдП bfloat16 рдкреНрд░рд┐рд╕реАрдЬрди рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рд╣реЗрддреБ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИред

import torch
from transformers import AutoProcessor, AutoModelForImageTextToText, BitsAndBytesConfig

model_id = "google/medgemma-4b-it"

# Check if GPU supports bfloat16
if torch.cuda.get_device_capability()[0] < 8:
    raise ValueError("GPU does not support bfloat16, please use a GPU that supports bfloat16.")

model_kwargs = dict(
    attn_implementation="eager",
    torch_dtype=torch.bfloat16,
    device_map="auto",
)

model = AutoModelForImageTextToText.from_pretrained(model_id, **model_kwargs)
processor = AutoProcessor.from_pretrained(model_id)

# Use right padding to avoid issues during training
processor.tokenizer.padding_side = "right"

7. рдореЙрдбрд▓ рд╕реЗрдЯ рдХрд░рдирд╛

MedGemma 4B Instruct рдореЙрдбрд▓ рдХреЛ рдХреБрд╢рд▓рддрд╛рдкреВрд░реНрд╡рдХ рдлрд╛рдЗрди-рдЯреНрдпреВрди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо Low-Rank Adaptation (LoRA) рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗ, рдЬреЛ рдПрдХ рдкреИрд░рд╛рдореАрдЯрд░-рдХреБрд╢рд▓ рдлрд╛рдЗрди-рдЯреНрдпреВрдирд┐рдВрдЧ рд╡рд┐рдзрд┐ рд╣реИред┬а

LoRA рд╣рдореЗрдВ рдХреЗрд╡рд▓ рдереЛрдбрд╝реЗ рдЕрддрд┐рд░рд┐рдХреНрдд рдкреИрд░рд╛рдореАрдЯрд░реНрд╕ рдкреНрд░рд╢рд┐рдХреНрд╖рд┐рдд рдХрд░рдХреЗ рдмрдбрд╝реЗ рдореЙрдбрд▓реЛрдВ рдХреЛ рдЕрдиреБрдХреВрд▓рд┐рдд рдХрд░рдиреЗ рджреЗрддрд╛ рд╣реИ, рдЬрд┐рд╕рд╕реЗ рдЧрдгрдирд╛рддреНрдордХ рд▓рд╛рдЧрдд рдореЗрдВ рдЙрд▓реНрд▓реЗрдЦрдиреАрдп рдХрдореА рдЖрддреА рд╣реИ рдФрд░ рдкреНрд░рджрд░реНрд╢рди рдмрдирд╛ рд░рд╣рддрд╛ рд╣реИред┬а

from peft import LoraConfig

peft_config = LoraConfig(
    lora_alpha=16,
    lora_dropout=0.05,
    r=16,
    bias="none",
    target_modules="all-linear",
    task_type="CAUSAL_LM",
    modules_to_save=[
        "lm_head",
        "embed_tokens",
    ],
)

рдЯреНрд░реЗрдирд┐рдВрдЧ рдХреЗ рджреМрд░рд╛рди рдЫрд╡рд┐ рдФрд░ рдкрд╛рда рджреЛрдиреЛрдВ рдЗрдирдкреБрдЯ рд╕рдБрднрд╛рд▓рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо рдПрдХ рдХрд╕реНрдЯрдо рдХреЛрд▓реЗрд╢рди рдлрд╝рдВрдХреНрд╢рди рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░рддреЗ рд╣реИрдВред рдпрд╣ рдлрд╝рдВрдХреНрд╢рди рдбреЗрдЯрд╛рд╕реЗрдЯ рдЙрджрд╣рд╛рд░рдгреЛрдВ рдХреЛ рдРрд╕реЗ рдлрд╝реЙрд░реНрдореИрдЯ рдореЗрдВ рдкреНрд░реЛрд╕реЗрд╕ рдХрд░рддрд╛ рд╣реИ рдЬреЛ рдореЙрдбрд▓ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреБрдХреНрдд рд╣реЛ, рдЬрд┐рд╕рдореЗрдВ рдкрд╛рда рдХрд╛ рдЯреЛрдХрдирд╛рдЗрдЬрд╝реЗрд╢рди рдФрд░ рдЗрдореЗрдЬ рдбреЗрдЯрд╛ рдХреА рддреИрдпрд╛рд░реА рд╢рд╛рдорд┐рд▓ рд╣реИред

def collate_fn(examples: list[dict[str, any]]):
    texts = []
    images = []
    for example in examples:
        images.append([example["image"]])
        texts.append(
            processor.apply_chat_template(
                example["messages"], add_generation_prompt=False, tokenize=False
            ).strip()
        )

    # Tokenize the texts and process the images
    batch = processor(text=texts, images=images, return_tensors="pt", padding=True)

    # The labels are the input_ids, with the padding and image tokens masked in
    # the loss computation
    labels = batch["input_ids"].clone()

    # Mask image tokens
    image_token_id = [
        processor.tokenizer.convert_tokens_to_ids(
            processor.tokenizer.special_tokens_map["boi_token"]
        )
    ]
    # Mask tokens that are not used in the loss computation
    labels[labels == processor.tokenizer.pad_token_id] = -100
    labels[labels == image_token_id] = -100
    labels[labels == 262144] = -100

    batch["labels"] = labels
    return batch

рд╣рдо trl рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХреА SFTConfig рдХреНрд▓рд╛рд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдЯреНрд░реЗрдирд┐рдВрдЧ рдЖрд░реНрдЧреНрдпреБрдореЗрдВрдЯреНрд╕ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд░рддреЗ рд╣реИрдВред рдпреЗ рдЖрд░реНрдЧреНрдпреБрдореЗрдВрдЯреНрд╕ рдлрд╛рдЗрди-рдЯреНрдпреВрдирд┐рдВрдЧ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХреЛ рдирд┐рдпрдВрддреНрд░рд┐рдд рдХрд░рддреЗ рд╣реИрдВ, рдЬреИрд╕реЗ рдмреИрдЪ рд╕рд╛рдЗрдЬ, рд▓рд░реНрдирд┐рдВрдЧ рд░реЗрдЯ, рдФрд░ рдЧреНрд░реЗрдбрд┐рдПрдВрдЯ рдПрдХреНрдпреВрдореНрдпреВрд▓реЗрд╢рди рд╕реНрдЯреЗрдкреНрд╕ред

from trl import SFTConfig

args = SFTConfig(
    output_dir="medgemma-brain-cancer",            
    num_train_epochs=1,                       
    per_device_train_batch_size=8,                           
    per_device_eval_batch_size=8,                            
    gradient_accumulation_steps=8,                           
    gradient_checkpointing=True,                             
    optim="adamw_torch_fused",                               
    logging_steps=0.1,                                        
    save_strategy="epoch",                                   
    eval_strategy="steps",                                   
    eval_steps=0.1,                                           
    learning_rate=2e-4,                             
    bf16=True,                                               
    max_grad_norm=0.3,                                       
    warmup_ratio=0.03,                                       
    lr_scheduler_type="linear",                              
    push_to_hub=True,                                        
    report_to="none",
    gradient_checkpointing_kwargs={"use_reentrant": False},  
    dataset_kwargs={"skip_prepare_dataset": True},           
    remove_unused_columns = False,                           
    label_names=["labels"],                                  
)

SFTTrainer рдореЙрдбрд▓, рдбреЗрдЯрд╛рд╕реЗрдЯ, рдбреЗрдЯрд╛ рдХреЛрд▓реЗрдЯрд░, рдЯреНрд░реЗрдирд┐рдВрдЧ рдЖрд░реНрдЧреНрдпреБрдореЗрдВрдЯреНрд╕ рдФрд░ LoRA рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдХреЛ рдПрдХ рд╣реА рд╡рд░реНрдХрдлрд╝реНрд▓реЛ рдореЗрдВ рдЬреЛрдбрд╝рдХрд░ рдлрд╛рдЗрди-рдЯреНрдпреВрдирд┐рдВрдЧ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХреЛ рд╕рд░рд▓ рдмрдирд╛рддрд╛ рд╣реИред рдЗрд╕рд╕реЗ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рд╕реБрдЧрдо рдФрд░ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛-рдЕрдиреБрдХреВрд▓ рд╣реЛ рдЬрд╛рддреА рд╣реИред

from trl import SFTTrainer

trainer = SFTTrainer(
    model=model,
    args=args,
    train_dataset=formatted_data["train"],
    eval_dataset=formatted_data["validation"].shuffle().select(range(50)), 
    peft_config=peft_config,
    processing_class=processor,
    data_collator=collate_fn,
)

8. рдореЙрдбрд▓ рдЯреНрд░реЗрдирд┐рдВрдЧ

рдЬрдм рдореЙрдбрд▓, рдбреЗрдЯрд╛рд╕реЗрдЯ рдФрд░ рдЯреНрд░реЗрдирд┐рдВрдЧ рдХреЙрдиреНрдлрд╝рд┐рдЧреБрд░реЗрд╢рдВрд╕ рддреИрдпрд╛рд░ рд╣реЛ рдЬрд╛рдПрдБ, рддреЛ рд╣рдо рдлрд╛рдЗрди-рдЯреНрдпреВрдирд┐рдВрдЧ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рд╢реБрд░реВ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред SFTTrainer рдЗрд╕ рдЪрд░рдг рдХреЛ рд╕рд░рд▓ рдмрдирд╛рддрд╛ рд╣реИ, рдЬрд┐рд╕рд╕реЗ рдХреЗрд╡рд▓ рдПрдХ рдХрдорд╛рдВрдб рд╕реЗ рдореЙрдбрд▓ рдЯреНрд░реЗрди рд╣реЛ рдЬрд╛рддрд╛ рд╣реИ:

trainer.train()

рдЯреНрд░реЗрдирд┐рдВрдЧ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХреЛ рдкреВрд░рд╛ рд╣реЛрдиреЗ рдореЗрдВ рд▓рдЧрднрдЧ 1 рдШрдВрдЯрд╛ 8 рдорд┐рдирдЯ рд▓рдЧреЗред рдЗрд╕ рджреМрд░рд╛рди, рдЯреНрд░реЗрдирд┐рдВрдЧ рд▓реЙрд╕ рдФрд░ рд╡реИрд▓рд┐рдбреЗрд╢рди рд▓реЙрд╕ рдкреНрд░рддреНрдпреЗрдХ рд╕реНрдЯреЗрдк рдХреЗ рд╕рд╛рде рд▓рдЧрд╛рддрд╛рд░ рдШрдЯрддреЗ рдЧрдП, рдЬреЛ рджрд░реНрд╢рд╛рддрд╛ рд╣реИ рдХрд┐ рдореЙрдбрд▓ рдкреНрд░рднрд╛рд╡реА рдврдВрдЧ рд╕реЗ рд╕реАрдЦ рд░рд╣рд╛ рдерд╛ред

рдлрд╛рдЗрди-рдЯреНрдпреВрдирд┐рдВрдЧ рдХреЗ рдЯреНрд░реЗрдирд┐рдВрдЧ рдФрд░ рд╡реИрд▓рд┐рдбреЗрд╢рди рд▓реЙрд╕ред

рдЯреНрд░реЗрдирд┐рдВрдЧ рдкреВрд░реА рд╣реЛрдиреЗ рдХреЗ рдмрд╛рдж, рдлрд╛рдЗрди-рдЯреНрдпреВрди рдХрд┐рдпрд╛ рдЧрдпрд╛ рдореЙрдбрд▓ рд▓реЛрдХрд▓ рд░реВрдк рд╕реЗ рд╕реЗрд╡ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ рдФрд░ save_model() рдореЗрдердб рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ Hugging Face Hub рдкрд░ рдкреБрд╢ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред┬а

trainer.save_model()

рдореЙрдбрд▓ рдЕрдм рдпрд╣рд╛рдБ рдЙрдкрд▓рдмреНрдз рд╣реИ kingabzpro/medgemma-brain-cancer ┬╖ Hugging Face

fine-tuned рдореЙрдбрд▓ Hugging Face Hub рдкрд░ рд╕реЗрд╡: kingabzpro/medgemma-brain-cancer

рд╕реНрд░реЛрдд kingabzpro/medgemma-brain-cancer

рдореЙрдбрд▓ рдореВрд▓реНрдпрд╛рдВрдХрди

MedGemma 4B рдореЙрдбрд▓ рдХреЗ рдкреНрд░рджрд░реНрд╢рди рдХрд╛ рдореВрд▓реНрдпрд╛рдВрдХрди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо рд╡реИрд▓рд┐рдбреЗрд╢рди рдбреЗрдЯрд╛рд╕реЗрдЯ рдкрд░ рдмреЗрд╕ рдореЙрдбрд▓ рдФрд░ рдлрд╛рдЗрди-рдЯреНрдпреВрди рдореЙрдбрд▓ рджреЛрдиреЛрдВ рдХрд╛ рдкрд░реАрдХреНрд╖рдг рдХрд░реЗрдВрдЧреЗред рдЗрд╕ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдореЗрдВ рдореЗрдореЛрд░реА рд╕рд╛рдл рдХрд░рдирд╛, рдЯреЗрд╕реНрдЯ рдбреЗрдЯрд╛ рддреИрдпрд╛рд░ рдХрд░рдирд╛, рд░рд┐рд╕реНрдкреЙрдиреНрд╕ рдЬрдирд░реЗрдЯ рдХрд░рдирд╛, рдФрд░ accuracy рддрдерд╛ F1 рд╕реНрдХреЛрд░ рдЬреИрд╕реЗ рдкреНрд░рдореБрдЦ рдореЗрдЯреНрд░рд┐рдХреНрд╕ рдХреА рдЧрдгрдирд╛ рд╢рд╛рдорд┐рд▓ рд╣реИред┬а

рдореВрд▓реНрдпрд╛рдВрдХрди рд╢реБрд░реВ рдХрд░рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ, рд╣рдо рдЯреНрд░реЗрдирд┐рдВрдЧ рд╕реЗрдЯрдЕрдк рд╣рдЯрд╛рддреЗ рд╣реИрдВ рддрд╛рдХрд┐ GPU рдореЗрдореЛрд░реА рдЦрд╛рд▓реА рд╣реЛ рдФрд░ рдЯреЗрд╕реНрдЯрд┐рдВрдЧ рдХреЗ рд▓рд┐рдП рд╕реНрд╡рдЪреНрдЫ рд╡рд╛рддрд╛рд╡рд░рдг рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рд╣реЛ

del model
del trainer
torch.cuda.empty_cache()

9. рдореЙрдбрд▓ рдЯреЗрд╕реНрдЯрд┐рдВрдЧ рдХреЗ рд▓рд┐рдП рд╕реЗрдЯрдЕрдк

рд╣рдо рд╡реИрд▓рд┐рдбреЗрд╢рди рдбреЗрдЯрд╛рд╕реЗрдЯ рдХреЛ рдореЙрдбрд▓ рджреНрд╡рд╛рд░рд╛ рдЕрдкреЗрдХреНрд╖рд┐рдд рдЗрдирдкреБрдЯ рд╕рдВрд░рдЪрдирд╛ рдХреЗ рдЕрдиреБрд░реВрдк рдлрд╝реЙрд░реНрдореИрдЯ рдХрд░рддреЗ рд╣реИрдВред рдЗрд╕рдореЗрдВ рдкреНрд░рддреНрдпреЗрдХ рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП рдпреВрдЬрд╝рд░ рдкреНрд░реЙрдореНрдкреНрдЯ рд╡рд╛рд▓рд╛ "messages" рдХреЙрд▓рдо рдмрдирд╛рдирд╛ рд╢рд╛рдорд┐рд▓ рд╣реИред

def format_test_data(example: dict[str, any]) -> dict[str, any]:
    example["messages"] = [
        {
            "role": "user",
            "content": [
                {
                    "type": "image",
                },
                {
                    "type": "text",
                    "text": PROMPT,
                },
            ],
        },
    ]
    return example

test_data = data["validation"]
test_data = test_data.map(format_test_data)

рдореЙрдбрд▓ рдХреЗ рдкреНрд░рджрд░реНрд╢рди рдХрд╛ рдореВрд▓реНрдпрд╛рдВрдХрди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╣рдо evaluate рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ, рдЬреЛ рд╡рд░реНрдЧреАрдХрд░рдг рдЬреИрд╕реЗ рдХрд╛рд░реНрдпреЛрдВ рдХреЗ рд▓рд┐рдП рдкреВрд░реНрд╡-рдирд┐рд░реНрдорд┐рдд рдореЗрдЯреНрд░рд┐рдХреНрд╕ рдкреНрд░рджрд╛рди рдХрд░рддреА рд╣реИред рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдЗрдореНрдкреЛрд░реНрдЯ рдХрд░рдХреЗ рдФрд░ рдЖрд╡рд╢реНрдпрдХ рдореЗрдЯреНрд░рд┐рдХреНрд╕ рд▓реЛрдб рдХрд░рдиреЗ рдХреЗ рдмрд╛рдж, рд╣рдо рдЯреЗрд╕реНрдЯ рдбреЗрдЯрд╛рд╕реЗрдЯ рд╕реЗ рдЧреНрд░рд╛рдЙрдВрдб-рдЯреНрд░реБрде рд▓реЗрдмрд▓ рдирд┐рдХрд╛рд▓рддреЗ рд╣реИрдВред рдПрдХ рд╣реЗрд▓реНрдкрд░ рдлрд╝рдВрдХреНрд╢рди compute_metrics рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдЬреЛ рднрд╡рд┐рд╖реНрдпрд╡рд╛рдгрд┐рдпреЛрдВ рдХреА рддреБрд▓рдирд╛ рдЗрди рд▓реЗрдмрд▓реНрд╕ рд╕реЗ рдХрд░рдХреЗ accuracy рдФрд░ F1 рд╕реНрдХреЛрд░ рдХреА рдЧрдгрдирд╛ рдХрд░рддрд╛ рд╣реИред

import evaluate

accuracy_metric = evaluate.load("accuracy")
f1_metric = evaluate.load("f1")

# Ground-truth labels
REFERENCES = test_data["label"]


def compute_metrics(predictions: list[int]) -> dict[str, float]:
    metrics = {}
    metrics.update(
        accuracy_metric.compute(
            predictions=predictions,
            references=REFERENCES,
        )
    )
    metrics.update(
        f1_metric.compute(
            predictions=predictions,
            references=REFERENCES,
            average="weighted",
        )
    )
    return metrics

рд▓реЗрдмрд▓ рд╣реИрдВрдбрд▓рд┐рдВрдЧ рдореЗрдВ рдПрдХрд░реВрдкрддрд╛ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо рдбреЗрдЯрд╛рд╕реЗрдЯ рдХреЗ "label" рдХреЙрд▓рдо рдХреЛ ClassLabel рдкреНрд░рдХрд╛рд░ рдореЗрдВ рдХрд╛рд╕реНрдЯ рдХрд░рддреЗ рд╣реИрдВред рдЗрд╕рд╕реЗ рд▓реЗрдмрд▓ рдЗрдВрдбреЗрдХреНрд╕ рдФрд░ рдЙрдирдХреЗ рдирд╛рдореЛрдВ рдХреЗ рдмреАрдЪ рдХреБрд╢рд▓ рдореИрдкрд┐рдВрдЧ рд╕рдВрднрд╡ рд╣реЛрддреА рд╣реИред рд╕рд╛рде рд╣реА, рдкреЛрд╕реНрдЯ-рдкреНрд░реЛрд╕реЗрд╕рд┐рдВрдЧ рдХреЗ рджреМрд░рд╛рди рд▓реЗрдмрд▓ рдлрд╝реЙрд░реНрдореИрдЯрд┐рдВрдЧ рдореЗрдВ рд╡рд┐рд╡рд┐рдзрддрд╛рдУрдВ рдХреЛ рд╕рдБрднрд╛рд▓рдиреЗ рд╣реЗрддреБ рд╡реИрдХрд▓реНрдкрд┐рдХ рд▓реЗрдмрд▓ рдореИрдкрд┐рдВрдЧреНрд╕ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░рддреЗ рд╣реИрдВред

from datasets import ClassLabel

test_data = test_data.cast_column(
    "label",
    ClassLabel(names=BRAIN_CANCER_CLASSES)
)

LABEL_FEATURE = test_data.features["label"]

ALT_LABELS = dict([
    (label, f"({label.replace(': ', ') ')}") for label in BRAIN_CANCER_CLASSES
])

рдореЙрдбрд▓ рдХреА рднрд╡рд┐рд╖реНрдпрд╡рд╛рдгрд┐рдпреЛрдВ рдХреЛ рд╕рд╣реА рдХреНрд▓рд╛рд╕ рд▓реЗрдмрд▓реНрд╕ рд╕реЗ рдореИрдк рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо postprocess рдлрд╝рдВрдХреНрд╢рди рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░рддреЗ рд╣реИрдВред рдпрд╣ рдлрд╝рдВрдХреНрд╢рди рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рддрд╛ рд╣реИ рдХрд┐ рднрд╡рд┐рд╖реНрдпрд╡рд╛рдгрд┐рдпрд╛рдБ рдЙрдкрдпреБрдХреНрдд рд▓реЗрдмрд▓ рд╕реЗ рдореЗрд▓ рдЦрд╛рдПрдБ, рдФрд░ рдХреИрдиреЙрдирд┐рдХрд▓ рддрдерд╛ рд╡реИрдХрд▓реНрдкрд┐рдХ рджреЛрдиреЛрдВ рдлрд╝реЙрд░реНрдореИрдЯреНрд╕ рдХреЛ рдзреНрдпрд╛рди рдореЗрдВ рд░рдЦрд╛ рдЬрд╛рдПред

def postprocess(prediction, do_full_match: bool = False) -> int:
    if isinstance(prediction, str):
        response_text = prediction
    else:
        response_text = prediction[0]["generated_text"]

    if do_full_match:
        return LABEL_FEATURE.str2int(response_text)

    for label in BRAIN_CANCER_CLASSES:
        # accept canonical or alternative wording
        if label in response_text or ALT_LABELS[label] in response_text:
            return LABEL_FEATURE.str2int(label)

    return -1

10. рдмреЗрд╕ рдореЙрдбрд▓ рдкрд░ рдореЙрдбрд▓ рдкреНрд░рджрд░реНрд╢рди

рдмреЗрд╕ рдореЙрдбрд▓ рдХреЗ рдкреНрд░рджрд░реНрд╢рди рдХрд╛ рдореВрд▓реНрдпрд╛рдВрдХрди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо рдкреНрд░реА-рдЯреНрд░реЗрдВрдб рдореЙрдбрд▓ рдФрд░ рдкреНрд░реЛрд╕реЗрд╕рд░ рд▓реЛрдб рдХрд░рддреЗ рд╣реИрдВ, рдЬреЗрдирд░реЗрд╢рди рд╕реЗрдЯрд┐рдВрдЧреНрд╕ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░рддреЗ рд╣реИрдВ, рдФрд░ рдЯреЗрд╕реНрдЯрд┐рдВрдЧ рдХреЗ рд▓рд┐рдП рдкреНрд░реЙрдореНрдкреНрдЯреНрд╕ рддрдерд╛ рдЗрдореЗрдЬреЗрдЬ рддреИрдпрд╛рд░ рдХрд░рддреЗ рд╣реИрдВред

import torch
from transformers import AutoModelForImageTextToText, AutoProcessor

model_kwargs = dict(
    torch_dtype=torch.bfloat16,
    device_map="auto",
)

model = AutoModelForImageTextToText.from_pretrained(
    model_id, **model_kwargs
)

from transformers import GenerationConfig
gen_cfg = GenerationConfig.from_pretrained(model_id)
gen_cfg.update(
    do_sample          = False, 
    top_k              = None, 
    top_p              = None,
    cache_implementation = "dynamic" 
)
model.generation_config = gen_cfg

processor  = AutoProcessor.from_pretrained(args.output_dir)
tok = processor.tokenizer

model.config.pad_token_id            = tok.pad_token_id
model.generation_config.pad_token_id = tok.pad_token_id

def chat_to_prompt(chat_turns):
    return processor.apply_chat_template(
        chat_turns,
        add_generation_prompt=True,   # tells the model "your turn"
        tokenize=False                # we want raw text, not ids
    )

prompts = [chat_to_prompt(c) for c in test_data["messages"]]
images  = test_data["image"]                         # already a list of PIL images
assert len(prompts) == len(images), "1 prompt must match 1 image!"

рд╣рдордиреЗ рдПрдХ batch_predict рдлрд╝рдВрдХреНрд╢рди рдмрдирд╛рдпрд╛ рд╣реИ рдЬреЛ рдЯреЗрд╕реНрдЯ рдбреЗрдЯрд╛рд╕реЗрдЯ рдХреЛ рдмреИрдЪ рдореЗрдВ рдкреНрд░реЛрд╕реЗрд╕ рдХрд░рддрд╛ рд╣реИред рдпрд╣ рдлрд╝рдВрдХреНрд╢рди рдкреНрд░рддреНрдпреЗрдХ рдкреНрд░реЙрдореНрдкреНрдЯ-рдЗрдореЗрдЬ рдЬреЛрдбрд╝реА рдХреЗ рд▓рд┐рдП рднрд╡рд┐рд╖реНрдпрд╡рд╛рдгреА рдЬрдирд░реЗрдЯ рдХрд░рддрд╛ рд╣реИ рдФрд░ рдЖрдЙрдЯрдкреБрдЯ рдХреЛ рд╕рд╣реА рд▓реЗрдмрд▓реНрд╕ рд╕реЗ рдореИрдк рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкреЛрд╕реНрдЯ-рдкреНрд░реЛрд╕реЗрд╕рд┐рдВрдЧ рд▓рд╛рдЧреВ рдХрд░рддрд╛ рд╣реИред

import torch
from typing import List, Any, Callable


def batch_predict(
    prompts,
    images,
    model,
    processor,
    postprocess,
    *,
    batch_size=64,
    device="cuda",
    dtype=torch.bfloat16,
    **gen_kwargs
):
    preds = []
    for i in range(0, len(prompts), batch_size):
        texts = prompts[i : i + batch_size]
        imgs = [[img] for img in images[i : i + batch_size]]
        enc = processor(text=texts, images=imgs, padding=True, return_tensors="pt").to(
            device, dtype=dtype
        )
        lens = enc["attention_mask"].sum(dim=1)
        with torch.inference_mode():
            out = model.generate(
                **enc,
                disable_compile=True,
                **gen_kwargs
            )
        for seq, ln in zip(out, lens):
            ans = processor.decode(seq[ln:], skip_special_tokens=True)
            preds.append(postprocess(ans))
    return preds

рд╣рдо рдЯреЗрд╕реНрдЯ рдбреЗрдЯрд╛рд╕реЗрдЯ рдкрд░ рдмреЗрд╕ рдореЙрдбрд▓ рдХреЗ рд▓рд┐рдП рднрд╡рд┐рд╖реНрдпрд╡рд╛рдгрд┐рдпрд╛рдБ рдЬрдирд░реЗрдЯ рдХрд░рдиреЗ рд╣реЗрддреБ batch_predict рдлрд╝рдВрдХреНрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗред рдЗрд╕рдХреЗ рдмрд╛рдж, рднрд╡рд┐рд╖реНрдпрд╡рд╛рдгрд┐рдпреЛрдВ рдХрд╛ рдореВрд▓реНрдпрд╛рдВрдХрди compute_metrics рдлрд╝рдВрдХреНрд╢рди рд╕реЗ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред

bf_preds = batch_predict(
    model         = model,
    processor     = processor,
    prompts       = prompts,
    images        = images,
    batch_size    = 64,
    max_new_tokens= 40,          # forwarded to generate
    postprocess= postprocess, # your label-mapping function
)




bf_metrics = compute_metrics(bf_preds)
print(f"Baseline metrics: {bf_metrics}")

рдкрд░рд┐рдгрд╛рдо рдкреНрд░рднрд╛рд╡рд╢рд╛рд▓реА рдирд╣реАрдВ рд╣реИред рд╣рдореЗрдВ 33% accuracy рдорд┐рд▓реА, рдЬреЛ рдХрд╛рдлреА рдХрдордЬреЛрд░ рд╣реИред┬а

Baseline metrics: {'accuracy': 0.33745874587458746, 'f1': 0.1737287617650654}

рдореЙрдбрд▓ рдХреЗ рд╡реНрдпрд╡рд╣рд╛рд░ рдХреЛ рдмреЗрд╣рддрд░ рд╕рдордЭрдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо рдбреЗрдЯрд╛рд╕реЗрдЯ рд╕реЗ рдПрдХрд▓ рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП рднрд╡рд┐рд╖реНрдпрд╡рд╛рдгреА рдЬрдирд░реЗрдЯ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдЗрд╕рдХреЗ рд▓рд┐рдП рдЗрдирдкреБрдЯ рдкреНрд░реЛрд╕реЗрд╕ рдХрд░рдиреЗ рдФрд░ рдореЙрдбрд▓ рдХрд╛ рдЙрддреНрддрд░ рд▓реМрдЯрд╛рдиреЗ рд╣реЗрддреБ рдПрдХ рд╣реЗрд▓реНрдкрд░ рдлрд╝рдВрдХреНрд╢рди рдмрдирд╛рддреЗ рд╣реИрдВред

predict_one рдлрд╝рдВрдХреНрд╢рди рдкреНрд░реЙрдореНрдкреНрдЯ рдФрд░ рдЗрдореЗрдЬ рдХреЛ рдЗрдирдкреБрдЯ рдХреЗ рд░реВрдк рдореЗрдВ рд▓реЗрдХрд░ рдореЙрдбрд▓ рдХреЗ рдкреНрд░реЛрд╕реЗрд╕рд░ рд╕реЗ рдкреНрд░реЛрд╕реЗрд╕ рдХрд░рддрд╛ рд╣реИ рдФрд░ рдПрдХ рд░рд┐рд╕реНрдкреЙрдиреНрд╕ рдЬрдирд░реЗрдЯ рдХрд░рддрд╛ рд╣реИред рдпрд╣ рдлрд╝рдВрдХреНрд╢рди рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рддрд╛ рд╣реИ рдХрд┐ рдореЙрдбрд▓ рдХрд╛ рдЖрдЙрдЯрдкреБрдЯ рдорд╛рдирд╡-рдкрдардиреАрдп рдЯреЗрдХреНрд╕реНрдЯ рдореЗрдВ рдбрд┐рдХреЛрдб рд╣реЛред

import torch
from typing import Union, Dict, Any, List
from transformers import AutoModelForImageTextToText, AutoProcessor


def predict_one(
    prompt,
    image,
    model,
    processor,
    *,
    device="cuda",
    dtype=torch.bfloat16,
    disable_compile=True,
    **gen_kwargs
) -> str:
    inputs = processor(text=prompt, images=image, return_tensors="pt").to(
        device, dtype=dtype
    )
    plen = inputs["input_ids"].shape[-1]
    with torch.inference_mode():
        ids = model.generate(
            **inputs,
            disable_compile=disable_compile,
            **gen_kwargs
        )
    return processor.decode(ids[0, plen:], skip_special_tokens=True)

рд╣рдо рдбреЗрдЯрд╛рд╕реЗрдЯ рдХреЗ 11рд╡реЗрдВ рд╕реИрдВрдкрд▓ рдХреЗ рд▓рд┐рдП predict_one рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЙрддреНрддрд░ рдЬрдирд░реЗрдЯ рдХрд░реЗрдВрдЧреЗред рдЗрд╕рдореЗрдВ рдкреНрд░реЙрдореНрдкреНрдЯ рддреИрдпрд╛рд░ рдХрд░рдирд╛ рдФрд░ рдкреНрд░реЗрдбрд┐рдХреНрд╢рди рдлрд╝рдВрдХреНрд╢рди рдЪрд▓рд╛рдирд╛ рд╢рд╛рдорд┐рд▓ рд╣реИред

idx     = 10
chat    = test_data["messages"][idx]
prompt  = processor.apply_chat_template(
            chat,
            add_generation_prompt=True,
            tokenize=False
          )

# run the one-sample helper
answer = predict_one(
    prompt   = prompt,
    image    = test_data["image"][idx],
    model    = model,
    processor= processor,
    max_new_tokens = 40 
)

print("Model answer:", answer)

рдкрд░рд┐рдгрд╛рдорд╕реНрд╡рд░реВрдк, рд╣рдореЗрдВ рдПрдХ рд▓рдВрдмрд╛ рд╡рд╛рдХреНрдп рдорд┐рд▓рд╛ рдЬрд┐рд╕рдореЗрдВ рдмрддрд╛рдпрд╛ рдЧрдпрд╛ рдХрд┐ рдмреНрд░реЗрди рдЧреНрд▓рд┐рдпреЛрдорд╛ рдХреНрдпреЛрдВ рдЪреБрдирд╛ рдЧрдпрд╛ред рдЙрддреНрддрд░ рдкреВрд░реА рддрд░рд╣ рдЧрд▓рдд рд╣реИ, рд╡рд░реНрдЧреАрдХрд░рдг рднреА рдЧрд▓рдд рд╣реИред

Model answer: Based on the MRI image, the most likely type of brain cancer is **A: brain glioma**.

Here's why:

*   **Gliomas** are a common type of brain tumor

11. рдлрд╛рдЗрди-рдЯреНрдпреВрди рдореЙрдбрд▓ рдкрд░ рдореЙрдбрд▓ рдкреНрд░рджрд░реНрд╢рди

рдлрд╛рдЗрди-рдЯреНрдпреВрди рдХрд┐рдП рдЧрдП рдореЙрдбрд▓ рдХрд╛ рдореВрд▓реНрдпрд╛рдВрдХрди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо рдЖрдЙрдЯрдкреБрдЯ рдбрд╛рдпрд░реЗрдХреНрдЯрд░реА рд╕реЗ рдореЙрдбрд▓ рд▓реЛрдб рдХрд░рдХреЗ, рднрд╡рд┐рд╖реНрдпрд╡рд╛рдгрд┐рдпрд╛рдБ рдЬрдирд░реЗрдЯ рдХрд░рдХреЗ рдФрд░ рдореЗрдЯреНрд░рд┐рдХреНрд╕ рдХреА рдЧрдгрдирд╛ рдХрд░рдХреЗ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХреЛ рджреЛрд╣рд░рд╛рддреЗ рд╣реИрдВред

рд╣рдо рдЖрдЙрдЯрдкреБрдЯ рдбрд╛рдпрд░реЗрдХреНрдЯрд░реА рд╕реЗ рдлрд╛рдЗрди-рдЯреНрдпреВрди рдореЙрдбрд▓ рдФрд░ рдкреНрд░реЛрд╕реЗрд╕рд░ рд▓реЛрдб рдХрд░рддреЗ рд╣реИрдВ, batch_predict рдлрд╝рдВрдХреНрд╢рди рдЪрд▓рд╛рддреЗ рд╣реИрдВ, рдФрд░ рдореЗрдЯреНрд░рд┐рдХреНрд╕ рдХреА рдЧрдгрдирд╛ рдХрд░рддреЗ рд╣реИрдВред┬а

model = AutoModelForImageTextToText.from_pretrained(
    args.output_dir, **model_kwargs
)
model.generation_config = gen_cfg

processor  = AutoProcessor.from_pretrained(args.output_dir)
tok = processor.tokenizer

model.config.pad_token_id            = tok.pad_token_id
model.generation_config.pad_token_id = tok.pad_token_id

af_preds = batch_predict(
    model         = model,
    processor     = processor,
    prompts       = prompts,
    images        = images,
    batch_size    = 64,
    max_new_tokens= 40,          # forwarded to generate
    postprocess= postprocess, # your label-mapping function
)
af_metrics = compute_metrics(af_preds)
print(f"Fine-tuned metrics: {af_metrics}")

рдпреЗ рдкрд░рд┐рдгрд╛рдо рдмреЗрд╕ рдореЙрдбрд▓ рдХреА рддреБрд▓рдирд╛ рдореЗрдВ рдорд╣рддреНрд╡рдкреВрд░реНрдг рд╕реБрдзрд╛рд░ рджрд░реНрд╢рд╛рддреЗ рд╣реИрдВ, рдЬреЛ рдлрд╛рдЗрди-рдЯреНрдпреВрдирд┐рдВрдЧ рдХреА рдкреНрд░рднрд╛рд╡рд╢реАрд▓рддрд╛ рдХреЛ рд░реЗрдЦрд╛рдВрдХрд┐рдд рдХрд░рддреЗ рд╣реИрдВред рдХреЗрд╡рд▓ 1 epoch рдореЗрдВ accuracy 33% рд╕реЗ рдмрдврд╝рдХрд░ 89% рд╣реЛ рдЧрдИред┬а

Fine-tuned metrics: {'accuracy': 0.8927392739273927, 'f1': 0.892641793935792}

рдлрд╛рдЗрди-рдЯреНрдпреВрди рдореЙрдбрд▓ рдХреЗ рдкреНрд░рджрд░реНрд╢рди рдХрд╛ рдФрд░ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо рдЯреЗрд╕реНрдЯ рдбреЗрдЯрд╛рд╕реЗрдЯ рд╕реЗ рдПрдХрд▓ рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП рднрд╡рд┐рд╖реНрдпрд╡рд╛рдгреА рдЬрдирд░реЗрдЯ рдХрд░рддреЗ рд╣реИрдВред

idx     = 10
chat    = test_data["messages"][idx]
prompt  = processor.apply_chat_template(
            chat,
            add_generation_prompt=True,
            tokenize=False
          )

# run the one-sample helper
answer = predict_one(
    prompt   = prompt,
    image    = test_data["image"][idx],
    model    = model,
    processor= processor,
    max_new_tokens = 40              # any generate-kwargs you need
)

print("Model answer:", answer)

рдореЙрдбрд▓ рдиреЗ рдкрд░рд┐рдгрд╛рдо рд╕реНрдкрд╖реНрдЯ рдФрд░ рд╕рдЯреАрдХ рддрд░реАрдХреЗ рд╕реЗ рджрд┐рдпрд╛, рдЬрд┐рд╕рдореЗрдВ рд╡рд░реНрдЧреАрдХрд░рдг рд╕рд╣реА рдФрд░ рд╕реБрд╡реНрдпрд╡рд╕реНрдерд┐рдд рдерд╛ред

Model answer: C: brain tumor

рдпрджрд┐ рдЖрдкрдХреЛ рдЙрдкрд░реЛрдХреНрдд рдХреЛрдб рдЪрд▓рд╛рдиреЗ рдореЗрдВ рд╕рдорд╕реНрдпрд╛ рдЖ рд░рд╣реА рд╣реИ, рддреЛ рдХреГрдкрдпрд╛ рд╕рд╣рд╛рдпрдХ рдиреЛрдЯрдмреБрдХ рджреЗрдЦреЗрдВ: Fine_tuning_MedGemma.ipynb

рдирд┐рд╖реНрдХрд░реНрд╖

MedGemma рдЪрд┐рдХрд┐рддреНрд╕рд╛ рд╡рд┐рдЬреНрдЮрд╛рди рдореЗрдВ AI рдХреЗ рдЙрдкрдпреЛрдЧ рдореЗрдВ рдПрдХ рдорд╣рддреНрд╡рдкреВрд░реНрдг рдХрджрдо рдХрд╛ рдкреНрд░рддрд┐рдирд┐рдзрд┐рддреНрд╡ рдХрд░рддрд╛ рд╣реИред рдбреЙрдХреНрдЯрд░реЛрдВ рдФрд░ рдЪрд┐рдХрд┐рддреНрд╕рдХреЛрдВ рдХреЛ рддреЗрдЬрд╝ рдФрд░ рдЕрдзрд┐рдХ рд╕рдЯреАрдХ рдирд┐рд░реНрдгрдп рд▓реЗрдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рдмрдирд╛рдХрд░, рдпрд╣ рддреЗрдЬрд╝ рдирд┐рджрд╛рди рдФрд░ рд░реЛрдЧрд┐рдпреЛрдВ рдХреЗ рд▓рд┐рдП рдЕрдзрд┐рдХ рдкреНрд░рднрд╛рд╡реА рдЙрдкрдЪрд╛рд░ рдпреЛрдЬрдирд╛рдПрдБ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рддрд╛ рд╣реИред┬а

MedGemma 4B Instruct рдЬреИрд╕реЗ рд╡рд┐рдЬрд╝рди-рд▓реИрдВрдЧреНрд╡реЗрдЬ рдореЙрдбрд▓реЛрдВ рдХрд╛ рдлрд╛рдЗрди-рдЯреНрдпреВрдирд┐рдВрдЧ, рдЗрдореЗрдЬ рдХреНрд▓рд╛рд╕рд┐рдлрд┐рдХреЗрд╢рди рд╕реЗ рд▓реЗрдХрд░ рддрд░реНрдХ-рдХреНрд╖рдорддрд╛рдУрдВ рдХреЗ рдПрдХреАрдХрд░рдг рддрдХ, рд╡рд┐рд╡рд┐рдз рдЪрд┐рдХрд┐рддреНрд╕рд╛ рдХрд╛рд░реНрдпреЛрдВ рдореЗрдВ рдЕрдиреБрдХреВрд▓рддрд╛ рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИред┬а

рдЗрд╕ рдЯреНрдпреВрдЯреЛрд░рд┐рдпрд▓ рдореЗрдВ, рд╣рдордиреЗ рдмреНрд░реЗрди рдХреИрдВрд╕рд░ рд╡рд░реНрдЧреАрдХрд░рдг рдХреЗ рд▓рд┐рдП рдмреНрд░реЗрди MRI рдбреЗрдЯрд╛рд╕реЗрдЯ рдкрд░ рд╡рд┐рдЬрд╝рди-рд▓реИрдВрдЧреНрд╡реЗрдЬ рдореЙрдбрд▓ рдХреЛ рдлрд╛рдЗрди-рдЯреНрдпреВрди рдХрд░рдирд╛ рд╕реАрдЦрд╛ред рдкрд░рд┐рдгрд╛рдо рдЙрд▓реНрд▓реЗрдЦрдиреАрдп рд░рд╣реЗтАФрдореЙрдбрд▓ рдХреА accuracy 33% рд╕реЗ рдмрдврд╝рдХрд░ 89% рд╣реЛ рдЧрдИтАФрдЬреЛ рдЪрд┐рдХрд┐рддреНрд╕рд╛ AI рдЕрдиреБрдкреНрд░рдпреЛрдЧреЛрдВ рдореЗрдВ рдлрд╛рдЗрди-рдЯреНрдпреВрдирд┐рдВрдЧ рдХреА рдХреНрд╖рдорддрд╛ рдХреЛ рджрд░реНрд╢рд╛рддрд╛ рд╣реИред

рдпрджрд┐ рдЖрдк рдФрд░ рд╕реАрдЦрдиреЗ рдореЗрдВ рд░реБрдЪрд┐ рд░рдЦрддреЗ рд╣реИрдВ, рддреЛ рдореИрдВ рдирд┐рдореНрди рд╕рдВрд╕рд╛рдзрди рджреЗрдЦрдиреЗ рдХреА рдЕрдиреБрд╢рдВрд╕рд╛ рдХрд░рддрд╛/рдХрд░рддреА рд╣реВрдБ:┬а

Abid Ali Awan

рд▓реЗрдЦрдХ

Abid Ali Awan

рдПрдХ рдкреНрд░рдорд╛рдгрд┐рдд рдбреЗрдЯрд╛ рд╕рд╛рдЗрдВрдЯрд┐рд╕реНрдЯ рдХреЗ рд░реВрдк рдореЗрдВ, рдореИрдВ рдЕрддреНрдпрд╛рдзреБрдирд┐рдХ рддрдХрдиреАрдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдирд╡рд╛рдЪрд╛рд░реА рдорд╢реАрди рд▓рд░реНрдирд┐рдВрдЧ рдЕрдиреБрдкреНрд░рдпреЛрдЧ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдЙрддреНрд╕рд╛рд╣рд┐рдд рд░рд╣рддрд╛/рд░рд╣рддреА рд╣реВрдБред рд╕реНрдкреАрдЪ рд░рд┐рдХреЙрдЧреНрдирд┐рд╢рди, рдбреЗрдЯрд╛ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдФрд░ рд░рд┐рдкреЛрд░реНрдЯрд┐рдВрдЧ, MLOps, рд╕рдВрд╡рд╛рджрд╛рддреНрдордХ AI рдФрд░ NLP рдореЗрдВ рдордЬрдмреВрдд рдкреГрд╖реНрдарднреВрдорд┐ рдХреЗ рд╕рд╛рде, рдореИрдВрдиреЗ рдРрд╕реЗ рдмреБрджреНрдзрд┐рдорд╛рди рд╕рд┐рд╕реНрдЯрдо рд╡рд┐рдХрд╕рд┐рдд рдХрд░рдиреЗ рдореЗрдВ рдЕрдкрдиреА рд╡рд┐рд╢реЗрд╖рдЬреНрдЮрддрд╛ рдирд┐рдЦрд╛рд░реА рд╣реИ рдЬреЛ рд╡рд╛рд╕реНрддрд╡рд┐рдХ рдкреНрд░рднрд╛рд╡ рдбрд╛рд▓ рд╕рдХреЗрдВред рддрдХрдиреАрдХреА рджрдХреНрд╖рддрд╛ рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдореИрдВ рдЬрдЯрд┐рд▓ рдЕрд╡рдзрд╛рд░рдгрд╛рдУрдВ рдХреЛ рд╕реНрдкрд╖реНрдЯ рдФрд░ рд╕рдВрдХреНрд╖рд┐рдкреНрдд рднрд╛рд╖рд╛ рдореЗрдВ рдкреНрд░рд╕реНрддреБрдд рдХрд░рдиреЗ рдореЗрдВ рднреА рдирд┐рдкреБрдг рд╣реВрдБред рдкрд░рд┐рдгрд╛рдорд╕реНрд╡рд░реВрдк, рдореИрдВ рдбреЗрдЯрд╛ рд╕рд╛рдЗрдВрд╕ рдкрд░ рдПрдХ рдорд╛рдВрдЧ рдореЗрдВ рд░рд╣рдиреЗ рд╡рд╛рд▓рд╛/рд╡рд╛рд▓реА рдмреНрд▓реЙрдЧрд░ рдмрди рдЧрдпрд╛/рдЧрдИ рд╣реВрдБ, рдФрд░ рдбреЗрдЯрд╛ рдкреНрд░реЛрдлреЗрд╢рдирд▓реЛрдВ рдХреЗ рдмрдврд╝рддреЗ рд╕рдореБрджрд╛рдп рдХреЗ рд╕рд╛рде рдЕрдкрдиреЗ рдЕрдиреБрднрд╡ рдФрд░ рд╡рд┐рдЪрд╛рд░ рд╕рд╛рдЭрд╛ рдХрд░рддрд╛/рдХрд░рддреА рд╣реВрдБред рд╡рд░реНрддрдорд╛рди рдореЗрдВ, рдореИрдВ рдХрдВрдЯреЗрдВрдЯ рдирд┐рд░реНрдорд╛рдг рдФрд░ рд╕рдВрдкрд╛рджрди рдкрд░ рдХреЗрдВрджреНрд░рд┐рдд рд╣реВрдБ, рдмрдбрд╝реЗ рднрд╛рд╖рд╛ рдореЙрдбрд▓реЛрдВ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рддреЗ рд╣реБрдП рдРрд╕рд╛ рдкреНрд░рднрд╛рд╡рд╢рд╛рд▓реА рдФрд░ рдЖрдХрд░реНрд╖рдХ рдХрдВрдЯреЗрдВрдЯ рд╡рд┐рдХрд╕рд┐рдд рдХрд░ рд░рд╣рд╛/рд░рд╣реА рд╣реВрдБ рдЬреЛ рд╡реНрдпрд╡рд╕рд╛рдпреЛрдВ рдФрд░ рд╡реНрдпрдХреНрддрд┐рдпреЛрдВ рджреЛрдиреЛрдВ рдХреЛ рдЕрдкрдиреЗ рдбреЗрдЯрд╛ рдХрд╛ рдЕрдзрд┐рдХрддрдо рд▓рд╛рдн рдЙрдард╛рдиреЗ рдореЗрдВ рдорджрдж рдХрд░ рд╕рдХреЗред

рд╡рд┐рд╖рдп