論文細細品讀----KGAT : Knowledge Graph Attention Network for Recommendation

0 ABSTRACT

在推薦系統領域中,爲了使推薦結果更加準確、可解釋性更高,不僅要考慮user-item之間的關係,引入外部知識豐富user-item之間的信息也非常有必要。在這方面比較常用的方法主要有FM算法(factorization machine,因子分解機),該方法主要問題在於將user-item作爲相互獨立的實例,忽視了item之間可能存在的相互作用關係。

本文提出了一種基於知識圖譜和注意力機制的新方法-KGAT(Knowledge Graph Attention Network)。該方法通過user和item之間的屬性將user-item實例鏈接在一起,摒棄user-item之間相互獨立的假設。該方法將user-item和知識圖譜融合在一起形成一種新的網絡結構,並從該網絡結構中抽取高階鏈接路徑用來表達網絡中的節點。
1 INTRODUCTION

常用推薦算法主要有CF算法(collaborative filtering)和SL算法(supervised learning)。

    協同過濾的模型一般爲m個物品,m個用戶的數據,只有部分用戶和部分數據之間是有評分數據的,其它部分評分是空白,此時我們要用已有的部分稀疏數據來預測那些空白的物品和數據之間的評分關係,找到最高評分的物品推薦給用戶。

    一般來說,協同過濾推薦分爲三種類型。第一種是基於用戶(user-based)的協同過濾,第二種是基於項目(item-based)的協同過濾,第三種是基於模型(model based)的協同過濾。基於模型(model based)的協同過濾是目前最主流的協同過濾類型了,我們的一大堆機器學習算法也可以在這裏找到用武之地。

    基於用戶的CF(User-Based CF主要思想是利用<user,item>的打分矩陣, 利用統計信息計算用戶和用戶, item和item之間的相似度。然後再利用相似度排序, 最終得出推薦結果。
    在協同過濾中,一個重要的環節就是如何選擇合適的相似度計算方法,常用的兩種相似度計算方法包括皮爾遜相關係數和餘弦相似度等。皮爾遜相關係數的計算公式爲:
    在這裏插入圖片描述
    根據皮爾遜公式,基於用戶的CF算法公式爲:
    在這裏插入圖片描述
    該公式要計算用戶i

i和用戶jj之間的相似度, IijIij​是代表用戶i和用戶j共同評價過的物品, R(i,x)R(i,x)代表用戶i對物品xx的評分, R(i)¯¯¯¯¯¯

    R(i)​代表用戶i所有評分的平均分:之所以要減去平均分是因爲有的用戶打分嚴有的鬆, 歸一化用戶打分避免相互影響。

    基於項目的CF(Item-Based CF) 和基於用戶的CF類似,只不過這時我們要求物品和物品之間的相似度,就先要找到(或獲得)目標用戶對某些物品的評分,那麼我們就可以對相似度高的類似物品進行預測,將評分最高的若干個相似物品推薦給用戶。比如你在網上買了一本機器學習相關的書,網站馬上會推薦一堆機器學習,大數據相關的書給你,這裏就明顯用到了基於項目的協同過濾思想。
    既然IBCF和UBCF是類似的,那就可以借鑑UBCF的思想,選一個合適的相似度唄——所以還可以用皮爾遜,最終得到IBCF公式:
    在這裏插入圖片描述

我們從上面最最最傳統的CF公式(好吧或者說是算法)可以看出它面臨兩個問題:

    矩陣稀疏問題
    計算資源有限導致的可擴展性不好

爲什麼會矩陣稀疏呢?

    什麼是稀疏矩陣:在矩陣中,如果數值爲0的元素數目遠遠多於非0元素的數目,並且非0元素分佈無規律時,則稱該矩陣爲稀疏矩陣;與之相反,若非0元素數目佔大多數時,則稱該矩陣爲稠密矩陣。

    那我還就稀疏了怎麼着了?:稀疏矩陣會導致空間複雜度和時間複雜度的問題。1. 在空間上,非常大的矩陣需要大量的內存,稀疏的矩陣其零值比數據值要多,因爲這些零值不包含任何信息,這顯然是對內存資源的浪費。 2. 在時間上,對於我們輸入的一個矩陣,如果該矩陣中大部分是零值,那麼處理的時候計算機需要或將零值相加或相乘。而因爲大多數O(N^3)算術運算都用於求解方程組或反轉(invert)包含零操作數的矩陣。所以時間複雜

    對於“可擴展性”也好理解,就以UBCF爲例,隨着系統用戶數量的增大,計算Top-K Relevance User的時間會顯著增長,使得該方法難以勝任用戶量變化巨大的系統,該方法限制了系統的可擴展性。

回到論文中來:
爲了解決CF上面的兩個問題,現在國際慣例是用一個結合用戶ID和項目ID的特徵向量,扔到監督學習模型中,預測新用戶和新項目的(契合)得分,比如我們的張量分解模型FM,xDeepFM模型云云…(下面我自己稱這些方法叫SL方法吧)
考慮由導演e1
e1​拍的電影i1i1​和客戶u1u1​之間的交互影響(interact)(注意這裏是電影和客戶的交互而不是導員和客戶的交互),CF算法會關注歷史上同樣看過電影i1i1​的用戶,從而根據這些用戶u4,u5u4​,u5​對其他電影的喜好(如i2i2​)來推薦給u1u1​; SL算法關注導演的影響,e1e1​導演拍過i1和i2i1​和i2​兩部電影,那麼是否把i2i2​也推薦給u1

u1​呢?

但是現實往往是殘酷的…作者說上面的想法是需要"high-order connectivity"的,SL算法不能考慮到比如黃圈裏的i3,i4
i3​,i4​看過同樣由e1

e1​導演的其他電影

    那麼怎麼理解這裏的“傳統算法無法接觸到黃圈等‘高維信息’呢?”以下是我個人理解,不一定正確甚至可能犯理論上的錯誤
    在論文 《Neural Collective Entity Linking》中,作者認爲傳統模型不能獲得“高度辨別的語義信號,比如實體關係(highly discriminative semantic signals)”,舉例如下:
    對於一句(超長超長的)話·

    Hussain, considered surplus to England’s one-day requirements, struck 158, his first championship century of the season, as Essex reached 372 and took a first innings lead of 82.

        1

    Youdao翻譯成中文是:“Hussain被認爲超出了英格蘭隊的單日比賽要求,他打出了158分,這是他本賽季第一次獲得冠軍,埃塞克斯達到了372分,並在第一局以82分領先”,那麼這裏的England應該被理解成
    除非傳統模型利用到在England、Hussain、Essex附近的,和話題"cricket"有相互干係的相鄰信息,纔可能消除England的歧義

        其實我覺得,這裏的意思是不是這裏England可能機器把他理解爲一個人了?或者是英格蘭的國家?(一個叫英格蘭的小夥?),需要知道下文的英格蘭的城市埃塞克斯纔可以知道具體指的是英格蘭隊?…那感覺這個“多義詞”的例子舉得不是很好啊…消歧消的是多義詞對吧。

    所以上文的作者提出用圖模型解決這一距離過長的問題:下圖展示了命名實體消歧(England,Hussian,Essex)
    在這裏插入圖片描述用箭頭線連接的節點是候選實體,其中紅色實線表示目標實體。
    當然僅僅用圖模型還是有很多缺陷,這也是 《Neural Collective Entity Linking》後續介紹的內容,但是圖模型能將實體關係複雜化是很好的消息。

再扯回來,剛剛我們提出了兩個目前對複雜高階連通的挑戰(黃色高亮),衆多SL算法能夠在一維實體關係層面解決上述兩種挑戰(計算能力和稀疏問題),那麼我們現在只需要引入圖模型,將SL算法擴展到在高維實體關係層面上。因此作者介紹了他的collective knowledge graph CKG模型:在這裏插入圖片描述
作者認爲,成功推薦的關鍵在於充分利用CKG圖的高階關係,比如這種(能夠到達SL所及不了的黃圈和灰圈)遠程連通性:在這裏插入圖片描述

畫餅簡單,但是怎麼用圖模型具體實現呢?
考慮怎麼實現,就要分析需要克服什麼問題:

    與目標用戶具有高階關係的節點隨着階數的增加而急劇增加,給模型增加了計算負荷(也就是爲後文embedding layer做鋪墊)
    高階關係對預測的貢獻是不均衡的,這就要求模型仔細地權衡(或選擇)它們(也就是爲後文Attention引入的權值矩陣做鋪墊)

接下來作者說,我們可以用圖神經網絡做,(但是這個我們目前懶(不)得做(會),你們誰會誰去做吧)。所以穩妥起見,作者提出了KGAT方法,這種方法有兩大寶具:

    遞歸嵌入傳播(對複雜度寶具)
    基於attention的聚合方法(對預測寶具)

2 TASK FORMULATION

剛剛說我們KGAT有兩大寶具,那麼這兩大寶具都是怎麼被作出的呢?作者說,你們啊還是要學習一個,所以先提出了一些基本概念,不着急慢慢來:
2.1 User-Item Bipartite Graph

還是以看電影爲例:用戶(user)和電影(items)之間是有歷史交互信息的,比如你們以前看過XXXX電影。那麼我們把這個interaction data做成一個用戶-項目的雙邊關係圖G1
G1​(哪位大俠能告訴我文章裏這一塊用的那個數學符號是啥名字嗎嚶嚶嚶…),定義:G1={(u,yui,i)∣u∈U,i∈I}G1​={(u,yui​,i)∣u∈U,i∈I}其中UU和II表示用戶和項目的集合,連接yui=1

yui​=1代表觀察到集合中某一個u和某一個i出現交互,反之爲0
2.2 Knowledge Graph

針對2.1中的這個交互interactions,我們可以從中的得到項目的附加信息(side information),比如電影的屬性和外部知識(啥是外部知識?可以理解爲比如一部電影的emmmm歷史背景?_?)。通常這些輔助數據可以從真實世界的實體(電影導演)和它們之間的關係獲得,進而組成一個電影(item)
比如形容一部電影可以從它的導演,燈光師,流派風格等等着手。那麼我們把這些side information做成“由實體-屬性-另一個對應的實體”三元組構成的有向圖G2
G2​:G2={(h,r,t)∣h,t∈ξ,r∈R}G2​={(h,r,t)∣h,t∈ξ,r∈R}其中每一個三元組表示一個從頭實體hh到尾實體t

t的雙向關係(怎麼理解?)

    比如三元組 (Altria ActorOf Saber)代表在《命運之夜天之杯》電影中:"人物阿爾託莉雅是角色Saber的飾演者"這層關係;而我們也可以表示成 (Saber ActorIn Altria)表明Saber的飾演者是型月著名女一號阿爾託莉雅小姐。然而無論是Saber還是阿爾託莉雅都不是用戶user,這也就是說這個G2能囊括很多電影相關的信息

然而作者並非止步於誰是Saber誰是Fate這個深度,作者希望把老虛也拉進來,於是建立了"item-entity alignments"這層關係:A={(i,e)∣i∈I,e∈ξ}

A={(i,e)∣i∈I,e∈ξ}從而拓寬了模型的深度(喜歡老虛的可能就能推薦Fate/Zero)
2.3 Collaborative Knowledge Graph

將用戶喜好和電影知識形成統一的關係圖,首先要用數學語言表示出“用戶喜好”:(u,Interact,i)
(u,Interact,i)其中,yui=1yui​=1表示在用戶和電影之間有交互關係
基於2.2中後半部分的電影-老虛關係(item-entity)集合的思想,爲了拓寬模型深度,作者一統天下,把用戶-老虛(user-entity)圖和2.2前半部分的KG圖G2G2​整合成統一圖:G={(h,r,t)∣h,t∈ξ′,r∈R′}G={(h,r,t)∣h,t∈ξ′,r∈R′}其中ξ′=ξ⋃Uξ′=ξ⋃U, R′=R⋃Interact

R′=R⋃Interact

換句話說這段意思就是:

    對於實體:把用戶和Saber、Altria、老虛…等等衆多和item有關的因素實體合起來形成的新實體集合ξ′

ξ′。
對於關係:將用戶(用戶只是衆多實體中的一種實體)與電影的單向交互關係Interact
Interact和多種其他實體的雙向關係結合起來,得到新關係集合R′

    R′

2.4 High-Order Connectivity

作者再次重申了利用高階連通性是優秀推薦的重要保障,併爲我們描述了L階連通性是什麼亞子:在這裏插入圖片描述
其中上面的ei
ei​和riri​都來自新實體集合ξ′ξ′和新關係集合R′R′。
上圖寫作(el−1,rl,el)(el−1​,rl​,el​)讀作第l

l個三元組,並稱這個三元組序列的長度爲L
##########################華麗的分界線##############################
至此,我們學習完了基本知識,但是爲什麼要學習這些知識呢?爲啥要把這幾個集合合起來呢?我要是不合起來會咋樣呢?

不合起來,行,那就走傳統路線,CF或者SL模型選一個吧!
好,CF模型的連通性結構長下面這個亞子:在這裏插入圖片描述
可以看出來,CF方法建立在用戶之間行爲相似的基礎上——更具體地說,相似的用戶在項目上表現出相似的偏好。比如,我舍友(u1)喜歡(r1)看《Fate/Zero》,而我(u2)也喜歡看,然後我u2還喜歡看《超炮》,那我把超炮推薦給我舍友u1嗎?事實上我舍友只喜歡看老虛這種風格的作品,超炮太治癒了舍友接受不了,所以這種連通不穩。

那換SL算法呢?在這裏插入圖片描述
SL算法通常只考慮一個實體的一個特徵,也就是說從一部電影到另一部電影只能考慮一個因素,比如上圖中的r2

r2​這一個因素,無法顯示items和相關實例之間的相關性,比如:在這裏插入圖片描述
這種情況(左邊考慮導演喜好關係右邊考慮演員喜好關係)就行不通。
3 METHODOLOGY

終於進入全篇高潮部分了,作者說KGAT模型由以下三個部分組成,嵌入層、注意力嵌入傳播層和預測層,這些在圖中表示的也很清晰:在這裏插入圖片描述
3.1 Embedding Layer

爲了將數據輸入網絡中,首先要進行嵌入,這裏給自己囉嗦一下啥是圖嵌入:

    圖嵌入是一種將圖數據(通常爲高維稠密的矩陣)映射爲低微稠密向量的過程。我們都知道圖是由節點和邊構成,這些向量關係一般只能使用數學,統計或者特定的子集進行表示,但是嵌入之後的向量空間具有更加靈活和豐富的計算方式,方便進行機器學習。

    圖嵌入能夠壓縮數據, 我們一般用鄰接矩陣描述圖中節點之間的連接。 連接矩陣的維度是∣V∣∗∣V∣

∣V∣∗∣V∣,其中∣V∣

    ∣V∣是圖中節點的個數。矩陣中的每一列和每一行都代表一個節點。矩陣中的非零值表示兩個節點已連接。

    將一個圖embedding成低維稠密向量有兩種方法,但這兩種方法萬變不離其宗的思想就是Worl2Vec思想(獨熱編碼後扔到DNN中梯度下降入Softmax輸出選擇概率)

        節點嵌入(以DeepWalk爲例):隨機遊走起始於選定的節點,然後從當前節點移至隨機鄰居,並執行一定的步數,該方法大致可分爲三個步驟:
        在這裏插入圖片描述

        採樣:通過隨機遊走對圖上的節點進行採樣,在給定的時間內得到一個節點構成的序列
        訓練skip-gram:隨機遊走得到的節點序列與word2vec方法中的句子相當。文本中skip-gram的輸入是一個句子,在這裏輸入爲隨機遊走採樣得到的序列,然後通過最大化預測相鄰節點的概率進而學習預測周圍節點
        3)計算嵌入之

        圖嵌入方法:圖嵌入是將整個圖用一個向量表示的方法,Graph2vec同樣由三個步驟構成:
        在這裏插入圖片描述

        採樣並重新標記圖中的所有子圖。子圖是出現在所選節點周圍的一組節點。子圖中的節點距離所選邊數不遠。
        訓練skip-gram模型,類比Word2Vec。經過訓練,可以最大程度地預測輸入中存在於圖中的子圖的概率。
        通過在輸入處提供子圖的id索引向量來計算嵌入

那麼,咱們分析一下,這裏用的是圖嵌入還是節點嵌入呢?
我個人的理解是圖嵌入,因爲從KGAT的模型中從第一步就開始建立子圖(三元組,就是圖中的ei10

ei1​​0等subgraph),畢竟我理解的兩種嵌入最大的區別就是是直接剛節點還是曲線救國積沙成塔整合區域節點爲子圖。

好了好了再扯回來…我們嵌入好了,就運用TransR模型:(關於TransR模型可以先簡單理解爲建立(h,r,t)
(h,r,t)的向量運算關係,是真正的數學層面關係)
TransR:ert=erh+erTransR:etr​=ehr​+er​其中eh,et∈Rdeh​,et​∈Rd代表一個三元組(h,r,t)(h,r,t)經過嵌入embedding後的頭實體和爲實體,er∈Rker​∈Rk同理。並且上角標rr表示的是經過TransR變換到r超平面中的eh,et

eh​,et​。

爲了解決之前提出的第二個高亮問題(分配不均衡),我們將輸入特徵轉換爲高層特徵,這一過程需要一個可學習的線性轉換(one learnable linear transformation)。爲了達到該目標,我們考慮採用《Attention is All You Need》這篇神文的一個共享的線性轉換,通過對每一個節點進行加權。我們稱這一過程爲self-attention。

對於一個給定的三元組,根據《Graph Attention Networks》給出的self-attention處理模型:在這裏插入圖片描述
回過頭針對這裏的三個變量模型,我們建立自己的勢能函數:在這裏插入圖片描述
其中Wr∈Rk×d
Wr​∈Rk×d是關係rr的變換矩陣,將RdRd的實體空間轉換到RkRk的r

r關係超平面中(這一超平面就是之前TransR過程中的超平面,換言之,若你用TransE就不需要轉換)

考慮到損失函數(loss function)是用來估量你模型的預測值f(x)
f(x)與真實值YY的不一致程度,它是一個非負實值函數,通常使用L(Y,f(x))L(Y,f(x))來表示,損失函數越小,模型的魯棒性就越好。所以這裏我們給出勢能函數g(h,r,t)g(h,r,t)的損失函數:
在這裏插入圖片描述
其中σ

σ是sigmoid函數,自變量趨於正/負無窮是輸出1或-1。通常我們給正樣例的分數高,負樣例的分數低,保證括號內作差小於0 (外面一個負號,負負得正)從而保證訓練過程每輪Loss大於0。

    這裏還需要囉嗦一句:g(h,r,t′)和g(h,r,t)

    g(h,r,t′)和g(h,r,t)的關係:前者表示不存在圖中的三元組組合。啥意思咧?
    咱們訓練不是要正負樣例嗎(在SL基礎上改的肯定要監督哇),我們用正樣例,比如:(美國 總統 奧巴馬) 去生成一個和這個正樣例相關的負樣例:(美國 總統 本拉登)。但是,萬一我們的語料庫中正好有拉登這個負樣例,那就重複了嘛,所以這裏還有專門的處理方法(我忘了,懇請各位大神補充)。

3.2 Attentive Embedding Propagation Layers

這一節講的是傳播。
我們先從單層的傳播描述,然後再介紹從單層到多層的方法。
3.2.1 Information Propagation

一個實體可以包含在多個三元組中,理論上充當連接兩個三元組和傳播信息的橋樑,比如:

在這裏插入圖片描述

在這裏插入圖片描述
這裏面i2
i2​可以將e1e1​和e2e2​作爲輸入來enrich自己的特徵,從而爲用戶u2

u2​提供更多的選擇推薦。這就是我們實現信息傳遞的中心思想。

考慮實體h
h,我們記"以實體h

h爲頭實體的所有三元組"爲ego-network:在這裏插入圖片描述

爲了刻畫實體h
h的一階連通性結構,我們記hh的ego-network網絡的線性組合爲:在這裏插入圖片描述
其中π(h,r,t)π(h,r,t)決定三元組(h,r,t)(h,r,t)上每次傳播的衰減係數,可以理解爲從tt到hh傳播的信息中有多少與r

r有關。

    通過公式怎麼看出衰減係數依賴於在關係r

r向量空間中尾實體 tt 與頭實體 h

    h的距離,具體這個是怎麼理解的?
    我的理解是這樣的:(這是我在知乎上的回答)
    1 首先,這裏的衰減係數π(h,r,t),就是我們通常attention機制中的計算相似度的第四種方法,而這個π(h,r,t)是怎麼來的呢?請看下文
    2 在attention中,我們取一個非線性函數f(比如LeakyReLU就行)表徵兩個實體之間的相似度(在《Attention is all you need》這篇神文裏指的是Q,V,K向量,可以瞭解一下)。那麼我們經過多次迭代所有實體後,需要輸出attention向量以計算對應特徵的線性加權,所以就需要將得到的相似度進行歸一化,就是文中的tanh(第四種)操作。所以這裏的衰減係數π(h,r,t),我謹理解爲是相似度的歸一化函數。
    3 2中的非線性函數,在這篇文章中就是g(h,r,t),所以衰減係數π(h,r,t)本質上是g的函數,而g(h,r,t)中是有着h與t的距離信息的。所以衰減係數π(h,r,t)就可能依賴於距離了

個人理解,可能不嚴謹或者完全不對,如有不正確的地方還望指出,也希望能和大家多多討論。
3.2.2 Knowledge-aware Attention

下面這一部分就是Attention中的內容了,注意力函數eij
eij​也有很多種變體。四種注意力變體:加性注意力(additive attention)、乘法(點積)注意力(multiplicative attention)、自注意力(self-attention)和關鍵值注意力(key-value attention)。這裏給出的是用tanh非線性激勵函數加性注意力(additive attention),可以使得注意力得分依賴於超平面rr空間中eheh​和etet​之間的距離,爲更近的實體傳播更多信息。在這裏插入圖片描述
我們採用softmax函數對所有與剛剛說的與h

h頭實體相連的三元組的係數進行歸一化處理:在這裏插入圖片描述
3.2.3 Information Aggregation

好了我現在得到每一層的輸出的概率了,那麼現在要把所有層加起來,大概對應於圖中的這一步:在這裏插入圖片描述
紅圈是第一層,藍圈是第二層,高亮黃框應該延伸到Wl1
W1l​和Wl2W2l​的,這裏是我塗鴉失誤,誤把這裏的W和之前的Wr

Wr​混淆了。

最後一步首先要完成聚合(aggregation),這裏我們以第一種聚合器爲例,《Semi-Supervised Classification with Graph Convolutional Networks》提出的聚合器:輸入是兩個表示向量的和,然後與可訓練權值的d′×d
d′×d 矩陣WW相乘後再經過激活函數(這裏取了LeakyReLU)後輸出。其中W

W是可以提取有用的信息用於傳播的權值矩陣(沒錯就是之前說的那個對預測寶具)。
3.2.4 High-order Propagation

我們可以進一步堆疊更多的傳播層來得到高階連接信息,收集從高階鄰點的傳播信息。在第lth
lth步驟中,我們遞歸地將一個實體的表示形式表示爲:在這裏插入圖片描述
其中,hh實體在l−egol−ego第l階的ego網絡中傳播的信息定義如下:在這裏插入圖片描述
這個式子表示每個經過Softmax的注意力分數(ππ)與其對應的值(實體e)相乘,這個過程會產生對應數量的對齊向量(alignment vector),我們通常稱之爲加權值。其中,el−1tetl−1​是從前面的信息傳播步驟中由尾實體tt產生的,包含着第l−1l−1階的所有鄰點信息。所以高階連通性如: 在這裏插入圖片描述
就可以通過以上四個過程得到了。(你看黃圈裏面的u2u2​(在編碼後叫做e(3)u1eu1​(3)​)不就和最左邊的u1

u1​連上了嗎)。

注意這裏還沒有合併,只是通過遞歸得到了我想要的階次的實體表示e(l)h

eh(l)​而已
3.3 Model Prediction

對應的是這一部分:在這裏插入圖片描述
concatenate的輸入是剛剛每層輸出的各階信息e(l)h

eh(l)​(沒錯就是剛剛的加權值).通過分析不同layer的輸出就可以得到從1到多階的連通性,我們採用layer-aggregation機制(上文提到的另一種方法)進行concatenate這麼多層的輸出。(說白了就是對加權值求和,得到輸出1)

在這裏插入圖片描述
最後,我們對用戶和項目的表示e進行內積,從而預測它們的匹配分數:在這裏插入圖片描述
3.4 Optimization

作者綜合了多種Loss模型,提出了分別對KG和CF兩種Loss合併起來算Loss:在這裏插入圖片描述

基本內容如上,這之後的訓練模型就是如論文中所述。感謝文章的作者提出的寶貴學術資料。

w_h = [
[0,0,1],
[1,1,0],
[0,1,0].
[1,1,0]]
w_r = [

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章