日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

员外带你读论文:SeqGAN论文分享

發(fā)布時間:2025/3/8 编程问答 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 员外带你读论文:SeqGAN论文分享 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

本次要分享和總結的論文為:,其論文鏈接SeqGAN,源自,參考的實現代碼鏈接代碼實現。

本篇論文結合了?和?的知識,整篇論文讀下來難度較大,在這里就淺薄的談下自己的見解。

好了,老規(guī)矩,帶著代碼分析論文。

動機

  • 我們知道?網絡在計算機視覺上得到了很好的應用,然而很可惜的是,其在自然語言處理上并不,最初的??僅僅定義在實數領域,?通過訓練出的生成器來產生合成數據,然后在合成數據上運行判別器,判別器的輸出梯度將會告訴你,如何通過略微改變合成數據而使其更加現實。一般來說只有在數據連續(xù)的情況下,你才可以略微改變合成的數據,而如果數據是離散的,則不能簡單的通過改變合成數據。例如,如果你輸出了一張圖片,其像素值是,那么接下來你可以將這個值改為。如果輸出了一個單詞“penguin”,那么接下來就不能將其改變?yōu)椤皃enguin + .001”,因為沒有“penguin +.001”這個單詞。因為所有的自然語言處理()的基礎都是離散值,如“單詞”、“字母”或者“音節(jié)”,??中應用??是非常困難的。

  • ?只能衡量一個完整的句子的好壞程度,對于部分生成的句子,很難預測其后面的部分,無法很好的對其打分。

  • 在傳統的?模型中,我們通常用?來訓練模型,但是這個訓練方式也存在一個嚴重的問題,也就是論文中所說的?,在模型訓練階段,我們用?作為?,但是在真正的預測階段時,我們只能從上一步產生的分布中以某種方式抽樣某一個?作為下一步的,也就是這個階段的?的分布可能是不一樣的。

論文的大體思路

這里寫圖片描述

我們先看左圖:現在有一批,生成器生成一批假數據,我們利用?的方式來?生成器,也就是讓生成器不斷擬合?的分布。這個過程經過幾個回合;然后把訓練好的生成器生成的數據作為,?作為?來?判別器。這樣就?出了生成器和判別器。

再看右圖:先了解下強化學習的四個重要概率:,?為現在已經生成的?,?是下一個即將生成的?,??為?的生成器,?為?的判別器所回傳的信息。

帶著代碼仔細分析各個部分

在實現代碼中,生成器是一個?神經網絡,判別器是一個?網絡,其?是由一個?生成的。

pretrain

由上面的分析可知,在?生成器時,只是利用?的方法來訓練,不需要考慮。

我們先看看代碼中是如何?生成器的:

for epoch in xrange(PRE_EPOCH_NUM):## gen_data_loader存儲真實數據。loss = pre_train_epoch(sess, generator, gen_data_loader)##該操作為利用MLE訓練生成器if epoch % 5 == 0:┆ generate_samples(sess, generator, BATCH_SIZE, generated_num, eval_file)## 利用生成器生成一批假數據┆ likelihood_data_loader.create_batches(eval_file)##將假數據存進likelihood_data_loader┆ test_loss = target_loss(sess, target_lstm, likelihood_data_loader)##測試下當前生成的假數據與target_lstm生成的真實數據的loss┆ print 'pre-train epoch ', epoch, 'test_loss ', test_loss┆ buffer = 'epoch:\t'+ str(epoch) + '\tnll:\t' + str(test_loss) + '\n'┆ log.write(buffer)

以上過程循環(huán)?個循環(huán),不斷的?生成器。

再來看看怎么?判別器的:

for _ in range(50):generate_samples(sess, generator, BATCH_SIZE, generated_num, negative_file)##上面的生成器生成一批負樣本dis_data_loader.load_train_data(positive_file, negative_file)for _ in range(3):┆ dis_data_loader.reset_pointer()┆ for it in xrange(dis_data_loader.num_batch):┆ ┆ x_batch, y_batch = dis_data_loader.next_batch()##獲取一個batch數據,二分類┆ ┆ feed = {┆ ┆ ┆ discriminator.input_x: x_batch,┆ ┆ ┆ discriminator.input_y: y_batch,┆ ┆ ┆ discriminator.dropout_keep_prob: dis_dropout_keep_prob┆ ┆ }## 判別器是一個二分類的CNN網絡,利用cross-entropy作為損失函數。┆ ┆ _ = sess.run(discriminator.train_op, feed)##訓練判別器

生成器的目標函數

由強化學習的相關知識,我們可知其目標就是,也就是生成器生成了一句完整的句子后,我們希望盡可能的使其所有?的?之和盡可能的大,也就是如何公式:

如何理解上式呢?其中?可理解為一個完整句子的?之和,?表示初始狀態(tài),?表示生成器的參數。后面的求和過程表示,每生成一個,我們都會計算其生成該?的概率與其對應的?值,那么兩者相乘即表示生成該?的期望?值。求和后即為該整句的期望?值。生成器的目標就是不斷的。至于?為啥表示成,因為?是由后面判別器?決定的。

reward 求法

由上面的?,如何求每一步的?呢?也就是求。論文中提到?只能對一個完整的句子進行打分,而不能對生成的不完整句子打分,因此引入強化學習的方式:

蒙特卡洛樹搜索方法:

在?的階段時,我們希望生成器生成的?在當前生成概率分布中對應的概率與該?的?乘積和越大越好(上面的意義),那么該?的?如何計算得到呢?要知道只有是一個完整的句子,其判別器才能對其進行打分。例如我們在生成第?步的時,后面的?是未知的,我們只能讓生成器繼續(xù)向后面生成,直到生成一個完整的句子。然后在喂給判別器打分,為了讓這個打分更有說服力,我們讓這個過程重復?次,然后取平均的,可以用如下圖示展示這個過程:

這里寫圖片描述

簡單來說,就是生成器每生成一個?都會有相應的一個,而這個?后面的?都是未知的,只能按照生成器來補全,形成一個完整的句子,這個過程進行?次,會生成?個不同的完整句子(因為生成器的隨機性,不可能出現相同的句子)。然后將這個句子放到判別器中得到?個不同的打分結果,對這?個打分結果取平均作為該?最終的,論文中講到當生成第?個?時:

上式左邊表示?出來的??個不同的完整句子。

綜上所述:

那么代碼中是如何實現這一步的呢?

def get_reward(self, sess, input_x, rollout_num, discriminator): """ input_x: 需要打分的序列 rollout_num: 即sample的次數,即上面的N discriminator: 判別器 """rewards = []for i in range(rollout_num):┆ # given_num between 1 to sequence_length - 1 for a part completed sentence會遍歷一整句中的每個token,給其打分┆ for given_num in range(1, self.sequence_length ):┆ ┆ feed = {self.x: input_x, self.given_num: given_num}##生成一批樣本,前give_num的token由input_x提供,give_num后的token由生成器補上。由此生成一批完整的句子。┆ ┆ samples = sess.run(self.gen_x, feed)┆ ┆ feed = {discriminator.input_x: samples, discriminator.dropout_keep_prob: 1.0}┆ ┆ ypred_for_auc = sess.run(discriminator.ypred_for_auc, feed)##喂給判別器,給每個句子打分,作為reward┆ ┆ ypred = np.array([item[1] for item in ypred_for_auc])┆ ┆ if i == 0:┆ ┆ ┆ rewards.append(ypred)┆ ┆ else:┆ ┆ ┆ rewards[given_num - 1] += ypred## 在rollout_num循環(huán)中,相同位置的reward相加。┆ # the last token reward┆ feed = {discriminator.input_x: input_x, discriminator.dropout_keep_prob: 1.0}##如果give_num已經是最后一個token了,則喂給判別器的樣本就全是input_x。┆ ypred_for_auc = sess.run(discriminator.ypred_for_auc, feed)##注意下:ypred_for_auc只是softmax_logits,二分類的,第一個數為該樣本為假樣本概率,第二個數為其為真樣本概率┆ ypred = np.array([item[1] for item in ypred_for_auc])##我們拿其真樣本概率作為reward┆ if i == 0:┆ ┆ rewards.append(ypred)┆ else:┆ ┆ # completed sentence reward┆ ┆ rewards[self.sequence_length - 1] += ypredrewards = np.transpose(np.array(rewards)) / (1.0 * rollout_num) # batch_size x seq_length##取平均值。return rewards

通過上面的分析,我們可知,每個?的?都是由判別器得到的。那么這個打分的過程是怎么做的呢?我們來看看判別器的實現代碼:

不行,代碼太多了,簡單解說:生成器就是一個?網絡,我們會將?(二分類的)??成一個四維的張量,然后通過各種的卷積,?操作得到一個結果,然后再經過一個線性操作最終得到只有二維的張量,再做一個?操作得到?作為?值等等,直接看下面精華代碼:

with tf.name_scope("output"):##num_classes為2,真樣本還是假樣本W = tf.Variable(tf.truncated_normal([num_filters_total, num_classes], stddev=0.1), name="W")b = tf.Variable(tf.constant(0.1, shape=[num_classes]), name="b")l2_loss += tf.nn.l2_loss(W)l2_loss += tf.nn.l2_loss(b)self.scores = tf.nn.xw_plus_b(self.h_drop, W, b, name="scores")self.ypred_for_auc = tf.nn.softmax(self.scores)##rewardself.predictions = tf.argmax(self.scores, 1, name="predictions")# CalculateMean cross-entropy loss with tf.name_scope("loss"):losses = tf.nn.softmax_cross_entropy_with_logits(logits=self.scores, labels=self.input_y)self.loss = tf.reduce_mean(losses) + l2_reg_lambda * l2_loss

***其實就是將該整句被判別器判別為真樣本的概率作為該??的?***,嗯,就是這么簡單。判別為真樣本的概率越大,則在當前步選擇該?越正向。

值得一提的是:這里?的方式并不唯一,論文中的對比實驗就用了?指標作為?來指導生成器的訓練。

好了,怎么求?已經搞清楚了。

接下來再看看判別器是如何訓練的?以及他的目標函數。

判別器的目標函數

簡短解說:判別器是一個?網絡,我們喂給判別器的樣本是一個二分類的樣本,即有生成器生成的一批假樣本,也有一批真樣本,然后直接做個二分類,損失函數就是一個?:

實現代碼上面已寫到。

policy Gradient

這一步有大量的數學公式需要推導。

我們由上面的分析,知道生成器的目標函數為:

我們再來看看上式是如何得到的:

可以這么理解:上式在?為生成器時,狀態(tài)為已經生成?到?的?情況下,當前第?步選擇?的?值。那么:

這樣,一個完整句子的期望?就可以表示成

那么如何?呢?利用?方法,需要對?求導。

具體求導過程就不贅述了,如有興趣請看論文。

最后求出的結果為:

這里寫圖片描述這里寫圖片描述

利用梯度上升法來更新生成器參數:

那么目標函數的優(yōu)化過程在代碼中如何實現呢?

self.g_loss = -tf.reduce_sum(## self.x 為生成器生成一個序列,我們需要找到這個序列中每個token在生成器分布中的概率,然后與對應的reward相乘。求和取負作為要優(yōu)化的losstf.reduce_sum(┆ tf.one_hot(tf.to_int32(tf.reshape(self.x, [-1])), self.num_emb, 1.0, 0.0) * tf.log(┆ ┆ tf.clip_by_value(tf.reshape(self.g_predictions, [-1, self.num_emb]), 1e-20, 1.0)┆ ), 1) * tf.reshape(self.rewards, [-1]) ) g_opt = self.g_optimizer(self.learning_rate)self.g_grad, _ = tf.clip_by_global_norm(tf.gradients(self.g_loss, self.g_params), self.grad_clip)##更新生成器參數 self.g_updates = g_opt.apply_gradients(zip(self.g_grad, self.g_params))

在?可以自動的反向求導,所以許多細節(jié)不需要在代碼中顯示。

整體算法流程

這里寫圖片描述

利用?方法?生成器、判別器,這部分上面已經講過。下面稍微詳細講下、。

G_step

  • 利用生成器生成一批假樣本。注意生成器每一步都是生成一個在?上的分布,我們以某種方式抽樣一個?作為本步生成的。

  • 在?作為目標函數時,我們需得到?中當前步的?在當前生成分布中的概率,在SeqGAN 中考慮的是當前步得到的??在生成分布中的概率以及該?的?,我們利用蒙特卡洛樹搜索法得到每個??的?。

  • 利用?更新生成器的參數。

  • 實現代碼:

    for total_batch in range(TOTAL_BATCH):# Train the generator for one stepfor it in range(1):┆ samples = generator.generate(sess)##生成器生成一批序列## 獲得序列中每個token 的reward┆ rewards = rollout.get_reward(sess, samples, 16, discriminator)## 將序列與其對應的reward 喂給生成器,以policy gradient更新生成器┆ feed = {generator.x: samples, generator.rewards: rewards}┆ _ = sess.run(generator.g_updates, feed_dict=feed)

    以上就是訓練生成器的過程, 在這個階段,判別器不發(fā)生改變只是對當前的生成情況做出反饋,也就是?。

    D_step

    利用上面已經訓完的生成器生成一批樣本作為假樣本,加上已有的一批真樣本,作為訓練數據,來訓練一個二分類的判別器。

    實現代碼:

    for _ in range(5):generate_samples(sess, generator, BATCH_SIZE, generated_num, negative_file)dis_data_loader.load_train_data(positive_file, negative_file)for _ in range(3):┆ dis_data_loader.reset_pointer()┆ for it in xrange(dis_data_loader.num_batch):┆ ┆ x_batch, y_batch = dis_data_loader.next_batch()┆ ┆ feed = { ┆ ┆ ┆ discriminator.input_x: x_batch,┆ ┆ ┆ discriminator.input_y: y_batch,┆ ┆ ┆ discriminator.dropout_keep_prob: dis_dropout_keep_prob┆ ┆ } ┆ ┆ _ = sess.run(discriminator.train_op, feed)

    個人總結與疑點

    • 如果用傳統的?網絡來做?的任務,那么生成器生成的序列需要喂給判別器,然后利用判別器來反向的糾正生成器,這個時候梯度的微調不再適用在離散的數據上,并且梯度在回傳時可能會有一些困難。如下圖:

    這里寫圖片描述

    生成器是以某種方式采樣生成一批數據傳給判別器的,這樣判別器反向將梯度回傳給生成器時貌似不太好辦?

    而在?中,生成器每生成一個?時,都會計算該?在生成分別中的概率,并且利用上一次訓完的判別器計算出相應的,這個?可以理解為生成該?的權重?經過幾輪的訓練后,?越大的?越正向,越容易生成(這其實是強化學習的思想)。這里面就不需要判別器反向傳梯度給生成器了。這就避免了梯度的微調導致不適用在離散的樣本上?

    不知道上面我個人的理解是否正確?如有想法歡迎留言討論。

    • 開頭就說了傳統的?方法存在?問題,在本篇論文中,生成器只是在?時用了?來做?,而在真正訓練生成器的時候,生成器并沒有用到,只是在判別器 中用到了?來訓練生成器 ,訓練好的生成器能得到更好、更準確的。那么無論在,還是在?階段,其生成器的輸入時一致的,不存在在?時用?作為?,而在預測的時候用。

    備注:公眾號菜單包含了整理了一本AI小抄非常適合在通勤路上用學習

    往期精彩回顧那些年做的學術公益-你不是一個人在戰(zhàn)斗適合初學者入門人工智能的路線及資料下載機器學習在線手冊深度學習在線手冊備注:加入本站微信群或者qq群,請回復“加群”加入知識星球(4500+用戶,ID:92416895),請回復“知識星球”

    喜歡文章,點個在看

    與50位技術專家面對面20年技術見證,附贈技術全景圖

    總結

    以上是生活随笔為你收集整理的员外带你读论文:SeqGAN论文分享的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。