RLHF(3) : WebGPT: Browser-assisted question-answering with human feedback 논문 리뷰

OpenAI에서 발표한 webGPT는 웹을 더욱 효율적이고 지능적으로 활용하기 위한 새로운 기술입니다. 오늘은 webGPT에 대해서 알아보도록 하겠습니다. 최근 streamlit으로 webGPT와 유사한 포스팅을 하였는데, 그 포스팅은 근간이 되는 논문이라고 보시면 됩니다.

WebGPT 예시
WebGPT 예시

WebGPT의 핵심 개념

WebGPT는 기본적으로 OpenAI의 GPT (Generative Pretraining Transformer) 시리즈의 연장선에 있는 것으로, 큰 데이터세트에 대한 비지도 학습을 통해 문맥을 이해하고, 텍스트 생성, 번역, 요약 등과 같은 작업을 수행하는 데 중점을 둡니다. 그러나 WebGPT는 이를 한 단계 더 나아가, 웹 콘텐츠를 이해하고 처리하는 능력을 갖추게 훈련되었습니다.

웹 페이지의 이해

웹 페이지는 HTML 형식으로 제공되며, 텍스트 뿐만 아니라 이미지, 비디오, 표, 폼 등의 다양한 요소를 포함하고 있습니다. 이런 요소들은 각각 복잡한 구조를 가지고 있으며, 이 구조를 파악하고 이해하는 것은 웹 페이지를 이해하는 데 중요한 요소입니다.

이를 위해 WebGPT는 웹 페이지를 ‘트리’라는 데이터 구조로 보는 것입니다. 웹 페이지의 각 요소는 이 트리의 ‘노드’에 해당하며, 웹 페이지의 구조는 이 노드들 사이의 연결로 표현됩니다.

복잡한 웹 상호작용

웹 페이지는 단순히 정보를 제공하는 것 이상의 기능을 가지고 있습니다. 사용자는 웹 페이지와 상호작용하며 정보를 찾거나, 입력하거나, 수정할 수 있습니다. 이러한 상호작용은 웹 페이지의 정보를 이해하고 활용하는 데 중요한 요소입니다.

WebGPT는 이러한 상호작용을 이해하고, 자동으로 수행할 수 있게 훈련되었습니다. 이를 통해 WebGPT는 더욱 다양한 웹 기반의 작업을 수행할 수 있습니다.

기능

기능은 크게 두 가지로 나눌 수 있습니다

웹 페이지의 이해

WebGPT는 HTML과 CSS에 대한 깊은 이해를 바탕으로 웹 페이지를 분석합니다. 웹 페이지의 모든 요소는 해당하는 노드로 변환되며, 이 노드들은 웹 페이지의 구조를 나타내는 트리를 구성합니다.

다음은 웹 페이지를 트리로 변환하는 예시입니다:

pythonCopy codefrom bs4 import BeautifulSoup

def html_to_tree(html):
    soup = BeautifulSoup(html, 'html.parser')
    root = {'tag': '[ROOT]', 'children': []}
    build_tree(soup, root)
    return root

def build_tree(soup, parent_node):
    for child in soup.children:
        if child.name is not None:
            child_node = {'tag': child.name, 'children': []}
            parent_node['children'].append(child_node)
            build_tree(child, child_node)

html = """
<html>
<head>
    <title>Page Title</title>
</head>
<body>
    <h1>This is a Heading</h1>
    <p>This is a paragraph.</p>
    <p>This is another paragraph.</p>
</body>
</html>
"""

tree = html_to_tree(html)
print(tree)

웹 상호작용

WebGPT는 사용자의 입력을 기반으로 웹 상호작용을 수행할 수 있습니다. 예를 들어, 사용자가 웹 페이지의 특정 요소를 클릭하라고 명령하면, WebGPT는 해당 요소를 찾아 클릭하는 동작을 수행합니다.

수식에 대한 이해

WebGPT의 핵심 메커니즘은 원래의 GPT-4 아키텍처에 기반한 트랜스포머 모델을 사용하고 있습니다. 이러한 트랜스포머 모델의 핵심 메커니즘은 자기 주의 메커니즘 (Self-attention mechanism) 입니다. 이는 입력 시퀀스의 각 요소가 다른 요소에 주는 중요도를 계산하고, 이 중요도를 기반으로 새로운 표현을 생성하는 방식으로 작동합니다.

자기 주의 메커니즘의 수학적 표현은 다음과 같습니다:

각 입력 요소의 쿼리 (Query), 키 (Key), 값 (Value) 벡터는 해당 요소의 임베딩 벡터에 선형 변환을 적용하여 계산됩니다:

mathCopy codeQ = XW_Q, K = XW_K, V = XW_V

여기서 X는 입력 임베딩 벡터, W_Q, W_K, W_V는 학습 가능한 가중치 행렬입니다.

그런 다음, 각 쿼리 벡터 Q_i에 대해, 모든 키 벡터 K_j와의 점곱 (dot product)을 계산하고, 이를 정규화하여 자기 주의 점수 (attention score) A_ij를 얻습니다:

mathCopy codeA_ij = softmax(Q_i K_j^T / sqrt(d_k))

여기서 d_k는 키 벡터의 차원입니다. sqrt(d_k)로 나누는 것은 스케일링 팩터로, 큰 차원에서의 점곱 값이 너무 커지는 것을 방지합니다.

마지막으로, 이 점수를 각 값 벡터 V_j에 적용하고, 이를 합산하여 출력 벡터 O_i를 얻습니다:

mathCopy codeO_i = sum_j(A_ij V_j)

이러한 자기 주의 메커니즘을 여러 개 겹쳐서 사용하는 것이 트랜스포머 모델의 핵심적인 특징입니다. 이를 통해 모델은 각 입력 요소가 다른 요소에 주는 상대적인 중요도를 파악하고, 이를 기반으로 새로운 표현을 생성할 수 있습니다.

WebGPT는 이러한 트랜스포머 모델을 웹 페이지의 이해와 상호작용에 적용하여, 웹을 더욱 효과적으로 활용할 수 있도록 합니다.

WebGPT의 적용 분야

WebGPT는 다양한 분야에서 활용될 수 있습니다. 먼저, 웹 페이지의 내용을 이해하고, 분석하고, 요약하는 데 사용될 수 있습니다. 예를 들어, 뉴스 기사, 블로그 글, 위키 문서 등의 콘텐츠를 자동으로 요약하거나, 웹 페이지의 구조를 분석하여 특정 정보를 추출하는 데 사용될 수 있습니다.

또한, WebGPT는 웹 서비스의 자동화에도 사용될 수 있습니다. 예를 들어, 웹 기반의 이메일 서비스, 쇼핑 사이트, 은행 서비스 등에서의 반복적인 작업을 자동화하는 데 사용될 수 있습니다.

관련 링크

파이썬 코드로 구현

import streamlit as st
from langchain.callbacks.base import BaseCallbackHandler
from langchain.chains import RetrievalQAWithSourcesChain
from langchain.retrievers.web_research import WebResearchRetriever

@st.cache_resource
def settings():

    # Vectorstore
    import faiss
    from langchain.vectorstores import FAISS 
    from langchain.embeddings.openai import OpenAIEmbeddings
    from langchain.docstore import InMemoryDocstore  
    embeddings_model = OpenAIEmbeddings()  
    embedding_size = 1536  
    index = faiss.IndexFlatL2(embedding_size)  
    vectorstore_public = FAISS(embeddings_model.embed_query, index, InMemoryDocstore({}), {})

    # LLM
    from langchain.chat_models import ChatOpenAI
    llm = ChatOpenAI(model_name="gpt-3.5-turbo-16k", temperature=0, streaming=True)

    # Search
    from langchain.utilities import GoogleSearchAPIWrapper
    search = GoogleSearchAPIWrapper()   

    # Initialize 
    web_retriever = WebResearchRetriever.from_llm(
    vectorstore=vectorstore_public,
    llm=llm, 
    search=search, 
    num_search_results=3
    )

    return web_retriever, llm

class StreamHandler(BaseCallbackHandler):
    def __init__(self, container, initial_text=""):
        self.container = container
        self.text = initial_text

    def on_llm_new_token(self, token: str, **kwargs) -> None:
        self.text += token
        self.container.info(self.text)


class PrintRetrievalHandler(BaseCallbackHandler):
    def __init__(self, container):
        self.container = container.expander("Context Retrieval")

    def on_retriever_start(self, query: str, **kwargs):
        self.container.write(f"**Question:** {query}")

    def on_retriever_end(self, documents, **kwargs):
        # self.container.write(documents)
        for idx, doc in enumerate(documents):
            source = doc.metadata["source"]
            self.container.write(f"**Results from {source}**")
            self.container.text(doc.page_content)


st.sidebar.image("img/ai.png")
st.header("`Interweb Explorer`")
st.info("`I am an AI that can answer questions by exploring, reading, and summarizing web pages."
    "I can be configured to use different moddes: public API or private (no data sharing).`")

# Make retriever and llm
web_retriever, llm = settings()

# User input 
question = st.text_input("`Ask a question:`")

if question:

    # Generate answer (w/ citations)
    import logging
    logging.basicConfig()
    logging.getLogger("langchain.retrievers.web_research").setLevel(logging.INFO)    
    qa_chain = RetrievalQAWithSourcesChain.from_chain_type(llm,
                                                           retriever=web_retriever)
    
    # Write answer and sources
    retrieval_streamer_cb = PrintRetrievalHandler(st.container())
    answer = st.empty()
    stream_handler = StreamHandler(answer, initial_text="`Answer:`\n\n")
    result = qa_chain({"question": question},callbacks=[retrieval_streamer_cb, stream_handler])
    answer.info('`Answer:`\n\n' + result['answer'])
    st.info('`Sources:`\n\n' + result['sources'])

마무리하며

웹은 우리 생활의 많은 부분을 차지하고 있습니다. WebGPT는 이런 웹을 더욱 효율적이고 지능적으로 활용하기 위한 새로운 도구입니다. 이를 통해 우리는 더욱 풍부한 정보를 얻고, 더욱 다양한 서비스를 이용하고, 더욱 편리한 생활을 누릴 수 있을 것입니다.

답글 남기기