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

模型Loss逐轮下降但准确率为0,求客户产品预测模型优化方案

问题描述

我试图预测客户将兑换的产品,使用如下表格数据:

id_customerproduct_nameitem_quantityproduct_name_indexproduct_category_indexproduct_categoryproduct_typeseller_name
1234tv140391212eletronics43
12345smart tv116347212eletronics45
123456tv140391212eletronics43
1234567security camera1144929eletronics26
12345678soda137969174food338

模型Loss逐轮下降,但准确率始终为0,训练日志如下:

Epoch 2/15
114/114 [==============================] - 4s 26ms/step - loss: 83.7829 - accuracy: 0.0000e+00 - val_loss: 54.7766 - val_accuracy: 0.0000e+00

Epoch 2/15
114/114 [==============================] - 3s 24ms/step - loss: 54.5661 - accuracy: >0.0000e+00 - val_loss: 54.7244 - val_accuracy: 0.0000e+00

以下是构建模型的代码,请问应如何修改以获得正确的预测结果?

embedding_size = 50
min_redemption = min(df_filtered['product_category_index'].value_counts())
max_redemption = max(df_filtered['product_category_index'].value_counts())

num_customers = len(df_filtered['id_customer'].drop_duplicates())
num_products = len(df_filtered['product_category_index'].drop_duplicates())


df = df_filtered.sample(frac=1, random_state=42)
X  = df.drop(['product_category_index'],axis=1)
y  = df['product_category_index']

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state = 0)

scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)

class RecommenderNet(Model):
    def __init__(self, num_customers, num_products, embedding_size, **kwargs):
        super(RecommenderNet, self).__init__(**kwargs)
        self.num_customers = num_customers
        self.num_products = num_products
        self.embedding_size = embedding_size
        self.customer_embedding = Embedding(
            num_customers,
            embedding_size,
            embeddings_initializer="he_normal",
            embeddings_regularizer=l2(1e-6),
        )
        self.customer_bias = Embedding(num_customers, 1)
        self.product_embedding = Embedding(
            num_products,
            embedding_size,
            embeddings_initializer="he_normal",
            embeddings_regularizer=l2(1e-6),
        )
        self.product_bias = Embedding(num_products, 1)

    def call(self, inputs):
        customer_vector = self.customer_embedding(inputs[:, 0])
        customer_bias = self.customer_bias(inputs[:, 0])
        product_vector = self.product_embedding(inputs[:, 1])
        product_bias = self.product_bias(inputs[:, 1])
        dot_customer_product = tensordot(customer_vector, product_vector, 2)
        # Add all the components (including bias)
        x = dot_customer_product + customer_bias + product_bias

        return relu(x)

model = RecommenderNet(num_customers,num_products, embedding_size)
model.compile(loss='mae', optimizer='adam', metrics='accuracy')

问题诊断与修改方案

核心问题分析

  1. 输入与模型不匹配:你的RecommenderNet设计为处理客户、产品的离散整数索引,但你将所有特征标准化为连续值,且输入包含多列特征,模型仅取前两列,完全不符合嵌入层的输入要求(嵌入层需要非负整数索引)。
  2. 任务与损失/输出不匹配:这是多分类任务(预测产品类别索引),但你使用了回归任务的mae损失,输出用relu激活,无法生成分类所需的概率分布,导致准确率计算失效。
  3. 特征编码错误:id_customer是离散ID,需编码为从0开始的连续整数才能被嵌入层处理,直接使用原ID或标准化都会导致嵌入层失效。

修改步骤

1. 修正数据编码与输入处理

import pandas as pd
from sklearn.preprocessing import LabelEncoder
from sklearn.model_selection import train_test_split

# 对客户ID和产品类别索引进行连续整数编码
customer_encoder = LabelEncoder()
df_filtered['customer_idx'] = customer_encoder.fit_transform(df_filtered['id_customer'])

product_encoder = LabelEncoder()
df_filtered['product_category_idx'] = product_encoder.fit_transform(df_filtered['product_category_index'])

# 采样并构造输入输出
df = df_filtered.sample(frac=1, random_state=42)
# 模型输入仅保留客户索引(如需加入其他特征,需单独处理嵌入)
X = df[['customer_idx']].values
y = df['product_category_idx'].values

# 划分数据集,无需标准化离散索引
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=0)

2. 调整模型结构适配多分类任务

from tensorflow.keras import Model
from tensorflow.keras.layers import Embedding, Dense, Flatten
from tensorflow.keras.regularizers import l2

embedding_size = 50
num_customers = len(customer_encoder.classes_)
num_products = len(product_encoder.classes_)

class RecommenderNet(Model):
    def __init__(self, num_customers, num_products, embedding_size, **kwargs):
        super(RecommenderNet, self).__init__(**kwargs)
        self.customer_embedding = Embedding(
            num_customers,
            embedding_size,
            embeddings_initializer="he_normal",
            embeddings_regularizer=l2(1e-6),
        )
        self.customer_bias = Embedding(num_customers, 1)
        # 加入全连接层将嵌入映射到分类空间
        self.dense = Dense(64, activation='relu')
        self.output_layer = Dense(num_products, activation='softmax')

    def call(self, inputs):
        customer_vector = self.customer_embedding(inputs)
        customer_bias = self.customer_bias(inputs)
        # 展平嵌入向量
        x = Flatten()(customer_vector)
        x = self.dense(x)
        # 加入偏置并输出分类概率
        x = self.output_layer(x + Flatten()(customer_bias))
        return x

model = RecommenderNet(num_customers, num_products, embedding_size)
# 多分类任务使用稀疏交叉熵损失(y为整数索引)
model.compile(loss='sparse_categorical_crossentropy', optimizer='adam', metrics=['accuracy'])

3. 可选:加入其他类别特征

如果要使用product_type、seller_name等历史交互特征,需对每个类别特征单独做嵌入,再拼接后输入全连接层:

from tensorflow.keras.layers import concatenate

# 先对product_type编码
type_encoder = LabelEncoder()
df_filtered['product_type_idx'] = type_encoder.fit_transform(df_filtered['product_type'])
num_product_types = len(type_encoder.classes_)

class RecommenderNet(Model):
    def __init__(self, num_customers, num_products, num_product_types, embedding_size, **kwargs):
        super(RecommenderNet, self).__init__(**kwargs)
        self.customer_embedding = Embedding(num_customers, embedding_size, embeddings_regularizer=l2(1e-6))
        self.product_type_embedding = Embedding(num_product_types, embedding_size//2, embeddings_regularizer=l2(1e-6))
        self.customer_bias = Embedding(num_customers, 1)
        self.dense1 = Dense(128, activation='relu')
        self.dense2 = Dense(64, activation='relu')
        self.output_layer = Dense(num_products, activation='softmax')

    def call(self, inputs):
        customer_vec = Flatten()(self.customer_embedding(inputs[:,0]))
        product_type_vec = Flatten()(self.product_type_embedding(inputs[:,1]))
        customer_bias = Flatten()(self.customer_bias(inputs[:,0]))
        # 拼接所有特征
        x = concatenate([customer_vec, product_type_vec])
        x = self.dense1(x)
        x = self.dense2(x)
        x = self.output_layer(x + customer_bias)
        return x

# 构造包含多特征的输入
X = df[['customer_idx', 'product_type_idx']].values
model = RecommenderNet(num_customers, num_products, num_product_types, embedding_size)
model.compile(loss='sparse_categorical_crossentropy', optimizer='adam', metrics=['accuracy'])

其他注意事项

  • 若任务是协同过滤推荐(预测用户是否兑换某产品),需构造用户-产品对输入,目标为二元标签,损失改用binary_crossentropy,输出用sigmoid。
  • 检查数据类别平衡:若部分产品类别样本极少,可通过过采样、欠采样或设置类别权重解决。

内容的提问来源于stack exchange,提问作者Ueslei Sutil

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 00:44:06