TL;DR для торопыжек

25 февраля — финал The MedGemma Impact Challenge на Kaggle. Я уже несколько недель копаюсь в этой медицинской модели от Google, пытаясь выжать из неё что-то крутое для конкурса. Пока идеальное решение где-то между "гениально" и "зачем я это делаю в 3 ночи", решил поделиться тем, как вообще эта штука работает и что с ней можно делать.

Спойлер: она умеет не только отвечать "идите к врачу" на любой симптом 🏥

Почему я вообще за это взялся?

Есть такая штука — MedGemma. Google взяли свою Gemma, скормили ей всю медицинскую литературу (наверное, включая инструкции к валидолу), и получилась модель, которая:

  • Понимает, что HbA1c — это не новая криптовалюта

  • Может анализировать симптомы без паники

  • Работает на обычной RTX 4060 (привет, майнерам прошлых лет)

  • Отвечает на русском без потери в качестве

И вот на Kaggle запустили челлендж с призовым фондом, а я подумал: "Сколько ещё можно писать скрипты для парсинга? Пора спасать человечество с помощью AI!"

Три недели спустя я уже знаю о тензорах в bfloat16 больше, чем о своём давлении. Но кое-что интересное удалось выяснить.

Что это вообще такое?

MedGemma — это не просто "ChatGPT для медицины". Это специально обученная модель, которая:

  1. Реально знает медицину — её учили не на Stack Overflow, а на PubMed и медицинских учебниках

  2. Мультимодальная — понимает и текст, и картинки (представьте, может анализировать рентген!)

  3. Локальная — работает у вас на компе, никуда не сливая ваши медицинские данные

  4. Весит разумно — 4B параметров, а не 175B как некоторые

Важный дисклеймер: это не медицинский прибор, не лицензированный софт для диагностики, и вообще всегда консультируйтесь с врачом. Но для исследований и прототипов — самое то.

Запускаем локально (да, на вашей RTX!)

Проверяем, есть ли у нас GPU

Первым делом убеждаемся, что видеокарта не ушла на майнинг:

import torch, gc

gc.collect()
if torch.cuda.is_available():
    torch.cuda.empty_cache()
    print(f"GPU: {torch.cuda.get_device_name(0)} | "
          f"{torch.cuda.get_device_properties(0).total_memory/1e9:.1f} GB")
else:
    print("Эх, придётся на CPU... Иди чай поставь на часик")

У меня вывод такой:

GPU: NVIDIA GeForce RTX 4060 Laptop GPU | 8.6 GB

8.6 гигов — в самый раз. На 4 гига уже будет грустно, на 16+ — вообще красота.

Грузим модель (осторожно, тяжело!)

from transformers import AutoProcessor, AutoModelForImageTextToText
import time

MODEL_ID = "google/medgemma-4b-it"
print(f"Loading {MODEL_ID}...")
print("(Самое время проверить почту, это займёт ~10 секунд)")
start = time.time()

model = AutoModelForImageTextToText.from_pretrained(
    MODEL_ID, 
    torch_dtype=torch.bfloat16,  # bfloat16 — магия для экономии памяти
    device_map="auto"            # auto = "разберись сам, умная библиотека"
)
processor = AutoProcessor.from_pretrained(MODEL_ID)

print(f"✅ Загрузилось за {time.time()-start:.1f}s")
print(f"💾 GPU занято: {torch.cuda.memory_allocated()/1e9:.2f} GB")
print("🎉 Можно работать!")

Мой результат:

✅ Загрузилось за 6.7s
💾 GPU занято: 8.63 GB
🎉 Можно работать!

Если у вас загрузка падает с CUDA out of memory — поздравляю, вы в клубе "пора обновляться". Можно попробовать квантизацию до int8, но это отдельная история.

Функция для общения с моделью

Чтобы каждый раз не писать километры кода, делаем helper:

def ask(prompt, tokens=300):
    """
    Спросить у MedGemma что-нибудь умное
    
    Args:
        prompt: ваш вопрос (можно на русском!)
        tokens: сколько максимум слов в ответе
    
    Returns:
        str: ответ модели (надеюсь, адекватный)
    """
    messages = [{
        "role": "user", 
        "content": [{"type": "text", "text": prompt}]
    }]
    
    inputs = processor.apply_chat_template(
        messages, 
        add_generation_prompt=True,
        tokenize=True, 
        return_dict=True, 
        return_tensors="pt"
    ).to(model.device, dtype=torch.bfloat16)
    
    with torch.inference_mode():
        outputs = model.generate(
            **inputs, 
            max_new_tokens=tokens, 
            do_sample=False  # детерминированные ответы
        )
    
    return processor.decode(
        outputs[0][inputs["input_ids"].shape[-1]:], 
        skip_special_tokens=True
    ).strip()

Гоняем тесты (и офигеваем от результатов)

Тест 1: Базовая проверка на адекватность

print("🩺 Спрашиваю про гипертензию...")
print("─" * 50)
print(ask("What is hypertension? Answer briefly."))

Ответ:

Hypertension is a condition in which the blood pressure 
in the arteries is persistently elevated.

Ок, модель не галлюцинирует, что гипертензия — это новый вид йоги. Годится.

Тест 2: А по-русски слабо?

print("🩺 Теперь по-русски...")
print("─" * 50)
print(ask("Что такое гипертензия и каковы её основные причины?"))

Ответ (сокращённо):

Гипертензия (высокое кровяное давление) - это состояние, 
при котором кровяное давление в артериях постоянно повышено.

Основные причины:
- Генетическая предрасположенность
- Образ жизни: неправильное питание, недостаток физической активности
- Возраст: с возрастом риск увеличивается
- Сопутствующие заболевания: диабет, болезни почек
- Стресс: хронический стресс может способствовать повышению давления

Вот это поворот! Модель не просто перевела, а дала структурированный ответ с маркированным списком. Кто-то в Google явно любит аккуратность.

Тест 3: Доктор Хаус режим ON

Даём модели симптомы и смотрим, что она предложит:

print("🔍 Анализируем симптомы...")
print("─" * 50)
print(ask("""Пациент: головная боль 3 дня, температура 38.5°C, 
боль в горле, насморк. Какие возможные диагнозы? 
Перечисли 3-4 варианта."""))

Ответ модели:

На основании предоставленной информации, возможные диагнозы:

1. Острый риносинусит (простуда): Сочетание насморка, боли в горле 
   и головной боли характерны для этого заболевания.

2. Грипп: Может проявляться схожими симптомами, включая головную боль, 
   лихорадку, боль в горле и насморк.

3. Инфекционный мононуклеоз: Хотя обычно сопровождается более выраженными 
   симптомами, может включать головную боль, лихорадку и боль в горле.

4. COVID-19: Может проявляться широким спектром симптомов, включая 
   перечисленные.

⚠️ ВАЖНО: Это лишь предположения. Для постановки точного диагноза 
необходима консультация врача.

Офигеть! Модель:

  • Дала 4 варианта с объяснениями

  • Не забыла про COVID (актуально)

  • Добавила disclaimer про врача

  • Не предложила лечиться чесноком и молитвами

Для AI-модели это очень зрелое поведение.

Тест 4: Провизор в твоём ноутбуке

print("💊 Рассказываем про лекарства...")
print("─" * 50)
print(ask("Расскажи о Метформине: показания, механизм действия, побочные эффекты."))

Ответ (кратко):

Модель выдала:

  • Показания: диабет 2 типа, преддиабет, СПКЯ, ожирение

  • Механизм: улучшение чувствительности к инсулину, снижение выработки глюкозы печенью

  • Побочки: ЖКТ-расстройства, дефицит B12, лактоацидоз (редко)

Это уровень ответа из хорошего медицинского справочника. Для модели на 4B параметров — впечатляет.

Тест 5: Опасные комбинации

Проверяем, понимает ли модель взаимодействие лекарств:

print("⚠️ Проверяем взаимодействия...")
print("─" * 50)
print(ask("Можно ли принимать аспирин и ибупрофен вместе? Какие риски?"))

Краткая выжимка ответа:

❌ Прием аспирина и ибупрофена вместе НЕ РЕКОМЕНДУЕТСЯ

Риски:
- Повышенный риск кровотечений (оба НПВП)
- Повреждение почек при длительном использовании
- Повреждение желудка и риск язвы
- Усиление побочных эффектов

Комбинация может быть оправдана только по назначению врача.

Модель не просто сказала "нельзя", а объяснила почему и когда всё-таки можно. Это важно.

Тест 6: Разбор анализов (самое интересное!)

Тут я проверяю, может ли модель интерпретировать результаты. Даём ей цифры из анализа крови:

print("📋 Интерпретируем анализы...")
print("─" * 50)
print(ask("""Результаты:
- Глюкоза: 7.8 ммоль/л (норма: 3.9-5.5)
- HbA1c: 6.8% (норма: <5.7%)
Что это значит?"""))

Ответ модели:

Ваши результаты анализов крови показывают, что у вас ДИАБЕТ 2 ТИПА.

📊 Глюкоза (7.8 ммоль/л):
Уровень выше нормы указывает на то, что организм не может 
эффективно использовать глюкозу для энергии.

📊 HbA1c (6.8%):
Показатель среднего уровня глюкозы за последние 2-3 месяца. 
Превышение нормы также указывает на диабет.

⚠️ Возможные долгосрочные осложнения:
- Сердечно-сосудистые заболевания
- Диабетическая нейропатия (повреждение нервов)
- Диабетическая нефропатия (повреждение почек)
- Диабетическая ретинопатия (повреждение глаз)

Это... это просто охренеть! Модель:

  1. Правильно определила диагноз

  2. Объяснила значение каждого показателя

  3. Перечислила осложнения

  4. Всё это — на основе двух цифр

Что я понял за три недели работы с MedGemma

Плюсы (их много)

Локальность — данные не уходят в облако
Скорость — ответы генерируются за секунды
Русский язык — работает без костылей
Структурированность — ответы как из учебника
Честность — признаёт ограничения и шлёт к врачу

Минусы (их тоже хватает)

Не может в контекст — не знает историю болезни
Галлюцинации — редко, но бывают
Нет персонализации — одинаково для всех
Юридически непригодна — не медицинский прибор
Требует GPU — на CPU будет медленно

Производительность на RTX 4060 Laptop

Метрика

Значение

Загрузка модели

~6.7 сек

Потребление VRAM

8.63 GB

Генерация (100 токенов)

~3-5 сек

Температура GPU

65-70°C

Потребление энергии

~80W

Вполне рабочие цифры для ноутбука.

Идеи для Kaggle Challenge (и не только)

Пока я экспериментирую с такими направлениями:

1. Медицинский чат-бот для триажа

Бот, который задаёт правильные вопросы и определяет срочность обращения. Не ставит диагноз, а помогает понять: "это вызов скорой" или "можно записаться к терапевту на неделе".

2. Анализатор взаимодействий лекарств

Загружаешь список своих препаратов, получаешь предупреждения о возможных конфликтах. Особенно актуально для пожилых людей с кучей таблеток.

3. Переводчик медицинского языка

Врач написал в выписке непонятные термины? Модель переводит на человеческий язык без потери смысла.

4. Помощник для интерпретации анализов

Получил результаты — вставил в приложение, получил объяснение что к чему. С рекомендацией "показать врачу", естественно.

Технические детали для гиков

Почему bfloat16, а не float16?

bfloat16 (brain float) — формат от Google с такой же точностью по экспоненте, как у float32, но с меньшей мантиссой. Для языковых моделей это идеально:

  • Меньше памяти (2 байта вместо 4)

  • Меньше риск переполнения

  • Почти та же точность

Про квантизацию

Если 8 GB VRAM не хватает, можно загрузить модель в int8:

from transformers import BitsAndBytesConfig

quantization_config = BitsAndBytesConfig(
    load_in_8bit=True,
    llm_int8_threshold=6.0
)

model = AutoModelForImageTextToText.from_pretrained(
    MODEL_ID,
    quantization_config=quantization_config,
    device_map="auto"
)

Качество почти не страдает, зато модель влезет в 4-6 GB.

Про inference_mode vs no_grad

torch.inference_mode() быстрее, чем torch.no_grad():

  • Отключает autograd полностью

  • Оптимизирует выполнение графа

  • Блокирует случайные изменения весов

Для инференса всегда используйте inference_mode.

Этические вопросы (да, они важны)

Работая с медицинским AI, я постоянно думаю:

🤔 Кто отвечает за ошибки? Если модель неправильно проанализирует симптомы и человек поверит?

🤔 Доступность vs безопасность? Медицинская информация должна быть доступной, но не опасной.

🤔 Замена врачей? Нет, это инструмент для врачей, не замена им.

🤔 Приватность данных? Даже локальная модель должна работать с шифрованием.

Пока у меня больше вопросов, чем ответов. Но думаю об этом.

Полезные ссылки

Заключение

MedGemma — это не просто "ещё одна LLM". Это первая медицинская модель, которую можно запустить локально на потребительском железе и получить реально полезные результаты.

Конечно, она не заменит врача. Но может:

  • Помочь студентам-медикам учиться

  • Объяснить пациентам их анализы понятным языком

  • Подсказать исследователям направления поиска

  • Стать основой для медицинских приложений

До финала челленджа осталось несколько недель. Посмотрим, что выйдет. В любом случае, опыт работы с медицинским AI — это круто.


P.S. Если у вас есть идеи для Kaggle Challenge или вы тоже участвуете — пишите в комментах! Может, что-то замутим вместе.

P.P.S. Всегда консультируйтесь с врачом. Эта статья — для образования и экспериментов, а не медицинских советов.

P.P.P.S. Да, я действительно провёл три недели, разговаривая с AI про диабет и гипертензию. Моя поисковая история теперь выглядит как будто я самый больной человек на планете 😅

Хабр, спасибо что дочитали до конца! Ставьте плюсики, если хотите продолжение после финала челленджа.