使用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
相关产品推荐
相关产品推荐

