👋 你好!这里有实用干货与深度分享✨✨ 若有帮助,欢迎:​
👍 点赞 | ⭐ 收藏 | 💬 评论 | ➕ 关注 ,解锁更多精彩!​
📁 收藏专栏即可第一时间获取最新推送🔔。​
📖后续我将持续带来更多优质内容,期待与你一同探索知识,携手前行,共同进步🚀。​



人工智能

深度学习指标及代码示例

深度学习指标用于评估模型的性能、训练效果及泛化能力,不同任务(分类、回归、语义分割等)适用的指标不同。以下是常见任务的核心指标及其详细解析:

一、分类任务指标

1. 准确率(Accuracy)

  • 公式
    [
    \text{Accuracy} = \frac{\text{正确预测的样本数}}{\text{总样本数}} = \frac{TP + TN}{TP + TN + FP + FN}
    ]
    ((TP):真阳性,(TN):真阴性,(FP):假阳性,(FN):假阴性)
  • 适用场景:类别均衡场景(如MNIST手写识别)。
  • 局限性:类别不平衡时失效(如癌症检测中健康样本占99%时,模型全预测为健康准确率仍高,但无意义)。

2. 精确率(Precision)与召回率(Recall)

  • 精确率(查准率)
    [
    \text{Precision} = \frac{TP}{TP + FP}
    ]
    含义:预测为正例的样本中实际为正例的比例(关注“误报”)。
  • 召回率(查全率)
    [
    \text{Recall} = \frac{TP}{TP + FN}
    ]
    含义:实际正例中被正确预测的比例(关注“漏报”)。
  • 应用
    • 精确率优先:垃圾邮件分类(误判正常邮件为垃圾邮件后果严重)。
    • 召回率优先:医学检测(漏诊癌症后果严重)。

3. F1分数(F1-Score)

  • 公式
    [
    F1 = 2 \times \frac{\text{Precision} \times \text{Recall}}{\text{Precision} + \text{Recall}}
    ]
    含义:精确率与召回率的调和平均数,平衡两者表现,适用于类别不平衡场景。

4. 混淆矩阵(Confusion Matrix)

  • 定义:以矩阵形式展示分类结果的TP、TN、FP、FN分布,直观反映模型在各类别上的表现。
  • 示例(二分类)
    真实\预测 正例(预测1) 负例(预测0)
    正例(1) TP FN
    负例(0) FP TN

5. ROC曲线与AUC

  • ROC曲线(Receiver Operating Characteristic)
    • 横轴:假正率(FPR = (\frac{FP}{TN + FP})),纵轴:真正率(TPR = (\frac{TP}{TP + FN}))。
    • 曲线越靠近左上角,模型分类能力越强。
  • AUC(Area Under Curve)
    • ROC曲线下的面积,取值范围[0, 1]。
    • AUC=0.5:模型性能等同于随机猜测;AUC=1:完美分类器。

二、回归任务指标

1. 均方误差(MSE, Mean Squared Error)

  • 公式
    [
    \text{MSE} = \frac{1}{n} \sum_{i=1}^n (y_i - \hat{y}_i)^2
    ]
    含义:预测值与真实值差值平方的均值,对异常值敏感(误差放大)。

2. 均方根误差(RMSE, Root Mean Squared Error)

  • 公式
    [
    \text{RMSE} = \sqrt{\text{MSE}} = \sqrt{\frac{1}{n} \sum_{i=1}^n (y_i - \hat{y}_i)^2}
    ]
    含义:MSE的平方根,与真实值单位一致,便于解释。

3. 平均绝对误差(MAE, Mean Absolute Error)

  • 公式
    [
    \text{MAE} = \frac{1}{n} \sum_{i=1}^n |y_i - \hat{y}_i|
    ]
    含义:预测值与真实值绝对误差的均值,对异常值鲁棒性优于MSE。

4. R²分数(R-Squared)

  • 公式
    [
    R^2 = 1 - \frac{\sum_{i=1}^n (y_i - \hat{y}_i)2}{\sum_{i=1}n (y_i - \bar{y})^2}
    ]
    ((\bar{y})为真实值均值)
  • 含义:模型解释真实值变化的比例:
    • (R2=1):完美预测;(R2=0):模型预测等于均值(无价值);(R^2<0):模型差于基线。

三、语义分割任务指标

1. 交并比(IoU, Intersection over Union)

  • 公式
    [
    \text{IoU} = \frac{\text{预测区域与真实区域的交集面积}}{\text{预测区域与真实区域的并集面积}}
    ]
  • 含义:衡量预测分割结果与真实标签的重叠程度,广泛用于目标检测、语义分割。

2. 平均交并比(mIoU, Mean IoU)

  • 计算:对每个类别计算IoU,再求平均值。
  • 应用:评估模型在多类别分割任务中的整体表现(如ADE20K数据集)。

3. 像素准确率(Pixel Accuracy, PA)

  • 公式
    [
    \text{PA} = \frac{\text{正确预测的像素数}}{\text{总像素数}}
    ]
  • 局限性:对大类别敏感,小目标易被忽略(如卫星图像中的车辆)。

四、目标检测任务指标

1. 平均精度(AP, Average Precision)

  • 计算
    • 在单类别中,遍历不同置信度阈值,计算对应的精确率和召回率,生成PR曲线,AP为曲线下面积。
    • 多类别场景下取所有类别的AP平均值,即mAP(mean Average Precision)。
  • 示例:COCO数据集使用mAP@[0.5:0.95](多IoU阈值下的平均mAP)评估模型。

2. 帧率(FPS, Frames Per Second)

  • 含义:模型每秒处理的图像帧数,衡量推理速度,用于实时检测(如YOLO系列)。

五、生成任务指标(如图像生成、NLP)

1. inception分数(IS, Inception Score)

  • 原理:基于预训练Inception网络,计算生成样本的类别概率分布熵(衡量多样性)与条件概率分布熵(衡量真实性)之差。
  • 公式
    [
    \text{IS} = \exp\left(\mathbb{E}x \left[ D{\text{KL}}(p(y|x) | p(y)) \right] \right)
    ]
    (值越大,生成样本越真实且多样)。

2. 弗雷歇 inception距离(FID, Fréchet Inception Distance)

  • 原理:比较生成样本与真实样本在Inception网络高层特征空间的均值和协方差距离,衡量分布相似度。
  • 优势:比IS更敏感,尤其适用于样本多样性低的场景。

六、其他通用指标

1. 损失函数(Loss Function)

  • 分类任务:交叉熵损失(Cross-Entropy Loss)、焦点损失(Focal Loss,缓解类别不平衡)。
  • 回归任务:均方损失(MSE Loss)、Huber损失(鲁棒性强,兼顾MAE和MSE)。
  • 生成任务:对抗损失(Adversarial Loss,如GAN)。

2. 过拟合与欠拟合指标

  • 训练集与验证集损失对比
    • 训练损失低、验证损失高:过拟合(需正则化、数据增强)。
    • 训练损失高、验证损失高:欠拟合(需增加模型复杂度、调整超参数)。

3. 计算资源指标

  • 参数量(Params):模型可训练参数总数,影响存储和推理速度。
  • 浮点运算量(FLOPs):衡量模型计算复杂度,用于比较不同架构的效率(如Transformer与CNN)。

总结:指标选择指南

任务类型 核心指标 场景示例
二分类/多分类 准确率、精确率/召回率、F1、AUC-ROC 情感分析、医学影像分类
回归 MSE、RMSE、MAE、R² 房价预测、温度预测
语义分割 IoU、mIoU、像素准确率 自动驾驶道路分割
目标检测 mAP、FPS 物体定位与识别
生成任务 IS、FID 图像生成、文本生成

关键原则

  • 结合业务需求(如医疗优先召回率,推荐系统优先精确率)。
  • 多指标综合评估(避免单一指标偏差)。
  • 关注数据分布(类别平衡、异常值影响)。

通过合理选择指标,可更全面地理解模型性能,指导调优方向。


代码示例

import numpy as np
from sklearn.metrics import confusion_matrix, roc_curve, auc, precision_recall_curve

# ================ 分类指标 ================
def accuracy(y_true, y_pred):
    """计算准确率"""
    return np.mean(y_true == y_pred)

def precision_recall_f1(y_true, y_pred):
    """计算精确率、召回率和F1分数"""
    cm = confusion_matrix(y_true, y_pred)
    if cm.shape != (2, 2):  # 处理二分类情况
        raise ValueError("仅支持二分类问题")
    
    tn, fp, fn, tp = cm.ravel()
    precision = tp / (tp + fp) if (tp + fp) > 0 else 0
    recall = tp / (tp + fn) if (tp + fn) > 0 else 0
    f1 = 2 * (precision * recall) / (precision + recall) if (precision + recall) > 0 else 0
    
    return precision, recall, f1

def roc_auc(y_true, y_score):
    """计算ROC曲线和AUC"""
    fpr, tpr, _ = roc_curve(y_true, y_score)
    roc_auc = auc(fpr, tpr)
    return fpr, tpr, roc_auc

def pr_curve(y_true, y_score):
    """计算PR曲线"""
    precision, recall, _ = precision_recall_curve(y_true, y_score)
    return precision, recall

# ================ 回归指标 ================
def mse(y_true, y_pred):
    """计算均方误差"""
    return np.mean((y_true - y_pred) ** 2)

def rmse(y_true, y_pred):
    """计算均方根误差"""
    return np.sqrt(mse(y_true, y_pred))

def mae(y_true, y_pred):
    """计算平均绝对误差"""
    return np.mean(np.abs(y_true - y_pred))

def r_squared(y_true, y_pred):
    """计算R²分数"""
    ss_res = np.sum((y_true - y_pred) ** 2)
    ss_tot = np.sum((y_true - np.mean(y_true)) ** 2)
    return 1 - (ss_res / ss_tot) if ss_tot != 0 else 0

# ================ 分割指标 ================
def iou(y_true, y_pred):
    """计算IoU(交并比)"""
    intersection = np.logical_and(y_true, y_pred)
    union = np.logical_or(y_true, y_pred)
    return np.sum(intersection) / np.sum(union) if np.sum(union) > 0 else 0

def miou(y_true, y_pred, num_classes):
    """计算mIoU(平均交并比)"""
    miou = 0
    for c in range(num_classes):
        c_true = (y_true == c)
        c_pred = (y_pred == c)
        miou += iou(c_true, c_pred)
    return miou / num_classes

def pixel_accuracy(y_true, y_pred):
    """计算像素准确率"""
    return np.mean(y_true == y_pred)

# ================ 目标检测指标 ================
def calculate_ap(recall, precision):
    """计算AP(平均精度) - 简化版"""
    # 插值计算AP
    mrec = np.concatenate(([0.0], recall, [1.0]))
    mpre = np.concatenate(([0.0], precision, [0.0]))
    
    for i in range(len(mpre) - 1, 0, -1):
        mpre[i - 1] = max(mpre[i - 1], mpre[i])
    
    i = np.where(mrec[1:] != mrec[:-1])[0]
    ap = np.sum((mrec[i + 1] - mrec[i]) * mpre[i + 1])
    return ap

# ================ 生成指标 ================
def calculate_fid(real_features, fake_features):
    """计算FID(简化版)"""
    # 计算均值和协方差
    mu1, sigma1 = np.mean(real_features, axis=0), np.cov(real_features, rowvar=False)
    mu2, sigma2 = np.mean(fake_features, axis=0), np.cov(fake_features, rowvar=False)
    
    # 计算FID
    diff = mu1 - mu2
    # 矩阵平方根近似
    covmean = _sqrtm(sigma1.dot(sigma2))
    if not np.isfinite(covmean).all():
        offset = np.eye(sigma1.shape[0]) * 1e-6
        covmean = _sqrtm((sigma1 + offset).dot(sigma2 + offset))
    
    # 计算最终FID
    fid = diff.dot(diff) + np.trace(sigma1 + sigma2 - 2 * covmean)
    return fid

def _sqrtm(mat):
    """矩阵平方根的简化实现"""
    # 实际应用中应使用更稳定的算法
    u, s, vh = np.linalg.svd(mat)
    return u @ np.diag(np.sqrt(s)) @ vh

# ================ 示例使用 ================
# 示例数据
y_true_clf = np.array([1, 0, 1, 1, 0, 1])
y_pred_clf = np.array([1, 0, 1, 0, 0, 1])
y_score_clf = np.array([0.8, 0.3, 0.9, 0.4, 0.2, 0.7])

y_true_reg = np.array([3.2, 5.1, 2.8, 7.6])
y_pred_reg = np.array([3.5, 4.9, 3.0, 7.8])

y_true_seg = np.array([[1, 1, 0], [0, 1, 1]])
y_pred_seg = np.array([[1, 0, 0], [0, 1, 1]])

# 计算指标
print("===== 分类指标 =====")
print(f"准确率: {accuracy(y_true_clf, y_pred_clf):.4f}")
p, r, f1 = precision_recall_f1(y_true_clf, y_pred_clf)
print(f"精确率: {p:.4f}, 召回率: {r:.4f}, F1: {f1:.4f}")
fpr, tpr, auc_val = roc_auc(y_true_clf, y_score_clf)
print(f"AUC-ROC: {auc_val:.4f}")

print("\n===== 回归指标 =====")
print(f"MSE: {mse(y_true_reg, y_pred_reg):.4f}")
print(f"RMSE: {rmse(y_true_reg, y_pred_reg):.4f}")
print(f"MAE: {mae(y_true_reg, y_pred_reg):.4f}")
print(f"R²: {r_squared(y_true_reg, y_pred_reg):.4f}")

print("\n===== 分割指标 =====")
print(f"IoU: {iou(y_true_seg, y_pred_seg):.4f}")
print(f"mIoU (假设2类): {miou(y_true_seg, y_pred_seg, 2):.4f}")
print(f"像素准确率: {pixel_accuracy(y_true_seg, y_pred_seg):.4f}")

print("\n===== 目标检测指标 =====")
recall = np.array([0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0])
precision = np.array([1.0, 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1, 0.0])
ap = calculate_ap(recall, precision)
print(f"AP: {ap:.4f}")

print("\n===== 生成指标 =====")
real_features = np.random.rand(100, 2048)  # 假设特征维度为2048
fake_features = np.random.rand(100, 2048)
fid = calculate_fid(real_features, fake_features)
print(f"FID: {fid:.4f}")

多分类 F1-score 计算

在上面提供的代码中,precision_recall_f1 函数仅支持二分类,无法直接处理多分类问题。这是因为它假设混淆矩阵为 2×2 结构(仅区分正例和负例)。
想要支持多分类,需要重构函数以处理任意数量的类别,并计算宏观(macro)或微观(micro)平均指标。

  • 多类别支持:通过处理任意大小的混淆矩阵(n×n)支持多分类。
  • 平均策略
    • 微平均(micro):将所有类别的 TP、FP、FN 汇总后计算指标,适用于类别不平衡场景。
    • 宏平均(macro):对每个类别单独计算指标后取平均,平等对待所有类别。
    • 加权平均(weighted):按类别样本数加权计算平均,避免小类别被忽视。

以下是重构后的代码,支持多分类的 F1-score 计算:

import numpy as np
from sklearn.metrics import confusion_matrix


def precision_recall_f1(y_true, y_pred, average='macro'):
    """
    计算多分类的精确率、召回率和F1分数
    :param y_true: 真实标签
    :param y_pred: 预测标签
    :param average: 平均方法,可选'macro'(宏平均)、'micro'(微平均)、'weighted'(加权平均)
    :return: 精确率、召回率、F1分数
    """
    cm = confusion_matrix(y_true, y_pred)
    n_classes = cm.shape[0]
    
    if average == 'micro':
        # 微平均:计算全局TP、FP、FN
        tp = np.diag(cm).sum()
        fp = cm.sum(axis=0) - np.diag(cm)
        fn = cm.sum(axis=1) - np.diag(cm)
        fp = fp.sum()
        fn = fn.sum()
        
        precision = tp / (tp + fp) if (tp + fp) > 0 else 0
        recall = tp / (tp + fn) if (tp + fn) > 0 else 0
        f1 = 2 * (precision * recall) / (precision + recall) if (precision + recall) > 0 else 0
        
        return precision, recall, f1
    
    else:  # macro或weighted
        # 为每个类别计算P、R、F1
        precisions = np.zeros(n_classes)
        recalls = np.zeros(n_classes)
        f1s = np.zeros(n_classes)
        support = np.sum(cm, axis=1)  # 每个类别的样本数
        
        for c in range(n_classes):
            tp = cm[c, c]
            fp = cm[:, c].sum() - tp
            fn = cm[c, :].sum() - tp
            
            precisions[c] = tp / (tp + fp) if (tp + fp) > 0 else 0
            recalls[c] = tp / (tp + fn) if (tp + fn) > 0 else 0
            f1s[c] = 2 * (precisions[c] * recalls[c]) / (precisions[c] + recalls[c]) if (precisions[c] + recalls[c]) > 0 else 0
        
        if average == 'macro':
            # 宏平均:直接平均所有类别的指标
            precision = np.mean(precisions)
            recall = np.mean(recalls)
            f1 = np.mean(f1s)
            return precision, recall, f1
        
        elif average == 'weighted':
            # 加权平均:按类别样本数加权
            precision = np.average(precisions, weights=support)
            recall = np.average(recalls, weights=support)
            f1 = np.average(f1s, weights=support)
            return precision, recall, f1
        
        else:
            raise ValueError("average参数必须为'macro'、'micro'或'weighted'")


# 示例:多分类评估
y_true = np.array([0, 1, 2, 0, 1, 2])
y_pred = np.array([0, 2, 1, 0, 0, 1])

# 计算宏平均指标
precision, recall, f1 = precision_recall_f1(y_true, y_pred, average='macro')
print(f"宏平均 - 精确率: {precision:.4f}, 召回率: {recall:.4f}, F1: {f1:.4f}")

# 计算微平均指标
precision, recall, f1 = precision_recall_f1(y_true, y_pred, average='micro')
print(f"微平均 - 精确率: {precision:.4f}, 召回率: {recall:.4f}, F1: {f1:.4f}")

# 计算加权平均指标
precision, recall, f1 = precision_recall_f1(y_true, y_pred, average='weighted')
print(f"加权平均 - 精确率: {precision:.4f}, 召回率: {recall:.4f}, F1: {f1:.4f}")

完整 FID 计算

FID(Fréchet Inception Distance)是一种用于评估生成模型质量的指标,特别适用于生成对抗网络(GAN)。FID通过计算生成样本与真实样本在Inception网络的特征空间中的距离来评估生成模型的质量。
FID 值越低,表示两个图像分布越相似。通常,FID 值在 10-30 之间表示生成质量较好,大于 50 则表示生成质量较差。

完整 FID 计算代码:

import numpy as np
import torch
import torch.nn.functional as F
from torch import nn
from torchvision.models import inception_v3
from scipy import linalg
from tqdm import tqdm
import os
from PIL import Image
import torchvision.transforms as transforms

class InceptionV3(nn.Module):
    """预训练的InceptionV3网络,用于提取特征"""
    def __init__(self, output_blocks=[3], resize_input=True, normalize_input=True):
        super(InceptionV3, self).__init__()
        self.resize_input = resize_input
        self.normalize_input = normalize_input
        self.output_blocks = sorted(output_blocks)
        self.last_needed_block = max(output_blocks)
        
        assert self.last_needed_block <= 3, 'Last possible output block is 3'
        
        # 显式设置aux_logits=True以兼容新版本PyTorch
        self.inception = inception_v3(pretrained=True, aux_logits=True)
        
        # 移除不必要的层
        for param in self.inception.parameters():
            param.requires_grad = False
            
        # 提取特征层
        self.block0 = nn.Sequential(
            self.inception.Conv2d_1a_3x3,
            self.inception.Conv2d_2a_3x3,
            self.inception.Conv2d_2b_3x3,
            nn.MaxPool2d(kernel_size=3, stride=2)
        )
        
        self.block1 = nn.Sequential(
            self.inception.Conv2d_3b_1x1,
            self.inception.Conv2d_4a_3x3,
            nn.MaxPool2d(kernel_size=3, stride=2)
        )
        
        self.block2 = nn.Sequential(
            self.inception.Mixed_5b,
            self.inception.Mixed_5c,
            self.inception.Mixed_5d,
            self.inception.Mixed_6a,
            self.inception.Mixed_6b,
            self.inception.Mixed_6c,
            self.inception.Mixed_6d,
            self.inception.Mixed_6e,
        )
        
        self.block3 = nn.Sequential(
            self.inception.Mixed_7a,
            self.inception.Mixed_7b,
            self.inception.Mixed_7c,
        )
        
    def forward(self, x):
        """
        提取InceptionV3的特征
        :param x: 输入图像,Tensor类型,形状为[batch_size, 3, height, width]
        :return: 特征向量
        """
        if self.resize_input:
            x = F.interpolate(x, size=(299, 299), mode='bilinear', align_corners=False)
            
        if self.normalize_input:
            x = 2 * x - 1  # 将输入从[0,1]归一化到[-1,1]
            
        x = self.block0(x)
        
        if self.last_needed_block >= 1:
            x = self.block1(x)
            
        if self.last_needed_block >= 2:
            x = self.block2(x)
            
        if self.last_needed_block >= 3:
            x = self.block3(x)
            
        # 全局平均池化
        x = F.adaptive_avg_pool2d(x, (1, 1))
        x = x.view(x.size(0), -1)
        
        return x

def calculate_activation_statistics(images, model, batch_size=64, dims=2048, device='cpu'):
    """
    计算激活值的均值和协方差矩阵
    :param images: 图像列表或DataLoader
    :param model: 特征提取模型
    :param batch_size: 批处理大小
    :param dims: 特征维度
    :param device: 计算设备
    :return: 均值和协方差矩阵
    """
    model.eval()
    
    if isinstance(images, torch.utils.data.DataLoader):
        dataloader = images
    else:
        # 创建简单的DataLoader
        dataset = torch.utils.data.TensorDataset(images)
        dataloader = torch.utils.data.DataLoader(dataset, batch_size=batch_size)
        
    act = np.empty((len(dataloader.dataset), dims))
    
    start_idx = 0
    
    for batch in tqdm(dataloader, desc="计算特征统计量"):
        if isinstance(batch, list) or isinstance(batch, tuple):
            batch = batch[0]  # 处理DataLoader返回的元组
            
        batch = batch.to(device)
        
        with torch.no_grad():
            pred = model(batch)
            
        # 如果输出是元组,获取第一个元素
        if isinstance(pred, tuple):
            pred = pred[0]
            
        # 将特征展平
        pred = pred.squeeze(3).squeeze(2).cpu().numpy()
        
        act[start_idx:start_idx + pred.shape[0]] = pred
        start_idx += pred.shape[0]
        
    mu = np.mean(act, axis=0)
    sigma = np.cov(act, rowvar=False)
    
    return mu, sigma

def calculate_frechet_distance(mu1, sigma1, mu2, sigma2, eps=1e-6):
    """
    计算两个分布之间的Frechet距离
    :param mu1: 第一个分布的均值
    :param sigma1: 第一个分布的协方差矩阵
    :param mu2: 第二个分布的均值
    :param sigma2: 第二个分布的协方差矩阵
    :param eps: 小常数,避免数值不稳定
    :return: Frechet距离
    """
    mu1 = np.atleast_1d(mu1)
    mu2 = np.atleast_1d(mu2)
    
    sigma1 = np.atleast_2d(sigma1)
    sigma2 = np.atleast_2d(sigma2)
    
    assert mu1.shape == mu2.shape, '两个均值向量的维度必须相同'
    assert sigma1.shape == sigma2.shape, '两个协方差矩阵的维度必须相同'
    
    # 计算均值差的平方
    diff = mu1 - mu2
    
    # 计算矩阵平方根
    covmean, _ = linalg.sqrtm(sigma1.dot(sigma2), disp=False)
    
    # 数值处理
    if not np.isfinite(covmean).all():
        msg = ('fid calculation produces singular product; '
               'adding %s to diagonal of cov estimates') % eps
        print(msg)
        offset = np.eye(sigma1.shape[0]) * eps
        covmean = linalg.sqrtm((sigma1 + offset).dot(sigma2 + offset))
        
    # 检查虚数部分
    if np.iscomplexobj(covmean):
        if not np.allclose(np.diagonal(covmean).imag, 0, atol=1e-3):
            m = np.max(np.abs(covmean.imag))
            raise ValueError('虚部大小: %f' % m)
        covmean = covmean.real
        
    # 计算最终FID
    tr_covmean = np.trace(covmean)
    
    return (diff.dot(diff) + np.trace(sigma1) + np.trace(sigma2) - 2 * tr_covmean)

def preprocess_image(img_path, image_size=299):
    """预处理图像,用于FID计算"""
    transform = transforms.Compose([
        transforms.Resize((image_size, image_size)),
        transforms.ToTensor(),
        transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
    ])
    
    img = Image.open(img_path).convert('RGB')
    return transform(img).unsqueeze(0)

def calculate_fid_given_paths(paths, batch_size=50, device='cpu', dims=2048):
    """
    计算两个图像文件夹之间的FID
    :param paths: 两个图像文件夹路径的列表
    :param batch_size: 批处理大小
    :param device: 计算设备
    :param dims: 特征维度
    :return: FID值
    """
    assert len(paths) == 2, '需要提供两个图像文件夹路径'
    
    model = InceptionV3([3]).to(device)
    
    fid_values = []
    
    for path in paths:
        if not os.path.exists(path):
            raise RuntimeError('路径 %s 不存在' % path)
            
        # 加载图像
        img_files = [os.path.join(path, f) for f in os.listdir(path) if 
                    os.path.isfile(os.path.join(path, f)) and 
                    f.lower().endswith(('.png', '.jpg', '.jpeg'))]
        
        if not img_files:
            raise RuntimeError('路径 %s 不包含图像文件' % path)
            
        # 预处理图像
        images = []
        for img_path in tqdm(img_files, desc=f"加载 {path} 中的图像"):
            img = preprocess_image(img_path)
            images.append(img)
            
        images = torch.cat(images, dim=0)
        
        # 计算统计量
        mu, sigma = calculate_activation_statistics(images, model, batch_size, dims, device)
        fid_values.append((mu, sigma))
    
    # 计算FID
    mu1, sigma1 = fid_values[0]
    mu2, sigma2 = fid_values[1]
    fid = calculate_frechet_distance(mu1, sigma1, mu2, sigma2)
    
    return fid

# 示例:计算两个图像文件夹之间的FID
paths = ['path/to/real_images', 'path/to/generated_images']
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

fid_value = calculate_fid_given_paths(paths, device=device)
print(f"FID 值: {fid_value:.4f}")




📌 感谢阅读!若文章对你有用,别吝啬互动~​
👍 点个赞 | ⭐ 收藏备用 | 💬 留下你的想法 ,关注我,更多干货持续更新!

Logo

脑启社区是一个专注类脑智能领域的开发者社区。欢迎加入社区,共建类脑智能生态。社区为开发者提供了丰富的开源类脑工具软件、类脑算法模型及数据集、类脑知识库、类脑技术培训课程以及类脑应用案例等资源。

更多推荐