[{"data":1,"prerenderedAt":2079},["ShallowReactive",2],{"recommendation-models-prologue-before":3,"recommendation-models-prologue-between":244,"recommendation-models-prologue-after":716},{"data":4,"body":5},{},{"type":6,"children":7},"root",[8,17,54,59,180,214,232,239],{"type":9,"tag":10,"props":11,"children":13},"element","h1",{"id":12},"prologue-choose-the-next-article",[14],{"type":15,"value":16},"text","Prologue: choose the next article",{"type":9,"tag":18,"props":19,"children":20},"p",{},[21,23,29,31,36,38,45,47,52],{"type":15,"value":22},"Meet Sam. Sam opens a feed of suggested articles. Bosca has to decide what to show next.\nFor this guide, Sam is a ",{"type":9,"tag":24,"props":25,"children":26},"strong",{},[27],{"type":15,"value":28},"reader",{"type":15,"value":30},": the person receiving recommendations. Bosca stores a\n",{"type":9,"tag":24,"props":32,"children":33},{},[34],{"type":15,"value":35},"profile",{"type":15,"value":37}," for Sam, meaning a record of information associated with that person. The\ntrainer calls the profile ID ",{"type":9,"tag":39,"props":40,"children":42},"code",{"className":41},"",[43],{"type":15,"value":44},"user_id",{"type":15,"value":46},". We will use the made-up ID ",{"type":9,"tag":39,"props":48,"children":49},{"className":41},[50],{"type":15,"value":51},"reader-1",{"type":15,"value":53},".",{"type":9,"tag":18,"props":55,"children":56},{},[57],{"type":15,"value":58},"Here is what happened earlier. The names, articles, and actions in this story are invented:",{"type":9,"tag":60,"props":61,"children":62},"table",{},[63,87],{"type":9,"tag":64,"props":65,"children":66},"thead",{},[67],{"type":9,"tag":68,"props":69,"children":70},"tr",{},[71,77,82],{"type":9,"tag":72,"props":73,"children":74},"th",{},[75],{"type":15,"value":76},"Article Sam saw",{"type":9,"tag":72,"props":78,"children":79},{},[80],{"type":15,"value":81},"What Bosca knew before showing it",{"type":9,"tag":72,"props":83,"children":84},{},[85],{"type":15,"value":86},"What Sam did afterward",{"type":9,"tag":88,"props":89,"children":90},"tbody",{},[91,120,147],{"type":9,"tag":68,"props":92,"children":93},{},[94,105,115],{"type":9,"tag":95,"props":96,"children":97},"td",{},[98,103],{"type":9,"tag":39,"props":99,"children":100},{"className":41},[101],{"type":15,"value":102},"article-9",{"type":15,"value":104},": “How stars form”",{"type":9,"tag":95,"props":106,"children":107},{},[108,110],{"type":15,"value":109},"English; category ",{"type":9,"tag":39,"props":111,"children":112},{"className":41},[113],{"type":15,"value":114},"science",{"type":9,"tag":95,"props":116,"children":117},{},[118],{"type":15,"value":119},"Completed it",{"type":9,"tag":68,"props":121,"children":122},{},[123,133,142],{"type":9,"tag":95,"props":124,"children":125},{},[126,131],{"type":9,"tag":39,"props":127,"children":128},{"className":41},[129],{"type":15,"value":130},"article-10",{"type":15,"value":132},": “Weekend match recap”",{"type":9,"tag":95,"props":134,"children":135},{},[136,137],{"type":15,"value":109},{"type":9,"tag":39,"props":138,"children":139},{"className":41},[140],{"type":15,"value":141},"sports",{"type":9,"tag":95,"props":143,"children":144},{},[145],{"type":15,"value":146},"Dismissed it",{"type":9,"tag":68,"props":148,"children":149},{},[150,160,168],{"type":9,"tag":95,"props":151,"children":152},{},[153,158],{"type":9,"tag":39,"props":154,"children":155},{"className":41},[156],{"type":15,"value":157},"article-11",{"type":15,"value":159},": “Why batteries age”",{"type":9,"tag":95,"props":161,"children":162},{},[163,164],{"type":15,"value":109},{"type":9,"tag":39,"props":165,"children":166},{"className":41},[167],{"type":15,"value":114},{"type":9,"tag":95,"props":169,"children":170},{},[171,173,178],{"type":15,"value":172},"Rated it ",{"type":9,"tag":39,"props":174,"children":175},{"className":41},[176],{"type":15,"value":177},"0.25",{"type":15,"value":179}," on a 0–1 scale",{"type":9,"tag":18,"props":181,"children":182},{},[183,185,190,192,198,200,205,207,212],{"type":15,"value":184},"A ",{"type":9,"tag":24,"props":186,"children":187},{},[188],{"type":15,"value":189},"feature",{"type":15,"value":191}," is a detail Bosca can use ",{"type":9,"tag":193,"props":194,"children":195},"em",{},[196],{"type":15,"value":197},"before",{"type":15,"value":199}," it chooses an article: language, category,\nfile type, and what it knows about Sam from earlier activity are examples. A ",{"type":9,"tag":24,"props":201,"children":202},{},[203],{"type":15,"value":204},"response",{"type":15,"value":206}," is\nwhat Sam does ",{"type":9,"tag":193,"props":208,"children":209},{},[210],{"type":15,"value":211},"afterward",{"type":15,"value":213},", such as completing or dismissing the article. The response in each\nrow is known now because those events happened in the past. For a new article, Bosca has the\nfeatures but cannot know Sam's response yet.",{"type":9,"tag":18,"props":215,"children":216},{},[217,218,223,225,230],{"type":15,"value":184},{"type":9,"tag":24,"props":219,"children":220},{},[221],{"type":15,"value":222},"candidate",{"type":15,"value":224}," is an article eligible to be shown next. A ",{"type":9,"tag":24,"props":226,"children":227},{},[228],{"type":15,"value":229},"model",{"type":15,"value":231}," is the saved set of\ncalculations Bosca uses to score or choose candidates. Some calculations follow fixed rules;\nothers use numbers learned from past responses. Before looking at the real code, follow one\nresponse into the next recommendation.",{"type":9,"tag":233,"props":234,"children":236},"h2",{"id":235},"try-it-see-how-a-response-changes-later-scores",[237],{"type":15,"value":238},"Try it: see how a response changes later scores",{"type":9,"tag":18,"props":240,"children":241},{},[242],{"type":15,"value":243},"Work through the five steps in the box. Turn article categories into numbers, set the points\nfor each category, and choose an article for Sam. Then record Sam's response, change the\nscoring rule, and see what happens to a later pair of articles.",{"data":245,"body":246},{},{"type":6,"children":247},[248,253,279,285,342,349,411,449,574,622,627,633,650,655,693,705,711],{"type":9,"tag":18,"props":249,"children":250},{},[251],{"type":15,"value":252},"You set the first two weights by hand, then used a simple made-up update to see how a response\ncan affect later scores. Bosca's real content model compares more item details; its\npersonalized model learns many weights from past examples. The next sections show those\npieces one at a time.",{"type":9,"tag":18,"props":254,"children":255},{},[256,258,263,265,270,272,277],{"type":15,"value":257},"In the Python code ahead, ",{"type":9,"tag":39,"props":259,"children":260},{"className":41},[261],{"type":15,"value":262},"features",{"type":15,"value":264}," is a dictionary of input arrays. For example,\n",{"type":9,"tag":39,"props":266,"children":267},{"className":41},[268],{"type":15,"value":269},"features['user_id']",{"type":15,"value":271}," holds profile IDs and ",{"type":9,"tag":39,"props":273,"children":274},{"className":41},[275],{"type":15,"value":276},"features['language_tag']",{"type":15,"value":278}," holds item languages.",{"type":9,"tag":233,"props":280,"children":282},{"id":281},"how-do-names-become-numbers",[283],{"type":15,"value":284},"How do names become numbers?",{"type":9,"tag":18,"props":286,"children":287},{},[288,290,294,296,301,303,308,310,314,316,321,323,327,328,333,335,340],{"type":15,"value":289},"The code knows a category as text, such as ",{"type":9,"tag":39,"props":291,"children":292},{"className":41},[293],{"type":15,"value":114},{"type":15,"value":295},". A calculation like multiplication cannot\nuse that word directly. One simple conversion is to choose an order for all known categories,\ncalled a ",{"type":9,"tag":24,"props":297,"children":298},{},[299],{"type":15,"value":300},"vocabulary",{"type":15,"value":302},". If the vocabulary is ",{"type":9,"tag":39,"props":304,"children":305},{"className":41},[306],{"type":15,"value":307},"['science', 'sports']",{"type":15,"value":309},", the item with category\n",{"type":9,"tag":39,"props":311,"children":312},{"className":41},[313],{"type":15,"value":114},{"type":15,"value":315}," becomes ",{"type":9,"tag":39,"props":317,"children":318},{"className":41},[319],{"type":15,"value":320},"[1, 0]",{"type":15,"value":322}," and the item with category ",{"type":9,"tag":39,"props":324,"children":325},{"className":41},[326],{"type":15,"value":141},{"type":15,"value":315},{"type":9,"tag":39,"props":329,"children":330},{"className":41},[331],{"type":15,"value":332},"[0, 1]",{"type":15,"value":334},". Each position\nanswers “Does this item have this category?” An item can have more than one ",{"type":9,"tag":39,"props":336,"children":337},{"className":41},[338],{"type":15,"value":339},"1",{"type":15,"value":341},". The towers\nchapter shows the Python that makes these rows.",{"type":9,"tag":343,"props":344,"children":346},"h3",{"id":345},"how-does-a-reader-id-become-numbers",[347],{"type":15,"value":348},"How does a reader ID become numbers?",{"type":9,"tag":18,"props":350,"children":351},{},[352,356,358,363,365,370,372,377,379,383,385,389,391,396,397,402,404,409],{"type":9,"tag":39,"props":353,"children":354},{"className":41},[355],{"type":15,"value":51},{"type":15,"value":357}," is the example profile's ID. The characters in that ID identify a record; they do\nnot say whether the person likes science. The personalized model has a ",{"type":9,"tag":24,"props":359,"children":360},{},[361],{"type":15,"value":362},"reader tower",{"type":15,"value":364},", a\nsequence of calculations for one reader, and an ",{"type":9,"tag":24,"props":366,"children":367},{},[368],{"type":15,"value":369},"item tower",{"type":15,"value":371}," for one article. To use an ID\nin those calculations, the reader tower first assigns each known ID an integer position.\nImagine the known IDs are\n",{"type":9,"tag":39,"props":373,"children":374},{"className":41},[375],{"type":15,"value":376},"['reader-1', 'reader-2']",{"type":15,"value":378},". In this example, the lookup gives ",{"type":9,"tag":39,"props":380,"children":381},{"className":41},[382],{"type":15,"value":51},{"type":15,"value":384}," position ",{"type":9,"tag":39,"props":386,"children":387},{"className":41},[388],{"type":15,"value":339},{"type":15,"value":390}," and\n",{"type":9,"tag":39,"props":392,"children":393},{"className":41},[394],{"type":15,"value":395},"reader-2",{"type":15,"value":384},{"type":9,"tag":39,"props":398,"children":399},{"className":41},[400],{"type":15,"value":401},"2",{"type":15,"value":403},"; position ",{"type":9,"tag":39,"props":405,"children":406},{"className":41},[407],{"type":15,"value":408},"0",{"type":15,"value":410}," is reserved for an ID outside that known list.",{"type":9,"tag":18,"props":412,"children":413},{},[414,416,421,423,428,430,435,437,441,443,447],{"type":15,"value":415},"An ",{"type":9,"tag":24,"props":417,"children":418},{},[419],{"type":15,"value":420},"embedding",{"type":15,"value":422}," is an ordered list of numbers a model associates with something. Another\nname for an ordered list of numbers is a ",{"type":9,"tag":24,"props":424,"children":425},{},[426],{"type":15,"value":427},"vector",{"type":15,"value":429},". An ",{"type":9,"tag":24,"props":431,"children":432},{},[433],{"type":15,"value":434},"embedding table",{"type":15,"value":436}," is a grid with one\nsuch list in each row. Looking up ",{"type":9,"tag":39,"props":438,"children":439},{"className":41},[440],{"type":15,"value":51},{"type":15,"value":442}," means\ntaking row ",{"type":9,"tag":39,"props":444,"children":445},{"className":41},[446],{"type":15,"value":339},{"type":15,"value":448},". The real ID table has 64 numbers in each row by default. Here is a two-number\nversion so we can see every value:",{"type":9,"tag":60,"props":450,"children":451},{},[452,479],{"type":9,"tag":64,"props":453,"children":454},{},[455],{"type":9,"tag":68,"props":456,"children":457},{},[458,464,469,474],{"type":9,"tag":72,"props":459,"children":461},{"align":460},"right",[462],{"type":15,"value":463},"Position",{"type":9,"tag":72,"props":465,"children":466},{},[467],{"type":15,"value":468},"ID",{"type":9,"tag":72,"props":470,"children":471},{},[472],{"type":15,"value":473},"Row at the start",{"type":9,"tag":72,"props":475,"children":476},{},[477],{"type":15,"value":478},"Possible row after training",{"type":9,"tag":88,"props":480,"children":481},{},[482,510,542],{"type":9,"tag":68,"props":483,"children":484},{},[485,492,497,505],{"type":9,"tag":95,"props":486,"children":487},{"align":460},[488],{"type":9,"tag":39,"props":489,"children":490},{"className":41},[491],{"type":15,"value":408},{"type":9,"tag":95,"props":493,"children":494},{},[495],{"type":15,"value":496},"ID outside the known list",{"type":9,"tag":95,"props":498,"children":499},{},[500],{"type":9,"tag":39,"props":501,"children":502},{"className":41},[503],{"type":15,"value":504},"[0, 0]",{"type":9,"tag":95,"props":506,"children":507},{},[508],{"type":15,"value":509},"Not used in this example",{"type":9,"tag":68,"props":511,"children":512},{},[513,520,527,534],{"type":9,"tag":95,"props":514,"children":515},{"align":460},[516],{"type":9,"tag":39,"props":517,"children":518},{"className":41},[519],{"type":15,"value":339},{"type":9,"tag":95,"props":521,"children":522},{},[523],{"type":9,"tag":39,"props":524,"children":525},{"className":41},[526],{"type":15,"value":51},{"type":9,"tag":95,"props":528,"children":529},{},[530],{"type":9,"tag":39,"props":531,"children":532},{"className":41},[533],{"type":15,"value":504},{"type":9,"tag":95,"props":535,"children":536},{},[537],{"type":9,"tag":39,"props":538,"children":539},{"className":41},[540],{"type":15,"value":541},"[0.4, -0.1]",{"type":9,"tag":68,"props":543,"children":544},{},[545,552,559,566],{"type":9,"tag":95,"props":546,"children":547},{"align":460},[548],{"type":9,"tag":39,"props":549,"children":550},{"className":41},[551],{"type":15,"value":401},{"type":9,"tag":95,"props":553,"children":554},{},[555],{"type":9,"tag":39,"props":556,"children":557},{"className":41},[558],{"type":15,"value":395},{"type":9,"tag":95,"props":560,"children":561},{},[562],{"type":9,"tag":39,"props":563,"children":564},{"className":41},[565],{"type":15,"value":504},{"type":9,"tag":95,"props":567,"children":568},{},[569],{"type":9,"tag":39,"props":570,"children":571},{"className":41},[572],{"type":15,"value":573},"[0.1, 0.3]",{"type":9,"tag":18,"props":575,"children":576},{},[577,579,584,586,590,592,596,598,602,604,608,610,614,616,620],{"type":15,"value":578},"The last column is invented. Bosca does ",{"type":9,"tag":24,"props":580,"children":581},{},[582],{"type":15,"value":583},"not",{"type":15,"value":585}," hardcode those values. Its ID rows start at\nzero. During the first training stage, a positive past example, such as ",{"type":9,"tag":39,"props":587,"children":588},{"className":41},[589],{"type":15,"value":51},{"type":15,"value":591}," completing\n",{"type":9,"tag":39,"props":593,"children":594},{"className":41},[595],{"type":15,"value":102},{"type":15,"value":597},", selects row ",{"type":9,"tag":39,"props":599,"children":600},{"className":41},[601],{"type":15,"value":339},{"type":15,"value":603},". The reader tower combines that row with other available reader\ninformation. The item tower calculates numbers for ",{"type":9,"tag":39,"props":605,"children":606},{"className":41},[607],{"type":15,"value":102},{"type":15,"value":609},". Training changes the ID row\nand the towers' shared weights to make this observed pair match better. Repeating that process\nwith other positive examples can change row ",{"type":9,"tag":39,"props":611,"children":612},{"className":41},[613],{"type":15,"value":339},{"type":15,"value":615}," further. Later, the ranking stage learns from\nboth positive and negative responses to order candidates while the towers' numbers stay fixed.\nThe individual numbers in row ",{"type":9,"tag":39,"props":617,"children":618},{"className":41},[619],{"type":15,"value":339},{"type":15,"value":621}," do not have names such as “science interest”; their effect\ndepends on the rest of the tower and the item vectors they are compared with.",{"type":9,"tag":18,"props":623,"children":624},{},[625],{"type":15,"value":626},"The ID row is useful because it can retain patterns specific to a known profile. It is only\none input. The reader tower also accepts saved information such as interests and earlier\ncategory activity. A profile included when this model version is built but with no past\ninteractions still has an all-zero ID row; its saved interests can contribute to its reader\nvector. After training, Bosca uses the saved values to score items. It does not need to wait\nfor a new response to look up that profile's row.",{"type":9,"tag":233,"props":628,"children":630},{"id":629},"what-is-a-text-embedding",[631],{"type":15,"value":632},"What is a text embedding?",{"type":9,"tag":18,"props":634,"children":635},{},[636,637,642,644,648],{"type":15,"value":184},{"type":9,"tag":24,"props":638,"children":639},{},[640],{"type":15,"value":641},"text embedding",{"type":15,"value":643}," is an ordered list of numbers calculated from a piece of text. It gives\nthat text a position in a number space so we can compare it with other text processed by the\nsame model. For example, the input might be the words “How stars form” and the output might\nbe a list such as ",{"type":9,"tag":39,"props":645,"children":646},{"className":41},[647],{"type":15,"value":320},{"type":15,"value":649}," in the tiny illustration below. Bosca's real text embeddings have\nmany more numbers. This is different from the reader ID embedding above: the ID row is learned\nfrom recommendation examples, while a text embedding is calculated from an item's words by a\nseparate, previously trained model.",{"type":9,"tag":18,"props":651,"children":652},{},[653],{"type":15,"value":654},"Here is the path in Bosca:",{"type":9,"tag":656,"props":657,"children":658},"ol",{},[659,665,683,688],{"type":9,"tag":660,"props":661,"children":662},"li",{},[663],{"type":15,"value":664},"The content service extracts text from an item. When embeddings are enabled, it sends that\ntext to the text embedding service.",{"type":9,"tag":660,"props":666,"children":667},{},[668,669,674,676,681],{"type":15,"value":184},{"type":9,"tag":24,"props":670,"children":671},{},[672],{"type":15,"value":673},"tokenizer",{"type":15,"value":675}," splits the text into pieces called ",{"type":9,"tag":24,"props":677,"children":678},{},[679],{"type":15,"value":680},"tokens",{"type":15,"value":682},". A token can be a word or part\nof a word. The text model turns those pieces into numbers it can calculate with.",{"type":9,"tag":660,"props":684,"children":685},{},[686],{"type":15,"value":687},"The text model uses weights learned before this recommendation training run to combine the\ntoken information into one list of numbers. If the item is too long, Bosca sends smaller\npieces and receives a list for each one.",{"type":9,"tag":660,"props":689,"children":690},{},[691],{"type":15,"value":692},"The recommendation trainer averages the piece lists, accounting for repeated text where\npieces overlap, then scales a nonzero result to length 1. It uses that one list as an item\ninput. The recommender does not train the separate text model in this process.",{"type":9,"tag":18,"props":694,"children":695},{},[696,698,703],{"type":15,"value":697},"Why call this a representation of ",{"type":9,"tag":193,"props":699,"children":700},{},[701],{"type":15,"value":702},"meaning",{"type":15,"value":704},"? The text model's training aims to put passages\nabout related ideas near each other in the number space, even when their words differ. No\nsingle number is a field named “topic” or “science.” We judge the representation by comparing\nthe entire lists: related text should often produce lists that point in similar directions.\nThis is a learned pattern, so it can make mistakes.",{"type":9,"tag":343,"props":706,"children":708},{"id":707},"compare-two-text-embeddings-by-hand",[709],{"type":15,"value":710},"Compare two text embeddings by hand",{"type":9,"tag":18,"props":712,"children":713},{},[714],{"type":15,"value":715},"Use the arrows below to compare two invented text embeddings. Pick a second article and watch\nthe arrow and calculation change. The numbers are tiny so we can work through them by hand;\nBosca's actual text embeddings have many more numbers.",{"data":717,"body":718},{},{"type":6,"children":719},[720,732,737,743,802,807,833,839,856,867,912,917,923,954,972,1002,1028,1037,1076,1102,1108,1415,1421,1426,1506,1511,1517,1527,1538,1555,1738,1750,1756,1768,1841,1847,1852,2044,2069],{"type":9,"tag":18,"props":721,"children":722},{},[723,725,730],{"type":15,"value":724},"The arrows each have length 1. Their multiply-and-add result is therefore also their\n",{"type":9,"tag":24,"props":726,"children":727},{},[728],{"type":15,"value":729},"cosine similarity",{"type":15,"value":731},": a number describing how closely the arrows point in the same direction.\nThe individual positions do not have labels like “star” or “football” in the real model.\nMeaning comes from how whole vectors compare across many texts. This comparison is useful,\nbut it does not guarantee that every related pair will be close.",{"type":9,"tag":18,"props":733,"children":734},{},[735],{"type":15,"value":736},"Why add this input when items already have categories? Two articles can discuss the same idea\nwithout sharing an assigned category or the same exact words. The text vector gives the model\nanother way to compare them. Bosca still uses the explicit category, language, and other item\ninformation alongside it.",{"type":9,"tag":233,"props":738,"children":740},{"id":739},"what-does-a-layer-do",[741],{"type":15,"value":742},"What does a layer do?",{"type":9,"tag":18,"props":744,"children":745},{},[746,747,752,754,759,761,766,768,773,775,779,781,786,788,793,795,800],{"type":15,"value":184},{"type":9,"tag":24,"props":748,"children":749},{},[750],{"type":15,"value":751},"layer",{"type":15,"value":753}," is one step that turns input numbers into output numbers. In a ",{"type":9,"tag":24,"props":755,"children":756},{},[757],{"type":15,"value":758},"dense layer",{"type":15,"value":760},", each\noutput is calculated by multiplying inputs by adjustable ",{"type":9,"tag":24,"props":762,"children":763},{},[764],{"type":15,"value":765},"weights",{"type":15,"value":767},", adding the results, and\nadding a ",{"type":9,"tag":24,"props":769,"children":770},{},[771],{"type":15,"value":772},"bias",{"type":15,"value":774},". For example, inputs ",{"type":9,"tag":39,"props":776,"children":777},{"className":41},[778],{"type":15,"value":320},{"type":15,"value":780},", weights ",{"type":9,"tag":39,"props":782,"children":783},{"className":41},[784],{"type":15,"value":785},"[0.4, 0.7]",{"type":15,"value":787},", and bias ",{"type":9,"tag":39,"props":789,"children":790},{"className":41},[791],{"type":15,"value":792},"0.1",{"type":15,"value":794}," produce\n",{"type":9,"tag":39,"props":796,"children":797},{"className":41},[798],{"type":15,"value":799},"1×0.4 + 0×0.7 + 0.1 = 0.5",{"type":15,"value":801},". Training adjusts the weights and bias. A layer can produce many\nnumbers at once; the next layer uses those numbers as its inputs. A tower is the full sequence\nof these steps for either the reader or the item. The towers chapter follows the actual code.",{"type":9,"tag":18,"props":803,"children":804},{},[805],{"type":15,"value":806},"Why learn those weights? They let the personalized model change how it combines reader and item\ninformation based on past responses. For instance, training can change how strongly a reader's\nrecorded category interests affect the reader vector. The layer's arithmetic stays the same;\nthe numbers used in that arithmetic change.",{"type":9,"tag":18,"props":808,"children":809},{},[810,812,817,819,824,826,831],{"type":15,"value":811},"Not every layer does the same calculation. A lookup layer turns an ID into its table row. A\ndense layer mixes its input numbers using learned weights. Some dense layers use ",{"type":9,"tag":24,"props":813,"children":814},{},[815],{"type":15,"value":816},"ReLU",{"type":15,"value":818},":\nafter the multiply-and-add step, any negative output is replaced with zero. For example,\n",{"type":9,"tag":39,"props":820,"children":821},{"className":41},[822],{"type":15,"value":823},"ReLU(-0.3) = 0",{"type":15,"value":825}," and ",{"type":9,"tag":39,"props":827,"children":828},{"className":41},[829],{"type":15,"value":830},"ReLU(0.5) = 0.5",{"type":15,"value":832},". This lets a later layer react when a learned\ncombination is positive while ignoring it when that combination is zero. Without a step such\nas ReLU between them, consecutive dense layers would amount to one larger multiply-and-add\ncalculation.",{"type":9,"tag":233,"props":834,"children":836},{"id":835},"why-are-there-two-towers",[837],{"type":15,"value":838},"Why are there two towers?",{"type":9,"tag":18,"props":840,"children":841},{},[842,844,848,850,854],{"type":15,"value":843},"The ",{"type":9,"tag":24,"props":845,"children":846},{},[847],{"type":15,"value":362},{"type":15,"value":849}," combines what Bosca knows about a reader. The ",{"type":9,"tag":24,"props":851,"children":852},{},[853],{"type":15,"value":369},{"type":15,"value":855}," combines\nwhat Bosca knows about an item. They each return a list of 64 numbers by default:",{"type":9,"tag":857,"props":858,"children":862},"pre",{"className":859,"code":861,"filename":-1,"highlights":-1,"language":15,"meta":41},[860],"language-text","reader ID + saved reader information → reader tower → reader vector\nitem ID + item properties + optional text vector → item tower → item vector\nreader vector × item vector, then add → match score\n",[863],{"type":9,"tag":39,"props":864,"children":865},{"__ignoreMap":41},[866],{"type":15,"value":861},{"type":9,"tag":18,"props":868,"children":869},{},[870,872,877,879,883,885,890,892,896,898,903,905,910],{"type":15,"value":871},"That last line is a ",{"type":9,"tag":24,"props":873,"children":874},{},[875],{"type":15,"value":876},"dot product",{"type":15,"value":878},". Suppose the reader tower returned ",{"type":9,"tag":39,"props":880,"children":881},{"className":41},[882],{"type":15,"value":320},{"type":15,"value":884},", one item tower\nreturned ",{"type":9,"tag":39,"props":886,"children":887},{"className":41},[888],{"type":15,"value":889},"[0.8, 0.6]",{"type":15,"value":891},", and another returned ",{"type":9,"tag":39,"props":893,"children":894},{"className":41},[895],{"type":15,"value":332},{"type":15,"value":897},". The first match score is\n",{"type":9,"tag":39,"props":899,"children":900},{"className":41},[901],{"type":15,"value":902},"1×0.8 + 0×0.6 = 0.8",{"type":15,"value":904},"; the second is ",{"type":9,"tag":39,"props":906,"children":907},{"className":41},[908],{"type":15,"value":909},"1×0 + 0×1 = 0",{"type":15,"value":911},". These two-number outputs are invented\nteaching values. Bosca's towers learn 64-number outputs from past reader-item examples. The\nsupplied text embedding above is an input to the item tower; its 64-number output is a separate\nvector learned for matching readers with items.",{"type":9,"tag":18,"props":913,"children":914},{},[915],{"type":15,"value":916},"Keeping reader and item calculations separate also lets Bosca calculate item vectors for the\neligible catalog and compare them with many different reader vectors. The export chapter shows\nhow the saved model stores and uses those vectors.",{"type":9,"tag":233,"props":918,"children":920},{"id":919},"what-changes-during-training",[921],{"type":15,"value":922},"What changes during training?",{"type":9,"tag":18,"props":924,"children":925},{},[926,928,933,935,940,942,946,948,952],{"type":15,"value":927},"Training works through past examples with recorded evidence about what happened. The trainer\nturns that evidence into a number called the ",{"type":9,"tag":24,"props":929,"children":930},{},[931],{"type":15,"value":932},"label",{"type":15,"value":934}," (or ",{"type":9,"tag":24,"props":936,"children":937},{},[938],{"type":15,"value":939},"training target",{"type":15,"value":941},"). Sam dismissed\n",{"type":9,"tag":39,"props":943,"children":944},{"className":41},[945],{"type":15,"value":130},{"type":15,"value":947},", so that example's label is ",{"type":9,"tag":39,"props":949,"children":950},{"className":41},[951],{"type":15,"value":408},{"type":15,"value":953},". The ranking model scores the pair, uses the\nlabel to calculate a penalty, and adjusts itself so pairs like that one score lower next time.",{"type":9,"tag":18,"props":955,"children":956},{},[957,959,964,966,970],{"type":15,"value":958},"A new article such as ",{"type":9,"tag":39,"props":960,"children":961},{"className":41},[962],{"type":15,"value":963},"article-12",{"type":15,"value":965}," has no label before there is usable evidence about Sam and\nthat article. The model can still score it using the information available before showing it.\nLater, an action such as a dismissal can produce a label. Even without an action, a recorded\ndisplay that Sam could see but ignored for the attribution window can produce a low-confidence\n",{"type":9,"tag":39,"props":967,"children":968},{"className":41},[969],{"type":15,"value":408},{"type":15,"value":971}," label. The observations chapter explains when such a display qualifies.",{"type":9,"tag":18,"props":973,"children":974},{},[975,977,981,983,987,989,993,995,1000],{"type":15,"value":976},"A label is a record of what happened, not a prediction. Sam's ",{"type":9,"tag":39,"props":978,"children":979},{"className":41},[980],{"type":15,"value":177},{"type":15,"value":982}," rating of ",{"type":9,"tag":39,"props":984,"children":985},{"className":41},[986],{"type":15,"value":157},{"type":15,"value":988},"\nbecomes the label ",{"type":9,"tag":39,"props":990,"children":991},{"className":41},[992],{"type":15,"value":177},{"type":15,"value":994},". It doesn't mean “a 25% chance Sam finishes it.” A prediction like\nthat would be a ",{"type":9,"tag":24,"props":996,"children":997},{},[998],{"type":15,"value":999},"calibrated probability",{"type":15,"value":1001},": of 100 recommendations each given a 25% chance,\nabout 25 would actually be completed. Bosca's scores are not calibrated probabilities either;\nthey are used only to put articles in order.",{"type":9,"tag":18,"props":1003,"children":1004},{},[1005,1007,1012,1014,1019,1021,1026],{"type":15,"value":1006},"To decide how to adjust, training calculates a ",{"type":9,"tag":24,"props":1008,"children":1009},{},[1010],{"type":15,"value":1011},"loss",{"type":15,"value":1013},": a penalty for how the model scored a\npast example. A smaller loss means the score fits that example's label better under the chosen\nformula. Bosca's ranking score is a ",{"type":9,"tag":24,"props":1015,"children":1016},{},[1017],{"type":15,"value":1018},"logit",{"type":15,"value":1020},", a raw number on a different scale from its\n0–1 labels. Its loss converts that score before comparing it with a label; the training\nchapter shows the arithmetic. A ",{"type":9,"tag":24,"props":1022,"children":1023},{},[1024],{"type":15,"value":1025},"gradient",{"type":15,"value":1027}," tells training which way to move each weight,\nand roughly how far, to reduce the loss. Here is a deliberately tiny example with one weight\nand a simpler loss formula:",{"type":9,"tag":857,"props":1029,"children":1032},{"className":1030,"code":1031,"filename":-1,"highlights":-1,"language":15,"meta":41},[860],"input = 1                 target = 1\nscore = weight × input\nloss = (score − target)²\n\nweight 0.2 → score 0.2 → loss (0.2 − 1)² = 0.64\nweight 0.3 → score 0.3 → loss (0.3 − 1)² = 0.49\n",[1033],{"type":9,"tag":39,"props":1034,"children":1035},{"__ignoreMap":41},[1036],{"type":15,"value":1031},{"type":9,"tag":18,"props":1038,"children":1039},{},[1040,1042,1047,1049,1054,1056,1061,1062,1067,1069,1074],{"type":15,"value":1041},"Raising the weight from ",{"type":9,"tag":39,"props":1043,"children":1044},{"className":41},[1045],{"type":15,"value":1046},"0.2",{"type":15,"value":1048}," to ",{"type":9,"tag":39,"props":1050,"children":1051},{"className":41},[1052],{"type":15,"value":1053},"0.3",{"type":15,"value":1055}," lowered the loss from ",{"type":9,"tag":39,"props":1057,"children":1058},{"className":41},[1059],{"type":15,"value":1060},"0.64",{"type":15,"value":1048},{"type":9,"tag":39,"props":1063,"children":1064},{"className":41},[1065],{"type":15,"value":1066},"0.49",{"type":15,"value":1068},", so for this\nexample the gradient tells training to move the weight up. Real training uses many examples at\nonce and different loss formulas for retrieval and ranking; the training chapter explains both.\nA ",{"type":9,"tag":24,"props":1070,"children":1071},{},[1072],{"type":15,"value":1073},"sample weight",{"type":15,"value":1075}," can make one past example count more than another in that calculation.",{"type":9,"tag":18,"props":1077,"children":1078},{},[1079,1081,1086,1088,1093,1095,1100],{"type":15,"value":1080},"Repeating this adjustment over the past examples to reduce the loss is called ",{"type":9,"tag":24,"props":1082,"children":1083},{},[1084],{"type":15,"value":1085},"fitting",{"type":15,"value":1087}," the\nmodel to those examples. Bosca stops when the loss stops improving or after a set number of full passes over the\nexamples, called ",{"type":9,"tag":24,"props":1089,"children":1090},{},[1091],{"type":15,"value":1092},"epochs",{"type":15,"value":1094},". The trainer calls TensorFlow's ",{"type":9,"tag":39,"props":1096,"children":1097},{"className":41},[1098],{"type":15,"value":1099},"fit",{"type":15,"value":1101}," function to do\nit, and the rest of this guide says “fit” for this step. A fitted model's weights are fixed\nuntil the next training run fits a new version.",{"type":9,"tag":233,"props":1103,"children":1105},{"id":1104},"quick-reference-after-the-examples",[1106],{"type":15,"value":1107},"Quick reference after the examples",{"type":9,"tag":60,"props":1109,"children":1110},{},[1111,1127],{"type":9,"tag":64,"props":1112,"children":1113},{},[1114],{"type":9,"tag":68,"props":1115,"children":1116},{},[1117,1122],{"type":9,"tag":72,"props":1118,"children":1119},{},[1120],{"type":15,"value":1121},"Word",{"type":9,"tag":72,"props":1123,"children":1124},{},[1125],{"type":15,"value":1126},"Plain meaning",{"type":9,"tag":88,"props":1128,"children":1129},{},[1130,1146,1162,1178,1194,1244,1260,1276,1297,1313,1335,1351,1367,1383,1399],{"type":9,"tag":68,"props":1131,"children":1132},{},[1133,1141],{"type":9,"tag":95,"props":1134,"children":1135},{},[1136],{"type":9,"tag":24,"props":1137,"children":1138},{},[1139],{"type":15,"value":1140},"Model",{"type":9,"tag":95,"props":1142,"children":1143},{},[1144],{"type":15,"value":1145},"A stored calculation that returns scores or suggested item IDs. Bosca has both fixed calculations and ones learned from examples.",{"type":9,"tag":68,"props":1147,"children":1148},{},[1149,1157],{"type":9,"tag":95,"props":1150,"children":1151},{},[1152],{"type":9,"tag":24,"props":1153,"children":1154},{},[1155],{"type":15,"value":1156},"Candidate",{"type":9,"tag":95,"props":1158,"children":1159},{},[1160],{"type":15,"value":1161},"An eligible item the model could return.",{"type":9,"tag":68,"props":1163,"children":1164},{},[1165,1173],{"type":9,"tag":95,"props":1166,"children":1167},{},[1168],{"type":9,"tag":24,"props":1169,"children":1170},{},[1171],{"type":15,"value":1172},"Context",{"type":9,"tag":95,"props":1174,"children":1175},{},[1176],{"type":15,"value":1177},"A saved recommendation setting that narrows eligible items and sets scoring weights, such as the placement being requested.",{"type":9,"tag":68,"props":1179,"children":1180},{},[1181,1189],{"type":9,"tag":95,"props":1182,"children":1183},{},[1184],{"type":9,"tag":24,"props":1185,"children":1186},{},[1187],{"type":15,"value":1188},"Observation",{"type":9,"tag":95,"props":1190,"children":1191},{},[1192],{"type":15,"value":1193},"One training example connecting a reader, an item, what the reader did, and when. Several recorded actions can become one example.",{"type":9,"tag":68,"props":1195,"children":1196},{},[1197,1205],{"type":9,"tag":95,"props":1198,"children":1199},{},[1200],{"type":9,"tag":24,"props":1201,"children":1202},{},[1203],{"type":15,"value":1204},"Label (training target)",{"type":9,"tag":95,"props":1206,"children":1207},{},[1208,1210,1214,1216,1220,1222,1226,1227,1231,1233,1237,1238,1242],{"type":15,"value":1209},"The known number assigned to a past reader-item example. In this guide, completing ",{"type":9,"tag":39,"props":1211,"children":1212},{"className":41},[1213],{"type":15,"value":102},{"type":15,"value":1215}," gets ",{"type":9,"tag":39,"props":1217,"children":1218},{"className":41},[1219],{"type":15,"value":339},{"type":15,"value":1221},", dismissing ",{"type":9,"tag":39,"props":1223,"children":1224},{"className":41},[1225],{"type":15,"value":130},{"type":15,"value":1215},{"type":9,"tag":39,"props":1228,"children":1229},{"className":41},[1230],{"type":15,"value":408},{"type":15,"value":1232},", and rating ",{"type":9,"tag":39,"props":1234,"children":1235},{"className":41},[1236],{"type":15,"value":157},{"type":15,"value":1215},{"type":9,"tag":39,"props":1239,"children":1240},{"className":41},[1241],{"type":15,"value":177},{"type":15,"value":1243},". The model uses it while learning.",{"type":9,"tag":68,"props":1245,"children":1246},{},[1247,1255],{"type":9,"tag":95,"props":1248,"children":1249},{},[1250],{"type":9,"tag":24,"props":1251,"children":1252},{},[1253],{"type":15,"value":1254},"Loss",{"type":9,"tag":95,"props":1256,"children":1257},{},[1258],{"type":15,"value":1259},"A number measuring how poorly a model's scores fit the known labels under a chosen formula. Fitting tries to make it smaller.",{"type":9,"tag":68,"props":1261,"children":1262},{},[1263,1271],{"type":9,"tag":95,"props":1264,"children":1265},{},[1266],{"type":9,"tag":24,"props":1267,"children":1268},{},[1269],{"type":15,"value":1270},"Gradient",{"type":9,"tag":95,"props":1272,"children":1273},{},[1274],{"type":15,"value":1275},"For each weight, which direction and roughly how far to change it to reduce the loss.",{"type":9,"tag":68,"props":1277,"children":1278},{},[1279,1287],{"type":9,"tag":95,"props":1280,"children":1281},{},[1282],{"type":9,"tag":24,"props":1283,"children":1284},{},[1285],{"type":15,"value":1286},"Fitting",{"type":9,"tag":95,"props":1288,"children":1289},{},[1290,1292,1296],{"type":15,"value":1291},"Adjusting a model's weights over many past examples to reduce its loss. TensorFlow's function for this is ",{"type":9,"tag":39,"props":1293,"children":1294},{"className":41},[1295],{"type":15,"value":1099},{"type":15,"value":53},{"type":9,"tag":68,"props":1298,"children":1299},{},[1300,1308],{"type":9,"tag":95,"props":1301,"children":1302},{},[1303],{"type":9,"tag":24,"props":1304,"children":1305},{},[1306],{"type":15,"value":1307},"Sample weight",{"type":9,"tag":95,"props":1309,"children":1310},{},[1311],{"type":15,"value":1312},"A number that controls how much a past example affects training. A larger weight gives that example more influence.",{"type":9,"tag":68,"props":1314,"children":1315},{},[1316,1324],{"type":9,"tag":95,"props":1317,"children":1318},{},[1319],{"type":9,"tag":24,"props":1320,"children":1321},{},[1322],{"type":15,"value":1323},"Vocabulary",{"type":9,"tag":95,"props":1325,"children":1326},{},[1327,1329,1333],{"type":15,"value":1328},"An ordered list of known values for a feature, such as ",{"type":9,"tag":39,"props":1330,"children":1331},{"className":41},[1332],{"type":15,"value":307},{"type":15,"value":1334},". Its order determines each value's position in a numeric row.",{"type":9,"tag":68,"props":1336,"children":1337},{},[1338,1346],{"type":9,"tag":95,"props":1339,"children":1340},{},[1341],{"type":9,"tag":24,"props":1342,"children":1343},{},[1344],{"type":15,"value":1345},"Embedding (vector)",{"type":9,"tag":95,"props":1347,"children":1348},{},[1349],{"type":15,"value":1350},"An ordered list of numbers. Bosca can receive one from a separate text model, learn an ID's table row, or calculate a reader or item output from a tower. Those lists serve different steps.",{"type":9,"tag":68,"props":1352,"children":1353},{},[1354,1362],{"type":9,"tag":95,"props":1355,"children":1356},{},[1357],{"type":9,"tag":24,"props":1358,"children":1359},{},[1360],{"type":15,"value":1361},"Tower",{"type":9,"tag":95,"props":1363,"children":1364},{},[1365],{"type":15,"value":1366},"The sequence of calculations that turns reader information or item information into a vector.",{"type":9,"tag":68,"props":1368,"children":1369},{},[1370,1378],{"type":9,"tag":95,"props":1371,"children":1372},{},[1373],{"type":9,"tag":24,"props":1374,"children":1375},{},[1376],{"type":15,"value":1377},"Ranking head",{"type":9,"tag":95,"props":1379,"children":1380},{},[1381],{"type":15,"value":1382},"Later scoring layers that adjust the tower match using recorded responses and saved context settings.",{"type":9,"tag":68,"props":1384,"children":1385},{},[1386,1394],{"type":9,"tag":95,"props":1387,"children":1388},{},[1389],{"type":9,"tag":24,"props":1390,"children":1391},{},[1392],{"type":15,"value":1393},"Tensor",{"type":9,"tag":95,"props":1395,"children":1396},{},[1397],{"type":15,"value":1398},"An array of numbers or strings consumed by TensorFlow; a batch holds values for several examples.",{"type":9,"tag":68,"props":1400,"children":1401},{},[1402,1410],{"type":9,"tag":95,"props":1403,"children":1404},{},[1405],{"type":9,"tag":24,"props":1406,"children":1407},{},[1408],{"type":15,"value":1409},"Artifact",{"type":9,"tag":95,"props":1411,"children":1412},{},[1413],{"type":15,"value":1414},"The files saved for one model version so a serving process can load it.",{"type":9,"tag":233,"props":1416,"children":1418},{"id":1417},"what-are-we-building",[1419],{"type":15,"value":1420},"What are we building?",{"type":9,"tag":18,"props":1422,"children":1423},{},[1424],{"type":15,"value":1425},"The trainer saves two artifacts:",{"type":9,"tag":60,"props":1427,"children":1428},{},[1429,1449],{"type":9,"tag":64,"props":1430,"children":1431},{},[1432],{"type":9,"tag":68,"props":1433,"children":1434},{},[1435,1439,1444],{"type":9,"tag":72,"props":1436,"children":1437},{},[1438],{"type":15,"value":1409},{"type":9,"tag":72,"props":1440,"children":1441},{},[1442],{"type":15,"value":1443},"Question it answers",{"type":9,"tag":72,"props":1445,"children":1446},{},[1447],{"type":15,"value":1448},"Inputs",{"type":9,"tag":88,"props":1450,"children":1451},{},[1452,1479],{"type":9,"tag":68,"props":1453,"children":1454},{},[1455,1463,1474],{"type":9,"tag":95,"props":1456,"children":1457},{},[1458],{"type":9,"tag":39,"props":1459,"children":1460},{"className":41},[1461],{"type":15,"value":1462},"recommender-content",{"type":9,"tag":95,"props":1464,"children":1465},{},[1466,1468,1472],{"type":15,"value":1467},"“Given ",{"type":9,"tag":39,"props":1469,"children":1470},{"className":41},[1471],{"type":15,"value":102},{"type":15,"value":1473},", which candidate items match its language, category, and other item properties?”",{"type":9,"tag":95,"props":1475,"children":1476},{},[1477],{"type":15,"value":1478},"Eligible item features. Reader responses are not required.",{"type":9,"tag":68,"props":1480,"children":1481},{},[1482,1490,1501],{"type":9,"tag":95,"props":1483,"children":1484},{},[1485],{"type":9,"tag":39,"props":1486,"children":1487},{"className":41},[1488],{"type":15,"value":1489},"recommender-personalized",{"type":9,"tag":95,"props":1491,"children":1492},{},[1493,1495,1499],{"type":15,"value":1494},"“For ",{"type":9,"tag":39,"props":1496,"children":1497},{"className":41},[1498],{"type":15,"value":51},{"type":15,"value":1500},", which eligible items should receive higher scores?”",{"type":9,"tag":95,"props":1502,"children":1503},{},[1504],{"type":15,"value":1505},"Reader and item features, plus prepared observations to learn from.",{"type":9,"tag":18,"props":1507,"children":1508},{},[1509],{"type":15,"value":1510},"The content artifact adds weighted matches between item properties. The personalized artifact\nlearns reader and item embeddings in two neural-network “towers,” then learns a ranking\ncorrection. Later chapters show the arithmetic of both approaches. Separate artifacts let the\ncontent path run even when too few positive observations exist for personalized fitting.",{"type":9,"tag":233,"props":1512,"children":1514},{"id":1513},"read-the-entry-point",[1515],{"type":15,"value":1516},"Read the entry point",{"type":9,"tag":18,"props":1518,"children":1519},{},[1520,1525],{"type":9,"tag":39,"props":1521,"children":1522},{"className":41},[1523],{"type":15,"value":1524},"trainer\u002Fpipeline.py → run_training",{"type":15,"value":1526}," loads data, builds the content model, and fits the\npersonalized model when enough data is available:",{"type":9,"tag":857,"props":1528,"children":1533},{"className":1529,"code":1531,"filename":-1,"highlights":-1,"language":1532,"meta":41},[1530],"language-python","users, interactions, content, categories, signals, feedback = load_data_from_bosca(\n    bosca_url, bosca_token\n)\nif \"context\" in config:\n    content = apply_context(content, config[\"context\"])\n","python",[1534],{"type":9,"tag":39,"props":1535,"children":1536},{"__ignoreMap":41},[1537],{"type":15,"value":1531},{"type":9,"tag":18,"props":1539,"children":1540},{},[1541,1546,1548,1553],{"type":9,"tag":39,"props":1542,"children":1543},{"className":41},[1544],{"type":15,"value":1545},"load_data_from_bosca",{"type":15,"value":1547}," returns six pandas DataFrames: tables with named columns. It calls named\nanalytics queries through Bosca GraphQL and joins supplied semantic embeddings to content.\n",{"type":9,"tag":39,"props":1549,"children":1550},{"className":41},[1551],{"type":15,"value":1552},"apply_context",{"type":15,"value":1554}," narrows the eligible item catalog. Both artifacts use that catalog.",{"type":9,"tag":60,"props":1556,"children":1557},{},[1558,1579],{"type":9,"tag":64,"props":1559,"children":1560},{},[1561],{"type":9,"tag":68,"props":1562,"children":1563},{},[1564,1569,1574],{"type":9,"tag":72,"props":1565,"children":1566},{},[1567],{"type":15,"value":1568},"Variable",{"type":9,"tag":72,"props":1570,"children":1571},{},[1572],{"type":15,"value":1573},"One row describes",{"type":9,"tag":72,"props":1575,"children":1576},{},[1577],{"type":15,"value":1578},"Example field",{"type":9,"tag":88,"props":1580,"children":1581},{},[1582,1605,1629,1660,1684,1714],{"type":9,"tag":68,"props":1583,"children":1584},{},[1585,1593,1598],{"type":9,"tag":95,"props":1586,"children":1587},{},[1588],{"type":9,"tag":39,"props":1589,"children":1590},{"className":41},[1591],{"type":15,"value":1592},"users",{"type":9,"tag":95,"props":1594,"children":1595},{},[1596],{"type":15,"value":1597},"An eligible reader profile",{"type":9,"tag":95,"props":1599,"children":1600},{},[1601],{"type":9,"tag":39,"props":1602,"children":1603},{"className":41},[1604],{"type":15,"value":44},{"type":9,"tag":68,"props":1606,"children":1607},{},[1608,1616,1621],{"type":9,"tag":95,"props":1609,"children":1610},{},[1611],{"type":9,"tag":39,"props":1612,"children":1613},{"className":41},[1614],{"type":15,"value":1615},"interactions",{"type":9,"tag":95,"props":1617,"children":1618},{},[1619],{"type":15,"value":1620},"A recorded event",{"type":9,"tag":95,"props":1622,"children":1623},{},[1624],{"type":9,"tag":39,"props":1625,"children":1626},{"className":41},[1627],{"type":15,"value":1628},"interaction_type",{"type":9,"tag":68,"props":1630,"children":1631},{},[1632,1640,1645],{"type":9,"tag":95,"props":1633,"children":1634},{},[1635],{"type":9,"tag":39,"props":1636,"children":1637},{"className":41},[1638],{"type":15,"value":1639},"content",{"type":9,"tag":95,"props":1641,"children":1642},{},[1643],{"type":15,"value":1644},"A candidate item",{"type":9,"tag":95,"props":1646,"children":1647},{},[1648,1653,1655],{"type":9,"tag":39,"props":1649,"children":1650},{"className":41},[1651],{"type":15,"value":1652},"content_id",{"type":15,"value":1654},", ",{"type":9,"tag":39,"props":1656,"children":1657},{"className":41},[1658],{"type":15,"value":1659},"language_tag",{"type":9,"tag":68,"props":1661,"children":1662},{},[1663,1671,1676],{"type":9,"tag":95,"props":1664,"children":1665},{},[1666],{"type":9,"tag":39,"props":1667,"children":1668},{"className":41},[1669],{"type":15,"value":1670},"categories",{"type":9,"tag":95,"props":1672,"children":1673},{},[1674],{"type":15,"value":1675},"One item-category membership",{"type":9,"tag":95,"props":1677,"children":1678},{},[1679],{"type":9,"tag":39,"props":1680,"children":1681},{"className":41},[1682],{"type":15,"value":1683},"category_id",{"type":9,"tag":68,"props":1685,"children":1686},{},[1687,1695,1700],{"type":9,"tag":95,"props":1688,"children":1689},{},[1690],{"type":9,"tag":39,"props":1691,"children":1692},{"className":41},[1693],{"type":15,"value":1694},"signals",{"type":9,"tag":95,"props":1696,"children":1697},{},[1698],{"type":15,"value":1699},"A configured value about a reader",{"type":9,"tag":95,"props":1701,"children":1702},{},[1703,1708,1709],{"type":9,"tag":39,"props":1704,"children":1705},{"className":41},[1706],{"type":15,"value":1707},"signal_key",{"type":15,"value":1654},{"type":9,"tag":39,"props":1710,"children":1711},{"className":41},[1712],{"type":15,"value":1713},"signal_value",{"type":9,"tag":68,"props":1715,"children":1716},{},[1717,1725,1730],{"type":9,"tag":95,"props":1718,"children":1719},{},[1720],{"type":9,"tag":39,"props":1721,"children":1722},{"className":41},[1723],{"type":15,"value":1724},"feedback",{"type":9,"tag":95,"props":1726,"children":1727},{},[1728],{"type":15,"value":1729},"An explicit rating or dismissal",{"type":9,"tag":95,"props":1731,"children":1732},{},[1733],{"type":9,"tag":39,"props":1734,"children":1735},{"className":41},[1736],{"type":15,"value":1737},"feedback_label",{"type":9,"tag":18,"props":1739,"children":1740},{},[1741,1743,1748],{"type":15,"value":1742},"The loader uses one ",{"type":9,"tag":39,"props":1744,"children":1745},{"className":41},[1746],{"type":15,"value":1747},"as_of",{"type":15,"value":1749}," snapshot time for interaction and feedback queries. An event after\nthat cutoff should not train this version.",{"type":9,"tag":233,"props":1751,"children":1753},{"id":1752},"find-the-code",[1754],{"type":15,"value":1755},"Find the code",{"type":9,"tag":18,"props":1757,"children":1758},{},[1759,1761,1766],{"type":15,"value":1760},"From the workspace root, open ",{"type":9,"tag":39,"props":1762,"children":1763},{"className":41},[1764],{"type":15,"value":1765},"experimentation\u002Fml\u002Frecommendation-trainer\u002F",{"type":15,"value":1767},". Follow these files in\norder:",{"type":9,"tag":656,"props":1769,"children":1770},{},[1771,1781,1791,1801,1811,1821,1831],{"type":9,"tag":660,"props":1772,"children":1773},{},[1774,1779],{"type":9,"tag":39,"props":1775,"children":1776},{"className":41},[1777],{"type":15,"value":1778},"trainer\u002Fdata.py",{"type":15,"value":1780}," loads tables.",{"type":9,"tag":660,"props":1782,"children":1783},{},[1784,1789],{"type":9,"tag":39,"props":1785,"children":1786},{"className":41},[1787],{"type":15,"value":1788},"trainer\u002Fobservations.py",{"type":15,"value":1790}," makes labeled observations.",{"type":9,"tag":660,"props":1792,"children":1793},{},[1794,1799],{"type":9,"tag":39,"props":1795,"children":1796},{"className":41},[1797],{"type":15,"value":1798},"trainer\u002Fdatasets.py",{"type":15,"value":1800}," builds TensorFlow datasets.",{"type":9,"tag":660,"props":1802,"children":1803},{},[1804,1809],{"type":9,"tag":39,"props":1805,"children":1806},{"className":41},[1807],{"type":15,"value":1808},"trainer\u002Fcontent_similarity.py",{"type":15,"value":1810}," builds the exact content path.",{"type":9,"tag":660,"props":1812,"children":1813},{},[1814,1819],{"type":9,"tag":39,"props":1815,"children":1816},{"className":41},[1817],{"type":15,"value":1818},"trainer\u002Fmodels.py",{"type":15,"value":1820}," defines the learned towers and ranking head.",{"type":9,"tag":660,"props":1822,"children":1823},{},[1824,1829],{"type":9,"tag":39,"props":1825,"children":1826},{"className":41},[1827],{"type":15,"value":1828},"trainer\u002Ftraining.py",{"type":15,"value":1830}," fits the models.",{"type":9,"tag":660,"props":1832,"children":1833},{},[1834,1839],{"type":9,"tag":39,"props":1835,"children":1836},{"className":41},[1837],{"type":15,"value":1838},"trainer\u002Fexport.py",{"type":15,"value":1840}," saves and checks serving functions.",{"type":9,"tag":343,"props":1842,"children":1844},{"id":1843},"the-libraries-the-trainer-uses",[1845],{"type":15,"value":1846},"The libraries the trainer uses",{"type":9,"tag":18,"props":1848,"children":1849},{},[1850],{"type":15,"value":1851},"The code leans on a few Python libraries. You do not need to know them in advance; this is\nwhat each one is for:",{"type":9,"tag":60,"props":1853,"children":1854},{},[1855,1876],{"type":9,"tag":64,"props":1856,"children":1857},{},[1858],{"type":9,"tag":68,"props":1859,"children":1860},{},[1861,1866,1871],{"type":9,"tag":72,"props":1862,"children":1863},{},[1864],{"type":15,"value":1865},"Library",{"type":9,"tag":72,"props":1867,"children":1868},{},[1869],{"type":15,"value":1870},"What it is",{"type":9,"tag":72,"props":1872,"children":1873},{},[1874],{"type":15,"value":1875},"What the trainer uses it for",{"type":9,"tag":88,"props":1877,"children":1878},{},[1879,1900,1921,1949,2008],{"type":9,"tag":68,"props":1880,"children":1881},{},[1882,1890,1895],{"type":9,"tag":95,"props":1883,"children":1884},{},[1885],{"type":9,"tag":24,"props":1886,"children":1887},{},[1888],{"type":15,"value":1889},"pandas",{"type":9,"tag":95,"props":1891,"children":1892},{},[1893],{"type":15,"value":1894},"A library for tables with named columns, called DataFrames",{"type":9,"tag":95,"props":1896,"children":1897},{},[1898],{"type":15,"value":1899},"Loading query results and turning events into observations",{"type":9,"tag":68,"props":1901,"children":1902},{},[1903,1911,1916],{"type":9,"tag":95,"props":1904,"children":1905},{},[1906],{"type":9,"tag":24,"props":1907,"children":1908},{},[1909],{"type":15,"value":1910},"NumPy",{"type":9,"tag":95,"props":1912,"children":1913},{},[1914],{"type":15,"value":1915},"A library for fast arrays of numbers",{"type":9,"tag":95,"props":1917,"children":1918},{},[1919],{"type":15,"value":1920},"Holding one column of values per feature before TensorFlow takes over",{"type":9,"tag":68,"props":1922,"children":1923},{},[1924,1932,1944],{"type":9,"tag":95,"props":1925,"children":1926},{},[1927],{"type":9,"tag":24,"props":1928,"children":1929},{},[1930],{"type":15,"value":1931},"TensorFlow",{"type":9,"tag":95,"props":1933,"children":1934},{},[1935,1937,1942],{"type":15,"value":1936},"Google's library for calculating with arrays of numbers (",{"type":9,"tag":24,"props":1938,"children":1939},{},[1940],{"type":15,"value":1941},"tensors",{"type":15,"value":1943},") and for adjusting weights to reduce a loss",{"type":9,"tag":95,"props":1945,"children":1946},{},[1947],{"type":15,"value":1948},"Every model calculation, plus saving the finished models",{"type":9,"tag":68,"props":1950,"children":1951},{},[1952,1960,1972],{"type":9,"tag":95,"props":1953,"children":1954},{},[1955],{"type":9,"tag":24,"props":1956,"children":1957},{},[1958],{"type":15,"value":1959},"Keras",{"type":9,"tag":95,"props":1961,"children":1962},{},[1963,1965,1970],{"type":15,"value":1964},"The part of TensorFlow for building models from layers (",{"type":9,"tag":39,"props":1966,"children":1967},{"className":41},[1968],{"type":15,"value":1969},"tf.keras",{"type":15,"value":1971},")",{"type":9,"tag":95,"props":1973,"children":1974},{},[1975,1977,1982,1983,1988,1989,1994,1995,2000,2002,2006],{"type":15,"value":1976},"The layers (",{"type":9,"tag":39,"props":1978,"children":1979},{"className":41},[1980],{"type":15,"value":1981},"Dense",{"type":15,"value":1654},{"type":9,"tag":39,"props":1984,"children":1985},{"className":41},[1986],{"type":15,"value":1987},"Embedding",{"type":15,"value":1654},{"type":9,"tag":39,"props":1990,"children":1991},{"className":41},[1992],{"type":15,"value":1993},"StringLookup",{"type":15,"value":1654},{"type":9,"tag":39,"props":1996,"children":1997},{"className":41},[1998],{"type":15,"value":1999},"Dropout",{"type":15,"value":2001},"), the loss formulas, the optimizer, and the ",{"type":9,"tag":39,"props":2003,"children":2004},{"className":41},[2005],{"type":15,"value":1099},{"type":15,"value":2007}," loop",{"type":9,"tag":68,"props":2009,"children":2010},{},[2011,2027,2032],{"type":9,"tag":95,"props":2012,"children":2013},{},[2014,2019,2021,2026],{"type":9,"tag":24,"props":2015,"children":2016},{},[2017],{"type":15,"value":2018},"TensorFlow Recommenders",{"type":15,"value":2020}," (imported as ",{"type":9,"tag":39,"props":2022,"children":2023},{"className":41},[2024],{"type":15,"value":2025},"tfrs",{"type":15,"value":1971},{"type":9,"tag":95,"props":2028,"children":2029},{},[2030],{"type":15,"value":2031},"A TensorFlow add-on with ready-made pieces for recommendation models",{"type":9,"tag":95,"props":2033,"children":2034},{},[2035,2037,2042],{"type":15,"value":2036},"The retrieval and ranking ",{"type":9,"tag":24,"props":2038,"children":2039},{},[2040],{"type":15,"value":2041},"tasks",{"type":15,"value":2043}," in the training chapter, and the nearest-item search in the export chapter",{"type":9,"tag":18,"props":2045,"children":2046},{},[2047,2049,2054,2055,2060,2062,2067],{"type":15,"value":2048},"When the guide writes ",{"type":9,"tag":39,"props":2050,"children":2051},{"className":41},[2052],{"type":15,"value":2053},"tf.",{"type":15,"value":1654},{"type":9,"tag":39,"props":2056,"children":2057},{"className":41},[2058],{"type":15,"value":2059},"tf.keras.",{"type":15,"value":2061},", or ",{"type":9,"tag":39,"props":2063,"children":2064},{"className":41},[2065],{"type":15,"value":2066},"tfrs.",{"type":15,"value":2068},", the code is calling one of these\nlibraries rather than Bosca code.",{"type":9,"tag":18,"props":2070,"children":2071},{},[2072,2077],{"type":9,"tag":24,"props":2073,"children":2074},{},[2075],{"type":15,"value":2076},"Before continuing:",{"type":15,"value":2078}," Which values in the example are features, and which are observed responses?\nThe answer: language and category are item features; completion, dismissal, and rating are responses.",1790541170519]