【实验踩坑小结】如何在keras构建model中取出tensor中的某一维数据

it2025-08-06  6

问题描述:

上一层得到的tensor是一个二维的【Tensor(“dense_3/BiasAdd:0”, shape=(?, 2), dtype=float32)】,我想对tensor中的不同列做不同的激活函数操作,所以需要单独的把我需要的那部分取出来。

错误做法:

inputs = Input((128, 128,1)) fc = Dense(2)(inputs) a = fc[:,0] s = fc[:,1] a = Activation('relu')(a) s = Activation('sigmoid')(s) a = UpSampling2D((128,128))(Reshape([1,1,1])(a)) s = UpSampling2D((128,128))(Reshape([1,1,1])(s)) outputs = Lambda(lambda x: tf.where(tf.less_equal(x[0], x[1]), x[0]*x[2], x[0]))([inputs, s, a]) model = Model(inputs = inputs, outputs = outputs)

在运行过程中是不存在语法问题的,且把a和s打印出来也可以看到的确是正确的tensor维度,但是到了构建model的时候,会报出以下错误:

AttributeError: ‘NoneType’ object has no attribute ‘_inbound_nodes’

非常眼熟的问题,之前写的那篇keras.layer中反复提到的报错问题——构建model的过程中出现了不属于keras.layer的函数。一步步往前排查,发现就是直接对fc取值时出了错,不能直接取。

解决方法:

用Lambda封装为layer。我最开始还用了tf.slice,其实可以直接把取值操作进行封装。

\\直接封装取值操作【类似list的做法】 a = Lambda(lambda x: x[:,0])(fc) s = Lambda(lambda x: x[:,1])(fc) \\用tf.slice,也需要封装 a = Lambda(lambda x: tf.slice(x,[0,0],[128,1]))(fc) s = Lambda(lambda x: tf.slice(x,[0,1],[128,1]))(fc)

ps:需要特别注意的是,list做法会导致降维,所以后续可能需要reshape操作等。而tf.slice的输出形状是和输入形状一致,shape不发生变化。

附录:

(1)tf.slice:把tensor切片

def slice(input_, begin, size, name=None):

input_:需要切片的tensor begin:每一个维度的起始位置 size:每个维度拿几个元素出来

例子:

t = tf.constant([[[1, 1, 1], [2, 2, 2]], [[3, 3, 3], [4, 4, 4]], [[5, 5, 5], [6, 6, 6]]]) a = tf.slice(t, [1, 0, 0], [1, 1, 3]) //a = [[[3, 3, 3]]] t的shape为[3,2,3],第一个维度是t = [A, B, C]。A = [[1, 1, 1], [2, 2, 2]],B = [[3, 3, 3], [4, 4, 4]], C = [[5, 5, 5], [6, 6, 6]]。第二个维度是 A,B,C=[i, j],以A为例,i = [1, 1, 1],j = [2, 2, 2]。第三个维度就是i,j中对应得元素个数。begin参数对应[1,0,0]。意思是在第一个维度从index为1开始算,由于起始index为0,所以此处指的是B。以此类推,第二个维度从i开始算,第三个维度从内框中的第一个元素开始算。size参数对应[1,1,3]。意思是每个维度取几个元素。和begin综合来看就是,第一个维度,从B开始取,取一个,就是只取B;第二个维度从i开始算,也是只取一个,就是取i;第三个维度从起始开始算,取三个,就是把i中的元素取三个。

(2)tf.where

tf.where(condition, A, B)

condition:一个Tensor,数据类型为tf.bool类型

如果A、B均为空,那么返回condition中值为True的位置的Tensor

如果A、B不为空的话(形状必相同),返回值和A、B有相同的形状,如果condition对应位置值为True那么返回Tensor对应位置为A的值,否则为B的值

最新回复(0)