ИИ для инженера: основы Железо: почему для ИИ нужны видеокарты
0%

Железо: почему для ИИ нужны видеокарты

Железо: почему для ИИ нужны видеокарты

Фрагмент лекции: «Все что нужно знать про ИИ айтишнику», 36:39 — отсюда взято содержание этой главы.

На вопрос «почему для ИИ нужны видеокарты» обычно отвечают «потому что они быстрые». Это не ответ, а тавтология: быстрые на чём и почему именно на этом. Разберём честно, и заодно станет понятно, откуда берутся три вещи, которые волнуют пользователя гораздо сильнее устройства железа: цена запроса, скорость ответа и возможность запустить модель у себя.

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

Что именно считается при генерации одного токена

Прямой проход трансформера — это не «алгоритм с ветвлениями», а фиксированная последовательность линейно-алгебраических операций. На каждом из десятков блоков модели происходит примерно одно и то же:

  1. Номера токенов заменяются на векторы из таблицы эмбеддингов — обычная выборка строк.
  2. Вектор умножается на три большие матрицы весов, получаются запросы, ключи и значения (Q, K, V).
  3. Считается внимание: скалярные произведения запросов на ключи, нормировка, взвешенная сумма значений.
  4. Результат прогоняется через двухслойную полносвязную сеть — снова два умножения на большие матрицы.
  5. Нормализации и нелинейности — поэлементные операции, дешёвые на фоне остального.
  6. В самом конце вектор умножается на матрицу размером «словарь × размерность» и получаются логиты — по одному числу на каждый токен словаря. Из них после softmax выходит распределение вероятностей следующего токена.

Внутреннее устройство внимания разбирается в соседнем треке — «Внимание и трансформеры». Здесь важно другое: подавляющая часть работы — это умножение матриц (в терминах библиотек — GEMM, general matrix multiply). У такой нагрузки три свойства:

  • Массовая параллельность. Каждый элемент результата считается независимо от остальных.
  • Однородность. Над всеми числами выполняется одна и та же операция «умножить и прибавить». Ветвлений нет — вычисления не зависят от значений данных.
  • Предсказуемый доступ к памяти. Заранее известно, какие блоки чисел понадобятся и в каком порядке.

Это ровно тот класс задач, под который спроектирован графический ускоритель. Видеокарта появилась не потому, что кто-то решил ускорить ИИ, — она изначально решала ту же математику для геометрии и освещения сцены. Языковая модель просто попала в существующую нишу.

Процессор и ускоритель: два разных компромисса

В лекции видеокарта названа «по сути процессором» — и это верная мысль, если развернуть её точнее. Современный GPU — это самостоятельный вычислительный модуль со своими ядрами, своей памятью и своим планировщиком, подключённый к системе по шине PCIe. Он не «помогает» центральному процессору выполнять его инструкции, он исполняет собственные программы над собственными данными.

Оба чипа сделаны из транзисторов по схожим техпроцессам. Разница — в том, на что потрачен бюджет этих транзисторов.

Раскладка кристалла: у процессора несколько крупных ядер и глубокий кеш, у видеокарты сетка простых ядер и широкая шина к видеопамяти

Ось сравнения CPU GPU
Число ядер Единицы — десятки Тысячи простых ALU, сгруппированных в блоки; плюс тензорные ядра под матричные операции
Что внутри ядра Внеочередное исполнение, предсказание переходов, большие кеши Минимум логики управления, максимум арифметики
Модель исполнения Независимые потоки, каждый со своим ходом SIMT: одна инструкция на группу потоков (варп из 32) над разными данными
Целевая нагрузка Ветвления, указатели, разнородный код, задачи с зависимостями Однородная арифметика над большими массивами
Пропускная способность памяти Десятки — сотня ГБ/с (DDR5, двухканально ~90 ГБ/с) Единицы ТБ/с (HBM: у NVIDIA V100 около 0,9 ТБ/с, у A100 около 2 ТБ/с, у H100 около 3,3 ТБ/с)
Латентность одной операции Оптимизирована: важно закончить быстро Высокая и намеренно скрывается переключением между тысячами потоков
Чем плох на чужой задаче Мало параллельных умножителей и узкая память Ветвление внутри варпа исполняется последовательно по веткам

Ключевая строка — предпоследняя. CPU оптимизирован под задержку, GPU — под пропускную способность (модель исполнения SIMT описана в CUDA C++ Programming Guide). Процессор старается выполнить одну цепочку операций как можно быстрее; ускоритель не пытается ускорить одну операцию, он выполняет их десятками тысяч одновременно и прячет задержки за счёт того, что всегда есть готовый к работе поток.

Отсюда же ответ на возражение «а многопоточность?». Многопоточность на CPU делит между ядрами ту же самую узкую память и те же несколько десятков векторных блоков. Прирост от восьми ядер — восьмикратный в лучшем случае, а разрыв в пиковой арифметике между процессором и ускорителем — два порядка. Проблема не в числе потоков, а в том, сколько умножителей и сколько байт в секунду доступно.

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

Обратите внимание на объём трафика по PCIe: туда уходят несколько килобайт номеров токенов, обратно — распределение вероятностей. Всё тяжёлое остаётся внутри карты. Именно поэтому веса должны жить в видеопамяти постоянно: подгружать их по шине на каждом шаге было бы медленнее в десятки раз.

Главное узкое место — не арифметика, а память

Генерация идёт по одному токену за шаг. Чтобы посчитать один-единственный следующий токен, нужно прогнать вектор через все слои модели, то есть прочитать из видеопамяти все веса целиком. Все 14 гигабайт для модели на 7 млрд параметров в 16 битах. И так на каждый токен.

Посчитаем баланс. При чтении одного веса в формате bfloat16 (2 байта) над ним выполняется одно умножение и одно сложение — 2 операции с плавающей точкой. Получается примерно 1 операция на прочитанный байт. А у современного ускорителя отношение «пиковая производительность к пропускной способности памяти» — порядка 300 операций на байт (для H100: около 990 TFLOPS в bf16 при 3,35 ТБ/с). Разрыв в сотни раз.

Вывод жёсткий и проверяемый: при генерации для одного пользователя видеокарта загружена по арифметике на доли процента и на 100% занята чтением памяти. Это классическая memory-bound задача в терминах модели Roofline. Скорость выдачи токенов упирается в байты в секунду, а не в операции в секунду.

Отсюда простая оценка потолка: токенов в секунду ≈ пропускная способность памяти / размер весов в байтах. Для модели на 7 млрд параметров в 16 битах (14 ГБ) на карте с 2 ТБ/с это около 140 токенов в секунду при одном запросе. Реальность обычно даёт 30–60% от потолка: мешают неидеальная утилизация шины, накладные расходы ядер, чтение KV-кеша.

Две фазы запроса ведут себя по-разному

Обработка входного текста и генерация ответа — принципиально разные режимы, хотя математика в них одна.

  • Префилл (prefill) — прогон всего промпта. Токены обрабатываются параллельно, матрицы получаются широкими, на каждый прочитанный вес приходится столько операций, сколько токенов в промпте. Это compute-bound фаза, ускоритель загружен арифметикой почти полностью.
  • Декодирование (decode) — генерация ответа по токену. Матрица вырождается в один вектор, арифметическая интенсивность падает до единицы. Это memory-bound фаза.

Практическое следствие, которое видно в счетах провайдеров: выходной токен дороже и в разы медленнее входного. Тысяча токенов промпта обрабатывается за один параллельный проход, тысяча токенов ответа — за тысячу последовательных.

Отсюда батчинг

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

Именно батчинг делает облачный инференс экономически возможным. При батче в несколько десятков запросов арифметическая интенсивность поднимается с 1 до десятков операций на байт, и карта наконец начинает считать, а не ждать. Современные серверы вроде vLLM идут дальше и применяют непрерывный батчинг: закончившийся запрос сразу заменяется новым из очереди, без ожидания всей пачки.

Почему второй пользователь замедляет генерацию

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

  1. Если запросы не батчатся (типичный случай, когда модель поднята простым локальным раннером на один поток), шаги генерации чередуются. Каждый пользователь получает примерно половину шагов — и, соответственно, половину скорости. Суммарная производительность системы не меняется.
  2. Если запросы батчатся, суммарная пропускная способность растёт почти линейно (веса читаются один раз на всех), но скорость каждого отдельного пользователя всё равно падает: шаг батча длится дольше одиночного из-за возросшей арифметики и чтения нескольких KV-кешей.
  3. Ёмкость видеопамяти конечна. Каждый параллельный запрос держит собственный KV-кеш. Когда кеши перестают помещаться, планировщик начинает вытеснять запросы и пересчитывать их префилл заново — производительность падает уже нелинейно.

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

Сколько видеопамяти нужно модели

Это единственная часть темы, где считать можно точно и без оговорок. Формула тривиальна: байт под веса = число параметров × байт на параметр, где байт на параметр задаётся разрядностью — 16 бит это 2 байта, 8 бит — 1 байт, 4 бита — 0,5 байта.

Возьмём масштаб DeepSeek-V3/R1 — 671 млрд параметров (на момент лекции, май 2026, это одна из самых крупных моделей с открытыми весами; технический отчёт).

Разрядность весов Байт на параметр Только веса Карт по 80 ГБ (минимум, без кеша)
16 бит (bf16) 2 ~1,34 ТБ (1,22 ТиБ) 17
8 бит 1 ~671 ГБ 9
4 бита 0,5 ~336 ГБ 5

Отсюда прямой ответ на вопрос «почему её нельзя запустить на домашней видеокарте»: веса просто не помещаются. Даже в 4 битах модель требует пяти ускорителей верхнего класса только под веса, а с учётом KV-кеша, активаций и фрагментации памяти — заметно больше. Такие модели живут на кластерах: восемь карт в узле, несколько узлов, связанных быстрым интерконнектом, и модель, разрезанная между ними по слоям или по тензорам.

Про MoE. DeepSeek-V3 — модель со смесью экспертов: из 671 млрд параметров на обработку одного токена задействуется около 37 млрд. Это меняет арифметику асимметрично: в память нужно поместить все веса, потому что заранее неизвестно, какие эксперты понадобятся, но читать на каждом шаге приходится только активную часть. Поэтому MoE-модель требует много памяти и при этом генерирует быстрее, чем плотная модель того же размера.

Про выгрузку на диск. Часть весов действительно можно держать в системной ОЗУ или на SSD и подгружать по мере необходимости — так делают локальные раннеры. Работает, но упирается в ту же формулу: PCIe даёт десятки ГБ/с, NVMe — единицы, тогда как HBM — тысячи. Скорость падает пропорционально самому узкому звену, то есть на один-два порядка.

Про деньги. Оценки стоимости такого парка железа в лекции звучат, но без источника, поэтому здесь не приводятся. Считать в любом случае стоит не цену карты, а стоимость GPU-часа у провайдера, умноженную на реальную загрузку, — методика в статье «Продакшн и стоимость».

Квантизация: чем платят за экономию памяти

Из таблицы выше видно: разрядность весов входит в требования к памяти линейным множителем. Квантизация — это перевод весов из 16-битного формата в 8-, 6- или 4-битный с сохранением приемлемого качества.

Механика в первом приближении простая: веса каждого блока делятся на группы, для группы запоминается масштабный коэффициент, а сами значения хранятся маленькими целыми числами. При умножении масштаб возвращается обратно. Тонкость в том, что распределение весов неравномерно, и наивное округление ломает модель на выбросах, — на решении этой проблемы построены методы LLM.int8(), GPTQ, AWQ и SmoothQuant.

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

Практический ориентир, устоявшийся в сообществе: 8 бит почти бесплатны по качеству, 4 бита — рабочий компромисс для локального запуска, ниже 4 бит стоит идти только осознанно. Практика локального запуска, форматы вроде GGUF и раннеры разбираются в статье «Локальные модели».

KV-кеш: память, которая растёт вместе с диалогом

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

Этого не происходит, потому что ключи и значения (K и V) для уже обработанных токенов не меняются. Их считают один раз и складывают в KV-кеш. На каждом новом шаге считаются K и V только для одного нового токена, дописываются в кеш, и внимание берётся по всему кешу.

Плата за это — память, пропорциональная длине контекста: байт кеша = 2 (K и V) × слои × KV-головы × размерность головы × байт на число × длина контекста × число запросов.

Подставим типичную конфигурацию открытой модели на 70 млрд параметров: 80 слоёв, 8 KV-голов, размерность головы 128, формат fp16.

  • На один токен: 2 × 80 × 8 × 128 × 2 = 327 680 байт — около 320 КиБ.
  • На контекст 32 000 токенов: около 10 ГиБ на один запрос.
  • На десять параллельных запросов с таким контекстом — 100 ГиБ, что уже больше памяти одной карты.

Если бы в этой модели не было группированного внимания (GQA) и все 64 головы имели собственные K и V, тот же кеш занимал бы около 82 ГиБ на один запрос. Именно поэтому MQA и GQA стали стандартом: они сокращают не арифметику, а размер кеша, то есть именно тот ресурс, который заканчивается первым. По той же причине в DeepSeek-V3 применяется multi-head latent attention, сжимающее KV-кеш до низкоразмерного представления.

Три следствия, которые полезно держать в голове:

  • Длинный контекст стоит памяти, а не только денег. Окно в миллион токенов — это в первую очередь вопрос, куда положить кеш.
  • Число одновременных пользователей ограничено ёмкостью кеша, а не числом ядер.
  • Фрагментация кеша — реальная проблема, ради решения которой придумали PagedAttention: кеш хранится страницами, как виртуальная память в ОС.

Экономическая сторона того же механизма — почему каждое следующее сообщение диалога дороже предыдущего — разобрана в главе «Токены, контекстное окно и память диалога».

От чего на самом деле зависит скорость выдачи

Конкретное число токенов в секунду называть бессмысленно: оно зависит сразу от нескольких множителей и устаревает вместе с железом. Полезнее знать список факторов — по убыванию влияния.

  1. Размер весов в байтах — прямое деление в формуле потолка. Квантизация в 8 бит примерно удваивает скорость декодирования.
  2. Пропускная способность памяти карты — второй множитель той же формулы. Разница между поколениями ускорителей здесь больше, чем разница в пиковых FLOPS.
  3. Размер батча — определяет, делите ли вы стоимость чтения весов с кем-то ещё.
  4. Длина контекста — чем длиннее кеш, тем больше читается на каждом шаге поверх весов.
  5. Разрезание модели между картами — межкарточные обмены добавляют задержку на каждом слое.
  6. Архитектура — MoE читает только активных экспертов; спекулятивное декодирование позволяет проверять несколько предсказанных токенов за один проход.

Инженерные детали развёртывания — квантизация, батчинг, спекулятивное декодирование, выбор сервера — разбираются в статье «Инференс и развёртывание».

Маршрутизация запросов: почему на вас отвечает не всегда большая модель

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

Отсюда стандартный инженерный приём — роутинг моделей (он же каскад): дешёвая быстрая модель разбирает запрос и либо отвечает сама, либо передаёт его дальше по цепочке.

Экономический мотив здесь очевиден и его незачем прятать: провайдер платит за GPU-часы и заинтересован обслужить запрос дешевле. Но сводить каскад к «экономии на пользователе» неверно — приём даёт три эффекта сразу:

  • Латентность. Маленькая модель отвечает за доли секунды там, где большая думала бы секунды.
  • Стоимость. Существенная доля запросов в любом продукте тривиальна; перевод их на младшую модель сокращает счёт в разы.
  • Пропускная способность. Освобождённые мощности большой модели достаются тем запросам, которым они действительно нужны.

Тот же приём вы применяете сами, когда строите систему на API: раскладка запросов по моделям — базовый рычаг продакшн-экономики, наравне с кэшированием префикса («Продакшн и стоимость»). И важная оговорка про наблюдаемый эффект: если ответ выглядит поверхностным, это не обязательно роутинг на слабую модель — тот же результат дают короткий системный промпт, обрезанный контекст или неудачная формулировка запроса. Роутинг тут объяснение, а не диагноз.

Практика: калькулятор требований к видеопамяти

Соберём всё в один скрипт. Он отвечает на вопрос, который возникает каждый раз перед локальным запуском: влезет ли.

from dataclasses import dataclass

# Байт на один параметр для распространённых разрядностей весов.
BYTES_PER_PARAM = {16: 2.0, 8: 1.0, 6: 0.75, 4: 0.5}
GB = 1024 ** 3  # считаем в гибибайтах: именно их показывает nvidia-smi


@dataclass
class ModelSpec:
    """Всё это есть в config.json карточки модели на Hugging Face."""
    name: str
    params: float            # общее число параметров
    layers: int              # число блоков трансформера
    kv_heads: int            # число KV-голов (при GQA меньше числа голов внимания)
    head_dim: int            # размерность одной головы
    active_params: float | None = None  # для MoE: сколько параметров работает на токен


def weights_gb(spec: ModelSpec, bits: int = 16) -> float:
    """Веса целиком должны лежать в видеопамяти — это неснижаемый минимум."""
    return spec.params * BYTES_PER_PARAM[bits] / GB


def kv_cache_gb(spec: ModelSpec, context: int, batch: int = 1, bits: int = 16) -> float:
    """KV-кеш: по ключу и значению на каждый токен каждого слоя каждой KV-головы."""
    per_token = 2 * spec.layers * spec.kv_heads * spec.head_dim * BYTES_PER_PARAM[bits]
    return per_token * context * batch / GB


def report(spec: ModelSpec, context: int, batch: int = 1,
           weight_bits: int = 16, kv_bits: int = 16,
           card_gb: float = 80.0, bandwidth_tb_s: float = 2.0) -> None:
    w = weights_gb(spec, weight_bits)
    kv = kv_cache_gb(spec, context, batch, kv_bits)
    # Активации и рабочие буферы сервера: эмпирическая надбавка порядка 10-20%.
    overhead = 0.15 * (w + kv)
    total = w + kv + overhead

    # Потолок скорости: на каждый токен читаются все активные веса.
    # Для MoE читается только активная часть, для плотной модели — всё.
    read_params = spec.active_params or spec.params
    read_gb = read_params * BYTES_PER_PARAM[weight_bits] / GB
    ceiling = bandwidth_tb_s * 1000 / read_gb  # токенов в секунду, верхняя граница

    print(f"{spec.name}: контекст {context}, батч {batch}, веса {weight_bits} бит")
    print(f"  веса {w:.1f} ГиБ, KV-кеш {kv:.1f} ГиБ, буферы {overhead:.1f} ГиБ")
    print(f"  итого {total:.1f} ГиБ -> карт по {card_gb:.0f} ГиБ: {-(-total // card_gb):.0f}")
    print(f"  потолок скорости {ceiling:.0f} ток/с (реально 30-60% от этого)")


dense_70b = ModelSpec("Плотная 70B", 70e9, layers=80, kv_heads=8, head_dim=128)
# У DeepSeek-V3 кеш сжат механизмом MLA, поэтому общая формула даёт верхнюю оценку.
moe_671b = ModelSpec("MoE 671B", 671e9, layers=61, kv_heads=128, head_dim=128,
                     active_params=37e9)

report(dense_70b, context=8_192, weight_bits=16)
report(dense_70b, context=32_768, batch=8, weight_bits=4, kv_bits=8)
report(moe_671b, context=8_192, weight_bits=8)

Что показывает запуск и на что смотреть:

  • У плотной модели на 70 млрд параметров в 16 битах веса дают около 130 ГиБ — две карты по 80 ГиБ, и это ещё до кеша.
  • Квантизация в 4 бита уводит те же веса под 33 ГиБ — модель начинает помещаться в одну карту, но при контексте 32k и батче 8 KV-кеш добавляет десятки гигабайт и снова выталкивает за её пределы.
  • У MoE-модели веса огромны — десяток карт даже в 8 битах, — но потолок скорости считается по активным 37 млрд: на каждом шаге она читает меньше байт, чем плотная модель на 70 млрд, и потому генерирует быстрее неё.

Сложность для полноты картины. Прямой проход на один токен — примерно 2 × P операций умножения-сложения, где P — число активных параметров, плюс O(n · d) на чтение кеша при длине контекста n. Префилл на n токенов — O(n · P) арифметики плюс O(n² · d) во внимании. По памяти: O(P) под веса плюс O(n · L · H_kv · d_head) под кеш на каждую активную последовательность.

Почему в этой картине нет места мышлению

Соберём главу в одну мысль. Всё, что происходит между вашим вопросом и ответом модели, — это чтение фиксированного массива чисел из видеопамяти и умножение матриц над ним. Ни одна операция в этом конвейере не зависит от смысла: одинаковые по форме данные дают одинаковый объём работы независимо от того, спрашиваете вы рецепт или доказательство теоремы. Модель не «думает дольше над сложным вопросом» — она тратит ровно столько же арифметики на токен, а разница во времени ответа объясняется только числом сгенерированных токенов. Это не приговор полезности моделей, но это точная граница того, что мы наблюдаем.

Источники

Мини-итог

  • Инференс языковой модели — это последовательность умножений матриц: массово параллельная однородная работа без ветвлений, то есть ровно та задача, под которую спроектирован GPU.
  • CPU оптимизирован под задержку одной операции, GPU — под пропускную способность: тысячи простых ядер, модель SIMT и память с полосой в единицы ТБ/с против десятков ГБ/с у процессора.
  • Генерация упирается не в арифметику, а в память: на каждый токен читаются все активные веса, поэтому потолок скорости равен пропускной способности памяти, делённой на размер весов.
  • Батчинг размазывает стоимость чтения весов по нескольким запросам — он поднимает пропускную способность системы ценой скорости каждого отдельного пользователя; второй пользователь замедляет генерацию именно поэтому, а не из-за нехватки ядер.
  • Память под веса считается точно: параметры × байт на параметр. Для 671 млрд параметров (масштаб DeepSeek-V3/R1, на момент лекции — май 2026) это ~1,34 ТБ в 16 битах, ~671 ГБ в 8 и ~336 ГБ в 4 — отсюда кластеры вместо одной карты.
  • KV-кеш убирает лишний пересчёт истории, но занимает видеопамять пропорционально длине контекста и числу параллельных запросов — часто именно он, а не веса, ограничивает число пользователей.
  • Роутинг моделей — штатный инженерный приём: дешёвая модель разбирает запрос, тяжёлая подключается по необходимости; это выигрыш и по деньгам, и по латентности одновременно.

Что дальше

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

Могут ли нейросети думать

Нашли неточность? Выделите фрагмент текста — рядом появится жучок.

Нужен разбор именно вашей ситуации?

Статья описывает общий случай. Если у вас частный — можно разобрать его отдельно, платно. А если не хватает целого материала, предложите тему: её оплачивают вскладчину, и она выходит открытой для всех.

Доска запросов