<?xml version="1.0" encoding="utf-8" ?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:tt="http://teletype.in/" xmlns:opensearch="http://a9.com/-/spec/opensearch/1.1/"><title>Властелин машин</title><subtitle>Всё о передовых инструментах исследования и трюках продуктивности, чтобы стать крутым аналитиком и специалистом по машинному обучению на Python.</subtitle><author><name>Властелин машин</name></author><id>https://teletype.in/atom/dt_analytic</id><link rel="self" type="application/atom+xml" href="https://teletype.in/atom/dt_analytic?offset=0"></link><link rel="alternate" type="text/html" href="https://teletype.in/@dt_analytic?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=dt_analytic"></link><link rel="next" type="application/rss+xml" href="https://teletype.in/atom/dt_analytic?offset=10"></link><link rel="search" type="application/opensearchdescription+xml" title="Teletype" href="https://teletype.in/opensearch.xml"></link><updated>2026-04-04T09:22:55.865Z</updated><entry><id>dt_analytic:lH04tbPQ_6a</id><link rel="alternate" type="text/html" href="https://teletype.in/@dt_analytic/lH04tbPQ_6a?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=dt_analytic"></link><title>Решение задач с разбиением чисел на цифры</title><published>2026-02-12T04:51:09.506Z</published><updated>2026-02-12T04:51:09.506Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img3.teletype.in/files/2d/46/2d46ba66-f872-4644-af25-76187d389b26.png"></media:thumbnail><category term="matematika" label="математика"></category><summary type="html">&lt;img src=&quot;https://img1.teletype.in/files/06/86/0686df17-fb7d-4c51-b6d8-a24cb937e09b.png&quot;&gt;Часто в задачах требуется не просто оперировать числом как целым, а разложить его на отдельные цифры — как разобрать механизм на детали. Рассмотрим простой, но эффективный подход.</summary><content type="html">
  &lt;figure id=&quot;hzod&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/06/86/0686df17-fb7d-4c51-b6d8-a24cb937e09b.png&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;0D3t&quot;&gt;Часто в задачах требуется не просто оперировать числом как целым, а разложить его на отдельные цифры — как разобрать механизм на детали. Рассмотрим простой, но эффективный подход.&lt;/p&gt;
  &lt;p id=&quot;9iQk&quot;&gt;Для этого вспомним, что мы можем подсчитать целую и остаточную части при делении на 10 (или другое число, смотря в какой системе счисления работаем). &lt;/p&gt;
  &lt;p id=&quot;T4Et&quot;&gt;Допустим, имеем задачу: &lt;/p&gt;
  &lt;p id=&quot;8gTt&quot;&gt;&amp;quot;Дано 32-битное знаковое целое число x. Верните x с перевернутыми цифрами. Если переворачивание x приводит к выходу значения за пределы диапазона 32-битных знаковых целых чисел [-2**31, 2**31 - 1], верните 0&amp;quot;&lt;/p&gt;
  &lt;p id=&quot;mMCP&quot;&gt;Ключевая часть алгоритма к решению может выглядеть так - итеративно, пока целая часть от деления на 10 не равна 0 берем дробную и добавляем к результату, умноженному на 10:&lt;/p&gt;
  &lt;pre id=&quot;yX7v&quot; data-lang=&quot;python&quot;&gt;def f(x):

    num = 2**31
    min_x = -num
    max_x = num - 1

    if x&amp;lt;0:
        sign = -1
        x = -x
    else:
        sign = 1

    res = 0

    while x!=0:
        ost = x%10
        x = x//10
        res = res*10 + ost

        if (res&amp;lt;min_x) or (res&amp;gt;max_x):
            return 0

    return res*sign

f(123)&lt;/pre&gt;
  &lt;p id=&quot;x0Qr&quot;&gt;&lt;/p&gt;
  &lt;figure id=&quot;RqIk&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/7b/94/7b94f7cb-6fd8-4282-8d5d-8b7336ae7571.png&quot; width=&quot;615&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;cWZ0&quot;&gt;Чтобы не мучиться с остатком, посчитаем знак и будем работать с положительным x. Напомню, что остаток в Python имеет знак делителя и работает правило:&lt;/p&gt;
  &lt;p id=&quot;fJBJ&quot;&gt;&lt;strong&gt;&lt;code&gt;a % b = a - b * floor(a / b)&lt;/code&gt;&lt;/strong&gt;, &lt;/p&gt;
  &lt;p id=&quot;Hriv&quot;&gt;floor(a / b) — округление вниз до ближайшего целого.&lt;/p&gt;
  &lt;p id=&quot;iTxz&quot;&gt;7%3 = 7 - 3*2=1&lt;/p&gt;
  &lt;p id=&quot;FiTN&quot;&gt;7%-3 = 7 + 3(-3) = -2&lt;/p&gt;
  &lt;p id=&quot;MMpd&quot;&gt;-7%-3 = -7 + 3*(2) = -1&lt;/p&gt;
  &lt;p id=&quot;wT79&quot;&gt;-7%3 = -7 - 3*(-3)=2&lt;/p&gt;
  &lt;p id=&quot;FKAv&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;Gd2W&quot;&gt;Логика аналогичная, если надо положительное целое из десятичной перевести в двоичную систему:&lt;/p&gt;
  &lt;pre id=&quot;VBmk&quot; data-lang=&quot;python&quot;&gt;x = 123
s = &amp;#x27;&amp;#x27;
while x!=0:
    ost = x%2
    s = f&amp;#x27;{ost}{s}&amp;#x27;
    x  = x//2&lt;/pre&gt;
  &lt;figure id=&quot;29F2&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/e9/b3/e9b3b67c-d169-4b31-b0ab-2142a54c1c57.png&quot; width=&quot;600&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;ATXm&quot;&gt;и обратно:&lt;/p&gt;
  &lt;pre id=&quot;jh7p&quot; data-lang=&quot;python&quot;&gt;res = 0
s_len = len(s)
for i, num in enumerate(s):
    res = res + int(num)*2**(s_len-1-i)
res&lt;/pre&gt;
  &lt;figure id=&quot;Dv29&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/51/07/5107e462-ccf9-41e0-a75d-f23d14ccb75b.png&quot; width=&quot;555&quot; /&gt;
  &lt;/figure&gt;

</content></entry><entry><id>dt_analytic:qv-WSVJ98O8</id><link rel="alternate" type="text/html" href="https://teletype.in/@dt_analytic/qv-WSVJ98O8?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=dt_analytic"></link><title>BM25Retriever под капотом</title><published>2026-02-10T01:09:41.169Z</published><updated>2026-02-10T01:09:41.169Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img3.teletype.in/files/ee/4e/ee4e4b33-f282-4da5-a265-0add4b82dc91.png"></media:thumbnail><category term="obrabotka-dannyh" label="обработка данных"></category><tt:hashtag>bm25retriever</tt:hashtag><tt:hashtag>retrievers</tt:hashtag><tt:hashtag>llm</tt:hashtag><tt:hashtag>rag</tt:hashtag><tt:hashtag>tfidf</tt:hashtag><tt:hashtag>nlp</tt:hashtag><tt:hashtag>ml</tt:hashtag><summary type="html">&lt;img src=&quot;https://img2.teletype.in/files/10/23/1023b3ba-221a-4612-a8e0-a0a0c4bfd241.png&quot;&gt;В современных rag системах центральным инструментом являются ретриверы - объекты, которые отвечают за поиск близкой к запросу информации (контекста). Одним из них является BM25Retriever, основанный на частоте встречаемости. В отличие от аналогов, использующих векторные представления, он полагается на точные совпадение единиц, на которые разбит текст (токенов).</summary><content type="html">
  &lt;figure id=&quot;vKCE&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/10/23/1023b3ba-221a-4612-a8e0-a0a0c4bfd241.png&quot; width=&quot;696&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;8ppD&quot;&gt;В современных rag системах центральным инструментом являются ретриверы - объекты, которые отвечают за поиск близкой к запросу информации (контекста). Одним из них является &lt;strong&gt;BM25Retriever&lt;/strong&gt;, основанный на частоте встречаемости. В отличие от аналогов, использующих векторные представления, он полагается на точные совпадение единиц, на которые разбит текст (токенов).&lt;/p&gt;
  &lt;p id=&quot;4MUd&quot;&gt;Для демонстрационных целей возмем набор текстов с описанием компьютерных угроз с сайта MITRE ATT&amp;amp;CK (&lt;a href=&quot;https://attack.mitre.org/techniques/T1593/&quot; target=&quot;_blank&quot;&gt;тут &lt;/a&gt;и &lt;a href=&quot;https://attack.mitre.org/techniques/T1570/&quot; target=&quot;_blank&quot;&gt;тут&lt;/a&gt;):&lt;/p&gt;
  &lt;pre id=&quot;Lx5Y&quot; data-lang=&quot;python&quot;&gt;import numpy as np

train_sents = [&amp;quot;Contagious Interview has utilized open-source indicator of compromise repositories to determine their exposure to include VirusTotal, and MalTrail&amp;quot;,
&amp;quot;Kimsuky has used LLMs to identify think tanks, government organizations, etc. that have information&amp;quot;,
&amp;#x27;&amp;#x27;&amp;#x27;Sandworm Team researched Ukraine&amp;#x27;s unique legal entity identifier (called an &amp;quot;EDRPOU&amp;quot; number), including running queries on the EDRPOU website, in preparation for the NotPetya attack. Sandworm Team has also researched third-party websites to help it craft credible spearphishing emails&amp;#x27;&amp;#x27;&amp;#x27;,
&amp;quot;During the 2015 Ukraine Electric Power Attack, Sandworm Team moved their tools laterally within the corporate network and between the ICS and corporate network&amp;quot;,
&amp;quot;During the 2022 Ukraine Electric Power Attack, Sandworm Team used a Group Policy Object (GPO) to copy CaddyWiper&amp;#x27;s executable msserver.exe from a staging server to a local hard drive before deployment&amp;quot;]


query_sent=&amp;quot;Mustang Panda has used open-source research to identify information about victims to use in targeting to include creating weaponized phishing lures and attachments&amp;quot;&lt;/pre&gt;
  &lt;figure id=&quot;COJQ&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/db/95/db95d9b9-59ee-4b1f-93d0-f0ea00e7c161.png&quot; width=&quot;1385&quot; /&gt;
  &lt;/figure&gt;
  &lt;h2 id=&quot;JZpA&quot;&gt;BM25Retriever&lt;/h2&gt;
  &lt;p id=&quot;uztG&quot;&gt;Для корректной работы &lt;strong&gt;BM25Retriever &lt;/strong&gt;важен способ разбиения текста на единицы, для этого используется параметр &lt;strong&gt;preprocess_func&lt;/strong&gt;. Зададим функцию, осуществляющую деление по словам и их стемминг:&lt;/p&gt;
  &lt;pre id=&quot;afb0&quot; data-lang=&quot;python&quot;&gt;import nltk
from nltk.stem import SnowballStemmer
nltk.download(&amp;#x27;punkt_tab&amp;#x27;)

def preprocess_func(text):
    text = text.lower()
    words_l = nltk.tokenize.word_tokenize(text)
    stemmer = SnowballStemmer(&amp;#x27;english&amp;#x27;)
    words_l = [stemmer.stem(w) for w in words_l]
    return words_l&lt;/pre&gt;
  &lt;figure id=&quot;T9iL&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/08/a6/08a65028-7b6e-4e29-a676-6476a798fa5b.png&quot; width=&quot;1326&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;UNDL&quot;&gt;Верхнеуровнево для работы надо уметь создать &lt;strong&gt;BM25Retriever&lt;/strong&gt;, используя, например, метод &lt;strong&gt;from_texts &lt;/strong&gt;и найти ближайшие тексты с &lt;strong&gt;invoke&lt;/strong&gt;:&lt;/p&gt;
  &lt;pre id=&quot;Z3DS&quot; data-lang=&quot;python&quot;&gt;from langchain_community.retrievers import BM25Retriever

# Возвращается объект pydantic BaseModel (в __init__ Serializable)
bm_retriever = BM25Retriever.from_texts(train_sents, k=2, preprocess_func=preprocess_func,
                                        metadatas=[{&amp;#x27;len&amp;#x27;:len(it)} for it in train_sents],
                                        ids=range(len(train_sents)))

bm_retriever.invoke(query_sent)
&lt;/pre&gt;
  &lt;figure id=&quot;G3bV&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/70/1d/701d43af-df55-458c-876e-f7bf3e5bda31.png&quot; width=&quot;1401&quot; /&gt;
  &lt;/figure&gt;
  &lt;h3 id=&quot;wWa0&quot;&gt;from_texts&lt;/h3&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;PacQ&quot;&gt;&lt;a href=&quot;https://github.com/langchain-ai/langchain-community/blob/libs/community/v0.4.1/libs/community/langchain_community/retrievers/bm25.py#L62&quot; target=&quot;_blank&quot;&gt;from_texts&lt;/a&gt; получает аргументы:&lt;/p&gt;
  &lt;ul id=&quot;z5nI&quot;&gt;
    &lt;li id=&quot;ALPV&quot;&gt;&lt;strong&gt;texts &lt;/strong&gt;- список текстов, формирующих базу для поиска;&lt;/li&gt;
    &lt;li id=&quot;7WBp&quot;&gt;&lt;strong&gt;k &lt;/strong&gt;- количество ближайших текстов в ответ на запрос поиска;&lt;/li&gt;
    &lt;li id=&quot;bNFg&quot;&gt;&lt;strong&gt;preprocess_func &lt;/strong&gt;- функция для разбиения текстов на токены;&lt;/li&gt;
    &lt;li id=&quot;J17x&quot;&gt;&lt;strong&gt;metadatas &lt;/strong&gt;- список словарей с метаданными для каждого текста в texts;&lt;/li&gt;
    &lt;li id=&quot;gqJC&quot;&gt;&lt;strong&gt;ids &lt;/strong&gt;- список идентификаторов для каждого текста в texts.&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;8HcP&quot;&gt;Следует отметить, что k можно поменять (например, когда вы загружаете настроенный дамп retriever-а) так: &lt;strong&gt;bm_retriever.k = 1&lt;/strong&gt;.&lt;/p&gt;
  &lt;p id=&quot;YkM5&quot;&gt;&lt;strong&gt;from_texts &lt;/strong&gt;выполняет следующий код:&lt;/p&gt;
  &lt;ul id=&quot;1Np1&quot;&gt;
    &lt;li id=&quot;MFZa&quot;&gt;texts_processed = [preprocess_func(t) for t in texts]&lt;/li&gt;
    &lt;li id=&quot;Klam&quot;&gt;vectorizer = BM25Okapi(texts_processed...)&lt;/li&gt;
  &lt;/ul&gt;
  &lt;h3 id=&quot;X4KQ&quot;&gt;invoke&lt;/h3&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;Nowy&quot;&gt;В &lt;strong&gt;invoke &lt;/strong&gt;выполняются:&lt;/p&gt;
  &lt;ul id=&quot;7iaj&quot;&gt;
    &lt;li id=&quot;YsJ2&quot;&gt;&lt;a href=&quot;https://github.com/langchain-ai/langchain/blob/langchain-core%3D%3D1.2.8/libs/core/langchain_core/retrievers.py#L226&quot; target=&quot;_blank&quot;&gt;invoke из BaseRetriever&lt;/a&gt; вызывает &lt;strong&gt;_get_relevant_documents&lt;/strong&gt;;&lt;/li&gt;
    &lt;li id=&quot;oPcC&quot;&gt;&lt;a href=&quot;https://github.com/langchain-ai/langchain-community/blob/libs/community/v0.4.1/libs/community/langchain_community/retrievers/bm25.py#L111&quot; target=&quot;_blank&quot;&gt;_get_relevant_documents&lt;/a&gt; осуществляет препроцессинг и возврат наиболее подходящих через &lt;strong&gt;get_top_n&lt;/strong&gt;:&lt;/li&gt;
    &lt;ul id=&quot;pFzf&quot;&gt;
      &lt;li id=&quot;oyMG&quot;&gt;processed_query = self.preprocess_func(query)&lt;/li&gt;
      &lt;li id=&quot;acbx&quot;&gt;self.vectorizer.get_top_n(processed_query, self.docs, n=self.k)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;cSuT&quot;&gt;Подытоживая, &lt;strong&gt;from_texts &lt;/strong&gt;инициирует препроцессинг текстов и создает класс &lt;strong&gt;BM25Okapi&lt;/strong&gt;, а &lt;strong&gt;invoke &lt;/strong&gt;- препроцессинг запроса и вызывает метод &lt;strong&gt;get_top_n &lt;/strong&gt;объекта класса BM25Okapi. Теперь разберемся с BM25Okapi и его особенностями.&lt;/p&gt;
  &lt;h2 id=&quot;eqck&quot;&gt;okapi&lt;/h2&gt;
  &lt;ul id=&quot;awAt&quot;&gt;
    &lt;li id=&quot;fGJm&quot;&gt;в конструкторе подсчитываются:&lt;/li&gt;
    &lt;ul id=&quot;irFD&quot;&gt;
      &lt;li id=&quot;g7mx&quot;&gt;&lt;a href=&quot;https://github.com/dorianbrown/rank_bm25/blob/0.2.2/rank_bm25.py#L42&quot; target=&quot;_blank&quot;&gt;словарь встречаемости слов в документах (doc_freqs)&lt;/a&gt;&lt;/li&gt;
      &lt;li id=&quot;B0Zz&quot;&gt;&lt;a href=&quot;https://github.com/dorianbrown/rank_bm25/blob/0.2.2/rank_bm25.py#L34&quot; target=&quot;_blank&quot;&gt;длины каждого документа в токенах (doc_len) и средняя длина документа в токенах (avgdl)&lt;/a&gt;&lt;/li&gt;
      &lt;li id=&quot;0FLr&quot;&gt;&lt;a href=&quot;https://github.com/dorianbrown/rank_bm25/blob/0.2.2/rank_bm25.py#L85&quot; target=&quot;_blank&quot;&gt;idf токенов (idf)&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
    &lt;li id=&quot;vshW&quot;&gt;в &lt;a href=&quot;https://github.com/dorianbrown/rank_bm25/blob/0.2.2/rank_bm25.py#L69&quot; target=&quot;_blank&quot;&gt;get_top_n&lt;/a&gt;:&lt;/li&gt;
    &lt;ul id=&quot;zEZo&quot;&gt;
      &lt;li id=&quot;83aP&quot;&gt;каждый документ (объект с текстом и метаданными) получает скор близости к запросу &lt;a href=&quot;https://github.com/dorianbrown/rank_bm25/blob/0.2.2/rank_bm25.py#L107&quot; target=&quot;_blank&quot;&gt;get scores in BM25Okapi&lt;/a&gt;&lt;/li&gt;
      &lt;li id=&quot;kAwc&quot;&gt;документы сортируются по убыванию скора и выбирается заданное число&lt;/li&gt;
      &lt;li id=&quot;bvAq&quot;&gt;соответствующий код:&lt;/li&gt;
    &lt;/ul&gt;
    &lt;ul id=&quot;CkO1&quot;&gt;
      &lt;ul id=&quot;vYwT&quot;&gt;
        &lt;li id=&quot;UgZM&quot;&gt;scores = self.get_scores(query)&lt;/li&gt;
        &lt;li id=&quot;ttV6&quot;&gt;top_n = np.argsort(scores)[::-1][:n]&lt;/li&gt;
        &lt;li id=&quot;PX1x&quot;&gt;[documents[i] for i in top_n]&lt;/li&gt;
      &lt;/ul&gt;
    &lt;/ul&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;HvQu&quot;&gt;Создадим вручную объект класса BM25Okapi и набор документов (без метаданных для простоты):&lt;/p&gt;
  &lt;pre id=&quot;AVp6&quot; data-lang=&quot;python&quot;&gt;from rank_bm25 import BM25Okapi
from langchain_core.documents import Document


texts_processed = [preprocess_func(t) for t in train_sents]
vectorizer = BM25Okapi(texts_processed)

docs = [Document(page_content=t) for t in train_sents]

processed_query = preprocess_func(query_sent)
&lt;/pre&gt;
  &lt;figure id=&quot;iHLt&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/28/cb/28cb8e7f-8d13-4f7e-a798-9c4b0c4cfa63.png&quot; width=&quot;1281&quot; /&gt;
  &lt;/figure&gt;
  &lt;h3 id=&quot;9Hm3&quot;&gt;свойства&lt;/h3&gt;
  &lt;ul id=&quot;LCRx&quot;&gt;
    &lt;li id=&quot;p6p5&quot;&gt;&lt;strong&gt;idf &lt;/strong&gt;- содержит idf токенов&lt;/li&gt;
    &lt;li id=&quot;oZ8S&quot;&gt;&lt;strong&gt;doc_freqs &lt;/strong&gt;- содержит список словарей с частотами токенов для каждого документа&lt;/li&gt;
    &lt;li id=&quot;MFXP&quot;&gt;&lt;strong&gt;get_scores &lt;/strong&gt;- возвращает список скоров каждого документа относительно query&lt;/li&gt;
    &lt;li id=&quot;c98p&quot;&gt;&lt;strong&gt;get_top_n &lt;/strong&gt;- возвращает топ k самых близких документов&lt;/li&gt;
    &lt;li id=&quot;FoiH&quot;&gt;&lt;strong&gt;doc_len &lt;/strong&gt;- содержит список количества токенов в каждом документе&lt;/li&gt;
    &lt;li id=&quot;UH3l&quot;&gt;&lt;strong&gt;avgdl &lt;/strong&gt;- содержит среднее количество токенов в документах&lt;/li&gt;
  &lt;/ul&gt;
  &lt;hr /&gt;
  &lt;h3 id=&quot;BlfV&quot;&gt;формула скора&lt;/h3&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;Oaj4&quot;&gt;Посчитаем вручную скор для нулевого документа, который возвращает &lt;strong&gt;get_scores&lt;/strong&gt;:&lt;/p&gt;
  &lt;pre id=&quot;YOVQ&quot; data-lang=&quot;python&quot;&gt;vectorizer.get_scores(processed_query)&lt;/pre&gt;
  &lt;figure id=&quot;vQdK&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/76/c0/76c03c51-3288-4b3b-9778-968474419339.png&quot; width=&quot;1014&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;9Tyq&quot;&gt;idf для каждого токена считается в BM25Okapi конструкторе по следующей формуле: &lt;/p&gt;
  &lt;figure id=&quot;RBCs&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/3a/c0/3ac07920-6135-40cd-93af-2c2312556ac0.png&quot; width=&quot;1140&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;KWcx&quot;&gt;Добавление константы (0.5) не дает знаменателю или числителю стать равным нулю и сглаживает рост idf для слов, которые встречаются только в единичных документах.&lt;/p&gt;
  &lt;p id=&quot;vway&quot;&gt;Посчитаем idf для токена &amp;quot;open-sourc&amp;quot;, который встречается в 1 из 5 текстов:&lt;/p&gt;
  &lt;pre id=&quot;R0Rf&quot; data-lang=&quot;python&quot;&gt;idf = np.log((5-1+0.5)/(1+0.5))
vectorizer.idf[&amp;#x27;open-sourc&amp;#x27;], idf&lt;/pre&gt;
  &lt;figure id=&quot;Rxj2&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/c8/d4/c8d47502-d452-4a08-adff-3962c56eb6b3.png&quot; width=&quot;1082&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;0AwX&quot;&gt;tf для &amp;quot;open-sourc&amp;quot; в нулевом документе получим так:&lt;/p&gt;
  &lt;pre id=&quot;uYx8&quot; data-lang=&quot;python&quot;&gt;N = 0
tf = vectorizer.doc_freqs[N][&amp;#x27;open-sourc&amp;#x27;]
tf&lt;/pre&gt;
  &lt;figure id=&quot;xtld&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/78/95/7895bdb6-1152-4085-a7df-19d3f7c315b1.png&quot; width=&quot;1084&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;iImJ&quot;&gt;Для извлечения скора документа надо итерировать по всем токенам query и посчитать сумму для каждого по формуле:&lt;/p&gt;
  &lt;figure id=&quot;r8RD&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/6e/c5/6ec53279-98c3-4fed-8acb-f85398c8f502.png&quot; width=&quot;1115&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;1L6a&quot;&gt;Из формулы следует, что для документов с длиной меньше средней слагаемое будет увеличено (короткие получают бонус), а для больше средней - уменьшено (штраф за размытость). Посчитаем добавку для токена &amp;quot;open-sourc&amp;quot;:&lt;/p&gt;
  &lt;pre id=&quot;YiFs&quot; data-lang=&quot;python&quot;&gt;idf*(tf * (1.5 + 1) /(tf + 1.5 * (1 - 0.75 + 0.75 * vectorizer.doc_len[N] / vectorizer.avgdl)))&lt;/pre&gt;
  &lt;figure id=&quot;WI8l&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/8d/e0/8de0797d-9bc1-4588-b849-f45397cac677.png&quot; width=&quot;1179&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;dF6m&quot;&gt;А теперь выведем скор для всего нулевого документа:&lt;/p&gt;
  &lt;pre id=&quot;DPKV&quot; data-lang=&quot;python&quot;&gt;score = 0
# для нулевого документа
for q in processed_query:
    q_freq = vectorizer.doc_freqs[N].get(q,0)
    adding = vectorizer.idf.get(q, 0) * (q_freq * (1.5 + 1) /
                                        (q_freq + 1.5 * (1 - 0.75 + 0.75 * vectorizer.doc_len[N] / vectorizer.avgdl)))
    if q==&amp;#x27;open-sourc&amp;#x27;:
      print(f&amp;#x27;принт добавка от &amp;quot;open-sourc&amp;quot; - {adding}&amp;#x27;)
    score += adding
score&lt;/pre&gt;
  &lt;figure id=&quot;eOmQ&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/b9/62/b962361c-a6ca-463d-a46b-7231f6c8b3a8.png&quot; width=&quot;1128&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;3mS2&quot;&gt;По скору наш (нулевой) документ второй, в такой очередности он и выводится в &lt;strong&gt;get_top_n&lt;/strong&gt;:&lt;/p&gt;
  &lt;pre id=&quot;hgOk&quot; data-lang=&quot;python&quot;&gt;k = 2

vectorizer.get_top_n(processed_query, docs, n=k)&lt;/pre&gt;
  &lt;figure id=&quot;uAWc&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/63/e1/63e1f429-eabe-4743-8aa7-2e39ad6b8443.png&quot; width=&quot;1125&quot; /&gt;
  &lt;/figure&gt;
  &lt;tt-tags id=&quot;dQtX&quot;&gt;
    &lt;tt-tag name=&quot;bm25retriever&quot;&gt;#bm25retriever&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;retrievers&quot;&gt;#retrievers&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;llm&quot;&gt;#llm&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;rag&quot;&gt;#rag&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;tfidf&quot;&gt;#tfidf&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;nlp&quot;&gt;#nlp&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;ml&quot;&gt;#ml&lt;/tt-tag&gt;
  &lt;/tt-tags&gt;

</content></entry><entry><id>dt_analytic:JWvPr50fMW1</id><link rel="alternate" type="text/html" href="https://teletype.in/@dt_analytic/JWvPr50fMW1?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=dt_analytic"></link><title>Многоканальное логирование для python проекта</title><published>2025-07-04T05:02:30.190Z</published><updated>2025-07-04T05:10:02.403Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img1.teletype.in/files/8c/9f/8c9fc929-7628-4d1a-b36b-27fcea98b4ca.png"></media:thumbnail><category term="python" label="python"></category><tt:hashtag>logger</tt:hashtag><tt:hashtag>logging</tt:hashtag><tt:hashtag>activitylogger</tt:hashtag><summary type="html">&lt;img src=&quot;https://img4.teletype.in/files/73/ef/73ef3893-6c76-4581-85fb-191810bdb2b0.png&quot;&gt;Логируй так, будто завтра сервер упадет, и только твои записи спасут мир.</summary><content type="html">
  &lt;figure id=&quot;3tNA&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/73/ef/73ef3893-6c76-4581-85fb-191810bdb2b0.png&quot; width=&quot;763&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;Ck3A&quot;&gt;&lt;strong&gt;Логируй так, будто завтра сервер упадет, и только твои записи спасут мир.&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;eQFG&quot;&gt;Рассмотрим, как создать логгер для проекта, который предусматривает вывод сообщений и в консоль, и в файл журнала. Реализовывать его будем в форме класса &lt;strong&gt;Python&lt;/strong&gt;, но сначала рассмотрим типичные особенности в интерактивном режиме. &lt;/p&gt;
  &lt;p id=&quot;lcF8&quot;&gt;Нашими строительными блоками будут составляющие модуля &lt;strong&gt;logging&lt;/strong&gt;:&lt;/p&gt;
  &lt;ul id=&quot;YEbJ&quot;&gt;
    &lt;li id=&quot;eZYP&quot;&gt;функция &lt;strong&gt;getLogger &lt;/strong&gt;для получения логгера с заданным именем;&lt;/li&gt;
    &lt;li id=&quot;I7l0&quot;&gt;классы handler-ов: &lt;strong&gt;FileHandler &lt;/strong&gt;для логирования в файл, &lt;strong&gt;StreamHandler &lt;/strong&gt;для вывода в консоль, которые добавляются в полученный на предыдущем этапе логгер;&lt;/li&gt;
    &lt;li id=&quot;RR6F&quot;&gt;метод логгера &lt;strong&gt;setLevel &lt;/strong&gt;для задания уровня вывода сообщений;&lt;/li&gt;
    &lt;li id=&quot;NfkZ&quot;&gt;методы логгера &lt;strong&gt;info&lt;/strong&gt;, &lt;strong&gt;debug&lt;/strong&gt;, &lt;strong&gt;error&lt;/strong&gt;, &lt;strong&gt;warning &lt;/strong&gt;для вывода сообщений с заданным уровнем.&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;p6vZ&quot;&gt;Про уровни вывода сообщений и методы я рассказывал &lt;a href=&quot;https://www.google.com/url?q=https%3A%2F%2Fdzen.ru%2Fa%2FYw3sJ7bEuy5UxE8w&quot; target=&quot;_blank&quot;&gt;ранее&lt;/a&gt;. Создадим тестовый logger:&lt;/p&gt;
  &lt;pre id=&quot;26Bh&quot; data-lang=&quot;python&quot;&gt;import logging

file_handler = logging.FileHandler(&amp;#x27;journal.log&amp;#x27;)
console_handler = logging.StreamHandler()

logger = logging.getLogger(&amp;#x27;test_logger&amp;#x27;)
logger.setLevel(logging.INFO)

logger.addHandler(file_handler)
logger.addHandler(console_handler)

logger.info(&amp;#x27;test message 1&amp;#x27;)&lt;/pre&gt;
  &lt;pre id=&quot;v8J1&quot;&gt;!cat journal.log&lt;/pre&gt;
  &lt;figure id=&quot;DqXb&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/2c/10/2c10637f-b7d7-4c56-9985-03ff97c95763.png&quot; width=&quot;1044&quot; /&gt;
  &lt;/figure&gt;
  &lt;h2 id=&quot;gs0P&quot;&gt;propagate&lt;/h2&gt;
  &lt;p id=&quot;F7md&quot;&gt;Можно заметить 2 сообщения в консоли и одно - в журнале. Почему в консоль отправлен лишний вывод? &lt;/p&gt;
  &lt;p id=&quot;ml28&quot;&gt;Поведение по умолчанию предполагает передачу сообщений вверх по иерархии к root-логгеру, который является предком всех logger-ов и обрабатывает сообщение путем вывода на консоль. Это регулируется атрибутом &lt;strong&gt;propagate &lt;/strong&gt;(который по умолчанию равен True). Соответственно, чтобы остановить передачу &amp;quot;наверх&amp;quot; надо задать: &lt;strong&gt;logger.propagate = False&lt;/strong&gt;:&lt;/p&gt;
  &lt;pre id=&quot;qvUM&quot; data-lang=&quot;python&quot;&gt;logger.propagate = False
logger.info(&amp;#x27;test message 2&amp;#x27;)&lt;/pre&gt;
  &lt;figure id=&quot;z4w9&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/fb/78/fb78d2c6-77a3-41f6-8315-099043b4ab79.png&quot; width=&quot;1053&quot; /&gt;
  &lt;/figure&gt;
  &lt;h2 id=&quot;qjoF&quot;&gt;разные хэндлеры&lt;/h2&gt;
  &lt;p id=&quot;sxPF&quot;&gt;Для вывода списка обработчиков, которые отвечают за отправку сообщений в канал, можно обратиться к свойству &lt;strong&gt;logger.handlers&lt;/strong&gt;:&lt;/p&gt;
  &lt;pre id=&quot;YJZi&quot; data-lang=&quot;python&quot;&gt;logger.handlers&lt;/pre&gt;
  &lt;figure id=&quot;O2mE&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/b0/62/b062aee5-ad00-490c-8758-3f75a44b0c00.png&quot; width=&quot;1008&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;WHEq&quot;&gt;Если попытаться добавить одинаковые хэндлеры, то список не изменится:&lt;/p&gt;
  &lt;pre id=&quot;m4zl&quot; data-lang=&quot;python&quot;&gt;logger.addHandler(file_handler)
logger.addHandler(console_handler)
logger.handlers&lt;/pre&gt;
  &lt;figure id=&quot;2vUP&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/6f/53/6f539460-cf2d-41a5-ba4c-4fe22f446ca1.png&quot; width=&quot;1047&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;hEsY&quot;&gt;Однако при создании новых объектов (и с другими id, соответственно) система будет считать их другими и произойдет дублирование вывода, поэтому при двухкратном обращении к одному логгеру в нашем классе надо будет предусмотреть такое поведение:&lt;/p&gt;
  &lt;pre id=&quot;ypop&quot;&gt;file_handler = logging.FileHandler(&amp;#x27;journal.log&amp;#x27;)
console_handler = logging.StreamHandler()

logger.addHandler(file_handler)
logger.addHandler(console_handler)
logger.handlers&lt;/pre&gt;
  &lt;figure id=&quot;VXe7&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/de/41/de41b10f-ff1f-4908-9616-93cc0a769410.png&quot; width=&quot;1026&quot; /&gt;
  &lt;/figure&gt;
  &lt;figure id=&quot;SlHz&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/80/e7/80e7f280-a9c4-4279-a952-354b2ef76afd.png&quot; width=&quot;1036&quot; /&gt;
  &lt;/figure&gt;
  &lt;h2 id=&quot;LXU9&quot;&gt;закрытие хэндлеров&lt;/h2&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;ZCZz&quot;&gt;По завершении работы с логгером надо удалить из него привязку к обработчикам, что можно сделать, очистив соответствующий список. Однако следует помнить о коварной ошибке при удалении handler-ов из того же списка, по которому происходит итерация:&lt;/p&gt;
  &lt;pre id=&quot;eh5X&quot; data-lang=&quot;python&quot;&gt;for handler in logger.handlers:
    logger.removeHandler(handler)

logger.handlers&lt;/pre&gt;
  &lt;figure id=&quot;JaAQ&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/e9/6e/e96ecf0d-db44-46bf-9e79-726e06ed81da.png&quot; width=&quot;1009&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;eX2O&quot;&gt;А так (logger.handlers[:]) создаем копию списка для итерации, поэтому результат будет пустым, и новые сообщения при обращении к логгеру не появляются:&lt;/p&gt;
  &lt;pre id=&quot;H01r&quot; data-lang=&quot;python&quot;&gt;for handler in logger.handlers[:]:
    logger.removeHandler(handler)
logger.handlers&lt;/pre&gt;
  &lt;figure id=&quot;3r2S&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/81/d8/81d85947-56e6-4bf9-95d1-4855353ab71f.png&quot; width=&quot;1042&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;u8OJ&quot;&gt;Для корректного освобождения ресурсов (закрытия файла, сброса буферов) также рекомендуется вызывать метод &lt;strong&gt;close &lt;/strong&gt;обработчиков:&lt;/p&gt;
  &lt;pre id=&quot;xnjT&quot; data-lang=&quot;python&quot;&gt;file_handler.stream.closed&lt;/pre&gt;
  &lt;pre id=&quot;Vc8N&quot;&gt;file_handler.close()
console_handler.close()
&lt;/pre&gt;
  &lt;figure id=&quot;gEEG&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/10/e4/10e4142b-4c4f-44be-9a28-0e062831b211.png&quot; width=&quot;1037&quot; /&gt;
  &lt;/figure&gt;
  &lt;h2 id=&quot;hq3J&quot;&gt;класс логгера&lt;/h2&gt;
  &lt;p id=&quot;5Lbp&quot;&gt;На основании описанного выше можно создать класс логгера, который одновременно выводит и в журнал, и на консоль. Также добавим удобный формат сообщений (подробнее было &lt;a href=&quot;true&quot;&gt;тут&lt;/a&gt;).&lt;/p&gt;
  &lt;pre id=&quot;jRGR&quot; data-lang=&quot;python&quot;&gt;import logging

LOG_FN = &amp;#x27;journal.log&amp;#x27;

class ActivityLogger():

    def __init__(self, level=logging.INFO, encoding=&amp;#x27;utf-8&amp;#x27;):

        self.level = level
        self.file_handler = logging.FileHandler(LOG_FN, encoding=encoding)
        self.console_handler = logging.StreamHandler()

    def get_logger(self, name):

        file_formatter = logging.Formatter(f&amp;#x27;%(asctime)s \nMODULE:{name}, LEVEL:%(levelname)s, LINE:%(lineno)s, MSG:%(message)s\n&amp;#x27;)
        cons_formatter = logging.Formatter(f&amp;#x27;%(asctime)s \n%(lineno)s %(message)s\n\n&amp;#x27;)

        # Применяем форматтер к обоим Handler
        self.file_handler.setFormatter(file_formatter)
        self.console_handler.setFormatter(cons_formatter)

        # Создаем объект logger и применяем к нему оба Handler
        logger = logging.getLogger(name)
        logger.setLevel(self.level)

        if len(logger.handlers)==0:
            logger.addHandler(self.file_handler)
            logger.addHandler(self.console_handler)

        # Disable propagation of messages to the root logger
        logger.propagate = False

        return logger

    def close_logger(self, logger):

        # import pdb;pdb.set_trace()
        for handler in logger.handlers[:]:
            logger.removeHandler(handler)

        self.file_handler.close()
        self.console_handler.close()
&lt;/pre&gt;
  &lt;p id=&quot;UBQp&quot;&gt;Для демонстрационных целей имитируем наличие проекта и класс logger-а в отдельном модуле:&lt;/p&gt;
  &lt;figure id=&quot;Enol&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/9d/c4/9dc40c99-66e8-41d2-b1d5-89f100f41ff6.png&quot; width=&quot;1057&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;6quK&quot;&gt;&lt;/p&gt;
  &lt;figure id=&quot;Q5Pr&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/34/ca/34ca02ba-bfa2-4c80-a81c-9cad6fbeb2e4.png&quot; width=&quot;1005&quot; /&gt;
  &lt;/figure&gt;
  &lt;figure id=&quot;Qe1i&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/2d/96/2d96566a-01e3-4d46-a19d-2413ecdda068.png&quot; width=&quot;1046&quot; /&gt;
  &lt;/figure&gt;
  &lt;h3 id=&quot;ek6R&quot;&gt;скрипты передают свои имена в журнал&lt;/h3&gt;
  &lt;p id=&quot;gK4i&quot;&gt;Теперь создадим 2 одинаковых скрипта, использующих логгер:&lt;/p&gt;
  &lt;pre id=&quot;X0Pu&quot; data-lang=&quot;python&quot;&gt;t = r&amp;#x27;&amp;#x27;&amp;#x27;
from constants import ActivityLogger

try:

    logger = ActivityLogger().get_logger(__file__)
    logger.info(f&amp;#x27;тестовое сообщение&amp;#x27;)

    ActivityLogger().close_logger(logger)

except Exception:
    logger.exception(&amp;#x27;ВОЗНИКЛО ИСКЛЮЧЕНИЕ!!!&amp;#x27;)
    ActivityLogger().close_logger(logger)

&amp;#x27;&amp;#x27;&amp;#x27;

with open(&amp;#x27;project/script1.py&amp;#x27;, &amp;#x27;wt&amp;#x27;) as f:
    f.write(t)

with open(&amp;#x27;project/script2.py&amp;#x27;, &amp;#x27;wt&amp;#x27;) as f:
    f.write(t)&lt;/pre&gt;
  &lt;figure id=&quot;A8E5&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/0f/aa/0faa7ef5-ef2c-44c1-ae6e-53689c53a9ea.png&quot; width=&quot;1013&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;aniN&quot;&gt;Запустим оба скрипта и увидим, что сообщения корректно выводятся и в журнал и на консоль с указанием файла-источника, что удобно для отладки:&lt;/p&gt;
  &lt;figure id=&quot;ARlv&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/3d/a5/3da50e26-b7c7-406d-993f-238c719d74e1.png&quot; width=&quot;1043&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;HUxh&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;DWfM&quot;&gt;нет дублирования при многократном обращении к логгеру &lt;/h3&gt;
  &lt;p id=&quot;ptI7&quot;&gt;Так как мы предусмотрели проверку наличия обработчиков (в блоке - if len...), при обращении к одному и тому же логгеру дважды сообщения не дублируются: &lt;/p&gt;
  &lt;pre id=&quot;WVJA&quot; data-lang=&quot;python&quot;&gt;from project.constants import ActivityLogger
import logging

logger1 = ActivityLogger(level = logging.ERROR).get_logger(&amp;#x27;note1&amp;#x27;)
logger1.error(&amp;quot;тестовое сообщение note 1&amp;quot;)

print(logging.getLogger(&amp;#x27;note1&amp;#x27;).handlers)&lt;/pre&gt;
  &lt;figure id=&quot;L7wD&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/1c/72/1c72da12-0bf7-47b3-96b9-77f57a03f7bf.png&quot; width=&quot;1078&quot; /&gt;
  &lt;/figure&gt;
  &lt;pre id=&quot;yjdS&quot; data-lang=&quot;python&quot;&gt;logger2 = ActivityLogger().get_logger(&amp;#x27;note1&amp;#x27;)

logger2.error(&amp;quot;тестовое сообщение note 2&amp;quot;)
print(logger2.handlers)&lt;/pre&gt;
  &lt;figure id=&quot;vXVi&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/e7/ff/e7ffb3d3-5ad7-4be9-bf7c-a1102e49dab1.png&quot; width=&quot;1046&quot; /&gt;
  &lt;/figure&gt;
  &lt;figure id=&quot;cwY8&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/aa/ba/aabac9eb-1c11-4884-a628-3103c8569b9d.png&quot; width=&quot;1044&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;XGo1&quot;&gt;Следует отметить, что вместо проверки наличия в логгере обработчиков, можно было бы задать их на уровне переменных класса (а не экземпляра), тогда они бы при повторном добавлении id не меняли и, соответственно, каналы бы не дублировались:&lt;/p&gt;
  &lt;pre id=&quot;tb80&quot; data-lang=&quot;python&quot;&gt;import logging

LOG_FN = &amp;#x27;journal.log&amp;#x27;

class ActivityLogger():

    file_handler = logging.FileHandler(LOG_FN, encoding=&amp;#x27;utf-8&amp;#x27;)
    console_handler = logging.StreamHandler()

    def __init__(self, level=logging.INFO):
        self.level = level

    def get_logger(self, name):

        file_formatter = logging.Formatter(f&amp;#x27;%(asctime)s \nMODULE:{name}, LEVEL:%(levelname)s, LINE:%(lineno)s, MSG:%(message)s\n&amp;#x27;)
        cons_formatter = logging.Formatter(f&amp;#x27;%(asctime)s \n%(lineno)s %(message)s\n\n&amp;#x27;)

        # Применяем форматтер к обоим Handler
        self.file_handler.setFormatter(file_formatter)
        self.console_handler.setFormatter(cons_formatter)

        # Создаем объект logger и применяем к нему оба Handler
        logger = logging.getLogger(name)
        logger.setLevel(logging.INFO)

        logger.addHandler(self.file_handler)
        logger.addHandler(self.console_handler)

        # Disable propagation of messages to the root logger
        logger.propagate = False

        return logger

    def close_logger(self, logger):

        for handler in logger.handlers[:]:
            logger.removeHandler(handler)

        self.file_handler.close()
        self.console_handler.close()

&lt;/pre&gt;
  &lt;h2 id=&quot;HbOY&quot;&gt;параллельная работа с несколькими логгерами&lt;/h2&gt;
  &lt;p id=&quot;JnYQ&quot;&gt;Если мы работаем с двумя логгерами, то закрытие одного не влияет на работу другого:&lt;/p&gt;
  &lt;pre id=&quot;b81A&quot; data-lang=&quot;python&quot;&gt;from project.constants import ActivityLogger

logger1 = ActivityLogger().get_logger(&amp;#x27;note1&amp;#x27;)
logger1.info(&amp;quot;тестовое сообщение note 1&amp;quot;)

logger2 = ActivityLogger().get_logger(&amp;#x27;note2&amp;#x27;)
logger2.info(&amp;quot;тестовое сообщение note 2&amp;quot;)&lt;/pre&gt;
  &lt;figure id=&quot;yV5a&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/ca/f7/caf7350f-094c-4c15-b50c-17c6fcded1ac.png&quot; width=&quot;1045&quot; /&gt;
  &lt;/figure&gt;
  &lt;figure id=&quot;8j7k&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/82/17/8217ecb8-5801-4300-879e-99f958469884.png&quot; width=&quot;1058&quot; /&gt;
  &lt;/figure&gt;
  &lt;figure id=&quot;Tskm&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/aa/09/aa09369f-5692-4883-b02f-ee97b69dc0e3.png&quot; width=&quot;1036&quot; /&gt;
  &lt;/figure&gt;
  &lt;figure id=&quot;oJ9k&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/97/f3/97f31ed9-4679-4137-a79b-f7b9d227392f.png&quot; width=&quot;1050&quot; /&gt;
  &lt;/figure&gt;
  &lt;tt-tags id=&quot;BECw&quot;&gt;
    &lt;tt-tag name=&quot;logger&quot;&gt;#logger&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;logging&quot;&gt;#logging&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;activitylogger&quot;&gt;#activitylogger&lt;/tt-tag&gt;
  &lt;/tt-tags&gt;

</content></entry><entry><id>dt_analytic:6NXbvm7_1G5</id><link rel="alternate" type="text/html" href="https://teletype.in/@dt_analytic/6NXbvm7_1G5?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=dt_analytic"></link><title>Как настроить окружение с PyTorch и CUDA</title><published>2025-05-05T07:32:17.463Z</published><updated>2025-05-05T07:32:17.463Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img4.teletype.in/files/32/67/32676516-b6d4-4b1a-902b-3aef67a21f51.png"></media:thumbnail><category term="python" label="python"></category><tt:hashtag>pytorch</tt:hashtag><tt:hashtag>nn</tt:hashtag><tt:hashtag>venv</tt:hashtag><tt:hashtag>conda</tt:hashtag><summary type="html">&lt;img src=&quot;https://img3.teletype.in/files/25/8c/258cf292-498c-4719-bad7-93f849d827c7.png&quot;&gt;&quot;Путь к успеху начинается с первого шага&quot;. Даже для опытных пользователей процесс настройки окружения с PyTorch и CUDA может превратиться в настоящую головную боль, если нет четкого алгоритма. Поэтому описание порядка установки станет в центре внимания в данном материале .</summary><content type="html">
  &lt;figure id=&quot;7n92&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/25/8c/258cf292-498c-4719-bad7-93f849d827c7.png&quot; width=&quot;1233&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;DLJA&quot;&gt;&amp;quot;&lt;strong&gt;Путь к успеху начинается с первого шага&lt;/strong&gt;&amp;quot;. Даже для опытных пользователей процесс настройки окружения с &lt;strong&gt;PyTorch&lt;/strong&gt; и &lt;strong&gt;CUDA &lt;/strong&gt;может превратиться в настоящую головную боль, если нет четкого алгоритма. Поэтому описание порядка установки станет в центре внимания в данном материале .&lt;/p&gt;
  &lt;p id=&quot;EzAh&quot;&gt;Первый этап - сбор информации о видеокарте, поддерживаемой версии CUDA и ее установка (все этапы тестировал на Windows). &lt;/p&gt;
  &lt;p id=&quot;V3Xu&quot;&gt;1) Инфо о видеокарте можно получить через браузер &lt;strong&gt;Chrome&lt;/strong&gt;:&lt;/p&gt;
  &lt;pre id=&quot;2aOD&quot;&gt;chrome://gpu/&lt;/pre&gt;
  &lt;figure id=&quot;Lcka&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/a6/8c/a68c7a39-36e1-4013-845c-e2cf4cac3708.png&quot; width=&quot;1272&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;rC9H&quot;&gt;2) Далее гуглим, какая &lt;strong&gt;версия CUDA&lt;/strong&gt; поддерживается вашей видеокартой, и скачиваем с официального сайта (в моем случае - CUDA 11.8 взял &lt;a href=&quot;https://developer.nvidia.com/cuda-11-8-0-download-archive&quot; target=&quot;_blank&quot;&gt;тут&lt;/a&gt;) и устанавливаем. О подробностях инсталляции и &lt;strong&gt;CUDA &lt;/strong&gt;можно почитать &lt;a href=&quot;https://docs.nvidia.com/cuda/cuda-installation-guide-microsoft-windows/index.html&quot; target=&quot;_blank&quot;&gt;на том же ресурсе&lt;/a&gt; (в целом процесс не отличается от установки обычной программы).&lt;/p&gt;
  &lt;p id=&quot;DvUN&quot;&gt;3) Если не прописана переменная среды &lt;strong&gt;CUDA_PATH&lt;/strong&gt;, то создаем ее с указанием на папку с &lt;strong&gt;CUDA&lt;/strong&gt;:&lt;/p&gt;
  &lt;p id=&quot;KGcG&quot;&gt;&lt;/p&gt;
  &lt;figure id=&quot;QcEN&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/30/21/30216441-5680-44d8-989d-1a0e4efc8a92.png&quot; width=&quot;1298&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;mLeB&quot;&gt;4) Проверка &lt;/p&gt;
  &lt;p id=&quot;Whk4&quot;&gt;инфо о &lt;strong&gt;CUDA&lt;/strong&gt;:&lt;/p&gt;
  &lt;pre id=&quot;SJA7&quot;&gt; nvcc -V&lt;/pre&gt;
  &lt;p id=&quot;vLOL&quot;&gt;+ мониторинг использования ГПУ:&lt;/p&gt;
  &lt;pre id=&quot;ThJQ&quot;&gt;nvidia-smi&lt;/pre&gt;
  &lt;figure id=&quot;O3UG&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/7b/53/7b5314b8-fd5e-4ff3-a545-012ca3a0e88f.png&quot; width=&quot;1095&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;IjRG&quot;&gt;5) Далее создаем виртуальное окружение (я делаю это с &lt;strong&gt;conda&lt;/strong&gt;):&lt;/p&gt;
  &lt;pre id=&quot;KoQi&quot;&gt;conda create -y --prefix D:/dev/envs/pytorch_env python=3.10&lt;/pre&gt;
  &lt;figure id=&quot;PhoX&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/1a/59/1a5939f4-d4f7-4b44-8fd2-337b31dee9ff.png&quot; width=&quot;1119&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;hE7O&quot;&gt;6) На сайте &lt;strong&gt;PyTorch&lt;/strong&gt; берем команды инсталляции пакета и исполняем их:&lt;/p&gt;
  &lt;p id=&quot;RpAH&quot;&gt;&lt;a href=&quot;https://pytorch.org/get-started/locally/&quot; target=&quot;_blank&quot;&gt;для самой свежей версии&lt;/a&gt;&lt;/p&gt;
  &lt;p id=&quot;gWtr&quot;&gt;&lt;a href=&quot;https://pytorch.org/get-started/previous-versions/&quot; target=&quot;_blank&quot;&gt;для более старых + установка с conda&lt;/a&gt; &lt;/p&gt;
  &lt;p id=&quot;sfNw&quot;&gt;В моем случае сработали команды:&lt;/p&gt;
  &lt;p id=&quot;nylY&quot;&gt;для cuda 11.8:&lt;/p&gt;
  &lt;pre id=&quot;ZatQ&quot;&gt;conda install pytorch==2.3.0 torchvision==0.18.0 torchaudio==2.3.0 pytorch-cuda=11.8 -c pytorch -c nvidia&lt;/pre&gt;
  &lt;p id=&quot;y7kp&quot;&gt;для cuda 10.1:&lt;/p&gt;
  &lt;pre id=&quot;jqum&quot;&gt;pip install torch==1.8.1+cu101 torchvision==0.9.1+cu101torchaudio==0.8.1 -f https://download.pytorch.org/whl/torch_stable.html&lt;/pre&gt;
  &lt;pre id=&quot;96US&quot;&gt;conda install pytorch torchvision torchaudio cudatoolkit=10.1 -c pytorch&lt;/pre&gt;
  &lt;p id=&quot;jVNJ&quot;&gt;&lt;/p&gt;
  &lt;figure id=&quot;9YaG&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/fd/4b/fd4b8827-4ae6-43d7-9e09-976a7e1337e3.png&quot; width=&quot;1108&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;05Lb&quot;&gt;...&lt;/p&gt;
  &lt;figure id=&quot;Cyff&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/ab/a2/aba2f3ac-a6d4-400f-90e8-b701b31b78ae.png&quot; width=&quot;1075&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;TH8a&quot;&gt;7) Проверяем доступность &lt;strong&gt;CUDA&lt;/strong&gt;:&lt;/p&gt;
  &lt;pre id=&quot;no4m&quot;&gt;python -c &amp;quot;import torch;print(torch.cuda.is_available())&amp;quot;&lt;/pre&gt;
  &lt;figure id=&quot;iKq1&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/62/64/6264de83-5325-43c2-8644-1ca0a4863c12.png&quot; width=&quot;1063&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;QXDF&quot;&gt;8) Напоминаю команды создания kernel-а из действующего окружения для jupyter (подробнее &lt;a href=&quot;https://dzen.ru/a/Yuv0Q1xRhkeqdtUx&quot; target=&quot;_blank&quot;&gt;писал тут&lt;/a&gt;):&lt;/p&gt;
  &lt;pre id=&quot;DIfA&quot;&gt;pip install ipykernel&lt;/pre&gt;
  &lt;pre id=&quot;pFuS&quot;&gt;python -m ipykernel install --user --name имя_среды &lt;/pre&gt;
  &lt;p id=&quot;BAOf&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;LRVL&quot;&gt;Вот как выглядит результат &lt;strong&gt;nvidia-smi&lt;/strong&gt; во время работы скрипта, использующего ГПУ:&lt;/p&gt;
  &lt;figure id=&quot;mBtb&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/2d/dc/2ddc664a-3271-4259-9b36-443e937a75a6.png&quot; width=&quot;1045&quot; /&gt;
  &lt;/figure&gt;
  &lt;tt-tags id=&quot;o0eY&quot;&gt;
    &lt;tt-tag name=&quot;pytorch&quot;&gt;#pytorch&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;nn&quot;&gt;#nn&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;venv&quot;&gt;#venv&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;conda&quot;&gt;#conda&lt;/tt-tag&gt;
  &lt;/tt-tags&gt;

</content></entry><entry><id>dt_analytic:HGtFYGEUMni</id><link rel="alternate" type="text/html" href="https://teletype.in/@dt_analytic/HGtFYGEUMni?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=dt_analytic"></link><title>Модуль inspect и самый частый код разработчика, который можно упростить до пары строк</title><published>2025-02-22T13:24:11.865Z</published><updated>2025-09-15T05:52:41.860Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img3.teletype.in/files/aa/f8/aaf8f709-13cf-49f6-be83-abadc8cfbc0d.png"></media:thumbnail><category term="python" label="python"></category><tt:hashtag>python</tt:hashtag><tt:hashtag>inspect</tt:hashtag><tt:hashtag>store_attr</tt:hashtag><tt:hashtag>frame</tt:hashtag><tt:hashtag>getmodule</tt:hashtag><tt:hashtag>copy_attr</tt:hashtag><tt:hashtag>copy_args</tt:hashtag><tt:hashtag>debug</tt:hashtag><summary type="html">&lt;img src=&quot;https://img3.teletype.in/files/e8/bc/e8bc7897-4c60-4eba-9c3f-d9a4fe9621ef.png&quot;&gt;Превратите сложные задачи в простые: узнайте, как модуль inspect помогает разработчикам отлаживать и лучше понимать чужой код, а также сокращать время, затрачиваемое на рутинные действия.</summary><content type="html">
  &lt;figure id=&quot;CYKm&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/e8/bc/e8bc7897-4c60-4eba-9c3f-d9a4fe9621ef.png&quot; width=&quot;869&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;sANf&quot;&gt;Превратите сложные задачи в простые: узнайте, как модуль &lt;strong&gt;inspect &lt;/strong&gt;помогает разработчикам отлаживать и лучше понимать чужой код, а также сокращать время, затрачиваемое на рутинные действия.&lt;/p&gt;
  &lt;p id=&quot;5DFi&quot;&gt;Начнем с описания самых простых и полезных функций модуля. &lt;/p&gt;
  &lt;h2 id=&quot;Odc9&quot;&gt;getmodule и getfile&lt;/h2&gt;
  &lt;p id=&quot;xS9h&quot;&gt;&lt;strong&gt;getmodule &lt;/strong&gt;и &lt;strong&gt;getfile &lt;/strong&gt;позволяют получить имя модуля и файла, в которых определен импортированный объект:&lt;/p&gt;
  &lt;pre id=&quot;rfgA&quot; data-lang=&quot;python&quot;&gt;import inspect
from fastai.vision.all import *

inspect.getmodule(L)&lt;/pre&gt;
  &lt;pre id=&quot;I5Ge&quot;&gt;inspect.getfile(L)&lt;/pre&gt;
  &lt;figure id=&quot;w1bn&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/e2/bb/e2bb4638-24ac-47f1-b266-6ca350b03ed7.png&quot; width=&quot;786&quot; /&gt;
  &lt;/figure&gt;
  &lt;h2 id=&quot;qOQl&quot;&gt;function signature&lt;/h2&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;7W5I&quot;&gt;Для получения описания параметров и значений по умолчанию исследуемой функции обратитесь к &lt;strong&gt;signature&lt;/strong&gt;:&lt;/p&gt;
  &lt;pre id=&quot;NkjG&quot; data-lang=&quot;python&quot;&gt;def f(a, b:list=[2]):
  pass

sig = inspect.signature(f)

for name, param in sig.parameters.items():
    print(f&amp;quot;Parameter: {name}&amp;quot;)
    print(f&amp;quot;  Default: {param.default}&amp;quot;)
    print(f&amp;quot;  Annotation: {param.annotation}&amp;quot;)
    print(f&amp;quot;  Kind: {param.kind}&amp;quot;)
    print()&lt;/pre&gt;
  &lt;figure id=&quot;4Pxh&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/9a/9a/9a9a440f-c8c7-42d6-9bb5-186607c20e89.png&quot; width=&quot;670&quot; /&gt;
  &lt;/figure&gt;
  &lt;h2 id=&quot;3hZ0&quot;&gt;frame&lt;/h2&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;TaEf&quot;&gt;Пожалуй, самым полезным объектом модуля является фрейм/блок. Функция &lt;strong&gt;currentframe &lt;/strong&gt;возвращает ссылку на текущий блок кода, у которого есть следующие важные атрибуты:&lt;/p&gt;
  &lt;ul id=&quot;HqkM&quot;&gt;
    &lt;li id=&quot;ZLTw&quot;&gt;&lt;strong&gt;f_locals &lt;/strong&gt;- словарь локальных переменных&lt;/li&gt;
    &lt;li id=&quot;t4b7&quot;&gt;&lt;strong&gt;f_globals &lt;/strong&gt;- словарь глобальных переменных&lt;/li&gt;
    &lt;li id=&quot;y7iI&quot;&gt;&lt;strong&gt;f_back &lt;/strong&gt;- позволяет обратиться к фрейму на уровень выше&lt;/li&gt;
    &lt;li id=&quot;Iizz&quot;&gt;&lt;strong&gt;f_code &lt;/strong&gt;- объект кода, привязанный к фрейму, как правило, описывает функцию, в которой происходит выполнение блока. В свою очередь, имеет атрибут &lt;strong&gt;co_varnames&lt;/strong&gt;, содержащий имена аргументов и локальных переменных;&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;XSQa&quot;&gt;Ниже демонстрируются эти свойства фреймов:&lt;/p&gt;
  &lt;pre id=&quot;gQ9r&quot; data-lang=&quot;python&quot;&gt;def f2(a=1):
  frame = inspect.currentframe()
  print(f&amp;#x27;f2 local vars - {(frame.f_locals.items())}&amp;#x27;)
  print(f&amp;#x27;f2 func vars and locals - {frame.f_code.co_varnames}&amp;#x27;)
  print(f&amp;#x27;f1 func vars and locals - {frame.f_back.f_code.co_varnames}&amp;#x27;)
  print(f&amp;#x27;f0 func vars and locals - {frame.f_back.f_back.f_code.co_varnames}&amp;#x27;)

def f1(b):
  f2()

def f0(c=2):
  f1(2)

f0()&lt;/pre&gt;
  &lt;figure id=&quot;HoLS&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/d3/8d/d38d08af-9029-4037-a4cf-aa73ec1295ad.png&quot; width=&quot;749&quot; /&gt;
  &lt;/figure&gt;
  &lt;h2 id=&quot;Lr9W&quot;&gt;&lt;strong&gt;store_attr &lt;/strong&gt;&lt;/h2&gt;
  &lt;p id=&quot;0gn9&quot;&gt;Представленные выше свойства можно использовать для автоматизации присвоения внутренним атрибутам значений переменных, передаваемых в конструкторе класса, вида:&lt;/p&gt;
  &lt;p id=&quot;dq9L&quot;&gt;self.a=a&lt;/p&gt;
  &lt;p id=&quot;3alq&quot;&gt;...&lt;/p&gt;
  &lt;p id=&quot;gHYB&quot;&gt;Этот шаблонный код, пожалуй, писал каждый питонист хотя бы раз.&lt;/p&gt;
  &lt;pre id=&quot;QKaN&quot; data-lang=&quot;python&quot;&gt;class C():

    def __init__(self, a, b):
        frame = inspect.currentframe()
        for k, v in frame.f_locals.items():
          setattr(self, k, v)

item = C(a=3, b=[1, 3])
item.a, item.b&lt;/pre&gt;
  &lt;figure id=&quot;8CZc&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/c8/c2/c8c2d14a-ccf6-495e-95f0-86fe8700e582.png&quot; width=&quot;723&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;YSAS&quot;&gt;Если делать то же через функцию, то понадобится обратиться к вышестоящему фрейму:&lt;/p&gt;
  &lt;pre id=&quot;aaIo&quot; data-lang=&quot;python&quot;&gt;def copy_args():

    frame = inspect.currentframe().f_back
    code = frame.f_code
    args = code.co_varnames

    self = frame.f_locals[args[0]]
    for k, v in frame.f_locals.items():
      setattr(self, k, v)

class C():
    def __init__(self, a, b):
        copy_args()

item = C(a=3, b=[1, 3])
item.a, item.b&lt;/pre&gt;
  &lt;figure id=&quot;Fma1&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/7a/3e/7a3eb212-7ed6-4835-a94b-354551293d83.png&quot; width=&quot;719&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;6nFy&quot;&gt;Схожий функционал заложен в функции &lt;strong&gt;store_attr &lt;/strong&gt;из модуля &lt;strong&gt;fastcore.basics&lt;/strong&gt;:&lt;/p&gt;
  &lt;pre id=&quot;yB1F&quot; data-lang=&quot;python&quot;&gt;from fastcore.basics import store_attr

class C():
    def __init__(self, a, b):
        store_attr()

item = C(a=3, b=[1, 3])
item.a, item.b&lt;/pre&gt;
  &lt;figure id=&quot;TwIi&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/06/25/06258e89-cd04-4cc7-be59-2a44f9280262.png&quot; width=&quot;728&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;WAlQ&quot;&gt;Можно часть параметров сохранить через &lt;strong&gt;store_attr&lt;/strong&gt;,перечислив их в скобках через запятую, а часть определить самим:&lt;/p&gt;
  &lt;pre id=&quot;wKXx&quot; data-lang=&quot;python&quot;&gt;from fastcore.basics import store_attr

class C():
    def __init__(self, a, b, c):
        store_attr(&amp;#x27;a, c&amp;#x27;)
        self.b = a+c

item = C(a=3, b=3, c=5)
item.a, item.b, item.c&lt;/pre&gt;
  &lt;h2 id=&quot;Abla&quot;&gt;&lt;strong&gt;stack &lt;/strong&gt;&lt;/h2&gt;
  &lt;p id=&quot;qf0H&quot;&gt;Еще посредством функции &lt;strong&gt;stack &lt;/strong&gt;модуля &lt;strong&gt;inspect &lt;/strong&gt;из произвольной строки можно получить информацию о стеке вызовов по аналогии с тем, который выводится при ошибке. Пусть у нас есть модуль:&lt;/p&gt;
  &lt;figure id=&quot;BzMd&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/6a/19/6a19dff4-7922-499d-8898-f783bb89b675.png&quot; width=&quot;799&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;Zhzn&quot;&gt;После вызова f0 мы получим информацию о номере строки текущего фрейма (&lt;strong&gt;lineno&lt;/strong&gt;), функции (&lt;strong&gt;function&lt;/strong&gt;) и файле, в котором она находится (&lt;strong&gt;filename&lt;/strong&gt;). Кроме того, ниже из стека выводится информация о служебных инструментах, которые используются collab-ом:&lt;/p&gt;
  &lt;pre id=&quot;Uib4&quot; data-lang=&quot;python&quot;&gt;import sys
sys.path.append(&amp;#x27;/content/drive/MyDrive/Colab Notebooks&amp;#x27;)
from my_funcs.module import f0

f0()&lt;/pre&gt;
  &lt;figure id=&quot;wxXE&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/0d/22/0d223e00-338a-43eb-a039-614593807c23.png&quot; width=&quot;854&quot; /&gt;
  &lt;/figure&gt;
  &lt;tt-tags id=&quot;dhKC&quot;&gt;
    &lt;tt-tag name=&quot;python&quot;&gt;#python&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;inspect&quot;&gt;#inspect&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;store_attr&quot;&gt;#store_attr&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;frame&quot;&gt;#frame&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;getmodule&quot;&gt;#getmodule&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;copy_attr&quot;&gt;#copy_attr&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;copy_args&quot;&gt;#copy_args&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;debug&quot;&gt;#debug&lt;/tt-tag&gt;
  &lt;/tt-tags&gt;

</content></entry><entry><id>dt_analytic:mzSTJ5hRZnn</id><link rel="alternate" type="text/html" href="https://teletype.in/@dt_analytic/mzSTJ5hRZnn?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=dt_analytic"></link><title>Защита реквизитов с Python</title><published>2024-10-17T13:13:17.805Z</published><updated>2024-10-17T13:17:51.501Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img2.teletype.in/files/d8/30/d830ebbf-3f08-4136-becd-a1c6bec84c44.png"></media:thumbnail><category term="python" label="python"></category><tt:hashtag>secret</tt:hashtag><tt:hashtag>python</tt:hashtag><tt:hashtag>system</tt:hashtag><tt:hashtag>credentials</tt:hashtag><summary type="html">&lt;img src=&quot;https://img2.teletype.in/files/d2/06/d206bbd7-8921-47e1-af68-892b05b80284.png&quot;&gt;&quot;Конфиденциальность — это не только право, это основа свободы.&quot; В эпоху цифровых технологий, когда данные становятся всё более ценным ресурсом, защита личной информации приобретает критическое значение. В этой статье я расскажу, как работать с конфиденциальными реквизитами в Python проекте.</summary><content type="html">
  &lt;figure id=&quot;V7nw&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/d2/06/d206bbd7-8921-47e1-af68-892b05b80284.png&quot; width=&quot;854&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;tbCd&quot;&gt;&amp;quot;Конфиденциальность — это не только право, это основа свободы.&amp;quot; В эпоху цифровых технологий, когда данные становятся всё более ценным ресурсом, защита личной информации приобретает критическое значение. В этой статье я расскажу, как работать с конфиденциальными реквизитами в Python проекте.&lt;/p&gt;
  &lt;h1 id=&quot;jyWT&quot;&gt;load_dotenv&lt;/h1&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;FDAc&quot;&gt;Первый способ - использовать функцию &lt;strong&gt;load_dotenv &lt;/strong&gt;из модуля &lt;strong&gt;dotenv&lt;/strong&gt;. Она позволяет считать строки вида ключ=значение из файла и загрузить их в переменные окружения с именем ключа. Обычно таким образом задаются конфиденциальные данные, как пароли, ключи API, которые не следует хранить в коде и тем более заливать в репозиторий. &lt;/p&gt;
  &lt;p id=&quot;6pql&quot;&gt;Отмечу, что этот способ подойдет, если злоумышленник не имеет доступ к локальным файлам, так как пароль хранится в открытом виде. Продемонстрируем работу на практике. Сначала установим модуль &lt;strong&gt;python-dotenv &lt;/strong&gt;и создадим файл:&lt;/p&gt;
  &lt;pre id=&quot;KqHd&quot; data-lang=&quot;python&quot;&gt;!pip install python-dotenv -q

!mkdir pers
!printf &amp;#x27;&amp;#x27;&amp;#x27; USER=&amp;quot;user&amp;quot;\n\
PSWD=&amp;quot;1pswd1&amp;quot; &amp;#x27;&amp;#x27;&amp;#x27; &amp;gt; pers/.env

!cat .env&lt;/pre&gt;
  &lt;figure id=&quot;1BZZ&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/3b/21/3b21243b-db77-4277-9450-665bfc8bc483.png&quot; width=&quot;1096&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;L9q1&quot;&gt;Теперь вызовем &lt;strong&gt;load_dotenv &lt;/strong&gt;с указанием пути к файлу:&lt;/p&gt;
  &lt;pre id=&quot;oJCQ&quot; data-lang=&quot;python&quot;&gt;from dotenv import load_dotenv

load_dotenv(&amp;#x27;pers/.env&amp;#x27;)&lt;/pre&gt;
  &lt;figure id=&quot;8HDp&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/04/f6/04f60c42-e1bd-4eec-b4f9-7f66a166661c.png&quot; width=&quot;1109&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;dqnB&quot;&gt;После этого переменные из файла доступны через окружение:&lt;/p&gt;
  &lt;pre id=&quot;Q1EF&quot; data-lang=&quot;python&quot;&gt;import os
os.environ[&amp;#x27;USER&amp;#x27;], os.environ[&amp;#x27;PSWD&amp;#x27;]&lt;/pre&gt;
  &lt;figure id=&quot;souw&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/4c/9f/4c9f6527-405d-4eed-a916-fda2c0944ea2.png&quot; width=&quot;1132&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;HhXC&quot;&gt;Если все равно страшно хранить реквизиты в открытом файле, можно немного усложнить и, например, хранить часть пароля в файле, а часть добавлять из кода (но это все равно не безопасное решение). В функции ниже прописано такое поведение - при отсутствии создается файл с реквизитами (лучше, чтобы каждый раз при старте сессии, после удалять), при этом первый и последний символы, пароля не хранятся в файле, а добавляются в коде:&lt;/p&gt;
  &lt;pre id=&quot;OWX1&quot; data-lang=&quot;python&quot;&gt;from getpass import getpass

def get_creds():

    if not os.path.exists(&amp;#x27;pers/.env&amp;#x27;):
        cred = getpass()
        with open(&amp;#x27;pers/.env&amp;#x27;, &amp;#x27;wt&amp;#x27;) as f_wr:
            f_wr.write(f&amp;#x27;PSWD={cred[1:-1]}&amp;#x27;)

    load_dotenv(&amp;#x27;pers/.env&amp;#x27;)
    PSWD = &amp;#x27;1&amp;#x27;+os.environ[&amp;#x27;PSWD&amp;#x27;]+&amp;#x27;1&amp;#x27;

    return PSWD return PSWD&lt;/pre&gt;
  &lt;figure id=&quot;CHKT&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/cc/39/cc39b7ec-d781-47de-bf17-b89d5be06c28.png&quot; width=&quot;1123&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;NTEE&quot;&gt;Удалим файл, старое значением переменной окружения и вызовем функцию:&lt;/p&gt;
  &lt;pre id=&quot;Pbnr&quot;&gt;!rm pers/.env&lt;/pre&gt;
  &lt;pre id=&quot;Xl57&quot; data-lang=&quot;python&quot;&gt;del os.environ[&amp;#x27;PSWD&amp;#x27;]&lt;/pre&gt;
  &lt;pre id=&quot;arga&quot; data-lang=&quot;python&quot;&gt;USER = &amp;#x27;user&amp;#x27;
PSWD = get_creds()
PSWD&lt;/pre&gt;
  &lt;figure id=&quot;2Ghz&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/7e/15/7e159b8c-80a3-438c-8e88-f69126aaddc5.png&quot; width=&quot;1107&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;hAbA&quot;&gt;Пароль правильный и он не хранится в файле полностью:&lt;/p&gt;
  &lt;pre id=&quot;oqvH&quot; data-lang=&quot;python&quot;&gt;!cat pers/.env&lt;/pre&gt;
  &lt;figure id=&quot;lGxf&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/c4/60/c460a41f-5ee6-437b-9e98-ebe61a24e56b.png&quot; width=&quot;1104&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;Iwnu&quot;&gt;Если вы делаете проект, который будет запускать лицо с другими реквизитами (например, заказчик), удобно функцию &lt;strong&gt;get_creds &lt;/strong&gt;не показывать, а объявить в отдельно модуле, который не попадет в репозиторий. При этом в отдельном общедоступном py файле прописать переменные &lt;strong&gt;USER = &amp;#x27;user&amp;#x27;, PSWD = get_creds()&lt;/strong&gt;. Во время передачи проекта указать, что следует задать в переменной &lt;strong&gt;PSWD &lt;/strong&gt;пароль для запуска или для большей безопасности прописать там &lt;strong&gt;getpass&lt;/strong&gt;.&lt;/p&gt;
  &lt;h1 id=&quot;wuS2&quot;&gt;keyring&lt;/h1&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;2Ktc&quot;&gt;Когда существует опасность доступа злоумышленника к вашим файлам, надежным способом хранения реквизитов является их шифрование. Как вариант, можно воспользоваться модулем &lt;strong&gt;keyring&lt;/strong&gt;. Сначала установим необходимые библиотеки:&lt;/p&gt;
  &lt;pre id=&quot;meNK&quot;&gt;pip install keyring keyrings.alt pycryptodome -q&lt;/pre&gt;
  &lt;pre id=&quot;O3tC&quot; data-lang=&quot;python&quot;&gt;import keyring
from keyrings.alt.file import EncryptedKeyring&lt;/pre&gt;
  &lt;figure id=&quot;eYPF&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/22/3c/223c6796-b1ae-4396-acc1-30c26d6b4c54.png&quot; width=&quot;1120&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;XvyY&quot;&gt;Зададим тип хранилища:&lt;/p&gt;
  &lt;pre id=&quot;EpeG&quot; data-lang=&quot;python&quot;&gt;keyring.set_keyring(EncryptedKeyring())&lt;/pre&gt;
  &lt;figure id=&quot;mxzZ&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/24/37/2437cc08-0763-4633-b145-9cdb8c215169.png&quot; width=&quot;1120&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;2BB2&quot;&gt;Для записи или обновления пароля можно использовать функцию &lt;strong&gt;set_password &lt;/strong&gt;модуля &lt;strong&gt;keyring&lt;/strong&gt;. Первый параметр - имя сервиса (ключа), к которому привязан пароль:&lt;/p&gt;
  &lt;pre id=&quot;1cQS&quot;&gt;keyring.set_password(&amp;#x27;main&amp;#x27;, &amp;#x27;user&amp;#x27;, &amp;#x27;1pswd1&amp;#x27;)&lt;/pre&gt;
  &lt;figure id=&quot;tmE5&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/43/d2/43d23d8d-c619-4595-8dd4-6933e800e975.png&quot; width=&quot;1140&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;I34D&quot;&gt;Для получения пароля необходимо указать имя сервиса и логин, а функция при первом ее вызове потребует ввод пароля хранилища, который задавался в &lt;strong&gt;set_password&lt;/strong&gt;:&lt;/p&gt;
  &lt;pre id=&quot;kKF1&quot; data-lang=&quot;python&quot;&gt;keyring.get_password(&amp;#x27;main&amp;#x27;, &amp;#x27;user&amp;#x27;)&lt;/pre&gt;
  &lt;figure id=&quot;xVFW&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/8b/dc/8bdc6d1c-428b-4f0c-9718-0ec326b23e55.png&quot; width=&quot;1100&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;MIpP&quot;&gt;Для получения пути к файлу с зашифрованным паролем можно вызвать атрибут &lt;strong&gt;file_path &lt;/strong&gt;класса &lt;strong&gt;EncryptedKeyring&lt;/strong&gt;:&lt;/p&gt;
  &lt;pre id=&quot;GBNy&quot; data-lang=&quot;python&quot;&gt;EncryptedKeyring().file_path&lt;/pre&gt;
  &lt;pre id=&quot;NyVi&quot;&gt;!cat /root/.local/share/python_keyring/crypted_pass.cfg&lt;/pre&gt;
  &lt;figure id=&quot;6YiL&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/0b/da/0bda648a-1cd5-43f4-b2a8-b0a4a7115014.png&quot; width=&quot;1110&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;g9bb&quot;&gt;Также есть и другие способы получения пути к файлу с реквизитами, которые в зависимости от системы могут сработать или нет:&lt;/p&gt;
  &lt;ol id=&quot;53Ai&quot;&gt;
    &lt;li id=&quot;ruFO&quot;&gt;&lt;strong&gt;keyring.get_keyring()&lt;/strong&gt; в ячейке&lt;/li&gt;
    &lt;li id=&quot;SghJ&quot;&gt;&lt;strong&gt;keyring diagnose&lt;/strong&gt; в терминале&lt;/li&gt;
  &lt;/ol&gt;
  &lt;tt-tags id=&quot;9Vo0&quot;&gt;
    &lt;tt-tag name=&quot;secret&quot;&gt;#secret&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;python&quot;&gt;#python&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;system&quot;&gt;#system&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;credentials&quot;&gt;#credentials&lt;/tt-tag&gt;
  &lt;/tt-tags&gt;

</content></entry><entry><id>dt_analytic:crMH2h96eAh</id><link rel="alternate" type="text/html" href="https://teletype.in/@dt_analytic/crMH2h96eAh?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=dt_analytic"></link><title>Визуализация матрицы расхождений - ключ к пониманию ошибок классификации</title><published>2024-08-09T13:58:55.620Z</published><updated>2024-08-09T14:05:11.424Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img2.teletype.in/files/53/b5/53b5a3ea-deee-4b5f-9ac2-140dfbacbdad.png"></media:thumbnail><category term="vizualizaciya" label="визуализация"></category><tt:hashtag>vis</tt:hashtag><tt:hashtag>draw</tt:hashtag><tt:hashtag>ml</tt:hashtag><tt:hashtag>evaluation</tt:hashtag><summary type="html">&lt;img src=&quot;https://img1.teletype.in/files/01/74/017499ff-471c-4598-b417-ffad0b2bcda0.png&quot;&gt;«Ошибки — это наука, помогающая нам двигаться вперёд», — говорил Уильям Ченнинг. Визуализация - отличный инструмент, который помогает анализировать данные и выявлять закономерности.</summary><content type="html">
  &lt;figure id=&quot;s3VO&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/01/74/017499ff-471c-4598-b417-ffad0b2bcda0.png&quot; width=&quot;761&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;UDdD&quot;&gt;«&lt;strong&gt;Ошибки — это наука, помогающая нам двигаться вперёд&lt;/strong&gt;», — говорил Уильям Ченнинг. Визуализация - отличный инструмент, который помогает анализировать данные и выявлять закономерности. &lt;/p&gt;
  &lt;p id=&quot;oIKF&quot;&gt;Рассмотрим удобный способ отображения в &lt;strong&gt;Python&lt;/strong&gt; одной из метрик классификации под названием &lt;strong&gt;confusion matrix &lt;/strong&gt;(на русский переводят по-разному - матрица ошибок, неточностей, расхождений или несоответствий).&lt;/p&gt;
  &lt;p id=&quot;QhGv&quot;&gt;Сначала загрузим демонстрационный датасет.&lt;/p&gt;
  &lt;pre id=&quot;h6iI&quot;&gt;import numpy as np
import pandas as pd

from sklearn.datasets import load_iris
from sklearn.linear_model import LogisticRegression

df = load_iris(as_frame=True)[&amp;#x27;frame&amp;#x27;]
d = {k:v for k, v in enumerate(load_iris().target_names)}
df[&amp;#x27;target&amp;#x27;] = df[&amp;#x27;target&amp;#x27;].map(d)
df = df.sample(frac=1, random_state=0)

df.head()&lt;/pre&gt;
  &lt;figure id=&quot;YpRG&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/e6/5d/e65de6f3-461e-4a75-aa97-82014b775228.png&quot; width=&quot;935&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;lzlG&quot;&gt;Имитируем обучение модели и предсказание, не проводя разбиения на выборки, так как наша цель - показать возможности для визуализации:&lt;/p&gt;
  &lt;pre id=&quot;jLXW&quot;&gt;model = LogisticRegression(random_state=0, max_iter=1000).fit(df.drop(columns=&amp;#x27;target&amp;#x27;), df.target)

y_p = model.predict(df.drop(columns=&amp;#x27;target&amp;#x27;))&lt;/pre&gt;
  &lt;p id=&quot;69rK&quot;&gt;Теперь получим значения ошибок, воспользовавшись функцией &lt;strong&gt;confusion_matrix &lt;/strong&gt;из модуля &lt;strong&gt;sklearn.metrics&lt;/strong&gt;:&lt;/p&gt;
  &lt;pre id=&quot;EKK1&quot;&gt;from sklearn.metrics import confusion_matrix

labels = np.sort(df[&amp;#x27;target&amp;#x27;].unique())
cm = confusion_matrix(y_true = df[&amp;#x27;target&amp;#x27;], y_pred = y_p,
                      labels=labels,
                      normalize=None)
cm&lt;/pre&gt;
  &lt;figure id=&quot;0gHI&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/ce/a1/cea1fd27-a32d-4d33-ad38-a073f8056f7c.png&quot; width=&quot;890&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;sbcT&quot;&gt;В строке i и колонке j матрицы располагаются значения, соответствующие количеству объектов класса i, которые предсказаны как j. Значения классов берутся, как метки встретившиеся хотя бы раз в y_true или y_pred упорядоченные по возрастанию. Я намеренно передаю метки явно в параметре labels для демонстрации этого поведения (этим же параметром, можно поменять порядок вывода или указать подмножество/список меток для вывода).&lt;/p&gt;
  &lt;h2 id=&quot;L8EP&quot;&gt;matshow&lt;/h2&gt;
  &lt;p id=&quot;5kPu&quot;&gt;Визуализацию начнем с низкоуровневых способов &lt;strong&gt;matplotlib &lt;/strong&gt;закончим более быстрыми. Первым кандидатом будет &lt;strong&gt;matshow &lt;/strong&gt;модуля &lt;strong&gt;matplotlib.pyplot&lt;/strong&gt;, которая предоставляет полотно, а элементы потребуется добавлять самостоятельно. Ниже показано, как задать размеры картинки, метки классов, а также дополнить ячейки значениями матрицы через текстовые элементы (большинство настроек разбирались ранее &lt;a href=&quot;https://dzen.ru/a/YSXY1ljCwRwFy6Da&quot; target=&quot;_blank&quot;&gt;здесь&lt;/a&gt; и&lt;a href=&quot;https://dzen.ru/a/YRyXhDTPoGnRVDu4&quot; target=&quot;_blank&quot;&gt;здесь&lt;/a&gt;):&lt;/p&gt;
  &lt;pre id=&quot;7iEQ&quot;&gt;import matplotlib.pyplot as plt
fig = plt.figure(figsize=(5, 5))

plt.matshow(cm, alpha=1, cmap=&amp;#x27;coolwarm&amp;#x27;, fignum=fig.number)

plt.xticks(range(len(labels)), labels, rotation=&amp;#x27;vertical&amp;#x27;)
plt.yticks(range(len(labels)), labels)
plt.gca().xaxis.set_ticks_position(&amp;#x27;bottom&amp;#x27;)

for i in range(cm.shape[0]):
    for j in range(cm.shape[1]):
        plt.gca().text(x=j, y=i, s=cm[i][j], ha=&amp;#x27;center&amp;#x27;, va=&amp;#x27;center&amp;#x27;)

plt.xlabel(&amp;#x27;Predicted label&amp;#x27;)
plt.ylabel(&amp;#x27;True label&amp;#x27;)&lt;/pre&gt;
  &lt;figure id=&quot;KQ7X&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/65/71/65712ad4-95c6-4ac7-8a50-5fa80c702af7.png&quot; width=&quot;853&quot; /&gt;
  &lt;/figure&gt;
  &lt;figure id=&quot;XVSQ&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/4a/6f/4a6f8857-7046-4cf3-a67c-fad3debecfb0.png&quot; width=&quot;861&quot; /&gt;
  &lt;/figure&gt;
  &lt;h2 id=&quot;0YOB&quot;&gt;imshow&lt;/h2&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;hKYn&quot;&gt;Функция &lt;strong&gt;imshow&lt;/strong&gt; работает аналогично, только для управления размером не надо явно передавать номер фигуры (как делали выше используя &lt;strong&gt;fignum&lt;/strong&gt;,так как по умолчанию &lt;strong&gt;matshow&lt;/strong&gt; сама создает фигуру):&lt;/p&gt;
  &lt;pre id=&quot;vJWM&quot;&gt;fig = plt.figure(figsize=(5, 5))

plt.imshow(cm, cmap=&amp;#x27;viridis&amp;#x27;)

plt.xticks(range(len(labels)), labels, rotation=&amp;#x27;vertical&amp;#x27;)
plt.yticks(range(len(labels)), labels)
plt.gca().xaxis.set_ticks_position(&amp;#x27;bottom&amp;#x27;)

for i in range(cm.shape[0]):
    for j in range(cm.shape[1]):
        plt.gca().text(x=j, y=i, s=cm[i][j], ha=&amp;#x27;center&amp;#x27;, va=&amp;#x27;center&amp;#x27;, color=&amp;quot;white&amp;quot;)

plt.xlabel(&amp;#x27;Predicted label&amp;#x27;)
plt.ylabel(&amp;#x27;True label&amp;#x27;)&lt;/pre&gt;
  &lt;figure id=&quot;FfbG&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/96/86/9686c66d-57ab-40e4-b9f1-9f32f11fb7af.png&quot; width=&quot;858&quot; /&gt;
  &lt;/figure&gt;
  &lt;figure id=&quot;wbcY&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/4b/fb/4bfb5aaa-5d6f-4425-8a98-70d05dce663a.png&quot; width=&quot;849&quot; /&gt;
  &lt;/figure&gt;
  &lt;h2 id=&quot;SCDA&quot;&gt;heatmap&lt;/h2&gt;
  &lt;p id=&quot;xotB&quot;&gt;Для отображения с помощью функции &lt;strong&gt;heatmap &lt;/strong&gt;из библиотеки &lt;strong&gt;seaborn &lt;/strong&gt;надо будет внести минимальные правки (закомментировал строки, которые помогут добавить подписи):&lt;/p&gt;
  &lt;pre id=&quot;noRT&quot;&gt;import seaborn as sns
plt.figure(figsize=(5,5))

# fmt=&amp;#x27;.1f&amp;#x27;
sns.heatmap(pd.DataFrame(cm, index=labels, columns=labels), annot=True,
            fmt=&amp;#x27;d&amp;#x27;, cmap=&amp;#x27;inferno&amp;#x27;, cbar=False)

# plt.xticks(range(len(labels)), list(labels), rotation=&amp;#x27;vertical&amp;#x27;)
# plt.yticks(range(len(labels)), labels)

# plt.xlabel(&amp;#x27;Predicted label&amp;#x27;)
# plt.ylabel(&amp;#x27;True label&amp;#x27;)&lt;/pre&gt;
  &lt;figure id=&quot;VYIP&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/83/69/8369887a-a0e7-4479-837e-abda2ee52aab.png&quot; width=&quot;836&quot; /&gt;
  &lt;/figure&gt;
  &lt;figure id=&quot;IRyG&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/ad/f2/adf223c0-a891-4091-851e-9534cc07f817.png&quot; width=&quot;851&quot; /&gt;
  &lt;/figure&gt;
  &lt;h2 id=&quot;ujrg&quot;&gt;ConfusionMatrixDisplay&lt;/h2&gt;
  &lt;p id=&quot;47Z8&quot;&gt;Об удобстве вывода задумались и разработчики &lt;strong&gt;scikit-learn&lt;/strong&gt;, написав класс &lt;strong&gt;ConfusionMatrixDisplay&lt;/strong&gt;. С помощью его методов, например, &lt;strong&gt;from_predictions &lt;/strong&gt;можно сразу нарисовать картинку:&lt;/p&gt;
  &lt;pre id=&quot;VfjT&quot;&gt;from sklearn.metrics import ConfusionMatrixDisplay


ConfusionMatrixDisplay.from_predictions(y_true=df[&amp;#x27;target&amp;#x27;], y_pred=y_p,
                                              labels=labels, colorbar=False,
                                              xticks_rotation=&amp;#x27;vertical&amp;#x27;, im_kw={&amp;#x27;cmap&amp;#x27;:&amp;#x27;viridis&amp;#x27;});

&lt;/pre&gt;
  &lt;figure id=&quot;NGCx&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/b2/5e/b25e1ace-ce53-4abf-8af1-0e73be4534af.png&quot; width=&quot;999&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;Buef&quot;&gt;Однако для более гибкой настройки лучше создать класс с помощью конструктора, инициализировав параметр &lt;strong&gt;confusion_matrix &lt;/strong&gt;нашей матрицей ошибок, а затем вызвать метод &lt;strong&gt;plot &lt;/strong&gt;объекта с настройками отображения:&lt;/p&gt;
  &lt;pre id=&quot;HhHY&quot;&gt;cmp = ConfusionMatrixDisplay(confusion_matrix=cm, display_labels=labels)

fig, ax = plt.subplots(figsize=(5,5))
cmp.plot(ax=ax, xticks_rotation=&amp;#x27;vertical&amp;#x27;, colorbar=False, im_kw={&amp;#x27;cmap&amp;#x27;:&amp;#x27;coolwarm&amp;#x27;},
         text_kw={&amp;#x27;color&amp;#x27;:&amp;quot;white&amp;quot;})
&lt;/pre&gt;
  &lt;figure id=&quot;HLSX&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/cc/56/cc56a93b-08e8-4f8a-b0bb-454039c3f2d9.png&quot; width=&quot;905&quot; /&gt;
  &lt;/figure&gt;
  &lt;figure id=&quot;OmVD&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/b6/24/b624df54-a9d2-43c5-baae-b8da7eea4863.png&quot; width=&quot;835&quot; /&gt;
  &lt;/figure&gt;
  &lt;tt-tags id=&quot;y44v&quot;&gt;
    &lt;tt-tag name=&quot;vis&quot;&gt;#vis&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;draw&quot;&gt;#draw&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;ml&quot;&gt;#ml&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;evaluation&quot;&gt;#evaluation&lt;/tt-tag&gt;
  &lt;/tt-tags&gt;

</content></entry><entry><id>dt_analytic:68Ux-rhNe1e</id><link rel="alternate" type="text/html" href="https://teletype.in/@dt_analytic/68Ux-rhNe1e?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=dt_analytic"></link><title>Как создать бесплатную виртуальную машину и запустить микросервис за час </title><published>2024-07-20T02:59:45.995Z</published><updated>2024-07-20T03:15:25.240Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img4.teletype.in/files/fb/99/fb990f12-8ea3-41d9-aa9c-e2feefd50ced.png"></media:thumbnail><category term="instrumenty-analitika" label="инструменты аналитика"></category><tt:hashtag>servers</tt:hashtag><tt:hashtag>сбер</tt:hashtag><tt:hashtag>cloud_ru</tt:hashtag><tt:hashtag>сбероблако</tt:hashtag><tt:hashtag>jupyter</tt:hashtag><tt:hashtag>web</tt:hashtag><summary type="html">&lt;img src=&quot;https://img2.teletype.in/files/18/42/1842b330-89b9-4f56-8052-31ad86324bd2.png&quot;&gt;&quot;Будущее уже здесь, просто оно еще не равномерно распределено&quot; (Уильям Гибсон). В наши дни будущее, где каждому можно получить собственную виртуальную машину и развернуть микросервис, уже наступило. Но все ли знают, как это сделать? В этом материале мы вместе пройдем по шагам, воспользовавшись сервисом cloud.ru.</summary><content type="html">
  &lt;figure id=&quot;bfPq&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/18/42/1842b330-89b9-4f56-8052-31ad86324bd2.png&quot; width=&quot;853&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;RPZT&quot;&gt;&lt;strong&gt;&amp;quot;Будущее уже здесь, просто оно еще не равномерно распределено&amp;quot; (Уильям Гибсон)&lt;/strong&gt;. В наши дни будущее, где каждому можно получить собственную виртуальную машину и развернуть микросервис, уже наступило. Но все ли знают, как это сделать? В этом материале мы вместе пройдем по шагам, воспользовавшись сервисом &lt;a href=&quot;https://console.cloud.ru/&quot; target=&quot;_blank&quot;&gt;cloud.ru. &lt;/a&gt;&lt;/p&gt;
  &lt;h2 id=&quot;nFIE&quot;&gt;Создание ключа доступа&lt;/h2&gt;
  &lt;p id=&quot;q1tu&quot;&gt;Предварительно сгенерируем rsa ключи для входа, используя утилиту &lt;strong&gt;ssh-keygen&lt;/strong&gt;:&lt;/p&gt;
  &lt;figure id=&quot;n0Rh&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/72/83/72839261-f97a-490d-a579-c1acb8ee4a25.png&quot; width=&quot;987&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;ZEVR&quot;&gt;Сгенерируется пара ключей rsa в домашнем каталоге:&lt;/p&gt;
  &lt;figure id=&quot;3cfK&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/91/a7/91a7a2eb-7658-4337-b5bb-fe7dc4d4217d.png&quot; width=&quot;946&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;RcQC&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;X2dY&quot;&gt;Создание машины&lt;/h2&gt;
  &lt;p id=&quot;PlXF&quot;&gt;Теперь надо перенести публичную часть (&lt;strong&gt;id_rsa.pub&lt;/strong&gt;) на сервер. Логинимся удобным способом на  &lt;a href=&quot;https://console.cloud.ru/&quot; target=&quot;_blank&quot;&gt;cloud.ru&lt;/a&gt;, например, по сбер id. Кликаем в левом верхнем углу на прямоугольник с точками и выбираем опцию &lt;strong&gt;SSH-ключи&lt;/strong&gt;:&lt;/p&gt;
  &lt;p id=&quot;S3iw&quot;&gt;&lt;/p&gt;
  &lt;figure id=&quot;Na8I&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/6e/c9/6ec9b3e6-d477-484a-ae7d-d1613f0f19c8.png&quot; width=&quot;1043&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;damr&quot;&gt;Выбираем &amp;quot;&lt;strong&gt;Создать ключ&lt;/strong&gt;&amp;quot;:&lt;/p&gt;
  &lt;figure id=&quot;Dd0Y&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/10/74/1074abf3-54f3-45c9-8522-68e0b39f40ea.png&quot; width=&quot;1800&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;WHWD&quot;&gt;Задаем имя, &amp;quot;&lt;strong&gt;загружаем публичный ключ из файла&lt;/strong&gt;&amp;quot; и жмем создать: &lt;/p&gt;
  &lt;p id=&quot;OBKa&quot;&gt;&lt;/p&gt;
  &lt;figure id=&quot;9LVa&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/15/1a/151aeb75-cd02-4a43-9d41-603deb6d49be.png&quot; width=&quot;1073&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;k5fY&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;LuVT&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;fFrb&quot;&gt;Затем кликаем на прямоугольник из точек в левом верхнем углу -&amp;gt; инфраструктура-&amp;gt; виртуальные машины:&lt;/p&gt;
  &lt;figure id=&quot;xlV3&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/cf/c5/cfc5bbac-81fd-4812-8bda-50fd371d4b80.png&quot; width=&quot;1204&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;v6Op&quot;&gt;Выбираем &amp;quot;Создать виртуальную машину&amp;quot;:&lt;/p&gt;
  &lt;figure id=&quot;2r3F&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/41/ed/41ed9476-ce88-42e9-ac11-32fefd1f3a7b.png&quot; width=&quot;1291&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;eiPE&quot;&gt;Переходим в опцию &amp;quot;&lt;strong&gt;Получить ВМ бесплатно&lt;/strong&gt;&amp;quot; (на картинке в левом нижнем углу): &lt;/p&gt;
  &lt;figure id=&quot;ekVi&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/3e/75/3e75d3b3-5692-4af5-84e5-e5db5ecc0756.png&quot; width=&quot;1436&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;G2vR&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;ZnU9&quot;&gt;Заполняем название, выбираем образ системы (я выбрал &lt;strong&gt;ubuntu&lt;/strong&gt;), указываем имя пользователя и публичный ключ, который недавно создали. Также ставим галочку на &amp;quot;&lt;strong&gt;Пароль&lt;/strong&gt;&amp;quot; и задаем его для входа через пароль (например, в виртуальном терминале в личном кабинете):&lt;/p&gt;
  &lt;figure id=&quot;8hrw&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/17/dd/17ddad97-a875-4089-81ab-777ab7492056.png&quot; width=&quot;889&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;Rb4I&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;pXaE&quot;&gt;Можно сразу подключить публичный IP или потом, чтобы взаимосвязь с машиной происходила через Интернет (это платно, около 150 рублей в месяц, однако на 2 месяца у вас будет 4 тыс. рублей в качестве бонусов). В конце кликаем на &amp;quot;&lt;strong&gt;Создать&lt;/strong&gt;&amp;quot; в самом низу:&lt;/p&gt;
  &lt;figure id=&quot;QsGX&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/5b/18/5b183e40-910c-4804-ae09-a93db558053e.png&quot; width=&quot;922&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;aMwp&quot;&gt;И ждем, когда машина будет создана:&lt;/p&gt;
  &lt;figure id=&quot;Dd31&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/8f/02/8f0202ae-8094-4c6a-8881-7b4b0f7c0bc2.png&quot; width=&quot;1800&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;q9lF&quot;&gt;Затем можно нажать на троеточие справа и перейти в виртуальную консоль:&lt;/p&gt;
  &lt;figure id=&quot;x1m1&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/ea/43/ea4311ec-26dc-4dc3-841f-888e6b7d30df.png&quot; width=&quot;1803&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;RKz8&quot;&gt;После ввода логина и пароля, вы получите доступ в терминал:&lt;/p&gt;
  &lt;figure id=&quot;6sJd&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/6b/3b/6b3b4f23-0231-4026-994e-3e3cc33d8831.png&quot; width=&quot;1040&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;k7Vw&quot;&gt;Видеоинструкцию по созданию машины можете посмотреть &lt;a href=&quot;https://www.youtube.com/results?search_query=free+tier+sber+cloud+%D0%BF%D0%BE%D0%B4%D0%BA%D0%BB%D1%8E%D1%87%D0%B5%D0%BD%D0%B8+%D0%BA+%D0%B2%D0%B8%D1%80%D1%82%D1%83%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B5+%D0%BC%D0%B0%D1%88%D0%B8%D0%BD%D0%B5&quot; target=&quot;_blank&quot;&gt;здесь&lt;/a&gt;.&lt;/p&gt;
  &lt;h2 id=&quot;kUcB&quot;&gt;Внешний ip&lt;/h2&gt;
  &lt;p id=&quot;0n9n&quot;&gt;Теперь давайте назначим публичный ip. Перейдите в опцию &amp;quot;&lt;strong&gt;Виртуальные машины&lt;/strong&gt;&amp;quot; (по аналогии, как выше), нажмите на троеточие и выберите соответствующий пункт:&lt;/p&gt;
  &lt;p id=&quot;hugY&quot;&gt;&lt;/p&gt;
  &lt;figure id=&quot;MUPJ&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/dd/9f/dd9f6b6d-e894-466d-9755-f7d7c8665f07.png&quot; width=&quot;1812&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;DhgO&quot;&gt;Выберите интерфейс из выпадающего списка и нажмите &amp;quot;&lt;strong&gt;Назначить&lt;/strong&gt;&amp;quot;:&lt;/p&gt;
  &lt;p id=&quot;r34X&quot;&gt;&lt;/p&gt;
  &lt;figure id=&quot;43Zm&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/ec/3a/ec3a6444-3841-4738-8772-000dd4eef2a3.png&quot; width=&quot;538&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;D7V7&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;5mK3&quot;&gt;Теперь у нас есть ip, и можно для удобства зайти на виртуальную машину по ssh с локальной машины:&lt;/p&gt;
  &lt;pre id=&quot;ktHJ&quot;&gt;ssh имя_пользователя@ip&lt;/pre&gt;
  &lt;p id=&quot;C10l&quot;&gt;Так как мы настроили аутентификацию по rsa, пароль вводить не придется.&lt;/p&gt;
  &lt;h2 id=&quot;U1yf&quot;&gt;Микросервис&lt;/h2&gt;
  &lt;h3 id=&quot;DRNF&quot;&gt;установка docker&lt;/h3&gt;
  &lt;p id=&quot;6EPJ&quot;&gt;Установим &lt;strong&gt;docker&lt;/strong&gt;, набрав команды (версия для ubuntu):&lt;/p&gt;
  &lt;pre id=&quot;F5cn&quot;&gt;sudo apt update
sudo apt install docker.io&lt;/pre&gt;
  &lt;p id=&quot;VrZl&quot;&gt;Для проверки установки наберите команду:&lt;/p&gt;
  &lt;pre id=&quot;Yqdn&quot;&gt;sudo systemctl start docker&lt;/pre&gt;
  &lt;p id=&quot;NjUv&quot;&gt;После этого желательно добавить текущего пользователя в группу &lt;strong&gt;docker&lt;/strong&gt;, чтобы команды данного инструмента выполнять без привилегий суперпользователя (&lt;strong&gt;sudo&lt;/strong&gt;):&lt;/p&gt;
  &lt;pre id=&quot;46tk&quot;&gt;sudo usermod -aG docker al&lt;/pre&gt;
  &lt;h3 id=&quot;vQFn&quot;&gt;настройка правил для подключений&lt;/h3&gt;
  &lt;p id=&quot;iFdi&quot;&gt;Перед запуском контейнера настроим правило для входящего трафика (&lt;a href=&quot;https://cloud.ru/docs/security-groups/ug/topics/guides__add-sg-rule.html&quot; target=&quot;_blank&quot;&gt;тут подробнее&lt;/a&gt;) от Jupyter lab. &lt;/p&gt;
  &lt;p id=&quot;34It&quot;&gt;Опять жмем прямоугольник из точек, выбираем раздел &amp;quot;&lt;strong&gt;Группы безопасности&lt;/strong&gt;&amp;quot;, нажимаем на группу:&lt;/p&gt;
  &lt;figure id=&quot;RMyX&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/b2/be/b2be5f80-efe0-4a37-bdf0-4027c7048742.png&quot; width=&quot;1804&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;ItxH&quot;&gt;Переходим во вкладку &amp;quot;&lt;strong&gt;Правила&lt;/strong&gt;&amp;quot;, жмем &amp;quot;&lt;strong&gt;Добавить правило&lt;/strong&gt;&amp;quot;:&lt;/p&gt;
  &lt;figure id=&quot;rgBE&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/fb/71/fb711214-7e30-400c-979c-84863a003864.png&quot; width=&quot;1328&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;7RPP&quot;&gt;и заполняем протокол, порт, ip адрес и маску (для разрешений всем - 0.0.0.0/0): &lt;/p&gt;
  &lt;figure id=&quot;uKsC&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/64/23/64237938-e04c-40c2-aaf6-d467dea91ab2.png&quot; width=&quot;737&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;0te4&quot;&gt;или так:&lt;/p&gt;
  &lt;figure id=&quot;jhde&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/f6/13/f6134256-aec6-453d-b585-9655ab3ac1ac.png&quot; width=&quot;570&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;HXcN&quot;&gt;Свой ip можно посмотреть &lt;a href=&quot;https://2ip.ru&quot; target=&quot;_blank&quot;&gt;тут&lt;/a&gt;. Для отдельных пользователей и малых офисов провайдер обычно использует динамические адреса и маску подсети /32, указывающую, что все биты адреса используются для идентификации конкретного устройства. Соответственно, из-за динамической природы адреса ваше правило для одиночного ip при следующем соединении может перестать работать.&lt;/p&gt;
  &lt;h3 id=&quot;Ublo&quot;&gt;запуск сервиса&lt;/h3&gt;
  &lt;p id=&quot;uWH5&quot;&gt;После этого перезагружаем машину, подключаемся к терминалу виртуальной машины и запускаем контейнер командой:&lt;/p&gt;
  &lt;pre id=&quot;aZL1&quot;&gt;docker run -p 8888:8888 -p 4040:4040 -it --user root jupyter/pyspark-notebook start.sh jupyter lab&lt;/pre&gt;
  &lt;p id=&quot;NXUh&quot;&gt;Затем на своей машине в браузере вводим:&lt;/p&gt;
  &lt;pre id=&quot;XaKe&quot;&gt;http://ip:8888/lab?token=a5a6e2d32063017ea28ebe0ea1ab1d928eadea15d16cab50&lt;/pre&gt;
  &lt;p id=&quot;q65E&quot;&gt;Напомню, что token высветится в логах запуска контейнера прямо в терминале.&lt;/p&gt;
  &lt;p id=&quot;1pYg&quot;&gt;Теперь наслаждаемся результатом:&lt;/p&gt;
  &lt;figure id=&quot;HcYp&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/b0/05/b005e957-da9e-4e7d-8933-0c452ecb1766.png&quot; width=&quot;1616&quot; /&gt;
  &lt;/figure&gt;
  &lt;tt-tags id=&quot;qDPK&quot;&gt;
    &lt;tt-tag name=&quot;servers&quot;&gt;#servers&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;сбер&quot;&gt;#сбер&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;cloud_ru&quot;&gt;#cloud_ru&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;сбероблако&quot;&gt;#сбероблако&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;jupyter&quot;&gt;#jupyter&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;web&quot;&gt;#web&lt;/tt-tag&gt;
  &lt;/tt-tags&gt;

</content></entry><entry><id>dt_analytic:VUXQ3Ssk8O8</id><link rel="alternate" type="text/html" href="https://teletype.in/@dt_analytic/VUXQ3Ssk8O8?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=dt_analytic"></link><title>Визуализация ошибок, как навигатор к скрытым проблемам модели</title><published>2024-05-12T14:15:39.417Z</published><updated>2024-05-12T14:15:39.417Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img3.teletype.in/files/ad/81/ad81fa52-5477-45f5-9f2a-11eca642b3a4.png"></media:thumbnail><category term="mashinnoe-obuchenie" label="машинное обучение"></category><tt:hashtag>ml</tt:hashtag><tt:hashtag>diag</tt:hashtag><tt:hashtag>ошибки</tt:hashtag><tt:hashtag>остатки</tt:hashtag><tt:hashtag>residuals</tt:hashtag><summary type="html">&lt;img src=&quot;https://img3.teletype.in/files/ee/8a/ee8a892f-1d60-445f-b0b8-4b98a0482c95.png&quot;&gt;Визуализация — это язык, который позволяет нам видеть данные и понимать их смысл. Простой и эффективный способ диагностики результатов работы модели на различных объектах заключается в анализе разницы между прогнозами и целями. Он может показать, что в некоторых группах поведение модели имеет особенности (например, склонность к завышению или занижению прогнозов). Для демонстрации того, как строится такая визуализация загрузим набор данных:</summary><content type="html">
  &lt;figure id=&quot;cr6j&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/ee/8a/ee8a892f-1d60-445f-b0b8-4b98a0482c95.png&quot; width=&quot;685&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;1Ckm&quot;&gt;&lt;strong&gt;Визуализация — это язык, который позволяет нам видеть данные и понимать их смысл&lt;/strong&gt;. Простой и эффективный способ диагностики результатов работы модели на различных объектах заключается в анализе разницы между прогнозами и целями. Он может показать, что в некоторых группах поведение модели имеет особенности (например, склонность к завышению или занижению прогнозов). Для демонстрации того, как строится такая визуализация загрузим набор данных:&lt;/p&gt;
  &lt;pre id=&quot;u3e1&quot; data-lang=&quot;python&quot;&gt;from sklearn.datasets import load_diabetes
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

np.random.seed(0)

df, y = load_diabetes(return_X_y=True, as_frame=True)
df[&amp;#x27;target&amp;#x27;] = y
display(df.head())
display(df.shape)&lt;/pre&gt;
  &lt;figure id=&quot;iDoA&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/be/ff/beff0162-5e84-4e94-9e99-a5d1c1245ab3.png&quot; width=&quot;733&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;9Tmd&quot;&gt;Разобьем датасет на две группы для обучения и оценки:&lt;/p&gt;
  &lt;pre id=&quot;jzJj&quot; data-lang=&quot;python&quot;&gt;from sklearn.model_selection import train_test_split

X_tr, X_ts, y_tr, y_ts = train_test_split(df.drop(columns=&amp;#x27;target&amp;#x27;).copy(),
                                          df[&amp;#x27;target&amp;#x27;], test_size=0.2)
y_tr.shape[0], y_ts.shape[0]&lt;/pre&gt;
  &lt;figure id=&quot;NFKD&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/27/35/2735cf0d-87b6-48ec-9e20-3ca689204167.png&quot; width=&quot;723&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;wbRi&quot;&gt;Теперь построим модель и сделаем предсказания:&lt;/p&gt;
  &lt;pre id=&quot;M64s&quot; data-lang=&quot;python&quot;&gt;from sklearn.linear_model import LinearRegression

model = LinearRegression()

model.fit(X_tr, y_tr)
y_p = model.predict(X_ts)&lt;/pre&gt;
  &lt;figure id=&quot;U9Sk&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/cb/a3/cba3f6ce-fd14-4802-960e-65beccbe5a16.png&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;ixzD&quot;&gt;Аналитический прием, о котором шла речь выше, заключается в визуализации распределения разности между целями и прогнозами (ошибками). Это можно сделать, например, путем построения гистограммы или графика разброса точек с координатами по оси y - ошибки, x - предсказания. Объявим функцию с соответствующими свойствами и вызовем ее:&lt;/p&gt;
  &lt;pre id=&quot;aYMF&quot; data-lang=&quot;python&quot;&gt;def plot_residuals(target, predictions, bins_num, figsize=(20, 8), style=&amp;#x27;seaborn&amp;#x27;):

    error = target - predictions
    with plt.style.context(style=style):

      plt.figure(figsize=figsize)
      plt.suptitle(f&amp;#x27;Анализ ошибок&amp;#x27;, fontsize=16)

      plt.subplot(1, 2, 1)
      plt.hist(error, edgecolor=&amp;#x27;blue&amp;#x27;, bins=bins_num)
      plt.axvline(x=0, color=&amp;#x27;black&amp;#x27;, label=&amp;#x27;ноль&amp;#x27;, linestyle=&amp;#x27;--&amp;#x27;)
      plt.axvline(x=error.median(), color=&amp;#x27;red&amp;#x27;, label=&amp;#x27;медиана&amp;#x27;)
      plt.axvline(x=error.mean(), color=&amp;#x27;orange&amp;#x27;, label=&amp;#x27;среднее&amp;#x27;)
      plt.title(f&amp;#x27;Гистограмма ошибок&amp;#x27;, fontsize=15)
      plt.ylabel(&amp;#x27;плотность распределения&amp;#x27;, fontsize=14)
      plt.xlabel(&amp;#x27;ошибки&amp;#x27;, fontsize=14)
      plt.legend()

      plt.subplot(1, 2, 2)
      plt.scatter(predictions, error, alpha=0.4)
      plt.axhline(y=0, color=&amp;#x27;red&amp;#x27;, label=&amp;#x27;ноль&amp;#x27;, linestyle=&amp;#x27;--&amp;#x27;)
      plt.title(f&amp;#x27;Анализ дисперсии ошибок&amp;#x27;, fontsize=15)
      plt.ylabel(&amp;#x27;ошибки&amp;#x27;, fontsize=14)
      plt.xlabel(&amp;#x27;предсказания модели&amp;#x27;, fontsize=14)
&lt;/pre&gt;
  &lt;figure id=&quot;hfvE&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/2d/2d/2d2d88bd-c9f9-40e2-b594-6476fd5eeae7.png&quot; width=&quot;751&quot; /&gt;
  &lt;/figure&gt;
  &lt;pre id=&quot;hDil&quot; data-lang=&quot;python&quot;&gt;plot_residuals(y_ts, y_p, bins_num = 10, figsize=(20, 5), style=&amp;#x27;bmh&amp;#x27;)&lt;/pre&gt;
  &lt;figure id=&quot;vNRS&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/d9/04/d9041d78-763e-43ec-b143-16cb8e1a57c1.png&quot; width=&quot;1007&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;sD7k&quot;&gt;На графике ошибки распределены равномерно относительно нуля, их среднее и медиана почти совпадают и равны 0.&lt;/p&gt;
  &lt;p id=&quot;tVsj&quot;&gt;Аналогичные графики можно построить с библиотекой sklearn (потребуется использовать метод &lt;strong&gt;from_predictions &lt;/strong&gt;класса &lt;strong&gt;PredictionErrorDisplay &lt;/strong&gt;из модуля &lt;strong&gt;sklearn.metrics&lt;/strong&gt;):&lt;/p&gt;
  &lt;pre id=&quot;VLWw&quot; data-lang=&quot;python&quot;&gt;from sklearn.metrics import PredictionErrorDisplay

PredictionErrorDisplay.from_predictions(y_ts, y_p)&lt;/pre&gt;
  &lt;figure id=&quot;34ox&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/f8/63/f8630018-1818-4ad9-b50b-a91e519d0286.png&quot; width=&quot;791&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;Q7BB&quot;&gt;По оси y можно вывести вместо ошибок реальные значения (цели) против предсказанных по оси x:&lt;/p&gt;
  &lt;pre id=&quot;DPkm&quot; data-lang=&quot;python&quot;&gt;PredictionErrorDisplay.from_predictions(y_ts, y_p, kind=&amp;#x27;actual_vs_predicted&amp;#x27;)&lt;/pre&gt;
  &lt;figure id=&quot;Qlva&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/b2/b0/b2b09888-313c-4c9d-80a2-1da2189ef689.png&quot; width=&quot;777&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;PxVd&quot;&gt;А теперь для демонстрационных целей добавим выброс в виде новой точки с очень большой целью и снова обучим модель:&lt;/p&gt;
  &lt;pre id=&quot;CvRm&quot; data-lang=&quot;python&quot;&gt;model.fit(pd.concat([X_tr, X_tr.iloc[[-1]]]),
          pd.concat([y_tr.to_frame(), pd.Series([1e10]).to_frame(&amp;#x27;target&amp;#x27;)])[&amp;#x27;target&amp;#x27;])

y_p = model.predict(X_ts)

plot_residuals(y_ts, y_p, bins_num = 10, figsize=(20, 5), style=&amp;#x27;bmh&amp;#x27;)&lt;/pre&gt;
  &lt;figure id=&quot;UbWD&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/73/b2/73b2ec5c-725e-480f-a57f-b1653599262a.png&quot; width=&quot;1008&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;Frgj&quot;&gt;После обучения на большом выбросе, модель для одних точек стала сильно занижать предсказания, а для других - завышать. Такой эффект может быть вызван не только выбросами в обучающих данных, но и простотой модели, плохими признаками. Например, вы пытаетесь предсказать цену квартиры, основываясь только на площади, и не учитываете особенности района, близость к метро. Тогда, если в датасете имеется перекос в сторону квартир из элитных райнов, фактор площади может остаться недооцененным.&lt;/p&gt;
  &lt;p id=&quot;MC0H&quot;&gt;Таким образом, неравномерность распределения ошибок относительно нуля является индикатором того, что модель требует доработки и оптимизации, а причины могут от случая к случаю меняться.&lt;/p&gt;
  &lt;tt-tags id=&quot;6Wg4&quot;&gt;
    &lt;tt-tag name=&quot;ml&quot;&gt;#ml&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;diag&quot;&gt;#diag&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;ошибки&quot;&gt;#ошибки&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;остатки&quot;&gt;#остатки&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;residuals&quot;&gt;#residuals&lt;/tt-tag&gt;
  &lt;/tt-tags&gt;

</content></entry><entry><id>dt_analytic:fN7IzGbL2yN</id><link rel="alternate" type="text/html" href="https://teletype.in/@dt_analytic/fN7IzGbL2yN?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=dt_analytic"></link><title>Особенности работы с LLM нейросетями в части исправления ошибок в ответах</title><published>2024-05-04T11:56:47.707Z</published><updated>2024-05-04T12:08:22.801Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img3.teletype.in/files/23/01/230148ee-4271-4fd8-9b58-4eab8ce602df.png"></media:thumbnail><category term="mashinnoe-obuchenie" label="машинное обучение"></category><tt:hashtag>llm</tt:hashtag><tt:hashtag>chatgpt</tt:hashtag><tt:hashtag>gigachat</tt:hashtag><tt:hashtag>алиса</tt:hashtag><tt:hashtag>gemini</tt:hashtag><tt:hashtag>promts</tt:hashtag><tt:hashtag>промты</tt:hashtag><tt:hashtag>нейросети</tt:hashtag><tt:hashtag>чатботы</tt:hashtag><summary type="html">&lt;img src=&quot;https://img1.teletype.in/files/cc/1d/cc1d93cb-6569-47c1-93a1-6fcfec93ff70.png&quot;&gt;После релиза ChatGPT сверхпопулярным направлением стало создание промтов. Появилось много &quot;экспертов&quot;, каждый из которых пытается предложить рецепт подходящего запроса. Пройдусь по одному из трендов - это расхожие фразы, которые призваны устранить логические ошибки .</summary><content type="html">
  &lt;figure id=&quot;w9C4&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/cc/1d/cc1d93cb-6569-47c1-93a1-6fcfec93ff70.png&quot; width=&quot;775&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;0Fu6&quot;&gt;После релиза &lt;strong&gt;ChatGPT &lt;/strong&gt;сверхпопулярным направлением стало создание промтов. Появилось много &amp;quot;экспертов&amp;quot;, каждый из которых пытается предложить рецепт подходящего запроса. Пройдусь по одному из трендов - это расхожие фразы, которые призваны устранить логические и фактологические ошибки в ответах.&lt;/p&gt;
  &lt;p id=&quot;yBJn&quot;&gt;Спросим у 4 нейросетей &lt;strong&gt;ChatGPT&lt;/strong&gt;, &lt;strong&gt;GigaChat&lt;/strong&gt;, &lt;strong&gt;Алиса Про&lt;/strong&gt;,&lt;strong&gt;Gemini &lt;/strong&gt;одно и то же, а потом попробуем скорректировать ошибки. Запрос такой:&lt;/p&gt;
  &lt;blockquote id=&quot;0T90&quot;&gt;можно ли методом compare в pandas сравнивать датафреймы с разным количеством строк. Приведи пример кода. &lt;/blockquote&gt;
  &lt;p id=&quot;GliL&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;yxE9&quot;&gt;Ответ &lt;strong&gt;Алиса Про&lt;/strong&gt;:&lt;/p&gt;
  &lt;figure id=&quot;JnTN&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/b1/4c/b14c4f92-081f-444e-ab5b-3a90f1da83b1.png&quot; width=&quot;916&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;s7JY&quot;&gt;Правильный. Кстати 10 минутами до, спрашивал то же и нейросеть отвечала постоянно неправильно, приводя неработающие куски кода (может мои многократные повторы одного вопроса расценились, как неудовлетворительный результат).&lt;/p&gt;
  &lt;p id=&quot;uiOQ&quot;&gt;Ответ &lt;strong&gt;GigaChat&lt;/strong&gt;:&lt;/p&gt;
  &lt;figure id=&quot;vB4t&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/e1/72/e17288e6-a597-4e4f-a7e9-4c80f8ba2769.png&quot; width=&quot;874&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;5dLR&quot;&gt;Опять ответ верный и противоположный прежнему. Однако я вспомнил, что до этого задавал тот же запрос без &amp;quot;в&amp;quot; между словами compare и pandas. Вот, какой ответ в этом случае:&lt;/p&gt;
  &lt;figure id=&quot;NBwJ&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/42/2c/422cc891-33b0-493a-a412-541c0178e060.png&quot; width=&quot;801&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;snY8&quot;&gt;Уже ответ неверный, однако &lt;strong&gt;GigaChat &lt;/strong&gt;дает нам пример другого полезного метода&lt;strong&gt;.&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;Di6W&quot;&gt;Ответ от &lt;strong&gt;ChatGPT&lt;/strong&gt;:&lt;/p&gt;
  &lt;figure id=&quot;qhn3&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/c6/6b/c66ba4f3-7e8c-4f97-b833-24cd887b4fd2.png&quot; width=&quot;934&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;UtZP&quot;&gt;На удивление у &lt;strong&gt;ChatGPT &lt;/strong&gt;ответ самый худший. Неправильный с неработающим куском кода.&lt;/p&gt;
  &lt;p id=&quot;V7IP&quot;&gt;Ответ от &lt;strong&gt;Gemini&lt;/strong&gt;:&lt;/p&gt;
  &lt;figure id=&quot;Rbrt&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/50/df/50dfa916-849c-4b7b-8306-3183bcbe1c93.png&quot; width=&quot;778&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;933i&quot;&gt;Неправильный с неработающим кодом. При этом удивительно, что 10 минут назад выдавала стабильно правильный ответ. Единственный момент - я запустил этот и предыдущие вопросы в рамках одного чата, соответственно, на ответ повлиял контекст. Действительно, открыв новый чат, снова получил правильный ответ. &lt;/p&gt;
  &lt;p id=&quot;2BGZ&quot;&gt;Резюме:&lt;/p&gt;
  &lt;p id=&quot;CKy7&quot;&gt;- 3 нейросети (кроме &lt;strong&gt;ChatGPT&lt;/strong&gt;) результат поменяли на противоположный в течение нескольких минут.&lt;/p&gt;
  &lt;p id=&quot;ngzR&quot;&gt;- На результат могут повлиять даже незначительные словесные элементы (в нашем примере - частицы)&lt;/p&gt;
  &lt;p id=&quot;H9UQ&quot;&gt;- На результат сильно влияет контекст&lt;/p&gt;
  &lt;p id=&quot;WPpJ&quot;&gt;А теперь проверим, &amp;quot;чувствительность&amp;quot; к промту по исправлению ошибок &lt;strong&gt;Gemini &lt;/strong&gt;и &lt;strong&gt;ChatGPT&lt;/strong&gt;.&lt;/p&gt;
  &lt;blockquote id=&quot;NuVP&quot;&gt;можно ли методом compare в pandas сравнивать датафреймы с разным количеством строк. Приведи пример кода. &lt;strong&gt;Убедись, что пример работает и в нем нет ошибок.&lt;/strong&gt;&lt;/blockquote&gt;
  &lt;p id=&quot;pzM8&quot;&gt;&lt;strong&gt;ChatGPT&lt;/strong&gt;:&lt;/p&gt;
  &lt;figure id=&quot;Ni2N&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/43/a7/43a77357-04a0-4ff2-b561-c57b9e5a7b48.png&quot; width=&quot;980&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;8T8T&quot;&gt;Опять пример неработающий.&lt;/p&gt;
  &lt;p id=&quot;t1ik&quot;&gt;&lt;strong&gt;Gemini&lt;/strong&gt;:&lt;/p&gt;
  &lt;figure id=&quot;KB4D&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/bf/8f/bf8f6741-1ed8-4305-9b6d-8d9564acfd32.png&quot; width=&quot;822&quot; /&gt;
    &lt;figcaption&gt;...&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;figure id=&quot;r12v&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/50/e7/50e75d14-e8af-494e-8724-c854442de40d.png&quot; width=&quot;814&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;uXm2&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;7Dk1&quot;&gt;&lt;strong&gt;Gemini &lt;/strong&gt;в данном случае дала опять же неправильный ответ, но уже работающий код, возможно, призыв протестировать на нее частично повлиял.&lt;/p&gt;
  &lt;p id=&quot;gBfZ&quot;&gt;Отмечу, что проверял и другие промты, нацеленные на исправление ошибок:&lt;/p&gt;
  &lt;p id=&quot;JHrn&quot;&gt;&amp;quot;&lt;em&gt;запрос&lt;/em&gt;...&lt;strong&gt;Если есть в коде ошибки, найди и устрани их&lt;/strong&gt;&amp;quot;&lt;/p&gt;
  &lt;p id=&quot;T6eL&quot;&gt;&amp;quot;&lt;em&gt;запрос&lt;/em&gt;...&lt;strong&gt;Проверь код в интерпретаторе Python и исправь ошибки&lt;/strong&gt;&amp;quot;&lt;/p&gt;
  &lt;p id=&quot;q4fE&quot;&gt;В целом такими промтами повлиять на результат &lt;strong&gt;ChatGPT&lt;/strong&gt;, а также&lt;strong&gt; GigaChat&lt;/strong&gt;, &lt;strong&gt;Алиса Про &lt;/strong&gt;(когда они давали неверный результат) не удалось. Только с &lt;strong&gt;Gemini&lt;/strong&gt; частично получилось.&lt;/p&gt;
  &lt;p id=&quot;LCiY&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;bhY5&quot;&gt;Вот еще пример. Зададим вопрос: &lt;/p&gt;
  &lt;blockquote id=&quot;h9ac&quot;&gt;когда губернатор штата Калифорния Гэвин Ньюсом подписал закон, который запрещал использование частных тюрем для содержания нелегальных иммигрантов.&lt;/blockquote&gt;
  &lt;p id=&quot;Y63h&quot;&gt;Из СМИ известно, что в октябре 2019 года.&lt;/p&gt;
  &lt;p id=&quot;YmRj&quot;&gt;&lt;strong&gt;Алиса Про&lt;/strong&gt;:&lt;/p&gt;
  &lt;figure id=&quot;qWee&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/e8/b3/e8b336b6-ae4b-4195-b058-87e559fe4750.png&quot; width=&quot;923&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;tNpd&quot;&gt;&lt;strong&gt;GigaChat&lt;/strong&gt;:&lt;/p&gt;
  &lt;figure id=&quot;TROt&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/13/08/13087a36-4da9-4644-aa7b-3ff048724019.png&quot; width=&quot;797&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;NcxM&quot;&gt;Сам я точную дату не знаю, но в октябре 2019. То есть с месяцем &lt;strong&gt;GigaChat &lt;/strong&gt;не ошибся. Опять же пару часов назад, он отказывался отвечать на этот вопрос. То есть результаты не стабильны.&lt;/p&gt;
  &lt;p id=&quot;4PXP&quot;&gt;&lt;strong&gt;ChatGPT&lt;/strong&gt;:&lt;/p&gt;
  &lt;figure id=&quot;wQu1&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/34/ae/34aef627-54cd-481f-a24a-f6c870f71ba7.png&quot; width=&quot;949&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;BkcL&quot;&gt;&lt;strong&gt;Gemini&lt;/strong&gt;:&lt;/p&gt;
  &lt;figure id=&quot;n8L2&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/9c/d8/9cd8fc4b-3df0-4624-ba8c-b48653ffd76f.png&quot; width=&quot;830&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;ynNi&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;lveg&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;ZsjI&quot;&gt;Получается &lt;strong&gt;ChatGPT &lt;/strong&gt;ошибся. Попробуем улучшающий промт:&lt;/p&gt;
  &lt;blockquote id=&quot;6pPL&quot;&gt;когда губернатор штата Калифорния Гэвин Ньюсом подписал закон, который запрещал использование частных тюрем для содержания нелегальных иммигрантов. Проверь, чтобы все даты и факты были правильными&lt;/blockquote&gt;
  &lt;p id=&quot;oOCp&quot;&gt;&lt;/p&gt;
  &lt;figure id=&quot;wBTL&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/61/65/6165125e-64fb-4aa5-852a-3dff708639d3.png&quot; width=&quot;809&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;Qex6&quot;&gt;Интересно, но в данном случае он исправил месяц. При этом более 5 раз до выдавал дату 11 сентября.&lt;/p&gt;
  &lt;p id=&quot;I52a&quot;&gt;Уже после спрашиваю в новом чате в первоначальной формулировке (без дополнения промта просьбой перепроверить факты и даты) &lt;strong&gt;ChatGPT &lt;/strong&gt;отвечает - 25 октября. То есть опять же результаты не стабильны, возможно, коррекция ответа вызвана настойчивыми попытками задать один и тот же вопрос, а возможно эффектом от просьбы перепроверить.&lt;/p&gt;
  &lt;p id=&quot;zUe1&quot;&gt;Таким образом, нельзя говорить о стабильном влиянии на результат &amp;quot;перероверяющих&amp;quot; промтов (&amp;quot;проверь факты и даты&amp;quot;, &amp;quot;если есть ошибки, найди и устрани их&amp;quot;). Возможно, в отдельных случаях они влияют, но в большинстве - нет.&lt;/p&gt;
  &lt;p id=&quot;A9T6&quot;&gt;Моя рекомендация: &lt;/p&gt;
  &lt;p id=&quot;bPvr&quot;&gt;- спрашивать у разных нейросетей, выбирая подходящий ответ&lt;/p&gt;
  &lt;p id=&quot;X6ct&quot;&gt;- для разных тематик открывать отдельные чаты, чтобы минимизировать влияние контекста. &lt;/p&gt;
  &lt;tt-tags id=&quot;PgNs&quot;&gt;
    &lt;tt-tag name=&quot;llm&quot;&gt;#llm&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;chatgpt&quot;&gt;#chatgpt&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;gigachat&quot;&gt;#gigachat&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;алиса&quot;&gt;#алиса&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;gemini&quot;&gt;#gemini&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;promts&quot;&gt;#promts&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;промты&quot;&gt;#промты&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;нейросети&quot;&gt;#нейросети&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;чатботы&quot;&gt;#чатботы&lt;/tt-tag&gt;
  &lt;/tt-tags&gt;

</content></entry></feed>