Tensor,翻译过来就是张量。
TensorFlow支持两种类型的Tensor,一种是立即执行的(eager execution),一种是图执行的(graph execution)。图执行的Tensor一般只是一个空壳(placeholder),没有值(tensor_content),它只定义了维度(shape)和数据类型(dtype),当然还有部分定义好的方法,待未来填值计算。TensorFlow将那些待计算的tensor组织成有向图(graph),后面tensor的计算依赖它前面的tensor的计算结果,因此,只要位于图入口处的那些tensor填入了值,就可执行图计算,就能输出结果。
Keras是建立在Tensorflow,CNTK或Theano之上的是一个高级神经网络库。Keras中的Tensor对底层TensorFlow或Theano的张量进行了扩展,加入了如下两个属性:
_Keras_history: 保存最近作用于这个tensor上的Layer对象及有关元数据。
_keras_shape: 保存(batch_size, input_dim,)与输入数据有关的维度大小的元组
张量是深度学习框架中的一个非常核心的概念,模型(内部)的计算都是基于张量进行的。
例子:
from keras.layers import Input, Dense from keras.models import Model inputs = Input(shape=(784,)) x = Dense(64, activation='relu')(inputs) x = Dense(64, activation='relu')(x) predictions = Dense(10, activation='softmax')(x) model = Model(inputs=inputs, outputs=predictions) model.compile(optimizer='rmsprop', loss='categorical_crossentropy', metrics=['accuracy']) model.fit(data, labels)上述的inputs和predictions都是tensor。显然,这里的tensor是一个图执行的tensor,由model.fit填入数据,然后执行计算。
下面来看Input是如何定义的:
def Input(shape=None, batch_shape=None, name=None, dtype=None, sparse=False, tensor=None): ...... if shape is not None and not batch_shape: batch_shape = (None,) + tuple(shape) if not dtype: dtype = K.floatx() input_layer = InputLayer(batch_input_shape=batch_shape, name=name, dtype=dtype, sparse=sparse, input_tensor=tensor) outputs = input_layer._inbound_nodes[0].output_tensors return unpack_singleton(outputs)代码中引入了一个InputLayer的对象,它是整个网络的起始输入层,它实际做的只是对原始数据的原样输出。从这里可知这个Input实际上在内部定义了一个输入层,并把该输入层的输出作为自己的输出返回, 也即返回这里的input_tensor,如果它不是None;否则返回下面代码中的K.placeholder对象。
unpack_singleton(outputs):如果outputs只有一个元素,则返回outputs[0],否则返回outputs。
下面我们来看InputLayer的源码:
class InputLayer(Layer): @interfaces.legacy_input_support def __init__(self, input_shape=None, batch_size=None, batch_input_shape=None, dtype=None, input_tensor=None, sparse=False, name=None): ...... self.trainable = False self.built = True self.sparse = sparse self.supports_masking = True ...... self.batch_input_shape = batch_input_shape self.dtype = dtype if input_tensor is None: self.is_placeholder = True input_tensor = K.placeholder(shape=batch_input_shape, dtype=dtype, sparse=self.sparse, name=self.name) else: self.is_placeholder = False input_tensor._keras_shape = batch_input_shape input_tensor._uses_learning_phase = False input_tensor._keras_history = (self, 0, 0) Node(self, inbound_layers=[], node_indices=[], tensor_indices=[], input_tensors=[input_tensor], output_tensors=[input_tensor], input_masks=[None], output_masks=[None], input_shapes=[batch_input_shape], output_shapes=[batch_input_shape])其中省略了一些对函数参数处理的代码。 对于NN中的每一层,不外乎三个部分:输入、处理(data的正向传播和error的反向传播)和输出。 在InputLayer的这段init的代码中,首先是对输入input_tensor的处理,如果是None, 则产生一个placeholder作为input tensor。从这里可看到所谓的tensor的占位符的特性。
接下来是一个逻辑处理和理解上的一个关键部分:new一个输入节点(Node)对象。Node对象的作用是用来联结两个层,我们将另辟章节对它进行分析,在这里我们只粗略地讨论一下传给它的参数。
Node的参数有4个主要部分:
(1)layers,包括outbound_layer和inbound_layers,这里outbound_layer接受的是这个InputLayer对象本身(self),inbound_layers=[],因为InputLayer是第一个输入层,所以它的inbound_layers是空。
(2)tensors,包括输入张量和输出张量,它们都等于[input_tensor],即:input_tensors=[input_tensor],output_tensors=[input_tensor],所以说这一层其实什么也没干。
(3)shapes,很自然地,输入和输出的维度参数(包括batch_size)都是[batch_input_shape],即:input_shapes=[batch_input_shape], output_shapes=[batch_input_shape]
(4)indices,这是一个很难理解的东东,需要在后面展开来讨论。 这里且注意这样一个细节就是output tensor(这里是input_tensor)的_keras_history,它的值的形式是(layer, node_index, tensor_index)这样的3元组,这里赋的值是(self, 0, 0)。
没有评论:
发表评论