dicembre 21, 2025
14 min di lettura

Domande per il Colloquio da Ricercatore Scientifico in IA: Guida Completa

interview
career-advice
job-search
Domande per il Colloquio da Ricercatore Scientifico in IA: Guida Completa
Milad Bonakdar

Milad Bonakdar

Autore

Padroneggia i fondamenti della ricerca sull'IA con domande essenziali per il colloquio che coprono la teoria del deep learning, la metodologia di ricerca, le architetture transformer, l'ottimizzazione e gli argomenti di IA all'avanguardia per i ricercatori scientifici.


Introduzione

Gli Scienziati della Ricerca sull'IA spingono i confini dell'intelligenza artificiale attraverso algoritmi, architetture e metodologie innovative. Questo ruolo richiede una profonda conoscenza teorica, solide basi matematiche, esperienza nella ricerca e la capacità di formulare e risolvere problemi aperti.

Questa guida completa copre le domande essenziali per i colloqui con gli Scienziati della Ricerca sull'IA, spaziando dalla teoria del deep learning, alle architetture transformer, alle tecniche di ottimizzazione, alla metodologia di ricerca, alla computer vision, all'NLP e agli argomenti di IA all'avanguardia. Ogni domanda include risposte dettagliate, valutazione della rarità e valutazione della difficoltà.


Teoria del Deep Learning (5 Domande)

1. Spiega in dettaglio la backpropagation e la regola della catena.

Risposta: La backpropagation calcola i gradienti in modo efficiente utilizzando la regola della catena.

  • Regola della Catena: Per le funzioni composte, la derivata è il prodotto delle derivate
  • Passaggio Forward: Calcola gli output e memorizza nella cache i valori intermedi
  • Passaggio Backward: Calcola i gradienti dall'output all'input
import numpy as np

# Rete neurale semplice per dimostrare la backpropagation
class SimpleNN:
    def __init__(self, input_size, hidden_size, output_size):
        # Inizializza i pesi
        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):
        # Livello 1
        self.z1 = np.dot(X, self.W1) + self.b1
        self.a1 = self.sigmoid(self.z1)
        
        # Livello 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]
        
        # Gradienti del livello di output
        # dL/da2 = a2 - y (per binary cross-entropy)
        # 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)
        
        # Gradienti del livello nascosto (regola della catena)
        # 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)
        
        # Aggiorna i pesi
        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):
            # Passaggio forward
            output = self.forward(X)
            
            # Passaggio backward
            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 {epoch}, Loss: {loss:.4f}')

# Esempio di utilizzo
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)

Rarità: Molto Comune Difficoltà: Difficile


2. Cos'è il problema del gradiente che svanisce e come lo risolvi?

Risposta: I gradienti che svaniscono si verificano quando i gradienti diventano estremamente piccoli nelle reti profonde.

  • Cause:
    • Attivazioni Sigmoid/tanh (derivate < 1)
    • Reti profonde (i gradienti si moltiplicano)
  • Soluzioni:
    • Attivazioni ReLU
    • Batch normalization
    • Connessioni residuali (ResNet)
    • LSTM/GRU per RNN
    • Inizializzazione accurata (Xavier, He)
import torch
import torch.nn as nn

# Problema: Rete profonda con sigmoid
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 livelli
        ])
    
    def forward(self, x):
        return self.layers(x)

# Soluzione 1: Attivazione 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)

# Soluzione 2: Connessioni residuali
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)

# Soluzione 3: Batch Normalization
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)

# Analisi del flusso del gradiente
def analyze_gradients(model, x, y):
    model.zero_grad()
    output = model(x)
    loss = nn.MSELoss()(output, y)
    loss.backward()
    
    # Controlla le magnitudini del gradiente
    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}")

Rarità: Molto Comune Difficoltà: Difficile


3. Spiega i meccanismi di attenzione e l'auto-attenzione.

Risposta: L'attenzione consente ai modelli di concentrarsi sulle parti rilevanti dell'input.

  • Attenzione: Somma ponderata dei valori basata sulla somiglianza query-key
  • Auto-Attenzione: Attenzione in cui query, key, value provengono dalla stessa fonte
  • Scaled Dot-Product Attention: 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)
        """
        # Calcola i punteggi di attenzione
        attn = torch.matmul(q, k.transpose(-2, -1)) / self.temperature
        
        # Applica la maschera (per il padding o l'attenzione causale)
        if mask is not None:
            attn = attn.masked_fill(mask == 0, -1e9)
        
        # Softmax per ottenere i pesi di attenzione
        attn_weights = F.softmax(attn, dim=-1)
        
        # Applica l'attenzione ai valori
        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
        
        # Proiezioni lineari
        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)
        
        # Proiezioni lineari e divisione in teste
        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)
        
        # Applica l'attenzione
        output, attn_weights = self.attention(q, k, v, mask)
        
        # Concatenazione delle teste
        output = output.transpose(1, 2).contiguous().view(batch_size, -1, self.d_model)
        
        # Proiezione lineare finale
        output = self.w_o(output)
        
        return output, attn_weights

# Esempio di utilizzo
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)

# Auto-attenzione (q, k, v tutti da x)
output, attn = mha(x, x, x)
print(f"Forma dell'output: {output.shape}")
print(f"Forma dei pesi di attenzione: {attn.shape}")

Rarità: Molto Comune Difficoltà: Difficile


4. Quali sono le differenze tra batch normalization e layer normalization?

Risposta: Entrambe normalizzano le attivazioni ma lungo dimensioni diverse.

  • Batch Normalization:
    • Normalizza attraverso la dimensione del batch
    • Richiede statistiche del batch
    • Problemi con batch piccoli, RNN
  • Layer Normalization:
    • Normalizza attraverso la dimensione delle feature
    • Indipendente dalla dimensione del batch
    • Migliore per RNN, Transformer
import torch
import torch.nn as nn

# Esempio di Batch Normalization
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)
        # Normalizza attraverso la dimensione del batch per ogni feature
        return self.bn(x)

# Esempio di Layer Normalization
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)
        # Normalizza attraverso la dimensione delle feature per ogni campione
        return self.ln(x)

# Implementazione manuale
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):
        # Calcola la media e la varianza attraverso l'ultima dimensione
        mean = x.mean(dim=-1, keepdim=True)
        var = x.var(dim=-1, keepdim=True, unbiased=False)
        
        # Normalizza
        x_norm = (x - mean) / torch.sqrt(var + self.eps)
        
        # Scala e sposta
        return self.gamma * x_norm + self.beta

# Comparazione
batch_size, seq_len, d_model = 2, 10, 512

# Batch Norm (per CNN)
x_cnn = torch.randn(batch_size, d_model, 28, 28)
bn = nn.BatchNorm2d(d_model)
out_bn = bn(x_cnn)

# Layer Norm (per Transformer)
x_transformer = torch.randn(batch_size, seq_len, d_model)
ln = nn.LayerNorm(d_model)
out_ln = ln(x_transformer)

print(f"Output di Batch Norm: {out_bn.shape}")
print(f"Output di Layer Norm: {out_ln.shape}")

Rarità: Comune Difficoltà: Media


5. Spiega in dettaglio l'architettura transformer.

Risposta: I Transformer utilizzano l'auto-attenzione per la modellazione di sequenze senza ricorrenza.

Loading diagram...
  • Componenti:
    • Encoder: Auto-attenzione + FFN
    • Decoder: Auto-attenzione mascherata + cross-attention + FFN
    • Positional Encoding: Inietta informazioni sulla posizione
    • Multi-Head Attention: Meccanismi di attenzione paralleli
import torch
import torch.nn as nn
import math

class PositionalEncoding(nn.Module):
    def __init__(self, d_model, max_len=5000):
        super().__init__()
        
        # Crea la matrice di positional encoding
        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__()
        
        # Multi-head attention
        self.self_attn = nn.MultiheadAttention(d_model, n_heads, dropout=dropout)
        
        # Rete feed-forward
        self.ffn = nn.Sequential(
            nn.Linear(d_model, d_ff),
            nn.ReLU(),
            nn.Dropout(dropout),
            nn.Linear(d_ff, d_model)
        )
        
        # Layer normalization
        self.norm1 = nn.LayerNorm(d_model)
        self.norm2 = nn.LayerNorm(d_model)
        
        self.dropout = nn.Dropout(dropout)
    
    def forward(self, x, mask=None):
        # Auto-attenzione con connessione residuale
        attn_output, _ = self.self_attn(x, x, x, attn_mask=mask)
        x = self.norm1(x + self.dropout(attn_output))
        
        # Feed-forward con connessione residuale
        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):
        # Embedding + positional encoding
        x = self.embedding(x) * math.sqrt(self.embedding.embedding_dim)
        x = self.pos_encoding(x)
        x = self.dropout(x)
        
        # Applica i livelli dell'encoder
        for layer in self.layers:
            x = layer(x, mask)
        
        return x

# Esempio di utilizzo
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)

# Input: (batch_size, seq_len)
x = torch.randint(0, vocab_size, (2, 10))
output = encoder(x)
print(f"Forma dell'output: {output.shape}")  # (2, 10, 512)

Rarità: Molto Comune Difficoltà: Difficile


Metodologia di Ricerca (4 Domande)

6. Come si formula un problema di ricerca e un'ipotesi?

Risposta: La ricerca inizia con l'identificazione delle lacune e la formulazione di ipotesi verificabili.

  • Passaggi:
    1. Revisione della Letteratura: Comprendere lo stato dell'arte
    2. Identificare la Lacuna: Cosa manca o può essere migliorato?
    3. Formulare l'Ipotesi: Affermazione specifica e verificabile
    4. Progettare Esperimenti: Come testare l'ipotesi?
    5. Definire le Metriche: Come misurare il successo?
  • Esempio:
    • Lacuna: I modelli attuali faticano con le dipendenze a lungo raggio
    • Ipotesi: L'attenzione sparsa può mantenere le prestazioni riducendo la complessità
    • Esperimento: Confronta l'attenzione sparsa con quella completa su sequenze lunghe
    • Metriche: Perplessità, accuratezza, tempo di inferenza

Rarità: Molto Comune Difficoltà: Media


7. Come si progettano studi di ablazione?

Risposta: Gli studi di ablazione isolano il contributo dei singoli componenti.

  • Scopo: Comprendere cosa fa funzionare il modello
  • Metodo: Rimuovere/modificare un componente alla volta
  • Best Practice:
    • Controllare tutte le altre variabili
    • Utilizzare gli stessi seed casuali
    • Riportare gli intervalli di confidenza
    • Testare su più dataset
# Esempio di studio di ablazione
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)

# Esegui esperimenti di ablazione
configs = [
    {'use_attention': True, 'use_residual': True, 'use_dropout': True},   # Modello completo
    {'use_attention': False, 'use_residual': True, 'use_dropout': True},  # Nessuna attenzione
    {'use_attention': True, 'use_residual': False, 'use_dropout': True},  # Nessuna residuale
    {'use_attention': True, 'use_residual': True, 'use_dropout': False},  # Nessun dropout
]

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

# Analizza i risultati
import pandas as pd
df = pd.DataFrame(results)
print(df)

Rarità: Molto Comune Difficoltà: Media


8. Come si garantisce la riproducibilità nella ricerca?

Risposta: La riproducibilità è fondamentale per la validità scientifica.

  • Best Practice:
    • Codice: Controllo della versione, documentazione chiara
    • Dati: Versione, documentare la preelaborazione
    • Ambiente: Docker, requirements.txt
    • Seed: Fissare tutti i seed casuali
    • Iperparametri: Registrare tutte le impostazioni
    • Hardware: Documentare le specifiche GPU/CPU
import random
import numpy as np
import torch
import os

def set_all_seeds(seed=42):
    """Imposta i seed per la riproducibilità"""
    random.seed(seed)
    np.random.seed(seed)
    torch.manual_seed(seed)
    torch.cuda.manual_seed_all(seed)
    os.environ['PYTHONHASHSEED'] = str(seed)
    
    # Operazioni deterministiche
    torch.backends.cudnn.deterministic = True
    torch.backends.cudnn.benchmark = False

# Registra tutto
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)

# Condividi codice e modelli
"""
# README.md
## Riproducibilità

### Ambiente
```bash
conda create -n research python=3.9
conda activate research
pip install -r requirements.txt

Dati

Scarica da: [link] Preelabora: python preprocess.py

Addestramento

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

Valutazione

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

"""


**Rarità:** Molto Comune
**Difficoltà:** Facile

---

### 9. Come si valutano e si confrontano i modelli in modo equo?

**Risposta:**
Un confronto equo richiede un'attenta progettazione sperimentale.
- **Considerazioni:**
    - **Stesse divisioni dei dati:** Utilizzare train/val/test identici
    - **Esecuzioni multiple:** Riportare media e deviazione standard
    - **Test statistici:** T-test, Wilcoxon
    - **Costo computazionale:** FLOP, parametri, tempo
    - **Metriche multiple:** Non fare cherry-picking
    - **Dataset multipli:** Generalizzazione

```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):
            # Imposta il seed per questa esecuzione
            set_all_seeds(seed)
            
            # Addestra il modello
            model = model_fn()
            model.fit(X_train, y_train)
            
            # Valuta
            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):
        """Test di significatività statistica"""
        scores_a = self.results[model_a]['scores']
        scores_b = self.results[model_b]['scores']
        
        # T-test appaiato
        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}]")

# Utilizzo
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"\nTest statistico: p-value = {result['p_value']:.4f}")

Rarità: Molto Comune Difficoltà: Media


Argomenti Avanzati (4 Domande)

10. Spiega l'apprendimento contrastivo e le sue applicazioni.

Risposta: L'apprendimento contrastivo apprende le rappresentazioni confrontando campioni simili e dissimili.

  • Idea Chiave: Avvicinare i campioni simili, allontanare quelli dissimili
  • Perdita: InfoNCE, NT-Xent
  • Applicazioni: 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) - coppie di campioni aumentati
        """
        batch_size = features.shape[0] // 2
        
        # Normalizza le feature
        features = F.normalize(features, dim=1)
        
        # Calcola la matrice di somiglianza
        similarity_matrix = torch.matmul(features, features.T)
        
        # Crea le etichette (coppie positive)
        labels = torch.cat([torch.arange(batch_size) + batch_size,
                           torch.arange(batch_size)]).to(features.device)
        
        # Maschera per rimuovere l'auto-somiglianza
        mask = torch.eye(2 * batch_size, dtype=torch.bool).to(features.device)
        similarity_matrix = similarity_matrix.masked_fill(mask, -9e15)
        
        # Calcola la perdita
        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):
        # Codifica entrambe le viste aumentate
        h1 = self.encoder(x1)
        h2 = self.encoder(x2)
        
        # Proietta nello spazio contrastivo
        z1 = self.projection(h1)
        z2 = self.projection(h2)
        
        # Concatena per la perdita contrastiva
        features = torch.cat([z1, z2], dim=0)
        
        return features

# Ciclo di addestramento
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:
        # Ottieni due viste aumentate
        x1, x2 = augment(batch)
        
        # Passaggio forward
        features = model(x1, x2)
        loss = criterion(features)
        
        # Passaggio backward
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

Rarità: Comune Difficoltà: Difficile


11. Cosa sono i Vision Transformer (ViT) e come funzionano?

Risposta: I Vision Transformer applicano l'architettura transformer alle immagini.

  • Idee Chiave:
    • Dividi l'immagine in patch
    • Embedding lineare delle patch
    • Aggiungi embedding posizionali
    • Applica l'encoder transformer
  • Vantaggi: Scalabilità, campo ricettivo globale
  • Sfide: Richiedono dataset di grandi dimensioni
import torch
import torch.nn as nn

class PatchEmbedding(nn.Module):
    def __init__(self, img_size=224, patch_size=16, in_channels=3, embed_dim=768):
        super().__init__()
        self.img_size = img_size
        self.patch_size = patch_size
        self.n_patches = (img_size // patch_size) ** 2
        
        # Convoluzione per estrar
Newsletter subscription

Consigli di carriera settimanali che funzionano davvero

Ricevi le ultime idee direttamente nella tua casella di posta

Distinguiti dai Reclutatori e Ottieni il Lavoro dei Tuoi Sogni

Unisciti a migliaia di persone che hanno trasformato la loro carriera con curriculum potenziati dall'IA che superano l'ATS e impressionano i responsabili delle assunzioni.

Inizia a creare ora

Condividi questo post

Raddoppia le Tue Chiamate per Colloqui

I candidati che personalizzano il loro curriculum in base alla descrizione del lavoro ottengono 2,5 volte più colloqui. Usa la nostra IA per personalizzare automaticamente il tuo CV per ogni singola candidatura istantaneamente.