keras——accuracy_score公式

本文详细解读Accuracy_score指标,涉及TruePositive、TrueNegative、FalsePositive和FalseNegative的概念及其在模型评估中的应用,帮助理解分类模型性能的关键要素。

Accuracy_score公式为,
在这里插入图片描述

其中,

TP:True Positive,表示预测正确的个数

TN:True Negative,表示不属于本类,但预测正确的个数

FP:False Positive,表示将其他类预测为本类的个数

FN:False Negative,表示预测为其他类的个数

# 导入所需的预训练模型 from tensorflow.keras.applications import VGG16, InceptionV3, MobileNetV2, ResNet50, DenseNet121, EfficientNetB0 # 导入自定义层所需的基础组件 from tensorflow.keras.layers import Layer, Dropout, LayerNormalization, Dense # 导入tensorflow核心库(补充原代码缺失的导入) import tensorflow as tf # 导入keras模型和层(补充原代码缺失的导入) from tensorflow.keras import models, layers # 导入numpy(补充原代码缺失的导入) import numpy as np # 导入评估指标(补充原代码缺失的导入) from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score, confusion_matrix, roc_curve, auc, \ label_binarize # 导入可视化库(补充原代码缺失的导入) import matplotlib.pyplot as plt import seaborn as sns """ 自定义多头自注意力层(Multi-Head Self-Attention) 用于捕获特征之间的依赖关系,增强模型对重要特征的关注 """ class MultiHeadSelfAttention(Layer): # 初始化函数 def __init__(self, embed_dim=256, num_heads=8, dropout_rate=0.1): super(MultiHeadSelfAttention, self).__init__() self.num_heads = num_heads # 注意力头的数量 self.embed_dim = embed_dim # 嵌入维度(特征维度) self.dropout_rate = dropout_rate # Dropout比率 # 检查嵌入维度是否能被注意力头数整除(必须满足,否则无法均分) if embed_dim % num_heads != 0: raise ValueError(f"嵌入维度 = {embed_dim} 必须能被注意力头数 = {num_heads} 整除") self.projection_dim = embed_dim // num_heads # 每个注意力头的投影维度 # 定义Q(查询)、K(键)、V(值)的投影全连接层 self.query_dense = Dense(embed_dim) self.key_dense = Dense(embed_dim) self.value_dense = Dense(embed_dim) # 定义融合所有注意力头输出的全连接层 self.combine_heads = Dense(embed_dim) # 定义Dropout层(防止过拟合)和层归一化层(稳定训练) self.dropout = Dropout(dropout_rate) self.layernorm = LayerNormalization(epsilon=1e-6) # 核心注意力计算函数 def attention(self, query, key, value): # 计算Q和K的点积(注意力分数) score = tf.matmul(query, key, transpose_b=True) # 获取K的最后一维维度并转换为浮点型(用于缩放) dim_key = tf.cast(tf.shape(key)[-1], tf.float32) # 缩放注意力分数(防止维度太大导致softmax饱和) scaled_score = score / tf.math.sqrt(dim_key) # 对注意力分数应用softmax,得到注意力权重 weights = tf.nn.softmax(scaled_score, axis=-1) # 用注意力权重加权V,得到注意力输出 attention = tf.matmul(weights, value) return attention # 将特征拆分为多个注意力头 def separate_heads(self, x, batch_size): # 重塑维度:(批次大小, 序列长度, 头数, 每个头的投影维度) x = tf.reshape(x, (batch_size, -1, self.num_heads, self.projection_dim)) # 转置维度:(批次大小, 头数, 序列长度, 每个头的投影维度),方便并行计算 return tf.transpose(x, perm=[0, 2, 1, 3]) # 前向传播函数(核心逻辑) def call(self, inputs): # 获取批次大小(动态计算,适配不同批次) batch_size = tf.shape(inputs)[0] # 将输入特征投影到Q/K/V空间 query = self.query_dense(inputs) key = self.key_dense(inputs) value = self.value_dense(inputs) # 将Q/K/V拆分为多个注意力头 query = self.separate_heads(query, batch_size) key = self.separate_heads(key, batch_size) value = self.separate_heads(value, batch_size) # 计算多头注意力 attention = self.attention(query, key, value) # 转置并拼接所有注意力头的输出:恢复为(批次大小, 序列长度, 嵌入维度) attention = tf.transpose(attention, perm=[0, 2, 1, 3]) concat_attention = tf.reshape(attention, (batch_size, -1, self.embed_dim)) # 融合注意力输出 + Dropout + 残差连接(保持信息完整性) + 层归一化 output = self.combine_heads(concat_attention) output = self.dropout(output) output = self.layernorm(inputs + output) # 对序列维度做均值池化,得到固定长度的输出(适配分类任务) output = tf.reduce_mean(output, axis=1) return output # 重复定义的函数(保留原代码结构,实际以最后一个为准) def compute_output_shape(self, input_shape): # 输出形状:(批次大小, 嵌入维度) return input_shape[0], self.embed_dim """ 以下函数用于创建不同的预训练模型+多头注意力的混合模型 统一结构:预训练骨干网络(冻结) + 全局平均池化 + 全连接层 + 多头注意力 + 分类头 """ # 创建自定义CNN模型(无预训练,纯手动构建) def create_cnn_model(): model = models.Sequential() # 第一卷积块:卷积 + 批归一化 + 最大池化 + Dropout model.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=(128, 128, 3))) model.add(layers.BatchNormalization()) # 批归一化:加速训练,稳定梯度 model.add(layers.MaxPooling2D((2, 2))) # 最大池化:降维,提取关键特征 model.add(layers.Dropout(0.3)) # Dropout:防止过拟合 # 第二卷积块 model.add(layers.Conv2D(64, (3, 3), activation='relu')) model.add(layers.BatchNormalization()) model.add(layers.MaxPooling2D((2, 2))) model.add(layers.Dropout(0.3)) # 第三卷积块 model.add(layers.Conv2D(128, (3, 3), activation='relu')) model.add(layers.BatchNormalization()) model.add(layers.MaxPooling2D((2, 2))) model.add(layers.Dropout(0.3)) # 第四卷积块 model.add(layers.Conv2D(256, (3, 3), activation='relu')) model.add(layers.BatchNormalization()) model.add(layers.MaxPooling2D((2, 2))) model.add(layers.Dropout(0.3)) # 展平特征图:转为一维向量 model.add(layers.Flatten()) # 全连接层 + L2正则化(防止过拟合) model.add(layers.Dense(512, activation='relu', kernel_regularizer=tf.keras.regularizers.l2(0.01))) model.add(layers.Dropout(0.5)) # 添加多头自注意力层(适配512维特征) model.add(MultiHeadSelfAttention(embed_dim=512, num_heads=8)) # 分类头 model.add(layers.Dense(256, activation='relu', kernel_regularizer=tf.keras.regularizers.l2(0.01))) model.add(layers.Dropout(0.5)) model.add(layers.Dense(num_classes, activation='softmax')) return model # 导入更多预训练模型 from tensorflow.keras.applications import ResNet50 # 创建ResNet50模型 def create_resnet50_model(): base_model = ResNet50( weights='/kaggle/input/tf-keras-pretrained-model-weights/No Top/resnet50_weights_tf_dim_ordering_tf_kernels_notop.h5', include_top=False, input_shape=(128, 128, 3)) for layer in base_model.layers: layer.trainable = False model = models.Sequential() model.add(base_model) model.add(layers.GlobalAveragePooling2D()) model.add(layers.Dense(256, activation='relu')) model.add(MultiHeadSelfAttention(embed_dim=256, num_heads=8)) model.add(layers.Dense(256, activation='relu')) model.add(layers.Dropout(0.5)) model.add(layers.Dense(num_classes, activation='softmax')) return model # 模型字典:键为模型名称,值为对应的模型实例 # 注意:使用前需先定义num_classes(类别数)、X_train/y_train/X_val/y_val(数据集)、label_names(类别名称) models_dict = { "ResNet50": create_resnet50_model(), } # 导入Keras后端(用于自定义损失函数) from tensorflow.keras import backend as K """ 自定义Focal Loss(焦点损失) 解决类别不平衡问题,降低易分类样本的权重,关注难分类样本 """ def focal_loss(gamma=2., alpha=0.25): """ 计算多分类任务的焦点损失 参数: gamma (float): 聚焦参数,gamma越大,对难分类样本的关注越高 alpha (float): 平衡参数,调节正负样本的权重 返回: function: 损失函数 """ def focal_loss_fixed(y_true, y_pred): epsilon = K.epsilon() # 防止log(0)的极小值 y_pred = K.clip(y_pred, epsilon, 1. - epsilon) # 裁剪预测值,避免数值不稳定 # 将真实标签转换为one-hot编码(适配多分类) y_true = tf.one_hot(tf.cast(y_true, tf.int32), depth=y_pred.shape[-1]) # 计算类别平衡权重 alpha_t = y_true * alpha + (K.ones_like(y_true) - y_true) * (1 - alpha) # 计算真实类别对应的预测概率 p_t = y_true * y_pred + (K.ones_like(y_true) - y_true) * (1 - y_pred) # 计算焦点损失核心公式 fl = - alpha_t * K.pow((K.ones_like(y_true) - p_t), gamma) * K.log(p_t) # 对所有类别求和并取均值,得到最终损失 return K.mean(K.sum(fl, axis=-1)) return focal_loss_fixed # 计算类别权重(解决类别不平衡) from sklearn.utils.class_weight import compute_class_weight # 注意:使用前需确保y_train已定义 class_weights = compute_class_weight('balanced', classes=np.unique(y_train), y=y_train) class_weights_dict = {i: class_weights[i] for i in range(len(class_weights))} # 导入优化器 from tensorflow.keras.optimizers import SGD, Adam # 训练并评估所有模型 results = {} # 存储各模型的评估结果 for model_name, model in models_dict.items(): print(f"开始训练 {model_name} 模型...") # 导入回调函数 from tensorflow.keras.callbacks import EarlyStopping, ReduceLROnPlateau # 定义早停回调:监控验证集准确率,最大值模式,耐心值8(8轮无提升则停止),恢复最佳权重 early_stopping = EarlyStopping(monitor='val_accuracy', mode='max', patience=8, restore_best_weights=True) # 定义学习率衰减回调:监控验证集损失,最小值模式,衰减因子0.5,耐心值3,最小学习率1e-8 reduce_lr = ReduceLROnPlateau(monitor='val_loss', mode='min', factor=0.5, patience=3, min_lr=1e-8) # 编译模型:使用Adam优化器,焦点损失,评估指标为准确率 model.compile(optimizer=Adam(learning_rate=1e-3), loss=focal_loss(gamma=2., alpha=0.25), metrics=['accuracy']) # 训练模型:20轮,使用验证集,添加回调函数,静默模式(无详细输出) # 注意:使用前需确保X_train/y_train/X_val/y_val已定义 model.fit(X_train, y_train, epochs=20, validation_data=(X_val, y_val), callbacks=[early_stopping, reduce_lr], verbose=0) # 恢复最佳权重(早停回调保存的最优权重) if early_stopping.best_weights is not None: model.set_weights(early_stopping.best_weights) print(f"{model_name} 模型已恢复最佳权重") print(f"开始评估 {model_name} 模型...") # 预测验证集 y_pred = model.predict(X_val, verbose=0) # 处理可能的稀疏张量(转换为普通张量) if isinstance(y_pred, tf.RaggedTensor): y_pred = y_pred.to_tensor() # 将预测概率转换为类别标签(取最大值对应的索引) y_pred_classes = np.argmax(y_pred, axis=1) # 计算评估指标(加权平均,适配多分类) accuracy = accuracy_score(y_val, y_pred_classes) # 准确率 precision = precision_score(y_val, y_pred_classes, average='weighted') # 精确率 recall = recall_score(y_val, y_pred_classes, average='weighted') # 召回率 f1 = f1_score(y_val, y_pred_classes, average='weighted') # F1分数 # 存储模型评估结果 results[model_name] = { "Accuracy": accuracy, "Precision": precision, "Recall": recall, "F1-score": f1 } # 绘制混淆矩阵 conf_mat = confusion_matrix(y_val, y_pred_classes) plt.figure(figsize=(7, 6)) # 热力图可视化混淆矩阵,标注数值,蓝色系,显示类别名称 sns.heatmap(conf_mat, annot=True, fmt='d', cmap='Blues', xticklabels=label_names, yticklabels=label_names) plt.title(f'混淆矩阵 - {model_name}') plt.xlabel('预测类别') plt.ylabel('真实类别') plt.savefig(f'confusion_matrix_{model_name}.png') # 保存图片 plt.show() # 显示图片 # 根据类别数选择不同的ROC曲线绘制方式 if num_classes == 2: # 二分类任务:绘制单条ROC曲线 # 计算ROC曲线和AUC fpr, tpr, _ = roc_curve(y_val, y_pred[:, 1]) # 使用正类的预测概率 roc_auc = auc(fpr, tpr) # 绘制ROC曲线 plt.figure() plt.plot(fpr, tpr, color='darkorange', lw=2, label=f'ROC曲线 (AUC = {roc_auc:.2f})') # 绘制对角线(随机猜测基准) plt.plot([0, 1], [0, 1], color='gray', lw=2, linestyle='--') plt.xlim([-0.01, 1.0]) plt.ylim([-0.01, 1.05]) plt.xlabel('假阳性率 (FPR)') plt.ylabel('真阳性率 (TPR)') plt.title(f'ROC曲线 - {model_name}') plt.legend(loc="lower right") plt.savefig(f'roc_curve_{model_name}.png') plt.show() else: # 多分类任务:绘制每个类别的ROC曲线 # 将真实标签转换为多标签二进制格式 y_val_bin = label_binarize(y_val, classes=label_names) n_classes = y_val_bin.shape[1] # 初始化存储每个类别ROC数据的字典 fpr = dict() tpr = dict() roc_auc = dict() # 计算每个类别的ROC曲线和AUC for i in range(n_classes): fpr[i], tpr[i], _ = roc_curve(y_val_bin[:, i], y_pred[:, i]) roc_auc[i] = auc(fpr[i], tpr[i]) # 绘制多分类ROC曲线 plt.figure() colors = ['aqua', 'darkorange', 'cornflowerblue'] # 颜色列表(可扩展) for i, color in zip(range(n_classes), colors): plt.plot(fpr[i], tpr[i], color=color, lw=2, label=f'{label_names[i]} 的ROC曲线 (AUC = {roc_auc[i]:.2f})') # 绘制对角线基准 plt.plot([0, 1], [0, 1], 'k--', lw=2) plt.xlim([-0.01, 1.0]) plt.ylim([-0.01, 1.05]) plt.xlabel('假阳性率 (FPR)') plt.ylabel('真阳性率 (TPR)') plt.title(f'多分类ROC曲线 - {model_name}') plt.legend(loc="lower right") plt.savefig(f'roc_curve_{model_name}.png') plt.show() # 打印所有模型的评估结果 print("=" * 50) print("所有模型评估结果汇总:") print("=" * 50) for model_name, metrics in results.items(): print(f"\n【{model_name}】") for metric, value in metrics.items(): print(f"{metric}:{value:.4f}")如果我只想要resnet50可以直接删除自建的cnn代码嘛?
最新发布
12-13
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值