Forward-backward梯度求導(tensorflow word2vec實例)


  1. 考慮不可分的例子

   

   

  1. 通過使用basis functions 使得不可分的線性模型變成可分的非線性模型

  1. 最常用的就是寫出一個目標函數 並且使用梯度下降法 來計算

   

  1. 梯度的下降法的梯度計算

   

   

   

   

  1. 關於線性和非線性的隱層

非線性隱層使得網絡可以計算更加復雜的函數

線性隱層不能增強網絡的表述能力,它們被用來做降維,減少訓練需要的參數數目,這在nlp相關的模型中

經常用到(embedding vector)

   

  1. 一個back prop的例子

   

   

前向計算 Forward pass

后向計算 Backward pass

激活梯度

權重梯度

   

來看一下計算某些變量的梯度,需要計算哪些其它變量

  • 如果要計算從單元A到單元Bweight的梯度需要哪些信息?

    參考上面的

    需要 A的激活梯度 B的反向傳播的梯度

另外一些需要了解的

  • 許多梯度計算都是0 這是因為我們采用了線性矯正來作為非線性單元
  • 有一些梯度計算出來比其它的大很多,這回造成連乘后傳遞擴大,這是所謂的"梯度爆炸"

   

   

  1. forward-backward的實例(word2vec)

考慮tensorflow實現的word2vec,tensorflow是可以自動求導的,但是你也可以自己來寫這一部分

Word2vec_optimized.py就是自己實現的forward-backward步驟(手寫),采用true sgd

看一下代碼

# Training nodes.

inc = global_step.assign_add(1)

with tf.control_dependencies([inc]):

train = word2vec.neg_train(

w_in, #上圖中左面的w,將在negtrain中被改變

w_out, #上圖中右面的w,將在negtrain中被改變

examples, # 中心詞編號數組,長度為batch_size

labels, # 周圍詞 surronding word 編號數組

lr, #學習率 learning rate

vocab_count=opts.vocab_counts.tolist(), #每個詞的頻次數組

num_negative_samples=opts.num_samples #負樣本采樣數目

)

   

   

REGISTER_OP("NegTrain")

.Input("w_in: Ref(float)") //Ref傳遞引用

.Input("w_out: Ref(float)")

.Input("examples: int32")

.Input("labels: int32")

.Input("lr: float")

.Attr("vocab_count: list(int)")

.Attr("num_negative_samples: int")

.Doc(R"doc(

Training via negative sampling.

   

w_in: input word embedding.

w_out: output word embedding.

examples: A vector of word ids.

labels: A vector of word ids.

vocab_count: Count of words in the vocabulary.

num_negative_samples: Number of negative samples per exaple.

)doc");

   

// Gradient accumulator for v_in.

Tensor buf(DT_FLOAT, TensorShape({dims}));

auto Tbuf = buf.flat<float>();

   

// Scalar buffer to hold sigmoid(+/- dot).

Tensor g_buf(DT_FLOAT, TensorShape({}));

auto g = g_buf.scalar<float>();

   

// The following loop needs 2 random 32-bit values per negative

// sample. We reserve 8 values per sample just in case the

// underlying implementation changes.

auto rnd = base_.ReserveSamples32(batch_size * num_samples_ * 8);

random::SimplePhilox srnd(&rnd);

   

for (int64 i = 0; i < batch_size; ++i) {

const int32 example = Texamples(i);

DCHECK(0 <= example && example < vocab_size) << example;

const int32 label = Tlabels(i);

DCHECK(0 <= label && label < vocab_size) << label;

auto v_in = Tw_in.chip<0>(example);

   

//正樣本label 1 負樣本label -1,累積誤差 這里應該是按照MLE 最大化可能概率 所以是累加梯度,參考ng課件

nce的做法,轉化為二分類問題

   

// Positive: example predicts label.

// forward: x = v_in' * v_out

// l = log(sigmoid(x))

// backward: dl/dx = g = sigmoid(-x)

// dl/d(v_in) = (dl/dx)*(dx/d(v_in)) = g * v_out'

// dl/d(v_out) = (dl/dx)*(dx/d(v_out)) = v_in' * g

{

auto v_out = Tw_out.chip<0>(label);

auto dot = (v_in * v_out).sum();

g = (dot.exp() + 1.f).inverse();

Tbuf = v_out * (g() * lr);

v_out += v_in * (g() * lr);

}

   

// Negative samples:

// forward: x = v_in' * v_sample

// l = log(sigmoid(-x))

// backward: dl/dx = g = -sigmoid(x)

// dl/d(v_in) = g * v_out'

// dl/d(v_out) = v_in' * g

for (int j = 0; j < num_samples_; ++j) {

const int sample = sampler_->Sample(&srnd);

if (sample == label) continue; // Skip.

auto v_sample = Tw_out.chip<0>(sample);

auto dot = (v_in * v_sample).sum();

g = -((-dot).exp() + 1.f).inverse();

Tbuf += v_sample * (g() * lr);

v_sample += v_in * (g() * lr);

}

   

// Applies the gradient on v_in.

v_in += Tbuf;

}

   

   


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM