optim.compute_gradients计算梯度 ,为什么返回的第一列为None? 5C

1.问题描述
模型通过keras.models.Sequential构建
loss => tf.losses.sparse_softmax_cross_entropy
通过 var_list=tf.trainable_variables() 获取可训练变量
计算梯度值:
loss_op = tf.losses.sparse_softmax_cross_entropy(y, y_pred)
grads_vars = optim.compute_gradients(loss_op, tf.trainable_variables())
grads_vars返回的第一元素为 None,导致面的程序异常。

 为什么grads_vars第一列返回的元素为None?

2.相关代码

import tensorflow as tf
import numpy as np
import time
import keras

# 加载数据集
x_dataset=np.random.rand(1000,28,28,1)
y_dataset=np.random.randint(0,10,size=(1000,))
act = tf.nn.leaky_relu

epoch = 200
batch_size = 5000
n_batch = len(x_dataset) // batch_size

# 把 batch 分成多少个 sub batch 来计算
subdivisions = 50
subdivisions_batch_size = int(np.ceil(batch_size / subdivisions))

# 是否使用 sub batch 方法,设置为 False 代表使用默认方法
is_on_subdivisions = True
def get_model(is_train=True, reuse=False):
    with tf.variable_scope('model', reuse=reuse):
        net = keras.models.Sequential()
        net.add(keras.layers.Conv2D(128,(3,3),input_shape=(28,28,1),strides=(2,2),padding='same',name='c1'))
        net.add(keras.layers.GlobalAveragePooling2D())
        net.add(keras.layers.Dense(10))
    return net


x = tf.placeholder(tf.float32, [None, 28, 28, 1])
y = tf.placeholder(tf.int32, [None,])

net = get_model()
y_pred=tf.cast(tf.argmax(net.outputs[0],axis=-1),dtype=tf.float32)
loss_op = tf.losses.sparse_softmax_cross_entropy(y, y_pred)
optim = tf.train.AdamOptimizer(0.01)
var_list=tf.trainable_variables()
grads_vars = optim.compute_gradients(loss_op, tf.trainable_variables())
#grads_vars返回的第一列为None,为什么?
for gv in grads_vars:
    print(gv)
# 删掉没梯度的参数, 倒序删除,减少麻烦
for i in range(len(grads_vars))[::-1]:
    if grads_vars[i][0] is None:
        del grads_vars[i]
#因为返回的第一列为None,所以所有变量都被删除了,导致后面的异常!        
print('len(grads_vars):',len(grads_vars))

# 生成梯度缓存:grads_vars第一列为None触发异常
grads_cache = [tf.Variable(np.zeros(t[0].shape.as_list(), np.float32), trainable=False) for t in grads_vars]

# 清空梯度缓存op,每一 batch 开始前调用
clear_grads_cache_op = tf.group([gc.assign(tf.zeros_like(gc)) for gc in grads_cache])

# 累积梯度op,累积每个 sub batch 的梯度
accumulate_grad_op = tf.group([gc.assign_add(gv[0]) for gc, gv in zip(grads_cache, grads_vars)])

# 求平均梯度,
mean_grad = [gc/tf.to_float(subdivisions) for gc in grads_cache]

# 组装梯度列表
new_grads_vars = [(g, gv[1]) for g, gv in zip(mean_grad, grads_vars)]

# 应用梯度op,累积完所有 sub batch 的梯度后,应用梯度
apply_grad_op = optim.apply_gradients(new_grads_vars)


# 原来的 optim ,跟上面做对照
ori_optim_op = tf.train.AdamOptimizer(0.01).minimize(loss_op, var_list=net.all_params)

config = tf.ConfigProto()
config.gpu_options.allow_growth = True
config.allow_soft_placement = True
sess = tf.Session(config=config)
sess.run(tf.global_variables_initializer())


for e in range(epoch):
    loss_sum = 0
    for b in progressbar(range(n_batch)):
        x_batch = x_dataset[b * batch_size: (b + 1) * batch_size]
        y_batch = y_dataset[b * batch_size: (b + 1) * batch_size]

        if is_on_subdivisions:
            # 每一批开始前需要清空梯度缓存
            sess.run(clear_grads_cache_op)

            sub_loss_sum = 0
            for s in range(subdivisions):
                x_sub_batch = x_batch[s * subdivisions_batch_size: (s + 1) * subdivisions_batch_size]
                y_sub_batch = y_batch[s * subdivisions_batch_size: (s + 1) * subdivisions_batch_size]
                if len(x_sub_batch) == 0:
                    break
                feed_dict = {x: x_sub_batch, y: y_sub_batch}
                _, los = sess.run([accumulate_grad_op, loss_op], feed_dict)
                sub_loss_sum += los
            loss_sum += sub_loss_sum / subdivisions

            # 梯度累积完成,开始应用梯度
            sess.run(apply_grad_op)
            # 本批次结束
        else:
            feed_dict = {x: x_batch, y: y_batch}
            _, los = sess.run([ori_optim_op, loss_op], feed_dict)
            loss_sum += los
    time.sleep(0.2)
    print('loss', loss_sum / n_batch)

3.报错信息

grads_vars:
(None, <tf.Variable 'model/c1/kernel:0' shape=(3, 3, 1, 128) dtype=float32_ref>)
(None, <tf.Variable 'model/c1/bias:0' shape=(128,) dtype=float32_ref>)
(None, <tf.Variable 'model/dense_1/kernel:0' shape=(128, 10) dtype=float32_ref>)
(None, <tf.Variable 'model/dense_1/bias:0' shape=(10,) dtype=float32_ref>)
(None, <tf.Variable 'model_1/c1/kernel:0' shape=(3, 3, 1, 128) dtype=float32_ref>)
(None, <tf.Variable 'model_1/c1/bias:0' shape=(128,) dtype=float32_ref>)
(None, <tf.Variable 'model_1/dense_2/kernel:0' shape=(128, 10) dtype=float32_ref>)
(None, <tf.Variable 'model_1/dense_2/bias:0' shape=(10,) dtype=float32_ref>)
(None, <tf.Variable 'model_2/c1/kernel:0' shape=(3, 3, 1, 128) dtype=float32_ref>)
(None, <tf.Variable 'model_2/c1/bias:0' shape=(128,) dtype=float32_ref>)
(None, <tf.Variable 'model_2/dense_3/kernel:0' shape=(128, 10) dtype=float32_ref>)
(None, <tf.Variable 'model_2/dense_3/bias:0' shape=(10,) dtype=float32_ref>)
len(grads_vars): 0

4.尝试过的方法方式
5.相关截图

wilsonwong
笔尖下的自由 直接编写公式compute_gradients可以获得正常值,但应用在keras构建的模型时,不知什么原因在哪里阻挡了梯度传递,导致返回为None!
8 个月之前 回复

1个回答

wilsonwong
笔尖下的自由 直接的公式计算可以,但是应用在keras构建的模型,不知道什么原因在哪里阻挡了梯度传递!!!
8 个月之前 回复
Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
立即提问