декабря 21, 2025
13 мин. чтения

Вопросы для собеседования AI Research Scientist

interview
career-advice
job-search
Вопросы для собеседования AI Research Scientist
Milad Bonakdar

Milad Bonakdar

Автор

Подготовьтесь к собеседованию на исследовательскую роль в ИИ: deep learning, Transformer, дизайн экспериментов, оценка моделей и исследовательская коммуникация.


Введение

Собеседование на роль AI Research Scientist проверяет, умеете ли вы мыслить как исследователь: формулировать гипотезы, обосновывать архитектурные решения, реализовывать ключевые идеи, честно сравнивать модели и ясно объяснять компромиссы в статьях или исследовательских презентациях. Ожидайте вопросы по deep learning и Transformer, а также открытые задачи про эксперименты, воспроизводимость, безопасность и следующие исследовательские шаги.

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


Теория глубокого обучения (5 вопросов)

1. Подробно объясните обратное распространение ошибки и цепное правило.

Ответ: Обратное распространение ошибки эффективно вычисляет градиенты с использованием цепного правила.

  • Цепное правило: Для сложных функций производная является произведением производных
  • Прямой проход: Вычисление выходных данных и кэширование промежуточных значений
  • Обратный проход: Вычисление градиентов от выхода ко входу
import numpy as np

# Простая нейронная сеть для демонстрации обратного распространения ошибки
class SimpleNN:
    def __init__(self, input_size, hidden_size, output_size):
        # Инициализация весов
        self.W1 = np.random.randn(input_size, hidden_size) * 0.01
        self.b1 = np.zeros((1, hidden_size))
        self.W2 = np.random.randn(hidden_size, output_size) * 0.01
        self.b2 = np.zeros((1, output_size))
    
    def sigmoid(self, x):
        return 1 / (1 + np.exp(-x))
    
    def sigmoid_derivative(self, x):
        return x * (1 - x)
    
    def forward(self, X):
        # Слой 1
        self.z1 = np.dot(X, self.W1) + self.b1
        self.a1 = self.sigmoid(self.z1)
        
        # Слой 2
        self.z2 = np.dot(self.a1, self.W2) + self.b2
        self.a2 = self.sigmoid(self.z2)
        
        return self.a2
    
    def backward(self, X, y, output, learning_rate=0.01):
        m = X.shape[0]
        
        # Градиенты выходного слоя
        # dL/da2 = a2 - y (для бинарной кросс-энтропии)
        # dL/dz2 = dL/da2 * da2/dz2 = (a2 - y) * sigmoid'(z2)
        dz2 = output - y
        dW2 = (1/m) * np.dot(self.a1.T, dz2)
        db2 = (1/m) * np.sum(dz2, axis=0, keepdims=True)
        
        # Градиенты скрытого слоя (цепное правило)
        # dL/da1 = dL/dz2 * dz2/da1 = dz2 * W2.T
        # dL/dz1 = dL/da1 * da1/dz1 = dL/da1 * sigmoid'(z1)
        da1 = np.dot(dz2, self.W2.T)
        dz1 = da1 * self.sigmoid_derivative(self.a1)
        dW1 = (1/m) * np.dot(X.T, dz1)
        db1 = (1/m) * np.sum(dz1, axis=0, keepdims=True)
        
        # Обновление весов
        self.W2 -= learning_rate * dW2
        self.b2 -= learning_rate * db2
        self.W1 -= learning_rate * dW1
        self.b1 -= learning_rate * db1
    
    def train(self, X, y, epochs=1000):
        for epoch in range(epochs):
            # Прямой проход
            output = self.forward(X)
            
            # Обратный проход
            self.backward(X, y, output)
            
            if epoch % 100 == 0:
                loss = -np.mean(y * np.log(output) + (1-y) * np.log(1-output))
                print(f'Эпоха {epoch}, Loss: {loss:.4f}')

# Пример использования
X = np.array([[0, 0], [0, 1], [1, 0], [1, 1]])
y = np.array([[0], [1], [1], [0]])  # XOR

nn = SimpleNN(input_size=2, hidden_size=4, output_size=1)
nn.train(X, y, epochs=5000)

Редкость: Очень часто Сложность: Высокая


2. Что такое проблема затухающего градиента и как ее решить?

Ответ: Затухающие градиенты возникают, когда градиенты становятся чрезвычайно малыми в глубоких сетях.

  • Причины:
    • Сигмоидальные/tanh активации (производные < 1)
    • Глубокие сети (градиенты умножаются)
  • Решения:
    • ReLU активации
    • Пакетная нормализация
    • Остаточные соединения (ResNet)
    • LSTM/GRU для RNN
    • Тщательная инициализация (Xavier, He)
import torch
import torch.nn as nn

# Проблема: Глубокая сеть с сигмоидой
class VanishingGradientNet(nn.Module):
    def __init__(self):
        super().__init__()
        self.layers = nn.Sequential(*[
            nn.Sequential(nn.Linear(100, 100), nn.Sigmoid())
            for _ in range(20)  # 20 слоев
        ])
    
    def forward(self, x):
        return self.layers(x)

# Решение 1: ReLU активация
class ReLUNet(nn.Module):
    def __init__(self):
        super().__init__()
        self.layers = nn.Sequential(*[
            nn.Sequential(nn.Linear(100, 100), nn.ReLU())
            for _ in range(20)
        ])
    
    def forward(self, x):
        return self.layers(x)

# Решение 2: Остаточные соединения
class ResidualBlock(nn.Module):
    def __init__(self, dim):
        super().__init__()
        self.layers = nn.Sequential(
            nn.Linear(dim, dim),
            nn.ReLU(),
            nn.Linear(dim, dim)
        )
    
    def forward(self, x):
        return x + self.layers(x)  # Skip connection

class ResNet(nn.Module):
    def __init__(self):
        super().__init__()
        self.blocks = nn.Sequential(*[
            ResidualBlock(100) for _ in range(20)
        ])
    
    def forward(self, x):
        return self.blocks(x)

# Решение 3: Пакетная нормализация
class BatchNormNet(nn.Module):
    def __init__(self):
        super().__init__()
        self.layers = nn.Sequential(*[
            nn.Sequential(
                nn.Linear(100, 100),
                nn.BatchNorm1d(100),
                nn.ReLU()
            )
            for _ in range(20)
        ])
    
    def forward(self, x):
        return self.layers(x)

# Анализ потока градиентов
def analyze_gradients(model, x, y):
    model.zero_grad()
    output = model(x)
    loss = nn.MSELoss()(output, y)
    loss.backward()
    
    # Проверка величины градиентов
    for name, param in model.named_parameters():
        if param.grad is not None:
            grad_norm = param.grad.norm().item()
            print(f"{name}: {grad_norm:.6f}")

Редкость: Очень часто Сложность: Высокая


3. Объясните механизмы внимания и самовнимание.

Ответ: Внимание позволяет моделям фокусироваться на релевантных частях ввода.

  • Внимание: Взвешенная сумма значений на основе сходства запроса и ключа
  • Самовнимание: Внимание, где запрос, ключ и значение исходят из одного источника
  • Масштабированное скалярное произведение внимания: Q·K^T / √d_k
import torch
import torch.nn as nn
import torch.nn.functional as F
import math

class ScaledDotProductAttention(nn.Module):
    def __init__(self, temperature):
        super().__init__()
        self.temperature = temperature
    
    def forward(self, q, k, v, mask=None):
        """
        q: (batch, seq_len, d_k)
        k: (batch, seq_len, d_k)
        v: (batch, seq_len, d_v)
        """
        # Вычисление оценок внимания
        attn = torch.matmul(q, k.transpose(-2, -1)) / self.temperature
        
        # Применение маски (для заполнения или причинного внимания)
        if mask is not None:
            attn = attn.masked_fill(mask == 0, -1e9)
        
        # Softmax для получения весов внимания
        attn_weights = F.softmax(attn, dim=-1)
        
        # Применение внимания к значениям
        output = torch.matmul(attn_weights, v)
        
        return output, attn_weights

class MultiHeadAttention(nn.Module):
    def __init__(self, d_model, n_heads, dropout=0.1):
        super().__init__()
        assert d_model % n_heads == 0
        
        self.d_model = d_model
        self.n_heads = n_heads
        self.d_k = d_model // n_heads
        
        # Линейные проекции
        self.w_q = nn.Linear(d_model, d_model)
        self.w_k = nn.Linear(d_model, d_model)
        self.w_v = nn.Linear(d_model, d_model)
        self.w_o = nn.Linear(d_model, d_model)
        
        self.attention = ScaledDotProductAttention(temperature=math.sqrt(self.d_k))
        self.dropout = nn.Dropout(dropout)
    
    def forward(self, q, k, v, mask=None):
        batch_size = q.size(0)
        
        # Линейные проекции и разделение на головы
        q = self.w_q(q).view(batch_size, -1, self.n_heads, self.d_k).transpose(1, 2)
        k = self.w_k(k).view(batch_size, -1, self.n_heads, self.d_k).transpose(1, 2)
        v = self.w_v(v).view(batch_size, -1, self.n_heads, self.d_k).transpose(1, 2)
        
        # Применение внимания
        output, attn_weights = self.attention(q, k, v, mask)
        
        # Конкатенация голов
        output = output.transpose(1, 2).contiguous().view(batch_size, -1, self.d_model)
        
        # Финальная линейная проекция
        output = self.w_o(output)
        
        return output, attn_weights

# Пример использования
d_model = 512
n_heads = 8
seq_len = 10
batch_size = 2

mha = MultiHeadAttention(d_model, n_heads)
x = torch.randn(batch_size, seq_len, d_model)

# Самовнимание (q, k, v все из x)
output, attn = mha(x, x, x)
print(f"Форма вывода: {output.shape}")
print(f"Форма весов внимания: {attn.shape}")

Редкость: Очень часто Сложность: Высокая


4. В чем разница между пакетной нормализацией и слоевой нормализацией?

Ответ: Обе нормализуют активации, но по разным измерениям.

  • Пакетная нормализация:
    • Нормализует по измерению пакета
    • Требует статистики пакета
    • Проблемы с небольшими пакетами, RNN
  • Слоевая нормализация:
    • Нормализует по измерению признаков
    • Независима от размера пакета
    • Лучше для RNN, Transformer
import torch
import torch.nn as nn

# Пример пакетной нормализации
class BatchNormExample(nn.Module):
    def __init__(self, num_features):
        super().__init__()
        self.bn = nn.BatchNorm1d(num_features)
    
    def forward(self, x):
        # x: (batch_size, num_features)
        # Нормализует по измерению пакета для каждого признака
        return self.bn(x)

# Пример слоевой нормализации
class LayerNormExample(nn.Module):
    def __init__(self, normalized_shape):
        super().__init__()
        self.ln = nn.LayerNorm(normalized_shape)
    
    def forward(self, x):
        # x: (batch_size, seq_len, d_model)
        # Нормализует по измерению признаков для каждого образца
        return self.ln(x)

# Ручная реализация
class ManualLayerNorm(nn.Module):
    def __init__(self, normalized_shape, eps=1e-5):
        super().__init__()
        self.eps = eps
        self.gamma = nn.Parameter(torch.ones(normalized_shape))
        self.beta = nn.Parameter(torch.zeros(normalized_shape))
    
    def forward(self, x):
        # Вычисление среднего и дисперсии по последнему измерению
        mean = x.mean(dim=-1, keepdim=True)
        var = x.var(dim=-1, keepdim=True, unbiased=False)
        
        # Нормализация
        x_norm = (x - mean) / torch.sqrt(var + self.eps)
        
        # Масштабирование и сдвиг
        return self.gamma * x_norm + self.beta

# Сравнение
batch_size, seq_len, d_model = 2, 10, 512

# Пакетная нормализация (для CNN)
x_cnn = torch.randn(batch_size, d_model, 28, 28)
bn = nn.BatchNorm2d(d_model)
out_bn = bn(x_cnn)

# Слоевая нормализация (для Transformer)
x_transformer = torch.randn(batch_size, seq_len, d_model)
ln = nn.LayerNorm(d_model)
out_ln = ln(x_transformer)

print(f"Вывод пакетной нормализации: {out_bn.shape}")
print(f"Вывод слоевой нормализации: {out_ln.shape}")

Редкость: Часто Сложность: Средняя


5. Подробно объясните архитектуру Transformer.

Ответ: Transformer использует самовнимание для моделирования последовательностей без рекуррентности.

Loading diagram...
  • Компоненты:
    • Кодировщик: Самовнимание + FFN
    • Декодировщик: Маскированное самовнимание + перекрестное внимание + FFN
    • Позиционное кодирование: Внедрение информации о позиции
    • Многоголовое внимание: Параллельные механизмы внимания
import torch
import torch.nn as nn
import math

class PositionalEncoding(nn.Module):
    def __init__(self, d_model, max_len=5000):
        super().__init__()
        
        # Создание матрицы позиционного кодирования
        pe = torch.zeros(max_len, d_model)
        position = torch.arange(0, max_len, dtype=torch.float).unsqueeze(1)
        div_term = torch.exp(torch.arange(0, d_model, 2).float() * 
                            (-math.log(10000.0) / d_model))
        
        pe[:, 0::2] = torch.sin(position * div_term)
        pe[:, 1::2] = torch.cos(position * div_term)
        
        pe = pe.unsqueeze(0)
        self.register_buffer('pe', pe)
    
    def forward(self, x):
        return x + self.pe[:, :x.size(1)]

class TransformerEncoderLayer(nn.Module):
    def __init__(self, d_model, n_heads, d_ff, dropout=0.1):
        super().__init__()
        
        # Многоголовое внимание
        self.self_attn = nn.MultiheadAttention(d_model, n_heads, dropout=dropout)
        
        # Сеть прямого распространения
        self.ffn = nn.Sequential(
            nn.Linear(d_model, d_ff),
            nn.ReLU(),
            nn.Dropout(dropout),
            nn.Linear(d_ff, d_model)
        )
        
        # Слоевая нормализация
        self.norm1 = nn.LayerNorm(d_model)
        self.norm2 = nn.LayerNorm(d_model)
        
        self.dropout = nn.Dropout(dropout)
    
    def forward(self, x, mask=None):
        # Самовнимание с остаточным соединением
        attn_output, _ = self.self_attn(x, x, x, attn_mask=mask)
        x = self.norm1(x + self.dropout(attn_output))
        
        # Прямое распространение с остаточным соединением
        ffn_output = self.ffn(x)
        x = self.norm2(x + self.dropout(ffn_output))
        
        return x

class TransformerEncoder(nn.Module):
    def __init__(self, vocab_size, d_model, n_heads, d_ff, n_layers, dropout=0.1):
        super().__init__()
        
        self.embedding = nn.Embedding(vocab_size, d_model)
        self.pos_encoding = PositionalEncoding(d_model)
        
        self.layers = nn.ModuleList([
            TransformerEncoderLayer(d_model, n_heads, d_ff, dropout)
            for _ in range(n_layers)
        ])
        
        self.dropout = nn.Dropout(dropout)
    
    def forward(self, x, mask=None):
        # Вложение + позиционное кодирование
        x = self.embedding(x) * math.sqrt(self.embedding.embedding_dim)
        x = self.pos_encoding(x)
        x = self.dropout(x)
        
        # Применение слоев кодировщика
        for layer in self.layers:
            x = layer(x, mask)
        
        return x

# Пример использования
vocab_size = 10000
d_model = 512
n_heads = 8
d_ff = 2048
n_layers = 6

encoder = TransformerEncoder(vocab_size, d_model, n_heads, d_ff, n_layers)

# Ввод: (batch_size, seq_len)
x = torch.randint(0, vocab_size, (2, 10))
output = encoder(x)
print(f"Форма вывода: {output.shape}")  # (2, 10, 512)

Редкость: Очень часто Сложность: Высокая


Методология исследований (4 вопроса)

6. Как вы формулируете исследовательскую проблему и гипотезу?

Ответ: Исследование начинается с выявления пробелов и формулирования проверяемых гипотез.

  • Шаги:
    1. Обзор литературы: Понимание современного уровня развития
    2. Выявление пробела: Чего не хватает или что можно улучшить?
    3. Формулировка гипотезы: Конкретное, проверяемое утверждение
    4. Разработка экспериментов: Как проверить гипотезу?
    5. Определение метрик: Как измерить успех?
  • Пример:
    • Пробел: Текущие модели испытывают трудности с зависимостями на больших расстояниях
    • Гипотеза: Разреженное внимание может поддерживать производительность при одновременном снижении сложности
    • Эксперимент: Сравнение разреженного и полного внимания на длинных последовательностях
    • Метрики: Перплексия, точность, время вывода

Редкость: Очень часто Сложность: Средняя


7. Как вы разрабатываете исследования абляции?

Ответ: Исследования абляции выделяют вклад отдельных компонентов.

  • Цель: Понять, что заставляет модель работать
  • Метод: Удаление/изменение одного компонента за раз
  • Лучшие практики:
    • Контроль всех остальных переменных
    • Использование одинаковых случайных начальных чисел
    • Отчет о доверительных интервалах
    • Тестирование на нескольких наборах данных
# Пример исследования абляции
class ModelWithAblations:
    def __init__(self, use_attention=True, use_residual=True, use_dropout=True):
        self.use_attention = use_attention
        self.use_residual = use_residual
        self.use_dropout = use_dropout
    
    def build_model(self):
        layers = []
        
        if self.use_attention:
            layers.append(AttentionLayer())
        
        layers.append(FFNLayer())
        
        if self.use_dropout:
            layers.append(nn.Dropout(0.1))
        
        if self.use_residual:
            return ResidualWrapper(nn.Sequential(*layers))
        else:
            return nn.Sequential(*layers)

# Запуск экспериментов абляции
configs = [
    {'use_attention': True, 'use_residual': True, 'use_dropout': True},   # Полная модель
    {'use_attention': False, 'use_residual': True, 'use_dropout': True},  # Нет внимания
    {'use_attention': True, 'use_residual': False, 'use_dropout': True},  # Нет остаточного соединения
    {'use_attention': True, 'use_residual': True, 'use_dropout': False},  # Нет dropout
]

results = []
for config in configs:
    model = ModelWithAblations(**config)
    accuracy = train_and_evaluate(model, seed=42)
    results.append({**config, 'accuracy': accuracy})

# Анализ результатов
import pandas as pd
df = pd.DataFrame(results)
print(df)

Редкость: Очень часто Сложность: Средняя


8. Как вы обеспечиваете воспроизводимость в исследованиях?

Ответ: Воспроизводимость имеет решающее значение для научной обоснованности.

  • Лучшие практики:
    • Код: Контроль версий, четкая документация
    • Данные: Версия, документирование предварительной обработки
    • Среда: Docker, requirements.txt
    • Начальные числа: Фиксация всех случайных начальных чисел
    • Гиперпараметры: Регистрация всех настроек
    • Оборудование: Документирование спецификаций GPU/CPU
import random
import numpy as np
import torch
import os

def set_all_seeds(seed=42):
    """Установка начальных чисел для воспроизводимости"""
    random.seed(seed)
    np.random.seed(seed)
    torch.manual_seed(seed)
    torch.cuda.manual_seed_all(seed)
    os.environ['PYTHONHASHSEED'] = str(seed)
    
    # Детерминированные операции
    torch.backends.cudnn.deterministic = True
    torch.backends.cudnn.benchmark = False

# Регистрация всего
import logging
import json

def log_experiment(config, results):
    experiment_log = {
        'timestamp': datetime.now().isoformat(),
        'config': config,
        'results': results,
        'environment': {
            'python_version': sys.version,
            'torch_version': torch.__version__,
            'cuda_version': torch.version.cuda,
            'gpu': torch.cuda.get_device_name(0) if torch.cuda.is_available() else 'CPU'
        }
    }
    
    with open('experiment_log.json', 'w') as f:
        json.dump(experiment_log, f, indent=2)

# Совместное использование кода и моделей
"""
# README.md
## Воспроизводимость

### Среда
```bash
conda create -n research python=3.9
conda activate research
pip install -r requirements.txt

Данные

Загрузка из: [ссылка] Предварительная обработка: python preprocess.py

Обучение

python train.py --config configs/experiment1.yaml --seed 42

Оценка

python evaluate.py --checkpoint checkpoints/best_model.pt

"""


**Редкость:** Очень часто
**Сложность:** Легкая

---

### 9. Как вы оцениваете и сравниваете модели справедливо?

**Ответ:**
Справедливое сравнение требует тщательной экспериментальной разработки.
- **Соображения:**
    - **Одинаковые разделения данных:** Использование идентичных наборов для обучения/валидации/тестирования
    - **Несколько запусков:** Отчет о среднем и стандартном отклонении
    - **Статистические тесты:** T-тест, Wilcoxon
    - **Вычислительная стоимость:** FLOPs, параметры, время
    - **Несколько метрик:** Не выбирайте только лучшие результаты
    - **Несколько наборов данных:** Обобщение

```python
import numpy as np
from scipy import stats

class ModelComparison:
    def __init__(self, n_runs=5):
        self.n_runs = n_runs
        self.results = {}
    
    def evaluate_model(self, model_name, model_fn, X_train, y_train, X_test, y_test):
        scores = []
        
        for seed in range(self.n_runs):
            # Установка начального числа для этого запуска
            set_all_seeds(seed)
            
            # Обучение модели
            model = model_fn()
            model.fit(X_train, y_train)
            
            # Оценка
            score = model.score(X_test, y_test)
            scores.append(score)
        
        self.results[model_name] = {
            'scores': scores,
            'mean': np.mean(scores),
            'std': np.std(scores),
            'ci_95': stats.t.interval(
                0.95, len(scores)-1,
                loc=np.mean(scores),
                scale=stats.sem(scores)
            )
        }
    
    def compare_models(self, model_a, model_b):
        """Статистический тест значимости"""
        scores_a = self.results[model_a]['scores']
        scores_b = self.results[model_b]['scores']
        
        # Парный t-тест
        statistic, p_value = stats.ttest_rel(scores_a, scores_b)
        
        return {
            'statistic': statistic,
            'p_value': p_value,
            'significant': p_value < 0.05,
            'better_model': model_a if np.mean(scores_a) > np.mean(scores_b) else model_b
        }
    
    def report(self):
        for model_name, result in self.results.items():
            print(f"\n{model_name}:")
            print(f"  Mean: {result['mean']:.4f}")
            print(f"  Std:  {result['std']:.4f}")
            print(f"  95% CI: [{result['ci_95'][0]:.4f}, {result['ci_95'][1]:.4f}]")

# Использование
comparison = ModelComparison(n_runs=10)
comparison.evaluate_model('Model A', lambda: ModelA(), X_train, y_train, X_test, y_test)
comparison.evaluate_model('Model B', lambda: ModelB(), X_train, y_train, X_test, y_test)

comparison.report()
result = comparison.compare_models('Model A', 'Model B')
print(f"\nСтатистический тест: p-value = {result['p_value']:.4f}")

Редкость: Очень часто Сложность: Средняя


Продвинутые темы (4 вопроса)

10. Объясните контрастное обучение и его приложения.

Ответ: Контрастное обучение изучает представления, сравнивая похожие и непохожие образцы.

  • Ключевая идея: Сближение похожих образцов, отдаление непохожих
  • Потери: InfoNCE, NT-Xent
  • Приложения: SimCLR, MoCo, CLIP
import torch
import torch.nn as nn
import torch.nn.functional as F

class ContrastiveLoss(nn.Module):
    def __init__(self, temperature=0.5):
        super().__init__()
        self.temperature = temperature
    
    def forward(self, features):
        """
        features: (2*batch_size, dim) - пары дополненных образцов
        """
        batch_size = features.shape[0] // 2
        
        # Нормализация признаков
        features = F.normalize(features, dim=1)
        
        # Вычисление матрицы сходства
        similarity_matrix = torch.matmul(features, features.T)
        
        # Создание меток (положительные пары)
        labels = torch.cat([torch.arange(batch_size) + batch_size,
                           torch.arange(batch_size)]).to(features.device)
        
        # Маска для удаления самоподобия
        mask = torch.eye(2 * batch_size, dtype=torch.bool).to(features.device)
        similarity_matrix = similarity_matrix.masked_fill(mask, -9e15)
        
        # Вычисление потерь
        similarity_matrix = similarity_matrix / self.temperature
        loss = F.cross_entropy(similarity_matrix, labels)
        
        return loss

class SimCLR(nn.Module):
    def __init__(self, encoder, projection_dim=128):
        super().__init__()
        self.encoder = encoder
        self.projection = nn.Sequential(
            nn.Linear(encoder.output_dim, 512),
            nn.ReLU(),
            nn.Linear(512, projection_dim)
        )
    
    def forward(self, x1, x2):
        # Кодирование обоих дополненных представлений
        h1 = self.encoder(x1)
        h2 = self.encoder(x2)
        
        # Проекция в контрастное пространство
        z1 = self.projection(h1)
        z2 = self.projection(h2)
        
        # Конкатенация для контрастных потерь
        features = torch.cat([z1, z2], dim=0)
        
        return features

# Цикл обучения
model = SimCLR(encoder, projection_dim=128)
criterion = ContrastiveLoss(temperature=0.5)
optimizer = torch.optim.Adam(model.parameters())

for epoch in range(100):
    for batch in dataloader:
        # Получение двух дополненных представлений
        x1, x2 = augment(batch)
        
        # Прямой проход
        features = model(x1, x2)
        loss = criterion(features)
        
        # Обратный проход
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

Редкость: Часто Сложность: Высокая


11. Что такое Vision Transformers (ViT) и как они работают?

Ответ: Vision Transformers применяют архитектуру Transformer к изображениям.

  • Ключевые идеи:
    • Разделение изображения на патчи
    • Линейное вложение патчей
    • Добавление позиционных вложений
    • Применение кодировщика Transformer
  • Преимущества: Масштабируемость, глобальное рецептивное поле
  • Проблемы: Требуются большие наборы данных
import torch
import torch.nn as nn

class PatchEmbedding(nn.Module):
    def __init__(self, img_size=
Newsletter subscription

Еженедельные советы по карьере, которые действительно работают

Получайте последние идеи прямо на вашу почту

Перестаньте откликаться. Начните получать предложения.

Превратите своё резюме в магнит для собеседований с оптимизацией на базе ИИ, которой доверяют соискатели по всему миру.

Начать бесплатно

Поделиться этим постом

Удвойте Количество Приглашений на Собеседование

Кандидаты, адаптирующие свои резюме под описание вакансии, получают в 2,5 раза больше собеседований. Используйте наш ИИ для автоматической настройки вашего резюме для каждой заявки мгновенно.