TensorFlow常用函数(四)

上一篇:TensorFlow常用函数(三)

1、tf.logging.set_verbosity():设置显示哪些级别的日志信息

 2、tf.nn.max_pool_with_argmax():带索引的最大池化,最大池化同时返回索引值

3、tf.scatter_nd():根据索引(indices)将给定的张量(updates)散布到新的(初始为零)形状为shape的张量

4、Unpool():反最大池化函数的封装,根据最大池化后的结果和最大池化索引值反最大池化

5、tf.nn.embedding_lookup():选取一个张量里面索引对应的元素

6、tf.nn.nce_loss():计算训练词向量过程中的NCE


1、tf.logging.set_verbosity():设置显示哪些级别的日志信息

    TensorFlow使用五个不同级别的日志消息。 按照上升的顺序,它们是DEBUG,INFO,WARN,ERRORFATAL。 当你在任何这些级别配置日志记录时,TensorFlow将输出与该级别相对应的所有日志消息以及所有级别的严重级别。 例如,如果设置了ERROR的日志记录级别,则会收到包含ERROR和FATAL消息的日志输出,如果设置了一个DEBUG级别,则会从所有五个级别获取日志消息。默认情况下,TENSFlow在WARN的日志记录级别进行配置,但是在跟踪模型训练时,您需要将级别调整为INFO,这将提供适合操作正在进行的其他反馈。

if __name__=='__main__':
    tf.logging.set_verbosity(tf.logging.INFO)
    tf.app.run()

 2、tf.nn.max_pool_with_argmax():带索引的最大池化,最大池化同时返回索引值

函数原型:
tf.nn.max_pool_with_argmax(
    input,
    ksize,
    strides,
    padding,
    Targmax=tf.int64,
    name=None
)
参数:
  input: 一个4-D的Tensor. 它的类型必须为: float32, float64, int32, uint8, int16, int8, int64, bfloat16, uint16, half, uint32, uint64.形状为[batch,height, width, channels]. 
  ksize: 池化核,length >= 4. 
  strides: 池化的步长length >= 4. 
  padding: 填充方式,为 "SAME", "VALID".
  Targmax: 可选的tf.DType 值类型为: tf.int32, tf.int64. Defaults to tf.int64.
  name: 操作名(可选).
返回值:
  Tensor对象元组(output, argmax).
  output: 一个Tensor.与输入有相同的类型.
  argmax: 一个Tensor与Targmax有相同的类型.

  实例如下: 

inputs = tf.constant([4,5,2,3,0,1,6,7,12,13,10,11,8,9,14,15],dtype = tf.float32,shape = [1,4,4,1])
net, indices = tf.nn.max_pool_with_argmax(inputs,ksize=[1,2,2,1],strides=[1,2,2,1],padding='SAME')
with tf.Session() as sess:
	print(inputs.eval())
	print (net.eval())
	print(indices.eval())

输出:
[[[[ 4.] [ 5.] [ 2.] [ 3.]]
  [[ 0.] [ 1.] [ 6.] [ 7.]]
  [[12.] [13.] [10.] [11.]]
  [[ 8.] [ 9.] [14.] [15.]]]]

[[[[ 5.] [ 7.]]
  [[13.] [15.]]]]

[[[[ 1] [ 7]]
  [[ 9] [15]]]]

3、tf.scatter_nd():根据索引(indices)将给定的张量(updates)散布到新的(初始为零)形状为shape的张量

函数原型:
tf.scatter_nd(
    indices,
    updates,
    shape,
    name=None
)
函数参数:
  indices:一个Tensor;必须是以下类型之一:int32,int64;指数张量。
  updates:一个Tensor;分散到输出的更新。
  shape:一个Tensor;必须与indices具有相同的类型;1-d;得到的张量的形状。
  name:操作的名称(可选)。
函数返回值:
  此函数将返回一个Tensor,它与updates有相同的类型;根据indices应用的一个新具有给定的形状和更新的张量。

indices是一个整数张量,其中含有索引形成一个新的形状shape张量。indices的最后的维度可以是shape的最多的秩:

indices.shape[-1] <= shape.rank

例如:

       

indices = tf.constant([[4], [3], [1], [7]])
updates = tf.constant([9, 10, 11, 12])
shape = tf.constant([8])
scatter = tf.scatter_nd(indices, updates, shape)
with tf.Session() as sess:
  print(sess.run(scatter))

结果:
[0, 11, 0, 10, 9, 0, 0, 12]

4、Unpool():反最大池化函数的封装,根据最大池化后的结果和最大池化索引值反最大池化

def unpool(updates, mask, k_size=[1, 2, 2, 1], output_shape=None, scope=''):
    '''Unpooling function based on the implementation by Panaetius at 
       https://github.com/tensorflow/tensorflow/issues/2169      
 https://github.com/yselivonchyk/Tensorflow_WhatWhereAutoencoder/blob/master/WhatWhereAutoencoder.py

    Args:
    - inputs: 池化后的结果,形状为 [batch_size, height, width, num_channels] 
    - mask: 最大池化索引,由tf.nn.max_pool_with_argmax()产生,它和inputs具有相同的形状。
    - k_size: 反池化核的维度。
    - output_shape:反池化后的输出形状
    - scope : 操作名

    Returns:
    - 一个4D张量,与output_shape有相同的形状

    '''
    with tf.variable_scope(scope):
        mask = tf.cast(mask, tf.int32)
        input_shape = tf.shape(updates, out_type=tf.int32)
        
        #  计算输出的形状
        if output_shape is None:
            output_shape = (input_shape[0], input_shape[1] * ksize[1], input_shape[2] * ksize[2], input_shape[3])

        # 接下来为batch, height, width、channel计算各自的索引
        one_like_mask = tf.ones_like(mask, dtype=tf.int32)
        
        # batch的索引使用默认值,因为反池化不改变batch
        batch_shape = tf.concat([[input_shape[0]], [1], [1], [1]], 0)
        batch_range = tf.reshape(tf.range(output_shape[0], dtype=tf.int32), shape=batch_shape)        
        b = one_like_mask * batch_range 
        
        # 根据最大池化索引值计算输出张量中height的索引 
        y = mask // (output_shape[2] * output_shape[3])
        
        # 根据最大池化索引值计算输出张量中width的索引
        x = (mask // output_shape[3]) % output_shape[2] 

        # channel的索引也使用默认值,因为反池化不改变channel
        feature_range = tf.range(output_shape[3], dtype=tf.int32)   
        f = one_like_mask * feature_range #

        # 把batch、height、width、channel的索引串联到一起,并改变其形状再进行转置,
        # 使得每个元素有4个坐标值,之后用scatter_nd()函数根据索引值将输入分发到输出的张量中, 
        # 每个元素根据4个坐标值在输出张量中找到其对应的位置,从而完成反池化过程
        updates_size = tf.size(updates)
        indices = tf.transpose(tf.reshape(tf.stack([b, y, x, f]), [4, updates_size]))
        values = tf.reshape(updates, [updates_size])
        ret = tf.scatter_nd(indices, values, output_shape)
        return ret

5、tf.nn.embedding_lookup():选取一个张量里面索引对应的元素

函数原型:
  tf.nn.embedding_lookup(params, ids, partition_strategy='mod', name=None, validate_indices=True, max_norm=None)

参数:
  params: 一个表示完整的词嵌入的tensor.
  ids: 一个类型为int32或者int64的tensor,用于在params中查询.
  partition_strategy: 指定分割方法的字符串,默认为'mod', 如果len(params) > 1,支持"div"和"mod" 两种方法。
  name: 操作名(可选).
  validate_indices: DEPRECATED. 
  max_norm: 如果不为None,每个词向量将被裁剪,如果它的二范数大于这个值。
  

实例:  

a = [[0.1, 0.2, 0.3], 
	 [1.1, 1.2, 1.3], 
	 [2.1, 2.2, 2.3], 
	 [3.1, 3.2, 3.3], 
	 [4.1, 4.2, 4.3]]
a = np.asarray(a)
idx1 = tf.Variable([0, 2, 3, 1], tf.int32)
idx2 = tf.Variable([[0, 2, 3, 1], [4, 0, 2, 2]], tf.int32)

out1 = tf.nn.embedding_lookup(a, idx1)
out2 = tf.nn.embedding_lookup(a, idx2)

init = tf.global_variables_initializer()

with tf.Session() as sess:
    sess.run(init)    
    print ('a')
    print (a)
    print ('out1')
    print (sess.run(out1))
    print ('out2')
    print (sess.run(out2))

输出:
a
[[0.1 0.2 0.3]
 [1.1 1.2 1.3]
 [2.1 2.2 2.3]
 [3.1 3.2 3.3]
 [4.1 4.2 4.3]]
out1
[[0.1 0.2 0.3]
 [2.1 2.2 2.3]
 [3.1 3.2 3.3]
 [1.1 1.2 1.3]]
out2
[[[0.1 0.2 0.3]
  [2.1 2.2 2.3]
  [3.1 3.2 3.3]
  [1.1 1.2 1.3]]
 [[4.1 4.2 4.3]
  [0.1 0.2 0.3]
  [2.1 2.2 2.3]
  [2.1 2.2 2.3]]]

6、tf.nn.nce_loss():计算训练词向量过程中的NCE

(1)为什么要使用NCE作为损失而不使用softmax呢?

    使用“标准”神经网络学习词向量存在一些问题。 这种方式下,当网络在学习在给定网络的输入的情况下预测下一个单词时,词向量同时被学习到。预测下一个单词就像预测一个类别一样。 也就是说,这样的网络只是一个“标准”的多分类器。 并且该网络必须具有与类别相同数量的输出神经元。 当类别是实际的单词时,神经元的数量是巨大的。“标准”神经网络通常使用交叉熵进行训练,该函数要求输出神经元的值表示概率 - 这意味着网络为每个类别计算的输出“得分”必须归一化,转换为 每个类别的实际概率。 该归一化步骤通过softmax函数实现。 当应用于巨大的输出层时,Softmax非常昂贵。

                                             

  其中为输入的词向量,为softmax的权重矩阵,为权重矩阵的一行。

  为了解决这个问题,即对softmax进行昂贵的计算,Word2Vec使用了一种称为噪声对比估计的技术。基本思想是转换多分类问题到二分类问题。也就是说,不使用softmax来估计输出单词的真实概率分布,而是使用逻辑回归(二元分类)来代替。对于每个训练样本,一个真正的对(一个中心词和出现在其上下文中的另一个词)和一些随机损坏的对(由中心词和随机选择的词组成) 词汇被输入到增强后分类器中,通过学习区分真实对与损坏对,分类器最终将学习到词向量。这很重要:增强的分类器不是预测下一个单词(“标准”训练技术),而是简单地预测一对单词是好还是坏。之前的问题是计算某个类的归一化概率是多少,二分类的问题是input和label正确匹配的概率是多少。

                        

其中k为负样本的个数,而Sigmoid函数为:

                                            

(2)NCE的TensorFlow实现

函数原型:
nce_loss(weights, 
           biases, 
           inputs, 
           labels, 
           num_sampled, 
           num_classes,
           num_true=1,
           sampled_values=None,
           remove_accidental_hits=False,
           partition_strategy="mod",
           name="nce_loss"):
  '''
  if mode == "train":
    loss = tf.nn.nce_loss(
        weights=weights,
        biases=biases,
        labels=labels,
        inputs=inputs,
        ...,
        partition_strategy="div")
  elif mode == "eval":
    logits = tf.matmul(inputs, tf.transpose(weights))
    logits = tf.nn.bias_add(logits, biases)
    labels_one_hot = tf.one_hot(labels, n_classes)
    loss = tf.nn.sigmoid_cross_entropy_with_logits(
        labels=labels_one_hot,
        logits=logits)
    loss = tf.reduce_sum(loss, axis=1)
  
Args:
    weight.shape = (N, K),这里输入数据是K维的,一共有N个类
    bias.shape = (N)
    inputs.shape = (batch_size, K)
    labels.shape = (batch_size, num_true)
    num_sampled: 采样出多少个负样本。
    num_classes: 总共有多少个类别,这里为词汇表单词个数 
    num_true :   实际的正样本个数。
    sampled_values: 采样出的负样本,如果是None,就会用不同的sampler去采样。  
    remove_accidental_hits: 如果采样时不小心采样到的负样本刚好是正样本,要不要干掉。
    partition_strategy:对weights进行embedding_lookup时并行查表时的策略。
  
 Returns:
    A `batch_size` 1-D tensor of per-example NCE losses.
  '''

  logits, labels = _compute_sampled_logits(
      weights=weights, biases=biases, labels=labels, inputs=inputs,
      num_sampled=num_sampled, num_classes=num_classes, num_true=num_true,
      sampled_values=sampled_values, subtract_log_q=True,
      remove_accidental_hits=remove_accidental_hits,
      partition_strategy=partition_strategy, name=name)

  sampled_losses = sigmoid_cross_entropy_with_logits(
      labels=labels, logits=logits, name="sampled_losses")

  return _sum_rows(sampled_losses)

nce_loss的实现逻辑如下:

  1) _compute_sampled_logits()负责采样,通过这个函数计算出正样本和采样出的负样本对应的output和label;

def _compute_sampled_logits(weights,
                            biases,
                            labels,
                            inputs,
                            num_sampled,
                            num_classes,
                            num_true=1,
                            sampled_values=None,
                            subtract_log_q=True,
                            remove_accidental_hits=False,
                            partition_strategy="mod",
                            name=None,
                            seed=None):
  """    
  Args:
    weight.shape = (N, K),这里输入数据是K维的,一共有N个类
    bias.shape = (N)
    labels.shape = (batch_size, num_true)
    inputs.shape = (batch_size, K)
    num_sampled: 采样出多少个负样本。
    num_classes: 总共有多少个类别,这里为词汇表单词个数 
    num_true :   实际的正样本个数。
    sampled_values: 采样出的负样本,如果是None,就会用不同的sampler去采样。
    remove_accidental_hits: 如果采样时不小心采样到的负样本刚好是正样本,要不要干掉。
    partition_strategy:对weights进行embedding_lookup时并行查表时的策略。
    name: 操作名(可选).
    seed: 随机采样的种子,默认为None
  
  Returns:
    out_logits: 一个tensor对象,其形状为[batch_size, num_true + num_sampled], 用于传递给
               nn.sigmoid_cross_entropy_with_logits (NCE) 或者
               nn.softmax_cross_entropy_with_logits_v2(sampled softmax).
    out_labels: 一个Tensor 对象,和out_logits有相同的形状。 
  """

  _compute_sampled_logits()完成的是一个什么过程呢。就是对于每一个样本,计算出一个维度为[batch_size, num_true + num_sampled]的向量,向量的每个元素都同之前logits的每个元素的意义一样,是输出值。同时,返回一个维度为[batch_size, num_true + num_sampled]的向量labels。这个labels中只有一个元素为1。 其实,此时的out_logits中对应(label位置为0)的元素就是,对应label位置为1)的元素就是。然后再传给sigmoid_cross_entropy_with_logitt().

  2)sigmoid_cross_entropy_with_logits()负责做逻辑回归(logistic regression),然后计算交叉熵损失(cross entropy loss),通过 sigmoid cross entropy来计算output和label的loss,从而进行反向传播。这个函数把最后的问题转化为了num_sampled+num_real个两类分类问题,然后每个分类问题用了交叉熵的损失函数,也就是logistic regression常用的损失函数;

  3)最后用_sum_rows()求和。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值