{"id":467792,"date":"2025-07-20T21:05:30","date_gmt":"2025-07-20T21:05:30","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=467792"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=467792","title":{"rendered":"<span>\u0421\u043e\u0431\u0438\u0440\u0430\u0435\u043c MVP product search: \u0434\u043e\u043e\u0431\u0443\u0447\u0435\u043d\u0438\u0435 E5 \u0438 \u0432\u0435\u0431-\u0441\u0435\u0440\u0432\u0438\u0441 \u0434\u043b\u044f \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044f \u043f\u043e\u0438\u0441\u043a\u043e\u0432\u044b\u0445 \u0432\u044b\u0434\u0430\u0447<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u0427\u0442\u043e \u0432\u0430\u0436\u043d\u0435\u0435: <strong>\u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043f\u0440\u043e\u0434\u0443\u043a\u0442<\/strong>, \u0438\u043b\u0438 <strong>\u0434\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0435\u0433\u043e \u0434\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f<\/strong>? \u041e\u0431\u0430 \u044d\u0442\u0430\u043f\u0430 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b. \u0421\u0435\u0433\u043e\u0434\u043d\u044f \u043e\u0431\u0441\u0443\u0434\u0438\u043c <strong>\u0432\u0442\u043e\u0440\u043e\u0439<\/strong>. \u041a\u0430\u043a \u043d\u0430\u043c \u043f\u043e\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u043f\u043e\u0438\u0441\u043a\u043e\u0432\u0443\u044e e-com \u0441\u0438\u0441\u0442\u0435\u043c\u0443.<\/p>\n<p>\u041f\u043e\u043a\u0430\u0436\u0435\u043c, \u0447\u0442\u043e \u0432 \u0441\u043b\u043e\u0432\u043e <strong>\u043b\u043e\u0433\u0438\u0441\u0442\u0438\u043a\u0430 \u0442\u043e\u0432\u0430\u0440\u0430<\/strong> \u0432\u0445\u043e\u0434\u044f\u0442 \u0441\u043b\u043e\u0436\u043d\u044b\u0435 \u0437\u0430\u0434\u0430\u0447\u0438 \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e: <strong>\u043f\u0435\u0440\u0435\u0432\u0435\u0437\u0442\u0438 \u043d\u0430\u0443\u0448\u043d\u0438\u043a\u0438 \u0438\u0437 \u041a\u0438\u0442\u0430\u044f \u0432 \u0410\u043c\u0435\u0440\u0438\u043a\u0443<\/strong>, \u043d\u043e \u0438 <strong>\u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043f\u043e\u0438\u0441\u043a\u043e\u0432\u043e\u0439 \u0432\u044b\u0434\u0430\u0447\u0438<\/strong> \u043f\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0443.<\/p>\n<p>\u0411\u044b\u0441\u0442\u0440\u043e \u0441\u043e\u0431\u0435\u0440\u0435\u043c <strong>\u043f\u043e\u0438\u0441\u043a\u043e\u0432\u043e\u0439 MVP-\u0441\u0435\u0440\u0432\u0438\u0441<\/strong>. <strong>\u0414\u043e\u043e\u0431\u0443\u0447\u0438\u043c \u043c\u043e\u0434\u0435\u043b\u044c E5<\/strong> \u043d\u0430 \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u043e\u0442 <strong>Amazon<\/strong>. \u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c \u043c\u0435\u0442\u0440\u0438\u043a\u0438 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0430 \u0438 \u0441\u0440\u0430\u0432\u043d\u0438\u043c <strong>BM25<\/strong>, <strong>pretrain E5<\/strong> \u0438 <strong>fine-tune E5<\/strong>. \u0422\u0430\u043a \u0436\u0435 <strong>\u0432\u0437\u0433\u043b\u044f\u043d\u0435\u043c \u0433\u043b\u0430\u0437\u0430\u043c\u0438 \u0441 \u043e\u0442\u043b\u0430\u0434\u043e\u0447\u043d\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0435\u0439<\/strong> \u0438 \u043f\u0440\u043e\u0430\u043d\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u043c <strong>\u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043f\u043e\u0438\u0441\u043a\u043e\u0432\u044b\u0445 \u0432\u044b\u0434\u0430\u0447<\/strong>.<\/p>\n<p>\u0418 \u043f\u043e\u0434 \u043a\u043e\u043d\u0435\u0446 \u043e\u0431\u0441\u0443\u0434\u0438\u043c \u043a\u0430\u043a\u0438\u0445 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0439 \u0435\u0449\u0435 \u043d\u0435 \u0445\u0432\u0430\u0442\u0430\u0435\u0442 \u0438 \u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c, \u0435\u0441\u043b\u0438 \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u044e\u0442 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u0442\u0440\u0443\u0434\u043d\u043e\u0441\u0442\u0438.<\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/wn\/ql\/am\/wnqlamwtggo_0-vkuhhczasd004.png\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/webt\/wn\/ql\/am\/wnqlamwtggo_0-vkuhhczasd004.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/webt\/wn\/ql\/am\/wnqlamwtggo_0-vkuhhczasd004.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/figure>\n<blockquote>\n<p>\u26a0\ufe0f \u0414\u0438\u0441\u043a\u043b\u0435\u0439\u043c\u0435\u0440<br \/> \u0412 \u043f\u0435\u0440\u0432\u0443\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u0446\u0435\u043b\u044c &#8212; \u043f\u043e\u0441\u0442\u0440\u043e\u0438\u0442\u044c MVP <strong>\u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0435\u0435<\/strong> \u0440\u0435\u0448\u0435\u043d\u0438\u0435, \u0447\u0442\u043e\u0431\u044b \u0441\u0440\u0430\u0437\u0443 \u043d\u0430\u0447\u0430\u0442\u044c \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c \u0433\u0438\u043f\u043e\u0442\u0435\u0437\u044b. \u041f\u0440\u0435\u0434\u043f\u043e\u043b\u043e\u0436\u0438\u043c \u043c\u044b \u043d\u0430 \u0445\u0430\u043a\u0430\u0442\u043e\u043d\u0435 \u0438 \u0445\u043e\u0442\u0438\u043c \u0435\u0433\u043e \u0432\u044b\u0439\u0433\u0440\u0430\u0442\u044c, \u0442\u043e\u0433\u0434\u0430 \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c  \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u0443\u044e ML \u0441\u0438\u0441\u0442\u0435\u043c\u0443 \u0438 \u0443 \u043d\u0430\u0441 \u043c\u0430\u043b\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438!<\/p>\n<\/blockquote>\n<details class=\"spoiler\">\n<summary>\ud83d\ude80 \u041f\u043e\u0447\u0435\u043c\u0443 \u0432\u0430\u0436\u043d\u043e \u0443\u043c\u0435\u0442\u044c \u0441\u0430\u043c\u043e\u043c\u0443 \u0431\u044b\u0441\u0442\u0440\u043e \u043f\u0438\u0441\u0430\u0442\u044c MVP \u0440\u0435\u0448\u0435\u043d\u0438\u044f? <\/summary>\n<div class=\"spoiler__content\">\n<p>\u0412\u044b \u0443\u043c\u0435\u0435\u0442\u0435 \u0431\u0440\u043e\u0441\u0430\u0442\u044c \u043a\u0430\u043c\u0435\u043d\u044c \u0432 \u0432\u043e\u0434\u0443 \u0442\u0430\u043a, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u0448\u043b\u043e \u043c\u043d\u043e\u0433\u043e \u0431\u043b\u0438\u043d\u0447\u0438\u043a\u043e\u0432? \u041d\u0430 \u0441\u043b\u043e\u0432\u0430\u0445 \u2014 \u043f\u0440\u043e\u0441\u0442\u043e: \u043a\u0438\u043d\u0443\u043b \u0438 \u0433\u043e\u0442\u043e\u0432\u043e. \u0410 \u043d\u0430 \u0434\u0435\u043b\u0435 \u2014 \u0441\u043e\u0432\u0441\u0435\u043c \u043d\u0435\u0442.<\/p>\n<p>\u041a\u043e\u0433\u0434\u0430 \u0442\u0440\u043e\u0433\u0430\u0435\u0448\u044c \u0437\u0430\u0434\u0430\u0447\u0443 \u0441\u0430\u043c \u2014 \u0441\u0442\u0430\u043b\u043a\u0438\u0432\u0430\u0435\u0448\u044c\u0441\u044f \u0441 \u0442\u0440\u0443\u0434\u043d\u043e\u0441\u0442\u044f\u043c\u0438, \u043f\u0440\u043e\u0445\u043e\u0434\u0438\u0448\u044c \u0438\u0445 \u0430, \u0441\u0430\u043c\u043e\u0435 \u0433\u043b\u0430\u0432\u043d\u043e\u0435, \u043b\u0443\u0447\u0448\u0435 \u0432\u0441\u0435\u0433\u043e \u0437\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u0435\u0448\u044c \u0438 \u0443\u0447\u0438\u0448\u044c\u0441\u044f!<br \/> \u0422\u0430\u043a \u0443\u0441\u0442\u0440\u043e\u0435\u043d\u0430 \u0433\u043e\u043b\u043e\u0432\u0430: \u043e\u043d\u0430 \u0445\u0443\u0436\u0435 \u0443\u0447\u0438\u0442\u0441\u044f \u043d\u0430 \u0447\u0443\u0436\u043e\u043c \u043e\u043f\u044b\u0442\u0435 \u0438 \u0433\u043e\u0440\u0430\u0437\u0434\u043e \u043b\u0443\u0447\u0448\u0435 \u2014 \u043d\u0430 \u0441\u0432\u043e\u0451\u043c.<\/p>\n<hr\/>\n<p>\u0422\u0430\u043a\u0436\u0435, \u043a\u043e\u0433\u0434\u0430 \u0441\u0440\u043e\u043a\u0438 \u0441\u0436\u0430\u0442\u044b \u2014 \u0442\u044b \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0432\u044b\u0431\u0438\u0440\u0430\u0435\u0448\u044c <strong>\u0441\u0430\u043c\u044b\u0435 \u043d\u0443\u0436\u043d\u044b\u0435 \u0438 \u0440\u0430\u0431\u043e\u0447\u0438\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u0432 \u0442\u0435\u043a\u0443\u0449\u0438\u0445 \u0443\u0441\u043b\u043e\u0432\u0438\u044f\u0445<\/strong>. \u042d\u0442\u043e \u043d\u0435 \u0445\u0430\u043e\u0441, \u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0430. \u0414\u0430\u0436\u0435 \u0435\u0441\u0442\u044c \u043f\u043e\u0434\u0445\u043e\u0434 \u2014 <a href=\"https:\/\/ru.wikipedia.org\/wiki\/Cynefin_framework\" rel=\"noopener noreferrer nofollow\">\u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a Cynefin<\/a>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0433\u043e\u0432\u043e\u0440\u0438\u0442: <strong>\u0432 \u0440\u0430\u0437\u043d\u044b\u0445 \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u044f\u0445 \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u044e\u0442\u0441\u044f \u043f\u043e-\u0440\u0430\u0437\u043d\u043e\u043c\u0443<\/strong>.<\/p>\n<p>\u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0442\u0435\u0431\u0435 \u043c\u043e\u0433\u0443\u0442 \u0441\u043a\u0430\u0437\u0430\u0442\u044c, \u0447\u0442\u043e \u0438\u043d\u0444\u0435\u0440\u0435\u043d\u0441 \u043c\u043e\u0434\u0435\u043b\u0438 <em>\u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e<\/em> \u043d\u0443\u0436\u043d\u043e \u0434\u0435\u043b\u0430\u0442\u044c \u043d\u0430 GPU. \u041d\u043e \u044d\u0442\u043e \u043d\u0435 \u0432\u0441\u0435\u0433\u0434\u0430 \u0442\u0430\u043a: <strong>\u043d\u0430 CPU \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u043e\u0449\u0435 \u0438 \u0434\u0435\u0448\u0435\u0432\u043b\u0435 \u0432\u044b\u0440\u0430\u0441\u0442\u0438 \u0433\u043e\u0440\u0438\u0437\u043e\u043d\u0442\u0430\u043b\u044c\u043d\u043e<\/strong>.<\/p>\n<p>\u0418\u043b\u0438 \u0432\u043e\u0442 \u0435\u0449\u0451 \u043f\u0440\u0438\u043c\u0435\u0440: \u043d\u0435 \u0432\u0441\u0435\u0433\u0434\u0430 \u043d\u0443\u0436\u0435\u043d \u0438\u043d\u0434\u0435\u043a\u0441 \u043f\u043e \u0431\u0430\u0437\u0435 \u0442\u043e\u0432\u0430\u0440\u043e\u0432. \u0418\u043d\u043e\u0433\u0434\u0430 <strong>\u043f\u0440\u044f\u043c\u043e\u0439 \u043f\u0440\u043e\u0445\u043e\u0434 \u043f\u043e \u0432\u0441\u0435\u043c \u0442\u043e\u0432\u0430\u0440\u0430\u043c \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043d\u0435 \u0445\u0443\u0436\u0435<\/strong>, \u0430 \u043f\u0440\u043e\u0431\u043b\u0435\u043c \u0441 \u043f\u0435\u0440\u0435\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u0435\u043c \u0438 \u043b\u0438\u0448\u043d\u0438\u043c \u043a\u043e\u0434\u043e\u043c \u2014 \u043c\u0435\u043d\u044c\u0448\u0435.<\/p>\n<p>\u0418\u043c\u0435\u043d\u043d\u043e \u043f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0435\u0433\u043e \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u2014 \u043f\u043e\u0434 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f\u043c\u0438, \u0441 \u0444\u0438\u0434\u0431\u0435\u043a\u043e\u043c \u0438 \u043e\u0448\u0438\u0431\u043a\u0430\u043c\u0438 \u2014 <strong>\u0432\u044b\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0438\u043d\u0442\u0443\u0438\u0446\u0438\u044f<\/strong>, \u0447\u0442\u043e, \u0433\u0434\u0435 \u0438 \u043a\u043e\u0433\u0434\u0430 \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0442\u044c.<br \/> \u0422\u0430 \u0441\u0430\u043c\u0430\u044f \u0438\u043d\u0436\u0435\u043d\u0435\u0440\u043d\u0430\u044f \u0447\u0443\u0439\u043a\u0430 \u2014 \u043e\u043d\u0430 \u043d\u0435 \u0438\u0437 \u043a\u043d\u0438\u0436\u0435\u043a. \u041e\u043d\u0430 \u0438\u0437 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0438.<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>\ud83e\udd28 \u041d\u0430 \u0441\u043a\u043e\u0440\u044e \u0440\u0443\u043a\u0443 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442\u0441\u044f \u043f\u043b\u043e\u0445\u043e\u0439 \u043a\u043e\u0434. \u041a\u0430\u043a \u044d\u0442\u043e\u0442 \u043d\u0430\u0432\u044b\u043a \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u043c\u043d\u0435 \u0432 \u0440\u0430\u0431\u043e\u0442\u0435?<\/summary>\n<div class=\"spoiler__content\">\n<p>\u041d\u0430 \u0441\u0430\u043c\u043e\u043c \u0434\u0435\u043b\u0435 \u2014 \u0441\u043a\u043e\u0440\u0435\u0435 \u043d\u0430\u043e\u0431\u043e\u0440\u043e\u0442. \u0421 \u043a\u0430\u0436\u0434\u044b\u043c \u0437\u0430\u0432\u0435\u0440\u0448\u0451\u043d\u043d\u044b\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u043c, \u0441 \u043a\u0430\u0436\u0434\u044b\u043c \u043d\u0435\u0432\u0435\u0440\u043d\u044b\u043c \u0440\u0435\u0448\u0435\u043d\u0438\u0435\u043c \u0442\u044b \u043e\u0442\u0431\u0440\u0430\u0441\u044b\u0432\u0430\u0435\u0448\u044c \u043b\u0438\u0448\u043d\u0435\u0435 \u0438 \u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0448\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0443\u0436\u043d\u043e\u0435. \u0422\u044b \u0443\u0436\u0435 \u0437\u043d\u0430\u0435\u0448\u044c, \u0447\u0442\u043e \u0442\u0443\u0442 \u0441\u0440\u0435\u0437\u0430\u043b \u0438 \u043f\u0438\u0441\u0430\u043b \u043d\u0435\u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u043a\u043e\u0434 \u0438 \u043f\u043e\u0442\u043e\u043c \u0441\u043f\u043e\u0442\u044b\u043a\u0430\u043b\u0441\u044f \u0438 \u0442\u0443\u0442 \u0442\u0435\u043f\u0435\u0440\u044c  \u043f\u0440\u043e\u0441\u0442\u043e \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u0435\u0439 \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e!<br \/> \u0425\u043e\u0447\u0435\u0448\u044c \u043d\u0435 \u0445\u043e\u0447\u0435\u0448\u044c \u2014 <strong>\u0441\u0440\u0435\u0434\u043d\u0435\u0435 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u043e \u0442\u0432\u043e\u0435\u0433\u043e \u043a\u043e\u0434\u0430 \u043c\u043e\u043d\u043e\u0442\u043e\u043d\u043d\u043e \u0440\u0430\u0441\u0442\u0451\u0442<\/strong>.<\/p>\n<p>\u042d\u0442\u043e \u043a\u0430\u0441\u0430\u0435\u0442\u0441\u044f \u0438 \u0441\u0430\u043c\u043e\u0433\u043e \u043a\u043e\u0434\u0430: \u0441\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0435\u043c \u0442\u044b \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0448\u044c \u043f\u0438\u0441\u0430\u0442\u044c \u00ab\u0440\u0443\u043a\u043e\u0439 \u043d\u0430\u0431\u0438\u0442\u043e\u0439\u00bb \u2014 \u043d\u0435 \u0433\u0430\u0434\u0430\u0435\u0448\u044c, \u043d\u043e\u0440\u043c \u0438\u043b\u0438 \u043d\u0435 \u043d\u043e\u0440\u043c, \u0442\u044b \u043f\u0440\u043e\u0441\u0442\u043e \u0437\u043d\u0430\u0435\u0448\u044c.<br \/> \u0418 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b: \u043f\u043e\u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0438\u043d\u0442\u0443\u0438\u0446\u0438\u044f, <strong>\u0447\u0442\u043e \u0437\u0430\u043b\u043e\u0436\u0438\u0442\u044c \u0441\u0435\u0439\u0447\u0430\u0441<\/strong>, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u0442\u043e\u043c \u043d\u0435 \u0441\u043e\u0435\u0434\u0438\u043d\u044f\u0442\u044c \u0432\u0441\u0451 \u043a\u043e\u0441\u0442\u044b\u043b\u044f\u043c\u0438.<\/p>\n<hr\/>\n<p>\u0412\u0434\u0440\u0443\u0433 \u0432\u044b \u0443\u0432\u0438\u0434\u0435\u043b\u0438 \u043a\u043e\u0441\u0442\u044b\u043b\u044c. \u0416\u0451\u0441\u0442\u043a\u0438\u0439, \u0441\u0442\u0440\u0430\u043d\u043d\u044b\u0439, \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u0447\u043d\u044b\u0439. \u042d\u0442\u043e \u043f\u043b\u043e\u0445\u043e\u0439 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0441\u0442?<br \/> \u042f \u0431\u044b \u043d\u0435 \u0441\u043f\u0435\u0448\u0438\u043b \u043a\u0438\u0434\u0430\u0442\u044c\u0441\u044f \u043f\u043e\u043c\u0438\u0434\u043e\u0440\u0430\u043c\u0438.<\/p>\n<p>\u0421\u0434\u0435\u043b\u0430\u0442\u044c \u0441\u0438\u0441\u0442\u0435\u043c\u0443, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043e\u0445\u0432\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u0434\u0435\u0441\u044f\u0442\u043a\u0438 \u0430\u0441\u043f\u0435\u043a\u0442\u043e\u0432 \u2014 \u0441\u043b\u043e\u0436\u043d\u043e, \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e \u0432 \u043e\u0434\u0438\u043d\u043e\u0447\u043a\u0443.<br \/> \u0415\u0441\u043b\u0438 \u0447\u0435\u043b\u043e\u0432\u0435\u043a \u0432 \u043a\u0430\u0436\u0434\u043e\u043c \u0448\u0430\u0433\u0435 \u043f\u0438\u0448\u0435\u0442 \u043a\u043e\u0441\u0442\u044b\u043b\u0438 \u0438 \u043d\u0435 \u043f\u043e\u043d\u0438\u043c\u0430\u0435\u0442, \u0447\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u0442 \u2014 \u0441\u043a\u043e\u0440\u0435\u0435 \u0432\u0441\u0435\u0433\u043e, \u043e\u043d \u043f\u0440\u043e\u0441\u0442\u043e, \u0441\u043a\u043e\u0440\u0435\u0435 \u0432\u0441\u0435\u0433\u043e, \u043d\u0435 \u0434\u043e\u0439\u0434\u0451\u0442 \u0434\u043e \u0444\u0438\u043d\u0430\u043b\u0430.<br \/> \u041e\u043d \u0441\u043f\u043e\u0442\u043a\u043d\u0451\u0442\u0441\u044f \u043d\u0430 \u043a\u0430\u043a\u043e\u043c-\u043d\u0438\u0431\u0443\u0434\u044c <code>gpt<\/code>-\u0437\u0430\u043f\u0440\u043e\u0441\u0435, \u043d\u0435 \u0441\u043c\u043e\u0436\u0435\u0442 \u0440\u0430\u0437\u0433\u0440\u0435\u0441\u0442\u0438 \u0431\u0430\u0433 \u2014 \u0438 \u0432\u0441\u0451 \u0437\u0430\u043a\u043e\u043d\u0447\u0438\u0442\u0441\u044f.<\/p>\n<p>\u041d\u043e \u0435\u0441\u043b\u0438 \u043f\u0440\u043e\u0434\u0443\u043a\u0442 <strong>\u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442<\/strong>, \u0440\u0435\u0448\u0430\u0435\u0442 \u0437\u0430\u0434\u0430\u0447\u0443, \u0438 \u0432 \u043d\u0451\u043c <strong>\u0436\u0451\u0441\u0442\u043a\u0438\u0435, \u043d\u043e \u0442\u043e\u0447\u0435\u0447\u043d\u044b\u0435 \u043a\u043e\u0441\u0442\u044b\u043b\u0438<\/strong> \u2014 \u0441\u043a\u043e\u0440\u0435\u0435 \u0432\u0441\u0435\u0433\u043e, \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0441\u0442 <strong>\u0441\u0434\u0435\u043b\u0430\u043b \u044d\u0442\u043e \u043e\u0441\u043e\u0437\u043d\u0430\u043d\u043d\u043e<\/strong>. \u0427\u0442\u043e\u0431\u044b <strong>\u043f\u043e\u0431\u044b\u0441\u0442\u0440\u0435\u0435 \u0441\u043e\u0431\u0440\u0430\u0442\u044c MVP<\/strong>.<br \/> \u0418, \u0432\u043f\u043e\u043b\u043d\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u043e\u043d <strong>\u0443\u0436\u0435 \u0434\u0435\u0440\u0436\u0438\u0442 \u0432 \u0433\u043e\u043b\u043e\u0432\u0435, \u043a\u0430\u043a \u044d\u0442\u043e \u043f\u043e\u0442\u043e\u043c \u0438\u0441\u043f\u0440\u0430\u0432\u0438\u0442\u044c<\/strong>.<\/p>\n<p>\ud83d\udca1 \u041d\u0430\u0441\u0442\u043e\u044f\u0449\u0438\u0439 \u043d\u0430\u0432\u044b\u043a \u2014 \u044d\u0442\u043e \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u044c \u0442\u0440\u0435\u0439\u0434-\u043e\u0444\u0444:<br \/> \u043c\u0435\u0436\u0434\u0443 &#171;\u043a\u0440\u0430\u0441\u0438\u0432\u043e\u0439 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u043e\u0439&#187; \u0438 &#171;\u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0438\u043c, \u043f\u043e\u043d\u044f\u0442\u043d\u044b\u043c, \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u043c\u044b\u043c \u043a\u043e\u0434\u043e\u043c&#187;.<\/p>\n<p>\u041f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u0438\u043d\u0430\u0447\u0435 \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c\u0441\u044f \u0432\u043e\u0442 \u044d\u0442\u043e:  <a href=\"https:\/\/www.youtube.com\/watch?v=gq6ZAuUQq9M&amp;list=LL&amp;index=3&amp;t=1749s\" rel=\"noopener noreferrer nofollow\">\u043f\u0440\u0438\u043c\u0435\u0440, \u043a\u0430\u043a \u0430\u0432\u0442\u043e\u0440 \u043a\u043d\u0438\u0433\u0438 \u043f\u043e \u0447\u0438\u0441\u0442\u043e\u043c\u0443 \u043a\u043e\u0434\u0443 \u043d\u0430\u043f\u0438\u0441\u0430\u043b Android-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043f\u0430\u0434\u0430\u0435\u0442 \u043d\u0430 \u043f\u0435\u0440\u0432\u043e\u043c \u044e\u0437\u043a\u0435\u0439\u0441\u0435<\/a><\/p>\n<\/div>\n<\/details>\n<p>\u041f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u043c \u043a \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438!<\/p>\n<hr\/>\n<h3>\u041f\u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0437\u0430\u0434\u0430\u0447\u0438<\/h3>\n<p>\u041d\u0443\u0436\u043d\u043e \u0441\u043e\u0431\u0440\u0430\u0442\u044c MVP-\u0441\u0435\u0440\u0432\u0438\u0441 \u0441 \u043d\u0430\u0448\u0435\u0439 \u043e\u0431\u0443\u0447\u0435\u043d\u043d\u043e\u0439 \u043c\u043e\u0434\u0435\u043b\u044c\u044e \u0434\u043b\u044f \u043f\u043e\u0438\u0441\u043a\u0430 \u0442\u043e\u0432\u0430\u0440\u043e\u0432 \u043f\u043e \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u043e\u043c\u0443 \u0437\u0430\u043f\u0440\u043e\u0441\u0443 (<a href=\"https:\/\/huggingface.co\/datasets?search=product+search\" rel=\"noopener noreferrer nofollow\">E-commerce Product Search<\/a>), \u043e\u0431\u0449\u0438\u0439 \u0432\u0438\u0434 \u0437\u0430\u0434\u0430\u0447\u0438 &#8212; <a href=\"https:\/\/en.wikipedia.org\/wiki\/Information_retrieval\" rel=\"noopener noreferrer nofollow\">IR (Information retrieval )<\/a>. \u0426\u0435\u043b\u044c \u2014 \u043d\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u0441\u043e\u0432\u043f\u0430\u0434\u0435\u043d\u0438\u0435 \u043f\u043e \u0441\u043b\u043e\u0432\u0430\u043c, \u0430 \u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u0435 e-com \u0438\u043d\u0442\u0435\u043d\u0442\u0430 \u0437\u0430\u043f\u0440\u043e\u0441\u0430. \u041f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e:<\/p>\n<ul>\n<li>\n<p>\u041d\u0430\u0437\u0432\u0430\u043d\u0438\u044f \u0442\u043e\u0432\u0430\u0440\u043e\u0432 \u0447\u0430\u0441\u0442\u043e \u043d\u0435 \u0433\u043e\u0432\u043e\u0440\u044f\u0442 \u043f\u0440\u044f\u043c\u043e, \u0447\u0442\u043e \u0437\u0430 \u043f\u0440\u043e\u0434\u0443\u043a\u0442 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0435\u0441\u043b\u0438 \u043f\u0440\u043e\u0434\u0430\u0435\u0442\u0441\u044f \u043a\u043d\u0438\u0433\u0430 &#8212; \u043d\u0435 \u0432\u0441\u0435\u0433\u0434\u0430 \u0435\u0441\u0442\u044c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u0432 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0438 \u043e\u0431 \u044d\u0442\u043e\u043c)<\/p>\n<\/li>\n<li>\n<p>\u0424\u043e\u0440\u043c\u0443\u043b\u0438\u0440\u043e\u0432\u043a\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u043d\u0435\u0441\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u044b \u0438 \u0441\u0443\u0431\u044a\u0435\u043a\u0442\u0438\u0432\u043d\u044b<\/p>\n<\/li>\n<li>\n<p>\u0420\u0435\u043b\u0435\u0432\u0430\u043d\u0442\u043d\u043e\u0441\u0442\u044c \u2014 \u043d\u0435 \u0431\u0438\u043d\u0430\u0440\u043d\u0430\u044f, \u0435\u0441\u0442\u044c \u00ab\u043f\u043e\u0447\u0442\u0438 \u0442\u043e\u00bb \u0438 \u00ab\u0432\u043e\u043e\u0431\u0449\u0435 \u043c\u0438\u043c\u043e\u00bb<\/p>\n<\/li>\n<li>\n<p>\u041e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u043e\u0435 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0442\u043e\u0432\u0430\u0440\u043e\u0432 \u043d\u0435 \u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442 \u0438\u0445 \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u0443\u044e \u0440\u0435\u043b\u0435\u0432\u0430\u043d\u0442\u043d\u043e\u0441\u0442\u044c<\/p>\n<\/li>\n<\/ul>\n<blockquote>\n<p>\u041a\u043e\u0440\u043e\u0442\u043a\u043e \u043e\u043f\u0438\u0448\u0435\u043c \u0440\u0435\u0448\u0435\u043d\u0438\u0435: \u0431\u0443\u0434\u0435\u043c \u0434\u043e\u043e\u0431\u0443\u0447\u0430\u0442\u044c <a href=\"https:\/\/www.microsoft.com\/en-us\/research\/wp-content\/uploads\/2016\/02\/cikm2013_DSSM_fullversion.pdf\" rel=\"noopener noreferrer nofollow\">DSSM<\/a> (\u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0435\u0434\u0438\u043d\u043e\u0439 \u043e\u0434\u043d\u043e\u0439 \u0431\u0430\u0448\u043d\u0438 \u0438 \u0441\u0442\u0430\u0440\u0442\u043e\u0432\u043e\u0439 \u0442\u043e\u0447\u043a\u0438 \u0432\u043e\u0437\u044c\u043c\u0435\u043c <a href=\"https:\/\/huggingface.co\/intfloat\/multilingual-e5-small\" rel=\"noopener noreferrer nofollow\">pretrain E5<\/a>) \u043d\u0430 <a href=\"https:\/\/huggingface.co\/datasets\/tasksource\/esci\" rel=\"noopener noreferrer nofollow\">\u0434\u0430\u043d\u043d\u044b\u0445 \u043e\u0442 Amazon<\/a>. Web \u0441\u0435\u0440\u0432\u0438\u0441 \u0441 \u043e\u0442\u043b\u0430\u0434\u043e\u0447\u043d\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0435\u0439 \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u043d\u0430 <a href=\"https:\/\/streamlit.io\/\" rel=\"noopener noreferrer nofollow\">Streamlit<\/a>.<\/p>\n<\/blockquote>\n<h3>\u0414\u0430\u0442\u0430\u0441\u0435\u0442: Amazon ESCI<\/h3>\n<p>\u0411\u0435\u0440\u0451\u043c \u0434\u0430\u0442\u0430\u0441\u0435\u0442 <a href=\"https:\/\/huggingface.co\/datasets\/tasksource\/esci\" rel=\"noopener noreferrer nofollow\">Amazon ESCI<\/a> \u0441 HuggingFace. \u041e\u043d \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0438 \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0435 \u0441 \u043d\u0438\u043c\u0438 \u0442\u043e\u0432\u0430\u0440\u044b, \u0440\u0430\u0437\u043c\u0435\u0447\u0435\u043d\u043d\u044b\u0435 \u043f\u043e \u0441\u0442\u0435\u043f\u0435\u043d\u0438 \u0440\u0435\u043b\u0435\u0432\u0430\u043d\u0442\u043d\u043e\u0441\u0442\u0438: <code>exact<\/code>, <code>substitute<\/code>, <code>irrelevant<\/code>.<\/p>\n<p>\u041f\u043e\u0447\u0435\u043c\u0443 \u043e\u043d \u0445\u043e\u0440\u043e\u0448:<\/p>\n<ul>\n<li>\n<p>\u0414\u0430\u043d\u043d\u044b\u0435 \u0438\u0437 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u0433\u043e e-commerce \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0430,<\/p>\n<\/li>\n<li>\n<p>\u041c\u043d\u043e\u0433\u043e \u0448\u0443\u043c\u0430 \u2014 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044f \u0442\u043e\u0432\u0430\u0440\u043e\u0432 \u043d\u0435\u043f\u043e\u043b\u043d\u044b\u0435 \u0438\u043b\u0438 \u043e\u0431\u043e\u0431\u0449\u0451\u043d\u043d\u044b\u0435,<\/p>\n<\/li>\n<li>\n<p>\u0417\u0430\u043f\u0440\u043e\u0441\u044b \u0440\u0430\u0437\u043d\u043e\u043f\u043b\u0430\u043d\u043e\u0432\u044b\u0435: \u043e\u0442 \u0442\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u0434\u043e \u0431\u044b\u0442\u043e\u0432\u044b\u0445,<\/p>\n<\/li>\n<li>\n<p>\u0420\u0435\u043b\u0435\u0432\u0430\u043d\u0442\u043d\u043e\u0441\u0442\u044c \u0440\u0430\u0437\u043c\u0435\u0447\u0435\u043d\u0430 \u0432\u0440\u0443\u0447\u043d\u0443\u044e.<\/p>\n<\/li>\n<\/ul>\n<p>\u041f\u043e\u0434\u0445\u043e\u0434\u0438\u0442 \u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0430 \u043f\u043e\u0438\u0441\u043a\u0430 \u0438 \u0434\u043e\u043e\u0431\u0443\u0447\u0435\u043d\u0438\u044f \u043c\u043e\u0434\u0435\u043b\u0435\u0439.<\/p>\n<details class=\"spoiler\">\n<summary>\u041f\u0440\u0438\u043c\u0435\u0440 \u0434\u0430\u043d\u043d\u044b\u0445<\/summary>\n<div class=\"spoiler__content\">\n<p>\u041a\u0430\u0436\u0434\u0430\u044f \u0441\u0442\u0440\u043e\u043a\u0430 \u0432 \u0434\u0430\u0442\u0430\u0441\u0435\u0442\u0435 \u2014 \u044d\u0442\u043e \u0442\u0440\u043e\u0439\u043a\u0430: <strong>\u0437\u0430\u043f\u0440\u043e\u0441 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f<\/strong>, <strong>\u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0442\u043e\u0432\u0430\u0440\u0430<\/strong>, \u0438 <strong>\u043e\u0446\u0435\u043d\u043a\u0430 \u0440\u0435\u043b\u0435\u0432\u0430\u043d\u0442\u043d\u043e\u0441\u0442\u0438<\/strong>.<\/p>\n<pre><code class=\"json\">{   \"query\": \"usb c charger for iphone\",   \"product_title\": \"USB C Charger, 20W PD Wall Charger Block Compatible with iPhone 13 12 11\",   \"product_description\": \"...\",   \"product_id\": \"B08K2S1NP5\",   \"query_id\": \"A1\",   \"product_locale\": \"us\",   \"esci_label\": \"exact\" } <\/code><\/pre>\n<p>\u0412\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f <code>esci_label<\/code>:<\/p>\n<ul>\n<li>\n<p><code>exact<\/code> \u2014 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441\u0443,<\/p>\n<\/li>\n<li>\n<p><code>substitute<\/code> \u2014 \u0431\u043b\u0438\u0437\u043a\u0438\u0439 \u0430\u043d\u0430\u043b\u043e\u0433, \u043d\u043e \u043d\u0435 \u0442\u043e\u0447\u043d\u043e\u0435 \u0441\u043e\u0432\u043f\u0430\u0434\u0435\u043d\u0438\u0435,<\/p>\n<\/li>\n<li>\n<p><code>complement<\/code> \u2014 \u0441\u043e\u043f\u0443\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 \u0442\u043e\u0432\u0430\u0440 (\u0442\u043e\u043b\u044c\u043a\u043e \u0432 \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u0439 \u0432\u044b\u0431\u043e\u0440\u043a\u0435),<\/p>\n<\/li>\n<li>\n<p><code>irrelevant<\/code> \u2014 \u043d\u0435 \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u0442.<\/p>\n<\/li>\n<\/ul>\n<p>\u0412 \u0442\u0440\u0435\u043d\u0438\u0440\u043e\u0432\u043e\u0447\u043d\u043e\u0439 \u0432\u044b\u0431\u043e\u0440\u043a\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e: <code>exact<\/code>, <code>substitute<\/code>, <code>irrelevant<\/code>.<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>\u0418\u0441\u0442\u043e\u0440\u0438\u044f \u0432\u043e\u0437\u043d\u0438\u043a\u043d\u043e\u0432\u0435\u043d\u0438\u044f \u0434\u0430\u0442\u0430\u0441\u0435\u0442\u0430<\/summary>\n<div class=\"spoiler__content\">\n<ul>\n<li>\n<p>\u041e\u043d \u0431\u044b\u043b \u0441\u043e\u0437\u0434\u0430\u043d \u0434\u043b\u044f <strong>KDD Cup 2022 \/ Amazon Shopping Queries Challenge<\/strong>, \u0446\u0435\u043b\u044c \u2014 \u0443\u043b\u0443\u0447\u0448\u0438\u0442\u044c \u043f\u043e\u0438\u0441\u043a \u0442\u043e\u0432\u0430\u0440\u043e\u0432 \u0432 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u0439 e\u2011commerce \u0441\u0440\u0435\u0434\u0435.<\/p>\n<\/li>\n<li>\n<p>\u041e\u0445\u0432\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043d\u0430 \u0442\u0440\u0451\u0445 \u044f\u0437\u044b\u043a\u0430\u0445 \u2014 <strong>\u0430\u043d\u0433\u043b\u0438\u0439\u0441\u043a\u0438\u0439, \u044f\u043f\u043e\u043d\u0441\u043a\u0438\u0439 \u0438 \u0438\u0441\u043f\u0430\u043d\u0441\u043a\u0438\u0439<\/strong>.<\/p>\n<\/li>\n<li>\n<p>\u041a\u0430\u0436\u0434\u044b\u0439 \u0437\u0430\u043f\u0440\u043e\u0441 \u0438\u043c\u0435\u0435\u0442 \u0434\u043e 40 \u0442\u043e\u0432\u0430\u0440\u043e\u0432 \u0441 \u0440\u0443\u0447\u043d\u043e\u0439 \u0440\u0430\u0437\u043c\u0435\u0442\u043a\u043e\u0439: <em>Exact<\/em>, <em>Substitute<\/em>, <em>Complement<\/em>, <em>Irrelevant<\/em>.<\/p>\n<\/li>\n<li>\n<p>\u0412\u0441\u0435\u0433\u043e ~130\u202f000 \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0438 \u2248\u202f2.6\u202f\u043c\u043b\u043d \u043f\u043e\u043c\u0435\u0447\u0435\u043d\u043d\u044b\u0445 \u043f\u0430\u0440 (query, product) \u0434\u043b\u044f \u043f\u043e\u043b\u043d\u043e\u0433\u043e \u0434\u0430\u0442\u0430\u0441\u0435\u0442\u0430, \u0432 \u0443\u043c\u0435\u043d\u044c\u0448\u0435\u043d\u043d\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u2014 ~48\u202f000 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0438 ~1.1\u202f\u043c\u043b\u043d \u043f\u0430\u0440. \u041f\u0440\u0438\u043c\u0435\u0440 \u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u0438 \u2014 \u044d\u0442\u043e \u043e\u0442\u0440\u0430\u0436\u0435\u043d\u043e \u0432 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0438 <a href=\"https:\/\/github.com\/amazon-science\/esci-data\" rel=\"noopener noreferrer nofollow\">\u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f Amazon ESCI \u043d\u0430 GitHub<\/a>.<\/p>\n<\/li>\n<\/ul>\n<blockquote>\n<p>\ud83d\udd0d \u0420\u0435\u043b\u0435\u0432\u0430\u043d\u0442\u043d\u043e\u0441\u0442\u044c \u0440\u0430\u0437\u043c\u0435\u0447\u0435\u043d\u0430 \u043d\u0435 \u043f\u043e \u043d\u0430\u043b\u0438\u0447\u0438\u044e \u043a\u043b\u044e\u0447\u0435\u0432\u044b\u0445 \u0441\u043b\u043e\u0432, \u0430 \u043f\u043e \u0444\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u043c\u0443 \u0441\u043c\u044b\u0441\u043b\u0443 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0438 \u0442\u043e\u0432\u0430\u0440\u0430, \u0447\u0442\u043e \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u0440\u0435\u0430\u043b\u0438\u0441\u0442\u0438\u0447\u043d\u044b\u0439 \u00ab\u0448\u0443\u043c\u00bb: \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0447\u0430\u0441\u0442\u043e \u043d\u0435\u043f\u043e\u043b\u043d\u044b\u0435, \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u043c\u0430\u0440\u043a\u0435\u0442\u0438\u043d\u0433\u043e\u0432\u044b\u043c\u0438, \u0435\u0441\u0442\u044c \u0441\u0438\u043d\u043e\u043d\u0438\u043c\u044b, \u043e\u0431\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0438 \u043f\u0440.<\/p>\n<\/blockquote>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>\u041f\u0440\u043e\u0441\u0442\u0435\u043d\u044c\u043a\u0438\u0439 EDA (\u0440\u0430\u0437\u0432\u0435\u0434\u043e\u0447\u043d\u044b\u0439 \u0430\u043d\u0430\u043b\u0438\u0437)<\/summary>\n<div class=\"spoiler__content\">\n<p>\u041a\u0430\u0447\u0430\u0435\u043c \u0434\u0430\u0442\u0430\u0441\u0435\u0442<\/p>\n<pre><code class=\"python\">from datasets import load_dataset # https:\/\/huggingface.co\/datasets\/tasksource\/esci # \u0417\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c \u0442\u0440\u0435\u043d\u0438\u0440\u043e\u0432\u043e\u0447\u043d\u0443\u044e \u0447\u0430\u0441\u0442\u044c dataset = load_dataset(\"tasksource\/esci\", split=\"train\") <\/code><\/pre>\n<p>\u0421\u043c\u043e\u0442\u0440\u0438\u043c \u043d\u0430 \u0438\u043c\u0435\u044e\u0449\u0438\u0435\u0441\u044f \u043f\u043e\u043b\u044f<\/p>\n<pre><code class=\"python\">import pandas as pd df = dataset.to_pandas() # \u0421\u043c\u043e\u0442\u0440\u0438\u043c \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043f\u043e\u043b\u044f print(df.columns) # \u041f\u0440\u0438\u043c\u0435\u0440 \u0441\u0442\u0440\u043e\u043a\u0438 print(df[['query', 'product_title', 'esci_label']].sample(5)) # \u0420\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u043f\u043e \u043c\u0435\u0442\u043a\u0430\u043c print(\"\u041c\u0435\u0442\u043a\u0438 \u0440\u0435\u043b\u0435\u0432\u0430\u043d\u0442\u043d\u043e\u0441\u0442\u0438:\") print(df['esci_label'].value_counts()) # \u0420\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u043f\u043e \u044f\u0437\u044b\u043a\u0443 print(\"\u041b\u043e\u043a\u0430\u043b\u0438:\")  print(df['product_locale'].value_counts()) <\/code><\/pre>\n<p>\u0420\u0438\u0441\u0443\u0435\u043c \u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u0434\u043b\u0438\u043d\u043d \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432\/\u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0439 \u0442\u043e\u0432\u0430\u0440\u043e\u0432\/\u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0439<\/p>\n<pre><code class=\"python\"># \u0420\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u0434\u043b\u0438\u043d df['query_len'] = df['query'].str.split().str.len() df['title_len'] = df['product_title'].str.split().str.len() df['desc_len'] = df['product_description'].str.split().str.len() df[['query_len', 'title_len', 'desc_len']].hist(bins=30, figsize=(12, 4)) <\/code><\/pre>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/gn\/7y\/eq\/gn7yeqsnaat1ullip9hqfsxexwe.png\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/webt\/gn\/7y\/eq\/gn7yeqsnaat1ullip9hqfsxexwe.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/webt\/gn\/7y\/eq\/gn7yeqsnaat1ullip9hqfsxexwe.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/figure>\n<p>\u0421\u0440\u0435\u0434\u043d\u0435\u0435 \u0447\u0438\u0441\u043b\u043e \u0440\u0435\u043b\u0435\u0432\u0430\u043d\u0442\u043d\u044b\u0445 \u0442\u043e\u0432\u0430\u0440\u043e\u0432 \u043d\u0430 \u0437\u0430\u043f\u0440\u043e\u0441<\/p>\n<pre><code class=\"python\">import matplotlib.pyplot as plt  # \u041e\u0441\u0442\u0430\u0432\u0438\u043c \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u0437\u0438\u0442\u0438\u0432\u043d\u044b\u0435 \u043f\u0440\u0438\u043c\u0435\u0440\u044b positive_df = df[df['esci_label'].isin(['Exact', 'Substitute'])]  # \u0421\u0447\u0438\u0442\u0430\u0435\u043c \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0440\u0435\u043b\u0435\u0432\u0430\u043d\u0442\u043d\u044b\u0445 \u0442\u043e\u0432\u0430\u0440\u043e\u0432 \u043d\u0430 \u043a\u0430\u0436\u0434\u044b\u0439 \u0437\u0430\u043f\u0440\u043e\u0441 relevant_counts = positive_df.groupby('query')['product_id'].nunique()  # \u0421\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u0430 print(\"\ud83d\udcca \u0421\u0440\u0435\u0434\u043d\u0435\u0435 \u0447\u0438\u0441\u043b\u043e \u0440\u0435\u043b\u0435\u0432\u0430\u043d\u0442\u043d\u044b\u0445 \u0442\u043e\u0432\u0430\u0440\u043e\u0432 \u043d\u0430 \u0437\u0430\u043f\u0440\u043e\u0441:\", relevant_counts.mean()) print(\"\ud83d\udd22 \u0420\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 (\u0432\u043a\u043b\u044e\u0447\u0430\u044f \u0442\u043e\u043f-10):\") print(relevant_counts.value_counts().head(10))  # \u0413\u0438\u0441\u0442\u043e\u0433\u0440\u0430\u043c\u043c\u0430 plt.figure(figsize=(10, 4)) relevant_counts.hist(bins=60) plt.title(\"\u0420\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u0440\u0435\u043b\u0435\u0432\u0430\u043d\u0442\u043d\u044b\u0445 \u0442\u043e\u0432\u0430\u0440\u043e\u0432 \u043d\u0430 \u0437\u0430\u043f\u0440\u043e\u0441\") plt.xlabel(\"\u041a\u043e\u043b-\u0432\u043e \u0440\u0435\u043b\u0435\u0432\u0430\u043d\u0442\u043d\u044b\u0445 \u0442\u043e\u0432\u0430\u0440\u043e\u0432\") plt.ylabel(\"\u0427\u0430\u0441\u0442\u043e\u0442\u0430\") plt.grid(True) plt.show() <\/code><\/pre>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/ov\/zt\/qd\/ovztqdfda5fmlnojyi4z7xl6i9w.png\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/webt\/ov\/zt\/qd\/ovztqdfda5fmlnojyi4z7xl6i9w.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/webt\/ov\/zt\/qd\/ovztqdfda5fmlnojyi4z7xl6i9w.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/figure>\n<p>\u0434\u0430\u043b\u0435\u0435 <a href=\"https:\/\/github.com\/naumtsevalex\/All-about-ML\/blob\/main\/02_query2product_e5_mvp_service\/EDA_plus_baseline.ipynb\" rel=\"noopener noreferrer nofollow\">\u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u0432 \u0442\u0435\u0442\u0440\u0430\u0434\u043a\u0435<\/a>&#8230;<\/p>\n<\/div>\n<\/details>\n<h3>\u041a\u0430\u043a \u043e\u0446\u0435\u043d\u0438\u0432\u0430\u0435\u043c \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u043e?<\/h3>\n<p>\u0414\u0430\u0442\u0430\u0441\u0435\u0442 \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437 \u0441\u0442\u0440\u043e\u0447\u0435\u043a <code>(query, pos, neg)<\/code> \u0438 \u0432 \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0438\u043c \u0440\u0430\u0437\u043e\u0431\u044c\u0435\u0442\u0441\u044f \u043f\u043e \u0431\u0430\u0442\u0447\u0430\u043c. \u0414\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u043f\u043e\u0437\u0438\u0442\u0438\u0432\u0430 \u0431\u0435\u0440\u0435\u043c \u0432\u0441\u0435 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 <code>pos<\/code> \u0438 <code>neg<\/code> \u0438\u0437 \u0431\u0430\u0442\u0447\u0430 \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043d\u0435\u0433\u0430\u0442\u0438\u0432\u043d\u044b\u0445 \u043f\u0440\u0438\u043c\u0435\u0440\u043e\u0432.<\/p>\n<p>\u0421\u0447\u0438\u0442\u0430\u0435\u043c <strong>Recall@K<\/strong> \u2014 \u0438\u0449\u0435\u043c, \u043f\u043e\u043f\u0430\u043b \u043b\u0438 <code>pos<\/code> \u0432 \u0442\u043e\u043f-K \u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u0430\u043d\u0438\u044f \u043c\u043e\u0434\u0435\u043b\u0438 (\u0435\u0441\u043b\u0438 \u0434\u0430 \u043c\u0435\u0442\u0440\u0438\u043a\u0430 \u0440\u0430\u0432\u043d\u0430 <code>1<\/code>, \u0438\u043d\u0430\u0447\u0435 <code>0<\/code>) \u0438 \u0443\u0441\u0440\u0435\u0434\u043d\u044f\u0435\u043c \u043f\u043e \u0431\u0430\u0442\u0447\u0443.<\/p>\n<h3>BM25 \u043a\u0430\u043a \u0431\u0435\u0439\u0437\u043b\u0430\u0439\u043d<\/h3>\n<p><a href=\"https:\/\/en.wikipedia.org\/wiki\/Okapi_BM25\" rel=\"noopener noreferrer nofollow\">BM25<\/a> \u2014 \u0440\u0430\u0437\u0432\u0438\u0442\u0438\u0435 \u0438\u0434\u0435\u0438 <a href=\"https:\/\/en.wikipedia.org\/wiki\/Tf%E2%80%93idf\" rel=\"noopener noreferrer nofollow\">TF-IDF<\/a>: \u0443\u0447\u0438\u0442\u044b\u0432\u0430\u0435\u0442, \u043d\u0430\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0441\u043b\u043e\u0432\u043e \u0432\u0430\u0436\u043d\u043e \u0432 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0435, \u043d\u043e \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043d\u043e\u0440\u043c\u0430\u043b\u0438\u0437\u0443\u0435\u0442 \u043f\u043e \u0434\u043b\u0438\u043d\u0435 \u0438 \u043b\u043e\u0433\u0430\u0440\u0438\u0444\u043c\u0438\u0447\u0435\u0441\u043a\u0438 \u0441\u0433\u043b\u0430\u0436\u0438\u0432\u0430\u0435\u0442 \u0432\u0435\u0441\u0430.<\/p>\n<p>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c <a href=\"https:\/\/pypi.org\/project\/rank-bm25\/\" rel=\"noopener noreferrer nofollow\"><code>rank_bm25<\/code><\/a> \u2014 \u0438\u043d\u0434\u0435\u043a\u0441\u0438\u0440\u0443\u0435\u043c <code>product_title<\/code>, \u0438\u0449\u0435\u043c \u043f\u043e <code>query<\/code>, \u0440\u0430\u043d\u0436\u0438\u0440\u0443\u0435\u043c \u043f\u043e \u0441\u043a\u043e\u0440\u0443.<\/p>\n<details class=\"spoiler\">\n<summary>\u0421\u0447\u0438\u0442\u0430\u0435\u043c \u0431\u0435\u0439\u0437\u043b\u0430\u0439\u043d \u043c\u0435\u0442\u0440\u0438\u043a\u0443 (\u043f\u043e\u043a\u0430 \u043f\u043e \u0432\u0441\u0435\u043c \u0442\u043e\u0432\u0430\u0440\u0430\u043c, \u043f\u043e\u0442\u043e\u043c \u0431\u0443\u0434\u0435\u043c \u043f\u043e \u0431\u0430\u0442\u0447\u0430\u043c)<\/summary>\n<div class=\"spoiler__content\">\n<p>\u0422\u043e\u043a\u0435\u043d\u0438\u0437\u0438\u0440\u0443\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u0435<\/p>\n<pre><code class=\"python\">import nltk from nltk.tokenize import word_tokenize import os  NLTK_DATA_PATH = os.path.expanduser('~\/nltk_data') os.makedirs(NLTK_DATA_PATH, exist_ok=True) nltk.download('punkt_tab', download_dir=NLTK_DATA_PATH)  nltk.data.path.append(NLTK_DATA_PATH) # \u041f\u0440\u043e\u0441\u0442\u043e\u0439 \u0442\u0435\u0441\u0442 \u2014 \u0435\u0441\u043b\u0438 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442, \u0432\u0441\u0451 \u043e\u043a print(word_tokenize(\"This is a test.\")) # ['This', 'is', 'a', 'test', '.'] <\/code><\/pre>\n<p>\u0421\u0447\u0438\u0442\u0430\u0435\u043c \u043c\u0435\u0442\u0440\u0438\u043a\u0443 \u0434\u043b\u044f BM25<\/p>\n<pre><code class=\"python\">import pandas as pd import numpy as np from nltk.tokenize import word_tokenize from rank_bm25 import BM25Okapi from tqdm import tqdm import time  # \u2014\u2014\u2014 0. \u0423\u0434\u043e\u0431\u043d\u0430\u044f \u0442\u043e\u043a\u0435\u043d\u0438\u0437\u0430\u0446\u0438\u044f \u0442\u0435\u043a\u0441\u0442\u0430 \u2014\u2014\u2014 def tokenize(text: str) -&gt; list[str]:     return word_tokenize(text.lower())  # \u2014\u2014\u2014 1. \u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430 \u043a\u043e\u0440\u043f\u0443\u0441\u0430 \u0442\u043e\u0432\u0430\u0440\u043e\u0432 \u2014\u2014\u2014 print(\"\ud83d\udce6 \u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430 \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0438 \u0442\u043e\u0432\u0430\u0440\u043e\u0432...\") start = time.perf_counter() products = df['product_title'].unique().tolist() tokenized_products = [tokenize(p) for p in tqdm(products, desc=\"\ud83e\uddfc \u0422\u043e\u043a\u0435\u043d\u0438\u0437\u0430\u0446\u0438\u044f \u0442\u043e\u0432\u0430\u0440\u043e\u0432\")] bm25 = BM25Okapi(tokenized_products) print(f\"\u2705 \u0418\u043d\u0434\u0435\u043a\u0441\u0430\u0446\u0438\u044f BM25 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0430 \u0437\u0430 {time.perf_counter() - start:.2f} \u0441\u0435\u043a\")  # \u2014\u2014\u2014 2. \u0423\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u044b\u0439 BM25 \u043f\u043e\u0438\u0441\u043a\u043e\u0432\u0438\u043a \u2014\u2014\u2014 class BM25Search:     def __init__(self, bm25_index, docs):         self.bm25 = bm25_index         self.docs = docs      def top_k(self, query: str, k: int = 10) -&gt; list[str]:         tokens = tokenize(query)         scores = self.bm25.get_scores(tokens)         top_idx = np.argsort(scores)[-k:][::-1]         return [self.docs[i] for i in top_idx]  # \u2014\u2014\u2014 3. \u0423\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u0430\u044f \u043c\u0435\u0442\u0440\u0438\u043a\u0430 Recall@k \u2014\u2014\u2014 def evaluate_recall_at_k(queries, true_items, searcher, k=10):     hits = 0     for q, true_item in tqdm(zip(queries, true_items), total=len(queries), desc=\"\ud83d\udd0d \u0418\u043d\u0444\u0435\u0440\u0435\u043d\u0441 + \u043c\u0435\u0442\u0440\u0438\u043a\u0430\"):         predicted = searcher.top_k(q, k)         if true_item in predicted:             hits += 1     return hits \/ len(queries)  # \u2014\u2014\u2014 4. \u041f\u0440\u0438\u043c\u0435\u0440 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u2014\u2014\u2014 print(\"\ud83d\udcca \u0424\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0439 \u0441\u0435\u0442...\") eval_df = df[df['esci_label'].isin(['Exact', 'Substitute'])].sample(200, random_state=42) queries = eval_df['query'].tolist() true_products = eval_df['product_title'].tolist()  print(\"\ud83d\ude80 \u0417\u0430\u043f\u0443\u0441\u043a \u043f\u043e\u0438\u0441\u043a\u0430 \u0438 \u043e\u0446\u0435\u043d\u043a\u0430 Recall@10...\") start = time.perf_counter() bm25_searcher = BM25Search(bm25, products) recall = evaluate_recall_at_k(queries, true_products, bm25_searcher, k=10) print(f\"\u2705 \u041c\u0435\u0442\u0440\u0438\u043a\u0430 \u0440\u0430\u0441\u0441\u0447\u0438\u0442\u0430\u043d\u0430 \u0437\u0430 {time.perf_counter() - start:.2f} \u0441\u0435\u043a\")  print(f\"\\n\ud83d\udcc8 Recall@10 (BM25 baseline): {recall:.4f}\")  # \ud83d\udce6 \u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430 \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0438 \u0442\u043e\u0432\u0430\u0440\u043e\u0432... # \ud83e\uddfc \u0422\u043e\u043a\u0435\u043d\u0438\u0437\u0430\u0446\u0438\u044f \u0442\u043e\u0432\u0430\u0440\u043e\u0432: 100%|\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588| 1423918\/1423918 [01:50&lt;00:00, 12909.02it\/s] # \u2705 \u0418\u043d\u0434\u0435\u043a\u0441\u0430\u0446\u0438\u044f BM25 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0430 \u0437\u0430 120.43 \u0441\u0435\u043a # \ud83d\udcca \u0424\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0439 \u0441\u0435\u0442... # \ud83d\ude80 \u0417\u0430\u043f\u0443\u0441\u043a \u043f\u043e\u0438\u0441\u043a\u0430 \u0438 \u043e\u0446\u0435\u043d\u043a\u0430 Recall@10... # \ud83d\udd0d \u0418\u043d\u0444\u0435\u0440\u0435\u043d\u0441 + \u043c\u0435\u0442\u0440\u0438\u043a\u0430: 100%|\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588| 200\/200 [03:37&lt;00:00,  1.09s\/it] # \u2705 \u041c\u0435\u0442\u0440\u0438\u043a\u0430 \u0440\u0430\u0441\u0441\u0447\u0438\u0442\u0430\u043d\u0430 \u0437\u0430 217.02 \u0441\u0435\u043a  # \ud83d\udcc8 Recall@10 (BM25 baseline): 0.1750 <\/code><\/pre>\n<\/div>\n<\/details>\n<p>\u0410\u043b\u0433\u043e\u0440\u0438\u0442\u043c <em>\u043d\u0435 \u0443\u0447\u0438\u0442\u044b\u0432\u0430\u0435\u0442 \u0441\u043c\u044b\u0441\u043b<\/em> \u0438 \u0442\u0435\u043c \u0431\u043e\u043b\u0435\u0435  <em>\u043d\u0435 \u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043d\u0430 \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u043e\u0441\u0442\u044c \u043e\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439<\/em>. \u041e\u043d \u043b\u0438\u0448\u044c \u0438\u0449\u0435\u0442 \u043f\u0435\u0440\u0435\u0441\u0435\u0447\u0435\u043d\u0438\u044f \u0447\u0430\u0441\u0442\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0438 \u0442\u043e\u0432\u0430\u0440\u0430 \u0438 \u0445\u0438\u0442\u0440\u043e \u0441\u0447\u0438\u0442\u0430\u0435\u0442 \u0441\u043a\u043e\u0440. <strong>\u041d\u0430 \u043a\u0430\u043a \u0431\u0435\u0439\u0437\u043b\u0430\u0439\u043d \u043e\u0447\u0435\u043d\u044c \u043b\u0435\u0433\u043a\u043e \u0437\u0430\u0432\u043e\u0434\u0438\u0442\u0441\u044f \u0438 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u0447\u0442\u043e-\u0442\u043e \u0430\u0434\u0435\u043a\u0432\u0430\u0442\u043d\u043e\u0435!<\/strong><\/p>\n<h3>\u041a\u0430\u043a\u0443\u044e \u043c\u043e\u0434\u0435\u043b\u044c \u0432\u0437\u044f\u0442\u044c? \u041a\u0430\u043a\u043e\u0439 pretrain? E5 !<\/h3>\n<p>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c <a href=\"https:\/\/huggingface.co\/intfloat\/multilingual-e5-small\" rel=\"noopener noreferrer nofollow\"><strong>E5 (intfloat\/multilingual-e5-small)<\/strong><\/a> \u2014 bi-encoder \u043d\u0430 \u0431\u0430\u0437\u0435 BERT \u0441 \u0441\u0438\u0430\u043c\u0441\u043a\u043e\u0439 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u043e\u0439: \u043e\u0434\u0438\u043d \u044d\u043d\u043a\u043e\u0434\u0435\u0440 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441 \u0438 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e, \u0441 \u043f\u0440\u0435\u0444\u0438\u043a\u0441\u0430\u043c\u0438 <code>query:<\/code> \u0438 <code>passage:<\/code>.<\/p>\n<p>\u041c\u043e\u0434\u0435\u043b\u044c \u043e\u0431\u0443\u0447\u0435\u043d\u0430 \u043d\u0430 <strong>1,2 \u043c\u043b\u0440\u0434 \u043f\u0430\u0440 &#171;\u0437\u0430\u043f\u0440\u043e\u0441\u2013\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442&#187;<\/strong> \u043d\u0430 100+ \u044f\u0437\u044b\u043a\u0430\u0445. \u0412 \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0438\u0441\u044c Common Crawl, Wikipedia, MS MARCO, BEIR \u0438 \u0434\u0440\u0443\u0433\u0438\u0435 \u0434\u0430\u0442\u0430\u0441\u0435\u0442\u044b. <a href=\"https:\/\/arxiv.org\/pdf\/2402.05672\" rel=\"noopener noreferrer nofollow\">E5 Technical Report (2024, Microsoft)<\/a><\/p>\n<p>\u0420\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0438\u0437 \u043a\u043e\u0440\u043e\u0431\u043a\u0438, \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e \u0434\u043e\u043e\u0431\u0443\u0447\u0430\u0435\u0442\u0441\u044f \u0438 \u0434\u0430\u0451\u0442 \u0441\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u044b\u0435 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u0434\u043b\u044f \u043f\u043e\u0438\u0441\u043a\u0430.<\/p>\n<details class=\"spoiler\">\n<summary>\u0421\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u0435 \u0441 \u0430\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u0430\u043c\u0438 (SBERT, T5, GTR, Contriever)<\/summary>\n<div class=\"spoiler__content\">\n<h4>\ud83d\udd39 SBERT (2019, UKPLab)<\/h4>\n<p>Siamese-\u0441\u0435\u0442\u044c \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 BERT. \u041e\u0431\u0443\u0447\u0430\u043b\u0430\u0441\u044c \u043d\u0430 \u0437\u0430\u0434\u0430\u0447\u0430\u0445 \u043f\u0430\u0440\u0430\u0444\u0440\u0430\u0437\u043e\u0432 \u0438 NLI: \u043c\u043e\u0434\u0435\u043b\u044c \u0443\u0447\u0438\u0442\u0441\u044f \u0440\u0430\u0441\u043f\u043e\u0437\u043d\u0430\u0432\u0430\u0442\u044c, \u043d\u0430\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0434\u0432\u0430 \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0441\u0445\u043e\u0436\u0438 \u043f\u043e \u0441\u043c\u044b\u0441\u043b\u0443. \u041f\u0440\u043e\u0441\u0442\u0430 \u0432 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438, \u043d\u043e \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0432\u044b\u0431\u043e\u0440\u0430 \u043f\u043e\u0434\u0445\u043e\u0434\u044f\u0449\u0435\u0439 \u043f\u0440\u0435\u0434\u043e\u0431\u0443\u0447\u0435\u043d\u043d\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u043f\u043e\u0434 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u0443\u044e \u0437\u0430\u0434\u0430\u0447\u0443.<br \/> \ud83d\udcce <a href=\"https:\/\/www.sbert.net\/docs\/pretrained_models.html\" rel=\"noopener noreferrer nofollow\">sbert.net<\/a> | <a href=\"https:\/\/arxiv.org\/abs\/1908.10084\" rel=\"noopener noreferrer nofollow\">Paper<\/a><\/p>\n<h4>\ud83d\udd39 GTR (2021, Google)<\/h4>\n<p>Dual-encoder \u043d\u0430 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0435 T5. \u041e\u0431\u0443\u0447\u0435\u043d \u043d\u0430 query\u2013document \u043f\u0430\u0440\u0430\u0445, \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u043e\u0442\u043b\u0438\u0447\u043d\u044b\u0435 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u043d\u0430 BEIR-\u0431\u0435\u043d\u0447\u043c\u0430\u0440\u043a\u0430\u0445. \u0422\u044f\u0436\u0451\u043b\u044b\u0439 \u043f\u043e \u0440\u0435\u0441\u0443\u0440\u0441\u0430\u043c \u0438 \u0432 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u043c \u0430\u043d\u0433\u043b\u043e\u044f\u0437\u044b\u0447\u043d\u044b\u0439, \u043d\u043e \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u0435\u0432\u043e\u0441\u0445\u043e\u0434\u0438\u0442\u044c \u0434\u0440\u0443\u0433\u0438\u0435 \u043c\u043e\u0434\u0435\u043b\u0438 \u043f\u043e \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0443.<br \/> \ud83d\udcce <a href=\"https:\/\/arxiv.org\/abs\/2112.07899\" rel=\"noopener noreferrer nofollow\">Paper<\/a><\/p>\n<h3>\ud83d\udccc \u0427\u0442\u043e \u0442\u0430\u043a\u043e\u0435 T5? (\u041f\u0435\u0440\u0432\u0430\u044f \u0432\u0435\u0440\u0441\u0438\u044f \u0441\u0442\u0430\u0442\u044c\u0438 2019)<\/h3>\n<p>T5 (Text-To-Text Transfer Transformer) \u2014 seq2seq \u043c\u043e\u0434\u0435\u043b\u044c \u043e\u0442 Google, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0444\u043e\u0440\u043c\u0443\u043b\u0438\u0440\u0443\u0435\u0442 \u0432\u0441\u0435 NLP-\u0437\u0430\u0434\u0430\u0447\u0438 \u043a\u0430\u043a \u00ab\u0442\u0435\u043a\u0441\u0442 \u2192 \u0442\u0435\u043a\u0441\u0442\u00bb.<br \/> \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440:<br \/> <code>\"translate English to German: house\" \u2192 \"Haus\"<\/code><br \/> \u0412 GTR \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e <strong>\u044d\u043d\u043a\u043e\u0434\u0435\u0440<\/strong> \u043e\u0442 T5 \u2014 \u043e\u043d \u043a\u043e\u0434\u0438\u0440\u0443\u0435\u0442 query \u0438 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442 \u043f\u043e \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u0432 \u044d\u043c\u0431\u0435\u0434\u0434\u0438\u043d\u0433\u0438, \u043a\u0430\u043a \u0432 bi-encoder \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0435.<br \/> \ud83d\udcce <a href=\"https:\/\/arxiv.org\/abs\/1910.10683\" rel=\"noopener noreferrer nofollow\">T5 paper<\/a><\/p>\n<hr\/>\n<h4>\ud83d\udd39 Contriever (2021, Meta AI)<\/h4>\n<p>Dense retriever \u043d\u0430 BERT, \u043e\u0431\u0443\u0447\u0435\u043d \u0431\u0435\u0437 \u0440\u0430\u0437\u043c\u0435\u0442\u043a\u0438 (self-supervised) \u2014 \u043f\u0440\u043e\u0441\u0442\u043e \u043d\u0430 \u0441\u043e\u0441\u0435\u0434\u043d\u0438\u0445 \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445 \u0438\u0437 \u0412\u0438\u043a\u0438\u043f\u0435\u0434\u0438\u0438. \u0420\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0431\u044b\u0441\u0442\u0440\u043e, \u043d\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0430\u043d\u043d\u043e\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445, \u043d\u043e \u0445\u0443\u0436\u0435 \u0441\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0441 \u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u0435\u043c \u0437\u0430\u043f\u0440\u043e\u0441\u0430. \u041f\u043e\u0434\u0445\u043e\u0434\u0438\u0442 \u0434\u043b\u044f \u0430\u043d\u0433\u043b\u043e\u044f\u0437\u044b\u0447\u043d\u044b\u0445 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0435\u0432.<br \/> \ud83d\udcce <a href=\"https:\/\/github.com\/facebookresearch\/contriever\" rel=\"noopener noreferrer nofollow\">GitHub<\/a> | <a href=\"https:\/\/arxiv.org\/abs\/2112.09118\" rel=\"noopener noreferrer nofollow\">Paper<\/a><\/p>\n<\/div>\n<\/details>\n<h3>\u0418\u043d\u0444\u0435\u0440\u0438\u043c pretrain E5<\/h3>\n<p>\u0414\u043b\u044f \u043f\u043e\u0434\u0441\u0447\u0435\u0442\u0430 \u0441\u043a\u043e\u0440\u043e\u0432 \u0440\u0435\u043b\u0435\u0432\u0430\u043d\u0442\u043d\u043e\u0441\u0442\u0438 \u043f\u043e\u0434 \u0437\u0430\u043f\u0440\u043e\u0441, \u043d\u0443\u0436\u0435\u043d \u0432 \u043e\u0444\u0444\u043b\u0430\u0439\u043d\u0435 \u043f\u0435\u0440\u0435\u043e\u0431\u043e\u0439\u0442\u0438 \u0432\u0441\u0435 \u043f\u0440\u043e\u0434\u0443\u043a\u0442\u044b.<\/p>\n<blockquote>\n<p>\u0414\u0435\u043b\u0430\u0435\u043c \u0431\u0435\u0437 \u0432\u0435\u043a\u0442\u043e\u0440\u043d\u043e\u0433\u043e \u0438\u043d\u0434\u0435\u043a\u0441\u0430. \u0411\u0443\u0434\u0435\u043c \u043f\u043e\u0434 \u0437\u0430\u043f\u0440\u043e\u0441 \u0441\u0447\u0438\u0442\u0430\u0442\u044c \u0441\u043a\u043e\u0440 \u0441\u043e \u0432\u0441\u0435\u0439 \u0431\u0430\u0437\u043e\u0439.<\/p>\n<\/blockquote>\n<details class=\"spoiler\">\n<summary>\u0421\u0447\u0438\u0442\u0430\u0435\u043c \u0432\u0435\u043a\u0442\u043e\u0440\u0430(\u0438 \u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u0443) \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0442\u043e\u0432\u0430\u0440\u0430 \u0438\u0437 \u0431\u0430\u0437\u044b<\/summary>\n<div class=\"spoiler__content\">\n<p><a href=\"https:\/\/github.com\/naumtsevalex\/All-about-ML\/blob\/main\/02_query2product_e5_mvp_service\/calc_all_embed.ipynb\" rel=\"noopener noreferrer nofollow\">\u0426\u0435\u043b\u044c\u043d\u044b\u0439 \u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u044b\u0439 \u043a\u043e\u0434<\/a><\/p>\n<p>\u041a\u0430\u0447\u0430\u0435\u043c \u043c\u043e\u0434\u0435\u043b\u044c \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c \u0432 \u0441\u0432\u043e\u044e \u043e\u0431\u0435\u0440\u0442\u043a\u0443.<\/p>\n<pre><code class=\"python\">import torch import numpy as np from transformers import AutoTokenizer, AutoModel  # https:\/\/huggingface.co\/intfloat\/multilingual-e5-small # --- \u041a\u043b\u0430\u0441\u0441 \u0434\u043b\u044f \u0438\u043d\u0444\u0435\u0440\u0435\u043d\u0441\u0430 \u0431\u0430\u0442\u0447\u0435\u0439 --- class E5InferenceModel:     def __init__(self, model_name='intfloat\/e5-small', device=None):         self.device = device or ('cuda' if torch.cuda.is_available() else 'cpu')         self.tokenizer = AutoTokenizer.from_pretrained(model_name)         self.model = AutoModel.from_pretrained(model_name).to(self.device)         self.model.eval()      def encode_batch(self, input_ids, attention_mask):         with torch.no_grad():             outputs = self.model(input_ids=input_ids.to(self.device), attention_mask=attention_mask.to(self.device))             return outputs.last_hidden_state[:, 0].cpu().numpy()  model_name = 'intfloat\/e5-small' device = 'cuda:6' if torch.cuda.is_available() else 'cpu' inference_model = E5InferenceModel(model_name=model_name, device=device)  # \u0421\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c \u043c\u043e\u0434\u0435\u043b\u044c # \u041f\u0443\u0442\u044c \u0434\u043b\u044f \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f SAVE_DIR = \"saved_e5_model\"  # \u0421\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c \u043c\u043e\u0434\u0435\u043b\u044c \u0438 \u0442\u043e\u043a\u0435\u043d\u0438\u0437\u0430\u0442\u043e\u0440 inference_model.model.save_pretrained(SAVE_DIR) inference_model.tokenizer.save_pretrained(SAVE_DIR)  print(f\"\u2705 \u041c\u043e\u0434\u0435\u043b\u044c \u0438 \u0442\u043e\u043a\u0435\u043d\u0438\u0437\u0430\u0442\u043e\u0440 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u044b \u0432: {SAVE_DIR}\") <\/code><\/pre>\n<p>\u0417\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c \u043c\u043e\u0434\u0435\u043b\u044c \u0432 \u043d\u0430\u0448\u0435\u0439 \u043e\u0431\u0435\u0440\u0442\u043a\u0435<\/p>\n<pre><code class=\"python\">from transformers import AutoModel, AutoTokenizer import torch  # \u041f\u0443\u0442\u044c \u043a \u0441\u043e\u0445\u0440\u0430\u043d\u0451\u043d\u043d\u043e\u0439 \u043c\u043e\u0434\u0435\u043b\u0438 MODEL_DIR = \"saved_e5_model\"  # \u0417\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u0442\u043e\u043a\u0435\u043d\u0438\u0437\u0430\u0442\u043e\u0440\u0430 \u0438 \u043c\u043e\u0434\u0435\u043b\u0438 tokenizer = AutoTokenizer.from_pretrained(MODEL_DIR) model = AutoModel.from_pretrained(MODEL_DIR) model.eval()  # \u041e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0434\u043b\u044f \u0438\u043d\u0444\u0435\u0440\u0435\u043d\u0441\u0430 device = torch.device('cuda:6' if torch.cuda.is_available() else 'cpu') model = model.to(device) <\/code><\/pre>\n<p>\u041d\u0430\u043f\u0438\u0441\u0430\u043d\u043e \u0433\u0440\u044f\u0437\u043d\u043e, \u043c\u043e\u0433\u043b\u0438 \u0431\u044b \u0438 \u043a\u043b\u0430\u0441\u0441 \u043f\u0435\u0440\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0441 \u0438\u043d\u0444\u0435\u0440\u0435\u043d\u0441\u043e\u043c \u0431\u0430\u0442\u0447\u0430, \u043d\u043e \u043a\u0430\u043a \u0435\u0441\u0442\u044c.<\/p>\n<pre><code class=\"python\">def encode_texts(texts, prefix=\"query\", batch_size=32):     \"\"\"     \u041a\u043e\u0434\u0438\u0440\u0443\u0435\u0442 \u0441\u043f\u0438\u0441\u043e\u043a \u0442\u0435\u043a\u0441\u0442\u043e\u0432 \u0432 \u044d\u043c\u0431\u0435\u0434\u0434\u0438\u043d\u0433\u0438 (\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f [CLS] \u0442\u043e\u043a\u0435\u043d).     prefix: \"query\" \u0438\u043b\u0438 \"passage\" (\u0434\u043b\u044f \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e\u0433\u043e \u0448\u0430\u0431\u043b\u043e\u043d\u0430).     \"\"\"     embeddings = []      for i in range(0, len(texts), batch_size):         batch = texts[i:i+batch_size]         inputs = tokenizer(             [f\"{prefix}: {text}\" for text in batch],             padding=True,             truncation=True,             return_tensors='pt'         ).to(device)          with torch.no_grad():             output = model(**inputs)             cls_emb = output.last_hidden_state[:, 0]  # [CLS] \u0442\u043e\u043a\u0435\u043d             embeddings.append(cls_emb.cpu())      return torch.cat(embeddings, dim=0).numpy()  # \u041f\u0440\u0438\u043c\u0435\u0440 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 queries = [\"wireless bluetooth headphones\", \"usb-c charging cable\"] query_embs = encode_texts(queries, prefix=\"query\")  print(\"\u2705 \u042d\u043c\u0431\u0435\u0434\u0434\u0438\u043d\u0433\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432:\", query_embs.shape) # \u2705 \u042d\u043c\u0431\u0435\u0434\u0434\u0438\u043d\u0433\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432: (2, 384)  <\/code><\/pre>\n<p>\u0421\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c \u0435\u043c\u0431\u0435\u0434\u044b \u0442\u043e\u0432\u0430\u0440\u043e\u0432<\/p>\n<pre><code class=\"python\"># \u0417\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u043c\u043e\u0434\u0435\u043b\u0438 print(\"\ud83d\udce6 \u0417\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c \u0441\u043e\u0445\u0440\u0430\u043d\u0451\u043d\u043d\u0443\u044e \u043c\u043e\u0434\u0435\u043b\u044c...\") model = AutoModel.from_pretrained(MODEL_PATH).eval().cuda() tokenizer = AutoTokenizer.from_pretrained(MODEL_PATH)  # \u041a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 product_embs = encode_texts(product_titles, batch_size=128) np.save(EMBEDS_PATH, product_embs) print(\"\u2705 \u042d\u043c\u0431\u0435\u0434\u0434\u0438\u043d\u0433\u0438 \u0438 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044f \u0442\u043e\u0432\u0430\u0440\u043e\u0432 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u044b.\") <\/code><\/pre>\n<p>\u0422\u0430\u043a \u0436\u0435 \u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u0443 \u0432\u0441\u0442\u0440\u0435\u0447\u0430\u0435\u043c\u043e\u0441\u0442\u0438 \u0432 \u0434\u0430\u0442\u0430\u0441\u0435\u0442\u0435 \u043f\u043e\u0441\u0447\u0438\u0442\u0430\u0435\u043c \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0442\u043e\u0432\u0430\u0440\u0430<\/p>\n<pre><code class=\"python\">import pandas as pd import os  # \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u0443 \u043f\u043e\u043a\u0430\u0437\u043e\u0432 \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0442\u043e\u0432\u0430\u0440\u0430 # \u2014\u2014\u2014 \u0417\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c \u0434\u0430\u0442\u0430\u0441\u0435\u0442, \u0435\u0441\u043b\u0438 \u0435\u0449\u0435 \u043d\u0435 \u0437\u0430\u0433\u0440\u0443\u0436\u0435\u043d \u2014\u2014\u2014 if not os.path.exists(PRODUCTS_PATH) or not os.path.exists(\"product_stats.csv\"):     print(\"\ud83d\udce5 \u0417\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c \u0434\u0430\u0442\u0430\u0441\u0435\u0442 \u0441 Hugging Face...\")     dataset = load_dataset(\"tasksource\/esci\", split=\"train\")     df = pd.DataFrame([x for x in tqdm(dataset, desc=\"\ud83d\udcc4 \u041f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u0443\u0435\u043c \u0432 DataFrame\")])          # \u0423\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0435 \u0442\u043e\u0432\u0430\u0440\u044b     product_titles = df['product_title'].dropna().unique().tolist()     pd.Series(product_titles).to_csv(PRODUCTS_PATH, index=False)      # \u2014\u2014\u2014 \u0421\u0447\u0438\u0442\u0430\u0435\u043c \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043f\u043e\u043a\u0430\u0437\u043e\u0432 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0442\u043e\u0432\u0430\u0440\u0430 \u2014\u2014\u2014     print(\"\ud83d\udcca \u0421\u0447\u0438\u0442\u0430\u0435\u043c \u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u0443 \u043f\u043e \u0442\u043e\u0432\u0430\u0440\u0430\u043c...\")     stats = df['product_title'].value_counts().reset_index()     stats.columns = ['product_title', 'views']     stats.to_csv(\"product_stats.csv\", index=False)     print(f\"\u2705 \u0421\u043e\u0445\u0440\u0430\u043d\u0438\u043b\u0438 \u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u0443 \u0434\u043b\u044f {len(stats)} \u0442\u043e\u0432\u0430\u0440\u043e\u0432\") <\/code><\/pre>\n<\/div>\n<\/details>\n<h3>\u041f\u0438\u0448\u0435\u043c \u043f\u043e\u0438\u0441\u043a\u043e\u0432\u043e\u0439 web-\u0441\u0435\u0440\u0432\u0438\u0441<\/h3>\n<p>\u041d\u0430\u0431\u0440\u0430\u0441\u044b\u0432\u0430\u0435\u043c \u043f\u0440\u043e\u0441\u0442\u0435\u043d\u044c\u043a\u0438\u0439 web \u043d\u0430 Streamlit. \u0423\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u043c\u043e\u0434\u0435\u043b\u044c, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u0432\u0435\u043a\u0442\u043e\u0440\u0438\u0437\u0443\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441 \u0438 \u043f\u0440\u043e\u0434\u0443\u043a\u0442. \u0423\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u0437\u0430\u043f\u0440\u043e\u0441, \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0432\u044b\u0434\u0430\u0447\u0438 \u0441 \u0441\u043a\u043e\u0440\u0430\u043c\u0438, \u043e\u0431\u0449\u0435\u0439 \u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u043e \u0441\u043a\u043e\u0440\u043e\u0432 \u0438 \u043a\u043e\u043b-\u0432\u043e \u043f\u043e\u043a\u0430\u0437\u043e\u0432 \u0442\u043e\u0432\u0430\u0440\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u043c.<\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/sw\/d5\/8s\/swd58sad1hzd4h27yqcpbrjnavc.jpeg\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/webt\/sw\/d5\/8s\/swd58sad1hzd4h27yqcpbrjnavc.jpeg 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/webt\/sw\/d5\/8s\/swd58sad1hzd4h27yqcpbrjnavc.jpeg 781w\" loading=\"lazy\" decode=\"async\"\/><\/figure>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 web-\u0441\u0435\u0440\u0432\u0438\u0441\u0430<\/summary>\n<div class=\"spoiler__content\">\n<p><a href=\"https:\/\/github.com\/naumtsevalex\/All-about-ML\/blob\/main\/02_query2product_e5_mvp_service\/app.py\" rel=\"noopener noreferrer nofollow\">\u0426\u0435\u043b\u044c\u043d\u044b\u0439 \u043a\u043e\u0434<\/a><\/p>\n<pre><code class=\"python\">import streamlit as st import numpy as np import pandas as pd import torch from transformers import AutoTokenizer, AutoModel from time import perf_counter import matplotlib.pyplot as plt import seaborn as sns  # \u042d\u0442\u043e \u043e\u0447\u0435\u043d\u044c \u043f\u043b\u043e\u0445\u043e \u0442\u0430\u043a \u043f\u0438\u0441\u0430\u0442\u044c, \u043d\u0435 \u0431\u0435\u0439\u0442\u0438 class E5Model(torch.nn.Module):     def __init__(self, model_name='intfloat\/e5-small'):         super().__init__()         self.encoder = AutoModel.from_pretrained(model_name)         self.tokenizer = AutoTokenizer.from_pretrained(model_name)      def encode(self, input_ids, attention_mask):         outputs = self.encoder(input_ids=input_ids, attention_mask=attention_mask)         return outputs.last_hidden_state[:, 0]      def forward(self, anchor_ids, anchor_mask, pos_ids, pos_mask, neg_ids, neg_mask):         anchor_emb = self.encode(anchor_ids, anchor_mask)         pos_emb = self.encode(pos_ids, pos_mask)         neg_emb = self.encode(neg_ids, neg_mask)         return anchor_emb, pos_emb, neg_emb   # --- \u041a\u043e\u043d\u0441\u0442\u0430\u043d\u0442\u044b --- PRETRAIN_MODEL_PATH = \"saved_e5_model\" # FT_MODEL_PATH = \"checkpoints\/e5_train_20250703_170142.pt\" # lr=2e-5 FT_MODEL_PATH = \"checkpoints\/e5_train_20250703_173139.pt\"  # lr=1e-4 + 3 epochs # FT_MODEL_PATH = \"checkpoints\/e5_train_20250703_175235.pt\"  # lr=1e-4 + 10 epochs   PRODUCTS_PATH = \"product_titles.csv\" # EMBEDS_PATH = \"small_product_embeddings.npy\" EMBEDS_PATH = \"product_embeddings.npy\" STATS_PATH = \"product_stats.csv\"  # CSV \u0441 \u043a\u043e\u043b\u043e\u043d\u043a\u0430\u043c\u0438 ['product_title', 'views']    # --- \u0412\u044b\u0431\u043e\u0440 \u043c\u043e\u0434\u0435\u043b\u0438 --- st.sidebar.markdown(\"\ud83e\udde0 **\u0412\u044b\u0431\u043e\u0440 \u043c\u043e\u0434\u0435\u043b\u0438**\") model_choice = st.sidebar.selectbox(     \"\u041c\u043e\u0434\u0435\u043b\u044c \u0434\u043b\u044f \u043f\u043e\u0438\u0441\u043a\u0430:\",     options=[\"\u0414\u043e\u043e\u0431\u0443\u0447\u0435\u043d\u043d\u0430\u044f (saved_e5_model)\", \"\u041f\u0440\u0435\u0434\u043e\u0431\u0443\u0447\u0435\u043d\u043d\u0430\u044f (intfloat\/e5-small)\"] )   # --- \u0417\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u043c\u043e\u0434\u0435\u043b\u0438 \u0438 \u0434\u0430\u043d\u043d\u044b\u0445 (\u043a\u0435\u0448\u0438\u0440\u0443\u0435\u0442\u0441\u044f) --- @st.cache_resource def load_model_and_data(model_choice):     if model_choice == \"\u0414\u043e\u043e\u0431\u0443\u0447\u0435\u043d\u043d\u0430\u044f (saved_e5_model)\":         model = E5Model(model_name=\"intfloat\/e5-small\")  # init \u0438\u0437 \u0442\u043e\u0433\u043e \u0436\u0435 \u0430\u0440\u0445\u0435\u0442\u0438\u043f\u0430         model.load_state_dict(torch.load(FT_MODEL_PATH))         tokenizer = model.tokenizer         model = model.encoder.eval().cuda()  # \u0434\u043e\u0441\u0442\u0430\u0451\u043c encoder     else:         tokenizer = AutoTokenizer.from_pretrained(PRETRAIN_MODEL_PATH)         model = AutoModel.from_pretrained(PRETRAIN_MODEL_PATH).eval().cuda()              product_titles = pd.read_csv(PRODUCTS_PATH).squeeze().tolist()     product_embs = np.load(EMBEDS_PATH)      # \u0417\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u0438     product_stats_df = pd.read_csv(STATS_PATH)     product_stats = dict(zip(product_stats_df['product_title'], product_stats_df['views']))     return tokenizer, model, product_titles, product_embs, product_stats  tokenizer, model, product_titles, product_embs, product_stats = load_model_and_data(model_choice=model_choice) total_products = len(product_titles)  # --- \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u0430 --- def encode_query(query):     inputs = tokenizer([f\"query: {query}\"], return_tensors=\"pt\", truncation=True, padding=True)     with torch.no_grad():         outputs = model(             input_ids=inputs[\"input_ids\"].cuda(),             attention_mask=inputs[\"attention_mask\"].cuda()         )     return outputs.last_hidden_state[:, 0].cpu().numpy()[0]  # --- \u0418\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 --- st.title(\"\ud83d\udd0e \u041f\u043e\u0438\u0441\u043a \u043f\u043e \u0442\u043e\u0432\u0430\u0440\u0430\u043c (E5)\")  st.markdown(f\"\ud83d\udecd\ufe0f **\u0412\u0441\u0435\u0433\u043e \u0442\u043e\u0432\u0430\u0440\u043e\u0432 \u0432 \u0431\u0430\u0437\u0435:** `{total_products}`\")  query = st.text_input(\"\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u0437\u0430\u043f\u0440\u043e\u0441:\", value=\"wireless headphones\") top_k = st.slider(\"\u0421\u043a\u043e\u043b\u044c\u043a\u043e \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432 \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c:\", 1, 30, 10)      if query:     with st.status(\"\ud83d\udd04 \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0437\u0430\u043f\u0440\u043e\u0441\u0430... \u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u043f\u043e\u0434\u043e\u0436\u0434\u0438\u0442\u0435.\", expanded=True) as status:          # --- \u042d\u0442\u0430\u043f 1: \u041a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 ---         t1 = perf_counter()         query_emb = encode_query(query)         query_time = perf_counter() - t1          query_emb \/= np.linalg.norm(query_emb)         prod_embs_norm = product_embs \/ np.linalg.norm(product_embs, axis=1, keepdims=True)          # --- \u042d\u0442\u0430\u043f 2: \u041f\u043e\u0438\u0441\u043a \u043f\u043e \u0431\u0430\u0437\u0435 ---         t2 = perf_counter()         scores = np.dot(prod_embs_norm, query_emb)         search_time = perf_counter() - t2          # --- \u042d\u0442\u0430\u043f 3: Top-K \u0440\u0430\u043d\u0436\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 ---         top_idx = np.argsort(scores)[-top_k:][::-1]         scores_top = scores[top_idx]          # --- \u0418\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441: \u0434\u0432\u0435 \u043a\u043e\u043b\u043e\u043d\u043a\u0438 ---         col1, col2 = st.columns([2, 1])          # --- \u041b\u0435\u0432\u0430\u044f \u043a\u043e\u043b\u043e\u043d\u043a\u0430: \u0432\u044b\u0434\u0430\u0447\u0430 \u0442\u043e\u0432\u0430\u0440\u043e\u0432 ---         with col1:             st.subheader(\"\ud83d\udccb \u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b:\")             for i in top_idx:                 title = product_titles[i]                 score = scores[i]                 views = product_stats.get(title, 0)                  st.markdown(                     f\"\"\"                     &lt;div style='                         background: #1c1c1c;                          padding: 10px 15px;                          margin: 8px 0;                          border-left: 4px solid #52c41a;                          border-radius: 6px;                     '&gt;                         &lt;div style='font-size: 16px; font-weight: bold; color: #ffffff;'&gt;{title}&lt;\/div&gt;                         &lt;div style='margin-top: 4px; color: #cccccc; font-size: 14px;'&gt;                             \ud83d\udd0d &lt;span style='color:#52c41a;'&gt;score: {score:.3f}&lt;\/span&gt; &amp;nbsp;&amp;nbsp;                              \ud83d\udc41\ufe0f &lt;span style='color:#f4d35e;'&gt;{views:,} \u043f\u043e\u043a\u0430\u0437\u043e\u0432&lt;\/span&gt;                         &lt;\/div&gt;                     &lt;\/div&gt;                     \"\"\",                     unsafe_allow_html=True                 )              st.markdown(\"---\")             st.markdown(f\"\u23f1\ufe0f \u0412\u0440\u0435\u043c\u044f \u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u0430: `{query_time:.4f} \u0441\u0435\u043a`\")             st.markdown(f\"\ud83d\udce1 \u0412\u0440\u0435\u043c\u044f \u043f\u043e\u0438\u0441\u043a\u0430 \u043f\u043e \u0431\u0430\u0437\u0435: `{search_time:.4f} \u0441\u0435\u043a`\")          # --- \u041f\u0440\u0430\u0432\u0430\u044f \u043a\u043e\u043b\u043e\u043d\u043a\u0430: \u0430\u043d\u0430\u043b\u0438\u0437 ---         with col2:             st.markdown(\"### \ud83d\udcca \u0410\u043d\u0430\u043b\u0438\u0437\")             fig, ax = plt.subplots(figsize=(5, 3))             sns.histplot(scores, bins=50, kde=True, ax=ax, color='skyblue', label='\u0412\u0441\u0435 \u0442\u043e\u0432\u0430\u0440\u044b')             ax.axvline(scores_top.min(), color='green', linestyle='--', label='Min Top-K')             ax.axvline(scores_top.max(), color='orange', linestyle='--', label='Max Top-K')             ax.set_xlabel(\"Score\")             ax.set_title(\"\u0420\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435\")             ax.legend()             st.pyplot(fig)              st.markdown(\"### \ud83d\udcd0 \u0421\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u0430\")             stats_dict = {                 \"Min\": float(np.min(scores)),                 \"Max\": float(np.max(scores)),                 \"Mean\": float(np.mean(scores)),                 \"Median\": float(np.median(scores)),                 \"Std\": float(np.std(scores)),                 \"5%\": float(np.percentile(scores, 5)),                 \"25%\": float(np.percentile(scores, 25)),                 \"75%\": float(np.percentile(scores, 75)),                 \"95%\": float(np.percentile(scores, 95)),              }             stats_df = pd.DataFrame(stats_dict, index=[\"Score\"]).T             st.dataframe(stats_df.style.format(\"{:.4f}\"))          status.update(label=\"\u2705 \u0413\u043e\u0442\u043e\u0432\u043e!\", state=\"complete\", expanded=True)   # \u0414\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430: # streamlit run app.py  <\/code><\/pre>\n<\/div>\n<\/details>\n<h3>\u041f\u0440\u0438\u0441\u0442\u0443\u043f\u0430\u0435\u043c \u043a \u0434\u043e\u043e\u0431\u0443\u0447\u0435\u043d\u0438\u044e \u043d\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0439 \u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u0438!<\/h3>\n<p>\u0423\u0447\u0438\u043c \u043a\u0430\u043a <a href=\"https:\/\/www.microsoft.com\/en-us\/research\/wp-content\/uploads\/2016\/02\/cikm2013_DSSM_fullversion.pdf\" rel=\"noopener noreferrer nofollow\">DSSM<\/a> \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u043d\u0430 \u043c\u043e\u0434\u0435\u043b\u044c \u0432\u0435\u043a\u0442\u043e\u0440\u0438\u0437\u0443\u0435\u0442 \u0434\u0432\u0435 \u0431\u0430\u0448\u043d\u0438 \u0441 \u043f\u0440\u0435\u0444\u0438\u043a\u0441\u043e\u043c <code>query:<\/code> \u0438 <code>passage:<\/code>  \u043d\u0430 <a href=\"https:\/\/docs.pytorch.org\/docs\/stable\/generated\/torch.nn.TripletMarginLoss.html\" rel=\"noopener noreferrer nofollow\">TripletMarginLoss<\/a>. \u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043c\u043e\u0434\u0435\u043b\u0438 \u0438 \u043f\u0440\u0435\u0442\u0440\u0430\u0439\u043d\u0430 \u0431\u0435\u0440\u0435\u043c E5.<\/p>\n<blockquote>\n<p>\u0423\u0447\u0443 \u043d\u0430 \u043e\u0434\u043d\u043e\u0439 A100<\/p>\n<\/blockquote>\n<blockquote>\n<p>\u042d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442\u0438\u0440\u0443\u044e \u0441 <code>lr<\/code>. \u0414\u043b\u044f <code>lr=0.2 - 0.3<\/code> \u043c\u043e\u0434\u0435\u043b\u044c \u0440\u0430\u0437\u043d\u043e\u0441\u0438\u0442 \u0438 \u0443\u0436\u0435 \u0431\u0435\u0441\u043f\u043e\u0432\u043e\u0440\u043e\u0442\u043d\u043e \u043f\u043e\u0440\u0442\u0438\u0442\u044c\u0441\u044f. \u0414\u043b\u044f <code>lr=0.4 - 0.5<\/code> \u043c\u043e\u0434\u0435\u043b\u044c \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0443\u0447\u0438\u0442\u0441\u044f (\u0438 \u0443\u0447\u0438\u0442\u044c\u0441\u044f \u0434\u0430\u043b\u044c\u0448\u0435, \u043d\u0435 \u0432\u044b\u0445\u043e\u0434\u0438\u0442 \u043d\u0430 \u043f\u043b\u0430\u0442\u043e!)<\/p>\n<\/blockquote>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/by\/xp\/yl\/byxpylbwnx3otjbiutzpecqsxie.jpeg\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/webt\/by\/xp\/yl\/byxpylbwnx3otjbiutzpecqsxie.jpeg 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/webt\/by\/xp\/yl\/byxpylbwnx3otjbiutzpecqsxie.jpeg 781w\" loading=\"lazy\" decode=\"async\"\/><\/figure>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/3j\/z_\/9a\/3jz_9axq2p9ppzkre2jykh1pank.jpeg\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/webt\/3j\/z_\/9a\/3jz_9axq2p9ppzkre2jykh1pank.jpeg 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/webt\/3j\/z_\/9a\/3jz_9axq2p9ppzkre2jykh1pank.jpeg 781w\" loading=\"lazy\" decode=\"async\"\/><\/figure>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/n2\/wf\/nk\/n2wfnkxnfayqpokj_oxisizinqc.jpeg\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/webt\/n2\/wf\/nk\/n2wfnkxnfayqpokj_oxisizinqc.jpeg 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/webt\/n2\/wf\/nk\/n2wfnkxnfayqpokj_oxisizinqc.jpeg 781w\" loading=\"lazy\" decode=\"async\"\/><\/figure>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/dm\/s-\/ia\/dms-iavns1sy8vgqplturg0tgoc.jpeg\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/webt\/dm\/s-\/ia\/dms-iavns1sy8vgqplturg0tgoc.jpeg 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/webt\/dm\/s-\/ia\/dms-iavns1sy8vgqplturg0tgoc.jpeg 781w\" loading=\"lazy\" decode=\"async\"\/><\/figure>\n<details class=\"spoiler\">\n<summary>\u0421\u043e\u0437\u0434\u0430\u0435\u043c Dataset<\/summary>\n<div class=\"spoiler__content\">\n<p><a href=\"https:\/\/github.com\/naumtsevalex\/All-about-ML\/blob\/main\/02_query2product_e5_mvp_service\/train_e5.ipynb\" rel=\"noopener noreferrer nofollow\">\u0426\u0435\u043b\u044c\u043d\u0430\u044f \u0442\u0435\u0442\u0440\u0430\u0434\u043a\u0430<\/a><\/p>\n<p>\u0412\u0430\u0440\u0438\u043c \u0434\u0430\u0442\u0430\u0441\u0435\u0442 \u0441 \u0442\u0440\u0438\u043f\u043b\u0435\u0442\u0430\u043c\u0438 <code>(query, pos, neg)<\/code><\/p>\n<pre><code class=\"python\">import pandas as pd import torch from torch.utils.data import Dataset, DataLoader from transformers import AutoTokenizer, AutoModel import pytorch_lightning as pl from torch.nn import TripletMarginLoss from torch.nn.functional import normalize from sklearn.model_selection import train_test_split import numpy as np import faiss from tqdm import tqdm from datetime import datetime import os import random   # \u2014\u2014\u2014 1. \u0422\u043e\u043a\u0435\u043d\u0438\u0437\u0430\u0446\u0438\u044f \u0438 \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u2014\u2014\u2014 # def dummy_tokenize(text: str): #     return text.lower()  class TripletDataset(Dataset):     def __init__(self, df, tokenizer, max_length=64, num_negatives=10):         self.samples = []         self.tokenizer = tokenizer         self.max_length = max_length         self.num_negatives = num_negatives         self.all_products = df['product_title'].unique()         self._build_triplets(df)      def _build_triplets(self, df):         n = len(df)         for i in range(self.num_negatives):             negs = random.choices(self.all_products, k=n)             for idx, row in enumerate(df.itertuples(index=False)):                 query = row.query                 pos = row.product_title                 neg = negs[idx]                 self.samples.append((query, pos, neg))      def __len__(self):         return len(self.samples)      def __getitem__(self, idx):         q, pos, neg = self.samples[idx]          # \u0422\u043e\u043a\u0435\u043d\u0438\u0437\u0430\u0446\u0438\u044f \u0441\u0440\u0430\u0437\u0443 \u0434\u043b\u044f \u043c\u043e\u0434\u0435\u043b\u0438         anchor_enc = self.tokenizer(             f\"query: {q}\", padding='max_length', truncation=True,             max_length=self.max_length, return_tensors='pt'         )         pos_enc = self.tokenizer(             f\"passage: {pos}\", padding='max_length', truncation=True,             max_length=self.max_length, return_tensors='pt'         )         neg_enc = self.tokenizer(             f\"passage: {neg}\", padding='max_length', truncation=True,             max_length=self.max_length, return_tensors='pt'         )          # \u0412\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u0442\u043e\u043b\u044c\u043a\u043e input_ids \u0438 attention_mask, \u043a\u0430\u043a \u043d\u0443\u0436\u043d\u043e \u0434\u043b\u044f forward         return (             (anchor_enc['input_ids'].squeeze(0), anchor_enc['attention_mask'].squeeze(0)),             (pos_enc['input_ids'].squeeze(0), pos_enc['attention_mask'].squeeze(0)),             (neg_enc['input_ids'].squeeze(0), neg_enc['attention_mask'].squeeze(0)),              f\"query: {q}\", # \u0434\u043b\u044f \u0434\u0435\u0431\u0430\u0433\u0430             f\"passage: {pos}\",             f\"passage: {neg}\"          ) <\/code><\/pre>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>\u0412\u0430\u0440\u0438\u043c Dataloader \u0438 \u0441\u043f\u043b\u0438\u0442\u0438\u043c \u0434\u0430\u043d\u043d\u044b\u0435<\/summary>\n<div class=\"spoiler__content\">\n<p><a href=\"https:\/\/github.com\/naumtsevalex\/All-about-ML\/blob\/main\/02_query2product_e5_mvp_service\/train_e5.ipynb\" rel=\"noopener noreferrer nofollow\">\u0426\u0435\u043b\u044c\u043d\u0430\u044f \u0442\u0435\u0442\u0440\u0430\u0434\u043a\u0430<\/a><\/p>\n<pre><code class=\"python\"> from datasets import load_dataset from tqdm import tqdm import pandas as pd from sklearn.model_selection import train_test_split from torch.utils.data import DataLoader from transformers import AutoTokenizer import pytorch_lightning as pl from datetime import datetime  # \u041f\u0440\u0435\u0434\u043f\u043e\u043b\u0430\u0433\u0430\u0435\u0442\u0441\u044f, \u0447\u0442\u043e TripletDataset \u0438 E5Model \u0443\u0436\u0435 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u044b \u0440\u0430\u043d\u0435\u0435  # \u2014\u2014\u2014 1. \u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u2014\u2014\u2014 def prepare_data(model_name='intfloat\/e5-small', batch_size=16, sample_rate=1.0):     print(\"\ud83d\udd3d \u0417\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c \u0434\u0430\u0442\u0430\u0441\u0435\u0442 tasksource\/esci...\")     dataset = load_dataset(\"tasksource\/esci\", split=\"train\")     dataset_len = len(dataset)      # \u0441\u0435\u043c\u043f\u043b\u0438\u043c \u0447\u0442\u043e\u0431\u044b \u0431\u044b\u0441\u0442\u0440\u0435\u0435 \u043e\u0442\u0434\u0435\u0431\u0430\u0436\u0438\u0442\u044c!     dataset_current_len = int(dataset_len * sample_rate)     dataset = dataset.shuffle(seed=42).select(range(dataset_current_len))      print(\"\ud83d\udce6 \u041a\u043e\u043d\u0432\u0435\u0440\u0442\u0438\u0440\u0443\u0435\u043c \u0432 pandas DataFrame...\")     df = pd.DataFrame([x for x in tqdm(dataset, desc=\"\u2192 \u041f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0441\u0442\u0440\u043e\u043a\")])      print(\"\ud83e\uddf9 \u0424\u0438\u043b\u044c\u0442\u0440\u0443\u0435\u043c \u043a\u043b\u0430\u0441\u0441\u044b: Exact \/ Substitute \/ Irrelevant...\")     df = df[df['esci_label'].isin(['Exact', 'Substitute', 'Irrelevant'])]      print(\"\ud83d\udd0d \u0423\u0434\u0430\u043b\u044f\u0435\u043c \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0441 &lt; 2 \u043f\u0440\u0438\u043c\u0435\u0440\u0430\u043c\u0438...\")     query_counts = df['query'].value_counts()     df = df[df['query'].isin(query_counts[query_counts &gt;= 2].index)]      print(\"\u2702\ufe0f \u0420\u0430\u0437\u0431\u0438\u0432\u0430\u0435\u043c \u043d\u0430 train\/val...\")     train_df, val_df = train_test_split(         df, test_size=0.1, random_state=42         # , stratify=df['query']     )     print(f\"\u2705 Train size: {len(train_df)} \/ Val size: {len(val_df)}\")      print(f\"\ud83d\udcda \u0417\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c \u0442\u043e\u043a\u0435\u043d\u0438\u0437\u0430\u0442\u043e\u0440: {model_name}\")     tokenizer = AutoTokenizer.from_pretrained(model_name)      print(\"\ud83d\udcd0 \u0421\u043e\u0437\u0434\u0430\u0451\u043c TripletDataset'\u044b...\")     train_dataset = TripletDataset(train_df, tokenizer)     val_dataset = TripletDataset(val_df, tokenizer)      print(f\"\ud83d\udcca Train triplets: {len(train_dataset)} \/ Val triplets: {len(val_dataset)}\")      train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True, drop_last=True)     val_loader = DataLoader(val_dataset, batch_size=batch_size, drop_last=True)      print(f\"Train batches: {len(train_loader)} \/ Val batches: {len(val_loader)} | {batch_size=}\")       return train_loader, val_loader, df <\/code><\/pre>\n<pre><code class=\"python\">train_loader, val_loader, df = prepare_data(sample_rate=0.01, batch_size=batch_size)  # \ud83d\udd3d \u0417\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c \u0434\u0430\u0442\u0430\u0441\u0435\u0442 tasksource\/esci... # \ud83d\udce6 \u041a\u043e\u043d\u0432\u0435\u0440\u0442\u0438\u0440\u0443\u0435\u043c \u0432 pandas DataFrame... # \u2192 \u041f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0441\u0442\u0440\u043e\u043a: 100%|\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588| 20278\/20278 [00:03&lt;00:00, 6354.40it\/s] # \ud83e\uddf9 \u0424\u0438\u043b\u044c\u0442\u0440\u0443\u0435\u043c \u043a\u043b\u0430\u0441\u0441\u044b: Exact \/ Substitute \/ Irrelevant... # \ud83d\udd0d \u0423\u0434\u0430\u043b\u044f\u0435\u043c \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0441 &lt; 2 \u043f\u0440\u0438\u043c\u0435\u0440\u0430\u043c\u0438... # \u2702\ufe0f \u0420\u0430\u0437\u0431\u0438\u0432\u0430\u0435\u043c \u043d\u0430 train\/val... # \u2705 Train size: 3657 \/ Val size: 407 # \ud83d\udcda \u0417\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c \u0442\u043e\u043a\u0435\u043d\u0438\u0437\u0430\u0442\u043e\u0440: intfloat\/e5-small # \ud83d\udcd0 \u0421\u043e\u0437\u0434\u0430\u0451\u043c TripletDataset'\u044b... # \ud83d\udcca Train triplets: 36570 \/ Val triplets: 4070 # Train batches: 285 \/ Val batches: 31 | batch_size=128 <\/code><\/pre>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>\u0423\u0447\u0438\u043c \u0438 \u0432\u0430\u043b\u0438\u0434\u0438\u0440\u0443\u0435\u043c \u043c\u043e\u0434\u0435\u043b\u044c<\/summary>\n<div class=\"spoiler__content\">\n<p><a href=\"https:\/\/github.com\/naumtsevalex\/All-about-ML\/blob\/main\/02_query2product_e5_mvp_service\/train_e5.ipynb\" rel=\"noopener noreferrer nofollow\">\u0426\u0435\u043b\u044c\u043d\u0430\u044f \u0442\u0435\u0442\u0440\u0430\u0434\u043a\u0430<\/a><\/p>\n<p>\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c \u043e\u0431\u0435\u0440\u0442\u043a\u0443 \u0434\u043b\u044f \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u044f \u043c\u043e\u0434\u0435\u043b\u0438<\/p>\n<pre><code class=\"python\">class E5Model(torch.nn.Module):     def __init__(self, model_name='intfloat\/e5-small'):         super().__init__()         self.encoder = AutoModel.from_pretrained(model_name)         self.tokenizer = AutoTokenizer.from_pretrained(model_name)      def encode(self, input_ids, attention_mask):         outputs = self.encoder(input_ids=input_ids, attention_mask=attention_mask)         return outputs.last_hidden_state[:, 0]      def forward(self, anchor_ids, anchor_mask, pos_ids, pos_mask, neg_ids, neg_mask):         anchor_emb = self.encode(anchor_ids, anchor_mask)         pos_emb = self.encode(pos_ids, pos_mask)         neg_emb = self.encode(neg_ids, neg_mask)         return anchor_emb, pos_emb, neg_emb <\/code><\/pre>\n<p>\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c eval \u0432 \u0432\u0440\u0435\u043c\u044f train<\/p>\n<pre><code class=\"python\">def eval_model(model, val_loader, device='cuda'):     model.eval()     model.to(device)      all_recalls = {k: [] for k in [1, 5, 10, 30]}      with torch.no_grad():         # for batch in tqdm(val_loader, desc=\"\ud83d\udd0e Eval\"):         for batch in val_loader:             (a_ids, a_mask), (p_ids, p_mask), (n_ids, n_mask), _, _, _ = batch              # \u041f\u0435\u0440\u0435\u043d\u043e\u0441\u0438\u043c \u043d\u0430 \u043d\u0443\u0436\u043d\u043e\u0435 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e             a_ids, a_mask = a_ids.to(device), a_mask.to(device)             p_ids, p_mask = p_ids.to(device), p_mask.to(device)             n_ids, n_mask = n_ids.to(device), n_mask.to(device)              # \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u044d\u043c\u0431\u0435\u0434\u0434\u0438\u043d\u0433\u0438             anchor_embs = model.encode(a_ids, a_mask).cpu().numpy()             pos_embs = model.encode(p_ids, p_mask).cpu().numpy()             neg_embs = model.encode(n_ids, n_mask).cpu().numpy()              # \u0421\u043e\u0431\u0438\u0440\u0430\u0435\u043c \"\u043f\u0443\u043b\" \u043f\u0440\u043e\u0434\u0443\u043a\u0442\u043e\u0432 (positive + negative)             product_embs = np.concatenate([pos_embs, neg_embs], axis=0)              recalls = RetrievalMetrics.recall_at_k_batch(anchor_embs, product_embs, k_list=k_list)             for k in recalls:                 all_recalls[k].append(recalls[k])          # \u0423\u0441\u0440\u0435\u0434\u043d\u0435\u043d\u0438\u0435 \u0438 \u043f\u0435\u0447\u0430\u0442\u044c     all_means_recalls = {}     for k in all_recalls:         all_means_recalls[k] = np.mean(all_recalls[k])     return all_means_recalls <\/code><\/pre>\n<p>\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u0435 + \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0432 tensorboard + \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u043c\u043e\u0434\u0435\u043b\u0438<\/p>\n<pre><code class=\"python\">import os CHECKPOINTS_DIR = \"checkpoints\" os.makedirs(CHECKPOINTS_DIR, exist_ok=True)   def train_model(model, train_loader, val_loader, num_epochs=3, lr=2e-5, device='cuda', every_n_step_do_val=50):     time_suffix = str(datetime.now().strftime('%Y%m%d_%H%M%S'))     run_name = f\"e5_train_{time_suffix}\" # and model_name!     writer = SummaryWriter(log_dir=f\"runs\/{run_name}\")           model.to(device)     optimizer = torch.optim.AdamW(model.parameters(), lr=lr)     loss_fn = TripletMarginLoss(margin=0.2)          global_step = 1     for epoch in range(num_epochs):         model.train()          for batch_id, batch in tqdm(enumerate(train_loader), desc=f\"\ud83d\udee0\ufe0f Epoch {epoch + 1}\/{num_epochs}\", total=len(train_loader)):             writer.add_scalar(\"train\/epoch_marker\", epoch, global_step)             (a_ids, a_mask), (p_ids, p_mask), (n_ids, n_mask), _, _, _ = batch              a_ids, a_mask = a_ids.to(device), a_mask.to(device)             p_ids, p_mask = p_ids.to(device), p_mask.to(device)             n_ids, n_mask = n_ids.to(device), n_mask.to(device)              anchor, pos, neg = model(a_ids, a_mask, p_ids, p_mask, n_ids, n_mask)             loss = loss_fn(anchor, pos, neg)              optimizer.zero_grad()             loss.backward()             optimizer.step()              grad_norm = torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1e9)              writer.add_scalar(\"train\/loss\", loss.item(), global_step)             writer.add_scalar(\"GradNorm\/train\", grad_norm, global_step)             writer.add_scalar(\"LR\/train\", optimizer.param_groups[0]['lr'], global_step)              train_recalls = eval_model(model, [batch], device=device)             for k, val in train_recalls.items():                 writer.add_scalar(f\"train\/recall@{k}\", val, global_step)                if batch_id % every_n_step_do_val == 0:                 recalls = eval_model(model, val_loader, device=device)                 for k, val in recalls.items():                     writer.add_scalar(f\"val\/recall@{k}\", val, global_step)                          global_step += 1              print(\"\u2705 \u041e\u0431\u0443\u0447\u0435\u043d\u0438\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u043e. \u0421\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c \u043c\u043e\u0434\u0435\u043b\u044c...\")     save_path = os.path.join(CHECKPOINTS_DIR, f\"{run_name}.pt\")     torch.save(model.state_dict(), save_path)     print(f\"\ud83d\udce6 \u041c\u043e\u0434\u0435\u043b\u044c \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0430 \u0432: {save_path}\")  <\/code><\/pre>\n<p>\u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u0441\u0430\u043c\u043e \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u0435<\/p>\n<pre><code class=\"python\"># train_loader, val_loader, _ = prepare_data(batch_size=16, sample_rate=0.05) model = E5Model(model_name='intfloat\/e5-small') train_model(model, train_loader, val_loader, num_epochs=3, device='cuda:6', lr=1e-4, every_n_step_do_val=10)  # \ud83d\udee0\ufe0f Epoch 1\/10: 100%|\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588| 285\/285 [04:22&lt;00:00,  1.09it\/s] # \ud83d\udee0\ufe0f Epoch 2\/10: 100%|\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588| 285\/285 [04:22&lt;00:00,  1.08it\/s] # ... # \ud83d\udee0\ufe0f Epoch 9\/10: 100%|\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588| 285\/285 [04:24&lt;00:00,  1.08it\/s] # \ud83d\udee0\ufe0f Epoch 10\/10: 100%|\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588| 285\/285 [04:23&lt;00:00,  1.08it\/s] # \u2705 \u041e\u0431\u0443\u0447\u0435\u043d\u0438\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u043e. \u0421\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c \u043c\u043e\u0434\u0435\u043b\u044c... # \ud83d\udce6 \u041c\u043e\u0434\u0435\u043b\u044c \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0430 \u0432: checkpoints\/e5_train_20250703_175235.pt <\/code><\/pre>\n<\/div>\n<\/details>\n<h3>\u0421\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u0435\u043c \u043c\u0435\u0442\u0440\u0438\u043a\u0438 BM25 &amp; pretrain E5 &amp; fine-tune E5<\/h3>\n<p>\u0412\u0438\u0434\u0438\u043c, \u0447\u0442\u043e \u0434\u043e\u043e\u0431\u0443\u0447\u0435\u043d\u0438\u0435 \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0441\u0445\u0432\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0443\u044e \u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u044c!<\/p>\n<blockquote>\n<p>\u0415\u0441\u043b\u0438 \u043e\u0431\u0443\u0447\u0430\u0442\u044c \u0434\u043e\u043b\u044c\u0448\u0435, \u0442\u043e \u043c\u0435\u0442\u0440\u0438\u043a\u0438 \u043d\u0435 \u0443\u0445\u043e\u0434\u044f\u0442 \u043d\u0430 \u043f\u043b\u0430\u0442\u043e! \u041e\u043d\u0438 \u0435\u0449\u0435 \u043b\u0443\u0447\u0448\u0435 \u043d\u0430\u0447\u0438\u043d\u0430\u044e\u0442 \u0443\u0447\u0438\u0442\u044b\u0432\u0430\u0442\u044c online \u0441\u0438\u0433\u043d\u0430\u043b. \u0422\u0443\u0442 \u0443\u0436\u0435 \u043d\u0443\u0436\u043d\u043e \u0437\u0430\u043a\u043b\u044e\u0447\u0430\u0442\u044c \u0442\u0440\u0435\u0439\u0434\u043e\u0444\u0444 \u043c\u0435\u0436\u0434\u0443 \u043a\u043b\u0438\u043a\u0430\u043c\u0438 \u0438 \u0441\u0435\u043c\u0430\u043d\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u0440\u0435\u043b\u0435\u0432\u0430\u043d\u0442\u043d\u043e\u0441\u0442\u044c\u044e.<\/p>\n<\/blockquote>\n<div>\n<div class=\"table\">\n<table>\n<tbody>\n<tr>\n<th>\n<p align=\"left\">Model<\/p>\n<\/th>\n<th>\n<p align=\"left\">Recall@1<\/p>\n<\/th>\n<th>\n<p align=\"left\">Recall@5<\/p>\n<\/th>\n<th>\n<p align=\"left\">Recall@10<\/p>\n<\/th>\n<th>\n<p align=\"left\">Recall@30<\/p>\n<\/th>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\"><strong>BM25<\/strong><\/p>\n<\/td>\n<td>\n<p align=\"left\">0.5731<\/p>\n<\/td>\n<td>\n<p align=\"left\">0.6822<\/p>\n<\/td>\n<td>\n<p align=\"left\">0.7145<\/p>\n<\/td>\n<td>\n<p align=\"left\">0.7631<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\"><strong>E5 (pretrain)<\/strong><\/p>\n<\/td>\n<td>\n<p align=\"left\">0.2686<\/p>\n<\/td>\n<td>\n<p align=\"left\">0.5129<\/p>\n<\/td>\n<td>\n<p align=\"left\">0.5862<\/p>\n<\/td>\n<td>\n<p align=\"left\">0.6971<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\"><strong>E5 (fine-tuned)<\/strong><\/p>\n<\/td>\n<td>\n<p align=\"left\">0.6413<\/p>\n<\/td>\n<td>\n<p align=\"left\">0.8750<\/p>\n<\/td>\n<td>\n<p align=\"left\">0.9270<\/p>\n<\/td>\n<td>\n<p align=\"left\">0.9660<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<details class=\"spoiler\">\n<summary>\u0421\u0447\u0438\u0442\u0430\u0435\u043c \u043c\u0435\u0442\u0440\u0438\u043a\u0438 \u043d\u0430 val \u0414\u043b\u044f BM25<\/summary>\n<div class=\"spoiler__content\">\n<p><a href=\"https:\/\/github.com\/naumtsevalex\/All-about-ML\/blob\/main\/02_query2product_e5_mvp_service\/train_e5.ipynb\" rel=\"noopener noreferrer nofollow\">\u0426\u0435\u043b\u044c\u043d\u0430\u044f \u0442\u0435\u0442\u0440\u0430\u0434\u043a\u0430<\/a><\/p>\n<p>\u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u043f\u043e\u0434\u0441\u0447\u0435\u0442\u0430 \u043c\u0435\u0442\u0440\u0438\u043a\u0438<\/p>\n<pre><code class=\"python\"># --- \u041a\u043b\u0430\u0441\u0441 \u0434\u043b\u044f \u043c\u0435\u0442\u0440\u0438\u043a \u0432\u043d\u0443\u0442\u0440\u0438 \u0431\u0430\u0442\u0447\u0430 --- class RetrievalMetrics:     @staticmethod     def recall_at_k_batch(anchor_embs, product_embs, k_list=[5, 10, 30]):         recalls = {k: 0 for k in k_list}         n = len(anchor_embs)         for i, a_emb in enumerate(anchor_embs):             scores = np.dot(product_embs, a_emb)             top_indices = np.argsort(scores)[-max(k_list):][::-1]             for k in k_list:                 # Positive \u0432\u0441\u0435\u0433\u0434\u0430 \u043d\u0430 \u043f\u043e\u0437\u0438\u0446\u0438\u0438 i (\u043f\u043e \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u044e TripletDataset)                 if i in top_indices[:k]:                     recalls[k] += 1         for k in k_list:             recalls[k] \/= n         return recalls <\/code><\/pre>\n<p>BM25 \u043d\u0430 \u0431\u0430\u0442\u0447\u0430\u0445<\/p>\n<pre><code class=\"python\">from rank_bm25 import BM25Okapi from nltk.tokenize import word_tokenize  def tokenize(text):     return word_tokenize(text.lower())  all_products = df['product_title'].dropna().unique().tolist() all_products = [f\"passage: {p}\" for p in all_products] tokenized_products_all = [tokenize(p) for p in all_products] bm25_full = BM25Okapi(tokenized_products_all)  ######  from collections import defaultdict bm25_recalls = defaultdict(list) k_list = [1, 5, 10, 30]  product_idx_map = {title: i for i, title in enumerate(all_products)}  for batch in tqdm(val_loader, desc=\"\ud83d\udd0d BM25 \u043d\u0430 \u0431\u0430\u0442\u0447\u0430\u0445\"):     _, _, _, queries, pos_titles, neg_titles = batch      # --- 1. \u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u043c \u0441\u043f\u0438\u0441\u043e\u043a \u0438\u0437 \u043f\u0440\u043e\u0434\u0443\u043a\u0442\u043e\u0432 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u0431\u0430\u0442\u0447\u0430 ---     batch_products = pos_titles + neg_titles      # --- 2. \u0418\u043d\u0434\u0435\u043a\u0441\u044b \u044d\u0442\u0438\u0445 \u0442\u043e\u0432\u0430\u0440\u043e\u0432 \u0432 all_products (\u0434\u043b\u044f score \u0444\u0438\u043b\u044c\u0442\u0440\u0430\u0446\u0438\u0438) ---     batch_indices = [product_idx_map[p] for p in batch_products if p in product_idx_map]      for q, true_title in zip(queries, pos_titles):         q_tokens = tokenize(q)         scores_all = bm25_full.get_scores(q_tokens)          # --- 3. \u041e\u0441\u0442\u0430\u0432\u0438\u043c \u0442\u043e\u043b\u044c\u043a\u043e \u0441\u043a\u043e\u0440\u044b \u0442\u043e\u0432\u0430\u0440\u043e\u0432 \u0438\u0437 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u0431\u0430\u0442\u0447\u0430 ---         scores_batch = [(i, scores_all[i]) for i in batch_indices]         top_indices = sorted(scores_batch, key=lambda x: x[1], reverse=True)         top_titles = [all_products[i] for i, _ in top_indices]                  for k in k_list:             bm25_recalls[k].append(int(true_title in top_titles[:k]))  # --- \u0423\u0441\u0440\u0435\u0434\u043d\u0435\u043d\u0438\u0435 --- for k in k_list:     print(f\"Recall@{k} (BM25): {np.mean(bm25_recalls[k]):.4f}\")    # Recall@1 (BM25): 0.5731 # Recall@5 (BM25): 0.6822 # Recall@10 (BM25): 0.7145 # Recall@30 (BM25): 0.7631 <\/code><\/pre>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>\u0414\u043b\u044f pretrain E5<\/summary>\n<div class=\"spoiler__content\">\n<p><a href=\"https:\/\/github.com\/naumtsevalex\/All-about-ML\/blob\/main\/02_query2product_e5_mvp_service\/train_e5.ipynb\" rel=\"noopener noreferrer nofollow\">\u0426\u0435\u043b\u044c\u043d\u0430\u044f \u0442\u0435\u0442\u0440\u0430\u0434\u043a\u0430<\/a><\/p>\n<p>pretrain E5<\/p>\n<pre><code class=\"python\"> # --- \u041f\u0440\u0438\u043c\u0435\u0440 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0441 val_loader --- model_name = 'intfloat\/e5-small' device = 'cuda:6' if torch.cuda.is_available() else 'cpu' inference_model = E5InferenceModel(model_name=model_name, device=device)  all_recalls = {k: [] for k in [1, 5, 10, 30]} k_list = [1, 5, 10, 30]  for batch in tqdm(val_loader, desc=\"\ud83d\udd0d Pretrain E5 \u043d\u0430 \u0431\u0430\u0442\u0447\u0430\u0445\"):      (anchor_ids, anchor_mask), (pos_ids, pos_mask), (neg_ids, neg_mask), q, pos, neg = batch      # \u0421\u043e\u0431\u0438\u0440\u0430\u0435\u043c \u0432\u0441\u0435 \u043f\u0440\u043e\u0434\u0443\u043a\u0442\u044b \u0431\u0430\u0442\u0447\u0430 (positive + negative)     batch_product_ids = torch.cat([pos_ids, neg_ids], dim=0)     batch_product_mask = torch.cat([pos_mask, neg_mask], dim=0)      # \u042d\u043c\u0431\u0435\u0434\u0434\u0438\u043d\u0433\u0438     anchor_embs = inference_model.encode_batch(anchor_ids, anchor_mask)     product_embs = inference_model.encode_batch(batch_product_ids, batch_product_mask)      # \u041c\u0435\u0442\u0440\u0438\u043a\u0438     recalls = RetrievalMetrics.recall_at_k_batch(anchor_embs, product_embs, k_list=k_list)     for k in k_list:         all_recalls[k].append(recalls[k])  # \u0423\u0441\u0440\u0435\u0434\u043d\u0435\u043d\u0438\u0435 \u043f\u043e \u0432\u0441\u0435\u043c \u0431\u0430\u0442\u0447\u0430\u043c for k in k_list:     mean_recall = np.mean(all_recalls[k])     print(f\"Recall@{k}: {mean_recall:.4f}\")  # Recall@1: 0.2686 # Recall@5: 0.5129 # Recall@10: 0.5862 # Recall@30: 0.6971 <\/code><\/pre>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>\u0414\u043b\u044f fine-tune E5<\/summary>\n<div class=\"spoiler__content\">\n<p>\u042f \u043f\u043e\u043b\u0435\u043d\u0438\u043b\u0441\u044f \u0438 \u0432\u043e\u0437\u044c\u043c\u0443 \u043c\u0435\u0442\u0440\u0438\u043a\u0443 \u0441 \u0433\u0440\u0430\u0444\u0438\u043a\u043e\u0432 (\u043c\u0435\u0440\u044f\u0442\u0441\u044f \u043d\u0430 \u0442\u043e\u043c \u0436\u0435 val).<\/p>\n<pre><code class=\"python\"># Recall@1: 0.6413 # Recall@5: 0.875 # Recall@10: 0.927 # Recall@30: 0.966 <\/code><\/pre>\n<\/div>\n<\/details>\n<h3>\u0420\u0430\u0437\u043d\u0438\u0446\u0430 \u043f\u043e\u0438\u0441\u043a\u043e\u0432\u044b\u0445 \u0432\u044b\u0434\u0430\u0447 pretrain E5 \u0438 fine-tune E5<\/h3>\n<blockquote>\n<p>\u0412\u0438\u0434\u0438\u043c, \u0447\u0442\u043e \u043f\u0440\u0438 \u0434\u043e\u043e\u0431\u0443\u0447\u0435\u043d\u0438\u0438 \u0432 \u0432\u044b\u0434\u0430\u0447\u0435 \u043d\u0430\u0447\u0438\u043d\u0430\u044e\u0442 \u0434\u043e\u043c\u0438\u043d\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0442\u043e\u0432\u0430\u0440\u044b \u0441 \u0431\u041e\u043b\u044c\u0448\u0438\u043c \u0447\u0438\u0441\u043b\u043e\u043c \u043f\u043e\u043a\u0430\u0437\u043e\u0432\/\u043a\u043b\u0438\u043a\u043e\u0432(=\u0431\u043e\u043b\u0435\u0435 \u043e\u0434\u043e\u0431\u0440\u044f\u0435\u043c\u044b\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u043c\u0438).<\/p>\n<\/blockquote>\n<blockquote>\n<p>\u0421\u043a\u043e\u0440 \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442 \u0437\u0430\u043a\u043b\u0430\u0434\u044b\u0432\u0430\u0442\u044c\u0441\u044f, \u043a\u0430\u043a\u043e\u0439-\u0442\u043e \u044d\u0444\u0435\u043c\u0435\u0440\u043d\u044b\u0439 \u0441\u043c\u044b\u0441\u043b \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u043e\u0441\u0442\u0438 \u0443 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 <img decoding=\"async\" class=\"formula inline\" source=\"\\Rightarrow\" alt=\"\\Rightarrow\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/0\/05\/055\/055889aaee38b7c53f994c5e42a40994.svg\" width=\"auto\" height=\"auto\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/0\/05\/055\/055889aaee38b7c53f994c5e42a40994.svg 780w,&#10;       https:\/\/habrastorage.org\/getpro\/habr\/formulas\/0\/05\/055\/055889aaee38b7c53f994c5e42a40994.svg 781w\" loading=\"lazy\" decode=\"async\"\/> \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442 \u0431\u044b\u0442\u044c \u043c\u0435\u043d\u0435 \u0443\u0432\u0435\u0440\u0435\u043d\u043d\u044b\u0439 (\u043e\u0442\u0434\u0430\u043b\u044f\u0435\u0442\u0441\u044f \u043e\u0442 \u043c\u0430\u043a\u0441\u0438\u043c\u0443\u043c\u0430 \u0440\u0430\u0432\u043d\u043e\u0433\u043e <img decoding=\"async\" class=\"formula inline\" source=\"1\" alt=\"1\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/c\/c4\/c4c\/c4ca4238a0b923820dcc509a6f75849b.svg\" width=\"auto\" height=\"auto\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/c\/c4\/c4c\/c4ca4238a0b923820dcc509a6f75849b.svg 780w,&#10;       https:\/\/habrastorage.org\/getpro\/habr\/formulas\/c\/c4\/c4c\/c4ca4238a0b923820dcc509a6f75849b.svg 781w\" loading=\"lazy\" decode=\"async\"\/>)<\/p>\n<\/blockquote>\n<p>pretrain <\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/sw\/d5\/8s\/swd58sad1hzd4h27yqcpbrjnavc.jpeg\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/webt\/sw\/d5\/8s\/swd58sad1hzd4h27yqcpbrjnavc.jpeg 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/webt\/sw\/d5\/8s\/swd58sad1hzd4h27yqcpbrjnavc.jpeg 781w\" loading=\"lazy\" decode=\"async\"\/><\/figure>\n<p>fine-tune <\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/8t\/ff\/b2\/8tffb2bzbuz8scpfsztxmtjujye.jpeg\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/webt\/8t\/ff\/b2\/8tffb2bzbuz8scpfsztxmtjujye.jpeg 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/webt\/8t\/ff\/b2\/8tffb2bzbuz8scpfsztxmtjujye.jpeg 781w\" loading=\"lazy\" decode=\"async\"\/><\/figure>\n<h4>\u2705 \u0418\u0442\u043e\u0433\u0438<\/h4>\n<p>\u0421\u043e\u0431\u0440\u0430\u043b\u0438 \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0435, \u043d\u043e \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435:<br \/> \u043f\u043e\u0438\u0441\u043a \u0442\u043e\u0432\u0430\u0440\u043e\u0432 \u043f\u043e \u0441\u043c\u044b\u0441\u043b\u0443, \u0441 \u0434\u043e\u043e\u0431\u0443\u0447\u0435\u043d\u043d\u043e\u0439 E5, \u0432\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0435\u0439 \u0432\u044b\u0434\u0430\u0447\u0438 \u0438 \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u043c\u0438 \u043c\u0435\u0442\u0440\u0438\u043a\u0430\u043c\u0438. \u0412\u0441\u0451 \u044d\u0442\u043e \u2014 \u0432 \u0432\u0438\u0434\u0435 \u043f\u0440\u043e\u0441\u0442\u043e\u0433\u043e MVP-\u0441\u0435\u0440\u0432\u0438\u0441\u0430.<\/p>\n<blockquote>\n<p>\u0420\u0435\u0448\u0435\u043d\u0438\u0435 \u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u043e: \u0441 \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u043c\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f\u043c\u0438 \u043e\u043d\u043e \u043f\u043e\u0434\u043e\u0439\u0434\u0451\u0442 \u0434\u043b\u044f \u0437\u0430\u0434\u0430\u0447 \u043f\u043e\u0438\u0441\u043a\u0430 \u043f\u043e \u0440\u0435\u0437\u044e\u043c\u0435, \u0441\u0442\u0430\u0442\u044c\u044f\u043c, \u0442\u0438\u043a\u0435\u0442\u0430\u043c, \u043f\u0440\u043e\u0434\u0443\u043a\u0442\u0430\u043c \u0438 \u0434\u0430\u0436\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u043c \u0432\u043e\u043f\u0440\u043e\u0441\u0430\u043c.<\/p>\n<\/blockquote>\n<details class=\"spoiler\">\n<summary>\u0422\u043e\u0447\u043a\u0438 \u0440\u043e\u0441\u0442\u0430 (\u0438\u0445 \u043c\u043d\u043e\u0433\u043e \ud83d\ude05)<\/summary>\n<div class=\"spoiler__content\">\n<p><strong>\u0422\u0435\u043a\u0443\u0449\u0438\u0439 \u0441\u0442\u0435\u043a:<\/strong><br \/> <code>HuggingFace + PyTorch + TensorBoard + Streamlit<\/code><\/p>\n<p><strong>\u0427\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0443\u043b\u0443\u0447\u0448\u0438\u0442\u044c:<\/strong><\/p>\n<p><strong>\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0438 \u043a\u043e\u0434\u043e\u0432\u0430\u044f \u0431\u0430\u0437\u0430<\/strong><\/p>\n<ul>\n<li>\n<p>\u0418\u0437\u0431\u0430\u0432\u043b\u044f\u0442\u044c\u0441\u044f \u043e\u0442 \u043d\u043e\u0443\u0442\u0431\u0443\u043a\u043e\u0432 \u0432 \u043f\u0440\u043e\u0434\u0435: \u0432\u044b\u043d\u043e\u0441\u0438\u0442\u044c \u043b\u043e\u0433\u0438\u043a\u0443 \u0432 \u043c\u043e\u0434\u0443\u043b\u0438 (<code>train.py<\/code>, <code>inference.py<\/code>, <code>app\/<\/code>)<\/p>\n<\/li>\n<li>\n<p>\u0423\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u044b\u0435 \u0441\u0438\u0433\u043d\u0430\u0442\u0443\u0440\u044b \u0444\u0443\u043d\u043a\u0446\u0438\u0439 \u0438 \u043c\u043e\u0434\u0435\u043b\u0435\u0439 (\u0435\u0434\u0438\u043d\u044b\u0439 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441)<\/p>\n<\/li>\n<li>\n<p>\u041f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u043c\u043e\u0434\u0435\u043b\u0435\u0439 \u0431\u0435\u0437 \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u044b\u0432\u0430\u043d\u0438\u044f \u043a\u043e\u0434\u0430<\/p>\n<\/li>\n<li>\n<p>\u0427\u0451\u0442\u043a\u0430\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430, \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u044f \u0438 \u0441\u0435\u0440\u0432\u0438\u0441\u0430<\/p>\n<\/li>\n<\/ul>\n<p><strong>\u041e\u0431\u0443\u0447\u0435\u043d\u0438\u0435 \u0438 \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435<\/strong><\/p>\n<ul>\n<li>\n<p>\u041f\u0435\u0440\u0435\u0439\u0442\u0438 \u043d\u0430 <a href=\"https:\/\/www.pytorchlightning.ai\/\" rel=\"noopener noreferrer nofollow\">PyTorch Lightning<\/a> \u0434\u043b\u044f \u043a\u043e\u043c\u043f\u0430\u043a\u0442\u043d\u043e\u0441\u0442\u0438 \u0438 \u0447\u0438\u0442\u0430\u0435\u043c\u043e\u0441\u0442\u0438 \u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d\u0430<\/p>\n<\/li>\n<li>\n<p>\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c <a href=\"https:\/\/clear.ml\/\" rel=\"noopener noreferrer nofollow\">ClearML<\/a> \u0438\u043b\u0438 <a href=\"https:\/\/wandb.ai\/\" rel=\"noopener noreferrer nofollow\">W&amp;B<\/a> \u0432\u043c\u0435\u0441\u0442\u043e TensorBoard \u0434\u043b\u044f \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u043d\u0438\u044f \u044d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442\u043e\u0432<\/p>\n<\/li>\n<li>\n<p>\u0412\u044b\u043d\u0435\u0441\u0442\u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u044f \u0432 \u043a\u043e\u043d\u0444\u0438\u0433\u0438 (<code>yaml<\/code>, <code>json<\/code>, <code>hydra<\/code>)<\/p>\n<\/li>\n<\/ul>\n<p><strong>\u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u044f \u0438\u043d\u0444\u0435\u0440\u0435\u043d\u0441\u0430<\/strong><\/p>\n<ul>\n<li>\n<p>ONNX \/ ONNX Runtime \u0434\u043b\u044f \u0443\u0441\u043a\u043e\u0440\u0435\u043d\u0438\u044f \u0438 \u043f\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u043c\u043e\u0441\u0442\u0438 \u043c\u043e\u0434\u0435\u043b\u0438<\/p>\n<\/li>\n<li>\n<p>\u041a\u0432\u0430\u043d\u0442\u043e\u0432\u0430\u043d\u0438\u0435 \u043c\u043e\u0434\u0435\u043b\u0438 (int8\/float16) \u0434\u043b\u044f \u043c\u0435\u043d\u044c\u0448\u0435\u0433\u043e \u0440\u0430\u0437\u043c\u0435\u0440\u0430 \u0438 CPU-\u0438\u043d\u0444\u0435\u0440\u0435\u043d\u0441\u0430<\/p>\n<\/li>\n<li>\n<p>\u041f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 \u0431\u0430\u0442\u0447\u0435\u0432\u043e\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0438 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0433\u043e \u0438\u043d\u0444\u0435\u0440\u0435\u043d\u0441\u0430<\/p>\n<\/li>\n<\/ul>\n<p><strong>\u041f\u043e\u0438\u0441\u043a \u0438 \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435<\/strong><\/p>\n<ul>\n<li>\n<p>\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432\u0435\u043a\u0442\u043e\u0440\u043d\u044b\u0439 \u0438\u043d\u0434\u0435\u043a\u0441 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, <a href=\"https:\/\/github.com\/facebookresearch\/faiss\" rel=\"noopener noreferrer nofollow\">Faiss<\/a>) \u0432\u043c\u0435\u0441\u0442\u043e \u043f\u043e\u043b\u043d\u043e\u0433\u043e \u043f\u0435\u0440\u0435\u0431\u043e\u0440\u0430<\/p>\n<\/li>\n<li>\n<p>CPU vs GPU: \u043f\u0440\u043e\u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c, \u0433\u0434\u0435 \u043f\u0440\u043e\u0449\u0435 \u0438 \u0434\u0435\u0448\u0435\u0432\u043b\u0435 \u2014 \u0431\u043e\u043b\u044c\u0448\u0435 CPU \u0441 \u0448\u0430\u0440\u0434\u0438\u043d\u0433\u043e\u043c \u0438\u043b\u0438 \u043e\u0434\u0438\u043d GPU<\/p>\n<\/li>\n<li>\n<p>\u0420\u0430\u0431\u043e\u0442\u0430 \u0441 \u0434\u0430\u0442\u0430\u0441\u0435\u0442\u043e\u043c \u043a\u0430\u043a \u0441 \u0438\u0442\u0435\u0440\u0430\u0442\u043e\u0440\u043e\u043c, \u0431\u0435\u0437 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0432 RAM<\/p>\n<\/li>\n<\/ul>\n<\/div>\n<\/details>\n<p>\u0412\u0435\u0441\u044c \u043a\u043e\u0434: \u0434\u0430\u043d\u043d\u044b\u0435, EDA, \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u0435 \u0438 MVP-\u0441\u0435\u0440\u0432\u0438\u0441 \u043b\u0435\u0436\u0438\u0442 \u0432 <a href=\"https:\/\/github.com\/naumtsevalex\/All-about-ML\/tree\/main\/02_query2product_e5_mvp_service\" rel=\"noopener noreferrer nofollow\">\u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438<\/a><\/p>\n<p>\u0422\u0430\u043a \u0436\u0435 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043f\u043e\u043b\u0435\u0437\u043d\u043e \u043f\u0440\u043e\u0431\u0435\u0436\u0430\u0442\u044c\u0441\u044f \u043f\u043e \u0441\u0442\u0430\u0442\u044c\u0435: <a href=\"https:\/\/habr.com\/ru\/articles\/916632\/\" rel=\"noopener noreferrer nofollow\">RecSys + DSSM + FPSLoss is all you need<\/a><\/p>\n<hr\/>\n<h3>\u0427\u0442\u043e \u0434\u0430\u043b\u044c\u0448\u0435?<\/h3>\n<p>\u0412 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0445 \u0441\u0442\u0430\u0442\u044c\u044f\u0445 \u043f\u043e\u043a\u0430\u0436\u0435\u043c, \u043a\u0430\u043a \u0440\u0435\u0448\u0430\u0442\u044c \u043f\u043e\u0434\u043e\u0431\u043d\u044b\u0435 \u0437\u0430\u0434\u0430\u0447\u0438 \u0435\u0449\u0451 \u043a\u043e\u043c\u043f\u0430\u043a\u0442\u043d\u0435\u0435 \u0438 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0447\u043d\u0435\u0435 \u2014 \u0432\u043f\u043b\u043e\u0442\u044c \u0434\u043e \u043f\u043e\u043b\u043d\u043e\u0433\u043e \u043e\u0442\u043a\u0430\u0437\u0430 \u043e\u0442 \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e NoCode-\u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432.<\/p>\n<p><em>\u0410 \u043f\u043e\u043a\u0430 \u2014 \u043f\u0440\u0438\u0441\u043e\u0435\u0434\u0438\u043d\u044f\u0439\u0442\u0435\u0441\u044c \u043a \u043d\u0430\u0448\u0435\u043c\u0443 Telegram-\u0441\u043e\u043e\u0431\u0449\u0435\u0441\u0442\u0432\u0443 <\/em><a href=\"https:\/\/t.me\/+w0V_HEhKSkIyMTYy\" rel=\"noopener noreferrer nofollow\"><em>@datafeeling<\/em><\/a><em> \u0438 \u0432\u0434\u043e\u0445\u043d\u043e\u0432\u043b\u044f\u0439\u0442\u0435\u0441\u044c \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u043c\u0438 \u043f\u043e\u0434\u0445\u043e\u0434\u0430\u043c\u0438 \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0445 \u0437\u0430\u0434\u0430\u0447.<\/em><\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/925290\/\"> https:\/\/habr.com\/ru\/articles\/925290\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u0427\u0442\u043e \u0432\u0430\u0436\u043d\u0435\u0435: <strong>\u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043f\u0440\u043e\u0434\u0443\u043a\u0442<\/strong>, \u0438\u043b\u0438 <strong>\u0434\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0435\u0433\u043e \u0434\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f<\/strong>? \u041e\u0431\u0430 \u044d\u0442\u0430\u043f\u0430 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b. \u0421\u0435\u0433\u043e\u0434\u043d\u044f \u043e\u0431\u0441\u0443\u0434\u0438\u043c <strong>\u0432\u0442\u043e\u0440\u043e\u0439<\/strong>. \u041a\u0430\u043a \u043d\u0430\u043c \u043f\u043e\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u043f\u043e\u0438\u0441\u043a\u043e\u0432\u0443\u044e e-com \u0441\u0438\u0441\u0442\u0435\u043c\u0443.<\/p>\n<p>\u041f\u043e\u043a\u0430\u0436\u0435\u043c, \u0447\u0442\u043e \u0432 \u0441\u043b\u043e\u0432\u043e <strong>\u043b\u043e\u0433\u0438\u0441\u0442\u0438\u043a\u0430 \u0442\u043e\u0432\u0430\u0440\u0430<\/strong> \u0432\u0445\u043e\u0434\u044f\u0442 \u0441\u043b\u043e\u0436\u043d\u044b\u0435 \u0437\u0430\u0434\u0430\u0447\u0438 \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e: <strong>\u043f\u0435\u0440\u0435\u0432\u0435\u0437\u0442\u0438 \u043d\u0430\u0443\u0448\u043d\u0438\u043a\u0438 \u0438\u0437 \u041a\u0438\u0442\u0430\u044f \u0432 \u0410\u043c\u0435\u0440\u0438\u043a\u0443<\/strong>, \u043d\u043e \u0438 <strong>\u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043f\u043e\u0438\u0441\u043a\u043e\u0432\u043e\u0439 \u0432\u044b\u0434\u0430\u0447\u0438<\/strong> \u043f\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0443.<\/p>\n<p>\u0411\u044b\u0441\u0442\u0440\u043e \u0441\u043e\u0431\u0435\u0440\u0435\u043c <strong>\u043f\u043e\u0438\u0441\u043a\u043e\u0432\u043e\u0439 MVP-\u0441\u0435\u0440\u0432\u0438\u0441<\/strong>. <strong>\u0414\u043e\u043e\u0431\u0443\u0447\u0438\u043c \u043c\u043e\u0434\u0435\u043b\u044c E5<\/strong> \u043d\u0430 \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u043e\u0442 <strong>Amazon<\/strong>. \u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c \u043c\u0435\u0442\u0440\u0438\u043a\u0438 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0430 \u0438 \u0441\u0440\u0430\u0432\u043d\u0438\u043c <strong>BM25<\/strong>, <strong>pretrain E5<\/strong> \u0438 <strong>fine-tune E5<\/strong>. \u0422\u0430\u043a \u0436\u0435 <strong>\u0432\u0437\u0433\u043b\u044f\u043d\u0435\u043c \u0433\u043b\u0430\u0437\u0430\u043c\u0438 \u0441 \u043e\u0442\u043b\u0430\u0434\u043e\u0447\u043d\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0435\u0439<\/strong> \u0438 \u043f\u0440\u043e\u0430\u043d\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u043c <strong>\u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043f\u043e\u0438\u0441\u043a\u043e\u0432\u044b\u0445 \u0432\u044b\u0434\u0430\u0447<\/strong>.<\/p>\n<p>\u0418 \u043f\u043e\u0434 \u043a\u043e\u043d\u0435\u0446 \u043e\u0431\u0441\u0443\u0434\u0438\u043c \u043a\u0430\u043a\u0438\u0445 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0439 \u0435\u0449\u0435 \u043d\u0435 \u0445\u0432\u0430\u0442\u0430\u0435\u0442 \u0438 \u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c, \u0435\u0441\u043b\u0438 \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u044e\u0442 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u0442\u0440\u0443\u0434\u043d\u043e\u0441\u0442\u0438.<\/p>\n<figure class=\"\"><\/figure>\n<blockquote>\n<p>\u26a0\ufe0f \u0414\u0438\u0441\u043a\u043b\u0435\u0439\u043c\u0435\u0440<br \/> \u0412 \u043f\u0435\u0440\u0432\u0443\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u0446\u0435\u043b\u044c &#8212; \u043f\u043e\u0441\u0442\u0440\u043e\u0438\u0442\u044c MVP <strong>\u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0435\u0435<\/strong> \u0440\u0435\u0448\u0435\u043d\u0438\u0435, \u0447\u0442\u043e\u0431\u044b \u0441\u0440\u0430\u0437\u0443 \u043d\u0430\u0447\u0430\u0442\u044c \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c \u0433\u0438\u043f\u043e\u0442\u0435\u0437\u044b. \u041f\u0440\u0435\u0434\u043f\u043e\u043b\u043e\u0436\u0438\u043c \u043c\u044b \u043d\u0430 \u0445\u0430\u043a\u0430\u0442\u043e\u043d\u0435 \u0438 \u0445\u043e\u0442\u0438\u043c \u0435\u0433\u043e \u0432\u044b\u0439\u0433\u0440\u0430\u0442\u044c, \u0442\u043e\u0433\u0434\u0430 \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c  \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u0443\u044e ML \u0441\u0438\u0441\u0442\u0435\u043c\u0443 \u0438 \u0443 \u043d\u0430\u0441 \u043c\u0430\u043b\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438!<\/p>\n<\/blockquote>\n<details class=\"spoiler\">\n<summary>\ud83d\ude80 \u041f\u043e\u0447\u0435\u043c\u0443 \u0432\u0430\u0436\u043d\u043e \u0443\u043c\u0435\u0442\u044c \u0441\u0430\u043c\u043e\u043c\u0443 \u0431\u044b\u0441\u0442\u0440\u043e \u043f\u0438\u0441\u0430\u0442\u044c MVP \u0440\u0435\u0448\u0435\u043d\u0438\u044f? <\/summary>\n<div class=\"spoiler__content\">\n<p>\u0412\u044b \u0443\u043c\u0435\u0435\u0442\u0435 \u0431\u0440\u043e\u0441\u0430\u0442\u044c \u043a\u0430\u043c\u0435\u043d\u044c \u0432 \u0432\u043e\u0434\u0443 \u0442\u0430\u043a, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u0448\u043b\u043e \u043c\u043d\u043e\u0433\u043e \u0431\u043b\u0438\u043d\u0447\u0438\u043a\u043e\u0432? \u041d\u0430 \u0441\u043b\u043e\u0432\u0430\u0445 \u2014 \u043f\u0440\u043e\u0441\u0442\u043e: \u043a\u0438\u043d\u0443\u043b \u0438 \u0433\u043e\u0442\u043e\u0432\u043e. \u0410 \u043d\u0430 \u0434\u0435\u043b\u0435 \u2014 \u0441\u043e\u0432\u0441\u0435\u043c \u043d\u0435\u0442.<\/p>\n<p>\u041a\u043e\u0433\u0434\u0430 \u0442\u0440\u043e\u0433\u0430\u0435\u0448\u044c \u0437\u0430\u0434\u0430\u0447\u0443 \u0441\u0430\u043c \u2014 \u0441\u0442\u0430\u043b\u043a\u0438\u0432\u0430\u0435\u0448\u044c\u0441\u044f \u0441 \u0442\u0440\u0443\u0434\u043d\u043e\u0441\u0442\u044f\u043c\u0438, \u043f\u0440\u043e\u0445\u043e\u0434\u0438\u0448\u044c \u0438\u0445 \u0430, \u0441\u0430\u043c\u043e\u0435 \u0433\u043b\u0430\u0432\u043d\u043e\u0435, \u043b\u0443\u0447\u0448\u0435 \u0432\u0441\u0435\u0433\u043e \u0437\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u0435\u0448\u044c \u0438 \u0443\u0447\u0438\u0448\u044c\u0441\u044f!<br \/> \u0422\u0430\u043a \u0443\u0441\u0442\u0440\u043e\u0435\u043d\u0430 \u0433\u043e\u043b\u043e\u0432\u0430: \u043e\u043d\u0430 \u0445\u0443\u0436\u0435 \u0443\u0447\u0438\u0442\u0441\u044f \u043d\u0430 \u0447\u0443\u0436\u043e\u043c \u043e\u043f\u044b\u0442\u0435 \u0438 \u0433\u043e\u0440\u0430\u0437\u0434\u043e \u043b\u0443\u0447\u0448\u0435 \u2014 \u043d\u0430 \u0441\u0432\u043e\u0451\u043c.<\/p>\n<hr\/>\n<p>\u0422\u0430\u043a\u0436\u0435, \u043a\u043e\u0433\u0434\u0430 \u0441\u0440\u043e\u043a\u0438 \u0441\u0436\u0430\u0442\u044b \u2014 \u0442\u044b \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0432\u044b\u0431\u0438\u0440\u0430\u0435\u0448\u044c <strong>\u0441\u0430\u043c\u044b\u0435 \u043d\u0443\u0436\u043d\u044b\u0435 \u0438 \u0440\u0430\u0431\u043e\u0447\u0438\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u0432 \u0442\u0435\u043a\u0443\u0449\u0438\u0445 \u0443\u0441\u043b\u043e\u0432\u0438\u044f\u0445<\/strong>. \u042d\u0442\u043e \u043d\u0435 \u0445\u0430\u043e\u0441, \u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0430. \u0414\u0430\u0436\u0435 \u0435\u0441\u0442\u044c \u043f\u043e\u0434\u0445\u043e\u0434 \u2014 <a href=\"https:\/\/ru.wikipedia.org\/wiki\/Cynefin_framework\" rel=\"noopener noreferrer nofollow\">\u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a Cynefin<\/a>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0433\u043e\u0432\u043e\u0440\u0438\u0442: <strong>\u0432 \u0440\u0430\u0437\u043d\u044b\u0445 \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u044f\u0445 \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u044e\u0442\u0441\u044f \u043f\u043e-\u0440\u0430\u0437\u043d\u043e\u043c\u0443<\/strong>.<\/p>\n<p>\u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0442\u0435\u0431\u0435 \u043c\u043e\u0433\u0443\u0442 \u0441\u043a\u0430\u0437\u0430\u0442\u044c, \u0447\u0442\u043e \u0438\u043d\u0444\u0435\u0440\u0435\u043d\u0441 \u043c\u043e\u0434\u0435\u043b\u0438 <em>\u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e<\/em> \u043d\u0443\u0436\u043d\u043e \u0434\u0435\u043b\u0430\u0442\u044c \u043d\u0430 GPU. \u041d\u043e \u044d\u0442\u043e \u043d\u0435 \u0432\u0441\u0435\u0433\u0434\u0430 \u0442\u0430\u043a: <strong>\u043d\u0430 CPU \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u043e\u0449\u0435 \u0438 \u0434\u0435\u0448\u0435\u0432\u043b\u0435 \u0432\u044b\u0440\u0430\u0441\u0442\u0438 \u0433\u043e\u0440\u0438\u0437\u043e\u043d\u0442\u0430\u043b\u044c\u043d\u043e<\/strong>.<\/p>\n<p>\u0418\u043b\u0438 \u0432\u043e\u0442 \u0435\u0449\u0451 \u043f\u0440\u0438\u043c\u0435\u0440: \u043d\u0435 \u0432\u0441\u0435\u0433\u0434\u0430 \u043d\u0443\u0436\u0435\u043d \u0438\u043d\u0434\u0435\u043a\u0441 \u043f\u043e \u0431\u0430\u0437\u0435 \u0442\u043e\u0432\u0430\u0440\u043e\u0432. \u0418\u043d\u043e\u0433\u0434\u0430 <strong>\u043f\u0440\u044f\u043c\u043e\u0439 \u043f\u0440\u043e\u0445\u043e\u0434 \u043f\u043e \u0432\u0441\u0435\u043c \u0442\u043e\u0432\u0430\u0440\u0430\u043c \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043d\u0435 \u0445\u0443\u0436\u0435<\/strong>, \u0430 \u043f\u0440\u043e\u0431\u043b\u0435\u043c \u0441 \u043f\u0435\u0440\u0435\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u0435\u043c \u0438 \u043b\u0438\u0448\u043d\u0438\u043c \u043a\u043e\u0434\u043e\u043c \u2014 \u043c\u0435\u043d\u044c\u0448\u0435.<\/p>\n<p>\u0418\u043c\u0435\u043d\u043d\u043e \u043f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0435\u0433\u043e \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u2014 \u043f\u043e\u0434 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f\u043c\u0438, \u0441 \u0444\u0438\u0434\u0431\u0435\u043a\u043e\u043c \u0438 \u043e\u0448\u0438\u0431\u043a\u0430\u043c\u0438 \u2014 <strong>\u0432\u044b\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0438\u043d\u0442\u0443\u0438\u0446\u0438\u044f<\/strong>, \u0447\u0442\u043e, \u0433\u0434\u0435 \u0438 \u043a\u043e\u0433\u0434\u0430 \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0442\u044c.<br \/> \u0422\u0430 \u0441\u0430\u043c\u0430\u044f \u0438\u043d\u0436\u0435\u043d\u0435\u0440\u043d\u0430\u044f \u0447\u0443\u0439\u043a\u0430 \u2014 \u043e\u043d\u0430 \u043d\u0435 \u0438\u0437 \u043a\u043d\u0438\u0436\u0435\u043a. \u041e\u043d\u0430 \u0438\u0437 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0438.<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>\ud83e\udd28 \u041d\u0430 \u0441\u043a\u043e\u0440\u044e \u0440\u0443\u043a\u0443 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442\u0441\u044f \u043f\u043b\u043e\u0445\u043e\u0439 \u043a\u043e\u0434. \u041a\u0430\u043a \u044d\u0442\u043e\u0442 \u043d\u0430\u0432\u044b\u043a \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u043c\u043d\u0435 \u0432 \u0440\u0430\u0431\u043e\u0442\u0435?<\/summary>\n<div class=\"spoiler__content\">\n<p>\u041d\u0430 \u0441\u0430\u043c\u043e\u043c \u0434\u0435\u043b\u0435 \u2014 \u0441\u043a\u043e\u0440\u0435\u0435 \u043d\u0430\u043e\u0431\u043e\u0440\u043e\u0442. \u0421 \u043a\u0430\u0436\u0434\u044b\u043c \u0437\u0430\u0432\u0435\u0440\u0448\u0451\u043d\u043d\u044b\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u043c, \u0441 \u043a\u0430\u0436\u0434\u044b\u043c \u043d\u0435\u0432\u0435\u0440\u043d\u044b\u043c \u0440\u0435\u0448\u0435\u043d\u0438\u0435\u043c \u0442\u044b \u043e\u0442\u0431\u0440\u0430\u0441\u044b\u0432\u0430\u0435\u0448\u044c \u043b\u0438\u0448\u043d\u0435\u0435 \u0438 \u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0448\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0443\u0436\u043d\u043e\u0435. \u0422\u044b \u0443\u0436\u0435 \u0437\u043d\u0430\u0435\u0448\u044c, \u0447\u0442\u043e \u0442\u0443\u0442 \u0441\u0440\u0435\u0437\u0430\u043b \u0438 \u043f\u0438\u0441\u0430\u043b \u043d\u0435\u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u043a\u043e\u0434 \u0438 \u043f\u043e\u0442\u043e\u043c \u0441\u043f\u043e\u0442\u044b\u043a\u0430\u043b\u0441\u044f \u0438 \u0442\u0443\u0442 \u0442\u0435\u043f\u0435\u0440\u044c  \u043f\u0440\u043e\u0441\u0442\u043e \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u0435\u0439 \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e!<br \/> \u0425\u043e\u0447\u0435\u0448\u044c \u043d\u0435 \u0445\u043e\u0447\u0435\u0448\u044c \u2014 <strong>\u0441\u0440\u0435\u0434\u043d\u0435\u0435 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u043e \u0442\u0432\u043e\u0435\u0433\u043e \u043a\u043e\u0434\u0430 \u043c\u043e\u043d\u043e\u0442\u043e\u043d\u043d\u043e \u0440\u0430\u0441\u0442\u0451\u0442<\/strong>.<\/p>\n<p>\u042d\u0442\u043e \u043a\u0430\u0441\u0430\u0435\u0442\u0441\u044f \u0438 \u0441\u0430\u043c\u043e\u0433\u043e \u043a\u043e\u0434\u0430: \u0441\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0435\u043c \u0442\u044b \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0448\u044c \u043f\u0438\u0441\u0430\u0442\u044c \u00ab\u0440\u0443\u043a\u043e\u0439 \u043d\u0430\u0431\u0438\u0442\u043e\u0439\u00bb \u2014 \u043d\u0435 \u0433\u0430\u0434\u0430\u0435\u0448\u044c, \u043d\u043e\u0440\u043c \u0438\u043b\u0438 \u043d\u0435 \u043d\u043e\u0440\u043c, \u0442\u044b \u043f\u0440\u043e\u0441\u0442\u043e \u0437\u043d\u0430\u0435\u0448\u044c.<br \/> \u0418 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b: \u043f\u043e\u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0438\u043d\u0442\u0443\u0438\u0446\u0438\u044f, <strong>\u0447\u0442\u043e \u0437\u0430\u043b\u043e\u0436\u0438\u0442\u044c \u0441\u0435\u0439\u0447\u0430\u0441<\/strong>, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u0442\u043e\u043c \u043d\u0435 \u0441\u043e\u0435\u0434\u0438\u043d\u044f\u0442\u044c \u0432\u0441\u0451 \u043a\u043e\u0441\u0442\u044b\u043b\u044f\u043c\u0438.<\/p>\n<hr\/>\n<p>\u0412\u0434\u0440\u0443\u0433 \u0432\u044b \u0443\u0432\u0438\u0434\u0435\u043b\u0438 \u043a\u043e\u0441\u0442\u044b\u043b\u044c. \u0416\u0451\u0441\u0442\u043a\u0438\u0439, \u0441\u0442\u0440\u0430\u043d\u043d\u044b\u0439, \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u0447\u043d\u044b\u0439. \u042d\u0442\u043e \u043f\u043b\u043e\u0445\u043e\u0439 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0441\u0442?<br \/> \u042f \u0431\u044b \u043d\u0435 \u0441\u043f\u0435\u0448\u0438\u043b \u043a\u0438\u0434\u0430\u0442\u044c\u0441\u044f \u043f\u043e\u043c\u0438\u0434\u043e\u0440\u0430\u043c\u0438.<\/p>\n<p>\u0421\u0434\u0435\u043b\u0430\u0442\u044c \u0441\u0438\u0441\u0442\u0435\u043c\u0443, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043e\u0445\u0432\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u0434\u0435\u0441\u044f\u0442\u043a\u0438 \u0430\u0441\u043f\u0435\u043a\u0442\u043e\u0432 \u2014 \u0441\u043b\u043e\u0436\u043d\u043e, \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e \u0432 \u043e\u0434\u0438\u043d\u043e\u0447\u043a\u0443.<br \/> \u0415\u0441\u043b\u0438 \u0447\u0435\u043b\u043e\u0432\u0435\u043a \u0432 \u043a\u0430\u0436\u0434\u043e\u043c \u0448\u0430\u0433\u0435 \u043f\u0438\u0448\u0435\u0442 \u043a\u043e\u0441\u0442\u044b\u043b\u0438 \u0438 \u043d\u0435 \u043f\u043e\u043d\u0438\u043c\u0430\u0435\u0442, \u0447\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u0442 \u2014 \u0441\u043a\u043e\u0440\u0435\u0435 \u0432\u0441\u0435\u0433\u043e, \u043e\u043d \u043f\u0440\u043e\u0441\u0442\u043e, \u0441\u043a\u043e\u0440\u0435\u0435 \u0432\u0441\u0435\u0433\u043e, \u043d\u0435 \u0434\u043e\u0439\u0434\u0451\u0442 \u0434\u043e \u0444\u0438\u043d\u0430\u043b\u0430.<br \/> \u041e\u043d \u0441\u043f\u043e\u0442\u043a\u043d\u0451\u0442\u0441\u044f \u043d\u0430 \u043a\u0430\u043a\u043e\u043c-\u043d\u0438\u0431\u0443\u0434\u044c <code>gpt<\/code>-\u0437\u0430\u043f\u0440\u043e\u0441\u0435, \u043d\u0435 \u0441\u043c\u043e\u0436\u0435\u0442 \u0440\u0430\u0437\u0433\u0440\u0435\u0441\u0442\u0438 \u0431\u0430\u0433 \u2014 \u0438 \u0432\u0441\u0451 \u0437\u0430\u043a\u043e\u043d\u0447\u0438\u0442\u0441\u044f.<\/p>\n<p>\u041d\u043e \u0435\u0441\u043b\u0438 \u043f\u0440\u043e\u0434\u0443\u043a\u0442 <strong>\u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442<\/strong>, \u0440\u0435\u0448\u0430\u0435\u0442 \u0437\u0430\u0434\u0430\u0447\u0443, \u0438 \u0432 \u043d\u0451\u043c <strong>\u0436\u0451\u0441\u0442\u043a\u0438\u0435, \u043d\u043e \u0442\u043e\u0447\u0435\u0447\u043d\u044b\u0435 \u043a\u043e\u0441\u0442\u044b\u043b\u0438<\/strong> \u2014 \u0441\u043a\u043e\u0440\u0435\u0435 \u0432\u0441\u0435\u0433\u043e, \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0441\u0442 <strong>\u0441\u0434\u0435\u043b\u0430\u043b \u044d\u0442\u043e \u043e\u0441\u043e\u0437\u043d\u0430\u043d\u043d\u043e<\/strong>. \u0427\u0442\u043e\u0431\u044b <strong>\u043f\u043e\u0431\u044b\u0441\u0442\u0440\u0435\u0435 \u0441\u043e\u0431\u0440\u0430\u0442\u044c MVP<\/strong>.<br \/> \u0418, \u0432\u043f\u043e\u043b\u043d\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u043e\u043d <strong>\u0443\u0436\u0435 \u0434\u0435\u0440\u0436\u0438\u0442 \u0432 \u0433\u043e\u043b\u043e\u0432\u0435, \u043a\u0430\u043a \u044d\u0442\u043e \u043f\u043e\u0442\u043e\u043c \u0438\u0441\u043f\u0440\u0430\u0432\u0438\u0442\u044c<\/strong>.<\/p>\n<p>\ud83d\udca1 \u041d\u0430\u0441\u0442\u043e\u044f\u0449\u0438\u0439 \u043d\u0430\u0432\u044b\u043a \u2014 \u044d\u0442\u043e \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u044c \u0442\u0440\u0435\u0439\u0434-\u043e\u0444\u0444:<br \/> \u043c\u0435\u0436\u0434\u0443 &#171;\u043a\u0440\u0430\u0441\u0438\u0432\u043e\u0439 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u043e\u0439&#187; \u0438 &#171;\u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0438\u043c, \u043f\u043e\u043d\u044f\u0442\u043d\u044b\u043c, \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u043c\u044b\u043c \u043a\u043e\u0434\u043e\u043c&#187;.<\/p>\n<p>\u041f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u0438\u043d\u0430\u0447\u0435 \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c\u0441\u044f \u0432\u043e\u0442 \u044d\u0442\u043e:  <a href=\"https:\/\/www.youtube.com\/watch?v=gq6ZAuUQq9M&amp;list=LL&amp;index=3&amp;t=1749s\" rel=\"noopener noreferrer nofollow\">\u043f\u0440\u0438\u043c\u0435\u0440, \u043a\u0430\u043a \u0430\u0432\u0442\u043e\u0440 \u043a\u043d\u0438\u0433\u0438 \u043f\u043e \u0447\u0438\u0441\u0442\u043e\u043c\u0443 \u043a\u043e\u0434\u0443 \u043d\u0430\u043f\u0438\u0441\u0430\u043b Android-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043f\u0430\u0434\u0430\u0435\u0442 \u043d\u0430 \u043f\u0435\u0440\u0432\u043e\u043c \u044e\u0437\u043a\u0435\u0439\u0441\u0435<\/a><\/p>\n<\/div>\n<\/details>\n<p>\u041f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u043c \u043a \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438!<\/p>\n<hr\/>\n<h3>\u041f\u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0437\u0430\u0434\u0430\u0447\u0438<\/h3>\n<p>\u041d\u0443\u0436\u043d\u043e \u0441\u043e\u0431\u0440\u0430\u0442\u044c MVP-\u0441\u0435\u0440\u0432\u0438\u0441 \u0441 \u043d\u0430\u0448\u0435\u0439 \u043e\u0431\u0443\u0447\u0435\u043d\u043d\u043e\u0439 \u043c\u043e\u0434\u0435\u043b\u044c\u044e \u0434\u043b\u044f \u043f\u043e\u0438\u0441\u043a\u0430 \u0442\u043e\u0432\u0430\u0440\u043e\u0432 \u043f\u043e \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u043e\u043c\u0443 \u0437\u0430\u043f\u0440\u043e\u0441\u0443 (<a href=\"https:\/\/huggingface.co\/datasets?search=product+search\" rel=\"noopener noreferrer nofollow\">E-commerce Product Search<\/a>), \u043e\u0431\u0449\u0438\u0439 \u0432\u0438\u0434 \u0437\u0430\u0434\u0430\u0447\u0438 &#8212; <a href=\"https:\/\/en.wikipedia.org\/wiki\/Information_retrieval\" rel=\"noopener noreferrer nofollow\">IR (Information retrieval )<\/a>. \u0426\u0435\u043b\u044c \u2014 \u043d\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u0441\u043e\u0432\u043f\u0430\u0434\u0435\u043d\u0438\u0435 \u043f\u043e \u0441\u043b\u043e\u0432\u0430\u043c, \u0430 \u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u0435 e-com \u0438\u043d\u0442\u0435\u043d\u0442\u0430 \u0437\u0430\u043f\u0440\u043e\u0441\u0430. \u041f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e:<\/p>\n<ul>\n<li>\n<p>\u041d\u0430\u0437\u0432\u0430\u043d\u0438\u044f \u0442\u043e\u0432\u0430\u0440\u043e\u0432 \u0447\u0430\u0441\u0442\u043e \u043d\u0435 \u0433\u043e\u0432\u043e\u0440\u044f\u0442 \u043f\u0440\u044f\u043c\u043e, \u0447\u0442\u043e \u0437\u0430 \u043f\u0440\u043e\u0434\u0443\u043a\u0442 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0435\u0441\u043b\u0438 \u043f\u0440\u043e\u0434\u0430\u0435\u0442\u0441\u044f \u043a\u043d\u0438\u0433\u0430 &#8212; \u043d\u0435 \u0432\u0441\u0435\u0433\u0434\u0430 \u0435\u0441\u0442\u044c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u0432 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0438 \u043e\u0431 \u044d\u0442\u043e\u043c)<\/p>\n<\/li>\n<li>\n<p>\u0424\u043e\u0440\u043c\u0443\u043b\u0438\u0440\u043e\u0432\u043a\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u043d\u0435\u0441\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u044b \u0438 \u0441\u0443\u0431\u044a\u0435\u043a\u0442\u0438\u0432\u043d\u044b<\/p>\n<\/li>\n<li>\n<p>\u0420\u0435\u043b\u0435\u0432\u0430\u043d\u0442\u043d\u043e\u0441\u0442\u044c \u2014 \u043d\u0435 \u0431\u0438\u043d\u0430\u0440\u043d\u0430\u044f, \u0435\u0441\u0442\u044c \u00ab\u043f\u043e\u0447\u0442\u0438 \u0442\u043e\u00bb \u0438 \u00ab\u0432\u043e\u043e\u0431\u0449\u0435 \u043c\u0438\u043c\u043e\u00bb<\/p>\n<\/li>\n<li>\n<p>\u041e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u043e\u0435 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0442\u043e\u0432\u0430\u0440\u043e\u0432 \u043d\u0435 \u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442 \u0438\u0445 \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u0443\u044e \u0440\u0435\u043b\u0435\u0432\u0430\u043d\u0442\u043d\u043e\u0441\u0442\u044c<\/p>\n<\/li>\n<\/ul>\n<blockquote>\n<p>\u041a\u043e\u0440\u043e\u0442\u043a\u043e \u043e\u043f\u0438\u0448\u0435\u043c \u0440\u0435\u0448\u0435\u043d\u0438\u0435: \u0431\u0443\u0434\u0435\u043c \u0434\u043e\u043e\u0431\u0443\u0447\u0430\u0442\u044c <a href=\"https:\/\/www.microsoft.com\/en-us\/research\/wp-content\/uploads\/2016\/02\/cikm2013_DSSM_fullversion.pdf\" rel=\"noopener noreferrer nofollow\">DSSM<\/a> (\u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0435\u0434\u0438\u043d\u043e\u0439 \u043e\u0434\u043d\u043e\u0439 \u0431\u0430\u0448\u043d\u0438 \u0438 \u0441\u0442\u0430\u0440\u0442\u043e\u0432\u043e\u0439 \u0442\u043e\u0447\u043a\u0438 \u0432\u043e\u0437\u044c\u043c\u0435\u043c <a href=\"https:\/\/huggingface.co\/intfloat\/multilingual-e5-small\" rel=\"noopener noreferrer nofollow\">pretrain E5<\/a>) \u043d\u0430 <a href=\"https:\/\/huggingface.co\/datasets\/tasksource\/esci\" rel=\"noopener noreferrer nofollow\">\u0434\u0430\u043d\u043d\u044b\u0445 \u043e\u0442 Amazon<\/a>. Web \u0441\u0435\u0440\u0432\u0438\u0441 \u0441 \u043e\u0442\u043b\u0430\u0434\u043e\u0447\u043d\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0435\u0439 \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u043d\u0430 <a href=\"https:\/\/streamlit.io\/\" rel=\"noopener noreferrer nofollow\">Streamlit<\/a>.<\/p>\n<\/blockquote>\n<h3>\u0414\u0430\u0442\u0430\u0441\u0435\u0442: Amazon ESCI<\/h3>\n<p>\u0411\u0435\u0440\u0451\u043c \u0434\u0430\u0442\u0430\u0441\u0435\u0442 <a href=\"https:\/\/huggingface.co\/datasets\/tasksource\/esci\" rel=\"noopener noreferrer nofollow\">Amazon ESCI<\/a> \u0441 HuggingFace. \u041e\u043d \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0438 \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0435 \u0441 \u043d\u0438\u043c\u0438 \u0442\u043e\u0432\u0430\u0440\u044b, \u0440\u0430\u0437\u043c\u0435\u0447\u0435\u043d\u043d\u044b\u0435 \u043f\u043e \u0441\u0442\u0435\u043f\u0435\u043d\u0438 \u0440\u0435\u043b\u0435\u0432\u0430\u043d\u0442\u043d\u043e\u0441\u0442\u0438: <code>exact<\/code>, <code>substitute<\/code>, <code>irrelevant<\/code>.<\/p>\n<p>\u041f\u043e\u0447\u0435\u043c\u0443 \u043e\u043d \u0445\u043e\u0440\u043e\u0448:<\/p>\n<ul>\n<li>\n<p>\u0414\u0430\u043d\u043d\u044b\u0435 \u0438\u0437 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u0433\u043e e-commerce \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0430,<\/p>\n<\/li>\n<li>\n<p>\u041c\u043d\u043e\u0433\u043e \u0448\u0443\u043c\u0430 \u2014 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044f \u0442\u043e\u0432\u0430\u0440\u043e\u0432 \u043d\u0435\u043f\u043e\u043b\u043d\u044b\u0435 \u0438\u043b\u0438 \u043e\u0431\u043e\u0431\u0449\u0451\u043d\u043d\u044b\u0435,<\/p>\n<\/li>\n<li>\n<p>\u0417\u0430\u043f\u0440\u043e\u0441\u044b \u0440\u0430\u0437\u043d\u043e\u043f\u043b\u0430\u043d\u043e\u0432\u044b\u0435: \u043e\u0442 \u0442\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u0434\u043e \u0431\u044b\u0442\u043e\u0432\u044b\u0445,<\/p>\n<\/li>\n<li>\n<p>\u0420\u0435\u043b\u0435\u0432\u0430\u043d\u0442\u043d\u043e\u0441\u0442\u044c \u0440\u0430\u0437\u043c\u0435\u0447\u0435\u043d\u0430 \u0432\u0440\u0443\u0447\u043d\u0443\u044e.<\/p>\n<\/li>\n<\/ul>\n<p>\u041f\u043e\u0434\u0445\u043e\u0434\u0438\u0442 \u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0430 \u043f\u043e\u0438\u0441\u043a\u0430 \u0438 \u0434\u043e\u043e\u0431\u0443\u0447\u0435\u043d\u0438\u044f \u043c\u043e\u0434\u0435\u043b\u0435\u0439.<\/p>\n<details class=\"spoiler\">\n<summary>\u041f\u0440\u0438\u043c\u0435\u0440 \u0434\u0430\u043d\u043d\u044b\u0445<\/summary>\n<div class=\"spoiler__content\">\n<p>\u041a\u0430\u0436\u0434\u0430\u044f \u0441\u0442\u0440\u043e\u043a\u0430 \u0432 \u0434\u0430\u0442\u0430\u0441\u0435\u0442\u0435 \u2014 \u044d\u0442\u043e \u0442\u0440\u043e\u0439\u043a\u0430: <strong>\u0437\u0430\u043f\u0440\u043e\u0441 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f<\/strong>, <strong>\u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0442\u043e\u0432\u0430\u0440\u0430<\/strong>, \u0438 <strong>\u043e\u0446\u0435\u043d\u043a\u0430 \u0440\u0435\u043b\u0435\u0432\u0430\u043d\u0442\u043d\u043e\u0441\u0442\u0438<\/strong>.<\/p>\n<pre><code class=\"json\">{   \"query\": \"usb c charger for iphone\",   \"product_title\": \"USB C Charger, 20W PD Wall Charger Block Compatible with iPhone 13 12 11\",   \"product_description\": \"...\",   \"product_id\": \"B08K2S1NP5\",   \"query_id\": \"A1\",   \"product_locale\": \"us\",   \"esci_label\": \"exact\" } <\/code><\/pre>\n<p>\u0412\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f <code>esci_label<\/code>:<\/p>\n<ul>\n<li>\n<p><code>exact<\/code> \u2014 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441\u0443,<\/p>\n<\/li>\n<li>\n<p><code>substitute<\/code> \u2014 \u0431\u043b\u0438\u0437\u043a\u0438\u0439 \u0430\u043d\u0430\u043b\u043e\u0433, \u043d\u043e \u043d\u0435 \u0442\u043e\u0447\u043d\u043e\u0435 \u0441\u043e\u0432\u043f\u0430\u0434\u0435\u043d\u0438\u0435,<\/p>\n<\/li>\n<li>\n<p><code>complement<\/code> \u2014 \u0441\u043e\u043f\u0443\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 \u0442\u043e\u0432\u0430\u0440 (\u0442\u043e\u043b\u044c\u043a\u043e \u0432 \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u0439 \u0432\u044b\u0431\u043e\u0440\u043a\u0435),<\/p>\n<\/li>\n<li>\n<p><code>irrelevant<\/code> \u2014 \u043d\u0435 \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u0442.<\/p>\n<\/li>\n<\/ul>\n<p>\u0412 \u0442\u0440\u0435\u043d\u0438\u0440\u043e\u0432\u043e\u0447\u043d\u043e\u0439 \u0432\u044b\u0431\u043e\u0440\u043a\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e: <code>exact<\/code>, <code>substitute<\/code>, <code>irrelevant<\/code>.<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>\u0418\u0441\u0442\u043e\u0440\u0438\u044f \u0432\u043e\u0437\u043d\u0438\u043a\u043d\u043e\u0432\u0435\u043d\u0438\u044f \u0434\u0430\u0442\u0430\u0441\u0435\u0442\u0430<\/summary>\n<div class=\"spoiler__content\">\n<ul>\n<li>\n<p>\u041e\u043d \u0431\u044b\u043b \u0441\u043e\u0437\u0434\u0430\u043d \u0434\u043b\u044f <strong>KDD Cup 2022 \/ Amazon Shopping Queries Challenge<\/strong>, \u0446\u0435\u043b\u044c \u2014 \u0443\u043b\u0443\u0447\u0448\u0438\u0442\u044c \u043f\u043e\u0438\u0441\u043a \u0442\u043e\u0432\u0430\u0440\u043e\u0432 \u0432 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u0439 e\u2011commerce \u0441\u0440\u0435\u0434\u0435.<\/p>\n<\/li>\n<li>\n<p>\u041e\u0445\u0432\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043d\u0430 \u0442\u0440\u0451\u0445 \u044f\u0437\u044b\u043a\u0430\u0445 \u2014 <strong>\u0430\u043d\u0433\u043b\u0438\u0439\u0441\u043a\u0438\u0439, \u044f\u043f\u043e\u043d\u0441\u043a\u0438\u0439 \u0438 \u0438\u0441\u043f\u0430\u043d\u0441\u043a\u0438\u0439<\/strong>.<\/p>\n<\/li>\n<li>\n<p>\u041a\u0430\u0436\u0434\u044b\u0439 \u0437\u0430\u043f\u0440\u043e\u0441 \u0438\u043c\u0435\u0435\u0442 \u0434\u043e 40 \u0442\u043e\u0432\u0430\u0440\u043e\u0432 \u0441 \u0440\u0443\u0447\u043d\u043e\u0439 \u0440\u0430\u0437\u043c\u0435\u0442\u043a\u043e\u0439: <em>Exact<\/em>, <em>Substitute<\/em>, <em>Complement<\/em>, <em>Irrelevant<\/em>.<\/p>\n<\/li>\n<li>\n<p>\u0412\u0441\u0435\u0433\u043e ~130\u202f000 \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0438 \u2248\u202f2.6\u202f\u043c\u043b\u043d \u043f\u043e\u043c\u0435\u0447\u0435\u043d\u043d\u044b\u0445 \u043f\u0430\u0440 (query, product) \u0434\u043b\u044f \u043f\u043e\u043b\u043d\u043e\u0433\u043e \u0434\u0430\u0442\u0430\u0441\u0435\u0442\u0430, \u0432 \u0443\u043c\u0435\u043d\u044c\u0448\u0435\u043d\u043d\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u2014 ~48\u202f000 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0438 ~1.1\u202f\u043c\u043b\u043d \u043f\u0430\u0440. \u041f\u0440\u0438\u043c\u0435\u0440 \u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u0438 \u2014 \u044d\u0442\u043e \u043e\u0442\u0440\u0430\u0436\u0435\u043d\u043e \u0432 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0438 <a href=\"https:\/\/github.com\/amazon-science\/esci-data\" rel=\"noopener noreferrer nofollow\">\u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f Amazon ESCI \u043d\u0430 GitHub<\/a>.<\/p>\n<\/li>\n<\/ul>\n<blockquote>\n<p>\ud83d\udd0d \u0420\u0435\u043b\u0435\u0432\u0430\u043d\u0442\u043d\u043e\u0441\u0442\u044c \u0440\u0430\u0437\u043c\u0435\u0447\u0435\u043d\u0430 \u043d\u0435 \u043f\u043e \u043d\u0430\u043b\u0438\u0447\u0438\u044e \u043a\u043b\u044e\u0447\u0435\u0432\u044b\u0445 \u0441\u043b\u043e\u0432, \u0430 \u043f\u043e \u0444\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u043c\u0443 \u0441\u043c\u044b\u0441\u043b\u0443 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0438 \u0442\u043e\u0432\u0430\u0440\u0430, \u0447\u0442\u043e \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u0440\u0435\u0430\u043b\u0438\u0441\u0442\u0438\u0447\u043d\u044b\u0439 \u00ab\u0448\u0443\u043c\u00bb: \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0447\u0430\u0441\u0442\u043e \u043d\u0435\u043f\u043e\u043b\u043d\u044b\u0435, \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u043c\u0430\u0440\u043a\u0435\u0442\u0438\u043d\u0433\u043e\u0432\u044b\u043c\u0438, \u0435\u0441\u0442\u044c \u0441\u0438\u043d\u043e\u043d\u0438\u043c\u044b, \u043e\u0431\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0438 \u043f\u0440.<\/p>\n<\/blockquote>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>\u041f\u0440\u043e\u0441\u0442\u0435\u043d\u044c\u043a\u0438\u0439 EDA (\u0440\u0430\u0437\u0432\u0435\u0434\u043e\u0447\u043d\u044b\u0439 \u0430\u043d\u0430\u043b\u0438\u0437)<\/summary>\n<div class=\"spoiler__content\">\n<p>\u041a\u0430\u0447\u0430\u0435\u043c \u0434\u0430\u0442\u0430\u0441\u0435\u0442<\/p>\n<pre><code class=\"python\">from datasets import load_dataset # https:\/\/huggingface.co\/datasets\/tasksource\/esci # \u0417\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c \u0442\u0440\u0435\u043d\u0438\u0440\u043e\u0432\u043e\u0447\u043d\u0443\u044e \u0447\u0430\u0441\u0442\u044c dataset = load_dataset(\"tasksource\/esci\", split=\"train\") <\/code><\/pre>\n<p>\u0421\u043c\u043e\u0442\u0440\u0438\u043c \u043d\u0430 \u0438\u043c\u0435\u044e\u0449\u0438\u0435\u0441\u044f \u043f\u043e\u043b\u044f<\/p>\n<pre><code class=\"python\">import pandas as pd df = dataset.to_pandas() # \u0421\u043c\u043e\u0442\u0440\u0438\u043c \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043f\u043e\u043b\u044f print(df.columns) # \u041f\u0440\u0438\u043c\u0435\u0440 \u0441\u0442\u0440\u043e\u043a\u0438 print(df[['query', 'product_title', 'esci_label']].sample(5)) # \u0420\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u043f\u043e \u043c\u0435\u0442\u043a\u0430\u043c print(\"\u041c\u0435\u0442\u043a\u0438 \u0440\u0435\u043b\u0435\u0432\u0430\u043d\u0442\u043d\u043e\u0441\u0442\u0438:\") print(df['esci_label'].value_counts()) # \u0420\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u043f\u043e \u044f\u0437\u044b\u043a\u0443 print(\"\u041b\u043e\u043a\u0430\u043b\u0438:\")  print(df['product_locale'].value_counts()) <\/code><\/pre>\n<p>\u0420\u0438\u0441\u0443\u0435\u043c \u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u0434\u043b\u0438\u043d\u043d \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432\/\u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0439 \u0442\u043e\u0432\u0430\u0440\u043e\u0432\/\u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0439<\/p>\n<pre><code class=\"python\"># \u0420\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u0434\u043b\u0438\u043d df['query_len'] = df['query'].str.split().str.len() df['title_len'] = df['product_title'].str.split().str.len() df['desc_len'] = df['product_description'].str.split().str.len() df[['query_len', 'title_len', 'desc_len']].hist(bins=30, figsize=(12, 4)) <\/code><\/pre>\n<figure class=\"\"><\/figure>\n<p>\u0421\u0440\u0435\u0434\u043d\u0435\u0435 \u0447\u0438\u0441\u043b\u043e \u0440\u0435\u043b\u0435\u0432\u0430\u043d\u0442\u043d\u044b\u0445 \u0442\u043e\u0432\u0430\u0440\u043e\u0432 \u043d\u0430 \u0437\u0430\u043f\u0440\u043e\u0441<\/p>\n<pre><code class=\"python\">import matplotlib.pyplot as plt  # \u041e\u0441\u0442\u0430\u0432\u0438\u043c \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u0437\u0438\u0442\u0438\u0432\u043d\u044b\u0435 \u043f\u0440\u0438\u043c\u0435\u0440\u044b positive_df = df[df['esci_label'].isin(['Exact', 'Substitute'])]  # \u0421\u0447\u0438\u0442\u0430\u0435\u043c \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0440\u0435\u043b\u0435\u0432\u0430\u043d\u0442\u043d\u044b\u0445 \u0442\u043e\u0432\u0430\u0440\u043e\u0432 \u043d\u0430 \u043a\u0430\u0436\u0434\u044b\u0439 \u0437\u0430\u043f\u0440\u043e\u0441 relevant_counts = positive_df.groupby('query')['product_id'].nunique()  # \u0421\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u0430 print(\"\ud83d\udcca \u0421\u0440\u0435\u0434\u043d\u0435\u0435 \u0447\u0438\u0441\u043b\u043e \u0440\u0435\u043b\u0435\u0432\u0430\u043d\u0442\u043d\u044b\u0445 \u0442\u043e\u0432\u0430\u0440\u043e\u0432 \u043d\u0430 \u0437\u0430\u043f\u0440\u043e\u0441:\", relevant_counts.mean()) print(\"\ud83d\udd22 \u0420\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 (\u0432\u043a\u043b\u044e\u0447\u0430\u044f \u0442\u043e\u043f-10):\") print(relevant_counts.value_counts().head(10))  # \u0413\u0438\u0441\u0442\u043e\u0433\u0440\u0430\u043c\u043c\u0430 plt.figure(figsize=(10, 4)) relevant_counts.hist(bins=60) plt.title(\"\u0420\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u0440\u0435\u043b\u0435\u0432\u0430\u043d\u0442\u043d\u044b\u0445 \u0442\u043e\u0432\u0430\u0440\u043e\u0432 \u043d\u0430 \u0437\u0430\u043f\u0440\u043e\u0441\") plt.xlabel(\"\u041a\u043e\u043b-\u0432\u043e \u0440\u0435\u043b\u0435\u0432\u0430\u043d\u0442\u043d\u044b\u0445 \u0442\u043e\u0432\u0430\u0440\u043e\u0432\") plt.ylabel(\"\u0427\u0430\u0441\u0442\u043e\u0442\u0430\") plt.grid(True) plt.show() <\/code><\/pre>\n<figure class=\"\"><\/figure>\n<p>\u0434\u0430\u043b\u0435\u0435 <a href=\"https:\/\/github.com\/naumtsevalex\/All-about-ML\/blob\/main\/02_query2product_e5_mvp_service\/EDA_plus_baseline.ipynb\" rel=\"noopener noreferrer nofollow\">\u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u0432 \u0442\u0435\u0442\u0440\u0430\u0434\u043a\u0435<\/a>&#8230;<\/p>\n<\/div>\n<\/details>\n<h3>\u041a\u0430\u043a \u043e\u0446\u0435\u043d\u0438\u0432\u0430\u0435\u043c \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u043e?<\/h3>\n<p>\u0414\u0430\u0442\u0430\u0441\u0435\u0442 \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437 \u0441\u0442\u0440\u043e\u0447\u0435\u043a <code>(query, pos, neg)<\/code> \u0438 \u0432 \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0438\u043c \u0440\u0430\u0437\u043e\u0431\u044c\u0435\u0442\u0441\u044f \u043f\u043e \u0431\u0430\u0442\u0447\u0430\u043c. \u0414\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u043f\u043e\u0437\u0438\u0442\u0438\u0432\u0430 \u0431\u0435\u0440\u0435\u043c \u0432\u0441\u0435 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 <code>pos<\/code> \u0438 <code>neg<\/code> \u0438\u0437 \u0431\u0430\u0442\u0447\u0430 \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043d\u0435\u0433\u0430\u0442\u0438\u0432\u043d\u044b\u0445 \u043f\u0440\u0438\u043c\u0435\u0440\u043e\u0432.<\/p>\n<p>\u0421\u0447\u0438\u0442\u0430\u0435\u043c <strong>Recall@K<\/strong> \u2014 \u0438\u0449\u0435\u043c, \u043f\u043e\u043f\u0430\u043b \u043b\u0438 <code>pos<\/code> \u0432 \u0442\u043e\u043f-K \u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u0430\u043d\u0438\u044f \u043c\u043e\u0434\u0435\u043b\u0438 (\u0435\u0441\u043b\u0438 \u0434\u0430 \u043c\u0435\u0442\u0440\u0438\u043a\u0430 \u0440\u0430\u0432\u043d\u0430 <code>1<\/code>, \u0438\u043d\u0430\u0447\u0435 <code>0<\/code>) \u0438 \u0443\u0441\u0440\u0435\u0434\u043d\u044f\u0435\u043c \u043f\u043e \u0431\u0430\u0442\u0447\u0443.<\/p>\n<h3>BM25 \u043a\u0430\u043a \u0431\u0435\u0439\u0437\u043b\u0430\u0439\u043d<\/h3>\n<p><a href=\"https:\/\/en.wikipedia.org\/wiki\/Okapi_BM25\" rel=\"noopener noreferrer nofollow\">BM25<\/a> \u2014 \u0440\u0430\u0437\u0432\u0438\u0442\u0438\u0435 \u0438\u0434\u0435\u0438 <a href=\"https:\/\/en.wikipedia.org\/wiki\/Tf%E2%80%93idf\" rel=\"noopener noreferrer nofollow\">TF-IDF<\/a>: \u0443\u0447\u0438\u0442\u044b\u0432\u0430\u0435\u0442, \u043d\u0430\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0441\u043b\u043e\u0432\u043e \u0432\u0430\u0436\u043d\u043e \u0432 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0435, \u043d\u043e \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043d\u043e\u0440\u043c\u0430\u043b\u0438\u0437\u0443\u0435\u0442 \u043f\u043e \u0434\u043b\u0438\u043d\u0435 \u0438 \u043b\u043e\u0433\u0430\u0440\u0438\u0444\u043c\u0438\u0447\u0435\u0441\u043a\u0438 \u0441\u0433\u043b\u0430\u0436\u0438\u0432\u0430\u0435\u0442 \u0432\u0435\u0441\u0430.<\/p>\n<p>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c <a href=\"https:\/\/pypi.org\/project\/rank-bm25\/\" rel=\"noopener noreferrer nofollow\"><code>rank_bm25<\/code><\/a> \u2014 \u0438\u043d\u0434\u0435\u043a\u0441\u0438\u0440\u0443\u0435\u043c <code>product_title<\/code>, \u0438\u0449\u0435\u043c \u043f\u043e <code>query<\/code>, \u0440\u0430\u043d\u0436\u0438\u0440\u0443\u0435\u043c \u043f\u043e \u0441\u043a\u043e\u0440\u0443.<\/p>\n<details class=\"spoiler\">\n<summary>\u0421\u0447\u0438\u0442\u0430\u0435\u043c \u0431\u0435\u0439\u0437\u043b\u0430\u0439\u043d \u043c\u0435\u0442\u0440\u0438\u043a\u0443 (\u043f\u043e\u043a\u0430 \u043f\u043e \u0432\u0441\u0435\u043c \u0442\u043e\u0432\u0430\u0440\u0430\u043c, \u043f\u043e\u0442\u043e\u043c \u0431\u0443\u0434\u0435\u043c \u043f\u043e \u0431\u0430\u0442\u0447\u0430\u043c)<\/summary>\n<div class=\"spoiler__content\">\n<p>\u0422\u043e\u043a\u0435\u043d\u0438\u0437\u0438\u0440\u0443\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u0435<\/p>\n<pre><code class=\"python\">import nltk from nltk.tokenize import word_tokenize import os  NLTK_DATA_PATH = os.path.expanduser('~\/nltk_data') os.makedirs(NLTK_DATA_PATH, exist_ok=True) nltk.download('punkt_tab', download_dir=NLTK_DATA_PATH)  nltk.data.path.append(NLTK_DATA_PATH) # \u041f\u0440\u043e\u0441\u0442\u043e\u0439 \u0442\u0435\u0441\u0442 \u2014 \u0435\u0441\u043b\u0438 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442, \u0432\u0441\u0451 \u043e\u043a print(word_tokenize(\"This is a test.\")) # ['This', 'is', 'a', 'test', '.'] <\/code><\/pre>\n<p>\u0421\u0447\u0438\u0442\u0430\u0435\u043c \u043c\u0435\u0442\u0440\u0438\u043a\u0443 \u0434\u043b\u044f BM25<\/p>\n<pre><code class=\"python\">import pandas as pd import numpy as np from nltk.tokenize import word_tokenize from rank_bm25 import BM25Okapi from tqdm import tqdm import time  # \u2014\u2014\u2014 0. \u0423\u0434\u043e\u0431\u043d\u0430\u044f \u0442\u043e\u043a\u0435\u043d\u0438\u0437\u0430\u0446\u0438\u044f \u0442\u0435\u043a\u0441\u0442\u0430 \u2014\u2014\u2014 def tokenize(text: str) -&gt; list[str]:     return word_tokenize(text.lower())  # \u2014\u2014\u2014 1. \u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430 \u043a\u043e\u0440\u043f\u0443\u0441\u0430 \u0442\u043e\u0432\u0430\u0440\u043e\u0432 \u2014\u2014\u2014 print(\"\ud83d\udce6 \u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430 \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0438 \u0442\u043e\u0432\u0430\u0440\u043e\u0432...\") start = time.perf_counter() products = df['product_title'].unique().tolist() tokenized_products = [tokenize(p) for p in tqdm(products, desc=\"\ud83e\uddfc \u0422\u043e\u043a\u0435\u043d\u0438\u0437\u0430\u0446\u0438\u044f \u0442\u043e\u0432\u0430\u0440\u043e\u0432\")] bm25 = BM25Okapi(tokenized_products) print(f\"\u2705 \u0418\u043d\u0434\u0435\u043a\u0441\u0430\u0446\u0438\u044f BM25 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0430 \u0437\u0430 {time.perf_counter() - start:.2f} \u0441\u0435\u043a\")  # \u2014\u2014\u2014 2. \u0423\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u044b\u0439 BM25 \u043f\u043e\u0438\u0441\u043a\u043e\u0432\u0438\u043a \u2014\u2014\u2014 class BM25Search:     def __init__(self, bm25_index, docs):         self.bm25 = bm25_index         self.docs = docs      def top_k(self, query: str, k: int = 10) -&gt; list[str]:         tokens = tokenize(query)         scores = self.bm25.get_scores(tokens)         top_idx = np.argsort(scores)[-k:][::-1]         return<\/code><\/pre>\n<\/div>\n<\/details>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-467792","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/467792","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=467792"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/467792\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=467792"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=467792"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=467792"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}