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

Python报错ValueError:无法将float NaN转换为整数的解决求助

问题:Chainer DQN训练触发ValueError: cannot convert float NaN to integer

运行以下Chainer框架的DQN训练代码时:

class Q_Network(chainer.Chain):

    def __init__(self, input_size, hidden_size, output_size):
        super(Q_Network, self).__init__(
            fc1 = L.Linear(input_size, hidden_size),
            fc2 = L.Linear(hidden_size, hidden_size),
            fc3 = L.Linear(hidden_size, output_size)
        )

    def __call__(self, x):
        h = F.relu(self.fc1(x))
        h = F.relu(self.fc2(h))
        y = self.fc3(h)
        return y

    def reset(self):
        self.zerograds()

Q = Q_Network(input_size=env.history_t+1, hidden_size=100, output_size=3)
Q_ast = copy.deepcopy(Q)
optimizer = chainer.optimizers.Adam()
optimizer.setup(Q)

epoch_num = 50
step_max = len(env.data)-1
memory_size = 200
batch_size = 20
epsilon = 1.0
epsilon_decrease = 1e-3
epsilon_min = 0.1
start_reduce_epsilon = 200
train_freq = 10
update_q_freq = 20
gamma = 0.97
show_log_freq = 5

memory = []
total_step = 0
total_rewards = []
total_losses = []

start = time.time()
for epoch in range(epoch_num):

    pobs = env.reset()
    step = 0
    done = False
    total_reward = 0
    total_loss = 0

    while not done and step < step_max:

        # select act
        pact = np.random.randint(3)
        if np.random.rand() > epsilon:
            pact = Q(np.array(pobs, dtype=np.float32).reshape(1, -1))
            pact = np.argmax(pact.data)

        # act
        obs, reward, done = env.step(pact)

        # add memory
        memory.append((pobs, pact, reward, obs, done))
        if len(memory) > memory_size:
            memory.pop(0)

        # train or update q
        if len(memory) == memory_size:
            if total_step % train_freq == 0:
                shuffled_memory = np.random.permutation(memory)
                memory_idx = range(len(shuffled_memory))
                for i in memory_idx[::batch_size]:
                    batch = np.array(shuffled_memory[i:i+batch_size])
                    b_pobs = np.array(batch[:, 0].tolist(), dtype=np.float32).reshape(batch_size, -1)
                    b_pact = np.array(batch[:, 1].tolist(), dtype=np.int32)
                    b_reward = np.array(batch[:, 2].tolist(), dtype=np.int32)
                    b_obs = np.array(batch[:, 3].tolist(), dtype=np.float32).reshape(batch_size, -1)
                    b_done = np.array(batch[:, 4].tolist(), dtype=np.bool)

                    q = Q(b_pobs)
                    maxq = np.max(Q_ast(b_obs).data, axis=1)
                    target = copy.deepcopy(q.data)
                    for j in range(batch_size):
                        target[j, b_pact[j]] = b_reward[j]+gamma*maxq[j]*(not b_done[j])
                    Q.reset()
                    loss = F.mean_squared_error(q, target)
                    total_loss += loss.data
                    loss.backward()
                    optimizer.update()

            if total_step % update_q_freq == 0:
                Q_ast = copy.deepcopy(Q)

        # epsilon
        if epsilon > epsilon_min and total_step > start_reduce_epsilon:
            epsilon -= epsilon_decrease

        # next step
        total_reward += reward
        pobs = obs
        step += 1
        total_step += 1

    total_rewards.append(total_reward)
    total_losses.append(total_loss)

    if (epoch+1) % show_log_freq == 0:
        log_reward = sum(total_rewards[((epoch+1)-show_log_freq):])/show_log_freq
        log_loss = sum(total_losses[((epoch+1)-show_log_freq):])/show_log_freq
        elapsed_time = time.time()-start
        print('\t'.join(map(str, [epoch+1, epsilon, total_step, log_reward, log_loss, elapsed_time])))
        start = time.time()
                
return Q, total_losses, total_rewards

执行Q, total_losses, total_rewards = train_dqn(Environment1(train))时触发错误:ValueError: cannot convert float NaN to integer,尝试int(numpy.nan)无效。


错误原因

该错误源于训练过程中Q网络输出出现NaN,导致将其转为整数动作时失败。常见诱因:

  • 状态数据或奖励值本身包含NaN
  • 梯度爆炸导致网络权重变为NaN
  • 批量数据处理时维度不匹配或数据类型错误

修复后的代码

以下是加入数据校验、梯度裁剪、权重初始化正则化的修复版本:

import numpy as np
import copy
import time
import chainer
from chainer import links as L
from chainer import functions as F

class Q_Network(chainer.Chain):

    def __init__(self, input_size, hidden_size, output_size):
        super(Q_Network, self).__init__(
            fc1 = L.Linear(input_size, hidden_size),
            fc2 = L.Linear(hidden_size, hidden_size),
            fc3 = L.Linear(hidden_size, output_size)
        )
        # 初始化权重,加入小范围随机值防止NaN初始值
        for param in self.params():
            param.data = np.random.normal(0, 0.01, param.data.shape).astype(np.float32)

    def __call__(self, x):
        h = F.relu(self.fc1(x))
        h = F.relu(self.fc2(h))
        y = self.fc3(h)
        return y

    def reset(self):
        self.zerograds()

def train_dqn(env):
    Q = Q_Network(input_size=env.history_t+1, hidden_size=100, output_size=3)
    Q_ast = copy.deepcopy(Q)
    optimizer = chainer.optimizers.Adam()
    optimizer.setup(Q)
    # 添加梯度裁剪防止爆炸
    optimizer.add_hook(chainer.optimizer.GradientClipping(1.0))

    epoch_num = 50
    step_max = len(env.data)-1
    memory_size = 200
    batch_size = 20
    epsilon = 1.0
    epsilon_decrease = 1e-3
    epsilon_min = 0.1
    start_reduce_epsilon = 200
    train_freq = 10
    update_q_freq = 20
    gamma = 0.97
    show_log_freq = 5

    memory = []
    total_step = 0
    total_rewards = []
    total_losses = []

    start = time.time()
    for epoch in range(epoch_num):

        pobs = env.reset()
        # 校验初始状态是否含NaN
        if np.isnan(pobs).any():
            raise ValueError("Initial state contains NaN")
        step = 0
        done = False
        total_reward = 0
        total_loss = 0

        while not done and step < step_max:

            # select act
            pact = np.random.randint(3)
            if np.random.rand() > epsilon:
                q_values = Q(np.array(pobs, dtype=np.float32).reshape(1, -1))
                q_data = q_values.data
                # 检查Q值是否含NaN,若有则随机选择动作
                if np.isnan(q_data).any():
                    pact = np.random.randint(3)
                else:
                    pact = np.argmax(q_data)

            # act
            obs, reward, done = env.step(pact)
            # 校验奖励和新状态是否含NaN
            if np.isnan(reward) or np.isnan(obs).any():
                reward = 0.0  # 替换NaN奖励为0
                obs = np.nan_to_num(obs)  # 替换状态中的NaN为0

            # add memory,过滤含NaN的样本
            if not (np.isnan(pobs).any() or np.isnan(reward) or np.isnan(obs).any()):
                memory.append((pobs, pact, reward, obs, done))
            if len(memory) > memory_size:
                memory.pop(0)

            # train or update q
            if len(memory) == memory_size:
                if total_step % train_freq == 0:
                    shuffled_memory = np.random.permutation(memory)
                    memory_idx = range(len(shuffled_memory))
                    for i in memory_idx[::batch_size]:
                        batch = np.array(shuffled_memory[i:i+batch_size])
                        # 确保批量数据无NaN
                        batch = batch[~np.isnan(batch).any(axis=1)]
                        if len(batch) < batch_size:
                            continue  # 跳过不足批量的样本
                        b_pobs = np.array(batch[:, 0].tolist(), dtype=np.float32).reshape(len(batch), -1)
                        b_pact = np.array(batch[:, 1].tolist(), dtype=np.int32)
                        b_reward = np.array(batch[:, 2].tolist(), dtype=np.float32)  # 改为float避免整数转换问题
                        b_obs = np.array(batch[:, 3].tolist(), dtype=np.float32).reshape(len(batch), -1)
                        b_done = np.array(batch[:, 4].tolist(), dtype=np.bool)

                        q = Q(b_pobs)
                        maxq = np.max(Q_ast(b_obs).data, axis=1)
                        # 检查maxq是否含NaN
                        maxq = np.nan_to_num(maxq)
                        target = copy.deepcopy(q.data)
                        for j in range(len(batch)):
                            target[j, b_pact[j]] = b_reward[j] + gamma * maxq[j] * (not b_done[j])
                        Q.reset()
                        loss = F.mean_squared_error(q, target)
                        total_loss += loss.data if not np.isnan(loss.data) else 0
                        loss.backward()
                        optimizer.update()

                if total_step % update_q_freq == 0:
                    Q_ast = copy.deepcopy(Q)

            # epsilon
            if epsilon > epsilon_min and total_step > start_reduce_epsilon:
                epsilon = max(epsilon_min, epsilon - epsilon_decrease)  # 确保不低于最小值

            # next step
            total_reward += reward
            pobs = obs
            step += 1
            total_step += 1

        total_rewards.append(total_reward)
        total_losses.append(total_loss)

        if (epoch+1) % show_log_freq == 0:
            log_reward = sum(total_rewards[((epoch+1)-show_log_freq):])/show_log_freq
            log_loss = sum(total_losses[((epoch+1)-show_log_freq):])/show_log_freq
            elapsed_time = time.time()-start
            print('\t'.join(map(str, [epoch+1, epsilon, total_step, log_reward, log_loss, elapsed_time])))
            start = time.time()
                    
    return Q, total_losses, total_rewards

关键修改点
  • 网络初始化时给权重赋予小范围随机值,避免初始NaN
  • 添加梯度裁剪钩子,防止梯度爆炸导致权重NaN
  • 动作选择前检查Q值是否含NaN,异常时 fallback 到随机动作
  • 对状态、奖励数据做NaN校验,替换异常值为合理值
  • 批量数据处理时过滤含NaN的样本,避免污染训练
  • 将奖励数据类型改为float,避免整数转换时的NaN问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 13:19:57