tf.nn.softmax_cross_entropy_with_logits 和 tf.contrib.legacy_seq2seq.sequence_loss_by_example 的联系与区别
文章目錄
- 0.函數(shù)介紹
- 1.區(qū)別聯(lián)系
- 1.1 tf.nn.softmax_cross_entropy_with_logits
- 1.2 tf.nn.sparse_softmax_cross_entropy_with_logits
- 1.3 tf.contrib.legacy_seq2seq.sequence_loss_by_example
- 2.代碼呈現(xiàn)
- 3.References
Author: Cao Shengming
Email: caoshengming@trio.ai ? checkmate.ming@gmail.com
Company: Trio 北京(三角獸)科技有限公司
0.函數(shù)介紹
這兩個(gè)函數(shù)是在 model 中非常常用的兩個(gè)損失函數(shù),不管是序列標(biāo)注還是語言模型中都會(huì)見到他們兩個(gè)的身影,總的來說tf.nn.softmax_cross_entropy_with_logits 是 tf.contrib.legacy_seq2seq.sequence_loss_by_example 的特殊情況,而且在代碼處理中也有一定的技巧。
(注:查東西的時(shí)候先看 api 和源碼再去翻各種亂七八糟的博客,效率會(huì)更高。)
1.區(qū)別聯(lián)系
1.1 tf.nn.softmax_cross_entropy_with_logits
**函數(shù)實(shí)現(xiàn):**傳統(tǒng)實(shí)現(xiàn)不贅述
函數(shù)輸入:
logits: [batch_size, num_classes]
labels: [batch_size, num_classes]
logits和 labels 擁有相同的shape
代碼示例:
import tensorflow as tf import numpy as np y = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1], [1, 0, 0], [0, 1, 0]]) # onestep vector logits = np.array([[12, 3, 2], [3, 10, 1], [1, 2, 5], [4, 6.5, 1.2], [3, 6, 1]]) y_ = tf.nn.softmax(logits) e1 = -np.sum(y * np.log(y_), -1) # reduce_sum 所有樣本 loss 求和sess = tf.Session() y = np.array(y).astype(np.float64) e2 = sess.run(tf.nn.softmax_cross_entropy_with_logits(labels=y, logits=logits)) # labels 和 logtis shape 相同print("公式計(jì)算的結(jié)果:\n", e1) print("tf api 計(jì)算的結(jié)果:\n", e2)1.2 tf.nn.sparse_softmax_cross_entropy_with_logits
主要區(qū)別:與上邊函數(shù)不同,輸入 labels 不是 one-hot 格式所以會(huì)少一維
函數(shù)輸入:
logits: [batch_size, num_classes]
labels: [batch_size]
logits和 labels 擁有相同的shape
代碼示例:
import tensorflow as tf labels = [0,1,2] #只需給類的編號(hào),從 0 開始logits = [[2,0.5,1],[0.1,1,3],[3.1,4,2]]logits_scaled = tf.nn.softmax(logits) result = tf.nn.sparse_softmax_cross_entropy_with_logits(labels=labels, logits=logits)with tf.Session() as sess:print(sess.run(result))1.3 tf.contrib.legacy_seq2seq.sequence_loss_by_example
函數(shù)實(shí)現(xiàn):
def sequence_loss_by_example(logits, targets, weights,average_across_timesteps=True,softmax_loss_function=None, name=None): #logits: List of 2D Tensors of shape [batch_size x num_decoder_symbols]. #targets: List of 1D batch-sized int32 Tensors of the same length as logits. #weights: List of 1D batch-sized float-Tensors of the same length as logits. #return:log_pers 形狀是 [batch_size].for logit, target, weight in zip(logits, targets, weights):if softmax_loss_function is None:# TODO(irving,ebrevdo): This reshape is needed because# sequence_loss_by_example is called with scalars sometimes, which# violates our general scalar strictness policy.target = array_ops.reshape(target, [-1])crossent = nn_ops.sparse_softmax_cross_entropy_with_logits(logit, target)else:crossent = softmax_loss_function(logit, target)log_perp_list.append(crossent * weight)log_perps = math_ops.add_n(log_perp_list)if average_across_timesteps:total_size = math_ops.add_n(weights) total_size += 1e-12 # Just to avoid division by 0 for all-0 weights.log_perps /= total_size函數(shù)說明: 可以發(fā)現(xiàn)通過 zip 操作對(duì) list 的每個(gè)元素執(zhí)行一次 sparse 操作,其他的都與 sparse 是相同的,所以使用這個(gè)函數(shù)的關(guān)鍵在于如何進(jìn)行輸入的 list 的構(gòu)造。最容易想到的是安 sequence_length進(jìn)行 unstack,但是這樣會(huì)給輸入的構(gòu)造帶來很多額外的工作量。具體代碼使用時(shí)是由一定技巧的,請(qǐng)參見下一部分代碼呈現(xiàn)。
2.代碼呈現(xiàn)
此處我們將展示在訓(xùn)練 char-level語言模型的時(shí)候,兩種損失函數(shù)的處理,就可以搞清這兩個(gè)函數(shù)到底是怎么使用的。
case1:使用 softmax…的情況
def build_loss(self):with tf.name_scope('loss'):y_one_hot = tf.one_hot(self.targets, self.num_classes)y_reshaped = tf.reshape(y_one_hot, self.logits.get_shape())loss =tf.nn.softmax_cross_entropy_with_logits(logits=self.logits, labels=y_reshaped)self.loss = tf.reduce_mean(loss)case1:使用 sequece…的情況
with tf.name_scope('loss'):output = tf.reshape(outputs, [-1, args.state_size])self.logits = tf.matmul(output, w) + bself.probs = tf.nn.softmax(self.logits)self.last_state = last_statetargets = tf.reshape(self.target_data, [-1])loss = seq2seq.sequence_loss_by_example([self.logits],[targets],[tf.ones_like(targets, dtype=tf.float32)])self.cost = tf.reduce_sum(loss) / args.batch_sizetf.summary.scalar('loss', self.cost)上述代碼總結(jié):
我們可以清晰地看到兩者接受的原始的輸入竟然都是一樣的,所以這兩者在處理時(shí)都用到了一定的技巧,前者的技巧是是將 [B*T] 作為 [B] ,后者的技巧是在外邊包一層 “[ ]” 留給函數(shù)內(nèi)部的 zip 來使用,當(dāng)然同樣是將 [B*T] 作為 [B] ,這些操作都要考慮清楚,才能搞清楚函數(shù)的差異到底在哪。
另外需要注意的一點(diǎn)是 sequence 函數(shù)中的 weight 參數(shù),可以替代手工的 loss mask 對(duì)不需要的 padding 位置不進(jìn)行 loss 的計(jì)算。
3.References
- cross_entropy 代碼
- sequence_loss 代碼
- tensorflow中sequence_loss_by_example()函數(shù)的計(jì)算過程(結(jié)合TF的ptb構(gòu)建語言模型例子)
- 新老損失函數(shù) api 介紹
總結(jié)
以上是生活随笔為你收集整理的tf.nn.softmax_cross_entropy_with_logits 和 tf.contrib.legacy_seq2seq.sequence_loss_by_example 的联系与区别的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Paper Reading: Paper
- 下一篇: Unix shell 编程相关命令