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

使用tf.keras.metrics.R2Score在TensorFlow中出现类型转换错误

问题描述

使用TensorFlow构建回归模型时,采用tf.keras.metrics.R2Score()作为评估指标,第一个epoch结束后抛出如下错误:

ValueError: Tensor conversion requested dtype int32 for Tensor with dtype float32: <tf.Tensor: shape=(), dtype=float32, numpy=0.0>

使用tf.keras.metrics.RootMeanSquaredError()等其他指标时模型可正常运行。

代码实现

import pandas as pd

weather_states = pd.read_sql("SELECT stations.id, stations.capacity_kw, start, wind_speed_10m, wind_direction_10m, wind_speed_80m, wind_direction_80m, wind_speed_180m, wind_direction_180m FROM stations INNER JOIN weather_states ON stations.id = weather_states.station WHERE weather_states.source = 'openmeteo_forecast/history/best' AND stations.source = 'wind'", db_client)
 
grid_states = pd.read_sql("SELECT start, wind FROM grid_states", db_client)
 
def create_x_y(df: tuple[Any, pd.DataFrame]):
    start = df[1]["start"].iloc[0]
    res = df[1].sort_values("id").drop(["id", "start"], axis=1)
    temp_wind = grid_states.loc[grid_states["start"] == start]["wind"].to_list()
    wind_kw = temp_wind if len(temp_wind) >= 1 else None
    res_flat_df = pd.DataFrame(res.to_numpy().reshape((1, -1)))
    res_flat_df["wind_kw"] = wind_kw
    return res_flat_df
 
data = pd.concat(map(create_x_y, weather_states.groupby("start"))).dropna()
from sklearn.model_selection import train_test_split
 

data = data.astype("float32")
train, test = train, test = train_test_split(data.dropna(), test_size=0.2)
 
train_y = train.pop("wind_kw")
train_x = train
 

test_y = test.pop("wind_kw")
test_x = test
 
norm = tf.keras.layers.Normalization()
norm.adapt(train_x)
 
model = tf.keras.Sequential([
    norm,
    tf.keras.layers.Dense(16, activation="linear"),
    tf.keras.layers.Dropout(0.3),
    tf.keras.layers.Dense(1, activation="linear"),
])
 

model.compile(
    optimizer=tf.keras.optimizers.legacy.Adam(0.001),
    metrics=[tf.keras.metrics.R2Score(dtype=tf.float32)],
    loss=tf.keras.losses.MeanSquaredError(),
)
 
model.fit(train_x, train_y, epochs=7, batch_size=2)
 
tf.keras.models.save_model(model, 'wind.keras')

数据信息

数据统计描述

0            1            2            3            4  ...          241          242          243          244      wind_kw
count    1896.0  1896.000000  1896.000000  1896.000000  1896.000000  ...  1896.000000  1896.000000  1896.000000  1896.000000  1896.000000
mean   144000.0     4.315717   189.610759     5.791377   193.830169  ...     3.881292   145.420359     4.572205   143.642405  1292.576958
std         0.0     2.482439   113.178764     2.926497   113.685887  ...     2.612259    93.293471     2.775681    94.721086   611.333721
min    144000.0     0.100000     1.000000     0.100000     1.000000  ...     0.100000     2.000000     0.000000     1.000000    34.263000
25%    144000.0     2.110000    88.000000     3.487500    90.000000  ...     1.900000    67.000000     2.500000    63.000000   793.109500
50%    144000.0     4.110000   199.000000     5.500000   231.000000  ...     3.075000   137.000000     3.940000   135.000000  1251.590000
75%    144000.0     6.220000   291.000000     7.882500   294.000000  ...     5.502500   205.000000     6.082500   205.000000  1761.926750
max    144000.0    11.670000   360.000000    15.210000   360.000000  ...    14.460000   360.000000    16.980000   360.000000  3008.125000

数据类型与形状

print(type(data))
#<class 'pandas.core.frame.DataFrame'>
print(data.dtypes)
#0          float32
#1          float32
#2          float32
#3          float32
#4          float32
#            ...   
#241        float32
#242        float32
#243        float32
#244        float32
#wind_kw    float32
#Length: 246, dtype: object
print(data.shape)
#(1896, 246)
问题分析与解决方案

这个错误的核心是R2Score指标计算过程中出现了 dtype 不匹配,具体是内部逻辑试图将float32张量转为int32,而其他指标无此转换步骤。结合代码和数据,可从以下方向修复:

1. 显式统一标签的张量类型

尽管已将DataFrame转为float32,但pop出的标签仍是pandas Series,TensorFlow处理时可能触发隐式类型转换异常。可显式转为TensorFlow的float32张量:

train_y = tf.convert_to_tensor(train.pop("wind_kw"), dtype=tf.float32)
test_y = tf.convert_to_tensor(test.pop("wind_kw"), dtype=tf.float32)

2. 调整R2Score的参数设置

尝试移除dtype=tf.float32参数,让指标自动匹配输入数据类型:

model.compile(
    optimizer=tf.keras.optimizers.legacy.Adam(0.001),
    metrics=[tf.keras.metrics.R2Score()],
    loss=tf.keras.losses.MeanSquaredError(),
)

3. 解决小批量导致的计算异常

batch_size设为2时,若某批次的真实标签方差为0(两个样本wind_kw完全相同),会导致R²计算时分母为0,进而触发 dtype 错误。可增大batch_size,或预处理时过滤标签方差为0的样本组:

# 过滤同一start下wind_kw值完全相同的组
data = pd.concat(map(create_x_y, weather_states.groupby("start"))).dropna()
data = data.groupby("start").filter(lambda x: x["wind_kw"].nunique() > 1).reset_index(drop=True)

4. 自定义R²指标替代官方实现

若官方R2Score仍有问题,可手动实现指标,避免内部类型转换冲突:

class CustomR2Score(tf.keras.metrics.Metric):
    def __init__(self, name='r2_score', **kwargs):
        super().__init__(name=name, **kwargs)
        self.ss_res = self.add_weight(name='ss_res', initializer='zeros')
        self.ss_tot = self.add_weight(name='ss_tot', initializer='zeros')

    def update_state(self, y_true, y_pred, sample_weight=None):
        y_true = tf.cast(y_true, tf.float32)
        y_pred = tf.cast(y_pred, tf.float32)
        ss_res = tf.reduce_sum(tf.square(y_true - y_pred))
        ss_tot = tf.reduce_sum(tf.square(y_true - tf.reduce_mean(y_true)))
        self.ss_res.assign_add(ss_res)
        self.ss_tot.assign_add(ss_tot)

    def result(self):
        return 1 - (self.ss_res / (self.ss_tot + 1e-7))  # 加小常数避免除以0

    def reset_state(self):
        self.ss_res.assign(0.0)
        self.ss_tot.assign(0.0)

# 编译时使用自定义指标
model.compile(
    optimizer=tf.keras.optimizers.legacy.Adam(0.001),
    metrics=[CustomR2Score()],
    loss=tf.keras.losses.MeanSquaredError(),
)

内容的提问来源于stack exchange,提问作者Jacques Amsel

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 06:28:11