<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>내가 보려고 만든 블로그</title>
    <link>https://jungeui.tistory.com/</link>
    <description>내가 보려고 만든 블로그</description>
    <language>ko</language>
    <pubDate>Sun, 16 Aug 2026 01:19:56 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>정의김</managingEditor>
    <item>
      <title>DW , DM 설계에 대한 내 생각 (BI ,DS 나눠서 생각해봄 )</title>
      <link>https://jungeui.tistory.com/57</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;DW ,DM을 정말 초창기부터 설계하는일은 경험하기가 쉽지 않은 것 같다 . 보통은 어느정도 자리잡은 회사에 들어가게 되니.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이걸 처음부터 설계한다고하면 어떻게 해야할까? BI ( Data Analyst를 위한 ) 와 DS( Data Scientist를 위한)를 나눠서 생각해보았다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. BI&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;RAW&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;우선 기본적으로 DB에 있는 테이블들을 그대로 가져오는 작업을 하게 될 것이다. 데이터가 유실될 가능성이 있기도 하고 우선 복사해두면 데이터에 대해 추가적으로 변경을 한다고 할 때 다시 DB에 접근할 필요없이 RAW테이블을 통해 작업할 수 있기 떄문이다 .&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;어떻게 가공할지&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;여기부터가 진짜 시작이다. DB설계를 할 때 정규화등을 고려하여 테이블을 만들지만 , DW, DM은 좀 다르다. 최대한 반정규화 , 그렇니까 한 테이블에 분석가가 필요한 컬럼들이 다 담기는 것이 좋다. 매번 조인을 해서 ( 많은시간이 소요) 테이블을 조회해야한다면 불편하기 때문.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 테이블의 주 사용자인 데이터분석가의 니즈를 반영하는게 가장 기본적인듯.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;테이블을 설계하는 마인드에 대해서는 위처럼 적어봤고. 일반적으로 설계할때는 Fact table , Dimension Table 형태로 분리하여 설계하는 것이 국룰? 이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DB에서 가져온 RAW 테이블 (fact table) 에서 확인할수 있는 각 column들 = 각 Dimension에 대해서 count ,sum 등 집계를 통해서 유의미한 테이블들을 만든다 . 유의미하다는 것이 사실 데이터분석가입장에서 유의미한테이블이기에 데이터분석가와 논의해서 만드는것이 가장 좋긴 할 것이다 .&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;그리고 이렇한 테이블을 만들때 증분 방식, 전체 복사 방식 중에 고민을 해야하는데. 테이블이 확장될 가능성이 다분하다면 증분방식, 그게 아니면 쉽게 접근할수 있는 복사 방식이 나은것 같다. 빨리 구축을 해야한다면 복사 방식으로 접근하는 것이 좋긴 하다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. DS&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;RAW&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 DB에 적재된걸 가져와서 가공하는 BI와 다르게 에초에 저장을 시작하는 단계부터 HDFS , S3 에 그대로 저장되는 경우도&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;많다. ( 고객이탈예측 이런거는 아니긴하다. 여기서 말하는건 이미지나 텍스트 데이터등) &amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 것들은 에초에 데이터를 넣어줄 때에 포맷을 잡고 넣주면 됨. 다시 긁는 짓은 굳이??.. 라는 생각이 든다.&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;어떻게 가공할지&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DS, 즉 feature들도 우선 기본적으로 주 소비자인 DS들과 협의해서 적재하는 것은 필수이다. BI와 다르게 DS가 가공한 feature , column등이 생길텐데 혹은 Embedding 형태의 데이터. 마찬가지로 속도가 중요하지 않은 (historical feature) 라면 그대로 hdfs를 이용하는 것이 괜찮다고 생각하되 혹시 조회 + 간단한 연산이 빈번하거나 임베딩형태라면 Elastic Search 혹은 vector database( 종류가 엄청 많은데 뭐가 best인지는 아직 잘 모르겠음. Redis 도 지원을 한다고 한다 . ) 를 쓰는 것도 나쁘지 않다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;여기서 DW에 추가적으로 (정확히 DW 관련은 아니지만) feature의 재사용성 , 추출의 편리성등을 위해 &amp;nbsp;featrue store(feast) 를 고려해 주는 것이 중요함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;또한 feature들을 저장할때 날짜와 함께 버전을 관리해주는 것 정도가 필수적이라고 생각한다 .&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Data Engineering</category>
      <author>정의김</author>
      <guid isPermaLink="true">https://jungeui.tistory.com/57</guid>
      <comments>https://jungeui.tistory.com/57#entry57comment</comments>
      <pubDate>Sun, 25 Jun 2023 12:50:28 +0900</pubDate>
    </item>
    <item>
      <title>Bert4Rec</title>
      <link>https://jungeui.tistory.com/56</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Bert를 Recommendation에 적용할 때 기존 BERT와의 차이점이 무엇인지 , 그리고 Bert4Rec의 Architecture에 대해 간단하게 적어봄.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. Input&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존의 BERT의 경우 3가지 임베딩이 합쳐져 Input으로 들어가게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. Token Embedding 2. Positional Embedding&amp;nbsp;3.&amp;nbsp;Segment Embedding&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Token Embedding의 경우 말 그대로 해당 Token 을 Embedding으로 표현한 것 .&amp;nbsp;Segment Embedding의 경우 문장을 구별하는 Embedding . 그리고 각 Token의 위치에 대한 Positional Embedding이 존재한다 .&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추천에서 BERT를 적용할때 문장을 구별 , 즉 , user의 세션동안 반응한 상품들이 input으로 들어가기 때문에 문장을 구별할 일은 딱히 없다. 따라서 Segment Embedding은 쓰이지 않음.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2. Masking&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;추천에서는 한 세션동안의 아이템을 바탕으로 마지막 아이템을 예측하면 되는 문제이다. 중간 중간의 아이템을 마스킹하고 이를 맞추도록 하는것이 학습에는 도움이 되겠지만 적용을 위해서는 마지막 아이템을 맞춰야한다. 따라서 기존 BERT차람 Masking을 랜덤하게 하여 학습을 시키되 test를 할 때는 마지막 item에 Masking을 하고 해당 Mask token의 BERT모델의 마지막 layer에서 얻어진 embedding을 바탕으로 추론을 하도록 하였다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3. Architecture&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;836&quot; data-origin-height=&quot;908&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b2RREf/btr6qQXQCJ7/oSKDEQAsIvlkVMxrXymm6K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b2RREf/btr6qQXQCJ7/oSKDEQAsIvlkVMxrXymm6K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b2RREf/btr6qQXQCJ7/oSKDEQAsIvlkVMxrXymm6K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb2RREf%2Fbtr6qQXQCJ7%2FoSKDEQAsIvlkVMxrXymm6K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;478&quot; height=&quot;519&quot; data-origin-width=&quot;836&quot; data-origin-height=&quot;908&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Architecture는 다음과 같다 . 결국에는 BERT처럼 Transformer를 여러개 쌓고 , GELU를 사용하고 등등 당연하게도 BERT와 똑같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 언급한데로 마지막 embedding에 대하여 fully connected layer를 통해 item을 예측하도록 함 .&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;갑자기 든 생각은 마지막 item으로부터 n개 까지만을 cutting하여 사용하는데 만약 sequence가 1개 일 경우에는 어떻게 될까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[mask , mask , mask , mask , item_A] 이런식으로 넣줘야할 것 같은데 이렇게 sequence가 짧을때에는 사용이 쉽지 않을 것 같다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;</description>
      <category>Recommendation</category>
      <author>정의김</author>
      <guid isPermaLink="true">https://jungeui.tistory.com/56</guid>
      <comments>https://jungeui.tistory.com/56#entry56comment</comments>
      <pubDate>Mon, 27 Mar 2023 21:13:58 +0900</pubDate>
    </item>
    <item>
      <title>Pyflink 간단한 사용법</title>
      <link>https://jungeui.tistory.com/55</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;요새 kafka, flink, spark 등등 자바로 만들어진 어플리케이션들도 python을 워낙 많이 지원하고 있어서 편리하다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Flink도 pyflink 라고 파이썬에서 flink 개발을 할 수 있도록 도와주는 라이브러리가 있어서 이를 간단히 정리하고자 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 이 글은 지금 패스트캠퍼스에 있는 강의를 참고해서 올리는데 코드의 세부 로직보다는 이런식으로 사용을 하는구나 정도를 정리함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;flink를 사용하는 방법이 여러가지가 있지만 쿼리형태로 source table , sink table 지정해서 사용하는게 제일 편리한 것 같아 이방법으로 정리함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;flink에서 가장 많이 사용되는 형태인 Kafka 를 통해 메세지를 받고 이를 가공해서 file이나 db등으로 보내는 것 을 예제로 담음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( kafka 메세지를 가공하고 hdfs에 csv를 적재하는 예제임 )&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;{text: &quot;hello world&quot;, timestamp: 13443252350 } , {text: &quot;hi&quot;, timestamp: 1323252350 }&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;와 같이 Json 형태의 데이터가 producing되면 이를 consuming한후 가공하여 hdfs에 csv로 적재하는 예제.&lt;/p&gt;
&lt;pre id=&quot;code_1679634510529&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import os
from pyflink.datastream import StreamExecutionEnvironment
from pyflink.table import StreamTableEnvironment, EnvironmentSettings, DataTypes
from pyflink.table.udf import udf 

env = StreamExecutionEnvironment.get_execution_environment()
env.set_parallelism(1)
settings = EnvironmentSettings.new_instance().in_streaming_mode().use_blink_planner().build()
t_env = StreamTableEnvironment.create(env, environment_settings=settings)

kafka_jar_path = os.path.join(
  os.path.abspath(os.path.dirname(__file__)), &quot;../&quot;,
  &quot;flink-sql-connector-kafka_2.11-1.14.0.jar&quot;
)

hadoop_jar_path = os.path.join(
    os.path.abspath(os.path.dirname(__file__)), &quot;../&quot;,
    &quot;flink-filesystem-hadoop-2.8.3-1.14.0.jar&quot;
)
jar_path = kafka_jar_path + ';' + hadoop_jar_path

t_env.get_config().get_configuration().set_string(
  &quot;pipeline.jars&quot;, jar_path
)

source_query = &quot;&quot;&quot;
  CREATE TABLE tweets (
    text STRING,
    timestamp_ms BIGINT,
    ts AS TO_TIMESTAMP_LTZ(timestamp_ms, 3),
    WATERMARK FOR ts AS ts - INTERVAL '5' SECOND
  ) WITH (
    'connector' = 'kafka',
    'topic' = 'korean-tweets',
    'properties.bootstrap.servers' = 'localhost:9092',
    'properties.group.id' = 'tweet-group',
    'format' = 'json',
    'scan.startup.mode' = 'latest-offset'
  )
&quot;&quot;&quot;

sink_query = &quot;&quot;&quot;
  CREATE TABLE sink (
    word STRING,
    count BIGINT
  ) WITH (
    'connector' = 'filesystem',
    'path' = 'hdfs://localhost:9000/output',
    'format' = 'csv'
  )
&quot;&quot;&quot;

t_env.execute_sql(source_query)
t_env.execute_sql(sink_query)

t_env.sql_query(&quot;&quot;&quot;
  SELECT word, COUNT(*)
  FROM (
    SELECT explode(split(text, ' ')) AS word
    FROM tweets
  )
  GROUP BY word
&quot;&quot;&quot;).execute_insert(&quot;sink&quot;)

env.execute(&quot;flink-kafka-hdfs&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 가장 먼저 spark , kafka 를 사용할 때 처럼 , &amp;nbsp;만들어줄 flink application과 관련한 env, setting 정의해주면 된다 .&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- set_parralelism 같은 경우 flink application이 데이터를 병렬처리할 수준을 정해줌 (쓰레드)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- streaming_mode와 함께 blink planner라는 것이 있는데 쿼리 옵티마이저를 선택해주는 부분이다. blink planner가 옵티마이징이 뛰어나다고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. &amp;nbsp;하둡 , 카프카를 사용하는데 필요한 jar파일 path 지정을 해주고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. source_query 와 sink query 부분을 각각 작성해줌.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(source =input으로 들어오는 데이터 - &amp;nbsp;kafka , sink = output으로 나가는 데이터- hdfs 를 정의)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;source_query를 tweet이라는 테이블명 , sink_query를 sink 라는 테이블로 이름 지어줌 .&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(스파크에서 createOrTempView 생각하면 됨 ).&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. t_env.execute_sql 은 실제로 실행해주는 부분은 아님 . 스파크의 lazy evaluation 생각하면됨 .&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. t_env.sql_query().execute_insert(&quot;sink&quot;) -&amp;gt; source_table tweet을 어떻게 가공해서 sink 테이블로 만들어줄지 부분을 정의하고 적재 할수 있도록 함 .&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6. env.exeute -&amp;gt; 위에서 정의한 job을 &quot;flink-kafka_hdfs&quot;이름의 application으로 flink 클러스터에 제출함.&lt;/p&gt;</description>
      <category>Data Engineering/Streaming</category>
      <author>정의김</author>
      <guid isPermaLink="true">https://jungeui.tistory.com/55</guid>
      <comments>https://jungeui.tistory.com/55#entry55comment</comments>
      <pubDate>Fri, 24 Mar 2023 11:23:35 +0900</pubDate>
    </item>
    <item>
      <title>Asynchronous 에 대한 간단한 정리</title>
      <link>https://jungeui.tistory.com/54</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;웹개발자가 아닌 나지만 하도 많이 들어본게 바로 Async 비동기 처리. 헷갈렸던 것들을 좀 적어보고 몇가지 개념들 정리해둠.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Non Blocknig , Async&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 non blocking 과 Async , 거의 같은 개념처럼 느껴지는데 솔직히 매우 유사하긴 하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Async는 프로그래밍의 방식이라고 생각하면된다. Synchronous하게 프로그래밍했다면 return값을 기다리는 방식이고 Async라고 하면 return 을 신경쓰지 않고 다음에 처리할수 있는 것을 처리하러 가게 프로그래밍하는 것.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;blocking은 반대로 방식이라기 보다는 실제로 물리적으로 일어나는 개념이라고 생각하면된다. io가 실제로 일어나냐 마느냐.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Coroutine&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비동기 처리가 가능한 함수를 파이썬에서 coroutine이라고함 , async def 와 같은 함수들.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Event loop , Await&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;coroutine객체는 event loop를 통해 관리가 된다고 한다. 정확히는 queue는 아니지만 queue처럼 들어온 coroutine객체를 차례차례 처리해줌 .&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Await는 다른 coroutine함수를 호출하는 함수임. coroutine객체를 호출하는 동안 호출한 해당함수는 멈추게 되고 다시 event loop의 관리에 들어가게 된다 .&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;예제) Fastapi , aioredis&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비동기 처리를 지원하는 웹프레임워크인 Fastapi . 보통 비동기 처리를 쓰는 경우가 네트워크 io, 디스크 io 일텐데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 redis를 쓴다고 할 때 비동기처리를 제대로 활용하기 위해선 그냥 redis 라이브러리가 아니라 aioredis와 같이 비동기처리가 지원되는 라이브러리를 써야된다고 한다. 간단한 코드 예제는 아래와 같음.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;라이브러리만 다르지 쓰는 방법은 거의 유사함&lt;/p&gt;
&lt;pre id=&quot;code_1679621802809&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import aioredis
from fastapi import FastAPI

app = FastAPI()

@app.on_event(&quot;startup&quot;)
async def startup():
    
    redis_pool = await aioredis.create_redis_pool(&quot;redis://localhost&quot;)

    app.state.redis = redis_pool

@app.on_event(&quot;shutdown&quot;)
async def shutdown():
    redis_pool.close()
    await redis_pool.wait_closed()

@app.post(&quot;/save&quot;)
async def save_data(data: str):
    redis_conn = redis_pool

    await redis_conn.set(&quot;mykey&quot;, data)

    return {&quot;message&quot;: &quot;Data saved successfully&quot;}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Python | Web/웹개발</category>
      <author>정의김</author>
      <guid isPermaLink="true">https://jungeui.tistory.com/54</guid>
      <comments>https://jungeui.tistory.com/54#entry54comment</comments>
      <pubDate>Fri, 24 Mar 2023 10:39:02 +0900</pubDate>
    </item>
    <item>
      <title>&amp;lt;Bayesian&amp;gt; MAB 톰슨 샘플링</title>
      <link>https://jungeui.tistory.com/53</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;MAB ( Multi Armed Bandit) :&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;활용되는 곳이 많지만 주로 상품 , 광고추천등에서 어떤 것 을 사용자에게 보여주어야 이득이 최대가 될까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동시에 특정 상품에 편향되지 않게 다양한 상품이 노출되게 할 수 있을까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;를 해결하는데 사용된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Epsilon- greedy, UCB등의 방법이 있는데 그 중에서도 많이 사용되는 Tomson Sampling 방법에 대해서 소개하고&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Pyro를 이용해서 구현해봄.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;베타분포&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_Photo_2022-12-03-19-17-32.jpeg&quot; data-origin-width=&quot;659&quot; data-origin-height=&quot;277&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bSzTVn/btrSIrE7g84/yb26ck9rbMwHOlAMUHVDx0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bSzTVn/btrSIrE7g84/yb26ck9rbMwHOlAMUHVDx0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bSzTVn/btrSIrE7g84/yb26ck9rbMwHOlAMUHVDx0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbSzTVn%2FbtrSIrE7g84%2Fyb26ck9rbMwHOlAMUHVDx0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;659&quot; height=&quot;277&quot; data-filename=&quot;KakaoTalk_Photo_2022-12-03-19-17-32.jpeg&quot; data-origin-width=&quot;659&quot; data-origin-height=&quot;277&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 베타분포에 대해서 알아야 하는데 베타분포는 성공횟수 a-1 , 실패횟수 B-1 만큼 관측 되었을 때 성공확률에 대한 확률분포이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;예를 들어 , a=1 , B=1 일 경우 사건이 발생하지 않은 경우이므로 성공확률은 어떤 정보도 없으므로 uniform distribution 형태가 될 것 이다. a=3 , B=3 일 경우 성공확률은 0.5 에서 가장 높고 대칭인 형태의 분포의가 나오게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Tomson Sampling&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;톰슨샘플링을 상품 추천에 대해 적용해서 설명해보고 구현도 해보았다. 사실 매우 간단해서 구현이라고 할 것도 없음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 톰슨샘플링은 각 상품에 대해 베타분포를 가정한다. &amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클릭률이 각각 3% , 5% , 10% 인 경우의 베타분포 a,b,c 를 가정하였음.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1670128828103&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import numpy as np
from scipy.special import beta
import matplotlib.pyplot as plt
import torch

beta_a = [3,100] # 3 %
beta_b = [6,120] # 5%
beta_c = [4,40] # 10 % 

beta_distributions = np.array([beta_a,beta_b,beta_c])
x = np.linspace(0, 1)

f,ax = plt.subplots(1,1,figsize=(20,8))
for b in beta_distributions:
    success = b[0]
    fail    = b[1] - b[0]
    y = (1 / beta(success, fail)) * x ** (success - 1) * (1 - x) ** (fail - 1)
    plt.plot(x,y)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;initial.png&quot; data-origin-width=&quot;1150&quot; data-origin-height=&quot;466&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Aq9aZ/btrSJxrw2xf/GszkGXkiVKHkeAw53wLEV1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Aq9aZ/btrSJxrw2xf/GszkGXkiVKHkeAw53wLEV1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Aq9aZ/btrSJxrw2xf/GszkGXkiVKHkeAw53wLEV1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAq9aZ%2FbtrSJxrw2xf%2FGszkGXkiVKHkeAw53wLEV1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1150&quot; height=&quot;466&quot; data-filename=&quot;initial.png&quot; data-origin-width=&quot;1150&quot; data-origin-height=&quot;466&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음으로 매 iteration 마다 3개의 베타분포에서 각각 샘플링을 한 후&amp;nbsp;가장 클릭률( x)이 높은 상품을 노출해주면 된다 .&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금 각각의 분포 a,b,c에서 샘플링을 한다면 좀더 오른쪽으로 치워치진 c &amp;gt; b &amp;gt; a 순으로 더 높은 x값을 기대해 볼 수 있다. ( exploit)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 항상 그런것은 아니다! 낮은 확률이지만 a의 샘플링 결과가 다른 두 분포보다 크게 나올 확률도 여전히 존재한다. (explore)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;샘플링을 한 결과 높은 값을 보여주고 베타분포를 매번 혹은 원하는 배치기간 마다 (ex - 매 10번 iteration 등) 업데이트 해주면 되겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시로는 샘플링을 한 결과를 항상 유저가 클릭했다고 가정하고 업데이트를 해보았다. ( 이런 경우는 없겠지만.. )&lt;/p&gt;
&lt;pre id=&quot;code_1670129391130&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;count = 0 
beta_distribution_a = torch.distributions.Beta(beta_a[0],beta_a[1] - beta_a[0] )
beta_distribution_b = torch.distributions.Beta(beta_b[0],beta_b[1] - beta_b[0])
beta_distribution_c = torch.distributions.Beta(beta_c[0],beta_c[1] - beta_c[0])
beta_distributions
for i in range(1000):
    
    samples = [beta_distribution_a.sample(), beta_distribution_b.sample() , beta_distribution_c.sample()]
    click = np.argmax(samples)
    beta_distributions[click][0] += 1
    beta_distributions[:,1] +=1&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1000번의 iteration 후 다음과 같이 1. 각 분포의 성공횟수, 전체횟수 2. 클릭률 이 변화하였다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;494&quot; data-origin-height=&quot;434&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rO8oP/btrSM4hsKIG/Qis2jqlOwtokynBfRJPI1K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rO8oP/btrSM4hsKIG/Qis2jqlOwtokynBfRJPI1K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rO8oP/btrSM4hsKIG/Qis2jqlOwtokynBfRJPI1K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrO8oP%2FbtrSM4hsKIG%2FQis2jqlOwtokynBfRJPI1K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;326&quot; height=&quot;286&quot; data-origin-width=&quot;494&quot; data-origin-height=&quot;434&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1670129512355&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;f,ax = plt.subplots(1,1,figsize=(20,8))
for b in beta_distributions:
    success = b[0]
    fail    = b[1] - b[0]
    y = (1 / beta(success, fail)) * x ** (success - 1) * (1 - x) ** (fail - 1)
    plt.plot(x,y)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;ㅋㅌㅊ.png&quot; data-origin-width=&quot;1150&quot; data-origin-height=&quot;466&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kBNQa/btrSJycTMV2/z4hmPBD8WH0alLPzvrlByk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kBNQa/btrSJycTMV2/z4hmPBD8WH0alLPzvrlByk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kBNQa/btrSJycTMV2/z4hmPBD8WH0alLPzvrlByk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkBNQa%2FbtrSJycTMV2%2Fz4hmPBD8WH0alLPzvrlByk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1150&quot; height=&quot;466&quot; data-filename=&quot;ㅋㅌㅊ.png&quot; data-origin-width=&quot;1150&quot; data-origin-height=&quot;466&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Data Science/Bayesian</category>
      <author>정의김</author>
      <guid isPermaLink="true">https://jungeui.tistory.com/53</guid>
      <comments>https://jungeui.tistory.com/53#entry53comment</comments>
      <pubDate>Sat, 3 Dec 2022 20:15:33 +0900</pubDate>
    </item>
    <item>
      <title>&amp;lt;Bayesian&amp;gt; Bayesian Optimization</title>
      <link>https://jungeui.tistory.com/52</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;Bayesian Optimization 을 이용하면 적은 시행만으로도 쉽게 Hyper Parameter 튜닝을 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;는 말을 ML 공부하는 사람이라면 한번 쯤은 들어봤을 듯.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떻게 Bayesian Optimization이 몇번의 시행만으로 Hyper Parameter를 쉽게 튜닝할 수 있을까?? 에 대해서 간단하게 적어보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Gaussian Process (GP)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;우선 Gaussian Process (GP)에 대해서 공부해야 한다. Bayesian Optimizaition을 수행함에 있어 GP 방법만이 있는 것은 아니다. 하지만 GP가 가장 많이 사용되는 방법임.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;Gausisian Process는 다변량 정규분포를 무한 차원으로 확장시킨 개념이다. 사실 &quot;무한&quot; 이라는 특징보다 Bayesian Optimizaition 을 이해함에 있어 중요한 특징은 따로 있다. 베이지안 리그레션의 경우 각 관측치 or 설명변수들이 서로 독립이다는 가정이 있는 것과 다르게 가우시안 프로세스의 경우에는 각 x_i 에서의 정규분포들 사이에 상관성을 가지고 있다. 회귀분석을 배울때 각 설명변수 x_i 에서 y의 값을 정규분포를 가정하는 것을 봤을 것이다. 이 정규분포들이 회귀분석 or 베이지안 리그레션등에서는 서로 독립이지만 가우시안 프로세스에서는 각 정규분포끼리 독립을 가정하지 않는다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;(일반적으로) 정규분포들끼리 연관이 되어있다 -&amp;gt; 공분산행렬 을 쉽게 떠올릴 수 있을 것이다. 살짝 다른 점은 공분산행렬 대신 커널함수를 사용하여 정규분포들끼리의 상관성을 나타낸다 . Kernel 함수의 경우에도 여러개가 있지만 대표적으로 많이 쓰이는 커널 함수에는 RBF 커널이 있다. (&amp;nbsp;식에서 d = x_i와 x_j 의 유클리안 거리를 의미 )&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;764&quot; data-origin-height=&quot;224&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sf8wY/btrSjvVhsjy/qlPArGrexwRL71hViJmvT0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sf8wY/btrSjvVhsjy/qlPArGrexwRL71hViJmvT0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sf8wY/btrSjvVhsjy/qlPArGrexwRL71hViJmvT0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fsf8wY%2FbtrSjvVhsjy%2FqlPArGrexwRL71hViJmvT0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;266&quot; height=&quot;78&quot; data-origin-width=&quot;764&quot; data-origin-height=&quot;224&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;커널함수는 GP를 통해 모델을 학습할 때 사용되는데 관측치 ( 알고 있는 x_i) 와 가까울 경우 신뢰구간이 매우 좁아지고 멀 경우 신뢰구간이 점점 멀어지게 된다. 이 2가지 포인트 &lt;b&gt;1. (베이지안 이므로) 점 추정이 아니라 확률분포로써 신뢰구간을 가짐. 2. 관측치와 가까운 지점은 신뢰구간이 매우 좁아지고 멀어질수록 신뢰구간이 커짐 ( 예를 들어 , f(100)을 추정함에 있어서 f(99)값이 f(1)값 보다 도움이 될 것 이라고 생각하는 것은 당연하다 . ) &lt;/b&gt;를 바탕으로 다음 베이지안 옵티마이제이션을 이어서 설명하겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가로 , 커널 함수가 &lt;span style=&quot;color: #000000;&quot;&gt; ( , )=  라면 ( 즉, 서로 독립이라면) Bayesian Regression과 같은 문제가 된다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1.일반적인 Regression 2. Bayesian Regression 3. Gaussian Process 의경우 다음과 같이 모델이 만들어지게 된다 .&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Bayesian Optimization&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 Bayesian Optimization이 어떻게 동작하는지 알아보자 . 먼저 추정하고자 하는 함수를 임의로 다음과 같이 정의 하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;x는 크기가 2인 list이고 2개의 값 x[0] 과 x[1]을 바탕으로 obj_func의 값이 나오게 된다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1669628054697&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def obj_func(x): # [a,b]
    return x[0] ** 2 * np.sin(5* np.pi * (-x[0] + 2 * x[1]))&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 샘플링을 수행하는 함수를 다음과 같이 정의 하였다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1669628221453&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import numpy as np
def sampler(n):
    return np.random.random((n,2))&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 샘플링(10개) 을 통해 최적화 하고 싶은 함수 obj_func에 대한 값을 관측해 준다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 샘플들(x)과 func(x)= Y 를 구함 .&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1669628424423&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;X = sampler(n) 
y = np.apply_along_axis(obj_func , axis = 1 , arr = X)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;X, y에 fit하는 가우시안 프로세스 모델을 만들어준다 .&amp;nbsp; RBF 커널을 사용하였고 WhiteKernel은 노이즈 .&lt;/p&gt;
&lt;pre id=&quot;code_1669628829249&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from sklearn.gaussian_process import GaussianProcessRegressor as GRR
from sklearn.gaussian_process.kernels import RBF , WhiteKernel

model = GRR(kernel = RBF() + WhiteKernel() , random_state =2022).fit(X,y)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;10개의 샘플링을 통해 가우시안 프로세스 모델을 만들었다면 다음으로 어디를 탐색해야 할지를 정해야 하는데 이 척도로 acquisition function을 사용한다. 가장 많이 사용되는 방법은 EI (&lt;span style=&quot;color: #555555;&quot;&gt;Expected Improvement) 이다. 강화학습에서 기본적인 idea가 되는 &lt;span style=&quot;color: #555555;&quot;&gt;Exploration 과 &lt;span style=&quot;color: #555555;&quot;&gt;Exploitation 방법을 적용하여 탐색을 해가는 방법이라는데&amp;nbsp; 요약하자면 기존에 구한 best_mu (최고의 평균값) 보다 더 높은 값이 나올 확률을 새로 구한 x들 에 대해서 구하고 ( 그림에서 초록 부분 )&amp;nbsp; 그 확률이 가장 높은 x를 다음 탐색 지점으로 정하는 것이다. 수식이 다음과 같이 나온다고 한다. 근데 (mu-best_mu -e) * norm.cdf(z) 여기까지가 초록 부분의 영역인데 다음 항은 왜 더해주는지는 아직 모르겠다..&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1669635080492&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from scipy.stats import norm

def EI(X_new, model , best_mu , e= 0.01):
    mu , sigma = model. predict(X_new , return_std = True)
    z= np.zeros(len(X_new))
    z[sigma&amp;gt;0] = ((mu- best_mu -e ) / sigma    )[sigma&amp;gt;0]
    return (mu-best_mu -e) * norm.cdf(z) + sigma * norm.pdf(z)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1734&quot; data-origin-height=&quot;1264&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4c2P3/btrSlkFVe4f/BkzexPBjwbkdktJiG4Tz61/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4c2P3/btrSlkFVe4f/BkzexPBjwbkdktJiG4Tz61/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4c2P3/btrSlkFVe4f/BkzexPBjwbkdktJiG4Tz61/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4c2P3%2FbtrSlkFVe4f%2FBkzexPBjwbkdktJiG4Tz61%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;605&quot; height=&quot;441&quot; data-origin-width=&quot;1734&quot; data-origin-height=&quot;1264&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;계속 설명하자면&lt;br /&gt;1. 아까 샘플링한 10개에서 최고의 값을 구하고 best_mu로 저장한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 다음 탐색할 지점을 정하기 위해 한번 더 랜덤하게 10개를 뽑은 후 각각의 지점에 대해서 EI값을 구한다 = score_list&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 구해진 score_list에서 가장 높게 나온 값을 다음 탐색지점으로 정함 = x_new . 실제로 func으로 predict&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 결과를 저장한다. (X ,y 에 )&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. iter 돌면서 반복&lt;/p&gt;
&lt;pre id=&quot;code_1669635626906&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;best_mu = max(model.predict(X))
X_new = sampler(n)
score_list = EI(X_new, model , best_mu)
x_new =  X_new[score_list.argmax()]
y_new = obj_func(x_new)
X = np.vstack([X,x_new])
y = np.append(y,y_new)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최종 코드는 다음과 같음.&lt;/p&gt;
&lt;pre id=&quot;code_1669635939105&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def main(n, num_iter):
    X = sampler(n)
    y = np.apply_along_axis(obj_func , axis = 1 , arr = X)
    
    for _ in range(num_iter):
        model = GRR(kernel = RBF() + WhiteKernel() , random_state =2022).fit(X,y)
        best_mu = max(model.predict(X))
        X_new = sampler(n)
        score_list = EI(X_new, model , best_mu)
        x_new =  X_new[score_list.argmax()]
        y_new = obj_func(x_new)
        X = np.vstack([X,x_new])
        y = np.append(y,y_new)
        
        print(X)
    return X[y.argmax()] , y.max()&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Data Science/Bayesian</category>
      <author>정의김</author>
      <guid isPermaLink="true">https://jungeui.tistory.com/52</guid>
      <comments>https://jungeui.tistory.com/52#entry52comment</comments>
      <pubDate>Sun, 27 Nov 2022 21:55:21 +0900</pubDate>
    </item>
    <item>
      <title>&amp;lt;Bayesian&amp;gt; Variational Inference  ( Pyro)</title>
      <link>https://jungeui.tistory.com/51</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;앞 선 포스팅에서 pyro를 이용해 mcmc를 사용하는 법을 써보았다. mcmc의 경우 샘플링수를 충분히 늘린다면 사후분포를 잘 추정할 수 있겠지만 샘플링수가 늘어나는 만큼 사후분포를 추정하는 시간이 오래 걸릴 것이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사후분포를 좀더 빠르게 추정하기 위해서 기존의 모델들이 그랬듯이 최소화할 Loss를 지정하고 이를 줄여서 근사한 해를 구하는 방식을 사용하여 사후분포를 추정할 수 있다. 이 방법이 바로 Vairational Inference = VI = 변분추론 .&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;VI에서는 후선 사후분포를 추정하기 위해 q라는 분포를 가정한다. 사후분포는 일반적으로 구하기에는 너무 복잡하기 때문. (notation은 당연히 다를 수 있는데 보통 q로 표현)&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 q라는 분포를 우리가 구해야하는 사후분포에 최대한 근사하게 만들면 그것이 바로 사후분포에 대한 좋은 추정값이 될 것이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사후분포와 q가 근사하다는 기준을 KL- diverence을 통해 구한다. KL- divergence가 최소가 되도록하는 q가 사후분포와 가장 근사한 분포가 되는 것. 이 KL-divergence도 구하기가 매우 어렵기 때문에 KL-divergence를 최소로 하기 위해서는 ELBO를 최대로 하면 된다 .&lt;br /&gt;이 ELBO가 일종의 loss function 역할을 해줄 것.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(KL- divergence와 ELBO에 대해서는 설명해주는 블로그 들이 매우 많으므로 그걸 참고. 이 글에서는 pyro를 통해 프로그래밍 하기 위해서 최소한의 지식만을 적어둠. )&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Pyro 를 통한 프로그래밍 .&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;역시나 pyro Doc에 있는 예제 가져옴. 동전던지기 예제. &amp;nbsp;베이지안을 공부하면 거의 항상 처음에 나오는 앞면이 나올 확률이 50프로가 정말 맞을까 예제임. &amp;nbsp;첫번째 포스팅에서 설명했던 것들은 생략하고 적어봄.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://pyro.ai/examples/svi_part_i.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://pyro.ai/examples/svi_part_i.html&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1668234509265&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;SVI Part I: An Introduction to Stochastic Variational Inference in Pyro &amp;mdash; Pyro Tutorials 1.8.2 documentation&quot; data-og-description=&quot;Pyro has been designed with particular attention paid to supporting stochastic variational inference as a general purpose inference algorithm. Let&amp;rsquo;s see how we go about doing variational inference in Pyro. Setup We&amp;rsquo;re going to assume we&amp;rsquo;ve already de&quot; data-og-host=&quot;pyro.ai&quot; data-og-source-url=&quot;https://pyro.ai/examples/svi_part_i.html&quot; data-og-url=&quot;https://pyro.ai/examples/svi_part_i.html&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dC6ahD/hyQxD0rdLF/fZrNZvMkJQLtzkIPb3U4b1/img.png?width=1154&amp;amp;height=736&amp;amp;face=0_0_1154_736&quot;&gt;&lt;a href=&quot;https://pyro.ai/examples/svi_part_i.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://pyro.ai/examples/svi_part_i.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dC6ahD/hyQxD0rdLF/fZrNZvMkJQLtzkIPb3U4b1/img.png?width=1154&amp;amp;height=736&amp;amp;face=0_0_1154_736');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;SVI Part I: An Introduction to Stochastic Variational Inference in Pyro &amp;mdash; Pyro Tutorials 1.8.2 documentation&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Pyro has been designed with particular attention paid to supporting stochastic variational inference as a general purpose inference algorithm. Let&amp;rsquo;s see how we go about doing variational inference in Pyro. Setup We&amp;rsquo;re going to assume we&amp;rsquo;ve already de&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;pyro.ai&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1668234819280&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import pyro.distributions as dist

def model(data):
    # define the hyperparameters that control the Beta prior
    alpha0 = torch.tensor(10.0)
    beta0 = torch.tensor(10.0)
    # sample f from the Beta prior
    f = pyro.sample(&quot;latent_fairness&quot;, dist.Beta(alpha0, beta0))
    # loop over the observed data
    for i in range(len(data)):
        # observe datapoint i using the Bernoulli
        # likelihood Bernoulli(f)
        pyro.sample(&quot;obs_{}&quot;.format(i), dist.Bernoulli(f), obs=data[i])&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 먼저 앞면이 나올 확률 p 를 f = 베타(10,10)으로 가정한다. &amp;nbsp;베타분포의 두 모수 alpha, beta 값이 같을 경우 x = 0.5에서 극대값을 가지면 대칭인 분포를 가진다. 샘플을 관측하기 전에 p= 0.5 즉 , 반반이라고 가정하는 것이 가장 타당한 사전분포 일 것이다. 그리고&lt;br /&gt;for i in range(len(data)):&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; pyro.sample~~~&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;을 통해 샘플링한 값을 넣어준다. 여기에는 for을 이용해서 샘플링한 값을 반영해주었지만 앞서 사용햇드이 plate를 이용해도 상관없다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음으로 f라는 사후분포를 추정하는데 사용할 q를 지정해줘야 한다. 이를 pyro 에서는 guide 라고 함 .&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1668235702141&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def guide(data):
    # register the two variational parameters with Pyro.
    alpha_q = pyro.param(&quot;alpha_q&quot;, torch.tensor(15.0),
                         constraint=constraints.positive)
    beta_q = pyro.param(&quot;beta_q&quot;, torch.tensor(15.0),
                        constraint=constraints.positive)
    # sample latent_fairness from the distribution Beta(alpha_q, beta_q)
    pyro.sample(&quot;latent_fairness&quot;, dist.Beta(alpha_q, beta_q))&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. &amp;nbsp;첫번째 포스팅에서 언급한적 있는데 &quot;latent_fairness&quot;라는 이름은 guide와 model 각각에서 똑같이 지정을 해주어야함.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. torch.param으로 지정해두면 default로 require_grad = True가 되어 그라디언트를 통해 학습이 됨 .&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 모델을 만들고 fit해주면 끝.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1668235983167&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# set up the optimizer
adam_params = {&quot;lr&quot;: 0.0005, &quot;betas&quot;: (0.90, 0.999)}
optimizer = Adam(adam_params)

# setup the inference algorithm
svi = SVI(model, guide, optimizer, loss=Trace_ELBO())

n_steps = 5000
# do gradient steps
for step in range(n_steps):
    svi.step(data)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. Optimizer로는 아담을 사용ㅎ.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. loss는 앞서 말했듯이 elbo를 사용할거고 Trace_ELbo() 를 통해 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. iteration은 5000번 .&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아직 data를 지정 안해주었는데 6번 앞면 이 나오고 4번 뒷면이 나온 상황을 가정할 것이다&amp;nbsp;&lt;br /&gt;data= [1,1,1,1,1,1,0,0,0,0]&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;종합하면 코드는 다음과 같음.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1668236104348&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import math
import os
import torch
import torch.distributions.constraints as constraints
import pyro
from pyro.optim import Adam
from pyro.infer import SVI, Trace_ELBO
import pyro.distributions as dist

# this is for running the notebook in our testing framework
smoke_test = ('CI' in os.environ)
n_steps = 2 if smoke_test else 2000

assert pyro.__version__.startswith('1.8.2')

# clear the param store in case we're in a REPL
pyro.clear_param_store()

# create some data with 6 observed heads and 4 observed tails
data = []
for _ in range(6):
    data.append(torch.tensor(1.0))
for _ in range(4):
    data.append(torch.tensor(0.0))

def model(data):
    # define the hyperparameters that control the Beta prior
    alpha0 = torch.tensor(10.0)
    beta0 = torch.tensor(10.0)
    # sample f from the Beta prior
    f = pyro.sample(&quot;latent_fairness&quot;, dist.Beta(alpha0, beta0))
    # loop over the observed data
    for i in range(len(data)):
        # observe datapoint i using the ernoulli likelihood
        pyro.sample(&quot;obs_{}&quot;.format(i), dist.Bernoulli(f), obs=data[i])

def guide(data):
    # register the two variational parameters with Pyro
    # - both parameters will have initial value 15.0.
    # - because we invoke constraints.positive, the optimizer
    # will take gradients on the unconstrained parameters
    # (which are related to the constrained parameters by a log)
    alpha_q = pyro.param(&quot;alpha_q&quot;, torch.tensor(15.0),
                         constraint=constraints.positive)
    beta_q = pyro.param(&quot;beta_q&quot;, torch.tensor(15.0),
                        constraint=constraints.positive)
    # sample latent_fairness from the distribution Beta(alpha_q, beta_q)
    pyro.sample(&quot;latent_fairness&quot;, dist.Beta(alpha_q, beta_q))

# setup the optimizer
adam_params = {&quot;lr&quot;: 0.0005, &quot;betas&quot;: (0.90, 0.999)}
optimizer = Adam(adam_params)

# setup the inference algorithm
svi = SVI(model, guide, optimizer, loss=Trace_ELBO())

# do gradient steps
for step in range(n_steps):
    svi.step(data)
    if step % 100 == 0:
        print('.', end='')

# grab the learned variational parameters
alpha_q = pyro.param(&quot;alpha_q&quot;).item()
beta_q = pyro.param(&quot;beta_q&quot;).item()

# here we use some facts about the Beta distribution
# compute the inferred mean of the coin's fairness
inferred_mean = alpha_q / (alpha_q + beta_q)
# compute inferred standard deviation
factor = beta_q / (alpha_q * (1.0 + alpha_q + beta_q))
inferred_std = inferred_mean * math.sqrt(factor)

print(&quot;\nBased on the data and our prior belief, the fairness &quot; +
      &quot;of the coin is %.3f +- %.3f&quot; % (inferred_mean, inferred_std))&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Data Science/Bayesian</category>
      <author>정의김</author>
      <guid isPermaLink="true">https://jungeui.tistory.com/51</guid>
      <comments>https://jungeui.tistory.com/51#entry51comment</comments>
      <pubDate>Sat, 12 Nov 2022 15:15:10 +0900</pubDate>
    </item>
    <item>
      <title>&amp;lt;Bayesian&amp;gt; MCMC, pyro 로 모델링 (HMC)</title>
      <link>https://jungeui.tistory.com/49</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;앞써서 베이지안 리그레션을 pyro로 모델링하는 방법에 대하여 포스팅 했다. svi를 이용해서 사후분포를 추론하는 방법을 다루었는데 이번에는 MCMC를 이용해 사후분포를 추정하는 것을 pyro를 이용해 모델링 하는 방법에 대하여 포스팅함.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실, 매우 간단함. 라이브러리를 사용하는 것은.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예제는 앞써서 사용했던 log_gdp를 두개의 설명변수 ( rugged ,&amp;nbsp; cont_africa , rugged* cont_africa)를 통해 모델링 하는 것을 그대로 사용하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 데이터를 받아와서 전처리하는 과정 . 특별한 것은 없고 df_rugged , df_cont_africa , df_log_gdp 를 torch의 텐서로 바꿔줌. (pyro가 토치를 기반으로 만들어진 프레임워크라)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1626&quot; data-origin-height=&quot;502&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ZG2Nt/btrPTjI9lqR/gVcLGq4nDvUTZekQnhuCj0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ZG2Nt/btrPTjI9lqR/gVcLGq4nDvUTZekQnhuCj0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ZG2Nt/btrPTjI9lqR/gVcLGq4nDvUTZekQnhuCj0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZG2Nt%2FbtrPTjI9lqR%2FgVcLGq4nDvUTZekQnhuCj0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1626&quot; height=&quot;502&quot; data-origin-width=&quot;1626&quot; data-origin-height=&quot;502&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 모델 정의, 앞서 베이지안 리그레션에서 사용한 모델 그대로이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2432&quot; data-origin-height=&quot;406&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/clxS7U/btrPR5j6C8T/iXk4AulilH7SAWHx3Fmwlk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/clxS7U/btrPR5j6C8T/iXk4AulilH7SAWHx3Fmwlk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/clxS7U/btrPR5j6C8T/iXk4AulilH7SAWHx3Fmwlk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FclxS7U%2FbtrPR5j6C8T%2FiXk4AulilH7SAWHx3Fmwlk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2432&quot; height=&quot;406&quot; data-origin-width=&quot;2432&quot; data-origin-height=&quot;406&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. Variational Inferece를 사용할 때는 근사분포 q를 위해 guide를 만들어줘야 했지만 mcmc는 샘플링 방법이므로 당연하게도 필요 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. mcmc&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 pyro의 mcmc 는 hmc라는 방법을 사용하여 mcmc를 수행한다고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실, 이건 처음 봤는데 기존에 metropolis hasting, gibbs sampling 등에 비하여 연산량이 많이 들지만 대신 적은 샘플링만으로도 꽤 훌륭하게 사후분포를 추정하는 것이 가능하다고 한다. 다만 단점으로는 parameter의 space가 conitnuous 하지 않고 discrete할 경우에는 사용 할 수 없다고 한다 . 이럴때에는 깁스샘플링을 사용해야할 것 같은데 깁스샘플링은 pyro 에서 제공하지 않아서 따로 작업을 조금해주어야한다. 다행히도 example이 있어서 후에 깁스샘플링도 올려보겠음!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 첫번째 줄에 보면 nuts라는 것이 있는데 no u-turn sampling 으로 hmc를 수행할 때 더 효율적으로 수행할 수 있다고 한다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1667117270501&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;kernel = NUTS(model) # no u-turn sampling 
mcmc = MCMC(kernel, num_samples=1000)

mcmc.run(df_rugged, df_cont_africa, df_log_gdp) # hmc 를 사용&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 추론한 결과에 대하여 다음과 같이 확인 가능하다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2030&quot; data-origin-height=&quot;1338&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bDB8Kf/btrPQx9s5jQ/L6Chlv3Sn8lik3KQUW7wdk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bDB8Kf/btrPQx9s5jQ/L6Chlv3Sn8lik3KQUW7wdk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bDB8Kf/btrPQx9s5jQ/L6Chlv3Sn8lik3KQUW7wdk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbDB8Kf%2FbtrPQx9s5jQ%2FL6Chlv3Sn8lik3KQUW7wdk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;690&quot; height=&quot;455&quot; data-origin-width=&quot;2030&quot; data-origin-height=&quot;1338&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1468&quot; data-origin-height=&quot;1488&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b8e2mK/btrPQg71KTQ/drMNxngKiVizS6lBGTPkq1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b8e2mK/btrPQg71KTQ/drMNxngKiVizS6lBGTPkq1/img.png&quot; data-alt=&quot;각 parameter에 대한 확률분포&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b8e2mK/btrPQg71KTQ/drMNxngKiVizS6lBGTPkq1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb8e2mK%2FbtrPQg71KTQ%2FdrMNxngKiVizS6lBGTPkq1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;661&quot; height=&quot;670&quot; data-origin-width=&quot;1468&quot; data-origin-height=&quot;1488&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;각 parameter에 대한 확률분포&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/todtjs92/Bayesian/blob/master/pyro/1.MCMC.ipynb&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/todtjs92/Bayesian/blob/master/pyro/1.MCMC.ipynb&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1667117829867&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - todtjs92/Bayesian: Pyro 또는 torch 를 이용한 베이지안 프로그래밍&quot; data-og-description=&quot;Pyro 또는 torch 를 이용한 베이지안 프로그래밍. Contribute to todtjs92/Bayesian development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/todtjs92/Bayesian/blob/master/pyro/1.MCMC.ipynb&quot; data-og-url=&quot;https://github.com/todtjs92/Bayesian&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bXNRtB/hyQpDLUGw5/gCNCO1GK8WN0WoZpaGKi7K/img.png?width=1200&amp;amp;height=600&amp;amp;face=969_136_1057_231&quot;&gt;&lt;a href=&quot;https://github.com/todtjs92/Bayesian/blob/master/pyro/1.MCMC.ipynb&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/todtjs92/Bayesian/blob/master/pyro/1.MCMC.ipynb&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bXNRtB/hyQpDLUGw5/gCNCO1GK8WN0WoZpaGKi7K/img.png?width=1200&amp;amp;height=600&amp;amp;face=969_136_1057_231');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - todtjs92/Bayesian: Pyro 또는 torch 를 이용한 베이지안 프로그래밍&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Pyro 또는 torch 를 이용한 베이지안 프로그래밍. Contribute to todtjs92/Bayesian development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Data Science/Bayesian</category>
      <author>정의김</author>
      <guid isPermaLink="true">https://jungeui.tistory.com/49</guid>
      <comments>https://jungeui.tistory.com/49#entry49comment</comments>
      <pubDate>Sun, 30 Oct 2022 17:17:18 +0900</pubDate>
    </item>
    <item>
      <title>&amp;lt;Recommendation&amp;gt; Faiss , 벡터서치</title>
      <link>https://jungeui.tistory.com/48</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Faiss는 페이스북에서 공개한 벡터 유사도를 검색해주는 프레임워크이다. 벡터 유사도 검색 외에 빠르게 k-means를 찾아 주는 등 여러 기능이 있다. 내부적으로 C++ 로 구현되어 있어 매우 빠르고 GPU 연산도 지원을 해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Latent Dimension = 5 인 임의의 벡터들중에서 가장 유사한 벡터를 찾는 예제&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;vector_index라는 객체를 만들어주고 sample_vectors 라는&amp;nbsp; hidden_dimension = 5인 100개의 벡터들을 색인해준다.&lt;/p&gt;
&lt;pre id=&quot;code_1666402885298&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import faiss

latent_dimension = 5
vector_index = faiss.IndexFlatIP(latent_dimension) # latent dimension = 5
vector_index.add(sample_vectors.astype('float32')) #&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1518&quot; data-origin-height=&quot;774&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KJD7U/btrPfnzIazO/u1fmKwQkY19pKUY0nqL9M0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KJD7U/btrPfnzIazO/u1fmKwQkY19pKUY0nqL9M0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KJD7U/btrPfnzIazO/u1fmKwQkY19pKUY0nqL9M0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKJD7U%2FbtrPfnzIazO%2Fu1fmKwQkY19pKUY0nqL9M0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;668&quot; height=&quot;341&quot; data-origin-width=&quot;1518&quot; data-origin-height=&quot;774&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 만든 100개의 벡터 (vector_index) 에 대해 가장 가까운 target_vector를 생성하고 찾는다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1474&quot; data-origin-height=&quot;184&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zmcdd/btrPh72YWgV/mOr00WvFxVrmkwWqvCUgZ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zmcdd/btrPh72YWgV/mOr00WvFxVrmkwWqvCUgZ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zmcdd/btrPh72YWgV/mOr00WvFxVrmkwWqvCUgZ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fzmcdd%2FbtrPh72YWgV%2FmOr00WvFxVrmkwWqvCUgZ1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1474&quot; height=&quot;184&quot; data-origin-width=&quot;1474&quot; data-origin-height=&quot;184&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5개까지 가까운 벡터를 찾았고 rating 과 랭킹을 반환 .&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1668&quot; data-origin-height=&quot;324&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/9RekI/btrPfbfdGFU/NmvCvDmUxx3kLWawOKgbtK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/9RekI/btrPfbfdGFU/NmvCvDmUxx3kLWawOKgbtK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/9RekI/btrPfbfdGFU/NmvCvDmUxx3kLWawOKgbtK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F9RekI%2FbtrPfbfdGFU%2FNmvCvDmUxx3kLWawOKgbtK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1668&quot; height=&quot;324&quot; data-origin-width=&quot;1668&quot; data-origin-height=&quot;324&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;인덱스가 있을 경우 .&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추천등에 사용할 때 user_id 혹은 item_id 와 같이 인덱스가 붙어있을때 주어진 인덱스를 바로 구할 수 있게 기능을 제공한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;faiss.IndexIDMap2 , add_with_ids 라는 메소드 사용해주면 됨.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1666403444716&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;vector_index = faiss.IndexFlatIP(latent_dimension)
vector_index = faiss.IndexIDMap2(vector_index)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아이디가 다음과 같이 부여되어있다고 가정해보았다. 아까 예제와 다르게 벡터사전의 크기도 4 * 5로 줄임&lt;/p&gt;
&lt;pre id=&quot;code_1666403517795&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ids = np.array([4,10,2,3])
vector_index.add_with_ids(sample_vectors.astype('float32'), ids) # ids도 같이 넣어주면됨.&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1566&quot; data-origin-height=&quot;314&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfgVWP/btrPgoR9iAk/kMPq3OGFvTNjFjqBQY1zY1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfgVWP/btrPgoR9iAk/kMPq3OGFvTNjFjqBQY1zY1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfgVWP/btrPgoR9iAk/kMPq3OGFvTNjFjqBQY1zY1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfgVWP%2FbtrPgoR9iAk%2FkMPq3OGFvTNjFjqBQY1zY1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1566&quot; height=&quot;314&quot; data-origin-width=&quot;1566&quot; data-origin-height=&quot;314&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;임의의 target_vector를 생성해주고 유사한 벡터를 찾으면 해당 인덱스를 반환하는 것을 확인 가능&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1580&quot; data-origin-height=&quot;138&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/csS5Zl/btrPgeoq14V/xHooAOhEKMaacvXGPNGGw0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/csS5Zl/btrPgeoq14V/xHooAOhEKMaacvXGPNGGw0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/csS5Zl/btrPgeoq14V/xHooAOhEKMaacvXGPNGGw0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcsS5Zl%2FbtrPgeoq14V%2FxHooAOhEKMaacvXGPNGGw0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1580&quot; height=&quot;138&quot; data-origin-width=&quot;1580&quot; data-origin-height=&quot;138&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1640&quot; data-origin-height=&quot;250&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mdsfj/btrPhmlE2Rz/DImQ7Z9pChfbg4T1WCcIa1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mdsfj/btrPhmlE2Rz/DImQ7Z9pChfbg4T1WCcIa1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mdsfj/btrPhmlE2Rz/DImQ7Z9pChfbg4T1WCcIa1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fmdsfj%2FbtrPhmlE2Rz%2FDImQ7Z9pChfbg4T1WCcIa1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1640&quot; height=&quot;250&quot; data-origin-width=&quot;1640&quot; data-origin-height=&quot;250&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빠르게 유사한 벡터를 찾아주는 방법이 있다면&amp;nbsp; 기존에 행렬을 복원하여 복원된 행렬을 바탕으로 추천해주는 방법 외에&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유저가 마지막으로 본 아이템과 유사한 아이템을 벡터서칭을 통해 찾아서 추천을 해주는 방법 또한 가능할 것 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_Photo_2022-10-22-11-03-01.jpeg&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;1018&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bXvYr5/btrPiujtpZn/kBi2oXzFs4DQFtCIkp9Q7K/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bXvYr5/btrPiujtpZn/kBi2oXzFs4DQFtCIkp9Q7K/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bXvYr5/btrPiujtpZn/kBi2oXzFs4DQFtCIkp9Q7K/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbXvYr5%2FbtrPiujtpZn%2FkBi2oXzFs4DQFtCIkp9Q7K%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;1018&quot; data-filename=&quot;KakaoTalk_Photo_2022-10-22-11-03-01.jpeg&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;1018&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Recommendation/서빙</category>
      <author>정의김</author>
      <guid isPermaLink="true">https://jungeui.tistory.com/48</guid>
      <comments>https://jungeui.tistory.com/48#entry48comment</comments>
      <pubDate>Sat, 22 Oct 2022 11:04:57 +0900</pubDate>
    </item>
    <item>
      <title>&amp;lt;Python&amp;gt; pydantic</title>
      <link>https://jungeui.tistory.com/47</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;pydantic은 type annotation 을 바탕으로 데이터를 검증해주고 어긋날 시 올바른 형태로 바꿔주는 역할을 해주는 라이브러리다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주로 사용처는 fastapi를 통해 웹개발을 할 때 request , response 등을 통해 데이터를 주고 받을 때 데이터들을 검증해줄때 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 포스팅에 sql_alchemy 이용해서 DB연동하는 내용을 적을라고 했는데 한번에 같이 적는 것 보다는 나눠 적는게 나은 것 같아 적어봄!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;fastapi에서 사용하는 예시를 가져왔다 (매우 간단하기 하지만) . 유저테이블에 다음과 같이 데이터를 넣어 줄 때 해당 컬럼의 자료형을 체크해주는 것. 이름에 이상한 숫자가 들어온다면 오류를 내뱉거나 자동으로 형변환이 가능하다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1665798950624&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def add_user(user: schemas.User, db: Session) -&amp;gt; models.User: # schema.py의 User클래스를 이용
    row = models.User(
        id=user.id,
        username=user.username,
        
    )
    db.add(row)
    db.commit()
    return row&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1666604191634&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# schema.py
from pydantic import BaseModel

class User(BaseModel):
    id: int
    user_name : str&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;pydantic을 사용할 때 위와 같이 BaseModel 이라는 클래스를 상속받아서 만들어준 클래스에 데이터와 자료형을 적어주면 됨 .&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 선언한 자료형과 다른 데이터가 들어올 경우 자동으로 자료형을 옳바른 자료형으로 바꿔준다 .&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1996&quot; data-origin-height=&quot;724&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KmooG/btrPxIpzKQn/cUNPKKktDY0aKbLlEoB3g1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KmooG/btrPxIpzKQn/cUNPKKktDY0aKbLlEoB3g1/img.png&quot; data-alt=&quot;items라는 리스트에 string형의 잘못된 데이터가 들어올 경우 자동으로 int로 바꿔준 모습 .&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KmooG/btrPxIpzKQn/cUNPKKktDY0aKbLlEoB3g1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKmooG%2FbtrPxIpzKQn%2FcUNPKKktDY0aKbLlEoB3g1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1996&quot; height=&quot;724&quot; data-origin-width=&quot;1996&quot; data-origin-height=&quot;724&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;items라는 리스트에 string형의 잘못된 데이터가 들어올 경우 자동으로 int로 바꿔준 모습 .&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Python | Web/Python</category>
      <author>정의김</author>
      <guid isPermaLink="true">https://jungeui.tistory.com/47</guid>
      <comments>https://jungeui.tistory.com/47#entry47comment</comments>
      <pubDate>Sat, 15 Oct 2022 10:55:55 +0900</pubDate>
    </item>
  </channel>
</rss>