README.html 86.5 KB
Newer Older
L
Luo Tao 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
<!DOCTYPE html>
<html class="theme theme-white">
<head>
<meta charset="utf-8">
<title>个性化推荐</title>
<link href="https://www.zybuluo.com/static/assets/template-theme-white.css" rel="stylesheet" media="screen">
<style type="text/css">

#wmd-preview h1  {
    color: #0077bb; /* 将标题改为蓝色 */
}</style>
</head>
<body class="theme theme-white">
<div style="visibility: hidden; overflow: hidden; position: absolute; top: 0px; height: 1px; width: auto; padding: 0px; border: 0px; margin: 0px; text-align: left; text-indent: 0px; text-transform: none; line-height: normal; letter-spacing: normal; word-spacing: normal;"><div id="MathJax_SVG_Hidden"></div><svg><defs id="MathJax_SVG_glyphs"><path id="MJMATHI-6B" stroke-width="1" d="M121 647Q121 657 125 670T137 683Q138 683 209 688T282 694Q294 694 294 686Q294 679 244 477Q194 279 194 272Q213 282 223 291Q247 309 292 354T362 415Q402 442 438 442Q468 442 485 423T503 369Q503 344 496 327T477 302T456 291T438 288Q418 288 406 299T394 328Q394 353 410 369T442 390L458 393Q446 405 434 405H430Q398 402 367 380T294 316T228 255Q230 254 243 252T267 246T293 238T320 224T342 206T359 180T365 147Q365 130 360 106T354 66Q354 26 381 26Q429 26 459 145Q461 153 479 153H483Q499 153 499 144Q499 139 496 130Q455 -11 378 -11Q333 -11 305 15T277 90Q277 108 280 121T283 145Q283 167 269 183T234 206T200 217T182 220H180Q168 178 159 139T145 81T136 44T129 20T122 7T111 -2Q98 -11 83 -11Q66 -11 57 -1T48 16Q48 26 85 176T158 471L195 616Q196 629 188 632T149 637H144Q134 637 131 637T124 640T121 647Z"></path><path id="MJMATHI-55" stroke-width="1" d="M107 637Q73 637 71 641Q70 643 70 649Q70 673 81 682Q83 683 98 683Q139 681 234 681Q268 681 297 681T342 682T362 682Q378 682 378 672Q378 670 376 658Q371 641 366 638H364Q362 638 359 638T352 638T343 637T334 637Q295 636 284 634T266 623Q265 621 238 518T184 302T154 169Q152 155 152 140Q152 86 183 55T269 24Q336 24 403 69T501 205L552 406Q599 598 599 606Q599 633 535 637Q511 637 511 648Q511 650 513 660Q517 676 519 679T529 683Q532 683 561 682T645 680Q696 680 723 681T752 682Q767 682 767 672Q767 650 759 642Q756 637 737 637Q666 633 648 597Q646 592 598 404Q557 235 548 205Q515 105 433 42T263 -22Q171 -22 116 34T60 167V183Q60 201 115 421Q164 622 164 628Q164 635 107 637Z"></path><path id="MJMATHI-3C9" stroke-width="1" d="M495 384Q495 406 514 424T555 443Q574 443 589 425T604 364Q604 334 592 278T555 155T483 38T377 -11Q297 -11 267 66Q266 68 260 61Q201 -11 125 -11Q15 -11 15 139Q15 230 56 325T123 434Q135 441 147 436Q160 429 160 418Q160 406 140 379T94 306T62 208Q61 202 61 187Q61 124 85 100T143 76Q201 76 245 129L253 137V156Q258 297 317 297Q348 297 348 261Q348 243 338 213T318 158L308 135Q309 133 310 129T318 115T334 97T358 83T393 76Q456 76 501 148T546 274Q546 305 533 325T508 357T495 384Z"></path><path id="MJMATHI-69" stroke-width="1" d="M184 600Q184 624 203 642T247 661Q265 661 277 649T290 619Q290 596 270 577T226 557Q211 557 198 567T184 600ZM21 287Q21 295 30 318T54 369T98 420T158 442Q197 442 223 419T250 357Q250 340 236 301T196 196T154 83Q149 61 149 51Q149 26 166 26Q175 26 185 29T208 43T235 78T260 137Q263 149 265 151T282 153Q302 153 302 143Q302 135 293 112T268 61T223 11T161 -11Q129 -11 102 10T74 74Q74 91 79 106T122 220Q160 321 166 341T173 380Q173 404 156 404H154Q124 404 99 371T61 287Q60 286 59 284T58 281T56 279T53 278T49 278T41 278H27Q21 284 21 287Z"></path><path id="MJMATHI-50" stroke-width="1" d="M287 628Q287 635 230 637Q206 637 199 638T192 648Q192 649 194 659Q200 679 203 681T397 683Q587 682 600 680Q664 669 707 631T751 530Q751 453 685 389Q616 321 507 303Q500 302 402 301H307L277 182Q247 66 247 59Q247 55 248 54T255 50T272 48T305 46H336Q342 37 342 35Q342 19 335 5Q330 0 319 0Q316 0 282 1T182 2Q120 2 87 2T51 1Q33 1 33 11Q33 13 36 25Q40 41 44 43T67 46Q94 46 127 49Q141 52 146 61Q149 65 218 339T287 628ZM645 554Q645 567 643 575T634 597T609 619T560 635Q553 636 480 637Q463 637 445 637T416 636T404 636Q391 635 386 627Q384 621 367 550T332 412T314 344Q314 342 395 342H407H430Q542 342 590 392Q617 419 631 471T645 554Z"></path><path id="MJMAIN-28" stroke-width="1" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z"></path><path id="MJMAIN-3D" stroke-width="1" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z"></path><path id="MJMAIN-7C" stroke-width="1" d="M139 -249H137Q125 -249 119 -235V251L120 737Q130 750 139 750Q152 750 159 735V-235Q151 -249 141 -249H139Z"></path><path id="MJMATHI-75" stroke-width="1" d="M21 287Q21 295 30 318T55 370T99 420T158 442Q204 442 227 417T250 358Q250 340 216 246T182 105Q182 62 196 45T238 27T291 44T328 78L339 95Q341 99 377 247Q407 367 413 387T427 416Q444 431 463 431Q480 431 488 421T496 402L420 84Q419 79 419 68Q419 43 426 35T447 26Q469 29 482 57T512 145Q514 153 532 153Q551 153 551 144Q550 139 549 130T540 98T523 55T498 17T462 -8Q454 -10 438 -10Q372 -10 347 46Q345 45 336 36T318 21T296 6T267 -6T233 -11Q189 -11 155 7Q103 38 103 113Q103 170 138 262T173 379Q173 380 173 381Q173 390 173 393T169 400T158 404H154Q131 404 112 385T82 344T65 302T57 280Q55 278 41 278H27Q21 284 21 287Z"></path><path id="MJMAIN-29" stroke-width="1" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z"></path><path id="MJMATHI-65" stroke-width="1" d="M39 168Q39 225 58 272T107 350T174 402T244 433T307 442H310Q355 442 388 420T421 355Q421 265 310 237Q261 224 176 223Q139 223 138 221Q138 219 132 186T125 128Q125 81 146 54T209 26T302 45T394 111Q403 121 406 121Q410 121 419 112T429 98T420 82T390 55T344 24T281 -1T205 -11Q126 -11 83 42T39 168ZM373 353Q367 405 305 405Q272 405 244 391T199 357T170 316T154 280T149 261Q149 260 169 260Q282 260 327 284T373 353Z"></path><path id="MJMATHI-76" stroke-width="1" d="M173 380Q173 405 154 405Q130 405 104 376T61 287Q60 286 59 284T58 281T56 279T53 278T49 278T41 278H27Q21 284 21 287Q21 294 29 316T53 368T97 419T160 441Q202 441 225 417T249 361Q249 344 246 335Q246 329 231 291T200 202T182 113Q182 86 187 69Q200 26 250 26Q287 26 319 60T369 139T398 222T409 277Q409 300 401 317T383 343T365 361T357 383Q357 405 376 424T417 443Q436 443 451 425T467 367Q467 340 455 284T418 159T347 40T241 -11Q177 -11 139 22Q102 54 102 117Q102 148 110 181T151 298Q173 362 173 380Z"></path><path id="MJSZ1-2211" stroke-width="1" d="M61 748Q64 750 489 750H913L954 640Q965 609 976 579T993 533T999 516H979L959 517Q936 579 886 621T777 682Q724 700 655 705T436 710H319Q183 710 183 709Q186 706 348 484T511 259Q517 250 513 244L490 216Q466 188 420 134T330 27L149 -187Q149 -188 362 -188Q388 -188 436 -188T506 -189Q679 -189 778 -162T936 -43Q946 -27 959 6H999L913 -249L489 -250Q65 -250 62 -248Q56 -246 56 -239Q56 -234 118 -161Q186 -81 245 -11L428 206Q428 207 242 462L57 717L56 728Q56 744 61 748Z"></path><path id="MJMATHI-6A" stroke-width="1" d="M297 596Q297 627 318 644T361 661Q378 661 389 651T403 623Q403 595 384 576T340 557Q322 557 310 567T297 596ZM288 376Q288 405 262 405Q240 405 220 393T185 362T161 325T144 293L137 279Q135 278 121 278H107Q101 284 101 286T105 299Q126 348 164 391T252 441Q253 441 260 441T272 442Q296 441 316 432Q341 418 354 401T367 348V332L318 133Q267 -67 264 -75Q246 -125 194 -164T75 -204Q25 -204 7 -183T-12 -137Q-12 -110 7 -91T53 -71Q70 -71 82 -81T95 -112Q95 -148 63 -167Q69 -168 77 -168Q111 -168 139 -140T182 -74L193 -32Q204 11 219 72T251 197T278 308T289 365Q289 372 288 376Z"></path><path id="MJMAIN-2208" stroke-width="1" d="M84 250Q84 372 166 450T360 539Q361 539 377 539T419 540T469 540H568Q583 532 583 520Q583 511 570 501L466 500Q355 499 329 494Q280 482 242 458T183 409T147 354T129 306T124 272V270H568Q583 262 583 250T568 230H124V228Q124 207 134 177T167 112T231 48T328 7Q355 1 466 0H570Q583 -10 583 -20Q583 -32 568 -40H471Q464 -40 446 -40T417 -41Q262 -41 172 45Q84 127 84 250Z"></path><path id="MJMATHI-56" stroke-width="1" d="M52 648Q52 670 65 683H76Q118 680 181 680Q299 680 320 683H330Q336 677 336 674T334 656Q329 641 325 637H304Q282 635 274 635Q245 630 242 620Q242 618 271 369T301 118L374 235Q447 352 520 471T595 594Q599 601 599 609Q599 633 555 637Q537 637 537 648Q537 649 539 661Q542 675 545 679T558 683Q560 683 570 683T604 682T668 681Q737 681 755 683H762Q769 676 769 672Q769 655 760 640Q757 637 743 637Q730 636 719 635T698 630T682 623T670 615T660 608T652 599T645 592L452 282Q272 -9 266 -16Q263 -18 259 -21L241 -22H234Q216 -22 216 -15Q213 -9 177 305Q139 623 138 626Q133 637 76 637H59Q52 642 52 648Z"></path></defs></svg></div><div id="wmd-preview" class="wmd-preview wmd-preview-full-reader"><div class="md-section-divider"></div><div class="md-section-divider"></div><h1 data-anchor-id="2hyd" id="个性化推荐">个性化推荐</h1><div class="md-section-divider"></div><h2 data-anchor-id="k5t4" id="背景介绍">背景介绍</h2><p data-anchor-id="6e0a">在网络技术不断发展和电子商务规模不断扩大的背景下,商品数量和种类快速增长,用户需要花费大量时间才能找到自己想买的商品,这就是信息超载问题。为了解决这个难题,推荐系统(Recommender System)应运而生。</p><p data-anchor-id="3wu6">个性化推荐系统是信息过滤系统(Information Filtering System)的子集,它可以用在很多领域,如电影、音乐、电商和 Feed 流推荐等。推荐系统通过分析、挖掘用户行为,发现用户的个性化需求与兴趣特点,将用户可能感兴趣的信息或商品推荐给用户。与搜索引擎不同,推荐系统不需要用户准确地描述出自己的需求,而是根据分析历史行为建模,主动提供满足用户兴趣和需求的信息。</p><p data-anchor-id="npdl">传统的推荐系统方法主要有:</p><ul data-anchor-id="1obm">
<li>协同过滤推荐(Collaborative Filtering Recommendation):该方法收集分析用户历史行为、活动、偏好,计算一个用户与其他用户的相似度,利用目标用户的相似用户对商品评价的加权评价值,来预测目标用户对特定商品的喜好程度。优点是可以给用户推荐未浏览过的新产品;缺点是对于没有任何行为的新用户存在冷启动的问题,同时也存在用户与商品之间的交互数据不够多造成的稀疏问题,会导致模型难以找到相近用户。</li>
<li>基于内容过滤推荐[<a href="#参考文献">1</a>](Content-based Filtering Recommendation):该方法利用商品的内容描述,抽象出有意义的特征,通过计算用户的兴趣和商品描述之间的相似度,来给用户做推荐。优点是简单直接,不需要依据其他用户对商品的评价,而是通过商品属性进行商品相似度度量,从而推荐给用户所感兴趣商品的相似商品;缺点是对于没有任何行为的新用户同样存在冷启动的问题。</li>
<li>组合推荐[<a href="#参考文献">2</a>](Hybrid Recommendation):运用不同的输入和技术共同进行推荐,以弥补各自推荐技术的缺点。</li>
</ul><p data-anchor-id="o51b">其中协同过滤是应用最广泛的技术之一,它又可以分为多个子类:基于用户 (User-Based)的推荐[<a href="#参考文献">3</a>] 、基于物品(Item-Based)的推荐[<a href="#参考文献">4</a>]、基于社交网络关系(Social-Based)的推荐[<a href="#参考文献">5</a>]、基于模型(Model-based)的推荐等。1994年明尼苏达大学推出的GroupLens系统[<a href="#参考文献">3</a>]一般被认为是推荐系统成为一个相对独立的研究方向的标志。该系统首次提出了基于协同过滤来完成推荐任务的思想,此后,基于该模型的协同过滤推荐引领了推荐系统十几年的发展方向。</p><p data-anchor-id="n78e">深度学习具有优秀的自动提取特征的能力,能够学习多层次的抽象特征表示,并对异质或跨域的内容信息进行学习,可以一定程度上处理推荐系统冷启动问题[<a href="#参考文献">6</a>]。本教程主要介绍个性化推荐的深度学习模型,以及如何使用PaddlePaddle实现模型。</p><div class="md-section-divider"></div><h2 data-anchor-id="z9ab" id="效果展示">效果展示</h2><p data-anchor-id="077s">我们使用包含用户信息、电影信息与电影评分的数据集作为个性化推荐的应用场景。当我们训练好模型后,只需要输入对应的用户ID和电影ID,就可以得出一个匹配的分数(范围[1,5],分数越高视为兴趣越大),然后根据所有电影的推荐得分排序,推荐给用户可能感兴趣的电影。</p><div class="md-section-divider"></div><pre class="prettyprint linenums prettyprinted" data-anchor-id="nuqj"><ol class="linenums"><li class="L0"><code><span class="typ">Input</span><span class="pln"> movie_id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1962</span></code></li><li class="L1"><code><span class="typ">Input</span><span class="pln"> user_id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span></code></li><li class="L2"><code><span class="typ">Prediction</span><span class="pln"> </span><span class="typ">Score</span><span class="pln"> </span><span class="kwd">is</span><span class="pln"> </span><span class="lit">4.25</span></code></li></ol></pre><div class="md-section-divider"></div><div class="md-section-divider"></div><p align="center" data-anchor-id="kpkf">
<img src="https://raw.githubusercontent.com/PaddlePaddle/book/develop/recommender_system/image/YouTube_Overview.png" width="700"><br>
图1. YouTube 推荐系统结构
</p><div class="md-section-divider"></div><h4 data-anchor-id="fvxx" id="候选生成网络candidate-generation-network">候选生成网络(Candidate Generation Network)</h4><p data-anchor-id="telc">候选生成网络将推荐问题建模为一个类别数极大的多类分类问题:对于一个Youtube用户,使用其观看历史(视频ID)、搜索词记录(search tokens)、人口学信息(如地理位置、用户登录设备)、二值特征(如性别,是否登录)和连续特征(如用户年龄)等,对视频库中所有视频进行多分类,得到每一类别的分类结果(即每一个视频的推荐概率),最终输出概率较高的几百个视频。</p><p data-anchor-id="78ec">首先,将观看历史及搜索词记录这类历史信息,映射为向量后取平均值得到定长表示;同时,输入人口学特征以优化新用户的推荐效果,并将二值特征和连续特征归一化处理到[0, 1]范围。接下来,将所有特征表示拼接为一个向量,并输入给非线形多层感知器(MLP,详见<a href="https://github.com/PaddlePaddle/book/blob/develop/recognize_digits/README.md" target="_blank">识别数字</a>教程)处理。最后,训练时将MLP的输出给softmax做分类,预测时计算用户的综合特征(MLP的输出)与所有视频的相似度,取得分最高的<span class="MathJax_Preview"></span><span class="MathJax_SVG" id="MathJax-Element-1-Frame" role="textbox" aria-readonly="true" style="font-size: 100%; display: inline-block;"><svg xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 -715.0516853480245 521.5 747.103370696049" style="width: 1.158ex; height: 1.737ex; vertical-align: -0.116ex; margin: 1px 0px;"><g stroke="black" fill="black" stroke-width="0" transform="matrix(1 0 0 -1 0 0)"><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#MJMATHI-6B"></use></g></svg></span><script type="math/tex" id="MathJax-Element-1">k</script>个作为候选生成网络的筛选结果。图2显示了候选生成网络结构。</p><p align="center" data-anchor-id="ocmu">
<img src="https://raw.githubusercontent.com/PaddlePaddle/book/develop/recommender_system/image/Deep_candidate_generation_model_architecture.png" width="700"><br>
图2. 候选生成网络结构
</p><p data-anchor-id="m58q">对于一个用户<span class="MathJax_Preview"></span><span class="MathJax_SVG" id="MathJax-Element-2-Frame" role="textbox" aria-readonly="true" style="font-size: 100%; display: inline-block;"><svg xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 -704.0516853480245 767.5 747.103370696049" style="width: 1.737ex; height: 1.737ex; vertical-align: -0.232ex; margin: 1px 0px;"><g stroke="black" fill="black" stroke-width="0" transform="matrix(1 0 0 -1 0 0)"><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#MJMATHI-55"></use></g></svg></span><script type="math/tex" id="MathJax-Element-2">U</script>,预测此刻用户要观看的视频<span class="MathJax_Preview"></span><span class="MathJax_SVG" id="MathJax-Element-3-Frame" role="textbox" aria-readonly="true" style="font-size: 100%; display: inline-block;"><svg xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 -464.0516853480245 622.5 497.10337069604896" style="width: 1.39ex; height: 1.158ex; vertical-align: -0.116ex; margin: 1px 0px;"><g stroke="black" fill="black" stroke-width="0" transform="matrix(1 0 0 -1 0 0)"><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#MJMATHI-3C9"></use></g></svg></span><script type="math/tex" id="MathJax-Element-3">\omega</script>为视频<span class="MathJax_Preview"></span><span class="MathJax_SVG" id="MathJax-Element-4-Frame" role="textbox" aria-readonly="true" style="font-size: 100%; display: inline-block;"><svg xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 -682.0516853480245 345.5 714.103370696049" style="width: 0.811ex; height: 1.622ex; vertical-align: -0.116ex; margin: 1px 0px;"><g stroke="black" fill="black" stroke-width="0" transform="matrix(1 0 0 -1 0 0)"><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#MJMATHI-69"></use></g></svg></span><script type="math/tex" id="MathJax-Element-4">i</script>的概率公式为:</p><div class="md-section-divider"></div><p data-anchor-id="ft5n"><span class="MathJax_Preview"></span><div class="MathJax_SVG_Display" role="textbox" aria-readonly="true" style="text-align: center;"><span class="MathJax_SVG" id="MathJax-Element-5-Frame" style="font-size: 100%; display: inline-block;"><svg xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 -1373.4070961948516 10600.151422196319 2540.448809973245" style="width: 24.672ex; height: 5.907ex; vertical-align: -2.78ex; margin: 1px 0px;"><g stroke="black" fill="black" stroke-width="0" transform="matrix(1 0 0 -1 0 0)"><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#MJMATHI-50"></use><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#MJMAIN-28" x="751" y="0"></use><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#MJMATHI-3C9" x="1141" y="0"></use><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#MJMAIN-3D" x="2041" y="0"></use><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#MJMATHI-69" x="3097" y="0"></use><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#MJMAIN-7C" x="3443" y="0"></use><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#MJMATHI-75" x="3721" y="0"></use><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#MJMAIN-29" x="4294" y="0"></use><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#MJMAIN-3D" x="4961" y="0"></use><g transform="translate(6137,0)"><rect stroke="none" width="4342" height="60" x="0" y="220"></rect><g transform="translate(1392,676)"><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#MJMATHI-65"></use><g transform="translate(466,362)"><use transform="scale(0.7071067811865476)" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#MJMATHI-76"></use><use transform="scale(0.5000000000000001)" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#MJMATHI-69" x="686" y="-213"></use><use transform="scale(0.7071067811865476)" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#MJMATHI-75" x="829" y="0"></use></g></g><g transform="translate(60,-716)"><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#MJSZ1-2211"></use><g transform="translate(1056,-287)"><use transform="scale(0.7071067811865476)" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#MJMATHI-6A"></use><use transform="scale(0.7071067811865476)" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#MJMAIN-2208" x="412" y="0"></use><use transform="scale(0.7071067811865476)" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#MJMATHI-56" x="1080" y="0"></use></g><g transform="translate(2630,0)"><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#MJMATHI-65"></use><g transform="translate(466,316)"><use transform="scale(0.7071067811865476)" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#MJMATHI-76"></use><use transform="scale(0.5000000000000001)" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#MJMATHI-6A" x="686" y="-213"></use><use transform="scale(0.7071067811865476)" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#MJMATHI-75" x="877" y="0"></use></g></g></g></g></g></svg></span></div><script type="math/tex; mode=display" id="MathJax-Element-5">P(\omega=i|u)=\frac{e^{v_{i}u}}{\sum_{j \in V}e^{v_{j}u}}</script></p><p data-anchor-id="cyym">其中<span class="MathJax_Preview"></span><span class="MathJax_SVG" id="MathJax-Element-6-Frame" role="textbox" aria-readonly="true" style="font-size: 100%; display: inline-block;"><svg xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 -463.0516853480245 572.5 495.10337069604896" style="width: 1.274ex; height: 1.158ex; vertical-align: -0.116ex; margin: 1px 0px;"><g stroke="black" fill="black" stroke-width="0" transform="matrix(1 0 0 -1 0 0)"><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#MJMATHI-75"></use></g></svg></span><script type="math/tex" id="MathJax-Element-6">u</script>为用户<span class="MathJax_Preview"></span><span class="MathJax_SVG" id="MathJax-Element-7-Frame" role="textbox" aria-readonly="true" style="font-size: 100%; display: inline-block;"><svg xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 -704.0516853480245 767.5 747.103370696049" style="width: 1.737ex; height: 1.737ex; vertical-align: -0.232ex; margin: 1px 0px;"><g stroke="black" fill="black" stroke-width="0" transform="matrix(1 0 0 -1 0 0)"><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#MJMATHI-55"></use></g></svg></span><script type="math/tex" id="MathJax-Element-7">U</script>的特征表示,<span class="MathJax_Preview"></span><span class="MathJax_SVG" id="MathJax-Element-8-Frame" role="textbox" aria-readonly="true" style="font-size: 100%; display: inline-block;"><svg xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 -704.0516853480245 769.5 747.103370696049" style="width: 1.737ex; height: 1.737ex; vertical-align: -0.232ex; margin: 1px 0px;"><g stroke="black" fill="black" stroke-width="0" transform="matrix(1 0 0 -1 0 0)"><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#MJMATHI-56"></use></g></svg></span><script type="math/tex" id="MathJax-Element-8">V</script>为视频库集合,<span class="MathJax_Preview"></span><span class="MathJax_SVG" id="MathJax-Element-9-Frame" role="textbox" aria-readonly="true" style="font-size: 100%; display: inline-block;"><svg xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 -464.0516853480245 829.8053928999522 642.5886520702876" style="width: 1.969ex; height: 1.506ex; vertical-align: -0.463ex; margin: 1px 0px;"><g stroke="black" fill="black" stroke-width="0" transform="matrix(1 0 0 -1 0 0)"><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#MJMATHI-76"></use><use transform="scale(0.7071067811865476)" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#MJMATHI-69" x="686" y="-213"></use></g></svg></span><script type="math/tex" id="MathJax-Element-9">v_i</script>为视频库中第<span class="MathJax_Preview"></span><span class="MathJax_SVG" id="MathJax-Element-10-Frame" role="textbox" aria-readonly="true" style="font-size: 100%; display: inline-block;"><svg xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 -682.0516853480245 345.5 714.103370696049" style="width: 0.811ex; height: 1.622ex; vertical-align: -0.116ex; margin: 1px 0px;"><g stroke="black" fill="black" stroke-width="0" transform="matrix(1 0 0 -1 0 0)"><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#MJMATHI-69"></use></g></svg></span><script type="math/tex" id="MathJax-Element-10">i</script>个视频的特征表示。<span class="MathJax_Preview"></span><span class="MathJax_SVG" id="MathJax-Element-11-Frame" role="textbox" aria-readonly="true" style="font-size: 100%; display: inline-block;"><svg xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 -463.0516853480245 572.5 495.10337069604896" style="width: 1.274ex; height: 1.158ex; vertical-align: -0.116ex; margin: 1px 0px;"><g stroke="black" fill="black" stroke-width="0" transform="matrix(1 0 0 -1 0 0)"><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#MJMATHI-75"></use></g></svg></span><script type="math/tex" id="MathJax-Element-11">u</script><span class="MathJax_Preview"></span><span class="MathJax_SVG" id="MathJax-Element-12-Frame" role="textbox" aria-readonly="true" style="font-size: 100%; display: inline-block;"><svg xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 -464.0516853480245 829.8053928999522 642.5886520702876" style="width: 1.969ex; height: 1.506ex; vertical-align: -0.463ex; margin: 1px 0px;"><g stroke="black" fill="black" stroke-width="0" transform="matrix(1 0 0 -1 0 0)"><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#MJMATHI-76"></use><use transform="scale(0.7071067811865476)" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#MJMATHI-69" x="686" y="-213"></use></g></svg></span><script type="math/tex" id="MathJax-Element-12">v_i</script>为长度相等的向量,两者点积可以通过全连接层实现。</p><p data-anchor-id="o2y1">考虑到softmax分类的类别数非常多,为了保证一定的计算效率:1)训练阶段,使用负样本类别采样将实际计算的类别数缩小至数千;2)推荐(预测)阶段,忽略softmax的归一化计算(不影响结果),将类别打分问题简化为点积(dot product)空间中的最近邻(nearest neighbor)搜索问题,取与<span class="MathJax_Preview"></span><span class="MathJax_SVG" id="MathJax-Element-13-Frame" role="textbox" aria-readonly="true" style="font-size: 100%; display: inline-block;"><svg xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 -463.0516853480245 572.5 495.10337069604896" style="width: 1.274ex; height: 1.158ex; vertical-align: -0.116ex; margin: 1px 0px;"><g stroke="black" fill="black" stroke-width="0" transform="matrix(1 0 0 -1 0 0)"><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#MJMATHI-75"></use></g></svg></span><script type="math/tex" id="MathJax-Element-13">u</script>最近的<span class="MathJax_Preview"></span><span class="MathJax_SVG" id="MathJax-Element-14-Frame" role="textbox" aria-readonly="true" style="font-size: 100%; display: inline-block;"><svg xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 -715.0516853480245 521.5 747.103370696049" style="width: 1.158ex; height: 1.737ex; vertical-align: -0.116ex; margin: 1px 0px;"><g stroke="black" fill="black" stroke-width="0" transform="matrix(1 0 0 -1 0 0)"><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#MJMATHI-6B"></use></g></svg></span><script type="math/tex" id="MathJax-Element-14">k</script>个视频作为生成的候选。</p><div class="md-section-divider"></div><h4 data-anchor-id="d1va" id="排序网络ranking-network">排序网络(Ranking Network)</h4><p data-anchor-id="veyo">排序网络的结构类似于候选生成网络,但是它的目标是对候选进行更细致的打分排序。和传统广告排序中的特征抽取方法类似,这里也构造了大量的用于视频排序的相关特征(如视频 ID、上次观看时间等)。这些特征的处理方式和候选生成网络类似,不同之处是排序网络的顶部是一个加权逻辑回归(weighted logistic regression),它对所有候选视频进行打分,从高到底排序后将分数较高的一些视频返回给用户。</p><div class="md-section-divider"></div><h3 data-anchor-id="oa0y" id="融合推荐模型">融合推荐模型</h3><p data-anchor-id="2h2q">在下文的电影推荐系统中:</p><ol data-anchor-id="bmth">
<li><p>首先,使用用户特征和电影特征作为神经网络的输入,其中:</p>

<ul><li><p>用户特征融合了四个属性信息,分别是用户ID、性别、职业和年龄。</p></li>
<li><p>电影特征融合了三个属性信息,分别是电影ID、电影类型ID和电影名称。</p></li></ul></li>
<li><p>对用户特征,将用户ID映射为维度大小为256的向量表示,输入全连接层,并对其他三个属性也做类似的处理。然后将四个属性的特征表示分别全连接并相加。</p></li>
<li><p>对电影特征,将电影ID以类似用户ID的方式进行处理,电影类型ID以向量的形式直接输入全连接层,电影名称用文本卷积神经网络(详见<a href="https://github.com/PaddlePaddle/book/blob/develop/understand_sentiment/README.md" target="_blank">第5章</a>)得到其定长向量表示。然后将三个属性的特征表示分别全连接并相加。</p></li>
<li><p>得到用户和电影的向量表示后,计算二者的余弦相似度作为推荐系统的打分。最后,用该相似度打分和用户真实打分的差异的平方作为该回归模型的损失函数。</p></li>
</ol><p align="center" data-anchor-id="frqc">
<img src="https://raw.githubusercontent.com/PaddlePaddle/book/develop/recommender_system/image/rec_regression_network.png" width="700"><br>
图3. 融合推荐模型 
</p><div class="md-section-divider"></div><h2 data-anchor-id="qce9" id="数据准备">数据准备</h2><div class="md-section-divider"></div><h3 data-anchor-id="ubvc" id="数据介绍与下载">数据介绍与下载</h3><p data-anchor-id="f1od">我们以 <a href="http://files.grouplens.org/datasets/movielens/ml-1m.zip" target="_blank">MovieLens 百万数据集(ml-1m)</a>为例进行介绍。ml-1m 数据集包含了 6,000 位用户对 4,000 部电影的 1,000,000 条评价(评分范围 1~5 分,均为整数),由 GroupLens Research 实验室搜集整理。</p><p data-anchor-id="t7tr">您可以运行 <code>data/getdata.sh</code> 下载数据,如果数椐获取成功,您将在目录<code>data/ml-1m</code>中看到下面的文件:</p><div class="md-section-divider"></div><pre class="prettyprint linenums prettyprinted" data-anchor-id="gyqy"><ol class="linenums"><li class="L0"><code><span class="pln">movies</span><span class="pun">.</span><span class="pln">dat  ratings</span><span class="pun">.</span><span class="pln">dat  users</span><span class="pun">.</span><span class="pln">dat  README </span></code></li></ol></pre><ul data-anchor-id="n72h">
<li>movies.dat:电影特征数据,格式为<code>电影ID::电影名称::电影类型</code></li>
<li>ratings.dat:评分数据,格式为<code>用户ID::电影ID::评分::时间戳</code></li>
<li>users.dat:用户特征数据,格式为<code>用户ID::性别::年龄::职业::邮编</code></li>
<li>README:数据集的详细描述</li>
</ul><div class="md-section-divider"></div><h3 data-anchor-id="lnbp" id="数据预处理">数据预处理</h3><p data-anchor-id="nn2k">首先安装 Python 第三方库(推荐使用 Virtualenv):</p><div class="md-section-divider"></div><pre class="prettyprint linenums prettyprinted" data-anchor-id="1pnx"><ol class="linenums"><li class="L0"><code class="language-shell"><span class="pln">pip install </span><span class="pun">-</span><span class="pln">r data</span><span class="pun">/</span><span class="pln">requirements</span><span class="pun">.</span><span class="pln">txt</span></code></li></ol></pre><p data-anchor-id="qyxa">其次在预处理<code>./preprocess.sh</code>过程中,我们将字段配置文件<code>data/config.json</code>转化为meta配置文件<code>meta_config.json</code>,并生成对应的meta文件<code>meta.bin</code>,以完成数据文件的序列化。然后再将<code>ratings.dat</code>分为训练集、测试集两部分,把它们的地址写入<code>train.list</code><code>test.list</code></p><p data-anchor-id="nom2">运行成功后目录<code>./data</code> 新增以下文件:</p><div class="md-section-divider"></div><pre class="prettyprint linenums prettyprinted" data-anchor-id="77p2"><ol class="linenums"><li class="L0"><code><span class="pln">meta_config</span><span class="pun">.</span><span class="pln">json  meta</span><span class="pun">.</span><span class="pln">bin  ratings</span><span class="pun">.</span><span class="pln">dat</span><span class="pun">.</span><span class="pln">train  ratings</span><span class="pun">.</span><span class="pln">dat</span><span class="pun">.</span><span class="pln">test  train</span><span class="pun">.</span><span class="pln">list  test</span><span class="pun">.</span><span class="pln">list</span></code></li></ol></pre><ul data-anchor-id="3j2u">
<li>meta.bin: meta文件是Python的pickle对象, 存储着电影和用户信息。</li>
<li>meta_config.json: meta配置文件,用来具体描述如何解析数据集中的每一个字段,由字段配置文件生成。</li>
<li>ratings.dat.train和ratings.dat.test: 训练集和测试集,训练集已经随机打乱。</li>
<li>train.list和test.list: 训练集和测试集的文件地址列表。</li>
</ul><div class="md-section-divider"></div><h3 data-anchor-id="fcqm" id="提供数据给-paddlepaddle">提供数据给 PaddlePaddle</h3><p data-anchor-id="50df">我们使用 Python 接口传递数据给系统,下面 <code>dataprovider.py</code> 给出了完整示例。</p><div class="md-section-divider"></div><pre class="prettyprint linenums prettyprinted" data-anchor-id="qzcv"><ol class="linenums"><li class="L0"><code class="language-python"><span class="kwd">from</span><span class="pln"> paddle</span><span class="pun">.</span><span class="pln">trainer</span><span class="pun">.</span><span class="typ">PyDataProvider2</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> </span><span class="pun">*</span></code></li><li class="L1"><code class="language-python"><span class="kwd">from</span><span class="pln"> common_utils </span><span class="kwd">import</span><span class="pln"> meta_to_header</span></code></li><li class="L2"><code class="language-python"></code></li><li class="L3"><code class="language-python"><span class="kwd">def</span><span class="pln"> __list_to_map__</span><span class="pun">(</span><span class="pln">lst</span><span class="pun">):</span><span class="pln">  </span><span class="com"># 将list转为map</span></code></li><li class="L4"><code class="language-python"><span class="pln">    ret_val </span><span class="pun">=</span><span class="pln"> dict</span><span class="pun">()</span></code></li><li class="L5"><code class="language-python"><span class="pln">    </span><span class="kwd">for</span><span class="pln"> each </span><span class="kwd">in</span><span class="pln"> lst</span><span class="pun">:</span></code></li><li class="L6"><code class="language-python"><span class="pln">        k</span><span class="pun">,</span><span class="pln"> v </span><span class="pun">=</span><span class="pln"> each</span></code></li><li class="L7"><code class="language-python"><span class="pln">        ret_val</span><span class="pun">[</span><span class="pln">k</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> v</span></code></li><li class="L8"><code class="language-python"><span class="pln">    </span><span class="kwd">return</span><span class="pln"> ret_val</span></code></li><li class="L9"><code class="language-python"></code></li><li class="L0"><code class="language-python"><span class="kwd">def</span><span class="pln"> hook</span><span class="pun">(</span><span class="pln">settings</span><span class="pun">,</span><span class="pln"> meta</span><span class="pun">,</span><span class="pln"> </span><span class="pun">**</span><span class="pln">kwargs</span><span class="pun">):</span><span class="pln"> </span><span class="com"># 读取meta.bin</span></code></li><li class="L1"><code class="language-python"><span class="pln">    </span><span class="com"># 定义电影特征</span></code></li><li class="L2"><code class="language-python"><span class="pln">    movie_headers </span><span class="pun">=</span><span class="pln"> list</span><span class="pun">(</span><span class="pln">meta_to_header</span><span class="pun">(</span><span class="pln">meta</span><span class="pun">,</span><span class="pln"> </span><span class="str">'movie'</span><span class="pun">))</span></code></li><li class="L3"><code class="language-python"><span class="pln">    settings</span><span class="pun">.</span><span class="pln">movie_names </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">h</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]</span><span class="pln"> </span><span class="kwd">for</span><span class="pln"> h </span><span class="kwd">in</span><span class="pln"> movie_headers</span><span class="pun">]</span></code></li><li class="L4"><code class="language-python"><span class="pln">    headers </span><span class="pun">=</span><span class="pln"> movie_headers</span></code></li><li class="L5"><code class="language-python"></code></li><li class="L6"><code class="language-python"><span class="pln">    </span><span class="com"># 定义用户特征</span></code></li><li class="L7"><code class="language-python"><span class="pln">    user_headers </span><span class="pun">=</span><span class="pln"> list</span><span class="pun">(</span><span class="pln">meta_to_header</span><span class="pun">(</span><span class="pln">meta</span><span class="pun">,</span><span class="pln"> </span><span class="str">'user'</span><span class="pun">))</span></code></li><li class="L8"><code class="language-python"><span class="pln">    settings</span><span class="pun">.</span><span class="pln">user_names </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">h</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]</span><span class="pln"> </span><span class="kwd">for</span><span class="pln"> h </span><span class="kwd">in</span><span class="pln"> user_headers</span><span class="pun">]</span></code></li><li class="L9"><code class="language-python"><span class="pln">    headers</span><span class="pun">.</span><span class="pln">extend</span><span class="pun">(</span><span class="pln">user_headers</span><span class="pun">)</span></code></li><li class="L0"><code class="language-python"></code></li><li class="L1"><code class="language-python"><span class="pln">    </span><span class="com"># 加载评分信息</span></code></li><li class="L2"><code class="language-python"><span class="pln">    headers</span><span class="pun">.</span><span class="pln">append</span><span class="pun">((</span><span class="str">"rating"</span><span class="pun">,</span><span class="pln"> dense_vector</span><span class="pun">(</span><span class="lit">1</span><span class="pun">)))</span></code></li><li class="L3"><code class="language-python"></code></li><li class="L4"><code class="language-python"><span class="pln">    settings</span><span class="pun">.</span><span class="pln">input_types </span><span class="pun">=</span><span class="pln"> __list_to_map__</span><span class="pun">(</span><span class="pln">headers</span><span class="pun">)</span></code></li><li class="L5"><code class="language-python"><span class="pln">    settings</span><span class="pun">.</span><span class="pln">meta </span><span class="pun">=</span><span class="pln"> meta</span></code></li><li class="L6"><code class="language-python"></code></li><li class="L7"><code class="language-python"><span class="lit">@provider</span><span class="pun">(</span><span class="pln">init_hook</span><span class="pun">=</span><span class="pln">hook</span><span class="pun">,</span><span class="pln"> cache</span><span class="pun">=</span><span class="typ">CacheType</span><span class="pun">.</span><span class="pln">CACHE_PASS_IN_MEM</span><span class="pun">)</span></code></li><li class="L8"><code class="language-python"><span class="kwd">def</span><span class="pln"> process</span><span class="pun">(</span><span class="pln">settings</span><span class="pun">,</span><span class="pln"> filename</span><span class="pun">):</span></code></li><li class="L9"><code class="language-python"><span class="pln">    </span><span class="kwd">with</span><span class="pln"> open</span><span class="pun">(</span><span class="pln">filename</span><span class="pun">,</span><span class="pln"> </span><span class="str">'r'</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">as</span><span class="pln"> f</span><span class="pun">:</span></code></li><li class="L0"><code class="language-python"><span class="pln">        </span><span class="kwd">for</span><span class="pln"> line </span><span class="kwd">in</span><span class="pln"> f</span><span class="pun">:</span></code></li><li class="L1"><code class="language-python"><span class="pln">            </span><span class="com"># 从评分文件中读取评分</span></code></li><li class="L2"><code class="language-python"><span class="pln">            user_id</span><span class="pun">,</span><span class="pln"> movie_id</span><span class="pun">,</span><span class="pln"> score </span><span class="pun">=</span><span class="pln"> map</span><span class="pun">(</span><span class="pln">int</span><span class="pun">,</span><span class="pln"> line</span><span class="pun">.</span><span class="pln">split</span><span class="pun">(</span><span class="str">'::'</span><span class="pun">)[:-</span><span class="lit">1</span><span class="pun">])</span></code></li><li class="L3"><code class="language-python"><span class="pln">            </span><span class="com"># 将评分平移到[-2, +2]范围内的整数</span></code></li><li class="L4"><code class="language-python"><span class="pln">            score </span><span class="pun">=</span><span class="pln"> float</span><span class="pun">(</span><span class="pln">score </span><span class="pun">-</span><span class="pln"> </span><span class="lit">3</span><span class="pun">)</span></code></li><li class="L5"><code class="language-python"></code></li><li class="L6"><code class="language-python"><span class="pln">            movie_meta </span><span class="pun">=</span><span class="pln"> settings</span><span class="pun">.</span><span class="pln">meta</span><span class="pun">[</span><span class="str">'movie'</span><span class="pun">][</span><span class="pln">movie_id</span><span class="pun">]</span></code></li><li class="L7"><code class="language-python"><span class="pln">            user_meta </span><span class="pun">=</span><span class="pln"> settings</span><span class="pun">.</span><span class="pln">meta</span><span class="pun">[</span><span class="str">'user'</span><span class="pun">][</span><span class="pln">user_id</span><span class="pun">]</span></code></li><li class="L8"><code class="language-python"></code></li><li class="L9"><code class="language-python"><span class="pln">            </span><span class="com"># 添加电影ID与电影特征</span></code></li><li class="L0"><code class="language-python"><span class="pln">            outputs </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[(</span><span class="str">'movie_id'</span><span class="pun">,</span><span class="pln"> movie_id </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)]</span></code></li><li class="L1"><code class="language-python"><span class="pln">            </span><span class="kwd">for</span><span class="pln"> i</span><span class="pun">,</span><span class="pln"> each_meta </span><span class="kwd">in</span><span class="pln"> enumerate</span><span class="pun">(</span><span class="pln">movie_meta</span><span class="pun">):</span></code></li><li class="L2"><code class="language-python"><span class="pln">                outputs</span><span class="pun">.</span><span class="pln">append</span><span class="pun">((</span><span class="pln">settings</span><span class="pun">.</span><span class="pln">movie_names</span><span class="pun">[</span><span class="pln">i </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">],</span><span class="pln"> each_meta</span><span class="pun">))</span></code></li><li class="L3"><code class="language-python"></code></li><li class="L4"><code class="language-python"><span class="pln">            </span><span class="com"># 添加用户ID与用户特征</span></code></li><li class="L5"><code class="language-python"><span class="pln">            outputs</span><span class="pun">.</span><span class="pln">append</span><span class="pun">((</span><span class="str">'user_id'</span><span class="pun">,</span><span class="pln"> user_id </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pun">))</span></code></li><li class="L6"><code class="language-python"><span class="pln">            </span><span class="kwd">for</span><span class="pln"> i</span><span class="pun">,</span><span class="pln"> each_meta </span><span class="kwd">in</span><span class="pln"> enumerate</span><span class="pun">(</span><span class="pln">user_meta</span><span class="pun">):</span></code></li><li class="L7"><code class="language-python"><span class="pln">                outputs</span><span class="pun">.</span><span class="pln">append</span><span class="pun">((</span><span class="pln">settings</span><span class="pun">.</span><span class="pln">user_names</span><span class="pun">[</span><span class="pln">i </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">],</span><span class="pln"> each_meta</span><span class="pun">))</span></code></li><li class="L8"><code class="language-python"></code></li><li class="L9"><code class="language-python"><span class="pln">            </span><span class="com"># 添加评分</span></code></li><li class="L0"><code class="language-python"><span class="pln">            outputs</span><span class="pun">.</span><span class="pln">append</span><span class="pun">((</span><span class="str">'rating'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">[</span><span class="pln">score</span><span class="pun">]))</span></code></li><li class="L1"><code class="language-python"><span class="pln">            </span><span class="com"># 将数据返回给 paddle</span></code></li><li class="L2"><code class="language-python"><span class="pln">            </span><span class="kwd">yield</span><span class="pln"> __list_to_map__</span><span class="pun">(</span><span class="pln">outputs</span><span class="pun">)</span></code></li></ol></pre><div class="md-section-divider"></div><h2 data-anchor-id="kqr2" id="模型配置说明">模型配置说明</h2><div class="md-section-divider"></div><h3 data-anchor-id="lurj" id="数据定义">数据定义</h3><p data-anchor-id="irta">加载<code>meta.bin</code>文件并定义通过<code>define_py_data_sources2</code>从dataprovider中读入数据:</p><div class="md-section-divider"></div><pre class="prettyprint linenums prettyprinted" data-anchor-id="szqz"><ol class="linenums"><li class="L0"><code class="language-python"><span class="kwd">from</span><span class="pln"> paddle</span><span class="pun">.</span><span class="pln">trainer_config_helpers </span><span class="kwd">import</span><span class="pln"> </span><span class="pun">*</span></code></li><li class="L1"><code class="language-python"></code></li><li class="L2"><code class="language-python"><span class="kwd">try</span><span class="pun">:</span></code></li><li class="L3"><code class="language-python"><span class="pln">    </span><span class="kwd">import</span><span class="pln"> cPickle </span><span class="kwd">as</span><span class="pln"> pickle</span></code></li><li class="L4"><code class="language-python"><span class="kwd">except</span><span class="pln"> </span><span class="typ">ImportError</span><span class="pun">:</span></code></li><li class="L5"><code class="language-python"><span class="pln">    </span><span class="kwd">import</span><span class="pln"> pickle</span></code></li><li class="L6"><code class="language-python"></code></li><li class="L7"><code class="language-python"><span class="pln">is_predict </span><span class="pun">=</span><span class="pln"> get_config_arg</span><span class="pun">(</span><span class="str">'is_predict'</span><span class="pun">,</span><span class="pln"> bool</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">False</span><span class="pun">)</span></code></li><li class="L8"><code class="language-python"></code></li><li class="L9"><code class="language-python"><span class="pln">META_FILE </span><span class="pun">=</span><span class="pln"> </span><span class="str">'data/meta.bin'</span></code></li><li class="L0"><code class="language-python"></code></li><li class="L1"><code class="language-python"><span class="com"># 加载 meta 文件</span></code></li><li class="L2"><code class="language-python"><span class="kwd">with</span><span class="pln"> open</span><span class="pun">(</span><span class="pln">META_FILE</span><span class="pun">,</span><span class="pln"> </span><span class="str">'rb'</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">as</span><span class="pln"> f</span><span class="pun">:</span></code></li><li class="L3"><code class="language-python"><span class="pln">    meta </span><span class="pun">=</span><span class="pln"> pickle</span><span class="pun">.</span><span class="pln">load</span><span class="pun">(</span><span class="pln">f</span><span class="pun">)</span></code></li><li class="L4"><code class="language-python"></code></li><li class="L5"><code class="language-python"><span class="kwd">if</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> is_predict</span><span class="pun">:</span></code></li><li class="L6"><code class="language-python"><span class="pln">    define_py_data_sources2</span><span class="pun">(</span></code></li><li class="L7"><code class="language-python"><span class="pln">        </span><span class="str">'data/train.list'</span><span class="pun">,</span></code></li><li class="L8"><code class="language-python"><span class="pln">        </span><span class="str">'data/test.list'</span><span class="pun">,</span></code></li><li class="L9"><code class="language-python"><span class="pln">        module</span><span class="pun">=</span><span class="str">'dataprovider'</span><span class="pun">,</span></code></li><li class="L0"><code class="language-python"><span class="pln">        obj</span><span class="pun">=</span><span class="str">'process'</span><span class="pun">,</span></code></li><li class="L1"><code class="language-python"><span class="pln">        args</span><span class="pun">={</span><span class="str">'meta'</span><span class="pun">:</span><span class="pln"> meta</span><span class="pun">})</span></code></li></ol></pre><div class="md-section-divider"></div><h3 data-anchor-id="uzsr" id="算法配置">算法配置</h3><p data-anchor-id="ek1r">这里我们设置了batch size、网络初始学习率和RMSProp自适应优化方法。</p><div class="md-section-divider"></div><pre class="prettyprint linenums prettyprinted" data-anchor-id="bg79"><ol class="linenums"><li class="L0"><code class="language-python"><span class="pln">settings</span><span class="pun">(</span></code></li><li class="L1"><code class="language-python"><span class="pln">    batch_size</span><span class="pun">=</span><span class="lit">1600</span><span class="pun">,</span><span class="pln"> learning_rate</span><span class="pun">=</span><span class="lit">1e-3</span><span class="pun">,</span><span class="pln"> learning_method</span><span class="pun">=</span><span class="typ">RMSPropOptimizer</span><span class="pun">())</span></code></li></ol></pre><div class="md-section-divider"></div><h3 data-anchor-id="km6i" id="模型结构">模型结构</h3><ol data-anchor-id="e135">
<li><p>定义数据输入和参数维度。</p>

<pre class="prettyprint linenums prettyprinted"><ol class="linenums"><li class="L0"><code class="language-python"><span class="pln">movie_meta </span><span class="pun">=</span><span class="pln"> meta</span><span class="pun">[</span><span class="str">'movie'</span><span class="pun">][</span><span class="str">'__meta__'</span><span class="pun">][</span><span class="str">'raw_meta'</span><span class="pun">]</span></code></li><li class="L1"><code class="language-python"><span class="pln">user_meta </span><span class="pun">=</span><span class="pln"> meta</span><span class="pun">[</span><span class="str">'user'</span><span class="pun">][</span><span class="str">'__meta__'</span><span class="pun">][</span><span class="str">'raw_meta'</span><span class="pun">]</span></code></li><li class="L2"><code class="language-python"></code></li><li class="L3"><code class="language-python"><span class="pln">movie_id </span><span class="pun">=</span><span class="pln"> data_layer</span><span class="pun">(</span><span class="str">'movie_id'</span><span class="pun">,</span><span class="pln"> size</span><span class="pun">=</span><span class="pln">movie_meta</span><span class="pun">[</span><span class="lit">0</span><span class="pun">][</span><span class="str">'max'</span><span class="pun">])</span><span class="pln">    </span><span class="com"># 电影ID</span></code></li><li class="L4"><code class="language-python"><span class="pln">title </span><span class="pun">=</span><span class="pln"> data_layer</span><span class="pun">(</span><span class="str">'title'</span><span class="pun">,</span><span class="pln"> size</span><span class="pun">=</span><span class="pln">len</span><span class="pun">(</span><span class="pln">movie_meta</span><span class="pun">[</span><span class="lit">1</span><span class="pun">][</span><span class="str">'dict'</span><span class="pun">]))</span><span class="pln">    </span><span class="com"># 电影名称</span></code></li><li class="L5"><code class="language-python"><span class="pln">genres </span><span class="pun">=</span><span class="pln"> data_layer</span><span class="pun">(</span><span class="str">'genres'</span><span class="pun">,</span><span class="pln"> size</span><span class="pun">=</span><span class="pln">len</span><span class="pun">(</span><span class="pln">movie_meta</span><span class="pun">[</span><span class="lit">2</span><span class="pun">][</span><span class="str">'dict'</span><span class="pun">]))</span><span class="pln">  </span><span class="com"># 电影类型</span></code></li><li class="L6"><code class="language-python"><span class="pln">user_id </span><span class="pun">=</span><span class="pln"> data_layer</span><span class="pun">(</span><span class="str">'user_id'</span><span class="pun">,</span><span class="pln"> size</span><span class="pun">=</span><span class="pln">user_meta</span><span class="pun">[</span><span class="lit">0</span><span class="pun">][</span><span class="str">'max'</span><span class="pun">])</span><span class="pln">        </span><span class="com"># 用户ID</span></code></li><li class="L7"><code class="language-python"><span class="pln">gender </span><span class="pun">=</span><span class="pln"> data_layer</span><span class="pun">(</span><span class="str">'gender'</span><span class="pun">,</span><span class="pln"> size</span><span class="pun">=</span><span class="pln">len</span><span class="pun">(</span><span class="pln">user_meta</span><span class="pun">[</span><span class="lit">1</span><span class="pun">][</span><span class="str">'dict'</span><span class="pun">]))</span><span class="pln">   </span><span class="com"># 用户性别</span></code></li><li class="L8"><code class="language-python"><span class="pln">age </span><span class="pun">=</span><span class="pln"> data_layer</span><span class="pun">(</span><span class="str">'age'</span><span class="pun">,</span><span class="pln"> size</span><span class="pun">=</span><span class="pln">len</span><span class="pun">(</span><span class="pln">user_meta</span><span class="pun">[</span><span class="lit">2</span><span class="pun">][</span><span class="str">'dict'</span><span class="pun">]))</span><span class="pln">          </span><span class="com"># 用户年龄</span></code></li><li class="L9"><code class="language-python"><span class="pln">occupation </span><span class="pun">=</span><span class="pln"> data_layer</span><span class="pun">(</span><span class="str">'occupation'</span><span class="pun">,</span><span class="pln"> size</span><span class="pun">=</span><span class="pln">len</span><span class="pun">(</span><span class="pln">user_meta</span><span class="pun">[</span><span class="lit">3</span><span class="pun">][</span><span class="str">'dict'</span><span class="pun">]))</span><span class="pln"> </span><span class="com"># 用户职业</span></code></li><li class="L0"><code class="language-python"></code></li><li class="L1"><code class="language-python"><span class="pln">embsize </span><span class="pun">=</span><span class="pln"> </span><span class="lit">256</span><span class="pln">  </span><span class="com"># 向量维度</span></code></li></ol></pre></li>
<li><p>构造“电影”特征。</p>

<pre class="prettyprint linenums prettyprinted"><ol class="linenums"><li class="L0"><code class="language-python"></code></li><li class="L1"><code class="language-python"><span class="com"># 电影ID和电影类型分别映射到其对应的特征隐层(256维)。</span></code></li><li class="L2"><code class="language-python"></code></li><li class="L3"><code class="language-python"><span class="pln">movie_id_emb </span><span class="pun">=</span><span class="pln"> embedding_layer</span><span class="pun">(</span><span class="pln">input</span><span class="pun">=</span><span class="pln">movie_id</span><span class="pun">,</span><span class="pln"> size</span><span class="pun">=</span><span class="pln">embsize</span><span class="pun">)</span></code></li><li class="L4"><code class="language-python"><span class="pln">movie_id_hidden </span><span class="pun">=</span><span class="pln"> fc_layer</span><span class="pun">(</span><span class="pln">input</span><span class="pun">=</span><span class="pln">movie_id_emb</span><span class="pun">,</span><span class="pln"> size</span><span class="pun">=</span><span class="pln">embsize</span><span class="pun">)</span></code></li><li class="L5"><code class="language-python"></code></li><li class="L6"><code class="language-python"><span class="pln">genres_emb </span><span class="pun">=</span><span class="pln"> fc_layer</span><span class="pun">(</span><span class="pln">input</span><span class="pun">=</span><span class="pln">genres</span><span class="pun">,</span><span class="pln"> size</span><span class="pun">=</span><span class="pln">embsize</span><span class="pun">)</span></code></li><li class="L7"><code class="language-python"></code></li><li class="L8"><code class="language-python"></code></li><li class="L9"><code class="language-python"><span class="com"># 对于电影名称,一个ID序列表示的词语序列,在输入卷积层后,</span></code></li><li class="L0"><code class="language-python"></code></li><li class="L1"><code class="language-python"></code></li><li class="L2"><code class="language-python"><span class="com"># 将得到每个时间窗口的特征(序列特征),然后通过在时间维度</span></code></li><li class="L3"><code class="language-python"></code></li><li class="L4"><code class="language-python"></code></li><li class="L5"><code class="language-python"><span class="com"># 降采样得到固定维度的特征,整个过程在text_conv_pool实现</span></code></li><li class="L6"><code class="language-python"></code></li><li class="L7"><code class="language-python"><span class="pln">title_emb </span><span class="pun">=</span><span class="pln"> embedding_layer</span><span class="pun">(</span><span class="pln">input</span><span class="pun">=</span><span class="pln">title</span><span class="pun">,</span><span class="pln"> size</span><span class="pun">=</span><span class="pln">embsize</span><span class="pun">)</span></code></li><li class="L8"><code class="language-python"><span class="pln">title_hidden </span><span class="pun">=</span><span class="pln"> text_conv_pool</span><span class="pun">(</span></code></li><li class="L9"><code class="language-python"><span class="pln">   input</span><span class="pun">=</span><span class="pln">title_emb</span><span class="pun">,</span><span class="pln"> context_len</span><span class="pun">=</span><span class="lit">5</span><span class="pun">,</span><span class="pln"> hidden_size</span><span class="pun">=</span><span class="pln">embsize</span><span class="pun">)</span></code></li><li class="L0"><code class="language-python"></code></li><li class="L1"><code class="language-python"></code></li><li class="L2"><code class="language-python"><span class="com"># 将三个属性的特征表示分别全连接并相加,结果即是电影特征的最终表示</span></code></li><li class="L3"><code class="language-python"></code></li><li class="L4"><code class="language-python"><span class="pln">movie_feature </span><span class="pun">=</span><span class="pln"> fc_layer</span><span class="pun">(</span></code></li><li class="L5"><code class="language-python"><span class="pln">   input</span><span class="pun">=[</span><span class="pln">movie_id_hidden</span><span class="pun">,</span><span class="pln"> title_hidden</span><span class="pun">,</span><span class="pln"> genres_emb</span><span class="pun">],</span><span class="pln"> size</span><span class="pun">=</span><span class="pln">embsize</span><span class="pun">)</span></code></li></ol></pre></li>
<li><p>构造“用户”特征。</p>

<pre class="prettyprint linenums prettyprinted"><ol class="linenums"><li class="L0"><code class="language-python"></code></li><li class="L1"><code class="language-python"><span class="com"># 将用户ID,性别,职业,年龄四个属性分别映射到其特征隐层。</span></code></li><li class="L2"><code class="language-python"></code></li><li class="L3"><code class="language-python"><span class="pln">user_id_emb </span><span class="pun">=</span><span class="pln"> embedding_layer</span><span class="pun">(</span><span class="pln">input</span><span class="pun">=</span><span class="pln">user_id</span><span class="pun">,</span><span class="pln"> size</span><span class="pun">=</span><span class="pln">embsize</span><span class="pun">)</span></code></li><li class="L4"><code class="language-python"><span class="pln">user_id_hidden </span><span class="pun">=</span><span class="pln"> fc_layer</span><span class="pun">(</span><span class="pln">input</span><span class="pun">=</span><span class="pln">user_id_emb</span><span class="pun">,</span><span class="pln"> size</span><span class="pun">=</span><span class="pln">embsize</span><span class="pun">)</span></code></li><li class="L5"><code class="language-python"></code></li><li class="L6"><code class="language-python"><span class="pln">gender_emb </span><span class="pun">=</span><span class="pln"> embedding_layer</span><span class="pun">(</span><span class="pln">input</span><span class="pun">=</span><span class="pln">gender</span><span class="pun">,</span><span class="pln"> size</span><span class="pun">=</span><span class="pln">embsize</span><span class="pun">)</span></code></li><li class="L7"><code class="language-python"><span class="pln">gender_hidden </span><span class="pun">=</span><span class="pln"> fc_layer</span><span class="pun">(</span><span class="pln">input</span><span class="pun">=</span><span class="pln">gender_emb</span><span class="pun">,</span><span class="pln"> size</span><span class="pun">=</span><span class="pln">embsize</span><span class="pun">)</span></code></li><li class="L8"><code class="language-python"></code></li><li class="L9"><code class="language-python"><span class="pln">age_emb </span><span class="pun">=</span><span class="pln"> embedding_layer</span><span class="pun">(</span><span class="pln">input</span><span class="pun">=</span><span class="pln">age</span><span class="pun">,</span><span class="pln"> size</span><span class="pun">=</span><span class="pln">embsize</span><span class="pun">)</span></code></li><li class="L0"><code class="language-python"><span class="pln">age_hidden </span><span class="pun">=</span><span class="pln"> fc_layer</span><span class="pun">(</span><span class="pln">input</span><span class="pun">=</span><span class="pln">age_emb</span><span class="pun">,</span><span class="pln"> size</span><span class="pun">=</span><span class="pln">embsize</span><span class="pun">)</span></code></li><li class="L1"><code class="language-python"></code></li><li class="L2"><code class="language-python"><span class="pln">occup_emb </span><span class="pun">=</span><span class="pln"> embedding_layer</span><span class="pun">(</span><span class="pln">input</span><span class="pun">=</span><span class="pln">occupation</span><span class="pun">,</span><span class="pln"> size</span><span class="pun">=</span><span class="pln">embsize</span><span class="pun">)</span></code></li><li class="L3"><code class="language-python"><span class="pln">occup_hidden </span><span class="pun">=</span><span class="pln"> fc_layer</span><span class="pun">(</span><span class="pln">input</span><span class="pun">=</span><span class="pln">occup_emb</span><span class="pun">,</span><span class="pln"> size</span><span class="pun">=</span><span class="pln">embsize</span><span class="pun">)</span></code></li><li class="L4"><code class="language-python"></code></li><li class="L5"><code class="language-python"></code></li><li class="L6"><code class="language-python"><span class="com"># 同样将这四个属性分别全连接并相加形成用户特征的最终表示。</span></code></li><li class="L7"><code class="language-python"></code></li><li class="L8"><code class="language-python"><span class="pln">user_feature </span><span class="pun">=</span><span class="pln"> fc_layer</span><span class="pun">(</span></code></li><li class="L9"><code class="language-python"><span class="pln">   input</span><span class="pun">=[</span><span class="pln">user_id_hidden</span><span class="pun">,</span><span class="pln"> gender_hidden</span><span class="pun">,</span><span class="pln"> age_hidden</span><span class="pun">,</span><span class="pln"> occup_hidden</span><span class="pun">],</span></code></li><li class="L0"><code class="language-python"><span class="pln">   size</span><span class="pun">=</span><span class="pln">embsize</span><span class="pun">)</span></code></li></ol></pre></li>
<li><p>计算余弦相似度,定义损失函数和网络输出。</p>

<pre class="prettyprint linenums prettyprinted"><ol class="linenums"><li class="L0"><code class="language-python"><span class="pln">similarity </span><span class="pun">=</span><span class="pln"> cos_sim</span><span class="pun">(</span><span class="pln">a</span><span class="pun">=</span><span class="pln">movie_feature</span><span class="pun">,</span><span class="pln"> b</span><span class="pun">=</span><span class="pln">user_feature</span><span class="pun">,</span><span class="pln"> scale</span><span class="pun">=</span><span class="lit">2</span><span class="pun">)</span></code></li><li class="L1"><code class="language-python"></code></li><li class="L2"><code class="language-python"></code></li><li class="L3"><code class="language-python"><span class="com"># 训练时,采用regression_cost作为损失函数计算回归误差代价,并作为网络的输出。</span></code></li><li class="L4"><code class="language-python"></code></li><li class="L5"><code class="language-python"></code></li><li class="L6"><code class="language-python"><span class="com"># 预测时,网络的输出即为余弦相似度。</span></code></li><li class="L7"><code class="language-python"></code></li><li class="L8"><code class="language-python"><span class="kwd">if</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> is_predict</span><span class="pun">:</span></code></li><li class="L9"><code class="language-python"><span class="pln">   lbl</span><span class="pun">=</span><span class="pln">data_layer</span><span class="pun">(</span><span class="str">'rating'</span><span class="pun">,</span><span class="pln"> size</span><span class="pun">=</span><span class="lit">1</span><span class="pun">)</span></code></li><li class="L0"><code class="language-python"><span class="pln">cost</span><span class="pun">=</span><span class="pln">regression_cost</span><span class="pun">(</span><span class="pln">input</span><span class="pun">=</span><span class="pln">similarity</span><span class="pun">,</span><span class="pln"> label</span><span class="pun">=</span><span class="pln">lbl</span><span class="pun">)</span></code></li><li class="L1"><code class="language-python"><span class="pln">outputs</span><span class="pun">(</span><span class="pln">cost</span><span class="pun">)</span></code></li><li class="L2"><code class="language-python"><span class="kwd">else</span><span class="pun">:</span></code></li><li class="L3"><code class="language-python"><span class="pln">   outputs</span><span class="pun">(</span><span class="pln">similarity</span><span class="pun">)</span></code></li></ol></pre></li>
</ol><div class="md-section-divider"></div><h2 data-anchor-id="4oba" id="训练模型">训练模型</h2><p data-anchor-id="egsb">执行<code>sh train.sh</code> 开始训练模型,将日志写入文件 <code>log.txt</code> 并打印在屏幕上。其中指定了总共需要执行 50 个pass。</p><div class="md-section-divider"></div><pre class="prettyprint linenums prettyprinted" data-anchor-id="vmzb"><ol class="linenums"><li class="L0"><code class="language-shell"><span class="kwd">set</span><span class="pln"> </span><span class="pun">-</span><span class="pln">e</span></code></li><li class="L1"><code class="language-shell"><span class="pln">paddle train \</span></code></li><li class="L2"><code class="language-shell"><span class="pln">    </span><span class="pun">--</span><span class="pln">config</span><span class="pun">=</span><span class="pln">trainer_config</span><span class="pun">.</span><span class="pln">py \         </span><span class="com"># 神经网络配置文件</span></code></li><li class="L3"><code class="language-shell"><span class="pln">    </span><span class="pun">--</span><span class="pln">save_dir</span><span class="pun">=./</span><span class="pln">output \                </span><span class="com"># 模型保存路径</span></code></li><li class="L4"><code class="language-shell"><span class="pln">    </span><span class="pun">--</span><span class="pln">use_gpu</span><span class="pun">=</span><span class="kwd">false</span><span class="pln"> \                    </span><span class="com"># 是否使用GPU(默认不使用)</span></code></li><li class="L5"><code class="language-shell"><span class="pln">    </span><span class="pun">--</span><span class="pln">trainer_count</span><span class="pun">=</span><span class="lit">4</span><span class="pln">\                   </span><span class="com"># 一台机器上面的线程数量</span></code></li><li class="L6"><code class="language-shell"><span class="pln">    </span><span class="pun">--</span><span class="pln">test_all_data_in_one_period</span><span class="pun">=</span><span class="kwd">true</span><span class="pln"> \ </span><span class="com"># 每个训练周期训练一次所有数据,否则每个训练周期测试batch_size个batch数据</span></code></li><li class="L7"><code class="language-shell"><span class="pln">    </span><span class="pun">--</span><span class="pln">log_period</span><span class="pun">=</span><span class="lit">100</span><span class="pln"> \                   </span><span class="com"># 训练log_period个batch后打印日志</span></code></li><li class="L8"><code class="language-shell"><span class="pln">    </span><span class="pun">--</span><span class="pln">dot_period</span><span class="pun">=</span><span class="lit">1</span><span class="pln"> \                     </span><span class="com"># 每训练dot_period个batch后打印一个"."</span></code></li><li class="L9"><code class="language-shell"><span class="pln">    </span><span class="pun">--</span><span class="pln">num_passes</span><span class="pun">=</span><span class="lit">50</span><span class="pln">  </span><span class="lit">2</span><span class="pun">&gt;&amp;</span><span class="lit">1</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> tee </span><span class="str">'log.txt'</span></code></li></ol></pre><p data-anchor-id="umsb">成功的输出类似如下:</p><div class="md-section-divider"></div><pre class="prettyprint linenums prettyprinted" data-anchor-id="feiy"><ol class="linenums"><li class="L0"><code class="language-bash"><span class="pln">I0117 </span><span class="lit">01</span><span class="pun">:</span><span class="lit">01</span><span class="pun">:</span><span class="lit">48.585651</span><span class="pln">  </span><span class="lit">9998</span><span class="pln"> </span><span class="typ">TrainerInternal</span><span class="pun">.</span><span class="pln">cpp</span><span class="pun">:</span><span class="lit">165</span><span class="pun">]</span><span class="pln">  </span><span class="typ">Batch</span><span class="pun">=</span><span class="lit">100</span><span class="pln"> samples</span><span class="pun">=</span><span class="lit">160000</span><span class="pln"> </span><span class="typ">AvgCost</span><span class="pun">=</span><span class="lit">0.600042</span><span class="pln"> </span><span class="typ">CurrentCost</span><span class="pun">=</span><span class="lit">0.600042</span><span class="pln"> </span><span class="typ">Eval</span><span class="pun">:</span><span class="pln">  </span><span class="typ">CurrentEval</span><span class="pun">:</span></code></li><li class="L1"><code class="language-bash"><span class="pun">...................................................................................................</span></code></li><li class="L2"><code class="language-bash"><span class="pln">I0117 </span><span class="lit">01</span><span class="pun">:</span><span class="lit">02</span><span class="pun">:</span><span class="lit">53.821918</span><span class="pln">  </span><span class="lit">9998</span><span class="pln"> </span><span class="typ">TrainerInternal</span><span class="pun">.</span><span class="pln">cpp</span><span class="pun">:</span><span class="lit">165</span><span class="pun">]</span><span class="pln">  </span><span class="typ">Batch</span><span class="pun">=</span><span class="lit">200</span><span class="pln"> samples</span><span class="pun">=</span><span class="lit">320000</span><span class="pln"> </span><span class="typ">AvgCost</span><span class="pun">=</span><span class="lit">0.602855</span><span class="pln"> </span><span class="typ">CurrentCost</span><span class="pun">=</span><span class="lit">0.605668</span><span class="pln"> </span><span class="typ">Eval</span><span class="pun">:</span><span class="pln">  </span><span class="typ">CurrentEval</span><span class="pun">:</span></code></li><li class="L3"><code class="language-bash"><span class="pun">...................................................................................................</span></code></li><li class="L4"><code class="language-bash"><span class="pln">I0117 </span><span class="lit">01</span><span class="pun">:</span><span class="lit">03</span><span class="pun">:</span><span class="lit">58.937922</span><span class="pln">  </span><span class="lit">9998</span><span class="pln"> </span><span class="typ">TrainerInternal</span><span class="pun">.</span><span class="pln">cpp</span><span class="pun">:</span><span class="lit">165</span><span class="pun">]</span><span class="pln">  </span><span class="typ">Batch</span><span class="pun">=</span><span class="lit">300</span><span class="pln"> samples</span><span class="pun">=</span><span class="lit">480000</span><span class="pln"> </span><span class="typ">AvgCost</span><span class="pun">=</span><span class="lit">0.605199</span><span class="pln"> </span><span class="typ">CurrentCost</span><span class="pun">=</span><span class="lit">0.609887</span><span class="pln"> </span><span class="typ">Eval</span><span class="pun">:</span><span class="pln">  </span><span class="typ">CurrentEval</span><span class="pun">:</span></code></li><li class="L5"><code class="language-bash"><span class="pun">...................................................................................................</span></code></li><li class="L6"><code class="language-bash"><span class="pln">I0117 </span><span class="lit">01</span><span class="pun">:</span><span class="lit">05</span><span class="pun">:</span><span class="lit">04.083251</span><span class="pln">  </span><span class="lit">9998</span><span class="pln"> </span><span class="typ">TrainerInternal</span><span class="pun">.</span><span class="pln">cpp</span><span class="pun">:</span><span class="lit">165</span><span class="pun">]</span><span class="pln">  </span><span class="typ">Batch</span><span class="pun">=</span><span class="lit">400</span><span class="pln"> samples</span><span class="pun">=</span><span class="lit">640000</span><span class="pln"> </span><span class="typ">AvgCost</span><span class="pun">=</span><span class="lit">0.608693</span><span class="pln"> </span><span class="typ">CurrentCost</span><span class="pun">=</span><span class="lit">0.619175</span><span class="pln"> </span><span class="typ">Eval</span><span class="pun">:</span><span class="pln">  </span><span class="typ">CurrentEval</span><span class="pun">:</span></code></li><li class="L7"><code class="language-bash"><span class="pun">...................................................................................................</span></code></li><li class="L8"><code class="language-bash"><span class="pln">I0117 </span><span class="lit">01</span><span class="pun">:</span><span class="lit">06</span><span class="pun">:</span><span class="lit">09.155859</span><span class="pln">  </span><span class="lit">9998</span><span class="pln"> </span><span class="typ">TrainerInternal</span><span class="pun">.</span><span class="pln">cpp</span><span class="pun">:</span><span class="lit">165</span><span class="pun">]</span><span class="pln">  </span><span class="typ">Batch</span><span class="pun">=</span><span class="lit">500</span><span class="pln"> samples</span><span class="pun">=</span><span class="lit">800000</span><span class="pln"> </span><span class="typ">AvgCost</span><span class="pun">=</span><span class="lit">0.613273</span><span class="pln"> </span><span class="typ">CurrentCost</span><span class="pun">=</span><span class="lit">0.631591</span><span class="pln"> </span><span class="typ">Eval</span><span class="pun">:</span><span class="pln">  </span><span class="typ">CurrentEval</span><span class="pun">:</span></code></li><li class="L9"><code class="language-bash"><span class="pun">.................................................................</span><span class="pln">I0117 </span><span class="lit">01</span><span class="pun">:</span><span class="lit">06</span><span class="pun">:</span><span class="lit">51.109654</span><span class="pln">  </span><span class="lit">9998</span><span class="pln"> </span><span class="typ">TrainerInternal</span><span class="pun">.</span><span class="pln">cpp</span><span class="pun">:</span><span class="lit">181</span><span class="pun">]</span></code></li><li class="L0"><code class="language-bash"><span class="pln"> </span><span class="typ">Pass</span><span class="pun">=</span><span class="lit">49</span><span class="pln"> </span><span class="typ">Batch</span><span class="pun">=</span><span class="lit">565</span><span class="pln"> samples</span><span class="pun">=</span><span class="lit">902826</span><span class="pln"> </span><span class="typ">AvgCost</span><span class="pun">=</span><span class="lit">0.614772</span><span class="pln"> </span><span class="typ">Eval</span><span class="pun">:</span></code></li><li class="L1"><code class="language-bash"><span class="pln">I0117 </span><span class="lit">01</span><span class="pun">:</span><span class="lit">07</span><span class="pun">:</span><span class="lit">04.205142</span><span class="pln">  </span><span class="lit">9998</span><span class="pln"> </span><span class="typ">Tester</span><span class="pun">.</span><span class="pln">cpp</span><span class="pun">:</span><span class="lit">115</span><span class="pun">]</span><span class="pln">  </span><span class="typ">Test</span><span class="pln"> samples</span><span class="pun">=</span><span class="lit">97383</span><span class="pln"> cost</span><span class="pun">=</span><span class="lit">0.721995</span><span class="pln"> </span><span class="typ">Eval</span><span class="pun">:</span></code></li><li class="L2"><code class="language-bash"><span class="pln">I0117 </span><span class="lit">01</span><span class="pun">:</span><span class="lit">07</span><span class="pun">:</span><span class="lit">04.205281</span><span class="pln">  </span><span class="lit">9998</span><span class="pln"> </span><span class="typ">GradientMachine</span><span class="pun">.</span><span class="pln">cpp</span><span class="pun">:</span><span class="lit">113</span><span class="pun">]</span><span class="pln"> </span><span class="typ">Saving</span><span class="pln"> parameters to </span><span class="pun">./</span><span class="pln">output</span><span class="pun">/</span><span class="pln">pass</span><span class="pun">-</span><span class="lit">00049</span></code></li></ol></pre><div class="md-section-divider"></div><h2 data-anchor-id="vc6d" id="应用模型">应用模型</h2><p data-anchor-id="uhz0">在训练了几轮以后,您可以对模型进行评估。运行以下命令,可以通过选择最小训练误差的一轮参数得到最好轮次的模型。</p><div class="md-section-divider"></div><pre class="prettyprint linenums prettyprinted" data-anchor-id="525h"><ol class="linenums"><li class="L0"><code class="language-shell"><span class="pun">./</span><span class="pln">evaluate</span><span class="pun">.</span><span class="pln">py log</span><span class="pun">.</span><span class="pln">txt</span></code></li></ol></pre><p data-anchor-id="6awi">您将看到:</p><div class="md-section-divider"></div><pre class="prettyprint linenums prettyprinted" data-anchor-id="u3is"><ol class="linenums"><li class="L0"><code class="language-shell"><span class="typ">Best</span><span class="pln"> </span><span class="kwd">pass</span><span class="pln"> </span><span class="kwd">is</span><span class="pln"> </span><span class="lit">00036</span><span class="pun">,</span><span class="pln"> error </span><span class="kwd">is</span><span class="pln"> </span><span class="lit">0.719281</span><span class="pun">,</span><span class="pln"> which means predict </span><span class="kwd">get</span><span class="pln"> error </span><span class="kwd">as</span><span class="pln"> </span><span class="lit">0.424052</span></code></li><li class="L1"><code class="language-shell"><span class="pln">evaluating </span><span class="kwd">from</span><span class="pln"> </span><span class="kwd">pass</span><span class="pln"> output</span><span class="pun">/</span><span class="kwd">pass</span><span class="pun">-</span><span class="lit">00036</span></code></li></ol></pre><p data-anchor-id="6svk">预测任何用户对于任何一部电影评价的命令如下:</p><div class="md-section-divider"></div><pre class="prettyprint linenums prettyprinted" data-anchor-id="xsrb"><ol class="linenums"><li class="L0"><code class="language-shell"><span class="pln">python prediction</span><span class="pun">.</span><span class="pln">py </span><span class="str">'output/pass-00036/'</span></code></li></ol></pre><p data-anchor-id="a4x3">预测程序将读取用户的输入,然后输出预测分数。您会看到如下命令行界面:</p><div class="md-section-divider"></div><pre class="prettyprint linenums prettyprinted" data-anchor-id="4ltb"><ol class="linenums"><li class="L0"><code><span class="typ">Input</span><span class="pln"> movie_id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1962</span></code></li><li class="L1"><code><span class="typ">Input</span><span class="pln"> user_id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span></code></li><li class="L2"><code><span class="typ">Prediction</span><span class="pln"> </span><span class="typ">Score</span><span class="pln"> </span><span class="kwd">is</span><span class="pln"> </span><span class="lit">4.25</span></code></li></ol></pre><div class="md-section-divider"></div><h2 data-anchor-id="sayc" id="总结">总结</h2><p data-anchor-id="9u3u">本章介绍了传统的推荐系统方法和YouTube的深度神经网络推荐系统,并以电影推荐为例,使用PaddlePaddle训练了一个个性化推荐神经网络模型。推荐系统几乎涵盖了电商系统、社交网络、广告推荐、搜索引擎等领域的方方面面,而在图像处理、自然语言处理等领域已经发挥重要作用的深度学习技术,也将会在推荐系统领域大放异彩。</p><div class="md-section-divider"></div><h2 data-anchor-id="w59q" id="参考文献">参考文献</h2><ol data-anchor-id="rikd">
<li><a href="https://en.wikipedia.org/wiki/Peter_Brusilovsky" target="_blank">Peter Brusilovsky</a> (2007). <em>The Adaptive Web</em>. p. 325.</li>
<li>Robin Burke , <a href="http://www.dcs.warwick.ac.uk/~acristea/courses/CS411/2010/Book%20-%20The%20Adaptive%20Web/HybridWebRecommenderSystems.pdf" target="_blank">Hybrid Web Recommender Systems</a>, pp. 377-408, The Adaptive Web, Peter Brusilovsky, Alfred Kobsa, Wolfgang Nejdl (Ed.), Lecture Notes in Computer Science, Springer-Verlag, Berlin, Germany, Lecture Notes in Computer Science, Vol. 4321, May 2007, 978-3-540-72078-2.</li>
<li>P. Resnick, N. Iacovou, etc. “<a href="http://ccs.mit.edu/papers/CCSWP165.html" target="_blank">GroupLens: An Open Architecture for Collaborative Filtering of Netnews</a>”, Proceedings of ACM Conference on Computer Supported Cooperative Work, CSCW 1994. pp.175-186.</li>
<li>Sarwar, Badrul, et al. "<a href="http://files.grouplens.org/papers/www10_sarwar.pdf" target="_blank">Item-based collaborative filtering recommendation algorithms.</a>" <em>Proceedings of the 10th international conference on World Wide Web</em>. ACM, 2001.</li>
<li>Kautz, Henry, Bart Selman, and Mehul Shah. "<a href="http://www.cs.cornell.edu/selman/papers/pdf/97.cacm.refweb.pdf" target="_blank">Referral Web: combining social networks and collaborative filtering.</a>" Communications of the ACM 40.3 (1997): 63-65. APA</li>
<li>Yuan, Jianbo, et al. <a href="https://arxiv.org/pdf/1611.05480v1.pdf" target="_blank">"Solving Cold-Start Problem in Large-scale Recommendation Engines: A Deep Learning Approach."</a> <em>arXiv preprint arXiv:1611.05480</em> (2016).</li>
<li>Covington P, Adams J, Sargin E. <a href="https://static.googleusercontent.com/media/research.google.com/zh-CN//pubs/archive/45530.pdf" target="_blank">Deep neural networks for youtube recommendations</a>[C]//Proceedings of the 10th ACM Conference on Recommender Systems. ACM, 2016: 191-198.</li>
</ol><p data-anchor-id="e7gv"><br> <br>
<img src="https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png" alt="知识共享许可协议"></p><p data-anchor-id="166j">本教程由<a href="http://book.paddlepaddle.org" target="_blank">PaddlePaddle</a>创作,采用<a href="http://creativecommons.org/licenses/by-nc-sa/4.0/" target="_blank">知识共享 署名-非商业性使用-相同方式共享 4.0 国际 许可协议</a>进行许可。</p></div>
</body>
</html>