You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Keras(TF后端)的说话人识别:sampled_softmax_loss参数及用法问询

在Keras中结合tf.nn.sampled_softmax_loss加速说话人识别训练

我来帮你梳理清楚怎么在你的Keras模型里用上tf.nn.sampled_softmax_loss,完美适配你现有的CNN架构,解决类别数量庞大带来的训练速度问题。

核心前提先明确

首先要纠正两个关键认知,不然很容易踩坑:

  1. 标签不用做One-Hot编码:tf.nn.sampled_softmax_loss需要的是整数形式的类别索引(比如0、1、2...对应不同说话人),而不是One-Hot向量,所以你原来的to_categorical步骤要去掉,直接用原始的y_train、y_valid、y_test即可。
  2. 模型最后输出是特征向量,不是概率/Logits:Sampled Softmax的核心优势就是避免计算所有类别的Logits,所以我们用CNN最后一个隐藏层的256维特征来计算损失,不用提前算所有类别的映射。
  3. 必须用tf.reduce_mean:tf.nn.sampled_softmax_loss会返回每个样本的损失(形状是[batch_size]),而Keras需要一个标量作为整个Batch的损失,所以一定要用tf.reduce_mean把样本损失平均成标量,和你原来用的categorical_crossentropy行为保持一致。

具体代码修改步骤

1. 调整标签处理

删掉原来的One-Hot编码代码:

# 移除这三行
# y_train_hot = to_categorical(y_train)
# y_valid_hot = to_categorical(y_valid)
# y_test_hot = to_categorical(y_test)
# 直接用原始的整数标签y_train、y_valid、y_test

2. 改用Keras函数式API构建模型

因为Sequential模型不好单独定义最后一层的权重变量,我们换成函数式API,保留你原来的CNN结构,只是最后输出特征向量:

from keras.models import Model
from keras.layers import Input

# 输入层和原来一致
inputs = Input(shape=(dim_1, dim_2, dim_3))
x = Conv2D(128, kernel_size=(6, 6), strides=2, activation='relu')(inputs)
x = Conv2D(64, kernel_size=(2, 2), strides=1, activation='relu')(x)
x = Conv2D(32, kernel_size=(2, 2), activation='relu')(x)
x = MaxPooling2D(pool_size=(2, 2))(x)
x = Dropout(0.3)(x)
x = Flatten()(x)
x = Dense(256, activation='relu', use_bias=True, kernel_regularizer=regularizers.l2(0.01))(x)
x = Dropout(0.2)(x)
x = Dense(256, activation='relu', use_bias=True, kernel_regularizer=regularizers.l2(0.02))(x)
x = Dropout(0.3)(x)
# 最后一个隐藏层,输出256维特征
features = Dense(256, activation='relu', use_bias=True, kernel_regularizer=regularizers.l2(0.02))(x)
x = Dropout(0.3)(features)

# 单独定义最后一层的权重和偏置(从256维特征到所有说话人类别)
final_weights = tf.Variable(
    tf.random.truncated_normal([256, num_classes], stddev=0.01),
    name='final_dense_weights'
)
final_biases = tf.Variable(
    tf.zeros([num_classes]),
    name='final_dense_biases'
)

# 模型输出是256维特征向量
model = Model(inputs=inputs, outputs=features)

3. 自定义损失函数和准确率指标

现在写一个适配Keras的损失函数,内部调用tf.nn.sampled_softmax_loss,同时自定义准确率指标(因为模型输出是特征,没法用默认的accuracy):

def sampled_softmax_loss(y_true, y_pred):
    # y_true: 输入的整数标签,形状[batch_size]
    # y_pred: 模型输出的256维特征,形状[batch_size, 256]
    # 把标签转换成[batch_size, 1]的形状,符合sampled_softmax_loss的要求
    labels = tf.expand_dims(tf.cast(y_true, tf.int64), axis=1)
    
    # 调用tf.nn.sampled_softmax_loss,参数对应你的场景
    per_sample_loss = tf.nn.sampled_softmax_loss(
        weights=tf.transpose(final_weights),  # 转置成[num_classes, 256],符合函数要求
        biases=final_biases,
        labels=labels,
        inputs=y_pred,
        num_sampled=100,  # 每次采样的类别数,可根据你的类别总数调整(比如类别数的1/10)
        num_classes=num_classes,
        num_true=1,  # 每个样本对应1个真实类别
        partition_strategy="div"  # 默认采样策略即可
    )
    
    # 对Batch内的损失取平均,返回标量损失
    return tf.reduce_mean(per_sample_loss)

# 自定义准确率:计算所有类别的Logits,再和真实标签比较
def sampled_accuracy(y_true, y_pred):
    logits = tf.matmul(y_pred, final_weights) + final_biases
    predictions = tf.argmax(logits, axis=1, output_type=tf.int64)
    y_true_int = tf.cast(y_true, tf.int64)
    return tf.reduce_mean(tf.cast(tf.equal(predictions, y_true_int), tf.float32))

4. 编译并训练模型

现在用自定义的损失和指标编译模型,训练时直接用原始整数标签:

model.compile(
    loss=sampled_softmax_loss,
    optimizer='adamax',
    metrics=[sampled_accuracy]
)

earlystopping = EarlyStopping(monitor='val_loss', min_delta=0.001, patience=15, verbose=verbose, mode='auto')
model.fit(
    X_train, y_train,
    batch_size=batch_size,
    callbacks=[earlystopping],
    epochs=epochs,
    verbose=verbose,
    validation_data=(X_valid, y_valid)
)

参数设置说明

给你拆解一下tf.nn.sampled_softmax_loss里每个参数的作用,方便你根据自己的数据集调整:

  • weights:从256维特征到所有类别的权重矩阵,转置后形状为[num_classes, 256],对应我们定义的final_weights的转置。
  • biases:每个类别的偏置项,形状[num_classes],对应final_biases。
  • labels:真实类别的整数索引,必须是[batch_size, num_true]的形状,这里我们把y_true扩展了一维。
  • inputs:模型输出的256维特征向量,形状[batch_size, 256]。
  • num_sampled:每次训练时随机采样的类别数量,建议设置为类别总数的1/10左右(比如你有1000个说话人,就设100),太小会导致损失估计偏差大,太大则失去加速效果。
  • num_classes:你的说话人总类别数,也就是len(labels)。
  • num_true:每个样本对应的真实类别数,这里每个样本只属于一个说话人,所以设为1。

内容的提问来源于stack exchange,提问作者Selim Alawwa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 07:35:59