hi各位大佬好,關于ytb可謂是無人不知無人不曉,這個玩意必然也是應知應會的題目,這是基本的問題,與FM是一樣的,
For Recommendation in Deep learning QQ Second Group 102948747
For Visual in deep learning QQ Group 629530787
I'm here waiting for you
不接受這個網頁的私聊/私信!!
本寶寶長期征集真實情感經歷(發在我公號:美好時光與你同行),長期接受付費咨詢(啥問題都可),付費改代碼,
付費咨詢,專屬服務,快人一步!!!
1-關于序列推薦的本質
序列推薦在本質上也是多對多問題,由多個點擊的item預測未來要點擊的多個item,這就是seq2seq,在翻譯中不也是如此么??

2-幾個函式
2.1tf-function中的input_signature
>>> @tf.function
... def f(x):
... return x + 1
>>> vector = tf.constant([1.0, 1.0])
>>> matrix = tf.constant([[3.0]])
>>> f.get_concrete_function(vector) is f.get_concrete_function(matrix)
False
>>> @tf.function(
... input_signature=[tf.TensorSpec(shape=None, dtype=tf.float32)])
... def f(x):
... return x + 1
>>> vector = tf.constant([1.0, 1.0])
>>> matrix = tf.constant([[3.0]])
>>> f.get_concrete_function(vector) is f.get_concrete_function(matrix)
True
get_concrete_function(*args, **kwargs) method of tensorflow.python.eager.def_function.Function instance
Returns a `ConcreteFunction` specialized to inputs and execution context.
If this `Function` was created with an `input_signature`, `args` and
`kwargs` may be omitted. With an input signature there is only one
concrete function associated with this `Function`.
An "input signature" can be optionally provided to `tf.function` to control
the graphs traced. The input signature specifies the shape and type of each
Tensor argument to the function using a `tf.TensorSpec` object. More general
shapes can be used. This is useful to avoid creating multiple graphs when
Tensors have dynamic shapes. It also restricts the shape and datatype of
Tensors that can be used:
只要輸入上面的引數(shape及資料型別),那么就是指定同一個function,
2.2-rsqrt開根號后求倒數
>>> tf.math.rsqrt([3.0,0,-4.0])
<tf.Tensor: shape=(3,), dtype=float32, numpy=array([0.57735026, inf, nan], dtype=float32)>
>>> tf.math.sqrt([3.0,0,-4.0])
<tf.Tensor: shape=(3,), dtype=float32, numpy=array([1.7320508, 0. , nan], dtype=float32)>
>>> 1/tf.math.sqrt([3.0,0,-4.0])
<tf.Tensor: shape=(3,), dtype=float32, numpy=array([0.57735026, inf, nan], dtype=float32)>
負數開根號為非數,非數的倒數還是非數,
2.3-增加兩個維度expand_dims
>>> k
<tf.Tensor: shape=(3, 4), dtype=float32, numpy=
array([[-0.19508752, -0.24705486, -1.4569125 , -0.48979878],
[ 0.3164492 , -0.01150408, 0.45663917, -0.8849148 ],
[ 0.31029478, -1.5752182 , 1.4130656 , 0.41960722]],
dtype=float32)>
tf.expand_dims(k,[-1])
#這個用兩次啊
或者
>>> k2=k[:,:,tf.newaxis,tf.newaxis]
>>> k2.shape
TensorShape([3, 4, 1, 1])
3-multi-head-attention多頭attention
如果是一個頭,那就是常規的attention,多個頭只是增加了多個q,k,v,僅此而已,
如果單純用多頭attention是可以進行增加維度(比如dense操作)的,但如果要加殘差結構,那么就必須保證維度一致,不然沒法加啊,
>>> mat=MultiHeadAttention(d_model,num_heads)
>>> x.shape
TensorShape([12, 10, 16])
>>> res=mat(x,x,x,mask)
>>> res.shape
TensorShape([12, 10, 32])
>>> d_model
32
>>> num_heads
2
Encoder單層,即最上圖的左邊,
>>> model=EncoderLayer(num_heads,x.shape[-1],dense_dim)
>>> res=model(x,True,mask)
>>> res.shape
TensorShape([12, 10, 16])
>>> x.shape
TensorShape([12, 10, 16])
3.1-由于mask采用的是下面的形式與常見的mask可能相反,
self.masks = 1- tf.tile(mask[:,:,tf.newaxis,tf.newaxis],[1,1,self.seq_len,self.num_heads])
然后就用了一層encoder,此時仍舊比上次的最佳要差一點
item_his_eb = self.encoder(item_his_eb,True,self.masks)
item_his_eb = self.dense3(tf.transpose(item_his_eb,[0,2,1]))
self.user_eb = tf.squeeze(item_his_eb)
[0.05438987 0.28721324 0.05550319 0.09987947 0.01372705]
3.2-當mask采用原來的mask(僅僅修改上面的mask,其他不改),那么如下,似乎沒多大影響啊
self.masks = tf.tile(mask[:,:,tf.newaxis,tf.newaxis],[1,1,self.seq_len,self.num_heads])
[0.0543663 0.2829085 0.04441036 0.09898286 0.01082832]
3.3-在3.1的基礎上去掉剛開始的mask,效果變差
item_his_eb = item_list_add_pos#tf.multiply(item_list_add_pos,tf.expand_dims(mask, -1))#[B,maxlen,dim]
[0.05211236 0.27617246 0.0436714 0.09578644 0.01040524]
3.4-在3.1的基礎上去掉mask,反而是目前最佳的結果,說明mask在attention中沒啥用啊
item_his_eb = self.encoder(item_his_eb,True,None)#self.masks)
item_his_eb = self.dense3(tf.transpose(item_his_eb,[0,2,1]))
self.user_eb = tf.squeeze(item_his_eb)
[0.05593012 0.2944682 0.06165472 0.10250784 0.01543112]
4-聚合方式
我感覺從上面的試驗及之前的試驗,最終決定效果天花板的應該是最后一步的dense或者說pooling
這種目前暫時沒有想到特別有效的聚合方式,
因此先試試gap吧,其實與mean是沒有區別的,
在3.4的基礎上換成gap,竟然取得最佳的結果,臥槽,那么是不是把位置資訊也給平均了?
[0.0581151 0.31083053 0.09423887 0.10766441 0.02585611]
因此將位置編碼去掉,結果稍微差點,說明pooling還是可以的
[0.05645998 0.30347934 0.08502831 0.10482394 0.02255137]
如果不去掉位置,而是將pooling換成mean,那么效果又提高了,haha
[0.05937547 0.3134265 0.09733415 0.10924349 0.02662534]
那么這就有一個問題擺在面前,一維pooling與mean有啥區別么?pooling有訓練的引數么?而且pooling得到的結果在faiss計算時相當慢(pooling 3s,mean-1s)
然而經過測驗發現,兩者結果是一樣的,對于指標不同,可能是訓練程序的問題,因為本就相差不大,基本上可以忽略,但對于faiss計算的快慢,我不知道咋解釋了,
>>> x0=tf.random.normal([13,10,18])
>>> x0.shape
TensorShape([13, 10, 18])
>>> x2=tf.keras.layers.GlobalAveragePooling1D()(x0)
>>> x3=tf.math.reduce_mean(x0,1)
>>> np.array_equal(x2.numpy(),x3.numpy())
True
>>>
按照舊版YouTube再試下聚合方式,以及參考其取mean方式,如下,
在本文最優的基礎上發現效果更差了,woc【我懷疑是user_id搞錯了,但搞錯的話應該沒這么高的指標啊】,這個指標與此博文對應,都是差不多的數值
item_his_eb = self.encoder(item_his_eb,True,None)
tmp = tf.concat([tf.nn.embedding_lookup(self.uid_embeddings_var,user_t1),tf.math.reduce_mean(item_his_eb,1)],axis=-1)
self.user_eb = self.dense2(tmp)
[0.03897376 0.23201779 0.05910321 0.07654342 0.01505933]
直接相加的結果也不太行,
self.user_eb = tf.nn.embedding_lookup(self.uid_embeddings_var,user_t1)+tf.math.reduce_mean(item_his_eb,1)
[0.03621471 0.24466549 0.06938735 0.07664543 0.01780289]
相乘呢?,,,
[0.02392878 0.16216457 0.01828449 0.05056945 0.00450191]
既然如此,將舊版本ytb再改為新版本的聚合模式,試試,沒啥提高,到此為止吧,
[0.04446743 0.24024637 0.01803327 0.08255393 0.00387843]
5-多層Encoder
用多層的時候報錯了,如下,這是啥玩意啊,
ValueError: Weights for model sequential_1 have not yet been created. Weights are created when the Model is first called on inputs or `build()` is called with an `input_shape`
后來發現是加了dropout的原因,但為啥呢?加上了input_shape還是不對,這個暫時不要吧,哈哈
兩層Encoder結果并沒有提高,如下,
[0.0585502 0.3106855 0.09285575 0.10797357 0.02531075]
三層也是差不多的結果,不再附,
愿我們終有重逢之時,而你還記得我們曾經討論的話題,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/297499.html
標籤:AI
上一篇:資料結構之樹以及二叉樹的相關概念
下一篇:np.argmax()
