Ml

負のサンプリングと損失



Negative Sampling Nce Loss



1.ノイズコントラスト推定(NCE)

言語モデルでは、最後の層で次のことが必要になることがよくあります。コンテキストcに従って、コーパスV全体で単語wの確率を予測します。通常はソフトマックスの形式です。

画像


分配関数Z(c)の目的は、pが確率分布になるように正規化することです。一般に、上記のパラメータは最尤法に従って推定されますが、V内のすべての単語をトラバースする必要があるため、この式の計算量は膨大です。

現在、NCEが舞台に立っています。膨大な量の計算を回避するために、NCEのアイデアは ソフトマックスのパラメータ推定問題は2つの分類に変換されます。 2種類のサンプルは、実際のサンプルとノイズサンプルです。正のサンプルは経験的に分布しています。



画像
生成された(つまり、真の分布)ラベルD = 0であり、負のサンプルは、ラベルD = 1に対応するq(w)によって生成されたノイズです。 cがコンテキストを表すと仮定すると、k個のノイズサンプルがノイズ分布から抽出され、wはサンプル全体(実際のサンプル+ノイズサンプル)で予測されるターゲット単語を表します。
この場合、(d、w)の同時確率分布は次のようになります。

画像
上記の式から取得することは難しくありません:サンプル全体でP(w / c)= p(d = 0、w / c)+ p(d = 1、w / c)

ヒント:Pは、正と負のサンプルの全体的な分布を指します。これは、前の正のサンプルの経験的分布と同じです。 画像異なる

条件付き同時確率式に従って続行すると、次のようになります。p(d = 0 / w、c)= p(d = 0、w / c)/ p(w / c)

p(d = 1 / w、c)類似

次の式は次のとおりです。



画像
実際、この式は条件付き確率に基づいて直接理解されます。

NCE利用モデルの分布 画像
経験の分配の代わりに 画像この時点で、冒頭で述べたソフトマックスに接続され、尤度を最大化することで最適なパラメータシータが得られます。しかし、問題はまだここでは解決されていません。 画像最初の式と同様に、分配関数Z©を計算するには、すべてのVをトラバースする必要があります。

    NCEは次に、2つの仮説を提案しました。
  1. 分配関数Z(c)は、Vをトラバースすることによって取得する必要はありませんが、パラメーターZcによって推定されます。
  2. ニューラルネットワークには多くのパラメータがあるため、Zcは固定値Zc = 1に設定できます。この設定は、すべてのcに有効です([Mnih and Teh2012])

上記の仮定に基づいて、式はさらに次のように書くことができます。




その後、対数尤度の最大化に従ってパラメーターがトレーニングされます。ここで、k個の負のサンプルが選択され、損失関数は次のようになります。


第2項は、kを含むため、まだ計算が困難です。 期待値(E)、 したがって、ここではモンテカルロ近似を使用してモンテカルロ近似を推定し、kの代わりにk個のサンプルを取得します。 期待する:

2.ネガティブサンプリング

負のサンプリングはNCEの変形であり、確率の定義は異なります。


NCEの確率式の場合:k = | V |の場合qが一様分布している場合、k * q = 1であり、2つの確率式は同じです。

ただし、上記に加えて、2つの確率式は異なります。ネガティブサンプリングが単語ベクトルでうまく機能する場合でも、ネガティブサンプリングはNCEの特性(漸近的一貫性の保証など)を持つことができません。

3、テンソルフローの損失

1つは、損失の計算です。

ネガティブサンプリングによってk個のネガティブサンプルが取得された後、各サンプルについて、ポジティブサンプルラベル= 1またはネガティブサンプルラベル= 0のいずれかです。上記の最後のNCE損失の最大ログを最小化ログに変更すると、NCEの損失関数は2クラスのロジスティクス損失(クロスエントロピー)として表すことができます。

    tensorflowでシンボルを使用します:
  1. x =ロジットは、上記のu(w、c)を意味します。これは、最後の層(単語wに対応)のネットワークパラメーターとcの単語ベクトルの積です。
  2. z =正のサンプル= 1、負のサンプル= 0のラベル
  3. 上記のロジットとラベルは、すべてのサンプル(正のサンプルとサンプリングされた負のサンプルを含む)を表すベクトルと行列です。

    次に、損失関数は次のように表すことができます。
    L = z * -log(sigmoid(x))+(1-z)* -log(1-sigmoid(x))
expの計算によって引き起こされるオーバーフローを回避するために、テンソルフローで単純な変換が実行されます。
 z * -log(sigmoid(x)) + (1 - z) * -log(1 - sigmoid(x)) = z * -log(1 / (1 + exp(-x))) + (1 - z) * -log(exp(-x) / (1 + exp(-x))) = z * log(1 + exp(-x)) + (1 - z) * (-log(exp(-x)) + log(1 + exp(-x))) = z * log(1 + exp(-x)) + (1 - z) * (x + log(1 + exp(-x)) = (1 - z) * x + log(1 + exp(-x)) = x - x * z + log(1 + exp(-x)) When x<0: For x 0 and x<0, the following formula is obtained: Hence, to ensure stability and avoid overflow, the implementation uses this equivalent formulation max(x, 0) - x * z + log(1 + exp(-abs(x))) 

第二に、クロスエントロピーを計算するためのソースコード

ラベルとロジットに基づいて損失を計算するためのコード:https://github.com/tensorflow/tensorflow/blob/r1.13/tensorflow/python/ops/nn_impl.py def sigmoid_cross_entropy_with_logits( # pylint: disable=invalid-name _sentinel=None, labels=None, logits=None, name=None): '''Computes sigmoid cross entropy given `logits`. Args: _sentinel: Used to prevent positional parameters. Internal, do not use. labels: A `Tensor` of the same type and shape as `logits`. logits: A `Tensor` of type `float32` or `float64`. name: A name for the operation (optional). Returns: A `Tensor` of the same shape as `logits` with the componentwise logistic losses. nn_ops._ensure_xent_args('sigmoid_cross_entropy_with_logits', _sentinel, labels, logits) # pylint: enable=protected-access with ops.name_scope(name, 'logistic_loss', [logits, labels]) as name: logits = ops.convert_to_tensor(logits, name='logits') labels = ops.convert_to_tensor(labels, name='labels') try: labels.get_shape().merge_with(logits.get_shape()) except ValueError: raise ValueError('logits and labels must have the same shape (%s vs %s)' % (logits.get_shape(), labels.get_shape())) # The logistic loss formula from above is # x - x * z + log(1 + exp(-x)) # For x <0, a more numerically stable formula is # -x * z + log(1 + exp(x)) # Note that these two expressions can be combined into the following: # max(x, 0) - x * z + log(1 + exp(-abs(x))) # To allow computing gradients at zero, we define custom versions of max and # abs functions. zeros = array_ops.zeros_like(logits, dtype=logits.dtype) cond = (logits>= zeros) relu_logits = array_ops.where(cond, logits, zeros) neg_abs_logits = array_ops.where(cond, -logits, logits) return math_ops.add( relu_logits - logits * labels, math_ops.log1p(math_ops.exp(neg_abs_logits)), name=name)

3、ネガティブサンプリング、ロジットとラベルの計算

tf.nn.log_uniform_candidate_sampler(一般的なサンプリング方法)に従って最初のサンプルを取得し、num_sampledの負のサンプルを取得します。

言語学では、単語が出現頻度に従って並べ替えられた後、それらはジップの分布に従います(ただし、他のシナリオが同様に調査に適用できるかどうか)サンプリングには対数均一(ジップの)分布を使用するため、単語は高頻度から低頻度低ランク、つまり、埋め込みを作成する場合、単語の頻度に従って作成されます。
nn.log_uniform_candidate_samplerは、この式を使用して、P(class)=(log(class + 2)-log(class + 1))/ log(range_max + 1)、クラスの値をサンプリングします。であるため、頻度でソートされていない場合、このメソッドは使用できません。

    次のステップは、すべてのサンプルのロジットとラベルを計算することです。注意すべき点は次のとおりです。
  1. ロジット:最後の層の重み行列の重みのサンプルに対応するベクトル*入力
  2. ラベル:(1)サンプリングされた負のサンプルは0です(2)デフォルトでは、入力は正のサンプルとlabel = 1にのみ対応しますが、num_true> 0の場合、各正のサンプルのlabel = 1 / num_true
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): '''Helper function for nce_loss and sampled_softmax_loss functions. Computes sampled output training logits and labels suitable for implementing e.g. noise-contrastive estimation (see nce_loss) or sampled softmax (see sampled_softmax_loss). Note: In the case where num_true > 1, we assign to each target class the target probability 1 / num_true so that the target probabilities sum to 1 per-example. Args: weights: A `Tensor` of shape `[num_classes, dim]`, or a list of `Tensor` objects whose concatenation along dimension 0 has shape `[num_classes, dim]`. The (possibly-partitioned) class embeddings. biases: A `Tensor` of shape `[num_classes]`. The (possibly-partitioned) class biases. labels: A `Tensor` of type `int64` and shape `[batch_size, num_true]`. The target classes. Note that this format differs from the `labels` argument of `nn.softmax_cross_entropy_with_logits_v2`. inputs: A `Tensor` of shape `[batch_size, dim]`. The forward activations of the input network. num_sampled: An `int`. The number of classes to randomly sample per batch. num_classes: An `int`. The number of possible classes. num_true: An `int`. The number of target classes per training example. sampled_values: a tuple of (`sampled_candidates`, `true_expected_count`, `sampled_expected_count`) returned by a `*_candidate_sampler` function. (if None, we default to `log_uniform_candidate_sampler`) subtract_log_q: A `bool`. whether to subtract the log expected count of the labels in the sample to get the logits of the true labels. Default is True. Turn off for Negative Sampling. remove_accidental_hits: A `bool`. whether to remove 'accidental hits' where a sampled class equals one of the target classes. Default is False. partition_strategy: A string specifying the partitioning strategy, relevant if `len(weights) > 1`. Currently `'div'` and `'mod'` are supported. Default is `'mod'`. See `tf.nn.embedding_lookup` for more details. name: A name for the operation (optional). seed: random seed for candidate sampling. Default to None, which doesn't set the op-level random seed for candidate sampling. Returns: out_logits: `Tensor` object with shape `[batch_size, num_true + num_sampled]`, for passing to either `nn.sigmoid_cross_entropy_with_logits` (NCE) or `nn.softmax_cross_entropy_with_logits_v2` (sampled softmax). out_labels: A Tensor object with the same shape as `out_logits`. '''

4、NCELossソースコード

上記の2つの部分を組み合わせると、NCE損失を直接計算できます。最初にすべてのサンプルのロジットとラベルを計算し(3番目のステップ)、次にクロスエントロピー損失を計算します(2番目のステップ)。def nce_loss(weights, biases, labels, inputs, num_sampled, num_classes, num_true=1, sampled_values=None, remove_accidental_hits=False, partition_strategy='mod', name='nce_loss'): '''Computes and returns the noise-contrastive estimation training loss. See [Noise-contrastive estimation: A new estimation principle for unnormalized statistical models](http://www.jmlr.org/proceedings/papers/v9/gutmann10a/gutmann10a.pdf). Also see our [Candidate Sampling Algorithms Reference](https://www.tensorflow.org/extras/candidate_sampling.pdf) A common use case is to use this method for training, and calculate the full sigmoid loss for evaluation or inference. In this case, you must set `partition_strategy='div'` for the two losses to be consistent, as in the Note: In the case where `num_true` > 1, we assign to each target class the target probability 1 / `num_true` so that the target probabilities sum to 1 per-example. Note: It would be useful to allow a variable number of target classes per example. We hope to provide this functionality in a future release. For now, if you have a variable number of target classes, you can pad them out to a constant number by either repeating them or by padding with an otherwise unused class. Args: weights: A `Tensor` of shape `[num_classes, dim]`, or a list of `Tensor` objects whose concatenation along dimension 0 has shape [num_classes, dim]. The (possibly-partitioned) class embeddings. biases: A `Tensor` of shape `[num_classes]`. The class biases. labels: A `Tensor` of type `int64` and shape `[batch_size, num_true]`. The target classes. inputs: A `Tensor` of shape `[batch_size, dim]`. The forward activations of the input network. num_sampled: An `int`. The number of negative classes to randomly sample per batch. This single sample of negative classes is evaluated for each element in the batch. num_classes: An `int`. The number of possible classes. num_true: An `int`. The number of target classes per training example. sampled_values: a tuple of (`sampled_candidates`, `true_expected_count`, `sampled_expected_count`) returned by a `*_candidate_sampler` function. (if None, we default to `log_uniform_candidate_sampler`) remove_accidental_hits: A `bool`. Whether to remove 'accidental hits' where a sampled class equals one of the target classes. If set to `True`, this is a 'Sampled Logistic' loss instead of NCE, and we are learning to generate log-odds instead of log probabilities. See our [Candidate Sampling Algorithms Reference] (https://www.tensorflow.org/extras/candidate_sampling.pdf). Default is False. partition_strategy: A string specifying the partitioning strategy, relevant if `len(weights) > 1`. Currently `'div'` and `'mod'` are supported. Default is `'mod'`. See `tf.nn.embedding_lookup` for more details. name: A name for the operation (optional). 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') # sampled_losses is batch_size x {true_loss, sampled_losses...} # We sum out true and sampled losses. return _sum_rows(sampled_losses)

参照:

[Mnih and Teh2012] AndriyMnihとYeeWhyeTeh。 2012.ニューラル確率言語モデルをトレーニングするための高速でシンプルなアルゴリズム。 Proc。 ICML。

ノイズコントラスト推定とネガティブサンプリングに関する注記( https://arxiv.org/pdf/1410.8251.pdf)

https://knet.readthedocs.io/en/v0.7.3/deprecated/nce.html