반응형
블로그 이미지
개발자로서 현장에서 일하면서 새로 접하는 기술들이나 알게된 정보 등을 정리하기 위한 블로그입니다. 운 좋게 미국에서 큰 회사들의 프로젝트에서 컬설턴트로 일하고 있어서 새로운 기술들을 접할 기회가 많이 있습니다. 미국의 IT 프로젝트에서 사용되는 툴들에 대해 많은 분들과 정보를 공유하고 싶습니다.
솔웅

최근에 올라온 글

최근에 달린 댓글

최근에 받은 트랙백

글 보관함

카테고리

LangChain - Interface

2023. 10. 27. 02:07 | Posted by 솔웅


반응형

https://python.langchain.com/docs/expression_language/interface

 

Interface | 🦜️🔗 Langchain

To make it as easy as possible to create custom chains, we've implemented a "Runnable" protocol. The Runnable protocol is implemented for most components.

python.langchain.com

 

In an effort to make it as easy as possible to create custom chains, we've implemented a "Runnable" protocol that most components implement. This is a standard interface with a few different methods, which makes it easy to define custom chains as well as making it possible to invoke them in a standard way. The standard interface exposed includes:

 

사용자 정의 체인을 최대한 쉽게 생성하기 위한 노력의 일환으로 우리는 대부분의 구성 요소가 구현하는 "실행 가능" 프로토콜을 구현했습니다. 이는 몇 가지 다른 메소드가 포함된 표준 인터페이스로, 사용자 정의 체인을 쉽게 정의할 수 있을 뿐만 아니라 표준 방식으로 호출할 수도 있습니다. 노출된 표준 인터페이스에는 다음이 포함됩니다.

 

  • stream: stream back chunks of the response  응답의 청크를 다시 스트리밍합니다.
  • invoke: call the chain on an input    입력에서 체인을 호출합니다.
  • batch: call the chain on a list of inputs  입력 목록에서 체인을 호출합니다.

 

These also have corresponding async methods: 여기에는 해당하는 비동기 메서드도 있습니다.

  • astream: stream back chunks of the response async  응답 비동기 청크를 다시 스트리밍합니다.
  • ainvoke: call the chain on an input async  입력 비동기에서 체인 호출
  • abatch: call the chain on a list of inputs async  비동기 입력 목록에서 체인을 호출합니다.
  • astream_log: stream back intermediate steps as they happen, in addition to the final response
    최종 응답 외에도 중간 단계가 발생하면 다시 스트리밍합니다.

The type of the input varies by component:

 

입력 유형은 구성 요소에 따라 다릅니다.

 

The output type also varies by component:

 

출력 유형도 구성요소에 따라 다릅니다.

 

All runnables expose properties to inspect the input and output types:

 

모든 실행 가능 항목은 입력 및 출력 유형을 검사하기 위한 속성을 노출합니다.

  • input_schema: an input Pydantic model auto-generated from the structure of the Runnable
  • input_schema: Runnable의 구조에서 자동 생성된 입력 Pydantic 모델
  • output_schema: an output Pydantic model auto-generated from the structure of the Runnable
  • output_schema: Runnable의 구조에서 자동 생성된 출력 Pydantic 모델

Let's take a look at these methods! To do so, we'll create a super simple PromptTemplate + ChatModel chain.

 

이러한 방법들을 살펴보겠습니다! 이를 위해 매우 간단한 PromptTemplate + ChatModel 체인을 생성하겠습니다.

 

from langchain.prompts import ChatPromptTemplate
from langchain.chat_models import ChatOpenAI

model = ChatOpenAI()
prompt = ChatPromptTemplate.from_template("tell me a joke about {topic}")
chain = prompt | model

이 코드는 "langchain" 라이브러리를 사용하여 OpenAI의 언어 모델을 활용하는 예시를 제공합니다. 

  1. from langchain.prompts import ChatPromptTemplate:
    • "langchain" 라이브러리에서 ChatPromptTemplate 클래스를 가져오는 명령입니다.
    • ChatPromptTemplate 클래스는 대화 생성에 사용되는 템플릿을 만들고 활용하는 데 도움을 주는 클래스입니다.
  2. from langchain.chat_models import ChatOpenAI:
    • "langchain" 라이브러리에서 ChatOpenAI 클래스를 가져오는 명령입니다.
    • ChatOpenAI 클래스는 OpenAI의 언어 모델을 활용하는 데 사용되는 클래스입니다.
  3. model = ChatOpenAI(openai_api_key = open_file('openaiapikey.txt'), temperature=0.9):
    • ChatOpenAI 클래스의 인스턴스를 생성합니다.
    • openai_api_key 매개변수에 OpenAI API 키를 파일로부터 읽어온 값을 전달합니다.
    • temperature 매개변수는 모델의 창의성을 조절하는 요소로, 0.9로 설정되어 있으며 높을수록 더 다양한 출력이 생성됩니다.
  4. prompt = ChatPromptTemplate.from_template("tell me a joke about {topic}"):
    • ChatPromptTemplate 클래스의 from_template 메서드를 사용하여 템플릿을 생성합니다.
    • 템플릿 문자열 "tell me a joke about {topic}"은 {topic} 부분이 나중에 대체될 변수를 나타냅니다.
  5. chain = prompt | model:
    • prompt와 model을 결합하여 대화 체인을 생성합니다.
    • 이러한 체인을 사용하면 템플릿을 모델과 함께 사용하여 모델에게 대화 형식으로 질문을 하고 응답을 받을 수 있습니다.

이 코드는 주어진 주제에 대한 재미있는 농담을 생성하기 위해 OpenAI 모델을 사용하는 예시를 나타내고 있습니다. 모델은 주어진 API 키 및 설정과 함께 템플릿을 사용하여 대화를 생성하고 대화의 연장으로 대화를 계속할 수 있습니다.

Input Schema

A description of the inputs accepted by a Runnable. This is a Pydantic model dynamically generated from the structure of any Runnable. You can call .schema() on it to obtain a JSONSchema representation.

 

Runnable이 허용하는 입력에 대한 설명입니다. 이는 Runnable의 구조에서 동적으로 생성된 Pydantic 모델입니다. .schema()를 호출하여 JSONSchema 표현을 얻을 수 있습니다.

 

# The input schema of the chain is the input schema of its first part, the prompt.
chain.input_schema.schema()

이 코드는 "chain"이라는 객체의 입력 스키마(input schema)를 설명하고 있습니다. "chain"은 여러 부분으로 구성된 대화 체인이며, 이 코드는 체인의 입력 스키마를 확인하는 부분에 대한 설명입니다.

 

# 체인의 입력 스키마는 체인의 첫 번째 부분인 prompt의 입력 스키마와 동일합니다.
chain.input_schema.schema()
  • "chain"은 여러 부분으로 이루어진 대화 체인을 나타내는 객체입니다. 이 대화 체인은 대화를 구성하고 관리하는 데 사용됩니다.
  • chain.input_schema.schema()은 체인의 입력 스키마를 확인하는 코드입니다. 입력 스키마는 데이터나 정보의 구조와 형식을 정의하는데 사용됩니다.
  • 주석(#)은 코드에 설명을 추가하는 데 사용되며, 이 경우에는 주석으로 코드의 목적을 설명하고 있습니다.
  • 이 코드에서 "chain"의 입력 스키마는 "prompt"라는 첫 번째 부분의 입력 스키마와 동일하다고 설명하고 있습니다. 즉, 체인의 입력 스키마는 체인의 첫 번째 부분인 "prompt"에서 정의한 입력 스키마와 일치합니다.
  • 입력 스키마의 역할은 데이터의 형식, 구조, 및 유효성 검사에 관련됩니다. 이 코드는 입력 스키마를 확인하는 용도로 사용되며, 체인의 구조와 입력 데이터에 대한 정보를 얻을 수 있습니다.

이 코드는 체인의 입력 스키마를 확인하고 첫 번째 부분 "prompt"의 입력 스키마와 일치한다는 점을 강조하는 목적으로 사용됩니다.

 

prompt.input_schema.schema()

model.input_schema.schema()

return 값

{'title': 'ChatOpenAIInput',
 'anyOf': [{'type': 'string'},
  {'$ref': '#/definitions/StringPromptValue'},
  {'$ref': '#/definitions/ChatPromptValueConcrete'},
  {'type': 'array',
   'items': {'anyOf': [{'$ref': '#/definitions/AIMessage'},
     {'$ref': '#/definitions/HumanMessage'},
     {'$ref': '#/definitions/ChatMessage'},
     {'$ref': '#/definitions/SystemMessage'},
     {'$ref': '#/definitions/FunctionMessage'}]}}],
 'definitions': {'StringPromptValue': {'title': 'StringPromptValue',
   'description': 'String prompt value.',
   'type': 'object',
   'properties': {'text': {'title': 'Text', 'type': 'string'},
    'type': {'title': 'Type',
     'default': 'StringPromptValue',
     'enum': ['StringPromptValue'],
     'type': 'string'}},
   'required': ['text']},
  'AIMessage': {'title': 'AIMessage',
   'description': 'A Message from an AI.',
   'type': 'object',
   'properties': {'content': {'title': 'Content', 'type': 'string'},
    'additional_kwargs': {'title': 'Additional Kwargs', 'type': 'object'},
    'type': {'title': 'Type',
     'default': 'ai',
     'enum': ['ai'],
     'type': 'string'},
    'example': {'title': 'Example', 'default': False, 'type': 'boolean'}},
   'required': ['content']},
  'HumanMessage': {'title': 'HumanMessage',
   'description': 'A Message from a human.',
   'type': 'object',
   'properties': {'content': {'title': 'Content', 'type': 'string'},
    'additional_kwargs': {'title': 'Additional Kwargs', 'type': 'object'},
    'type': {'title': 'Type',
     'default': 'human',
     'enum': ['human'],
     'type': 'string'},
    'example': {'title': 'Example', 'default': False, 'type': 'boolean'}},
   'required': ['content']},
  'ChatMessage': {'title': 'ChatMessage',
   'description': 'A Message that can be assigned an arbitrary speaker (i.e. role).',
   'type': 'object',
   'properties': {'content': {'title': 'Content', 'type': 'string'},
    'additional_kwargs': {'title': 'Additional Kwargs', 'type': 'object'},
    'type': {'title': 'Type',
     'default': 'chat',
     'enum': ['chat'],
     'type': 'string'},
    'role': {'title': 'Role', 'type': 'string'}},
   'required': ['content', 'role']},
  'SystemMessage': {'title': 'SystemMessage',
   'description': 'A Message for priming AI behavior, usually passed in as the first of a sequence\nof input messages.',
   'type': 'object',
   'properties': {'content': {'title': 'Content', 'type': 'string'},
    'additional_kwargs': {'title': 'Additional Kwargs', 'type': 'object'},
    'type': {'title': 'Type',
     'default': 'system',
     'enum': ['system'],
     'type': 'string'}},
   'required': ['content']},
  'FunctionMessage': {'title': 'FunctionMessage',
   'description': 'A Message for passing the result of executing a function back to a model.',
   'type': 'object',
   'properties': {'content': {'title': 'Content', 'type': 'string'},
    'additional_kwargs': {'title': 'Additional Kwargs', 'type': 'object'},
    'type': {'title': 'Type',
     'default': 'function',
     'enum': ['function'],
     'type': 'string'},
    'name': {'title': 'Name', 'type': 'string'}},
   'required': ['content', 'name']},
  'ChatPromptValueConcrete': {'title': 'ChatPromptValueConcrete',
   'description': 'Chat prompt value which explicitly lists out the message types it accepts.\nFor use in external schemas.',
   'type': 'object',
   'properties': {'messages': {'title': 'Messages',
     'type': 'array',
     'items': {'anyOf': [{'$ref': '#/definitions/AIMessage'},
       {'$ref': '#/definitions/HumanMessage'},
       {'$ref': '#/definitions/ChatMessage'},
       {'$ref': '#/definitions/SystemMessage'},
       {'$ref': '#/definitions/FunctionMessage'}]}},
    'type': {'title': 'Type',
     'default': 'ChatPromptValueConcrete',
     'enum': ['ChatPromptValueConcrete'],
     'type': 'string'}},
   'required': ['messages']}}}

 

Output Schema

A description of the outputs produced by a Runnable. This is a Pydantic model dynamically generated from the structure of any Runnable. You can call .schema() on it to obtain a JSONSchema representation.

 

Runnable이 생성한 출력에 대한 설명입니다. 이는 Runnable의 구조에서 동적으로 생성된 Pydantic 모델입니다. .schema()를 호출하여 JSONSchema 표현을 얻을 수 있습니다.

 

# The output schema of the chain is the output schema of its last part, in this case a ChatModel, which outputs a ChatMessage
chain.output_schema.schema()

 

이 코드는 "chain" 객체의 출력 스키마를 설명하고 있습니다. "chain"은 여러 부분으로 구성된 대화 체인이며, 이 코드는 체인의 출력 스키마를 확인하는 부분에 대한 설명입니다.

 

# 체인의 출력 스키마는 마지막 부분인 ChatModel의 출력 스키마와 동일합니다. 이 경우에는 ChatMessage가 출력됩니다.
chain.output_schema.schema()
  • "chain"은 여러 부분으로 이루어진 대화 체인을 나타내는 객체입니다. 이 대화 체인은 대화의 구조와 출력을 관리하는 데 사용됩니다.
  • chain.output_schema.schema()은 체인의 출력 스키마를 확인하는 코드입니다. 출력 스키마는 데이터나 정보의 구조와 형식을 정의하는데 사용됩니다.
  • 주석(#)은 코드에 설명을 추가하는 데 사용되며, 이 경우에는 주석으로 코드의 목적을 설명하고 있습니다.
  • 이 코드에서 "chain"의 출력 스키마는 이 체인의 마지막 부분인 "ChatModel"에서 정의한 출력 스키마와 일치한다고 설명하고 있습니다. 마지막 부분인 "ChatModel"이 "ChatMessage"를 출력하므로, 체인의 출력 스키마도 "ChatMessage"와 일치합니다.
  • 출력 스키마의 역할은 데이터의 형식, 구조, 및 유효성 검사에 관련됩니다. 이 코드는 출력 스키마를 확인하는 용도로 사용되며, 체인의 구조와 출력 데이터에 대한 정보를 얻을 수 있습니다.

이 코드는 체인의 출력 스키마를 확인하고 마지막 부분 "ChatModel"의 출력 스키마와 일치한다는 점을 강조하는 목적으로 사용됩니다.

return 값

{'title': 'ChatOpenAIOutput',
 'anyOf': [{'$ref': '#/definitions/AIMessage'},
  {'$ref': '#/definitions/HumanMessage'},
  {'$ref': '#/definitions/ChatMessage'},
  {'$ref': '#/definitions/SystemMessage'},
  {'$ref': '#/definitions/FunctionMessage'}],
 'definitions': {'AIMessage': {'title': 'AIMessage',
   'description': 'A Message from an AI.',
   'type': 'object',
   'properties': {'content': {'title': 'Content', 'type': 'string'},
    'additional_kwargs': {'title': 'Additional Kwargs', 'type': 'object'},
    'type': {'title': 'Type',
     'default': 'ai',
     'enum': ['ai'],
     'type': 'string'},
    'example': {'title': 'Example', 'default': False, 'type': 'boolean'}},
   'required': ['content']},
  'HumanMessage': {'title': 'HumanMessage',
   'description': 'A Message from a human.',
   'type': 'object',
   'properties': {'content': {'title': 'Content', 'type': 'string'},
    'additional_kwargs': {'title': 'Additional Kwargs', 'type': 'object'},
    'type': {'title': 'Type',
     'default': 'human',
     'enum': ['human'],
     'type': 'string'},
    'example': {'title': 'Example', 'default': False, 'type': 'boolean'}},
   'required': ['content']},
  'ChatMessage': {'title': 'ChatMessage',
   'description': 'A Message that can be assigned an arbitrary speaker (i.e. role).',
   'type': 'object',
   'properties': {'content': {'title': 'Content', 'type': 'string'},
    'additional_kwargs': {'title': 'Additional Kwargs', 'type': 'object'},
    'type': {'title': 'Type',
     'default': 'chat',
     'enum': ['chat'],
     'type': 'string'},
    'role': {'title': 'Role', 'type': 'string'}},
   'required': ['content', 'role']},
  'SystemMessage': {'title': 'SystemMessage',
   'description': 'A Message for priming AI behavior, usually passed in as the first of a sequence\nof input messages.',
   'type': 'object',
   'properties': {'content': {'title': 'Content', 'type': 'string'},
    'additional_kwargs': {'title': 'Additional Kwargs', 'type': 'object'},
    'type': {'title': 'Type',
     'default': 'system',
     'enum': ['system'],
     'type': 'string'}},
   'required': ['content']},
  'FunctionMessage': {'title': 'FunctionMessage',
   'description': 'A Message for passing the result of executing a function back to a model.',
   'type': 'object',
   'properties': {'content': {'title': 'Content', 'type': 'string'},
    'additional_kwargs': {'title': 'Additional Kwargs', 'type': 'object'},
    'type': {'title': 'Type',
     'default': 'function',
     'enum': ['function'],
     'type': 'string'},
    'name': {'title': 'Name', 'type': 'string'}},
   'required': ['content', 'name']}}}

 

Stream

for s in chain.stream({"topic": "bears"}):
    print(s.content, end="", flush=True)

이 코드는 "chain" 객체를 사용하여 대화를 생성하고 출력하는 부분을 설명하고 있습니다.

  • for s in chain.stream({"topic": "bears"})::
    • 이 부분은 "chain" 객체를 사용하여 대화를 생성하는 반복문입니다.
    • "chain.stream({"topic": "bears"})"은 주어진 입력 매개변수인 {"topic": "bears"}를 사용하여 대화를 시작하고 그 결과를 반복적으로 처리합니다.
  • print(s.content, end="", flush=True):
    • "s"는 반복문에서 가져온 대화의 한 부분을 나타냅니다.
    • "s.content"는 대화의 내용을 나타내며, 이 부분은 출력됩니다.
    • "end=""`"는 "print" 함수가 줄 바꿈 문자를 출력하지 않도록 합니다. 따라서 출력이 연이어 나타납니다.
    • "flush=True"는 출력을 즉시 표시하도록 하는 옵션으로, 출력이 즉시 화면에 나타납니다.

이 코드는 "chain"을 사용하여 주제가 "bears"인 대화를 생성하고 해당 대화를 반복적으로 처리하여 출력합니다. 출력은 줄 바꿈 없이 연이어 표시되며, flush=True 옵션을 사용하여 즉시 표시됩니다.

 

Invoke

chain.invoke({"topic": "bears"})

이 코드는 "chain" 객체를 사용하여 대화를 생성하고 실행하는 부분을 설명하고 있습니다.

 

  • chain.invoke({"topic": "bears"}):
    • 이 부분은 "chain" 객체를 사용하여 대화를 생성하고 실행하는 명령입니다.
    • {"topic": "bears"}는 입력 매개변수로 주어진 딕셔너리를 나타냅니다. 여기서 "topic"은 대화 주제를 설정하는데 사용되는 키이며, "bears"는 주제로 설정됩니다.

이 코드는 "chain"을 사용하여 주제가 "bears"인 대화를 생성하고 실행합니다. 이로써 대화 모델은 "bears" 주제에 관한 대화를 생성하고 결과를 반환합니다.

 

Batch

chain.batch([{"topic": "bears"}, {"topic": "cats"}])

이 코드는 "chain" 객체를 사용하여 여러 대화를 일괄 처리하는 방법을 보여주고 있습니다.

  • chain.batch([{"topic": "bears"}, {"topic": "cats"}]):
    • 이 부분은 "chain" 객체를 사용하여 여러 대화를 일괄 처리하는 명령입니다.
    • {"topic": "bears"}와 {"topic": "cats"}는 입력 매개변수로 주어진 딕셔너리의 목록을 나타냅니다. 각 딕셔너리에는 "topic" 키와 대화 주제를 설정하는 값이 포함되어 있습니다.

이 코드는 "chain"을 사용하여 "bears" 주제와 "cats" 주제에 관한 여러 대화를 생성하고 처리합니다. 이로써 대화 모델은 주어진 주제에 따라 대화를 생성하고 결과를 반환합니다.

 

Async Stream

async for s in chain.astream({"topic": "bears"}):
    print(s.content, end="", flush=True)

이 코드는 비동기로 "chain" 객체를 사용하여 대화를 생성하고 출력하는 부분을 설명하고 있습니다.

 

  • async for s in chain.astream({"topic": "bears"})::
    • 이 부분은 비동기 반복문으로, "chain" 객체를 사용하여 대화를 생성하고 결과를 처리합니다.
    • chain.astream({"topic": "bears"})은 주어진 입력 매개변수인 {"topic": "bears"}를 사용하여 대화를 시작하고 비동기 스트림을 통해 결과를 받아옵니다.
  • print(s.content, end="", flush=True):
    • "s"는 스트림에서 가져온 대화의 한 부분을 나타냅니다.
    • "s.content"는 대화의 내용을 나타내며, 이 부분은 출력됩니다.
    • "end=""`"는 "print" 함수가 줄 바꿈 문자를 출력하지 않도록 합니다. 따라서 출력이 연이어 나타납니다.
    • "flush=True"는 출력을 즉시 표시하도록 하는 옵션으로, 출력이 즉시 화면에 나타납니다.

이 코드는 "chain"을 사용하여 주제가 "bears"인 대화를 생성하고 비동기 스트림을 통해 결과를 받아오며, 결과를 출력합니다. 출력은 줄 바꿈 없이 연이어 표시되며, flush=True 옵션을 사용하여 즉시 표시됩니다.

 

Async Invoke

await chain.ainvoke({"topic": "bears"})

이 코드는 "chain" 객체를 사용하여 대화를 생성하고 실행하는 비동기 방식을 설명하고 있습니다.

 

  • await chain.ainvoke({"topic": "bears"}):
    • 이 부분은 "chain" 객체를 사용하여 비동기로 대화를 생성하고 실행하는 명령입니다.
    • {"topic": "bears"}는 입력 매개변수로 주어진 딕셔너리를 나타냅니다. 여기서 "topic"은 대화 주제를 설정하는데 사용되는 키이며, "bears"는 주제로 설정됩니다.

이 코드는 "chain"을 사용하여 "bears" 주제에 관한 대화를 생성하고 실행합니다. await 키워드는 비동기 작업이 완료될 때까지 대기하도록 하며, 대화의 실행이 완료되면 결과를 반환합니다.

Async Batch

await chain.abatch([{"topic": "bears"}])

이 코드는 "chain" 객체를 사용하여 대화를 생성하고 실행하는 비동기 일괄 처리 방법을 설명하고 있습니다.

  • await chain.abatch([{"topic": "bears"}]):
    • 이 부분은 "chain" 객체를 사용하여 비동기로 대화를 생성하고 실행하는 명령입니다.
    • {"topic": "bears"}는 입력 매개변수로 주어진 딕셔너리의 목록을 나타냅니다. 각 딕셔너리에는 "topic" 키와 대화 주제를 설정하는 값이 포함되어 있습니다.

이 코드는 "chain"을 사용하여 "bears" 주제에 관한 대화를 생성하고 실행합니다. await 키워드는 비동기 작업이 완료될 때까지 대기하도록 하며, 대화의 실행이 완료되면 결과를 반환합니다.

 

Async Stream Intermediate Steps

All runnables also have a method .astream_log() which is used to stream (as they happen) all or part of the intermediate steps of your chain/sequence.

 

모든 runnables 는 체인/시퀀스의 중간 단계 전체 또는 일부를 스트리밍하는 데 사용되는 .astream_log() 메서드도 있습니다.

 

This is useful to show progress to the user, to use intermediate results, or to debug your chain.

 

이는 사용자에게 진행 상황을 표시하거나, 중간 결과를 사용하거나, 체인을 디버깅하는 데 유용합니다.

 

You can stream all steps (default) or include/exclude steps by name, tags or metadata.

 

모든 단계를 스트리밍(기본값)하거나 이름, 태그 또는 메타데이터별로 단계를 포함/제외할 수 있습니다.

 

This method yields JSONPatch ops that when applied in the same order as received build up the RunState.

 

이 메서드는 수신된 순서와 동일한 순서로 적용될 때 RunState를 구축하는 JSONPatch 작업을 생성합니다.

 

class LogEntry(TypedDict):
    id: str
    """ID of the sub-run."""
    name: str
    """Name of the object being run."""
    type: str
    """Type of the object being run, eg. prompt, chain, llm, etc."""
    tags: List[str]
    """List of tags for the run."""
    metadata: Dict[str, Any]
    """Key-value pairs of metadata for the run."""
    start_time: str
    """ISO-8601 timestamp of when the run started."""

    streamed_output_str: List[str]
    """List of LLM tokens streamed by this run, if applicable."""
    final_output: Optional[Any]
    """Final output of this run.
    Only available after the run has finished successfully."""
    end_time: Optional[str]
    """ISO-8601 timestamp of when the run ended.
    Only available after the run has finished."""


class RunState(TypedDict):
    id: str
    """ID of the run."""
    streamed_output: List[Any]
    """List of output chunks streamed by Runnable.stream()"""
    final_output: Optional[Any]
    """Final output of the run, usually the result of aggregating (`+`) streamed_output.
    Only available after the run has finished successfully."""

    logs: Dict[str, LogEntry]
    """Map of run names to sub-runs. If filters were supplied, this list will
    contain only the runs that matched the filters."""

 

위의 코드는 Python 3.8 이상에서 사용 가능한 TypedDict를 사용하여 두 개의 타입 딕셔너리(LogEntryRunState)를 정의하고 있습니다. 이 타입 딕셔너리는 특정 키와 그에 상응하는 데이터 형식을 명시적으로 정의함으로써 딕셔너리의 구조를 제한하고 코드의 가독성과 안정성을 향상시킵니다.

 

  1. LogEntry 타입 딕셔너리:
    • id: str: 서브런의 ID를 나타내는 문자열.
    • name: str: 실행 중인 객체의 이름을 나타내는 문자열.
    • type: str: 실행 중인 객체의 유형(예: 프롬프트, 체인, llm 등)을 나타내는 문자열.
    • tags: List[str]: 실행에 대한 태그 목록을 나타내는 문자열 리스트.
    • metadata: Dict[str, Any]: 실행에 대한 메타데이터를 나타내는 키-값 쌍의 딕셔너리.
    • start_time: str: 실행이 시작된 ISO-8601 타임스탬프를 나타내는 문자열.
    • streamed_output_str: List[str]: 이 실행에 의해 스트리밍된 LLM 토큰의 목록(적용 가능한 경우).
    • final_output: Optional[Any]: 이 실행의 최종 출력. 실행이 성공적으로 완료된 후에만 사용 가능한 옵셔널 타입 데이터.
    • end_time: Optional[str]: 실행이 종료된 ISO-8601 타임스탬프. 실행이 성공적으로 완료된 후에만 사용 가능한 옵셔널 타입 데이터.
  2. RunState 타입 딕셔너리:
    • id: str: 실행의 ID를 나타내는 문자열.
    • streamed_output: List[Any]: Runnable.stream()에 의해 스트리밍된 출력 청크 목록을 나타내는 리스트.
    • final_output: Optional[Any]: 실행의 최종 출력. 일반적으로 streamed_output을 집계한 결과입니다. 실행이 성공적으로 완료된 후에만 사용 가능한 옵셔널 타입 데이터.
    • logs: Dict[str, LogEntry]: 실행의 이름과 서브런(로그 엔트리) 간의 매핑. 필터가 제공된 경우 해당 필터와 일치하는 실행만 포함합니다.

이러한 타입 딕셔너리는 데이터 구조와 형식을 명확히 정의하며, 이러한 정보를 사용하는 코드에서 유용한 형식 검증과 가독성을 제공합니다.

 

 

Streaming JSONPatch chunks

 

This is useful eg. to stream the JSONPatch in an HTTP server, and then apply the ops on the client to rebuild the run state there. See LangServe for tooling to make it easier to build a webserver from any Runnable.

 

이는 유용합니다. HTTP 서버에서 JSONPatch를 스트리밍한 다음 클라이언트에 작업을 적용하여 실행 상태를 다시 빌드합니다. Runnable에서 웹 서버를 더 쉽게 구축할 수 있는 도구는 LangServe를 참조하세요.

 

from langchain.embeddings import OpenAIEmbeddings
from langchain.schema.output_parser import StrOutputParser
from langchain.schema.runnable import RunnablePassthrough
from langchain.vectorstores import FAISS

template = """Answer the question based only on the following context:
{context}

Question: {question}
"""
prompt = ChatPromptTemplate.from_template(template)

vectorstore = FAISS.from_texts(["harrison worked at kensho"], embedding=OpenAIEmbeddings())
retriever = vectorstore.as_retriever()

retrieval_chain = (
    {"context": retriever.with_config(run_name='Docs'), "question": RunnablePassthrough()}
    | prompt 
    | model 
    | StrOutputParser()
)

async for chunk in retrieval_chain.astream_log("where did harrison work?", include_names=['Docs']):
    print("-"*40)
    print(chunk)

이 코드는 "langchain" 라이브러리를 사용하여 OpenAI 모델을 활용하여 질문 응답 시스템을 구축하는 예시를 제공합니다. 

 

  1. 모듈 및 클래스 가져오기:
    • langchain.embeddings 모듈에서 OpenAIEmbeddings 클래스를 가져옵니다. 이 클래스는 OpenAI의 임베딩을 사용하기 위한 도구를 제공합니다.
    • langchain.schema.output_parser 모듈에서 StrOutputParser 클래스를 가져옵니다. 이 클래스는 출력을 파싱하는 데 사용됩니다.
    • langchain.schema.runnable 모듈에서 RunnablePassthrough 클래스를 가져옵니다. 이 클래스는 실행 가능한 객체를 나타내는 클래스입니다.
    • langchain.vectorstores 모듈에서 FAISS 클래스를 가져옵니다. 이 클래스는 FAISS 벡터 저장소를 만들고 관리하는 도구를 제공합니다.
  2. 템플릿 정의:
    • "template" 변수에는 질문에 대한 컨텍스트와 질문 자체를 템플릿으로 정의합니다.
  3. 질문 응답 시스템 구성:
    • "prompt" 변수에는 "ChatPromptTemplate.from_template(template)"을 사용하여 템플릿을 기반으로한 대화 템플릿을 생성합니다.
    • "vectorstore" 변수에는 "FAISS.from_texts"를 사용하여 벡터 저장소를 생성합니다. 이 벡터 저장소는 "harrison worked at kensho"와 같은 텍스트로 초기화되며, OpenAI 임베딩을 사용하여 벡터를 생성합니다.
    • "retriever" 변수에는 "vectorstore.as_retriever()"를 사용하여 정보 검색(retrieval)을 위한 객체를 생성합니다.
  4. 실행 체인 설정:
    • "retrieval_chain" 변수에는 실행 체인을 설정합니다. 이 체인은 다음과 같이 구성됩니다:
      • "context"와 "question" 매개변수를 사용하여 "retriever.with_config(run_name='Docs')"와 "RunnablePassthrough()"를 결합합니다.
      • "prompt" 템플릿을 추가합니다.
      • 모델(model)을 추가합니다.
      • 출력 파서(StrOutputParser)를 추가합니다.
  5. 결과 검색 및 출력:
    • 비동기 반복문(async for)을 사용하여 질문을 실행하고 결과를 검색합니다.
    • retrieval_chain.astream_log("where did harrison work?", include_names=['Docs'])를 사용하여 "where did harrison work?"라는 질문을 실행하고, 실행 결과를 가져옵니다.
    • 실행 결과를 출력합니다.

이 코드는 OpenAI 모델을 사용하여 컨텍스트와 질문을 기반으로 질문 응답 시스템을 구현하고, 결과를 출력하는 과정을 나타냅니다.

 

나는 OpenAI key를 외부 파일에서 읽어 오도록 아래와 같이 코딩 했음

 

return 값

 

Streaming the incremental RunState

You can simply pass diff=False to get incremental values of RunState. You get more verbose output with more repetitive parts.

 

간단히 diff=False를 전달하여 RunState의 증분 값을 얻을 수 있습니다. 반복되는 부분이 많아지면 더 자세한 출력을 얻을 수 있습니다.

 

async for chunk in retrieval_chain.astream_log("where did harrison work?", include_names=['Docs'], diff=False):
    print("-"*70)
    print(chunk)

 

이 코드는 질문 응답 시스템을 통해 질문을 실행하고 결과를 비동기적으로 가져오는 부분을 설명하고 있습니다. 

 

  • async for chunk in retrieval_chain.astream_log("where did harrison work?", include_names=['Docs'], diff=False)::
    • 이 부분은 비동기 반복문으로, "retrieval_chain" 객체를 사용하여 질문을 실행하고 결과를 비동기적으로 처리합니다.
    • retrieval_chain.astream_log("where did harrison work?", include_names=['Docs'], diff=False)는 "where did harrison work?"라는 질문을 실행하고 결과를 가져오는 코드입니다.
    • include_names=['Docs']는 결과에 대한 필터로, "Docs"라는 이름을 가진 실행에 대한 결과만 포함합니다.
    • diff=False는 결과를 비교(diff)하지 않도록 설정합니다.
  • print("-"*70):
    • 이 부분은 구분선을 출력합니다. 출력 결과를 시각적으로 구분하기 위해 사용됩니다.
  • print(chunk):
    • "chunk"는 질문 실행의 결과를 나타냅니다.
    • 이 부분은 실행 결과를 출력합니다.

이 코드는 "retrieval_chain"을 사용하여 "where did harrison work?"라는 질문을 실행하고 결과를 가져오며, 결과를 출력합니다. 결과는 "Docs"라는 이름을 가진 실행에 대한 것만 포함되며, diff를 비활성화하고 결과를 출력합니다.

 

return 값

----------------------------------------------------------------------
RunLog({'final_output': None,
 'id': 'd16fad8f-018a-4dcd-9bce-bab37e9c19d7',
 'logs': {},
 'streamed_output': []})
----------------------------------------------------------------------
RunLog({'final_output': None,
 'id': 'd16fad8f-018a-4dcd-9bce-bab37e9c19d7',
 'logs': {'Docs': {'end_time': None,
                   'final_output': None,
                   'id': '91e795ef-5cf9-4580-bf94-b4a2464cf5ab',
                   'metadata': {},
                   'name': 'Docs',
                   'start_time': '2023-10-26T16:54:45.839',
                   'streamed_output_str': [],
                   'tags': ['map:key:context', 'FAISS', 'OpenAIEmbeddings'],
                   'type': 'retriever'}},
 'streamed_output': []})
----------------------------------------------------------------------
RunLog({'final_output': None,
 'id': 'd16fad8f-018a-4dcd-9bce-bab37e9c19d7',
 'logs': {'Docs': {'end_time': '2023-10-26T16:54:46.135',
                   'final_output': {'documents': [Document(page_content='harrison worked at kensho')]},
                   'id': '91e795ef-5cf9-4580-bf94-b4a2464cf5ab',
                   'metadata': {},
                   'name': 'Docs',
                   'start_time': '2023-10-26T16:54:45.839',
                   'streamed_output_str': [],
                   'tags': ['map:key:context', 'FAISS', 'OpenAIEmbeddings'],
                   'type': 'retriever'}},
 'streamed_output': []})
----------------------------------------------------------------------
RunLog({'final_output': None,
 'id': 'd16fad8f-018a-4dcd-9bce-bab37e9c19d7',
 'logs': {'Docs': {'end_time': '2023-10-26T16:54:46.135',
                   'final_output': {'documents': [Document(page_content='harrison worked at kensho')]},
                   'id': '91e795ef-5cf9-4580-bf94-b4a2464cf5ab',
                   'metadata': {},
                   'name': 'Docs',
                   'start_time': '2023-10-26T16:54:45.839',
                   'streamed_output_str': [],
                   'tags': ['map:key:context', 'FAISS', 'OpenAIEmbeddings'],
                   'type': 'retriever'}},
 'streamed_output': ['']})
----------------------------------------------------------------------
RunLog({'final_output': None,
 'id': 'd16fad8f-018a-4dcd-9bce-bab37e9c19d7',
 'logs': {'Docs': {'end_time': '2023-10-26T16:54:46.135',
                   'final_output': {'documents': [Document(page_content='harrison worked at kensho')]},
                   'id': '91e795ef-5cf9-4580-bf94-b4a2464cf5ab',
                   'metadata': {},
                   'name': 'Docs',
                   'start_time': '2023-10-26T16:54:45.839',
                   'streamed_output_str': [],
                   'tags': ['map:key:context', 'FAISS', 'OpenAIEmbeddings'],
                   'type': 'retriever'}},
 'streamed_output': ['', 'H']})
----------------------------------------------------------------------
RunLog({'final_output': None,
 'id': 'd16fad8f-018a-4dcd-9bce-bab37e9c19d7',
 'logs': {'Docs': {'end_time': '2023-10-26T16:54:46.135',
                   'final_output': {'documents': [Document(page_content='harrison worked at kensho')]},
                   'id': '91e795ef-5cf9-4580-bf94-b4a2464cf5ab',
                   'metadata': {},
                   'name': 'Docs',
                   'start_time': '2023-10-26T16:54:45.839',
                   'streamed_output_str': [],
                   'tags': ['map:key:context', 'FAISS', 'OpenAIEmbeddings'],
                   'type': 'retriever'}},
 'streamed_output': ['', 'H', 'arrison']})
----------------------------------------------------------------------
RunLog({'final_output': None,
 'id': 'd16fad8f-018a-4dcd-9bce-bab37e9c19d7',
 'logs': {'Docs': {'end_time': '2023-10-26T16:54:46.135',
                   'final_output': {'documents': [Document(page_content='harrison worked at kensho')]},
                   'id': '91e795ef-5cf9-4580-bf94-b4a2464cf5ab',
                   'metadata': {},
                   'name': 'Docs',
                   'start_time': '2023-10-26T16:54:45.839',
                   'streamed_output_str': [],
                   'tags': ['map:key:context', 'FAISS', 'OpenAIEmbeddings'],
                   'type': 'retriever'}},
 'streamed_output': ['', 'H', 'arrison', ' worked']})
----------------------------------------------------------------------
RunLog({'final_output': None,
 'id': 'd16fad8f-018a-4dcd-9bce-bab37e9c19d7',
 'logs': {'Docs': {'end_time': '2023-10-26T16:54:46.135',
                   'final_output': {'documents': [Document(page_content='harrison worked at kensho')]},
                   'id': '91e795ef-5cf9-4580-bf94-b4a2464cf5ab',
                   'metadata': {},
                   'name': 'Docs',
                   'start_time': '2023-10-26T16:54:45.839',
                   'streamed_output_str': [],
                   'tags': ['map:key:context', 'FAISS', 'OpenAIEmbeddings'],
                   'type': 'retriever'}},
 'streamed_output': ['', 'H', 'arrison', ' worked', ' at']})
----------------------------------------------------------------------
RunLog({'final_output': None,
 'id': 'd16fad8f-018a-4dcd-9bce-bab37e9c19d7',
 'logs': {'Docs': {'end_time': '2023-10-26T16:54:46.135',
                   'final_output': {'documents': [Document(page_content='harrison worked at kensho')]},
                   'id': '91e795ef-5cf9-4580-bf94-b4a2464cf5ab',
                   'metadata': {},
                   'name': 'Docs',
                   'start_time': '2023-10-26T16:54:45.839',
                   'streamed_output_str': [],
                   'tags': ['map:key:context', 'FAISS', 'OpenAIEmbeddings'],
                   'type': 'retriever'}},
 'streamed_output': ['', 'H', 'arrison', ' worked', ' at', ' Kens']})
----------------------------------------------------------------------
RunLog({'final_output': None,
 'id': 'd16fad8f-018a-4dcd-9bce-bab37e9c19d7',
 'logs': {'Docs': {'end_time': '2023-10-26T16:54:46.135',
                   'final_output': {'documents': [Document(page_content='harrison worked at kensho')]},
                   'id': '91e795ef-5cf9-4580-bf94-b4a2464cf5ab',
                   'metadata': {},
                   'name': 'Docs',
                   'start_time': '2023-10-26T16:54:45.839',
                   'streamed_output_str': [],
                   'tags': ['map:key:context', 'FAISS', 'OpenAIEmbeddings'],
                   'type': 'retriever'}},
 'streamed_output': ['', 'H', 'arrison', ' worked', ' at', ' Kens', 'ho']})
----------------------------------------------------------------------
RunLog({'final_output': None,
 'id': 'd16fad8f-018a-4dcd-9bce-bab37e9c19d7',
 'logs': {'Docs': {'end_time': '2023-10-26T16:54:46.135',
                   'final_output': {'documents': [Document(page_content='harrison worked at kensho')]},
                   'id': '91e795ef-5cf9-4580-bf94-b4a2464cf5ab',
                   'metadata': {},
                   'name': 'Docs',
                   'start_time': '2023-10-26T16:54:45.839',
                   'streamed_output_str': [],
                   'tags': ['map:key:context', 'FAISS', 'OpenAIEmbeddings'],
                   'type': 'retriever'}},
 'streamed_output': ['', 'H', 'arrison', ' worked', ' at', ' Kens', 'ho', '.']})
----------------------------------------------------------------------
RunLog({'final_output': None,
 'id': 'd16fad8f-018a-4dcd-9bce-bab37e9c19d7',
 'logs': {'Docs': {'end_time': '2023-10-26T16:54:46.135',
                   'final_output': {'documents': [Document(page_content='harrison worked at kensho')]},
                   'id': '91e795ef-5cf9-4580-bf94-b4a2464cf5ab',
                   'metadata': {},
                   'name': 'Docs',
                   'start_time': '2023-10-26T16:54:45.839',
                   'streamed_output_str': [],
                   'tags': ['map:key:context', 'FAISS', 'OpenAIEmbeddings'],
                   'type': 'retriever'}},
 'streamed_output': ['',
                     'H',
                     'arrison',
                     ' worked',
                     ' at',
                     ' Kens',
                     'ho',
                     '.',
                     '']})
----------------------------------------------------------------------
RunLog({'final_output': {'output': 'Harrison worked at Kensho.'},
 'id': 'd16fad8f-018a-4dcd-9bce-bab37e9c19d7',
 'logs': {'Docs': {'end_time': '2023-10-26T16:54:46.135',
                   'final_output': {'documents': [Document(page_content='harrison worked at kensho')]},
                   'id': '91e795ef-5cf9-4580-bf94-b4a2464cf5ab',
                   'metadata': {},
                   'name': 'Docs',
                   'start_time': '2023-10-26T16:54:45.839',
                   'streamed_output_str': [],
                   'tags': ['map:key:context', 'FAISS', 'OpenAIEmbeddings'],
                   'type': 'retriever'}},
 'streamed_output': ['',
                     'H',
                     'arrison',
                     ' worked',
                     ' at',
                     ' Kens',
                     'ho',
                     '.',
                     '']})

 

Parallelism

Let's take a look at how LangChain Expression Language supports parallel requests. For example, when using a RunnableParallel (often written as a dictionary) it executes each element in parallel.

 

LangChain Expression Language가 어떻게 병렬 요청을 지원하는지 살펴보겠습니다. 예를 들어 RunnableParallel(종종 사전으로 작성됨)을 사용하면 각 요소가 병렬로 실행됩니다.

 

from langchain.schema.runnable import RunnableParallel
chain1 = ChatPromptTemplate.from_template("tell me a joke about {topic}") | model
chain2 = ChatPromptTemplate.from_template("write a short (2 line) poem about {topic}") | model
combined = RunnableParallel(joke=chain1, poem=chain2)
chain1.invoke({"topic": "bears"})

이 코드는 "langchain" 라이브러리를 사용하여 두 개의 병렬 실행 체인을 생성하고, 이 두 체인을 조합하여 단일 실행 객체를 만들고, 그 중 하나인 "chain1"을 사용하여 특정 주제에 대한 실행을 시작하는 예시를 보여줍니다

 

  1. 모듈 및 클래스 가져오기:
    • langchain.schema.runnable 모듈에서 RunnableParallel 클래스를 가져옵니다. 이 클래스는 병렬 실행을 관리하고 조합하는 데 사용됩니다.
  2. 실행 체인 생성:
    • "chain1"은 "ChatPromptTemplate.from_template("tell me a joke about {topic}") | model"를 사용하여 생성됩니다. 이 체인은 주어진 주제에 관한 농담을 생성하기 위해 대화 템플릿과 모델을 조합합니다.
    • "chain2"는 "ChatPromptTemplate.from_template("write a short (2 line) poem about {topic}") | model"를 사용하여 생성됩니다. 이 체인은 주어진 주제에 관한 짧은 시를 생성하기 위해 대화 템플릿과 모델을 조합합니다.
  3. 병렬 실행 조합:
    • "combined"는 "RunnableParallel(joke=chain1, poem=chain2)"를 사용하여 생성됩니다. 이 객체는 "joke" 및 "poem"이라는 이름으로 "chain1"과 "chain2"를 조합한 것입니다. 이를 통해 "joke" 및 "poem" 실행을 병렬로 시작하고 결과를 처리할 수 있습니다.
  4. 실행 시작:
    • "chain1.invoke({"topic": "bears"})"을 사용하여 "chain1"을 실행합니다. 이 부분은 "bears" 주제에 관한 농담을 생성하는 실행을 시작합니다.

이 코드는 두 개의 병렬 실행 체인을 생성하고 실행하기 위한 방법을 보여주며, "chain1"을 사용하여 "bears" 주제에 관한 실행을 시작합니다.

chain2.invoke({"topic": "bears"})
combined.invoke({"topic": "bears"})

이 코드는 "chain2"와 "combined" 두 실행 체인을 사용하여 "bears" 주제에 관한 실행을 시작하는 부분을 설명하고 있습니다.

 

  1. "chain2.invoke({"topic": "bears"})":
    • 이 부분은 "chain2"를 사용하여 "bears" 주제에 관한 실행을 시작합니다. "chain2"는 주어진 주제에 관한 짧은 시를 생성하기 위한 실행을 나타냅니다.
  2. "combined.invoke({"topic": "bears"})":
    • 이 부분은 "combined"를 사용하여 "bears" 주제에 관한 실행을 시작합니다. "combined"는 "joke" 및 "poem"이라는 이름으로 두 개의 실행 체인을 병렬로 조합한 것입니다.

이 코드는 "chain2"와 "combined" 두 실행 체인을 사용하여 "bears" 주제에 관한 실행을 시작하며, 각 실행은 주어진 주제에 따라 농담 또는 시를 생성하는 목적을 갖고 있습니다.

Parallelism on batches

Parallelism can be combined with other runnables. Let's try to use parallelism with batches.

 

병렬성은 다른 실행 가능 항목과 결합될 수 있습니다. 배치에 병렬성을 사용해 보겠습니다.

 

chain1.batch([{"topic": "bears"}, {"topic": "cats"}])

이 코드는 "chain1" 실행 체인을 사용하여 여러 개의 실행을 일괄 처리하는 방법을 설명하고 있습니다.

 

  • chain1.batch([{"topic": "bears"}, {"topic": "cats"}]):
    • 이 부분은 "chain1"을 사용하여 "bears" 주제와 "cats" 주제에 관한 여러 실행을 일괄 처리하는 명령입니다.
    • [{"topic": "bears"}, {"topic": "cats"}]는 실행의 입력 매개변수로 사용되는 딕셔너리 목록을 나타냅니다. 각 딕셔너리에는 "topic" 키와 실행할 주제에 해당하는 값이 포함되어 있습니다.

이 코드는 "chain1"을 사용하여 "bears" 주제와 "cats" 주제에 대한 여러 실행을 생성하고 처리합니다. 각 실행은 주어진 주제에 따라 농담을 생성하는 목적을 갖고 있습니다.

 

chain2.batch([{"topic": "bears"}, {"topic": "cats"}])

combined.batch([{"topic": "bears"}, {"topic": "cats"}])

 

 

 

 

 

 

 

반응형


반응형

https://www.youtube.com/watch?v=kYRB-vJFy38

 

먼저 Langchain과 open AI를 인스톨 한다.

pip install langchain

pip install openai

 

(필요에 따라 langchain과 openai를 업그레이드 할 필요가 있음)

 

나는 openai api key 세팅을 아래와 같이 별도의 txt 파일에 두고 이를 불러와서 씀.

 

LangChain에 OpenAI key를 세팅하고 OpenAI에게 질문을 해서 답변을 받는 가장 간단한 코딩.

langchain.llms에 있는 OpenAI 모듈을 사용해서 api key를 세팅한 후 질문을 보내면 답변을 받을 수 있음.

위 코드는 파스타를 좋아하는 사람이 휴가때 가기 좋은 곳 5곳을 질문했고 그에 대한 답을 얻었음.

(변수 lim에 openAI 세팅이 되 있음. 원래는 llm 인데 lim 으로 오타가 난 것임. 참고 바람)

 

 

위 코드는 langchain의 PromptTemplate으로 프롬프트를 관리하는 간단한 예제이다.

위 예제에서는 질문 안에 있는 음식(food)을 변수로 처리해서 별도로 값을 입력 받아서 prompt를 완성할 수 있게 하는 소스코드임.

 

질문을 던질 때 food에 dessert를 넣어서 디저트를 좋아하는 사람이 갈만한 휴가 장소 5곳을 물었고 그에 대한 답을 OpenAI로 부터 받았음.

 

 

위 코드는 langchain.chains 의 LLMChain 을 사용해서 OpenAI에 질문을 던지는 방법을 보여 준다.

소스코드가 하는 일은 위와 같다.

이번에는 food에 fruit을 넣어서 질문을 했고 위와는 다른 답변을 얻어 냈다.

 

다음은 Agents 에 대해 살펴 본다.

 

 

google-search-results 모듈을 인스톨 한다.

 

필요한 모듈을 import 한다.

그리고 llm 변수에 OpenAI 모델을 load 한다.

 

참고로 open_file() 함수는 위에 세팅해 두었던 것인데 이 부분을 따로 사용하려면 아래 함수를 넣는다.

 

def open_file(filepath) :
    with open(filepath, 'r', encoding='utf-8') as infile :
        return infile.read()

그 다음 필요한 툴을 로드한다.

 

# Load in some tools to use

# os.environ["SERPAPI_API_KEY"] = "..."

tools = load_tools(["serpapi", "llm-math"], llm=llm)

 

이 모듈을 실행하려면 SerpAPI 계정이 있어야 한다. 이 서비스는 유료인 것 같음.

 

# Finally, let's initialize an agent with:
# 1. The tools
# 2. The language model
# 3. The type of agent we want to use.

agent = initialize_agent(tools, llm, agent="zero-shot-react-description", verbose=True)

이제 agent를 초기화 한다. 

initialize_agent() 메소드를 사용하고 파라미터로 tools와 llm 그리고 agent 를 전달한다.

 

Agent Type들에는 여러개가 있는데 자세한 사항은 아래 페이지에서 보면 된다.

 

https://python.langchain.com/docs/modules/agents/agent_types/

 

Agent Types | 🦜️🔗 Langchain

Agents use an LLM to determine which actions to take and in what order.

python.langchain.com

 

# Now let's test it out!
agent.run("Who is the current leader of Japan? What is the largest prime number that is smaller than their age?")

 

이제 이 agent를 run 하면 된다. 이때 원하는 prompt를 전달한다.

prompt에는 두가지 질문이 있다. 일본의 현재 리더는 누구인가? 그리고 나이보다 작은 가장 큰 소수는 무엇입니까? 이다.

 

위 유투브 클립에서는 아래와 같은 답변을 얻어 냈다.

 

위 질문에 답변을 하기 위해 이 agent 는 여러 일을 하게 된다.

 

처음에 자기가 할 일을 얘기한다. 이 agent 가 할 일은 일본의 수상이 누구인지 찾고 그 수상의 나이를 찾아서 그 나이보다 작은 가장 큰 소수를 찾는 일을 하는 것이다.

 

처음 질문에 대한 답변은 Fumio Kishida이다.

그 다음 이 수상의 나이를 찾아야 한다. age of Fumio Kishida. 나이는 65세이다.

 

그리고 나서 65보다 작은 가장 큰 소수를 찾는 거다.

65가 소수이기 때문에 답은 65 이다.

 

그리고 나서 final answer를 내 놓는다.

이 작업은 chain을 통해 이루어 진다.

 

다음은 Memory에 대해서 알아본다.

 

우선 ConversationChain 모듈을 import해야 한다.

 

그 다음 OpenAI를 세팅하고 나서 ConversationChain을 초기화 한다.

 

그 다음 predict() 메소드를 사용해서 실행한다. 결과는 다음과 같다.

 

conversation.predict(input="Hi there!")

 

Hi there라는 프롬프트를 보냈더니 자기가 알아서 prompt를 포맷해서 전달합니다.

 

prompt 앞에 이 시스템 조건을 붙입니다.

 

The following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.

 

다음은 인간과 AI의 친근한 대화이다. AI는 말이 많고 상황에 맞는 구체적인 세부 정보를 많이 제공합니다. AI가 질문에 대한 답을 모른다면, 사실은 모른다고 말합니다.

 

그 다음 전달한 prompt 'hi there!를 붙입니다.

 

그럼 답변으로 Hello! How are you doing today? 를 받았습니다.

 

conversation.predict(input="I'm doing well! Just having a conversation with an AI.")

 

그 다음 이어서 질문을 합니다. 

 

그러면 이전 prompt에다가 현재의 prompt를 추가해서 보냅니다.

이렇게 함으로서 대화가 맥락이 끊기지 않고 계속 이어질 수 있도록 합니다.

맥락이 끊어지지 않도록 하기 위해서 이전 prompt를 계속 memory 하게 됩니다.

이 일을 하는게 ConversationChain입니다.

 

conversation.predict(input="what is an alternative phrase for the first thing I said to you?")

그 다음. 내가 너한테 맨 먼저 한 말이 뭐지? 라고 물어봅니다.

 

 

맨 먼저 한 말은 Hi there! 였고 OpenAI는 잘 대답합니다. 

대화들을 계속 기억하고 있다는 이야기 입니다.

 

그 다음에는 그 내가 맨 처음 한 얘기는 어떤 의미인지에 대해 질문합니다.

 

conversation.predict(input="what is an alternative phrase for the first thing I said to you?")

 

OpenAI 는 Hi there!는 그냥 인사말이었다고 답변을 하네요.

 

뭔가 대화가 되어 가는 느낌 입니다.

 

이상 Greg Kamradt 가 운영하는 채널에 있는 LangChain 101: Quickstart Guide를 살펴 봤습니다.

 

 

 

반응형


반응형

LangChain Expression Language or LCEL is a declarative way to easily compose chains together. There are several benefits to writing chains in this manner (as opposed to writing normal code):

 

LangChain 표현 언어(LCEL)는 체인을 쉽게 구성하는 선언적 방법입니다. 이러한 방식으로 체인을 작성하면 다음과 같은 여러 이점이 있습니다(일반 코드 작성과 반대).

 

Async, Batch, and Streaming Support Any chain constructed this way will automatically have full sync, async, batch, and streaming support. This makes it easy to prototype a chain in a Jupyter notebook using the sync interface, and then expose it as an async streaming interface.

 

비동기, 배치 및 스트리밍 지원 이러한 방식으로 구성된 모든 체인은 자동으로 전체 동기화, 비동기, 배치 및 스트리밍을 지원합니다. 이를 통해 동기화 인터페이스를 사용하여 Jupyter 노트북에서 체인의 프로토타입을 쉽게 만든 다음 이를 비동기 스트리밍 인터페이스로 노출할 수 있습니다.

 

Fallbacks The non-determinism of LLMs makes it important to be able to handle errors gracefully. With LCEL you can easily attach fallbacks to any chain.

 

폴백 LLM의 비결정성으로 인해 오류를 적절하게 처리하는 것이 중요합니다. LCEL을 사용하면 모든 체인에 폴백을 쉽게 연결할 수 있습니다.

 

Parallelism Since LLM applications involve (sometimes long) API calls, it often becomes important to run things in parallel. With LCEL syntax, any components that can be run in parallel automatically are.

 

병렬성 LLM 응용 프로그램에는 (때때로 긴) API 호출이 포함되므로 작업을 병렬로 실행하는 것이 중요해지는 경우가 많습니다. LCEL 구문을 사용하면 병렬로 실행될 수 있는 모든 구성 요소가 자동으로 실행됩니다.

 

Seamless LangSmith Tracing Integration As your chains get more and more complex, it becomes increasingly important to understand what exactly is happening at every step. With LCEL, all steps are automatically logged to LangSmith for maximal observability and debuggability.

 

원활한 LangSmith 추적 통합 체인이 점점 더 복잡해짐에 따라 모든 단계에서 정확히 무슨 일이 일어나고 있는지 이해하는 것이 점점 더 중요해지고 있습니다. LCEL을 사용하면 관찰 가능성과 디버그 가능성을 극대화하기 위해 모든 단계가 자동으로 LangSmith에 기록됩니다.

 

 

Interface

The base interface shared by all LCEL objects  모든 LCEL 객체가 공유하는 기본 인터페이스

How to

How to use core features of LCEL   LCEL 핵심 기능 활용 방법

Cookbook

Examples of common LCEL usage patterns  일반적인 LCEL 사용 패턴의 예

Why use LCEL

A deeper dive into the benefits of LCEL  LCEL의 이점에 대해 자세히 알아보기

반응형

LangChain - Quickstart

2023. 10. 20. 05:19 | Posted by 솔웅


반응형

https://python.langchain.com/docs/get_started/quickstart

 

Quickstart | 🦜️🔗 Langchain

Installation

python.langchain.com

 

 

Installation

To install LangChain run:

 

pip install langchain

 

For more details, see our Installation guide. 자세한 내용은 설치 가이드를 참조하세요.

 

 

Environment setup

Using LangChain will usually require integrations with one or more model providers, data stores, APIs, etc. For this example, we'll use OpenAI's model APIs.

 

LangChain을 사용하려면 일반적으로 하나 이상의 모델 공급자, 데이터 저장소, API 등과의 통합이 필요합니다. 이 예에서는 OpenAI의 모델 API를 사용합니다.

 

First we'll need to install their Python package:

 

먼저 Python 패키지를 설치해야 합니다.

 

pip install openai

 

Accessing the API requires an API key, which you can get by creating an account and heading here. Once we have a key we'll want to set it as an environment variable by running:

 

API에 액세스하려면 API 키가 필요합니다. API 키는 계정을 생성하고 여기에서 얻을 수 있습니다. 키가 있으면 다음을 실행하여 이를 환경 변수로 설정하려고 합니다.

 

export OPENAI_API_KEY="..."

 

If you'd prefer not to set an environment variable you can pass the key in directly via the openai_api_key named parameter when initiating the OpenAI LLM class:

 

환경 변수를 설정하지 않으려는 경우 OpenAI LLM 클래스를 시작할 때 openai_api_key라는 매개변수를 통해 직접 키를 전달할 수 있습니다.

 

from langchain.llms import OpenAI

llm = OpenAI(openai_api_key="...")

 

나는 아래 방법 이용함.

 

 

Building an application

Now we can start building our language model application. LangChain provides many modules that can be used to build language model applications. Modules can be used as stand-alones in simple applications and they can be combined for more complex use cases.

 

이제 언어 모델 애플리케이션 구축을 시작할 수 있습니다. LangChain은 언어 모델 애플리케이션을 구축하는 데 사용할 수 있는 많은 모듈을 제공합니다. 모듈은 간단한 애플리케이션에서 독립 실행형으로 사용할 수 있으며 더 복잡한 사용 사례에서는 결합할 수 있습니다.

 

The most common and most important chain that LangChain helps create contains three things:

 

LangChain이 생성하는 데 도움이 되는 가장 일반적이고 가장 중요한 체인에는 다음 세 가지가 포함됩니다.

 

  • LLM: The language model is the core reasoning engine here. In order to work with LangChain, you need to understand the different types of language models and how to work with them.
  • LLM: 언어 모델은 여기서 핵심 추론 엔진입니다. LangChain을 사용하려면 다양한 유형의 언어 모델과 이를 사용하는 방법을 이해해야 합니다.
  • Prompt Templates: This provides instructions to the language model. This controls what the language model outputs, so understanding how to construct prompts and different prompting strategies is crucial.
  • 프롬프트 템플릿: 언어 모델에 대한 지침을 제공합니다. 이는 언어 모델의 출력을 제어하므로 프롬프트와 다양한 프롬프트 전략을 구성하는 방법을 이해하는 것이 중요합니다.
  • Output Parsers: These translate the raw response from the LLM to a more workable format, making it easy to use the output downstream.
  • 출력 파서: LLM의 원시 응답을 보다 실행 가능한 형식으로 변환하여 출력 다운스트림을 쉽게 사용할 수 있도록 합니다.

In this getting started guide we will cover those three components by themselves, and then go over how to combine all of them. Understanding these concepts will set you up well for being able to use and customize LangChain applications. Most LangChain applications allow you to configure the LLM and/or the prompt used, so knowing how to take advantage of this will be a big enabler.

 

이 시작 가이드에서는 이 세 가지 구성 요소를 단독으로 다룬 다음 이 모든 구성 요소를 결합하는 방법을 살펴보겠습니다. 이러한 개념을 이해하면 LangChain 애플리케이션을 사용하고 사용자 정의하는 데 도움이 됩니다. 대부분의 LangChain 애플리케이션에서는 LLM 및/또는 사용되는 프롬프트를 구성할 수 있으므로 이를 활용하는 방법을 아는 것이 큰 도움이 될 것입니다.

 

LLMs

There are two types of language models, which in LangChain are called:

 

LangChain에는 두 가지 유형의 언어 모델이 있습니다.

 

  • LLMs: this is a language model which takes a string as input and returns a string
  • LLM: 문자열을 입력으로 받아 문자열을 반환하는 언어 모델입니다.
  • ChatModels: this is a language model which takes a list of messages as input and returns a message
  • ChatModels: 메시지 목록을 입력으로 받아 메시지를 반환하는 언어 모델입니다.

The input/output for LLMs is simple and easy to understand - a string. But what about ChatModels? The input there is a list of ChatMessages, and the output is a single ChatMessage. A ChatMessage has two required components:

 

LLM의 입력/출력은 간단하고 이해하기 쉽습니다. 즉, 문자열입니다. 하지만 ChatModel은 어떻습니까? 입력에는 ChatMessage 목록이 있고 출력은 단일 ChatMessage입니다. ChatMessage에는 두 가지 필수 구성 요소가 있습니다.

 

  • content: This is the content of the message  메시지의 내용입니다..
  • role: This is the role of the entity from which the ChatMessage is coming from. ChatMessage가 나오는 엔터티의 역할입니다.

LangChain provides several objects to easily distinguish between different roles:

 

LangChain은 서로 다른 역할을 쉽게 구별할 수 있는 여러 개체를 제공합니다.

 

  • HumanMessage: A ChatMessage coming from a human/user.
  • AIMessage: A ChatMessage coming from an AI/assistant.
  • SystemMessage: A ChatMessage coming from the system.
  • FunctionMessage: A ChatMessage coming from a function call.

If none of those roles sound right, there is also a ChatMessage class where you can specify the role manually. For more information on how to use these different messages most effectively, see our prompting guide.

 

이러한 역할 중 어느 것도 적절하지 않은 경우 역할을 수동으로 지정할 수 있는 ChatMessage 클래스도 있습니다. 이러한 다양한 메시지를 가장 효과적으로 사용하는 방법에 대한 자세한 내용은 메시지 안내 가이드를 참조하세요.

 

LangChain provides a standard interface for both, but it's useful to understand this difference in order to construct prompts for a given language model. The standard interface that LangChain provides has two methods:

 

LangChain은 두 가지 모두에 대한 표준 인터페이스를 제공하지만 주어진 언어 모델에 대한 프롬프트를 구성하려면 이러한 차이점을 이해하는 것이 유용합니다. LangChain이 제공하는 표준 인터페이스에는 두 가지 방법이 있습니다.

 

  • predict: Takes in a string, returns a string  문자열을 받아 문자열을 반환합니다.
  • predict_messages: Takes in a list of messages, returns a message.  메시지 목록을 가져와 메시지를 반환합니다.

Let's see how to work with these different types of models and these different types of inputs. First, let's import an LLM and a ChatModel.

 

이러한 다양한 유형의 모델과 다양한 유형의 입력을 사용하여 작업하는 방법을 살펴보겠습니다. 먼저 LLM과 ChatModel을 가져오겠습니다.

 

from langchain.llms import OpenAI
from langchain.chat_models import ChatOpenAI

llm = OpenAI()
chat_model = ChatOpenAI()

llm.predict("hi!")
>>> "Hi"

chat_model.predict("hi!")
>>> "Hi"

 

 

Note) 아래와 같은 에러메시지가 나오면 Langchain을 최신 버전으로 업그레이드 합니다.

pip install langchain --upgrade

 

The OpenAI and ChatOpenAI objects are basically just configuration objects. You can initialize them with parameters like temperature and others, and pass them around.

 

OpenAI 및 ChatOpenAI 개체는 기본적으로 구성 개체입니다. temperature  및 기타 매개변수로 초기화하고 전달할 수 있습니다.

 

Next, let's use the predict method to run over a string input.

 

다음으로 예측 메서드를 사용하여 문자열 입력을 실행해 보겠습니다.

 

text = "What would be a good company name for a company that makes colorful socks?"

llm.predict(text)
# >> Feetful of Fun

chat_model.predict(text)
# >> Socks O'Color

Finally, let's use the predict_messages method to run over a list of messages.

 

마지막으로 Predict_messages 메서드를 사용하여 메시지 목록을 살펴보겠습니다.

 

from langchain.schema import HumanMessage

text = "What would be a good company name for a company that makes colorful socks?"
messages = [HumanMessage(content=text)]

llm.predict_messages(messages)
# >> Feetful of Fun

chat_model.predict_messages(messages)
# >> Socks O'Color

For both these methods, you can also pass in parameters as keyword arguments. For example, you could pass in temperature=0 to adjust the temperature that is used from what the object was configured with. Whatever values are passed in during run time will always override what the object was configured with.

 

두 가지 방법 모두 매개변수를 키워드 인수로 전달할 수도 있습니다. 예를 들어, 온도=0을 전달하여 객체 구성에 사용되는 온도를 조정할 수 있습니다. 런타임 중에 전달되는 값은 항상 개체 구성을 재정의합니다.

 

Prompt templates

 

Most LLM applications do not pass user input directly into an LLM. Usually they will add the user input to a larger piece of text, called a prompt template, that provides additional context on the specific task at hand.

 

대부분의 LLM 응용 프로그램은 사용자 입력을 LLM에 직접 전달하지 않습니다. 일반적으로 그들은 현재 특정 작업에 대한 추가 컨텍스트를 제공하는 프롬프트 템플릿이라는 더 큰 텍스트에 사용자 입력을 추가합니다.

 

In the previous example, the text we passed to the model contained instructions to generate a company name. For our application, it'd be great if the user only had to provide the description of a company/product, without having to worry about giving the model instructions.

 

이전 예에서 모델에 전달한 텍스트에는 회사 이름을 생성하는 지침이 포함되어 있습니다. 우리 애플리케이션의 경우 사용자가 모델 지침을 제공하는 것에 대해 걱정할 필요 없이 회사/제품에 대한 설명만 제공하면 좋을 것입니다.

 

PromptTemplates help with exactly this! They bundle up all the logic for going from user input into a fully formatted prompt. This can start off very simple - for example, a prompt to produce the above string would just be:

 

PromptTemplate이 바로 이 작업에 도움이 됩니다! 사용자 입력을 완전히 형식화된 프롬프트로 전환하기 위한 모든 논리를 묶습니다. 이는 매우 간단하게 시작할 수 있습니다. 예를 들어 위 문자열을 생성하라는 프롬프트는 다음과 같습니다.

 

from langchain.prompts import PromptTemplate

prompt = PromptTemplate.from_template("What is a good name for a company that makes {product}?")
prompt.format(product="colorful socks")
What is a good name for a company that makes colorful socks?

However, the advantages of using these over raw string formatting are several. You can "partial" out variables - e.g. you can format only some of the variables at a time. You can compose them together, easily combining different templates into a single prompt. For explanations of these functionalities, see the section on prompts for more detail.

 

그러나 원시 문자열 형식화에 비해 이를 사용하면 여러 가지 장점이 있습니다. 변수를 "부분적으로" 출력할 수 있습니다. 한 번에 일부 변수만 형식화할 수 있습니다. 다양한 템플릿을 하나의 프롬프트로 쉽게 결합하여 함께 구성할 수 있습니다. 이러한 기능에 대한 설명은 프롬프트 섹션을 참조하세요.

 

PromptTemplates can also be used to produce a list of messages. In this case, the prompt not only contains information about the content, but also each message (its role, its position in the list, etc) Here, what happens most often is a ChatPromptTemplate is a list of ChatMessageTemplates. Each ChatMessageTemplate contains instructions for how to format that ChatMessage - its role, and then also its content. Let's take a look at this below:

 

PromptTemplate을 사용하여 메시지 목록을 생성할 수도 있습니다. 이 경우 프롬프트에는 콘텐츠에 대한 정보뿐만 아니라 각 메시지(해당 역할, 목록에서의 위치 등)도 포함됩니다. 여기서 가장 자주 발생하는 것은 ChatPromptTemplate이 ChatMessageTemplate의 목록이라는 것입니다. 각 ChatMessageTemplate에는 해당 ChatMessage(해당 역할 및 콘텐츠)의 형식을 지정하는 방법에 대한 지침이 포함되어 있습니다. 아래에서 이에 대해 살펴보겠습니다.

 

from langchain.prompts.chat import ChatPromptTemplate

template = "You are a helpful assistant that translates {input_language} to {output_language}."
human_template = "{text}"

chat_prompt = ChatPromptTemplate.from_messages([
    ("system", template),
    ("human", human_template),
])

chat_prompt.format_messages(input_language="English", output_language="French", text="I love programming.")

 

[
    SystemMessage(content="You are a helpful assistant that translates English to French.", additional_kwargs={}),
    HumanMessage(content="I love programming.")
]

 

Output parsers

OutputParsers convert the raw output of an LLM into a format that can be used downstream. There are few main type of OutputParsers, including:

 

OutputParser는 LLM의 원시 출력을 다운스트림에서 사용할 수 있는 형식으로 변환합니다. 다음을 포함하여 몇 가지 주요 유형의 OutputParser가 있습니다.

 

  • Convert text from LLM -> structured information (e.g. JSON)
  • LLM에서 텍스트 변환 -> 구조화된 정보(예: JSON)
  • Convert a ChatMessage into just a string
  • ChatMessage를 문자열로 변환
  • Convert the extra information returned from a call besides the message (like OpenAI function invocation) into a string.
  • 메시지(예: OpenAI 함수 호출) 외에 호출에서 반환된 추가 정보를 문자열로 변환합니다.

For full information on this, see the section on output parsers

 

Output parsers | 🦜️🔗 Langchain

Language models output text. But many times you may want to get more structured information than just text back. This is where output parsers come in.

python.langchain.com

이에 대한 자세한 내용은 section on output parsers 을 참조하세요.

 

In this getting started guide, we will write our own output parser - one that converts a comma separated list into a list.

 

이 시작 가이드에서는 쉼표로 구분된 목록을 목록으로 변환하는 자체 출력 구문 분석기를 작성합니다.

 

from langchain.schema import BaseOutputParser

class CommaSeparatedListOutputParser(BaseOutputParser):
    """Parse the output of an LLM call to a comma-separated list."""


    def parse(self, text: str):
        """Parse the output of an LLM call."""
        return text.strip().split(", ")

CommaSeparatedListOutputParser().parse("hi, bye")
# >> ['hi', 'bye']

PromptTemplate + LLM + OutputParser

 

We can now combine all these into one chain. This chain will take input variables, pass those to a prompt template to create a prompt, pass the prompt to a language model, and then pass the output through an (optional) output parser. This is a convenient way to bundle up a modular piece of logic. Let's see it in action!

 

이제 이 모든 것을 하나의 체인으로 결합할 수 있습니다. 이 체인은 입력 변수를 가져와 프롬프트 템플릿에 전달하여 프롬프트를 생성하고, 프롬프트를 언어 모델에 전달한 다음 (선택 사항) 출력 구문 분석기를 통해 출력을 전달합니다. 이는 모듈식 로직 조각을 묶는 편리한 방법입니다. 실제로 확인해 봅시다!

 

from langchain.chat_models import ChatOpenAI
from langchain.prompts.chat import ChatPromptTemplate
from langchain.schema import BaseOutputParser

class CommaSeparatedListOutputParser(BaseOutputParser):
    """Parse the output of an LLM call to a comma-separated list."""


    def parse(self, text: str):
        """Parse the output of an LLM call."""
        return text.strip().split(", ")

template = """You are a helpful assistant who generates comma separated lists.
A user will pass in a category, and you should generate 5 objects in that category in a comma separated list.
ONLY return a comma separated list, and nothing more."""
human_template = "{text}"

chat_prompt = ChatPromptTemplate.from_messages([
    ("system", template),
    ("human", human_template),
])
chain = chat_prompt | ChatOpenAI() | CommaSeparatedListOutputParser()
chain.invoke({"text": "colors"})
# >> ['red', 'blue', 'green', 'yellow', 'orange']

Note that we are using the | syntax to join these components together. This | syntax is called the LangChain Expression Language. To learn more about this syntax, read the documentation here.

 

우리는 | 이러한 구성 요소를 함께 결합하는 구문입니다. 이 | 구문을 LangChain 표현 언어라고 합니다. 이 구문에 대해 자세히 알아보려면 여기에서 설명서를 읽어보세요.

 

Next steps

This is it! We've now gone over how to create the core building block of LangChain applications. There is a lot more nuance in all these components (LLMs, prompts, output parsers) and a lot more different components to learn about as well. To continue on your journey:

 

여기까지 입니다! 이제 우리는 LangChain 애플리케이션의 핵심 빌딩 블록을 생성하는 방법을 살펴보았습니다. 이러한 모든 구성 요소(LLM, 프롬프트, 출력 구문 분석기)에는 훨씬 더 많은 미묘한 차이가 있으며, 배워야 할 구성 요소도 훨씬 더 많습니다. 여행을 계속하려면:

 

 

Retrieval-augmented generation (RAG) | 🦜️🔗 Langchain

Open In Colab

python.langchain.com

 

 

반응형

'LangChain > Get Started' 카테고리의 다른 글

LangChain - Installation  (0) 2023.10.20
Langchain - Introduction  (0) 2023.10.20

LangChain - Installation

2023. 10. 20. 03:22 | Posted by 솔웅


반응형

https://python.langchain.com/docs/get_started/installation

 

Installation | 🦜️🔗 Langchain

Official release

python.langchain.com

 

To install LangChain run:

 

pip install langchain

 

This will install the bare minimum requirements of LangChain. A lot of the value of LangChain comes when integrating it with various model providers, datastores, etc. By default, the dependencies needed to do that are NOT installed. However, there are two other ways to install LangChain that do bring in those dependencies.

 

LangChain의 최소 요구 사항을 설치하겠습니다.  LangChain의 많은 가치는 LangChain을 다양한 모델 공급자, 데이터 저장소 등과 통합할 때 발생합니다. 기본적으로 이를 수행하는 데 필요한 종속성은 설치되지 않습니다. 그러나 이러한 종속성을 가져오는 LangChain을 설치하는 다른 두 가지 방법이 있습니다.

 

To install modules needed for the common LLM providers, run:

 

일반 LLM 공급자에 필요한 모듈을 설치하려면 다음을 실행하세요.

 

pip install langchain[llms]

 

To install all modules needed for all integrations, run:

 

모든 통합에 필요한 모든 모듈을 설치하려면 다음을 실행하세요.

 

pip install langchain[all]

 

 

 

Note that if you are using zsh, you'll need to quote square brackets when passing them as an argument to a command, for example:

 

zsh를 사용하는 경우 명령에 대한 인수로 전달할 때 대괄호를 인용해야 합니다. 예를 들면 다음과 같습니다.

 

pip install 'langchain[all]'

 

If you want to install from source, you can do so by cloning the repo and be sure that the directory is PATH/TO/REPO/langchain/libs/langchain running:

 

소스에서 설치하려면 repo를 복제하여 설치할 수 있으며 디렉터리가 PATH/TO/REPO/langchain/libs/langchain이 실행 중인지 확인하세요.

 

pip install -e .

 

Langchain 을 설치한 후 최신 버전으로 업그레이드 한다.

 

pip install -U langchain

 

 

 

 

 

반응형

'LangChain > Get Started' 카테고리의 다른 글

LangChain - Quickstart  (1) 2023.10.20
Langchain - Introduction  (0) 2023.10.20

Langchain - Introduction

2023. 10. 20. 02:28 | Posted by 솔웅


반응형

https://python.langchain.com/docs/get_started/introduction

 

Introduction | 🦜️🔗 Langchain

LangChain is a framework for developing applications powered by language models. It enables applications that:

python.langchain.com

 

 

 

LangChain is a framework for developing applications powered by language models. It enables applications that:

 

LangChain은 언어 모델을 기반으로 하는 애플리케이션을 개발하기 위한 프레임워크입니다. 이는 다음과 같은 애플리케이션을 가능하게 합니다.

 

  • Are context-aware: connect a language model to sources of context (prompt instructions, few shot examples, content to ground its response in, etc.)
  • 상황 인식: 언어 모델을 상황 소스( prompt instructions, few shot examples, content to ground its response in, etc. )에 연결합니다.

  • Reason: rely on a language model to reason (about how to answer based on provided context, what actions to take, etc.)
  • 이유: 추론하기 위해 언어 모델에 의존합니다(제공된 맥락에 따라 대답하는 방법, 취해야 할 조치 등에 대해).

 

The main value props of LangChain are:

 

LangChain의 주요 가치 제안은 다음과 같습니다:

 

  1. Components: abstractions for working with language models, along with a collection of implementations for each abstraction. Components are modular and easy-to-use, whether you are using the rest of the LangChain framework or not

    구성요소: 각 추상화에 대한 구현 모음과 함께 언어 모델 작업을 위한 추상화입니다. LangChain 프레임워크의 나머지 부분을 사용하는지 여부에 관계없이 구성 요소는 모듈식이며 사용하기 쉽습니다.

  2. Off-the-shelf chains: a structured assembly of components for accomplishing specific higher-level tasks

    기성품 체인: 특정 상위 수준 작업을 수행하기 위한 구성 요소의 구조화된 어셈블리

Off-the-shelf chains make it easy to get started. For complex applications, components make it easy to customize existing chains and build new ones.

 

기성품 체인을 사용하면 쉽게 시작할 수 있습니다. 복잡한 애플리케이션의 경우 구성요소를 사용하면 기존 체인을 쉽게 맞춤화하고 새 체인을 구축할 수 있습니다.

 

 

Get started

Here’s how to install LangChain, set up your environment, and start building.

 

LangChain을 설치하고, 환경을 설정하고, 구축을 시작하는 방법은 다음과 같습니다.

 

We recommend following our Quickstart guide to familiarize yourself with the framework by building your first LangChain application.

 

첫 번째 LangChain 애플리케이션을 구축하여 프레임워크에 익숙해지려면 빠른 시작 가이드를 따르는 것이 좋습니다.

 

Note: These docs are for the LangChain Python package. For documentation on LangChain.js, the JS/TS version, head here.

 

참고: 이 문서는 LangChain Python 패키지용입니다. JS/TS 버전인 LangChain.js에 대한 문서를 보려면 여기를 방문하세요.

 

 

Modules

LangChain provides standard, extendable interfaces and external integrations for the following modules, listed from least to most complex:

LangChain은 가장 덜 복잡한 것부터 가장 복잡한 것 순으로 나열된 다음 모듈에 대해 확장 가능한 표준 인터페이스와 외부 통합을 제공합니다.

Model I/O

Interface with language models  언어 모델과의 인터페이스

Retrieval

Interface with application-specific data 애플리케이션별 데이터와의 인터페이스

Chains

Construct sequences of calls  호출 시퀀스 구성

Agents

Let chains choose which tools to use given high-level directives

 

체인이 주어진 높은 수준의 지시문에 사용할 도구를 선택하도록 허용

Memory

Persist application state between runs of a chain  체인 실행 간에 애플리케이션 상태 유지

Callbacks

Log and stream intermediate steps of any chain  모든 체인의 중간 단계를 기록하고 스트리밍합니다.

 

 

Examples, ecosystem, and resources

Use cases

Walkthroughs and best-practices for common end-to-end use cases, like:

 

다음과 같은 일반적인 엔드투엔드 사용 사례에 대한 연습 및 모범 사례:

 

Guides

Learn best practices for developing with LangChain.

 

LangChain 개발 모범 사례를 알아보세요.

 

Ecosystem

LangChain is part of a rich ecosystem of tools that integrate with our framework and build on top of it. Check out our growing list of integrations and dependent repos.

 

LangChain은 우리의 프레임워크와 통합되고 그 위에 구축되는 풍부한 도구 생태계의 일부입니다. 점점 늘어나는 통합 및 종속 저장소 목록을 확인하세요.

 

Additional resources

Our community is full of prolific developers, creative builders, and fantastic teachers. Check out YouTube tutorials for great tutorials from folks in the community, and Gallery for a list of awesome LangChain projects, compiled by the folks at KyroLabs.

 

우리 커뮤니티는 활발한 개발자, 창의적인 개발자, 환상적인 교사로 가득 차 있습니다. YouTube 튜토리얼에서 커뮤니티 사람들의 훌륭한 튜토리얼을 확인하고 갤러리에서 KyroLabs 사람들이 편집한 멋진 LangChain 프로젝트 목록을 확인하세요.

 

Community

Head to the Community navigator to find places to ask questions, share feedback, meet other developers, and dream about the future of LLM’s.

 

커뮤니티 탐색기로 이동하여 질문하고, 피드백을 공유하고, 다른 개발자를 만나고, LLM의 미래에 대해 꿈꿀 수 있는 장소를 찾으세요.

 

API refer

Head to the reference section for full documentation of all classes and methods in the LangChain Python package.

 

LangChain Python 패키지의 모든 클래스와 메서드에 대한 전체 문서를 보려면 참조 섹션으로 이동하세요.

 

 

 

 

 

 

 

반응형

'LangChain > Get Started' 카테고리의 다른 글

LangChain - Quickstart  (1) 2023.10.20
LangChain - Installation  (0) 2023.10.20


반응형

https://d2l.ai/chapter_preliminaries/lookup-api.html

 

2.7. Documentation — Dive into Deep Learning 1.0.3 documentation

 

d2l.ai

 

2.7. Documentation

 

While we cannot possibly introduce every single PyTorch function and class (and the information might become outdated quickly), the API documentation and additional tutorials and examples provide such documentation. This section provides some guidance for how to explore the PyTorch API.

 

PyTorch의 모든 기능과 클래스를 모두 소개할 수는 없지만(정보가 빨리 구식이 될 수 있음) API 문서와 추가 튜토리얼 및 예제에서 이러한 문서를 제공합니다. 이 섹션에서는 PyTorch API를 탐색하는 방법에 대한 몇 가지 지침을 제공합니다.

 

import torch

 

2.7.1. Functions and Classes in a Module

 

To know which functions and classes can be called in a module, we invoke the dir function. For instance, we can query all properties in the module for generating random numbers:

 

모듈에서 어떤 함수와 클래스를 호출할 수 있는지 알기 위해 dir 함수를 호출합니다. 예를 들어 난수 생성을 위해 모듈의 모든 속성을 쿼리할 수 있습니다.

 

print(dir(torch.distributions))

주어진 코드는 PyTorch에서 확률 분포와 관련된 클래스와 함수를 탐색하기 위해 사용되는 코드입니다. 코드는 PyTorch의 torch 라이브러리를 사용하며, torch.Distributions 모듈 아래에 있는 클래스와 함수를 나열합니다. 아래는 코드의 설명입니다:

  1. import torch: PyTorch 라이브러리를 임포트합니다. PyTorch는 딥 러닝 및 확률적 모델링을 위한 라이브러리로 널리 사용됩니다.
  2. print(dir(torch.Distributions)): torch.Distributions 모듈 아래에 있는 클래스와 함수를 나열하고 출력합니다. 이 명령은 해당 모듈에 포함된 모든 객체 및 함수의 이름을 보여줍니다. 이를 통해 PyTorch에서 제공하는 확률 분포와 관련된 클래스와 함수의 리스트를 확인할 수 있습니다.

PyTorch의 torch.Distributions 모듈에는 다양한 확률 분포를 다루는 클래스와 함수가 포함되어 있으며, 이러한 분포를 사용하여 확률적 모델링을 수행할 수 있습니다. 이 코드를 실행하면 해당 모듈의 내용을 확인할 수 있으며, 확률 분포와 관련된 작업을 수행할 때 유용한 클래스와 함수를 찾을 수 있습니다.

['AbsTransform', 'AffineTransform', 'Bernoulli', 'Beta', 'Binomial', 'CatTransform', 'Categorical', 'Cauchy', 'Chi2', 'ComposeTransform', 'ContinuousBernoulli', 'CorrCholeskyTransform', 'CumulativeDistributionTransform', 'Dirichlet', 'Distribution', 'ExpTransform', 'Exponential', 'ExponentialFamily', 'FisherSnedecor', 'Gamma', 'Geometric', 'Gumbel', 'HalfCauchy', 'HalfNormal', 'Independent', 'IndependentTransform', 'Kumaraswamy', 'LKJCholesky', 'Laplace', 'LogNormal', 'LogisticNormal', 'LowRankMultivariateNormal', 'LowerCholeskyTransform', 'MixtureSameFamily', 'Multinomial', 'MultivariateNormal', 'NegativeBinomial', 'Normal', 'OneHotCategorical', 'OneHotCategoricalStraightThrough', 'Pareto', 'Poisson', 'PositiveDefiniteTransform', 'PowerTransform', 'RelaxedBernoulli', 'RelaxedOneHotCategorical', 'ReshapeTransform', 'SigmoidTransform', 'SoftmaxTransform', 'SoftplusTransform', 'StackTransform', 'StickBreakingTransform', 'StudentT', 'TanhTransform', 'Transform', 'TransformedDistribution', 'Uniform', 'VonMises', 'Weibull', 'Wishart', '__all__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__', 'bernoulli', 'beta', 'biject_to', 'binomial', 'categorical', 'cauchy', 'chi2', 'constraint_registry', 'constraints', 'continuous_bernoulli', 'dirichlet', 'distribution', 'exp_family', 'exponential', 'fishersnedecor', 'gamma', 'geometric', 'gumbel', 'half_cauchy', 'half_normal', 'identity_transform', 'independent', 'kl', 'kl_divergence', 'kumaraswamy', 'laplace', 'lkj_cholesky', 'log_normal', 'logistic_normal', 'lowrank_multivariate_normal', 'mixture_same_family', 'multinomial', 'multivariate_normal', 'negative_binomial', 'normal', 'one_hot_categorical', 'pareto', 'poisson', 'register_kl', 'relaxed_bernoulli', 'relaxed_categorical', 'studentT', 'transform_to', 'transformed_distribution', 'transforms', 'uniform', 'utils', 'von_mises', 'weibull', 'wishart']

 

Generally, we can ignore functions that start and end with __ (special objects in Python) or functions that start with a single _(usually internal functions). Based on the remaining function or attribute names, we might hazard a guess that this module offers various methods for generating random numbers, including sampling from the uniform distribution (uniform), normal distribution (normal), and multinomial distribution (multinomial).

 

일반적으로 __(파이썬의 특수 객체)로 시작하고 끝나는 함수나 단일 _(일반적으로 내부 함수)로 시작하는 함수를 무시할 수 있습니다. 나머지 함수 또는 속성 이름을 기반으로 이 모듈이 균일 분포(균일), 정규 분포(정규) 및 다항 분포(다항)로부터의 샘플링을 포함하여 난수를 생성하는 다양한 방법을 제공한다고 추측할 수 있습니다.

 

2.7.2. Specific Functions and Classes

 

For specific instructions on how to use a given function or class, we can invoke the help function. As an example, let’s explore the usage instructions for tensors’ ones function.

 

주어진 함수나 클래스를 사용하는 방법에 대한 구체적인 지침을 보려면 도움말 함수를 호출할 수 있습니다. 예를 들어, 텐서의 함수에 대한 사용 지침을 살펴보겠습니다.

 

help(torch.ones)

주어진 코드는 PyTorch에서 torch.Ones 함수에 대한 도움말 문서를 출력하는 코드입니다. help() 함수는 파이썬 내장 함수로, 주어진 객체나 함수에 대한 도움말 문서를 출력합니다. 아래는 코드의 설명입니다:

  1. help(torch.Ones): 이 코드는 PyTorch의 torch.Ones 함수에 대한 도움말을 요청합니다. torch.Ones 함수는 텐서를 생성하며, 모든 요소가 1인 텐서를 생성합니다. 이 함수의 도움말 문서에는 함수의 사용법, 매개변수, 반환값 등에 대한 정보가 포함되어 있을 것입니다.

도움말 문서는 함수나 클래스의 사용법을 이해하고 해당 함수 또는 클래스를 효과적으로 활용하기 위해 유용한 정보를 제공합니다. PyTorch와 같은 라이브러리의 도움말 문서를 읽어보면 함수나 클래스의 매개변수와 반환값에 대한 이해를 높일 수 있으며, 코드를 개발하고 디버그하는 데 도움이 됩니다.

Help on built-in function ones in module torch:

ones(...)
    ones(*size, *, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False) -> Tensor
    
    Returns a tensor filled with the scalar value `1`, with the shape defined
    by the variable argument :attr:`size`.
    
    Args:
        size (int...): a sequence of integers defining the shape of the output tensor.
            Can be a variable number of arguments or a collection like a list or tuple.
    
    Keyword arguments:
        out (Tensor, optional): the output tensor.
        dtype (:class:`torch.dtype`, optional): the desired data type of returned tensor.
            Default: if ``None``, uses a global default (see :func:`torch.set_default_tensor_type`).
        layout (:class:`torch.layout`, optional): the desired layout of returned Tensor.
            Default: ``torch.strided``.
        device (:class:`torch.device`, optional): the desired device of returned tensor.
            Default: if ``None``, uses the current device for the default tensor type
            (see :func:`torch.set_default_tensor_type`). :attr:`device` will be the CPU
            for CPU tensor types and the current CUDA device for CUDA tensor types.
        requires_grad (bool, optional): If autograd should record operations on the
            returned tensor. Default: ``False``.
    
    Example::
    
        >>> torch.ones(2, 3)
        tensor([[ 1.,  1.,  1.],
                [ 1.,  1.,  1.]])
    
        >>> torch.ones(5)
        tensor([ 1.,  1.,  1.,  1.,  1.])

 

From the documentation, we can see that the ones function creates a new tensor with the specified shape and sets all the elements to the value of 1. Whenever possible, you should run a quick test to confirm your interpretation:

 

문서에서 ones 함수가 지정된 모양을 가진 새 텐서를 생성하고 모든 요소를 1의 값으로 설정하는 것을 볼 수 있습니다. 가능할 때마다 빠른 테스트를 실행하여 해석을 확인해야 합니다.

 

torch.ones(4)

주어진 코드는 PyTorch에서 torch.Ones(4)를 사용하여 모든 요소가 1로 초기화된 1차원 텐서를 생성하는 코드입니다. 아래는 코드의 설명입니다:

  1. torch.Ones(4): 이 코드는 PyTorch에서 torch.Ones 함수를 호출하여 4개의 요소로 구성된 1차원 텐서를 생성합니다. torch.Ones 함수는 모든 요소가 1로 초기화된 텐서를 생성하는 함수입니다. 따라서 이 코드는 길이가 4이고 모든 요소가 1로 초기화된 1차원 텐서를 생성합니다.

이렇게 생성된 텐서는 PyTorch를 사용하여 다양한 수치 연산을 수행하는 데 사용할 수 있으며, 데이터 처리 및 머신 러닝 작업에서 유용하게 활용될 수 있습니다.

tensor([1., 1., 1., 1.])

 

In the Jupyter notebook, we can use ? to display the document in another window. For example, list? will create content that is almost identical to help(list), displaying it in a new browser window. In addition, if we use two question marks, such as list??, the Python code implementing the function will also be displayed.

 

Jupyter 노트북에서는? 문서를 다른 창에 표시하려면 예를 들어 목록? help(list)와 거의 동일한 콘텐츠를 생성하여 새 브라우저 창에 표시합니다. 또한 list??와 같은 물음표 두 개를 사용하면 해당 함수를 구현하는 Python 코드도 표시됩니다.

 

 

The official documentation provides plenty of descriptions and examples that are beyond this book. We emphasize important use cases that will get you started quickly with practical problems, rather than completeness of coverage. We also encourage you to study the source code of the libraries to see examples of high-quality implementations of production code. By doing this you will become a better engineer in addition to becoming a better scientist.

 

공식 문서는 이 책보다 더 많은 설명과 예제를 제공합니다. 우리는 적용 범위의 완전성보다는 실제 문제를 빠르게 시작할 수 있는 중요한 사용 사례를 강조합니다. 또한 프로덕션 코드의 고품질 구현 예를 보려면 라이브러리의 소스 코드를 연구하는 것이 좋습니다. 이렇게 함으로써 당신은 더 나은 과학자가 될 뿐만 아니라 더 나은 엔지니어가 될 것입니다.

 

 

 

 

 

 

 

 

반응형


반응형

https://d2l.ai/chapter_preliminaries/probability.html

 

2.6. Probability and Statistics — Dive into Deep Learning 1.0.3 documentation

 

d2l.ai

2.6. Probability and Statistics

 

One way or another, machine learning is all about uncertainty. In supervised learning, we want to predict something unknown (the target) given something known (the features). Depending on our objective, we might attempt to predict the most likely value of the target. Or we might predict the value with the smallest expected distance from the target. And sometimes we wish not only to predict a specific value but to quantify our uncertainty. For example, given some features describing a patient, we might want to know how likely they are to suffer a heart attack in the next year. In unsupervised learning, we often care about uncertainty. To determine whether a set of measurements are anomalous, it helps to know how likely one is to observe values in a population of interest. Furthermore, in reinforcement learning, we wish to develop agents that act intelligently in various environments. This requires reasoning about how an environment might be expected to change and what rewards one might expect to encounter in response to each of the available actions.

 

어떤 식으로든 머신러닝은 불확실성에 관한 것입니다. 지도 학습 supervised learning 에서는 알려진 것(특성)을 고려하여 알려지지 않은 것(목표)을 예측하려고 합니다. 목표에 따라 목표의 가장 가능성 있는 값을 예측하려고 시도할 수도 있습니다. 또는 대상으로부터 예상되는 거리가 가장 작은 값을 예측할 수도 있습니다. 때로는 특정 값을 예측하는 것뿐만 아니라 불확실성을 정량화하고 싶을 때도 있습니다. 예를 들어, 환자를 설명하는 일부 특징이 주어지면 해당 환자가 내년에 심장마비를 겪을 가능성이 얼마나 되는지 알고 싶을 수 있습니다. 비지도 학습 unsupervised learning 에서는 종종 불확실성에 관심을 갖습니다. 일련의 측정값이 비정상적인지 여부를 확인하려면 관심 모집단에서 값을 관찰할 가능성이 얼마나 되는지 아는 것이 도움이 됩니다. 또한 강화학습 reinforcement learning 에서는 다양한 환경에서 지능적으로 행동하는 에이전트를 개발하고자 합니다. 이를 위해서는 환경이 어떻게 변할 것으로 예상되는지, 그리고 사용 가능한 각 조치에 대한 응답으로 어떤 보상을 받을 수 있는지에 대한 추론이 필요합니다.

 

Probability is the mathematical field concerned with reasoning under uncertainty. Given a probabilistic model of some process, we can reason about the likelihood of various events. The use of probabilities to describe the frequencies of repeatable events (like coin tosses) is fairly uncontroversial. In fact, frequentist scholars adhere to an interpretation of probability that applies only to such repeatable events. By contrast Bayesian scholars use the language of probability more broadly to formalize reasoning under uncertainty. Bayesian probability is characterized by two unique features: (i) assigning degrees of belief to non-repeatable events, e.g., what is the probability that a dam will collapse?; and (ii) subjectivity. While Bayesian probability provides unambiguous rules for how one should update their beliefs in light of new evidence, it allows for different individuals to start off with different prior beliefs. Statistics helps us to reason backwards, starting off with collection and organization of data and backing out to what inferences we might draw about the process that generated the data. Whenever we analyze a dataset, hunting for patterns that we hope might characterize a broader population, we are employing statistical thinking. Many courses, majors, theses, careers, departments, companies, and institutions have been devoted to the study of probability and statistics. While this section only scratches the surface, we will provide the foundation that you need to begin building models.

 

확률 Probability  은 불확실성 하에서 추론과 관련된 수학적 분야입니다. 일부 프로세스의 확률적 모델이 주어지면 다양한 이벤트가 발생할 가능성에 대해 추론할 수 있습니다. 반복 가능한 사건(예: 동전 던지기)의 빈도를 설명하기 위해 확률을 사용하는 것은 논란의 여지가 없습니다. 사실, 빈도주의 학자들은 그러한 반복 가능한 사건에만 적용되는 확률의 해석을 고수합니다. 대조적으로 베이지안 학자들은 불확실성 하에서 추론을 공식화하기 위해 확률이라는 언어를 보다 광범위하게 사용합니다. 베이지안 확률은 두 가지 고유한 특징이 특징입니다. (i) 반복 불가능한 사건에 대한 신뢰도 할당(예: 댐이 붕괴할 확률은 얼마입니까?) (ii) 주관성. 베이지안 확률은 새로운 증거에 비추어 자신의 믿음을 업데이트하는 방법에 대한 명확한 규칙을 제공하지만, 개인마다 다른 이전 믿음으로 시작할 수 있습니다. 통계는 데이터 수집 및 구성부터 시작하여 데이터를 생성한 프로세스에 대해 어떤 추론을 이끌어낼 수 있는지 역으로 추론하는 데 도움이 됩니다. 우리는 데이터 세트를 분석하고 더 광범위한 인구를 특징짓는 패턴을 찾을 때마다 통계적 사고를 사용합니다. 많은 과정, 전공, 논문, 경력, 학과, 회사 및 기관에서 확률과 통계 연구에 전념해 왔습니다. 이 섹션에서는 표면적인 내용만 다루지만 모델 구축을 시작하는 데 필요한 기초를 제공합니다.

 

https://youtu.be/SoKjCUcDBf0?si=M5wjpR8J_O7w3Lai 

 

%matplotlib inline
import random
import torch
from torch.distributions.multinomial import Multinomial
from d2l import torch as d2l

이 코드는 다음 작업을 수행하기 위해 필요한 라이브러리 및 설정을 가져오고 있습니다:

  1. %matplotlib inline: 이는 IPython 환경에서 Matplotlib를 사용하여 그래프 및 이미지를 노트북에 직접 표시하도록 설정합니다. 즉, 그래프를 노트북 내에서 바로 볼 수 있도록 합니다.
  2. random: Python의 기본 모듈로서, 무작위 수를 생성하는 데 사용됩니다.
  3. torch: PyTorch 라이브러리입니다. 딥러닝 작업을 수행하는 데 사용됩니다.
  4. Multinomial: PyTorch에서 제공하는 분포 클래스 중 하나인 다항 분포(Multinomial distribution)에 대한 모듈입니다. 다항 분포는 여러 범주 중 하나를 샘플링하는 확률 모델을 나타냅니다.
  5. d2l: "Dive into Deep Learning" 프로젝트의 PyTorch 버전인 d2l(torch) 라이브러리입니다. 딥러닝 모델을 학습하고 시각화하는 데 도움이 되는 기능과 도구를 제공합니다.

이 코드는 딥러닝 모델을 구축하고 실험하기 위한 환경을 설정하는 데 사용될 수 있습니다.

 

2.6.1. A Simple Example: Tossing Coins

Imagine that we plan to toss a coin and want to quantify how likely we are to see heads (vs. tails). If the coin is fair, then both outcomes (heads and tails), are equally likely. Moreover if we plan to toss the coin n times then the fraction of heads that we expect to see should exactly match the expected fraction of tails. One intuitive way to see this is by symmetry: for every possible outcome with nh heads and nt=(n−nh) tails, there is an equally likely outcome with nt heads and nh tails. Note that this is only possible if on average we expect to see 1/2 of tosses come up heads and 1/2 come up tails. Of course, if you conduct this experiment many times with n=1000000 tosses each, you might never see a trial where nh=nt exactly.

 

우리가 동전을 던질 계획을 세우고 앞면과 뒷면이 나올 확률을 정량화하고 싶다고 가정해 보세요. 동전이 공정하다면 두 가지 결과(앞면과 뒷면)의 확률은 동일합니다. 더욱이 동전을 n번 던질 계획이라면 우리가 볼 것으로 예상되는 앞면의 비율은 예상되는 뒷면의 비율과 정확히 일치해야 합니다. 이것을 보는 한 가지 직관적인 방법은 대칭을 이용하는 것입니다. nh개의 앞면과 nt=(n−nh)개의 꼬리가 있는 모든 가능한 결과에 대해 nt개의 앞면과 nh개의 꼬리가 있는 동일한 가능성의 결과가 있습니다. 이것은 평균적으로 던진 숫자 중 1/2이 앞면이 나오고 1/2이 뒷면이 나올 것으로 예상하는 경우에만 가능합니다. 물론 n=1000000번 던지기로 이 실험을 여러 번 수행하면 정확히 nh=nt인 실험을 결코 볼 수 없을 수도 있습니다.

 

Formally, the quantity 1/2 is called a probability and here it captures the certainty with which any given toss will come up heads. Probabilities assign scores between 0 and 1 to outcomes of interest, called events. Here the event of interest is heads and we denote the corresponding probability P(heads). A probability of 1 indicates absolute certainty (imagine a trick coin where both sides were heads) and a probability of 0 indicates impossibility (e.g., if both sides were tails). The frequencies nh/n and nt/n are not probabilities but rather statistics. Probabilities are theoretical quantities that underly the data generating process. Here, the probability 1/2 is a property of the coin itself. By contrast, statistics are empirical quantities that are computed as functions of the observed data. Our interests in probabilistic and statistical quantities are inextricably intertwined. We often design special statistics called estimators that, given a dataset, produce estimates of model parameters such as probabilities. Moreover, when those estimators satisfy a nice property called consistency, our estimates will converge to the corresponding probability. In turn, these inferred probabilities tell about the likely statistical properties of data from the same population that we might encounter in the future.

 

공식적으로 1/2이라는 수량을 확률이라고 하며 여기서는 주어진 던지기에서 앞면이 나올 확실성을 포착합니다. 확률은 이벤트라고 하는 관심 결과에 0과 1 사이의 점수를 할당합니다. 여기서 관심 있는 이벤트는 앞면이고 해당 확률 P(앞면)를 나타냅니다. 확률 1은 절대적 확실성(양쪽이 앞면인 트릭 코인을 상상해 보세요)을 나타내고 확률 0은 불가능함(예: 양쪽이 뒷면인 경우)을 나타냅니다. 빈도 nh/n 및 nt/n은 확률이 아니라 통계입니다. 확률은 데이터 생성 프로세스의 기초가 되는 이론적 수량입니다. 여기서 확률 1/2은 코인 자체의 속성입니다. 대조적으로, 통계는 관찰된 데이터의 함수로 계산되는 경험적 수량입니다. 확률적 수량과 통계적 수량에 대한 우리의 관심은 서로 밀접하게 얽혀 있습니다. 우리는 주어진 데이터 세트에서 확률과 같은 모델 매개변수의 추정치를 생성하는 추정기라는 특수 통계를 설계하는 경우가 많습니다. 또한 이러한 추정기가 일관성이라는 좋은 속성을 충족하면 추정치가 해당 확률로 수렴됩니다. 결과적으로 이러한 추론된 확률은 우리가 미래에 접할 수 있는 동일한 모집단의 데이터에 대한 통계적 속성에 대해 알려줍니다.

 

Suppose that we stumbled upon a real coin for which we did not know the true P(heads). To investigate this quantity with statistical methods, we need to (i) collect some data; and (ii) design an estimator. Data acquisition here is easy; we can toss the coin many times and record all the outcomes. Formally, drawing realizations from some underlying random process is called sampling. As you might have guessed, one natural estimator is the ratio of the number of observed heads to the total number of tosses.

 

우리가 실제 P(앞면)를 알지 못하는 실제 동전을 우연히 발견했다고 가정해 보십시오. 통계적 방법으로 이 수량을 조사하려면 (i) 일부 데이터를 수집해야 합니다. (ii) 추정기를 설계합니다. 여기서 데이터 수집은 쉽습니다. 동전을 여러 번 던지고 모든 결과를 기록할 수 있습니다. 공식적으로는 일부 기본 무작위 프로세스에서 구현한 그림을 샘플링이라고 합니다. 짐작할 수 있듯이 자연 추정량 중 하나는 총 던지기 횟수에 대한 관찰된 앞면 숫자의 비율입니다.

 

Now, suppose that the coin was in fact fair, i.e., P(heads)=0.5. To simulate tosses of a fair coin, we can invoke any random number generator. There are some easy ways to draw samples of an event with probability 0.5. For example Python’s random.random yields numbers in the interval [0,1] where the probability of lying in any sub-interval [a,b]⊂[0,1] is equal to b−a. Thus we can get out 0 and 1 with probability 0.5 each by testing whether the returned float number is greater than 0.5:

 

이제 동전이 실제로 공정했다고 가정합니다. 즉, P(heads)=0.5입니다. 공정한 동전 던지기를 시뮬레이션하기 위해 난수 생성기를 호출할 수 있습니다. 확률이 0.5인 사건의 샘플을 추출하는 몇 가지 쉬운 방법이 있습니다. 예를 들어 Python의 random.random은 하위 구간 [a,b]⊂[0,1]에 속할 확률이 b−a와 같은 구간 [0,1]의 숫자를 생성합니다. 따라서 반환된 부동 소수점 숫자가 0.5보다 큰지 테스트하여 각각 0.5 확률로 0과 1을 얻을 수 있습니다.

 

num_tosses = 100
heads = sum([random.random() > 0.5 for _ in range(num_tosses)])
tails = num_tosses - heads
print("heads, tails: ", [heads, tails])

이 코드는 동전 던지기 실험을 시뮬레이션하는 데 사용됩니다. 다음과 같이 동작합니다:

  1. num_tosses = 100: num_tosses라는 변수를 정의하고 100으로 설정합니다. 이는 동전을 100번 던지겠다는 것을 나타냅니다.
  2. heads = sum([random.random() > 0.5 for _ in range(num_tosses)]): heads 변수는 동전 던지기 실험에서 앞면(heads)이 나온 횟수를 나타냅니다. 리스트 내포(list comprehension)를 사용하여 0.5보다 큰 임의의 숫자(0~1 범위)를 100번 생성하고, 이 숫자가 0.5보다 크면(True인 경우), random.random() > 0.5는 1(참)이 됩니다. 그리고 sum() 함수를 사용하여 1의 개수를 세어 앞면(heads) 횟수를 계산합니다.
  3. tails = num_tosses - heads: tails 변수는 동전 던지기 실험에서 뒷면(tails)이 나온 횟수를 나타냅니다. 전체 던진 횟수(num_tosses)에서 앞면(heads) 횟수를 뺌으로써 얻습니다.
  4. print("heads, tails: ", [heads, tails]): 앞면(heads) 횟수와 뒷면(tails) 횟수를 출력합니다.

이 코드는 무작위로 동전을 100번 던진 후 앞면(heads)과 뒷면(tails)이 나오는 횟수를 계산하고 출력합니다. 결과는 매번 다를 수 있으며, 대략적으로 동전 던지기의 확률을 시뮬레이션합니다.

 

heads, tails:  [44, 56]

 

More generally, we can simulate multiple draws from any variable with a finite number of possible outcomes (like the toss of a coin or roll of a die) by calling the multinomial function, setting the first argument to the number of draws and the second as a list of probabilities associated with each of the possible outcomes. To simulate ten tosses of a fair coin, we assign probability vector [0.5, 0.5], interpreting index 0 as heads and index 1 as tails. The function returns a vector with length equal to the number of possible outcomes (here, 2), where the first component tells us the number of occurrences of heads and the second component tells us the number of occurrences of tails.

 

보다 일반적으로, 다항 함수를 호출하고 첫 번째 인수를 무승부 횟수로 설정하고 두 번째 인수를 가능한 각 결과와 관련된 확률 목록입니다. 공정한 동전 던지기 10회를 시뮬레이션하기 위해 확률 벡터 [0.5, 0.5]를 할당하여 인덱스 0을 앞면으로 해석하고 인덱스 1을 뒷면으로 해석합니다. 이 함수는 가능한 결과 수(여기서는 2)와 동일한 길이의 벡터를 반환합니다. 여기서 첫 번째 구성 요소는 앞면이 나타나는 횟수를 나타내고 두 번째 구성 요소는 꼬리가 나타나는 횟수를 알려줍니다.

 

fair_probs = torch.tensor([0.5, 0.5])
Multinomial(100, fair_probs).sample()
  1. 이 코드는 다수의 동전 던지기 실험을 시뮬레이션하는 데 사용됩니다. 코드를 간단히 설명하겠습니다:
    1. fair_probs = torch.tensor([0.5, 0.5]): fair_probs는 각 동전이 앞면(heads) 또는 뒷면(tails)을 나올 확률을 나타내는 텐서입니다. 여기서 [0.5, 0.5]는 공평한(fair) 동전을 나타내며, 앞면과 뒷면이 나올 확률이 각각 50%입니다.
    2. Multinomial(100, fair_probs): 이 부분은 Multinomial 분포에서 무작위 표본(sample)을 생성하는데 사용됩니다. 100은 시행 횟수, fair_probs는 각 결과(앞면 또는 뒷면)가 나올 확률을 나타내는 확률 분포입니다.
    3. .sample(): 이 메서드는 Multinomial 분포를 따르는 난수 생성을 수행합니다. 여기서는 100번의 동전 던지기 시뮬레이션을 수행하며, 각 시행에서 앞면 또는 뒷면이 나오는 횟수를 반환합니다.
    결과로 나오는 텐서는 [heads_count, tails_count]와 같은 형태를 가지며, heads_count는 앞면이 나온 횟수, tails_count는 뒷면이 나온 횟수를 나타냅니다. 위의 fair_probs에서는 공평한 동전을 사용했으므로, heads_count와 tails_count는 대략적으로 50, 50이 될 것입니다.하지만 시뮬레이션 결과는 무작위성에 의해 실제로는 다를 수 있습니다.
tensor([50., 50.])

 

Each time you run this sampling process, you will receive a new random value that may differ from the previous outcome. Dividing by the number of tosses gives us the frequency of each outcome in our data. Note that these frequencies, just like the probabilities that they are intended to estimate, sum to 1.

 

이 샘플링 프로세스를 실행할 때마다 이전 결과와 다를 수 있는 새로운 임의 값을 받게 됩니다. 던지는 횟수로 나누면 데이터의 각 결과 빈도를 알 수 있습니다. 추정하려는 확률과 마찬가지로 이러한 빈도의 합은 1이 됩니다.

 

Multinomial(100, fair_probs).sample() / 100

이 코드는 앞면(heads)과 뒷면(tails)이 나오는 확률이 0.5로 동일한 공평한 동전을 100번 던진 후에 각 결과의 상대 빈도를 계산합니다. 코드를 설명하겠습니다.

  1. Multinomial(100, fair_probs): 이 부분은 Multinomial 분포에서 100번의 시행을 수행하여 무작위로 결과를 샘플링합니다. 100은 시행 횟수이고, fair_probs는 각 결과(앞면 또는 뒷면)가 나올 확률을 나타내는 확률 분포입니다.
  2. .sample(): 이 메서드는 Multinomial 분포를 따르는 난수 생성을 수행합니다. 따라서 이 부분의 결과는 [heads_count, tails_count]와 같은 형태의 텐서로, heads_count는 앞면이 나오는 횟수, tails_count는 뒷면이 나오는 횟수를 나타냅니다.
  3. / 100: 여기서 나눗셈 연산을 수행하여 각 결과의 상대적인 빈도를 계산합니다. 각 결과(앞면 또는 뒷면)의 횟수를 100으로 나누면 각 결과가 나오는 상대적인 확률을 얻을 수 있습니다. 이 결과는 공평한 동전에서 앞면 또는 뒷면이 나올 확률에 가까워질 것이며, 대략적으로 [0.5, 0.5]가 될 것입니다.

즉, 이 코드는 공평한 동전 던지기 실험을 100번 수행하여 앞면과 뒷면의 상대적인 빈도(확률)를 계산합니다.

tensor([0.4800, 0.5200])

Here, even though our simulated coin is fair (we ourselves set the probabilities [0.5, 0.5]), the counts of heads and tails may not be identical. That is because we only drew a relatively small number of samples. If we did not implement the simulation ourselves, and only saw the outcome, how would we know if the coin were slightly unfair or if the possible deviation from 1/2 was just an artifact of the small sample size? Let’s see what happens when we simulate 10,000 tosses.

 

여기서, 시뮬레이션된 코인이 공정하더라도(우리가 직접 확률 [0.5, 0.5] 설정) 앞면과 뒷면의 개수가 동일하지 않을 수 있습니다. 그 이유는 상대적으로 적은 수의 샘플만 추출했기 때문입니다. 시뮬레이션을 직접 구현하지 않고 결과만 본다면 동전이 약간 불공평한지, 아니면 1/2에서 벗어날 수 있는 편차가 단지 작은 샘플 크기의 인공물인지 어떻게 알 수 있습니까? 10,000번의 던지기를 시뮬레이션하면 어떤 일이 일어나는지 살펴보겠습니다.

 

counts = Multinomial(10000, fair_probs).sample()
counts / 10000

이 코드는 공평한 동전을 10,000번 던지고, 그 결과를 사용하여 각 결과(앞면 또는 뒷면)의 상대적인 확률을 계산합니다. 코드를 단계별로 설명하겠습니다.

  1. Multinomial(10000, fair_probs): 이 부분은 Multinomial 분포에서 10,000번의 시행을 수행하여 무작위로 결과를 샘플링합니다. 10,000은 시행 횟수이고, fair_probs는 각 결과(앞면 또는 뒷면)가 나올 확률을 나타내는 확률 분포입니다. 이 부분에서는 10,000번의 독립적인 동전 던지기 시뮬레이션을 수행합니다.
  2. .sample(): 이 메서드는 Multinomial 분포를 따르는 난수 생성을 수행합니다. 따라서 이 부분의 결과는 [heads_count, tails_count]와 같은 형태의 텐서로, heads_count는 앞면이 나오는 횟수, tails_count는 뒷면이 나오는 횟수를 나타냅니다.
  3. / 10,000: 마지막으로, 각 결과(앞면 또는 뒷면)의 횟수를 10,000으로 나누면 각 결과가 나오는 상대적인 확률을 얻을 수 있습니다. 이 결과는 공평한 동전에서 앞면 또는 뒷면이 나오는 확률에 가까워질 것이며, 대략적으로 [0.5, 0.5]가 될 것입니다.

따라서 이 코드는 공평한 동전 던지기 실험을 10,000번 수행하여 앞면과 뒷면의 상대적인 빈도(확률)를 계산합니다.

tensor([0.4966, 0.5034])

 

In general, for averages of repeated events (like coin tosses), as the number of repetitions grows, our estimates are guaranteed to converge to the true underlying probabilities. The mathematical formulation of this phenomenon is called the law of large numbers and the central limit theorem tells us that in many situations, as the sample size n grows, these errors should go down at a rate of (1/√n). Let's get some more intuition by studying how our estimate evolves as we grow the number of tosses from 1 to 10,000.

 

일반적으로 반복되는 사건(예: 동전 던지기)의 평균의 경우 반복 횟수가 증가함에 따라 우리의 추정치는 실제 기본 확률로 수렴됩니다. 이 현상의 수학적 공식을 대수의 법칙이라고 하며 중심 극한 정리는 많은 상황에서 표본 크기 n이 커짐에 따라 이러한 오류가 (1/√n)의 비율로 감소해야 함을 알려줍니다. 던지기 횟수를 1회에서 10,000회까지 증가시키면서 추정치가 어떻게 변화하는지 연구하여 좀 더 직관력을 갖도록 합시다.

 

counts = Multinomial(1, fair_probs).sample((10000,))
cum_counts = counts.cumsum(dim=0)
estimates = cum_counts / cum_counts.sum(dim=1, keepdims=True)
estimates = estimates.numpy()

d2l.set_figsize((4.5, 3.5))
d2l.plt.plot(estimates[:, 0], label=("P(coin=heads)"))
d2l.plt.plot(estimates[:, 1], label=("P(coin=tails)"))
d2l.plt.axhline(y=0.5, color='black', linestyle='dashed')
d2l.plt.gca().set_xlabel('Samples')
d2l.plt.gca().set_ylabel('Estimated probability')
d2l.plt.legend();

 

이 코드는 공평한 동전 던지기 실험에서 상대적인 확률을 추정하고 그 추정치를 그래프로 표현하는 부분입니다.

  1. counts = Multinomial(1, fair_probs).sample((10000,)): 이 부분은 공평한 동전을 1번 던질 때, 앞면(coin=heads) 또는 뒷면(coin=tails)이 나오는 횟수를 10,000번 샘플링합니다. counts는 10,000번의 시뮬레이션 결과를 담고 있는 텐서입니다.
  2. cum_counts = counts.cumsum(dim=0): 누적 횟수(cumulative counts)를 계산합니다. 이것은 각 시뮬레이션 스텝에서 앞면과 뒷면의 상대적인 누적 횟수를 나타냅니다.
  3. estimates = cum_counts / cum_counts.sum(dim=1, keepdims=True): 이 부분에서는 누적 횟수를 누적 합으로 나눠 상대적인 확률을 계산합니다. 이것은 각 시뮬레이션 스텝에서 앞면과 뒷면의 상대적인 확률을 나타냅니다.
  4. estimates = estimates.numpy(): 계산된 확률 추정치를 NumPy 배열로 변환합니다.
  5. 그래프를 그리는 부분: 계산된 확률 추정치를 이용하여 앞면(coin=heads)과 뒷면(coin=tails)의 확률 변화를 그래프로 표현합니다. d2l.plt.plot(estimates[:, 0], label=("P(coin=heads)"))는 앞면의 확률을 나타내는 그래프를 그리고, d2l.plt.plot(estimates[:, 1], label=("P(coin=tails)"))는 뒷면의 확률을 나타내는 그래프를 그립니다. d2l.plt.axhline(y=0.5, color='black', linestyle='dashed')는 확률 0.5에 수평 점선을 추가합니다. 나머지 코드는 그래프의 레이블과 축 이름을 설정하고 범례를 추가합니다.

결과적으로 이 코드는 공평한 동전 던지기 실험에서 시뮬레이션된 결과를 기반으로 앞면과 뒷면의 확률을 추정하고, 그 추정치를 그래프로 시각화합니다. 동전 던지기 시뮬레이션 횟수가 증가함에 따라 추정치가 공평한 동전의 확률(0.5)로 수렴하는 것을 관찰할 수 있습니다.

 

 

 

 

Each solid curve corresponds to one of the two values of the coin and gives our estimated probability that the coin turns up that value after each group of experiments. The dashed black line gives the true underlying probability. As we get more data by conducting more experiments, the curves converge towards the true probability. You might already begin to see the shape of some of the more advanced questions that preoccupy statisticians: How quickly does this convergence happen? If we had already tested many coins manufactured at the same plant, how might we incorporate this information?

 

각 실선은 동전의 두 값 중 하나에 해당하며 각 실험 그룹 후에 동전이 해당 값을 나타낼 확률을 추정합니다. 검은 점선은 실제 기본 확률을 나타냅니다. 더 많은 실험을 수행하여 더 많은 데이터를 얻을수록 곡선은 실제 확률로 수렴됩니다. 통계학자들을 사로잡는 고급 질문 중 일부의 형태가 이미 보이기 시작했을 수도 있습니다. 이 수렴은 얼마나 빨리 발생합니까? 동일한 공장에서 제조된 많은 동전을 이미 테스트했다면 이 정보를 어떻게 통합할 수 있을까요?

 

2.6.2. A More Formal Treatment

We have already gotten pretty far: posing a probabilistic model, generating synthetic data, running a statistical estimator, empirically assessing convergence, and reporting error metrics (checking the deviation). However, to go much further, we will need to be more precise.

 

우리는 이미 확률 모델 제시, 합성 데이터 생성, 통계 추정기 실행, 경험적 수렴 평가, 오류 측정항목 보고(편차 확인) 등 꽤 많은 작업을 수행했습니다. 그러나 더 나아가려면 더 정확해야 합니다.

 

When dealing with randomness, we denote the set of possible outcomes S and call it the sample space or outcome space. Here, each element is a distinct possible outcome. In the case of rolling a single coin, S={heads,tails}. For a single die, S={1,2,3,4,5,6}. When flipping two coins, possible outcomes are {(heads,heads),(heads,tails),(tails,heads),(tails,tails)}. Events are subsets of the sample space. For instance, the event “the first coin toss comes up heads” corresponds to the set {(heads,heads),(heads,tails)}. Whenever the outcome z of a random experiment satisfies z∈A, then event A has occurred. For a single roll of a die, we could define the events “seeing a 5” (A={5}) and “seeing an odd number” (B={1,3,5}). In this case, if the die came up 5, we would say that both A and B occurred. On the other hand, if z=3, then A did not occur but B did.

 

무작위성을 다룰 때 가능한 결과 집합 S를 표시하고 이를 표본 공간 또는 결과 공간이라고 부릅니다. 여기서 각 요소는 서로 다른 가능한 결과입니다. 단일 동전을 굴리는 경우 S={heads,tails}입니다. 단일 주사위의 경우 S={1,2,3,4,5,6}입니다. 두 개의 동전을 뒤집을 때 가능한 결과는 {(앞면, 앞면),(앞면,뒷면),(뒷면,앞면),(뒷면,뒷면)}입니다. 사건은 표본 공간의 부분 집합입니다. 예를 들어, "첫 번째 동전 던지기에서 앞면이 나옵니다" 이벤트는 {(앞면, 앞면),(앞면, 뒷면)} 집합에 해당합니다. 무작위 실험의 결과 z가 z∈A를 충족할 때마다 사건 A가 발생합니다. 주사위를 한 번 굴릴 때 "5를 보는 것"(A={5})과 "홀수를 보는 것"(B={1,3,5}) 이벤트를 정의할 수 있습니다. 이 경우 주사위가 5가 나오면 A와 B가 모두 발생했다고 말할 수 있습니다. 반면, z=3이면 A는 발생하지 않았지만 B는 발생했습니다.

 

A probability function maps events onto real values P:A⊆S→[0,1]. The probability, denoted P(A), of an event A in the given sample space S, has the following properties:

 

확률 함수는 사건을 실제 값 P:A⊆S→[0,1]에 매핑합니다. 주어진 표본 공간 S에서 사건 A의 확률 P(A)는 다음과 같은 속성을 갖습니다.

  • The probability of any event A is a nonnegative real number, i.e., P(A)≥0;
  • 어떤 사건 A의 확률은 음이 아닌 실수입니다. 즉, P(A)≥0입니다.
  • The probability of the entire sample space is 1, i.e., P(S)=1;
  • 전체 표본 공간의 확률은 1입니다. 즉, P(S)=1입니다.
  • For any countable sequence of events A1,A2,… that are mutually exclusive (i.e., Ai∩Aj=∅ for all i≠j), the probability that any of them happens is equal to the sum of their individual probabilities, i.e., P(⋃i=1 Ai)=∑i=1 P(Ai).
  • 상호 배타적인 사건 A1,A2,…의 셀 수 있는 시퀀스에 대해(즉, 모든 i≠j에 대해 Ai∩Aj=∅), 그 중 하나가 발생할 확률은 개별 확률의 합과 같습니다. 즉, P(⋃i=1 Ai)=∑i=1 P(Ai).

 

These axioms of probability theory, proposed by Kolmogorov (1933), can be applied to rapidly derive a number of important consequences. For instance, it follows immediately that the probability of any event A or its complement A′ occurring is 1 (because A∪A′=S). We can also prove that P(∅)=0 because 1=P(S∪S′)=P(S∪∅)=P(S)+P(∅)=1+P(∅). Consequently, the probability of any event A and its complement A occurring simultaneously is P(A∩A′)=0. Informally, this tells us that impossible events have zero probability of occurring.

 

Kolmogorov(1933)가 제안한 확률 이론의 이러한 공리는 여러 가지 중요한 결과를 신속하게 도출하는 데 적용될 수 있습니다. 예를 들어, 임의의 사건 A 또는 그 보수 A'가 발생할 확률은 1입니다(A∪A'=S이기 때문에). 1=P(S∪S′)=P(S∪∅)=P(S)+P(∅)=1+P(∅)이기 때문에 P(∅)=0임을 증명할 수도 있습니다. 결과적으로, 사건 A와 그 보수 A'가 동시에 발생할 확률은 P(A∩A')=0입니다. 비공식적으로 이는 불가능한 사건이 발생할 확률이 0이라는 것을 알려줍니다.

 

2.6.3. Random Variables

 

When we spoke about events like the roll of a die coming up odds or the first coin toss coming up heads, we were invoking the idea of a random variable. Formally, random variables are mappings from an underlying sample space to a set of (possibly many) values. You might wonder how a random variable is different from the sample space, since both are collections of outcomes. Importantly, random variables can be much coarser than the raw sample space. We can define a binary random variable like “greater than 0.5” even when the underlying sample space is infinite, e.g., points on the line segment between 0 and 1. Additionally, multiple random variables can share the same underlying sample space. For example “whether my home alarm goes off” and “whether my house was burgled” are both binary random variables that share an underlying sample space. Consequently, knowing the value taken by one random variable can tell us something about the likely value of another random variable. Knowing that the alarm went off, we might suspect that the house was likely burgled.

 

주사위를 굴려 앞면이 나올 확률이나 첫 번째 동전 던지기에서 앞면이 나올 때와 같은 사건에 대해 이야기할 때 우리는 무작위 변수라는 아이디어를 떠올렸습니다. 공식적으로 확률 변수는 기본 표본 공간에서 (아마도 많은) 값 세트로의 매핑입니다. 둘 다 결과 모음이기 때문에 확률 변수가 표본 공간과 어떻게 다른지 궁금할 것입니다. 중요한 것은 확률 변수가 원시 표본 공간보다 훨씬 더 거칠 수 있다는 것입니다. 기본 표본 공간이 무한하더라도(예: 0과 1 사이 선분의 점) "0.5보다 큼"과 같은 이진 확률 변수를 정의할 수 있습니다. 또한 여러 확률 변수가 동일한 기본 표본 공간을 공유할 수 있습니다. 예를 들어 "내 집 알람이 울리는지 여부"와 "내 집에 도난이 발생했는지 여부"는 모두 기본 표본 공간을 공유하는 이진 무작위 변수입니다. 결과적으로, 하나의 무작위 변수가 취하는 값을 알면 다른 무작위 변수의 가능한 값에 대해 알 수 있습니다. 경보기가 울렸다는 것을 알면 집에 도둑이 들었을 가능성이 있다고 의심할 수 있습니다.

 

Every value taken by a random variable corresponds to a subset of the underlying sample space. Thus the occurrence where the random variable X takes value v, denoted by X=v, is an event and P(X=v) denotes its probability. Sometimes this notation can get clunky, and we can abuse notation when the context is clear. For example, we might use P(X) to refer broadly to the distribution of X, i.e., the function that tells us the probability that X takes any given value. Other times we write expressions like P(X,Y)=P(X)P(Y), as a shorthand to express a statement that is true for all of the values that the random variables X and Y can take, i.e., for all i,j it holds that P(X=i and Y=j)=P(X=i)P(Y=j). Other times, we abuse notation by writing P(v) when the random variable is clear from the context. Since an event in probability theory is a set of outcomes from the sample space, we can specify a range of values for a random variable to take. For example, P(1≤X≤3) denotes the probability of the event {1≤X≤3}.

 

무작위 변수가 취한 모든 값은 기본 표본 공간의 하위 집합에 해당합니다. 따라서 확률 변수 X가 X=v로 표시되는 값 v를 취하는 발생은 이벤트이고 P(X=v)는 해당 확률을 나타냅니다. 때로는 이 표기법이 투박해질 수 있으며, 문맥이 명확할 때 표기법을 남용할 수 있습니다. 예를 들어, P(X)를 사용하여 X의 분포, 즉 X가 주어진 값을 취할 확률을 알려주는 함수를 광범위하게 나타낼 수 있습니다. 다른 경우에는 확률 변수 X와 Y가 취할 수 있는 모든 값에 대해 참인 진술을 표현하기 위해 P(X,Y)=P(X)P(Y)와 같은 표현식을 작성합니다. 모든 i,j는 P(X=i and Y=j)=P(X=i)P(Y=j)를 유지합니다. 다른 경우에는 무작위 변수가 문맥에서 명확할 때 P(v)를 작성하여 표기법을 남용합니다. 확률 이론의 사건은 표본 공간의 결과 집합이므로 무작위 변수가 취할 값의 범위를 지정할 수 있습니다. 예를 들어 P(1<X<<3)은 사건 {1<<X<<3}의 확률을 나타냅니다.

 

Note that there is a subtle difference between discrete random variables, like flips of a coin or tosses of a die, and continuous ones, like the weight and the height of a person sampled at random from the population. In this case we seldom really care about someone’s exact height. Moreover, if we took precise enough measurements, we would find that no two people on the planet have the exact same height. In fact, with fine enough measurements, you would never have the same height when you wake up and when you go to sleep. There is little point in asking about the exact probability that someone is 1.801392782910287192 meters tall. Instead, we typically care more about being able to say whether someone’s height falls into a given interval, say between 1.79 and 1.81 meters. In these cases we work with probability densities. The height of exactly 1.80 meters has no probability, but nonzero density. To work out the probability assigned to an interval, we must take an integral of the density over that interval.

 

동전 던지기나 주사위 던지기와 같은 이산형 확률 변수와 모집단에서 무작위로 추출된 사람의 체중 및 키와 같은 연속 변수 사이에는 미묘한 차이가 있습니다. 이 경우 우리는 누군가의 정확한 키에 대해 거의 신경 쓰지 않습니다. 더욱이, 우리가 충분히 정확하게 측정한다면, 지구상에 정확히 같은 키를 가진 사람은 두 명도 없다는 것을 알게 될 것입니다. 사실, 충분히 세밀하게 측정하면 잠에서 깰 때와 잠에 들 때의 키가 결코 같지 않을 것입니다. 누군가의 키가 1.801392782910287192미터일 정확한 확률에 대해 묻는 것은 별 의미가 없습니다. 대신, 우리는 일반적으로 누군가의 키가 주어진 간격, 즉 1.79미터에서 1.81미터 사이에 속하는지 여부를 말할 수 있는지에 더 관심을 둡니다. 이 경우 우리는 확률 밀도를 사용하여 작업합니다. 정확히 1.80미터의 높이는 확률은 없지만 밀도는 0이 아닙니다. 구간에 할당된 확률을 계산하려면 해당 구간에 대한 밀도를 적분해야 합니다.

 

2.6.4. Multiple Random Variables

You might have noticed that we could not even make it through the previous section without making statements involving interactions among multiple random variables (recall P(X,Y)=P(X)P(Y)). Most of machine learning is concerned with such relationships. Here, the sample space would be the population of interest, say customers who transact with a business, photographs on the Internet, or proteins known to biologists. Each random variable would represent the (unknown) value of a different attribute. Whenever we sample an individual from the population, we observe a realization of each of the random variables. Because the values taken by random variables correspond to subsets of the sample space that could be overlapping, partially overlapping, or entirely disjoint, knowing the value taken by one random variable can cause us to update our beliefs about which values of another random variable are likely. If a patient walks into a hospital and we observe that they are having trouble breathing and have lost their sense of smell, then we believe that they are more likely to have COVID-19 than we might if they had no trouble breathing and a perfectly ordinary sense of smell.

 

여러 확률 변수 간의 상호 작용을 포함하는 진술을 작성하지 않고는 이전 섹션을 완료할 수도 없다는 점을 눈치챘을 것입니다(P(X,Y)=P(X)P(Y)를 기억하세요). 대부분의 기계 학습은 이러한 관계와 관련이 있습니다. 여기서 표본 공간은 관심 모집단, 즉 기업과 거래하는 고객, 인터넷 사진, 생물학자에게 알려진 단백질이 될 것입니다. 각 무작위 변수는 다른 속성의 (알 수 없는) 값을 나타냅니다. 모집단에서 개인을 샘플링할 때마다 각 무작위 변수가 실현되는 것을 관찰합니다. 무작위 변수가 취한 값은 중복되거나, 부분적으로 겹치거나, 완전히 분리될 수 있는 표본 공간의 하위 집합에 해당하기 때문에, 하나의 무작위 변수가 취한 값을 알면 다른 무작위 변수의 어떤 값이 가능성이 높은지에 대한 우리의 믿음을 업데이트할 수 있습니다. . 환자가 병원에 들어왔을 때 호흡 곤란을 겪고 후각을 잃은 것을 관찰하면, 우리는 호흡 곤란이 없고 완전히 평범한 후각이 있는 경우보다 코로나19에 걸릴 가능성이 더 높다고 믿습니다.

 

When working with multiple random variables, we can construct events corresponding to every combination of values that the variables can jointly take. The probability function that assigns probabilities to each of these combinations (e.g. A=a and B=b) is called the joint probability function and simply returns the probability assigned to the intersection of the corresponding subsets of the sample space. The joint probability assigned to the event where random variables A and B take values a and b, respectively, is denoted P(A=a,B=b), where the comma indicates “and”. Note that for any values a and b, it follows that

 

여러 확률 변수를 사용하여 작업할 때 변수가 공동으로 취할 수 있는 모든 값 조합에 해당하는 이벤트를 구성할 수 있습니다. 이러한 각 조합(예: A=a 및 B=b)에 확률을 할당하는 확률 함수를 결합 확률 함수라고 하며 단순히 표본 공간의 해당 하위 집합의 교차점에 할당된 확률을 반환합니다. 확률 변수 A와 B가 각각 a와 b 값을 갖는 사건에 할당된 결합 확률은 P(A=a,B=b)로 표시되며, 여기서 쉼표는 "and"를 나타냅니다. 임의의 값 a와 b에 대해 다음이 따른다는 점에 유의하십시오.

 

 

since for A=a and B=b to happen, A=a has to happen and B=b also has to happen. Interestingly, the joint probability tells us all that we can know about these random variables in a probabilistic sense, and can be used to derive many other useful quantities, including recovering the individual distributions P(A) and P(B). To recover P(A=a) we simply sum up P(A=a,B=v) over all values v that the random variable B can take: P(A=a)=∑vP(A=a,B=v).

 

A=a와 B=b가 발생하려면 A=a가 발생해야 하고 B=b도 발생해야 하기 때문입니다. 흥미롭게도 결합 확률은 우리가 확률적 의미에서 이러한 확률 변수에 대해 알 수 있는 모든 것을 알려주고 개별 분포 P(A) 및 P(B)를 복구하는 것을 포함하여 다른 많은 유용한 양을 도출하는 데 사용될 수 있습니다. P(A=a)를 복구하려면 모든 값 v에 대해 P(A=a,B=v)를 간단히 합산하면 됩니다.확률 변수 B는 P(A=a)=∑vP(A=a,B=v)를 취할 수 있습니다.

 

The ratio P(A=a,B=b)/P(A=a)≤1 turns out to be extremely important. It is called the conditional probability, and is denoted via the “” symbol:

 

P(A=a,B=b)/P(A=a)≤1 비율은 매우 중요합니다. 조건부 확률이라고 하며 "∣" 기호로 표시됩니다.

 

It tells us the new probability associated with the event B=b, once we condition on the fact A=a took place. We can think of this conditional probability as restricting attention only to the subset of the sample space associated with A=a and then renormalizing so that all probabilities sum to 1. Conditional probabilities are in fact just ordinary probabilities and thus respect all of the axioms, as long as we condition all terms on the same event and thus restrict attention to the same sample space. For instance, for disjoint events B and B, we have that P(B∪B′∣A=a)=P(B∣A=a)+P(B′∣A=a).

 

A=a가 발생했다는 사실을 조건으로 하면 사건 B=b와 관련된 새로운 확률을 알려줍니다. 이 조건부 확률은 A=a와 관련된 표본 공간의 하위 집합에만 주의를 제한하고 모든 확률의 합이 1이 되도록 재정규화하는 것으로 생각할 수 있습니다. 조건부 확률은 실제로 일반적인 확률이므로 모든 공리를 존중합니다. 모든 항을 동일한 사건에 대해 조건을 지정하여 동일한 표본 공간에 주의를 기울이는 한. 예를 들어, 분리된 사건 B와 B'에 대해 P(B∪B'∣A=a)=P(B∣A=a)+P(B'∣A=a)가 됩니다.

 

Using the definition of conditional probabilities, we can derive the famous result called Bayes’ theorem. By construction, we have that P(A,B)=P(B∣A)P(A) and P(A,B)=P(A∣B)P(B). Combining both equations yields P(B∣A)P(A) = P(A∣B)P(B) and hence

 

조건부 확률의 정의를 사용하면 베이즈 정리라는 유명한 결과를 도출할 수 있습니다. 구성에 따르면 P(A,B)=P(B∣A)P(A) 및 P(A,B)=P(A∣B)P(B)가 있습니다. 두 방정식을 결합하면 P(B∣A)P(A) = P(A∣B)P(B)가 생성되므로

 

 

Bayes' theorem 이란?

 

베이즈 정리(Bayes' theorem)는 확률 이론의 중요한 개념 중 하나로, 조건부 확률을 계산하는 데 사용됩니다. 이 정리는 머신 러닝, 통계학, 확률 이론, 생물학, 의학, 자연어 처리 및 다양한 분야에서 다양한 응용을 가지고 있습니다. 베이즈 정리는 역사적으로 영국의 수학자 토머스 베이즈(Thomas Bayes)의 이름을 따서 명명되었습니다.

 

베이즈 정리의 일반적인 형태는 다음과 같습니다:

 

P(A|B) = (P(B|A) * P(A)) / P(B)

 

여기서 각 요소의 의미는 다음과 같습니다:

  • P(A|B): 사건 B가 발생한 조건에서 사건 A가 발생할 확률, 즉 A의 조건부 확률.
  • P(B|A): 사건 A가 발생한 조건에서 사건 B가 발생할 확률, 즉 B의 조건부 확률.
  • P(A): 사건 A가 발생할 사전 확률.
  • P(B): 사건 B가 발생할 사전 확률.

베이즈 정리의 주요 아이디어는 조건부 확률을 계산할 때, 사전 확률과 관련 사건들 간의 확률을 사용하여 업데이트할 수 있다는 것입니다. 즉, 사건 B가 발생한 후에는 사건 A의 확률을 더 정확하게 추정할 수 있습니다.

 

베이즈 정리의 응용 분야 중 하나는 베이지안 통계(Bayesian statistics)입니다. 이 방법론은 불확실성을 다루는데 특히 유용하며, 사후 확률을 업데이트하고 불확실성을 줄이는 데 활용됩니다. 머신 러닝에서는 베이지안 모델링을 통해 다양한 문제를 해결하고 불확실성을 고려한 예측을 수행하는데 사용됩니다.

 

베이즈 정리는 많은 현실 세계의 문제를 다루는데 유용한 도구로, 사후 확률을 업데이트하고 불확실성을 처리하기 위해 다양한 분야에서 활발하게 사용됩니다.

 

This simple equation has profound implications because it allows us to reverse the order of conditioning. If we know how to estimate P(B∣A), P(A), and P(B), then we can estimate P(A∣B). We often find it easier to estimate one term directly but not the other and Bayes’ theorem can come to the rescue here. For instance, if we know the prevalence of symptoms for a given disease, and the overall prevalences of the disease and symptoms, respectively, we can determine how likely someone is to have the disease based on their symptoms. In some cases we might not have direct access to P(B), such as the prevalence of symptoms. In this case a simplified version of Bayes’ theorem comes in handy:

 

이 간단한 방정식은 조건화 순서를 뒤집을 수 있기 때문에 심오한 의미를 갖습니다. P(B∣A), P(A), P(B)를 추정하는 방법을 안다면 P(A∣B)를 추정할 수 있습니다. 우리는 종종 한 항을 직접 추정하는 것이 더 쉽지만 다른 항은 그렇지 않다는 것을 알게 되며 여기서 베이즈 정리가 도움이 될 수 있습니다. 예를 들어, 특정 질병에 대한 증상의 유병률과 질병 및 증상의 전반적인 유병률을 각각 안다면 증상을 기반으로 누군가가 질병에 걸릴 가능성이 얼마나 되는지 판단할 수 있습니다. 어떤 경우에는 증상의 유병률과 같이 P(B)에 직접 접근할 수 없을 수도 있습니다. 이 경우 베이즈 정리의 단순화된 버전이 유용합니다.

 

Since we know that P(A∣B) must be normalized to 1, i.e., aP(A=a∣B)=1, we can use it to compute

 

P(A∣B)가 1로 정규화되어야 함, 즉 ∑aP(A=a∣B)=1이라는 것을 알고 있으므로 이를 사용하여 계산할 수 있습니다.

 

 

In Bayesian statistics, we think of an observer as possessing some (subjective) prior beliefs about the plausibility of the available hypotheses encoded in the prior P(H), and a likelihood function that says how likely one is to observe any value of the collected evidence for each of the hypotheses in the class P(E∣H). Bayes’ theorem is then interpreted as telling us how to update the initial prior P(H) in light of the available evidence E to produce posterior beliefs P(H∣E) = P(E∣H)P(H)/P(E). Informally, this can be stated as “posterior equals prior times likelihood, divided by the evidence”. Now, because the evidence P(E) is the same for all hypotheses, we can get away with simply normalizing over the hypotheses.

 

베이지안 통계에서 우리는 관찰자가 사전 P(H)에 인코딩된 사용 가능한 가설의 타당성에 대한 일부 (주관적) 사전 신념과 수집된 값을 관찰할 가능성이 얼마나 되는지 알려주는 우도 함수를 보유하고 있다고 생각합니다. P(E∣H) 클래스의 각 가설에 대한 증거. 베이즈 정리는 사후 신념 P(H∣E) = P(E∣H)P(H)/P(E)를 생성하기 위해 이용 가능한 증거 E에 비추어 초기 사전 P(H)를 업데이트하는 방법을 알려주는 것으로 해석됩니다.  비공식적으로, 이는 "사후는 이전 가능성과 증거를 나눈 값과 동일합니다"라고 말할 수 있습니다. 이제 증거 P(E)는 모든 가설에 대해 동일하므로 단순히 가설에 대해 정규화하면 됩니다.

 

Note that aP(A=a∣B)=1 also allows us to marginalize over random variables. That is, we can drop variables from a joint distribution such as P(A,B). After all, we have that Independence is another fundamentally important concept that forms the backbone of many important ideas in statistics.

 

aP(A=a∣B)=1을 사용하면 무작위 변수를 소외시킬 수도 있습니다. 즉, P(A,B)와 같은 결합 분포에서 변수를 삭제할 수 있습니다. 결국 우리는 독립성이 통계학의 많은 중요한 아이디어의 중추를 형성하는 또 다른 근본적으로 중요한 개념이라는 것을 알고 있습니다.

 

 

In short, two variables are independent if conditioning on the value of A does not cause any change to the probability distribution associated with B and vice versa. More formally, independence, denoted A⊥B, requires that P(A∣B) = P(A) and, consequently, that P(A,B) = P(A∣B)P(B) = P(A)P(B). Independence is often an appropriate assumption. For example, if the random variable A represents the outcome from tossing one fair coin and the random variable B represents the outcome from tossing another, then knowing whether A came up heads should not influence the probability of B coming up heads.

 

간단히 말해서, A 값에 대한 조건이 B와 관련된 확률 분포에 어떠한 변화도 일으키지 않고 그 반대의 경우에도 두 변수는 독립적입니다. 보다 공식적으로, A⊥B로 표시되는 독립성은 P(A∣B) = P(A)를 요구하며 결과적으로 P(A,B) = P(A∣B)P(B) = P(A)를 충족해야 합니다. P(B). 독립성은 종종 적절한 가정입니다. 예를 들어, 확률 변수 A가 공정한 동전 하나를 던진 결과를 나타내고 확률 변수 B가 다른 동전을 던진 결과를 나타내는 경우 A가 앞면이 나오는지 여부를 아는 것이 B가 앞면이 나올 확률에 영향을 주어서는 안 됩니다.

 

Independence is especially useful when it holds among the successive draws of our data from some underlying distribution (allowing us to make strong statistical conclusions) or when it holds among various variables in our data, allowing us to work with simpler models that encode this independence structure. On the other hand, estimating the dependencies among random variables is often the very aim of learning. We care to estimate the probability of disease given symptoms specifically because we believe that diseases and symptoms are not independent.

 

독립성은 일부 기본 분포에서 데이터를 연속적으로 추출할 때(강력한 통계적 결론을 내릴 수 있음) 데이터의 다양한 변수 간에 유지될 때 특히 유용하며 이 독립성 구조를 인코딩하는 더 간단한 모델로 작업할 수 있습니다.  반면, 확률 변수 간의 종속성을 추정하는 것이 학습의 목적인 경우가 많습니다. 우리는 질병과 증상이 독립적이지 않다고 믿기 때문에 특정 증상에 따른 질병의 확률을 추정하는 데 관심을 둡니다.

 

Note that because conditional probabilities are proper probabilities, the concepts of independence and dependence also apply to them. Two random variables A and B are conditionally independent given a third variable C if and only if P(A,B∣C) = P(A∣C)P(B∣C). Interestingly, two variables can be independent in general but become dependent when conditioning on a third. This often occurs when the two random variables A and B correspond to causes of some third variable C. For example, broken bones and lung cancer might be independent in the general population but if we condition on being in the hospital then we might find that broken bones are negatively correlated with lung cancer. That is because the broken bone explains away why some person is in the hospital and thus lowers the probability that they are hospitalized because of having lung cancer.

 

조건부 확률은 고유 확률이므로 독립성과 종속성의 개념도 적용됩니다. 두 개의 확률 변수 A와 B는 P(A,B∣C) = P(A∣C)P(B∣C)인 경우에만 세 번째 변수 C가 주어지면 조건부 독립입니다. 흥미롭게도 두 변수는 일반적으로 독립적일 수 있지만 세 번째 변수에 조건을 적용하면 종속성이 됩니다. 이는 두 개의 무작위 변수 A와 B가 세 번째 변수 C의 원인에 해당할 때 자주 발생합니다. 예를 들어, 부러진 뼈와 폐암은 일반 인구 집단에서는 독립적일 수 있지만 병원에 입원하는 것을 조건으로 하면 뼈가 부러진 것을 발견할 수 있습니다. 뼈는 폐암과 음의 상관관계가 있습니다. 이는 부러진 뼈가 어떤 사람이 병원에 있는 이유를 설명하여 폐암으로 인해 입원할 가능성을 낮추기 때문입니다.

 

And conversely, two dependent random variables can become independent upon conditioning on a third. This often happens when two otherwise unrelated events have a common cause. Shoe size and reading level are highly correlated among elementary school students, but this correlation disappears if we condition on age.

 

그리고 반대로, 두 개의 종속 확률 변수는 세 번째 변수에 대한 조건에 따라 독립 변수가 될 수 있습니다. 이는 서로 관련이 없는 두 가지 사건에 공통 원인이 있는 경우에 자주 발생합니다. 신발 사이즈와 독서 수준은 초등학생 사이에서 높은 상관관계가 있지만, 연령을 조건으로 하면 이러한 상관관계가 사라집니다.

 

2.6.5. An Example

 

Let’s put our skills to the test. Assume that a doctor administers an HIV test to a patient. This test is fairly accurate and fails only with 1% probability if the patient is healthy but reported as diseased, i.e., healthy patients test positive in 1% of cases. Moreover, it never fails to detect HIV if the patient actually has it. We use D1∈{0,1} to indicate the diagnosis (0 if negative and 1 if positive) and H∈{0,1} to denote the HIV status.

 

우리의 능력을 시험해 봅시다. 의사가 환자에게 HIV 테스트를 실시한다고 가정합니다. 이 테스트는 매우 정확하며 환자가 건강하지만 질병이 있는 것으로 보고된 경우, 즉 건강한 환자가 1%의 사례에서 양성 반응을 보이는 경우 1% 확률로만 실패합니다. 더욱이, 환자가 실제로 HIV에 감염되어 있는 경우에도 HIV를 탐지하는 데 실패하지 않습니다. D1∈{0,1}을 사용하여 진단(음성인 경우 0, 양성인 경우 1)을 나타내고 H∈{0,1}을 사용하여 HIV 상태를 나타냅니다.

 

 

Note that the column sums are all 1 (but the row sums do not), since they are conditional probabilities. Let’s compute the probability of the patient having HIV if the test comes back positive, i.e., P(H=1∣D1=1). Intuitively this is going to depend on how common the disease is, since it affects the number of false alarms. Assume that the population is fairly free of the disease, e.g., P(H=1)=0.0015. To apply Bayes’ theorem, we need to apply marginalization to determine

 

조건부 확률이므로 열 합은 모두 1입니다(행 합은 그렇지 않음). 검사 결과가 양성으로 나오면 환자가 HIV에 감염될 확률을 계산해 보겠습니다(예: P(H=1∣D1=1)). 직관적으로 이것은 잘못된 경보의 수에 영향을 미치기 때문에 질병이 얼마나 흔한지에 따라 달라집니다. 인구에 질병이 전혀 없다고 가정합니다(예: P(H=1)=0.0015). 베이즈 정리를 적용하려면 주변화를 적용하여 다음을 결정해야 합니다.

 

 

In other words, there is only a 13.06% chance that the patient actually has HIV, despite the test being pretty accurate. As we can see, probability can be counterintuitive. What should a patient do upon receiving such terrifying news? Likely, the patient would ask the physician to administer another test to get clarity. The second test has different characteristics and it is not as good as the first one.

 

즉, 테스트가 매우 정확함에도 불구하고 환자가 실제로 HIV에 감염될 확률은 13.06%에 불과합니다. 보시다시피 확률은 직관에 반할 수 있습니다. 이런 무서운 소식을 접한 환자는 어떻게 해야 할까요? 아마도 환자는 명확성을 얻기 위해 의사에게 또 다른 검사를 실시해 달라고 요청할 것입니다. 두 번째 테스트는 특성이 다르고 첫 번째 테스트만큼 좋지 않습니다.

 

 

Unfortunately, the second test comes back positive, too. Let’s calculate the requisite probabilities to invoke Bayes’ theorem by assuming conditional independence:

 

불행히도 두 번째 테스트에서도 양성 반응이 나왔습니다. 조건부 독립을 가정하여 베이즈 정리를 적용하는 데 필요한 확률을 계산해 보겠습니다.

 

Now we can apply marginalization to obtain the probability that both tests come back positive:

 

이제 우리는 소외화를 적용하여 두 테스트가 모두 양성으로 돌아올 확률을 얻을 수 있습니다.

 

Finally, the probability of the patient having HIV given that both tests are positive is

 

마지막으로, 두 검사 모두 양성인 경우 환자가 HIV에 감염될 확률은 다음과 같습니다.

 

That is, the second test allowed us to gain much higher confidence that not all is well. Despite the second test being considerably less accurate than the first one, it still significantly improved our estimate. The assumption of both tests being conditionally independent of each other was crucial for our ability to generate a more accurate estimate. Take the extreme case where we run the same test twice. In this situation we would expect the same outcome both times, hence no additional insight is gained from running the same test again. The astute reader might have noticed that the diagnosis behaved like a classifier hiding in plain sight where our ability to decide whether a patient is healthy increases as we obtain more features (test outcomes).

 

즉, 두 번째 테스트를 통해 우리는 모든 것이 좋지 않다는 훨씬 더 높은 확신을 얻을 수 있었습니다. 두 번째 테스트는 첫 번째 테스트보다 정확도가 상당히 떨어졌음에도 불구하고 여전히 우리의 추정치를 크게 향상시켰습니다. 두 테스트가 서로 조건부 독립이라는 가정은 보다 정확한 추정치를 생성하는 데 매우 중요했습니다. 동일한 테스트를 두 번 실행하는 극단적인 경우를 생각해 보겠습니다. 이 상황에서는 두 번 모두 동일한 결과가 나올 것으로 예상되므로 동일한 테스트를 다시 실행해도 추가적인 통찰력을 얻을 수 없습니다. 기민한 독자는 진단이 더 많은 특징(테스트 결과)을 얻을수록 환자의 건강 여부를 결정하는 능력이 증가하는 눈에 잘 띄는 곳에 숨어 있는 분류기처럼 행동한다는 것을 알아차렸을 것입니다.

 

2.6.6. Expectations

 

Often, making decisions requires not just looking at the probabilities assigned to individual events but composing them together into useful aggregates that can provide us with guidance. For example, when random variables take continuous scalar values, we often care about knowing what value to expect on average. This quantity is formally called an expectation. If we are making investments, the first quantity of interest might be the return we can expect, averaging over all the possible outcomes (and weighting by the appropriate probabilities). For instance, say that with 50% probability, an investment might fail altogether, with 40% probability it might provide a 2× return, and with 10% probability it might provide a 10× return 10×. To calculate the expected return, we sum over all returns, multiplying each by the probability that they will occur. This yields the expectation 0.5⋅0+0.4⋅2+0.1⋅10=1.8. Hence the expected return is 1.8×.

 

종종 결정을 내리려면 개별 사건에 할당된 확률을 살펴보는 것뿐만 아니라 지침을 제공할 수 있는 유용한 집계로 이를 함께 구성해야 합니다. 예를 들어, 확률 변수가 연속적인 스칼라 값을 취하는 경우 우리는 평균적으로 어떤 값을 기대하는지 아는 데 종종 관심을 갖습니다. 이 수량을 공식적으로 기대값이라고 합니다. 투자를 하는 경우 첫 번째 관심 수량은 가능한 모든 결과에 대한 평균을 계산하고 적절한 확률에 따라 가중치를 부여하여 기대할 수 있는 수익일 수 있습니다. 예를 들어, 50% 확률로 투자가 완전히 실패할 수 있고, 40% 확률로 2배의 수익을 제공할 수 있으며, 10% 확률로 10배의 수익을 제공할 수 있다고 가정해 보겠습니다. 기대 수익을 계산하기 위해 우리는 모든 수익을 합산하고 각 수익에 발생할 확률을 곱합니다. 이는 기대값 0.5⋅0+0.4⋅2+0.1⋅10=1.8을 산출합니다. 따라서 기대수익률은 1.8×입니다.

 

In general, the expectation (or average) of the random variable X is defined as

 

일반적으로 확률 변수 X의 기대값(또는 평균)은 다음과 같이 정의됩니다.

 

 

Likewise, for densities we obtain E[X]=∫x dp(x). Sometimes we are interested in the expected value of some function of x. We can calculate these expectations as

 

마찬가지로 밀도의 경우 E[X]=∫xdp(x)를 얻습니다. 때때로 우리는 x의 어떤 함수의 기대값에 관심이 있습니다. 우리는 이러한 기대치를 다음과 같이 계산할 수 있습니다.

 

 

for discrete probabilities and densities, respectively. Returning to the investment example from above, f might be the utility (happiness) associated with the return. Behavior economists have long noted that people associate greater disutility with losing money than the utility gained from earning one dollar relative to their baseline. Moreover, the value of money tends to be sub-linear. Possessing 100k dollars versus zero dollars can make the difference between paying the rent, eating well, and enjoying quality healthcare versus suffering through homelessness. On the other hand, the gains due to possessing 200k versus 100k are less dramatic. Reasoning like this motivates the cliché that “the utility of money is logarithmic”.

 

이산 확률과 밀도에 대해 각각. 위의 투자 예로 돌아가면, f는 수익과 관련된 효용(행복)일 수 있습니다. 행동경제학자들은 사람들이 자신의 기준에 비해 1달러를 벌어서 얻는 효용보다 돈을 잃는 데 더 큰 비효용성을 연관시킨다는 점을 오랫동안 지적해 왔습니다. 더욱이 화폐의 가치는 준선형적인 경향이 있습니다. 10만 달러를 소유하는 것과 0달러를 소유하는 것은 집세를 내고, 잘 먹고, 양질의 의료 서비스를 받는 것과 노숙자로 고통받는 것 사이의 차이를 만들 수 있습니다. 반면에 200,000개와 100,000개를 소유함으로써 얻을 수 있는 이득은 덜 극적입니다. 이런 추론은 “돈의 효용은 대수적이다”라는 상투적인 말을 하게 만든다.

 

If the utility associated with a total loss were −1, and the utilities associated with returns of 1, 2, and 10 were 1, 2 and 4, respectively, then the expected happiness of investing would be 0.5⋅(−1)+0.4⋅2+0.1⋅4=0.7 (an expected loss of utility of 30%). If indeed this were your utility function, you might be best off keeping the money in the bank.

 

총 손실과 관련된 효용이 −1이고 수익 1, 2, 10과 관련된 효용이 각각 1, 2, 4라면 투자의 기대 행복은 0.5⋅(−1)+0.4가 됩니다. ⋅2+0.1⋅4=0.7(예상 효용 손실 30%). 실제로 이것이 유틸리티 기능이라면 돈을 은행에 보관하는 것이 가장 좋습니다.

 

For financial decisions, we might also want to measure how risky an investment is. Here, we care not just about the expected value but how much the actual values tend to vary relative to this value. Note that we cannot just take the expectation of the difference between the actual and expected values. This is because the expectation of a difference is the difference of the expectations, i.e., E[X−E[X]]=E[X]−E[E[X]]=0. However, we can look at the expectation of any non-negative function of this difference. The variance of a random variable is calculated by looking at the expected value of the squared differences:

 

재정적 결정을 위해 투자가 얼마나 위험한지 측정하고 싶을 수도 있습니다. 여기서는 기대값뿐만 아니라 이 값에 비해 실제 값이 얼마나 달라지는 경향이 있는지도 중요합니다. 실제 값과 예상 값의 차이를 기대하는 것만으로는 충분하지 않습니다. 이는 차이에 대한 기대가 기대의 차이, 즉 E[X−E[X]]=E[X]−E[E[X]]=0이기 때문입니다. 그러나 우리는 이 차이의 음이 아닌 함수에 대한 기대를 살펴볼 수 있습니다. 확률 변수의 분산은 차이 제곱의 기대값을 확인하여 계산됩니다.

 

Here the equality follows by expanding (X−E[X])**2 = X**2 − 2XE[X]+E[X]**2 and taking expectations for each term. The square root of the variance is another useful quantity called the standard deviation. While this and the variance convey the same information (either can be calculated from the other), the standard deviation has the nice property that it is expressed in the same units as the original quantity represented by the random variable.

 

여기서는 (X−E[X])**2 = X**2 − 2XE[X]+E[X]**2를 확장하고 각 항에 대한 기대값을 취하여 동등성을 따릅니다. 분산의 제곱근은 표준편차라고 불리는 또 다른 유용한 양입니다. 이것과 분산은 동일한 정보를 전달하지만(둘 중 하나를 다른 것으로 계산할 수 있음), 표준 편차는 랜덤 변수가 나타내는 원래 양과 동일한 단위로 표현된다는 좋은 속성을 가지고 있습니다.

 

Lastly, the variance of a function of a random variable is defined analogously as

 

마지막으로, 확률 변수의 함수 분산은 다음과 유사하게 정의됩니다.

 

 

Returning to our investment example, we can now compute the variance of the investment. It is given by 0.5⋅0+0.4⋅2**2+0.1⋅10**2−1.8**2=8.36. For all intents and purposes this is a risky investment. Note that by mathematical convention mean and variance are often referenced as μ  and σ**2. This is particularly the case whenever we use it to parametrize a Gaussian distribution.

 

투자 예로 돌아가서 이제 투자의 분산을 계산할 수 있습니다. 이는 0.5⋅0+0.4⋅2**2+0.1⋅10**2−1.8**2=8.36으로 제공됩니다. 모든 의도와 목적을 위해 이것은 위험한 투자입니다. 수학적 관례에 따라 평균과 분산은 종종 μ 및 σ**2로 참조됩니다. 특히 가우스 분포를 매개변수화하는 데 사용할 때마다 그렇습니다.

 

In the same way as we introduced expectations and variance for scalar random variables, we can do so for vector-valued ones. Expectations are easy, since we can apply them elementwise. For instance, μ def= Ex∼p[x] has coordinates μ i = Ex∼p[xi]. Covariances are more complicated. We define them by taking expectations of the outer product of the difference between random variables and their mean:

 

스칼라 확률 변수에 대한 기대치와 분산을 도입한 것과 같은 방식으로 벡터 값 변수에 대해서도 그렇게 할 수 있습니다. 요소별로 적용할 수 있으므로 기대하기 쉽습니다. 예를 들어 μ def= Ex∼p[x]는 μ i = Ex∼p[xi] 좌표를 갖는다. 공분산은 더 복잡합니다. 우리는 확률 변수와 평균 간의 차이에 대한 외부 곱을 기대하여 이를 정의합니다.

 

This matrix  is referred to as the covariance matrix. An easy way to see its effect is to consider some vector v of the same size as x. It follows that

 

 

As such,  allows us to compute the variance for any linear function of x by a simple matrix multiplication. The off-diagonal elements tell us how correlated the coordinates are: a value of 0 means no correlation, where a larger positive value means that they are more strongly correlated.

 

따라서 ∑를 사용하면 간단한 행렬 곱셈을 통해 x의 모든 선형 함수에 대한 분산을 계산할 수 있습니다. 비대각선 요소는 좌표의 상관 관계를 알려줍니다. 값이 0이면 상관 관계가 없음을 의미하고 양수 값이 클수록 상관 관계가 더 강하다는 의미입니다.

 

2.6.7. Discussion

 

In machine learning, there are many things to be uncertain about! We can be uncertain about the value of a label given an input. We can be uncertain about the estimated value of a parameter. We can even be uncertain about whether data arriving at deployment is even from the same distribution as the training data.

 

머신러닝에는 불확실한 부분이 많습니다! 입력이 주어지면 레이블의 값이 불확실할 수 있습니다. 매개변수의 추정값이 불확실할 수 있습니다. 배포 시 도착하는 데이터가 교육 데이터와 동일한 분포에서 나온 것인지 여부도 불확실할 수 있습니다.

 

By aleatoric uncertainty, we mean uncertainty that is intrinsic to the problem, and due to genuine randomness unaccounted for by the observed variables. By epistemic uncertainty, we mean uncertainty over a model’s parameters, the sort of uncertainty that we can hope to reduce by collecting more data. We might have epistemic uncertainty concerning the probability that a coin turns up heads, but even once we know this probability, we are left with aleatoric uncertainty about the outcome of any future toss. No matter how long we watch someone tossing a fair coin, we will never be more or less than 50% certain that the next toss will come up heads. These terms come from mechanical modeling, (see e.g., Der Kiureghian and Ditlevsen (2009) for a review on this aspect of uncertainty quantification). It is worth noting, however, that these terms constitute a slight abuse of language. The term epistemic refers to anything concerning knowledge and thus, in the philosophical sense, all uncertainty is epistemic.

 

우연적 불확실성이란 문제에 내재된 불확실성, 관찰된 변수에 의해 설명되지 않는 진정한 무작위성으로 인한 불확실성을 의미합니다. 인식론적 불확실성이란 모델 매개변수에 대한 불확실성, 즉 더 많은 데이터를 수집하여 줄일 수 있는 불확실성을 의미합니다. 동전이 앞면이 나올 확률에 대해 인식론적 불확실성이 있을 수 있지만, 이 확률을 알더라도 미래 던지기의 결과에 대한 우연적 불확실성이 남아 있습니다. 누군가가 공정한 동전을 던지는 것을 얼마나 오랫동안 지켜보더라도 우리는 다음 번 던질 때 앞면이 나올 것이라는 확신을 50% 이상 또는 이하로 결코 확신할 수 없습니다. 이러한 용어는 기계적 모델링에서 유래되었습니다(불확도 정량화의 이러한 측면에 대한 검토는 Der Kiureghian 및 Ditlevsen(2009) 참조). 그러나 이러한 용어가 약간의 언어 남용을 구성한다는 점은 주목할 가치가 있습니다. 인식론이라는 용어는 지식에 관한 모든 것을 의미하므로 철학적 의미에서 모든 불확실성은 인식론적입니다.

 

We saw that sampling data from some unknown probability distribution can provide us with information that can be used to estimate the parameters of the data generating distribution. That said, the rate at which this is possible can be quite slow. In our coin tossing example (and many others) we can do no better than to design estimators that converge at a rate of 1/ n, where n is the sample size (e.g., the number of tosses). This means that by going from 10 to 1000 observations (usually a very achievable task) we see a tenfold reduction of uncertainty, whereas the next 1000 observations help comparatively little, offering only a 1.41 times reduction. This is a persistent feature of machine learning: while there are often easy gains, it takes a very large amount of data, and often with it an enormous amount of computation, to make further gains. For an empirical review of this fact for large scale language models see Revels et al. (2016).

 

우리는 알려지지 않은 확률 분포의 샘플링 데이터가 데이터 생성 분포의 매개변수를 추정하는 데 사용할 수 있는 정보를 제공할 수 있음을 확인했습니다. 즉, 이것이 가능한 속도는 상당히 느릴 수 있습니다. 동전 던지기 예제(및 기타 여러 예제)에서 우리는 1/ √n의 비율로 수렴하는 추정기를 설계하는 것보다 더 나은 것을 할 수 없습니다. 여기서 n은 표본 크기(예: 던지기 횟수)입니다. 이는 10개에서 1000개의 관측값(일반적으로 매우 달성 가능한 작업)으로 이동하면 불확실성이 10배 감소한 반면, 다음 1000개의 관측값은 1.41배만 감소하여 비교적 거의 도움이 되지 않는다는 것을 의미합니다. 이는 기계 학습의 지속적인 특징입니다. 쉽게 얻을 수 있는 경우가 많지만 추가 이득을 얻으려면 매우 많은 양의 데이터와 엄청난 양의 계산이 필요한 경우가 많습니다. 대규모 언어 모델에 대한 이 사실에 대한 실증적 검토는 Revels et al. (2016).

 

We also sharpened our language and tools for statistical modeling. In the process of that we learned about conditional probabilities and about one of the most important equations in statistics—Bayes’ theorem. It is an effective tool for decoupling information conveyed by data through a likelihood term P(B∣A) that addresses how well observations B match a choice of parameters A, and a prior probability P(A) which governs how plausible a particular choice of A was in the first place. In particular, we saw how this rule can be applied to assign probabilities to diagnoses, based on the efficacy of the test and the prevalence of the disease itself (i.e., our prior).

 

우리는 또한 통계 모델링을 위한 언어와 도구를 개선했습니다. 그 과정에서 우리는 조건부 확률과 통계에서 가장 중요한 방정식 중 하나인 베이즈 정리에 대해 배웠습니다. 이는 관측치 B가 매개변수 A의 선택과 얼마나 잘 일치하는지를 다루는 가능성 항 P(B∣A)와 매개변수 A의 선택이 얼마나 타당한지를 제어하는 사전 확률 P(A)를 통해 데이터에 의해 전달되는 정보를 분리하는 효과적인 도구입니다. A가 먼저였다. 특히, 우리는 테스트의 효능과 질병 자체의 유병률(예: 이전)을 기반으로 진단에 확률을 할당하기 위해 이 규칙을 적용할 수 있는 방법을 살펴보았습니다.

 

Lastly, we introduced a first set of nontrivial questions about the effect of a specific probability distribution, namely expectations and variances. While there are many more than just linear and quadratic expectations for a probability distribution, these two already provide a good deal of knowledge about the possible behavior of the distribution. For instance, Chebyshev’s inequality states that P(X|X− μ|≥k σ)≤1/k**2, where μ  is the expectation, σ**2 is the variance of the distribution, and k>1 is a confidence parameter of our choosing. It tells us that draws from a distribution lie with at least 50% probability within a [− 2σ ,  2σ ] interval centered on the expectation.

 

마지막으로, 특정 확률 분포, 즉 기대값과 분산의 효과에 대한 첫 번째 중요하지 않은 질문 세트를 소개했습니다. 확률 분포에 대한 선형 및 2차 기대치보다 더 많은 것이 있지만 이 두 가지는 이미 분포의 가능한 동작에 대한 많은 지식을 제공합니다. 예를 들어, 체비쇼프 부등식은 P(X|X− μ|≥k σ)≤1/k**2라고 말합니다. 여기서 μ는 기대값이고, σ**2는 분포의 분산이고, k>1은 우리가 선택한 신뢰 매개변수. 이는 기대값을 중심으로 [− √ 2σ , √ 2σ ] 간격 내에서 최소 50% 확률로 분포 거짓말에서 도출된다는 것을 알려줍니다.

 

2.6.8. Exercises

 

  1. Give an example where observing more data can reduce the amount of uncertainty about the outcome to an arbitrarily low level.

    더 많은 데이터를 관찰하면 결과에 대한 불확실성을 임의로 낮은 수준으로 줄일 수 있는 예를 들어보세요.

  2. Give an example where observing more data will only reduce the amount of uncertainty up to a point and then no further. Explain why this is the case and where you expect this point to occur.

    더 많은 데이터를 관찰하면 불확실성의 양이 어느 정도 줄어들 뿐 그 이상은 줄어들지 않는 예를 들어보세요. 왜 이런 일이 발생하는지, 그리고 이러한 상황이 어디서 발생할 것으로 예상하는지 설명하세요.

  3. We empirically demonstrated convergence to the mean for the toss of a coin. Calculate the variance of the estimate of the probability that we see a head after drawing n samples.

    우리는 동전 던지기의 평균에 대한 수렴을 경험적으로 증명했습니다. n개의 샘플을 뽑은 후 머리가 보일 확률 추정치의 분산을 계산합니다.

    1. How does the variance scale with the number of observations?

      관측치 수에 따라 분산이 어떻게 확장되나요?

    2. Use Chebyshev’s inequality to bound the deviation from the expectation.

      체비쇼프 부등식을 사용하여 기대치로부터의 편차를 제한합니다.

    3. How does it relate to the central limit theorem?

      중심극한정리와 어떤 관련이 있나요?

 

 

반응형


반응형

https://d2l.ai/chapter_preliminaries/autograd.html

 

2.5. Automatic Differentiation — Dive into Deep Learning 1.0.3 documentation

 

d2l.ai

2.5. Automatic Differentiation

Recall from Section 2.4 that calculating derivatives is the crucial step in all the optimization algorithms that we will use to train deep networks. While the calculations are straightforward, working them out by hand can be tedious and error-prone, and these issues only grow as our models become more complex.

 

섹션 2.4에서 도함수를 계산하는 것이 심층 네트워크를 훈련하는 데 사용할 모든 최적화 알고리즘에서 중요한 단계라는 점을 상기해 보세요. 계산은 간단하지만 손으로 계산하는 것은 지루하고 오류가 발생하기 쉬울 수 있으며 이러한 문제는 모델이 더 복잡해질수록 커집니다.

 

Fortunately all modern deep learning frameworks take this work off our plates by offering automatic differentiation (often shortened to autograd). As we pass data through each successive function, the framework builds a computational graph that tracks how each value depends on others. To calculate derivatives, automatic differentiation works backwards through this graph applying the chain rule. The computational algorithm for applying the chain rule in this fashion is called backpropagation.

 

다행스럽게도 모든 최신 딥 러닝 프레임워크는 자동 차별화 automatic differentiation (종종 autograd로 축약됨)를 제공하여 이 작업을 수행합니다. 각 연속 함수를 통해 데이터를 전달할 때 프레임워크는 각 값이 다른 값에 어떻게 의존하는지 추적하는 계산 그래프를 작성합니다. 도함수를 계산하기 위해 자동 미분은 체인 규칙을 적용하여 이 그래프를 통해 역방향으로 작동합니다. 이러한 방식으로 체인 규칙을 적용하는 계산 알고리즘을 역전파라고 합니다.

 

While autograd libraries have become a hot concern over the past decade, they have a long history. In fact the earliest references to autograd date back over half of a century (Wengert, 1964). The core ideas behind modern backpropagation date to a PhD thesis from 1980 (Speelpenning, 1980) and were further developed in the late 1980s (Griewank, 1989). While backpropagation has become the default method for computing gradients, it is not the only option. For instance, the Julia programming language employs forward propagation (Revels et al., 2016). Before exploring methods, let’s first master the autograd package.

 

Autograd 라이브러리는 지난 10년 동안 뜨거운 관심사가 되었지만 오랜 역사를 가지고 있습니다. 실제로 autograd에 대한 최초의 언급은 반세기 전으로 거슬러 올라갑니다(Wengert, 1964). 현대 역전파 backpropagation 의 핵심 아이디어는 1980년 박사 학위 논문(Speelpenning, 1980)으로 시작되었으며 1980년대 후반에 더욱 발전되었습니다(Griewank, 1989). 역전파가 기울기를 계산하는 기본 방법이 되었지만 이것이 유일한 옵션은 아닙니다. 예를 들어 Julia 프로그래밍 언어는 순방향 전파 forward propagation 를 사용합니다(Revels et al., 2016). 방법을 살펴보기 전에 먼저 autograd 패키지를 마스터해 보겠습니다.

 

import torch

 

2.5.1. A Simple Function

Let’s assume that we are interested in differentiating the function y=2xx with respect to the column vector x. To start, we assign x an initial value.

 

열 벡터 x에 대해 함수 y=2xx를 미분하는 데 관심이 있다고 가정해 보겠습니다. 시작하려면 x에 초기 값을 할당합니다.

 

x = torch.arange(4.0)
x

이 코드는 파이토치(PyTorch)를 사용하여 텐서를 생성하고 값을 출력하는 간단한 코드입니다. 각 줄의 코드를 설명하겠습니다:

  1. x = torch.arange(4.0): 이 코드는 0부터 3까지의 연속된 실수 값을 가지는 1차원 텐서를 생성합니다. torch는 파이토치 라이브러리를 나타내며, torch.arange(4.0)는 0.0, 1.0, 2.0, 3.0으로 구성된 텐서를 만듭니다. 따라서 x에는 이러한 값들이 저장됩니다.
  2. x: 이 부분은 x를 출력하는 코드입니다. 따라서 코드를 실행하면 텐서 x의 값이 표시됩니다.

실행 결과로 x에는 0.0, 1.0, 2.0, 3.0이 포함된 1차원 텐서가 저장되며, 출력에서는 이 값들이 표시됩니다.

tensor([0., 1., 2., 3.])

 

Before we calculate the gradient of y with respect to x, we need a place to store it. In general, we avoid allocating new memory every time we take a derivative because deep learning requires successively computing derivatives with respect to the same parameters a great many times, and we might risk running out of memory. Note that the gradient of a scalar-valued function with respect to a vector x is vector-valued with the same shape as x.

 

x에 대한 y의 기울기를 계산하기 전에 이를 저장할 장소가 필요합니다. 일반적으로 딥 러닝에서는 동일한 매개변수에 대해 여러 번 연속적으로 derivatives 을 계산해야 하고 메모리가 부족할 위험이 있으므로 derivatives 을 가져올 때마다 새 메모리를 할당하는 것을 피합니다. 벡터 x에 대한 스칼라 값 함수의 기울기는 x와 동일한 모양으로 벡터 값을 갖습니다.

 

# Can also create x = torch.arange(4.0, requires_grad=True)
x.requires_grad_(True)
x.grad  # The gradient is None by default

이 코드는 PyTorch를 사용하여 그레디언트(gradient)를 계산하기 위해 텐서에 requires_grad 속성을 추가하는 방법을 보여줍니다. 한국어로 코드를 설명하겠습니다:

  1. x.requires_grad_(True): 이 코드는 x 텐서의 requires_grad 속성을 True로 설정합니다. 이것은 텐서 x에서 그레디언트를 계산하려는 의도를 나타냅니다. 즉, x의 값이 어떻게 변경되는지 추적하여 나중에 그레디언트를 계산할 수 있도록 합니다.
  2. x.grad: 이 코드는 x 텐서의 그레디언트를 검색합니다. 그러나 여기서는 x의 그레디언트가 아직 계산되지 않았으므로 그 값은 기본적으로 None입니다.

즉, x.requires_grad_(True)를 통해 PyTorch에게 x의 그레디언트를 추적하도록 지시하고, 나중에 해당 그레디언트를 계산할 수 있도록 준비를 마칩니다. 현재는 아직 그레디언트가 계산되지 않았기 때문에 x.grad의 값은 None입니다. 그레디언트는 손실 함수 등의 역전파(backpropagation) 과정에서 계산됩니다.

 

We now calculate our function of x and assign the result to y.

 

이제 x의 함수를 계산하고 그 결과를 y에 할당합니다.

 

y = 2 * torch.dot(x, x)
y

이 코드는 PyTorch를 사용하여 스칼라 값을 계산하고 y에 저장하는 예제입니다. 

  1. x는 PyTorch 텐서입니다. 이 코드에서는 벡터 x와 자기 자신을 내적(dot product)한 결과를 활용하려고 합니다.
  2. torch.dot(x, x)는 x 텐서와 x 자기 자신과의 내적을 계산합니다.
  3. 2 * torch.dot(x, x)는 내적 결과에 2를 곱한 값을 y에 할당합니다. 즉, y는 2 * x 벡터의 내적값입니다.
  4. 따라서 y에는 2 * x 벡터의 내적값이 저장됩니다.

y에는 스칼라 값이 저장되므로 y는 스칼라 텐서입니다. 내적은 벡터 간의 유사도를 계산하는 데 사용되며, 위의 코드에서는 x 벡터와 x 벡터의 유사도를 계산하여 2를 곱한 결과가 y에 저장됩니다.

tensor(28., grad_fn=<MulBackward0>)

We can now take the gradient of y with respect to x by calling its backward method. Next, we can access the gradient via x’s grad attribute.

 

이제 역방향 메소드를 호출하여 x에 대한 y의 기울기를 얻을 수 있습니다. 다음으로, x의 grad 속성을 통해 그래디언트에 접근할 수 있습니다.

 

y.backward()
x.grad

이 코드는 PyTorch에서 역전파(backpropagation)를 사용하여 그래디언트(gradient)를 계산하는 예제입니다.

  1. y는 이전 코드에서 정의한 스칼라 값입니다. 이 값을 계산하기 위해 사용된 연산 그래프를 통해 역전파를 수행하려고 합니다.
  2. y.backward()는 y의 그래디언트(도함수)를 계산하는 역전파(backpropagation)를 시작합니다. backward 메서드는 그래디언트를 계산하고 x.grad에 저장합니다.
  3. x.grad는 x 텐서에 대한 그래디언트 값을 나타냅니다. 그래디언트는 손실 함수(여기서는 y)를 x에 대해 편미분한 결과로, x의 각 요소에 대한 미분값이 저장됩니다.

즉, x.grad에는 x 텐서의 각 원소에 대한 미분값이 저장되며, 이것은 역전파를 통해 손실 함수 y를 x에 대해 미분한 결과입니다. 이를 통해 PyTorch를 사용하여 그래디언트를 계산하고, 이후에 그래디언트 기반 최적화 알고리즘(예: 확률적 경사 하강법)을 사용하여 모델을 업데이트할 수 있습니다.

tensor([ 0.,  4.,  8., 12.])

We already know that the gradient of the function y=2xx with respect to x should be 4x. We can now verify that the automatic gradient computation and the expected result are identical.

 

우리는 x에 대한 함수 y=2xx의 기울기가 4x여야 한다는 것을 이미 알고 있습니다. 이제 자동 기울기 계산과 예상 결과가 동일한 것을 확인할 수 있습니다.

 

x.grad == 4 * x

이 코드는 PyTorch를 사용하여 그래디언트(gradient)를 계산하고 검증하는 부분입니다.

 

  1. x.grad는 x 텐서의 그래디언트 값을 나타냅니다. 이 그래디언트는 y = 2 * torch.dot(x, x)의 손실 함수에 대한 x에 대한 미분값으로 이전 코드에서 y.backward()를 호출하여 계산되었습니다.
  2. 4 * x는 x 텐서의 각 요소에 4를 곱한 결과를 나타냅니다.
  3. x.grad == 4 * x는 x.grad와 4 * x를 비교하여 각 요소가 동일한지 여부를 확인합니다. 이것은 그래디언트 계산이 올바르게 수행되었는지 검증하는 부분입니다. 만약 x.grad의 각 요소가 4 * x와 동일하다면, 그래디언트 계산이 정확하게 이루어졌음을 의미합니다.

이를 통해 코드는 그래디언트를 계산하고 이 값이 수동으로 계산한 기대값과 일치하는지 확인하는 유효성 검사(validation)를 수행합니다.

tensor([True, True, True, True])

Now let’s calculate another function of x and take its gradient. Note that PyTorch does not automatically reset the gradient buffer when we record a new gradient. Instead, the new gradient is added to the already-stored gradient. This behavior comes in handy when we want to optimize the sum of multiple objective functions. To reset the gradient buffer, we can call x.grad.zero_() as follows:

 

이제 x의 또 다른 함수를 계산하고 그 기울기를 살펴보겠습니다. PyTorch는 새 그래디언트를 기록할 때 그래디언트 버퍼를 자동으로 재설정하지 않습니다. 대신 이미 저장된 그래디언트에 새 그래디언트가 추가됩니다. 이 동작은 여러 목적 함수의 합을 최적화하려고 할 때 유용합니다. 그래디언트 버퍼를 재설정하려면 다음과 같이 x.grad.zero_()를 호출할 수 있습니다.

 

x.grad.zero_()  # Reset the gradient
y = x.sum()
y.backward()
x.grad

이 코드는 PyTorch를 사용하여 그래디언트(gradient)를 계산하고 초기화하는 부분입니다.

tensor([1., 1., 1., 1.])
  1. x.grad.zero_()은 x 텐서의 그래디언트 값을 초기화합니다. 그래디언트를 초기화하는 이유는 이전 그래디언트 값이 아직 y.backward()로 계산되지 않았을 때 그대로 남아있을 수 있기 때문입니다. 이 함수를 호출하여 모든 그래디언트 값을 0으로 설정합니다.
  2. y = x.sum()는 x 텐서의 모든 요소를 더한 값을 y에 저장합니다.
  3. y.backward()는 y를 사용하여 x 텐서의 그래디언트를 계산합니다. 여기서 y는 x에 대한 함수이며, x의 각 요소에 대한 편미분을 계산합니다.
  4. x.grad는 이렇게 계산된 그래디언트를 나타냅니다. x의 각 요소에 대한 미분값이 저장되어 있습니다.

따라서 이 코드는 그래디언트를 초기화한 다음 y를 사용하여 그래디언트를 계산하고, x.grad에 이 그래디언트 값을 저장합니다.

 

 

2.5.2. Backward for Non-Scalar Variables

 

When y is a vector, the most natural representation of the derivative of y with respect to a vector x is a matrix called the Jacobian that contains the partial derivatives of each component of y with respect to each component of x. Likewise, for higher-order y and x, the result of differentiation could be an even higher-order tensor.

 

y가 벡터인 경우 벡터 x에 대한 y의 도함수의 가장 자연스러운 표현은 x의 각 구성 요소에 대한 y의 각 구성 요소의 부분 도함수를 포함하는 야코비안(Jacobian)이라는 행렬입니다. 마찬가지로, 고차 y와 x의 경우 미분의 결과는 훨씬 더 고차 텐서가 될 수 있습니다.

 

Jacobian matrix 란?

 

The Jacobian matrix, often denoted as J, is a fundamental concept in mathematics and plays a crucial role in various fields, particularly in calculus, linear algebra, and optimization. It is essentially a matrix of all the first-order partial derivatives of a vector-valued function. Let's break down the Jacobian matrix step by step:

 

야코비안 행렬(Jacobian matrix)은 수학에서 중요한 개념 중 하나로, 주로 미적분학, 선형 대수 및 최적화 분야에서 핵심 역할을 합니다. 이것은 벡터 값 함수의 모든 일차 편미분치를 나타내는 행렬입니다. 야코비안 행렬을 단계별로 살펴보겠습니다.

 

1. Vector-Valued Function:

  • The Jacobian matrix is used to represent the derivative of a vector-valued function, which takes one or more input variables and maps them to a vector of output variables.
  • 야코비안 행렬은 하나 이상의 입력 변수를 가지고 이들을 출력 변수 벡터로 매핑하는 벡터 값 함수의 도함수를 나타내는 데 사용됩니다.

2. Components of the Jacobian:

  • Consider a vector-valued function F(x), where x is an input vector, and F(x) is a vector of functions (F₁(x), F₂(x), ..., Fₙ(x)).
  • 벡터 값 함수 F(x)를 고려해봅시다. 여기서 x는 입력 벡터이고 F(x)는 함수 값 벡터(F₁(x), F₂(x), ..., Fₙ(x))입니다.
  • The Jacobian matrix J of F(x) consists of all the first-order partial derivatives of these component functions with respect to the input variables:
  • F(x)의 야코비안 행렬 J는 이러한 구성 함수들의 입력 변수 x에 대한 모든 일차 편미분을 포함합니다:
  • Here, each entry Jᵢⱼ represents the partial derivative of Fᵢ with respect to xⱼ.
  • 여기서 각 항목 Jᵢⱼ는 Fᵢ가 xⱼ에 대한 편미분을 나타냅니다.

3. Interpretation:

  • Each row of the Jacobian matrix corresponds to one of the component functions Fᵢ, and each column corresponds to one of the input variables xⱼ.
  • 야코비안 행렬의 각 행은 출력 Fᵢ의 하나의 구성 함수에 해당하고, 각 열은 입력 변수 xⱼ 중 하나에 해당합니다.
  • The value in the Jᵢⱼ entry represents how much the i-th component of the output Fᵢ changes with respect to a small change in the j-th input variable xⱼ.
  • Jᵢⱼ 항목의 값은 출력 Fᵢ의 i번째 구성 요소가 입력 변수 xⱼ에 대한 작은 변화에 얼마나 민감한지를 나타냅니다.
  • Essentially, it quantifies the sensitivity of the component functions to changes in the input variables.
  • 기본적으로, 입력 변수의 변화에 대한 구성 함수의 민감도를 측정합니다.

4. Applications:

  • The Jacobian matrix is widely used in various fields:
  • 야코비안 행렬은 다양한 분야에서 널리 활용됩니다:
    • Calculus: It helps in solving problems related to multivariate calculus, such as gradient descent, optimization, and Taylor series expansions.
    • 미적분학: 경사 하강법, 최적화 및 테일러 급수 전개와 관련된 다변수 미적분 문제 해결에 사용됩니다.
    • Physics: It plays a role in mechanics, quantum mechanics, and the study of dynamic systems.
    • 물리학: 역학, 양자 역학 및 동적 시스템 연구에 역할을 합니다.
    • Engineering: Engineers use it in control theory and robotics to understand the relationships between input and output variables.
    • 공학: 제어 이론 및 로봇 공학에서 입력과 출력 변수 간의 관계를 이해하는 데 사용됩니다.
    • Machine Learning: It is used in neural networks for backpropagation, where the Jacobian matrix helps calculate gradients.
    • 기계 학습: 야코비안 행렬은 역전파(backpropagation)와 관련하여 신경망에서 기울기를 계산하는 데 사용됩니다.
    • Economics: It has applications in economics models that involve multiple variables and equations.
    • 경제학: 여러 변수와 방정식을 포함하는 경제 모델에서 응용됩니다.

In summary, the Jacobian matrix is a powerful mathematical tool used to understand how a vector-valued function responds to small changes in its input variables. It is a fundamental concept in various scientific and engineering disciplines and is a key component of many numerical and analytical techniques.

 

요약하면 야코비안 행렬은 벡터 값 함수가 입력 변수의 작은 변화에 어떻게 반응하는지를 이해하는 강력한 수학적 도구입니다. 다양한 과학 및 공학 분야에서 중요한 개념이며 많은 수치 및 해석적 기술의 핵심 구성 요소입니다.

 

While Jacobians do show up in some advanced machine learning techniques, more commonly we want to sum up the gradients of each component of y with respect to the full vector x, yielding a vector of the same shape as x. For example, we often have a vector representing the value of our loss function calculated separately for each example among a batch of training examples. Here, we just want to sum up the gradients computed individually for each example.

 

Jacobians   행렬은 일부 고급 기계 학습 기술에 나타나기도 하지만, 더 일반적으로는 전체 벡터 x에 대한 y의 각 구성 요소의 기울기를 합산하여 x와 동일한 모양의 벡터를 생성하려고 합니다. 예를 들어, 훈련 예제 배치 중 각 예제에 대해 별도로 계산된 손실 함수 값을 나타내는 벡터가 있는 경우가 많습니다. 여기서는 각 예에 대해 개별적으로 계산된 그래디언트를 요약하려고 합니다.

 

Because deep learning frameworks vary in how they interpret gradients of non-scalar tensors, PyTorch takes some steps to avoid confusion. Invoking backward on a non-scalar elicits an error unless we tell PyTorch how to reduce the object to a scalar. More formally, we need to provide some vector v such that backward will compute v xy rather than  xy . This next part may be confusing, but for reasons that will become clear later, this argument (representing v) is named gradient. For a more detailed description, see Yang Zhang’s Medium post.

 

딥 러닝 프레임워크는 비 스칼라 텐서의 기울기를 해석하는 방법이 다양하므로 PyTorch는 혼란을 피하기 위해 몇 가지 조치를 취합니다. 스칼라가 아닌 항목을 역으로 호출하면 PyTorch에 객체를 스칼라로 줄이는 방법을 알려주지 않는 한 오류가 발생합니다. 보다 공식적으로, 우리는 역방향이 ∂xy 대신 vxy를 계산하도록 일부 벡터 v를 제공해야 합니다. 다음 부분은 혼란스러울 수 있지만 나중에 명확해질 이유로 이 인수(v를 나타냄)의 이름은 그래디언트입니다. 자세한 설명은 Yang Zhang의 Medium 게시물을 참조하세요.

 

x.grad.zero_()
y = x * x
y.backward(gradient=torch.ones(len(y)))  # Faster: y.sum().backward()
x.grad

이 코드는 PyTorch를 사용하여 텐서 x에 대한 그래디언트를 계산하는 예제입니다. 아래에서 코드를 한 줄씩 설명하겠습니다.

x.grad는 x에 대한 그래디언트(미분)를 나타내는 PyTorch 텐서입니다. 이 코드는 이 그래디언트를 0으로 초기화합니다. 즉, 이전에 계산된 그래디언트를 지우고 새로운 그래디언트를 계산할 준비를 합니다.

새로운 텐서 y를 생성하며, 이는 x의 제곱을 계산한 결과입니다.

  • y.backward() 메서드는 y에 대한 그래디언트를 계산하는 역전파(backpropagation)를 수행합니다. 여기서 gradient 매개변수는 역전파 시, 역전파 시작점에서의 그래디언트 값을 설정합니다.
  • gradient=torch.ones(len(y))은 y가 스칼라값이 아니라 벡터(여기서는 x의 길이만큼)라는 것을 고려해, 역전파의 시작점에서 그래디언트를 모든 요소가 1인 벡터로 설정합니다.
  • 이렇게 하면 x에 대한 그래디언트가 각 원소마다 2 * x로 설정됩니다.
  • 이제 x.grad에는 x에 대한 그래디언트 값이 포함되어 있습니다. 이 경우, x.grad의 모든 원소는 2 * x와 동일한 값을 가지게 됩니다.

이 코드는 x를 사용하여 y = x^2를 계산하고, 이후 x에 대한 그래디언트를 역전파를 통해 계산하는 간단한 예제를 보여줍니다. 역전파를 수행하면 x.grad에 그래디언트 값이 저장되므로, 이를 통해 x에 대한 미분을 계산하거나 경사 하강법과 같은 최적화 알고리즘을 수행할 수 있습니다.

tensor([0., 2., 4., 6.])

 

2.5.3. Detaching Computation

Sometimes, we wish to move some calculations outside of the recorded computational graph. For example, say that we use the input to create some auxiliary intermediate terms for which we do not want to compute a gradient. In this case, we need to detach the respective computational graph from the final result. The following toy example makes this clearer: suppose we have z = x * y and y = x * x but we want to focus on the direct influence of x on z rather than the influence conveyed via y. In this case, we can create a new variable u that takes the same value as y but whose provenance (how it was created) has been wiped out. Thus u has no ancestors in the graph and gradients do not flow through u to x. For example, taking the gradient of z = x * u will yield the result u, (not 3 * x * x as you might have expected since z = x * x * x).

 

때로는 기록된 계산 그래프 외부로 일부 계산을 이동하고 싶을 때도 있습니다. 예를 들어 입력을 사용하여 기울기를 계산하지 않으려는 일부 보조 중간 항을 생성한다고 가정해 보겠습니다. 이 경우 최종 결과에서 해당 계산 그래프를 분리해야 합니다. 다음  toy 예제는 이를 더 명확하게 해줍니다. z = x * y 및 y = x * x가 있지만 y를 통해 전달되는 영향보다는 x가 z에 미치는 직접적인 영향에 초점을 맞추고 싶다고 가정합니다. 이 경우 y와 동일한 값을 가지지만 출처(생성 방법)가 지워진 새 변수 u를 만들 수 있습니다. 따라서 u에는 그래프에 조상이 없으며 기울기는 u를 통해 x로 흐르지 않습니다. 예를 들어, z = x * u의 기울기를 취하면 결과 u가 생성됩니다(z = x * x * x 이후 예상했던 3 * x * x가 아님).

 

x.grad.zero_()
y = x * x
u = y.detach()
z = u * x

z.sum().backward()
x.grad == u

이 코드는 PyTorch를 사용하여 그래디언트(미분)와 .detach() 메서드의 역할을 설명하는 예제입니다. 아래에서 코드를 한 줄씩 설명하겠습니다.

x.grad는 x에 대한 그래디언트(미분)를 나타내는 PyTorch 텐서입니다. 이 코드는 이전에 계산된 그래디언트를 지우고 새로운 그래디언트를 계산할 준비를 합니다.

새로운 텐서 y를 생성하며, 이는 x의 제곱을 계산한 결과입니다.

.detach() 메서드는 텐서를 분리(detach)하고 그래디언트 연산을 중단합니다. 이는 u가 y와 동일한 값을 가지지만 그래디언트가 연결되어 있지 않음을 의미합니다.

z는 u와 x의 곱셈으로 계산됩니다.

z의 모든 원소의 합에 대한 그래디언트를 계산합니다. 이러한 그래디언트 계산은 역전파(backpropagation)를 통해 수행됩니다.

  • 이 코드는 x.grad와 u를 비교합니다. 여기서 x.grad는 z.sum()에 대한 그래디언트이며, u는 y를 detach하여 생성된 텐서입니다. 이 둘은 같은 값을 가지므로 이 비교는 True를 반환합니다.

즉, x.grad는 z.sum()에 대한 그래디언트이며, 이는 u를 사용하여 x를 곱한 결과인 z에 대한 그래디언트와 같습니다.detach() 메서드를 사용하여 그래디언트 연산을 분리함으로써 그래디언트가 일부 연산에서 중지되도록 할 수 있습니다.

tensor([True, True, True, True])

Note that while this procedure detaches y’s ancestors from the graph leading to z, the computational graph leading to y persists and thus we can calculate the gradient of y with respect to x.

 

이 절차가 z로 이어지는 그래프에서 y의 조상을 분리하는 동안 y로 이어지는 계산 그래프는 지속되므로 x에 대한 y의 기울기를 계산할 수 있습니다.

 

x.grad.zero_()
y.sum().backward()
x.grad == 2 * x

이 코드는 PyTorch를 사용하여 그래디언트(미분)를 계산하는 예제입니다. 아래에서 코드를 한 줄씩 설명하겠습니다.

x.grad는 x에 대한 그래디언트(미분)를 나타내는 PyTorch 텐서입니다. 이 코드는 이전에 계산된 그래디언트를 지우고 새로운 그래디언트를 계산할 준비를 합니다. zero_() 메서드는 그래디언트를 모두 0으로 초기화합니다.

y의 모든 원소의 합에 대한 그래디언트를 계산합니다. 이러한 그래디언트 계산은 역전파(backpropagation)를 통해 수행됩니다. 여기서 y는 x의 제곱인 텐서입니다.

  • 이 코드는 x.grad와 2 * x를 비교합니다. x.grad는 y.sum()에 대한 그래디언트이며, 이것은 y가 x의 제곱이므로 2 * x입니다. 따라서 이 비교는 True를 반환합니다.

즉, x.grad는 y를 x로 미분한 결과이며, 이는 y가 2 * x의 형태를 가지는 관계를 반영합니다. 이것은 연쇄 법칙(Chain Rule)을 통해 계산되며, y가 x에 대한 제곱 함수인 경우 그래디언트는 2 * x가 됩니다.

tensor([True, True, True, True])

 

2.5.4. Gradients and Python Control Flow

So far we reviewed cases where the path from input to output was well defined via a function such as z = x * x * x. Programming offers us a lot more freedom in how we compute results. For instance, we can make them depend on auxiliary variables or condition choices on intermediate results. One benefit of using automatic differentiation is that even if building the computational graph of a function required passing through a maze of Python control flow (e.g., conditionals, loops, and arbitrary function calls), we can still calculate the gradient of the resulting variable. To illustrate this, consider the following code snippet where the number of iterations of the while loop and the evaluation of the if statement both depend on the value of the input a.

 

지금까지 우리는 z = x * x * x와 같은 함수를 통해 입력에서 출력까지의 경로가 잘 정의된 사례를 검토했습니다. 프로그래밍은 결과를 계산하는 방법에 있어 훨씬 더 많은 자유를 제공합니다. 예를 들어, 중간 결과에 대한 보조 변수나 조건 선택에 의존하도록 만들 수 있습니다. 자동 미분을 사용하면 미로 같은 Python 제어 흐름(예: 조건문, 루프 및 임의 함수 호출)을 통과해야 하는 함수의 계산 그래프를 작성하더라도 결과 변수의 기울기를 계속 계산할 수 있다는 이점이 있습니다. 이를 설명하기 위해 while 루프의 반복 횟수와 if 문의 평가가 모두 입력 a의 값에 따라 달라지는 다음 코드 조각을 고려해보세요.

 

def f(a):
    b = a * 2
    while b.norm() < 1000:
        b = b * 2
    if b.sum() > 0:
        c = b
    else:
        c = 100 * b
    return c

이 코드는 파이썬 함수 f(a)를 정의합니다. 이 함수는 입력으로 스칼라 텐서 a를 받아서 다음과 같은 작업을 수행합니다.

  1. b라는 새로운 변수를 생성하고 a에 2를 곱한 값을 할당합니다.
  2. b의 L2 노름(norm)이 1000보다 작을 때까지 b를 2배씩 계속해서 곱해갑니다. 이것은 b가 L2 노름이 1000보다 커질 때까지 반복하는 루프입니다.
  3. 만약 b의 원소들의 합이 0보다 크다면, c에 b를 할당합니다.
  4. 그렇지 않다면 (즉, b의 원소들의 합이 0 이하인 경우), c에 100을 곱한 b를 할당합니다.
  5. 최종적으로 c를 반환합니다.

이 함수는 입력 a를 사용하여 b를 계산하고, 이후에 b의 크기와 합을 고려하여 c를 정합니다. c의 값은 a와 b에 따라 다르며, 함수의 결과로 반환됩니다.

 

Below, we call this function, passing in a random value, as input. Since the input is a random variable, we do not know what form the computational graph will take. However, whenever we execute f(a) on a specific input, we realize a specific computational graph and can subsequently run backward.

 

아래에서는 이 함수를 호출하여 임의의 값을 입력으로 전달합니다. 입력이 랜덤 변수이기 때문에 계산 그래프가 어떤 형태를 취할지 알 수 없습니다. 그러나 특정 입력에 대해 f(a)를 실행할 때마다 특정 계산 그래프를 실현하고 이후에 역방향으로 실행할 수 있습니다.

 

a = torch.randn(size=(), requires_grad=True)
d = f(a)
d.backward()

이 코드는 PyTorch를 사용하여 작성된 것으로 보이는 예제입니다. 코드는 다음과 같은 작업을 수행합니다:

  1. a라는 이름의 스칼라 텐서를 생성합니다. requires_grad=True 매개변수를 사용하여 a에 대한 경사도(gradient)가 계산되도록 설정합니다.
  2. 이전에 정의한 f(a) 함수를 호출하여 a를 입력으로 사용하고, 이를 d에 할당합니다.
  3. backward 메서드를 사용하여 d의 경사도를 계산합니다. 이것은 연쇄 법칙(chain rule)을 사용하여 d를 a에 대한 함수로 간주하고, d의 a에 대한 경사도를 계산합니다.

즉, 코드는 a에서 f(a)로의 계산 그래프를 구성하고, f(a)의 결과 d에 대한 a의 경사도를 계산합니다. 이렇게 하면 a.grad에 a에 대한 경사도가 저장됩니다.

 

Even though our function f is, for demonstration purposes, a bit contrived, its dependence on the input is quite simple: it is a linear function of a with piecewise defined scale. As such, f(a) / a is a vector of constant entries and, moreover, f(a) / a needs to match the gradient of f(a) with respect to a.

 

함수 f는 데모 목적으로 약간 인위적으로 만들어졌지만 입력에 대한 의존성은 매우 간단합니다. 부분적으로 정의된 스케일을 사용하는 a의 선형 함수입니다. 따라서 f(a) / a는 상수 항목으로 구성된 벡터이며 더욱이 f(a) / a는 a에 대한 f(a)의 기울기와 일치해야 합니다.

 

a.grad == d / a

이 코드는 a.grad와 d를 a로 나눈 값인 d / a를 비교하여 결과를 확인합니다.

a.grad는 a에 대한 경사도(gradient)를 나타내며, 이 값은 .backward()를 호출하여 계산됩니다.

d는 f(a) 함수의 결과를 나타내는 변수입니다.

따라서, a.grad는 d를 a로 미분한 값이 됩니다. 코드는 이 계산된 경사도 a.grad와 d / a를 비교하여 두 값이 동일한지 확인합니다.

이 비교가 참인 경우, 이는 PyTorch의 자동 미분이 제대로 작동하고 있다는 것을 의미합니다. 즉, d를 a로 미분한 결과가 d / a와 일치한다는 것을 의미합니다.

tensor(True)

 

Dynamic control flow is very common in deep learning. For instance, when processing text, the computational graph depends on the length of the input. In these cases, automatic differentiation becomes vital for statistical modeling since it is impossible to compute the gradient a priori.

 

동적 제어 흐름은 딥러닝에서 매우 일반적입니다. 예를 들어 텍스트를 처리할 때 계산 그래프는 입력 길이에 따라 달라집니다. 이러한 경우 사전에 기울기를 계산하는 것이 불가능하기 때문에 통계 모델링에 자동 미분이 필수적입니다.

 

2.5.5. Discussion

You have now gotten a taste of the power of automatic differentiation. The development of libraries for calculating derivatives both automatically and efficiently has been a massive productivity booster for deep learning practitioners, liberating them so they can focus on less menial. Moreover, autograd lets us design massive models for which pen and paper gradient computations would be prohibitively time consuming. Interestingly, while we use autograd to optimize models (in a statistical sense) the optimization of autograd libraries themselves (in a computational sense) is a rich subject of vital interest to framework designers. Here, tools from compilers and graph manipulation are leveraged to compute results in the most expedient and memory-efficient manner.

 

이제 자동 미분의 힘을 맛보셨습니다. 도함수를 자동으로 효율적으로 계산하기 위한 라이브러리의 개발은 딥 러닝 실무자들의 생산성을 대폭 향상시켜 그들이 덜 천박한 일에 집중할 수 있도록 해방시켜 주었습니다. 게다가, autograd를 사용하면 펜과 종이의 그라디언트 계산에 엄청난 시간이 소요되는 대규모 모델을 설계할 수 있습니다. 흥미롭게도, 우리가 모델을 최적화하기 위해(통계적 의미에서) autograd를 사용하는 반면, autograd 라이브러리 자체의 최적화(계산적 의미에서)는 프레임워크 설계자들에게 매우 중요한 주제입니다. 여기서는 컴파일러 도구와 그래프 조작을 활용하여 가장 편리하고 메모리 효율적인 방식으로 결과를 계산합니다.

 

For now, try to remember these basics: (i) attach gradients to those variables with respect to which we desire derivatives; (ii) record the computation of the target value; (iii) execute the backpropagation function; and (iv) access the resulting gradient.

 

지금은 다음 기본 사항을 기억해 보십시오. (i) 도함수를 원하는 변수에 기울기를 적용합니다. (ii) 목표값의 계산을 기록하고; (iii) 역전파 기능을 실행합니다. (iv) 결과 그래디언트에 액세스합니다.

 

2.5.6. Exercises

 

 

 

 

 

 

 

반응형


반응형

https://d2l.ai/chapter_preliminaries/calculus.html

 

2.4. Calculus — Dive into Deep Learning 1.0.3 documentation

 

d2l.ai

 

2.4. Calculus

 

For a long time, how to calculate the area of a circle remained a mystery. Then, in Ancient Greece, the mathematician Archimedes came up with the clever idea to inscribe a series of polygons with increasing numbers of vertices on the inside of a circle (Fig. 2.4.1). For a polygon with n vertices, we obtain n triangles. The height of each triangle approaches the radius r as we partition the circle more finely. At the same time, its base approaches 2 π r/n, since the ratio between arc and secant approaches 1 for a large number of vertices. Thus, the area of the polygon approaches n⋅r⋅1/2(2 π r /n)= π r **2.

 

오랫동안 원의 넓이를 계산하는 방법은 미스터리로 남아 있었습니다. 그런 다음 고대 그리스의 수학자 아르키메데스는 원 내부에 정점 수가 증가하는 일련의 다각형을 새기는 영리한 아이디어를 생각해 냈습니다(그림 2.4.1). n개의 꼭지점을 가진 다각형의 경우 n개의 삼각형을 얻습니다. 원을 더 세밀하게 분할할수록 각 삼각형의 높이는 반지름 r에 가까워집니다. 동시에, 그 밑변은 2π r/n에 가까워집니다. 왜냐하면 호와 시컨트 사이의 비율이 많은 수의 꼭지점에 대해 1에 가까워지기 때문입니다. 따라서 다각형의 면적은 n⋅r⋅1/2(2 π r /n)= π r **2에 가까워집니다.

 

Fig. 2.4.1&nbsp; Finding the area of a circle as a limit procedure.

 

This limiting procedure is at the root of both differential calculus and integral calculus. The former can tell us how to increase or decrease a function’s value by manipulating its arguments. This comes in handy for the optimization problems that we face in deep learning, where we repeatedly update our parameters in order to decrease the loss function. Optimization addresses how to fit our models to training data, and calculus is its key prerequisite. However, do not forget that our ultimate goal is to perform well on previously unseen data. That problem is called generalization and will be a key focus of other chapters.

 

이 제한 절차는 미분 계산 calculus  과 적분 계산 integral calculus 의 기초입니다. 전자는 인수를 조작하여 함수의 값을 늘리거나 줄이는 방법을 알려줄 수 있습니다. 이는 손실 함수를 줄이기 위해 매개변수를 반복적으로 업데이트하는 딥러닝에서 직면하는 최적화 문제에 유용합니다. 최적화는 모델을 훈련 데이터에 맞추는 방법을 다루며, 미적분학은 핵심 전제 조건입니다. 그러나 우리의 궁극적인 목표는 이전에 볼 수 없었던 데이터를 잘 활용하는 것임을 잊지 마십시오. 이 문제를 일반화 generalization  라고 하며 다른 장에서 중점적으로 다룰 것입니다.

 

%matplotlib inline
import numpy as np
from matplotlib_inline import backend_inline
from d2l import torch as d2l

 

주어진 코드는 Python 코드로, Jupyter Notebook 또는 IPython 환경에서 사용됩니다. 코드는 다음과 같은 작업을 수행합니다:

  1. %matplotlib inline: 이 코드는 Jupyter Notebook에서 사용하는 "매직 명령어" 중 하나로, 그래프나 그림을 출력할 때 그림을 노트북 내부에 표시하도록 설정하는 역할을 합니다. 이렇게 하면 그림이 노트북 내에서 바로 볼 수 있습니다.
  2. import numpy as np: NumPy 라이브러리를 불러옵니다. NumPy는 파이썬의 수치 계산과 배열 처리에 유용한 라이브러리로, 주로 다차원 배열과 관련된 작업에 사용됩니다. np는 일반적으로 NumPy의 별칭으로 사용됩니다.
  3. from matplotlib_inline import backend_inline: matplotlib_inline 라이브러리에서 backend_inline 모듈을 가져옵니다. 이 모듈은 Matplotlib 그래프를 노트북 내에서 인라인으로 표시할 때 사용됩니다.
  4. from d2l import torch as d2l: D2L (Dive into Deep Learning) 라이브러리에서 torch 모듈을 가져온 다음, 이 모듈을 d2l이라는 별칭으로 사용합니다. D2L은 딥러닝 및 머신러닝 교육과 관련된 코드와 자료를 제공하는 라이브러리로, torch 모듈은 PyTorch를 기반으로 한 딥러닝 코드를 작성하기 위해 사용됩니다.

이 코드는 주로 딥러닝 및 머신러닝 관련 작업을 수행하고 시각화를 위한 환경 설정을 위해 사용됩니다. 또한 이 코드는 Jupyter Notebook 또는 IPython 환경에서 노트북 내에서 그래프 및 그림을 표시하기 위한 설정을 제공합니다.

 

2.4.1. Derivatives and Differentiation

Put simply, a derivative is the rate of change in a function with respect to changes in its arguments. Derivatives can tell us how rapidly a loss function would increase or decrease were we to increase or decrease each parameter by an infinitesimally small amount. Formally, for functions ƒ : , that map from scalars to scalars, the derivative of ƒ  at a point x is defined as

 

간단히 말해서, 도함수 derivative  는 인수의 변화에 대한 함수의 변화율입니다. Derivatives  은 각 매개변수를 극소량씩 늘리거나 줄이면 손실 함수가 얼마나 빠르게 증가하거나 감소하는지 알려줄 수 있습니다. 공식적으로, 스칼라에서 스칼라로 매핑되는 함수 f : ℝ → ℝ에 대해 점 x에서 의 도함수는 다음과 같이 정의됩니다.

 

 

lim (극한) 이란?

 

In mathematics, "lim" is an abbreviation for the limit. The limit is a fundamental concept in calculus and analysis that describes the behavior of a function or sequence as it approaches a certain value or approaches infinity or negative infinity.

 

수학에서 "lim"은 "극한(limit)"의 줄임말로 사용됩니다. 극한은 미적분학과 해석학에서 중요한 개념으로, 함수나 수열이 특정한 값을 향하거나 무한대 또는 음의 무한대를 향하는 과정을 기술합니다.

 

The limit of a function f(x) as x approaches a particular value, say 'a', is denoted as:

 

특정 값 'a'로 접근할 때 함수 f(x)의 극한은 다음과 같이 나타납니다:

 

lim (x → a) f(x)

 

This notation represents the value that the function approaches as x gets closer and closer to 'a'. In other words, it describes what happens to the function as x gets infinitely close to 'a'.

 

이 표기법은 x가 'a'에 점점 가까워질 때 함수가 어떻게 동작하는지를 설명합니다. 다시 말해, x가 'a'에 무한히 가까워질 때 함수가 어떻게 행동하는지를 나타냅니다.

 

Limits are used to study the behavior of functions, analyze continuity, and find derivatives and integrals in calculus. They are a crucial tool for understanding the fundamental properties and characteristics of functions, especially in the context of differential and integral calculus. The concept of limits is also essential in real analysis, where it is used to rigorously define continuity, convergence, and other key mathematical concepts.

 

극한은 미적분학에서 함수의 행동을 연구하고 연속성을 분석하며, 미분 및 적분을 찾는 데 사용되는 중요한 도구입니다. 극한은 함수의 기본적인 특성과 특징을 이해하는 데 필수적이며, 특히 미분 및 적분 미적분학의 맥락에서 중요합니다. 극한의 개념은 또한 해석학에서 사용되어 연속성, 수렴 및 기타 주요 수학적 개념을 엄밀하게 정의하는 데 필수적입니다.

 

 

This term on the right hand side is called a limit and it tells us what happens to the value of an expression as a specified variable approaches a particular value. This limit tells us what the ratio between a perturbation  and the change in the function value  f(x+ℎ)−  f(x) converges to as we shrink its size to zero.

 

오른쪽에 있는 용어는 극한 limit  이라고 하며 지정된 변수가 특정 값에 접근할 때 표현식의 값에 어떤 일이 발생하는지 알려줍니다. 이 극한 limit 는 크기를 0으로 줄이면 섭동 perturbation  ℎ와 함수 값 f(x+ℎ)− f(x)의 변화 사이의 비율이 수렴되는 것을 알려줍니다.

 

When f ′(x) exists, f  is said to be differentiable at x; and when f ′(x) exists for all x on a set, e.g., the interval [a,b], we say that f  is differentiable on this set. Not all functions are differentiable, including many that we wish to optimize, such as accuracy and the area under the receiving operating characteristic (AUC). However, because computing the derivative of the loss is a crucial step in nearly all algorithms for training deep neural networks, we often optimize a differentiable surrogate instead.

 

f ′(x)가 존재할 때 f는 x에서 미분 가능하다고 합니다. 그리고 f ′(x)가 세트의 모든 x에 대해 존재할 때(예: 구간 [a,b]), 우리는 f가 이 세트에서 미분 가능하다고 말합니다. 정확도, 수신 작동 특성(AUC) 하의 영역 등 최적화하려는 많은 기능을 포함하여 모든 기능이 차별화 가능한 것은 아닙니다. 그러나 손실의 도함수 derivative  를 계산하는 것은 심층 신경망 훈련을 위한 거의 모든 알고리즘에서 중요한 단계이기 때문에 대신 미분 가능한 대리자를 최적화하는 경우가 많습니다.

 

We can interpret the derivative f ′(x) as the instantaneous rate of change of f(x) with respect to x. Let’s develop some intuition with an example. Define u= f(x)=3x**2 − 4x.

 

도함수 f'(x)를 x에 대한 f(x)의 순간 변화율로 해석할 수 있습니다. 예를 들어 직관력을 키워 봅시다. u= f(x)=3x**2−4x를 정의합니다.

 

def f(x):
    return 3 * x ** 2 - 4 * x

주어진 코드는 파이썬에서 정의한 함수를 설명하고 있습니다. 함수 이름은 f이며, 주어진 입력(x)에 대한 출력을 계산하는 방법을 정의합니다. 함수의 내용은 다음과 같이 나타납니다:

 

이 코드의 설명은 다음과 같습니다:

  1. def f(x):: def 키워드는 파이썬 함수를 정의하기 위해 사용되며, 함수 이름인 f를 정의합니다. 괄호 안에 있는 x는 함수의 입력 매개변수(parameter)입니다. 이 함수는 x라는 입력을 받아서 계산을 수행하고 결과를 반환합니다.
  2. return 3 * x ** 2 - 4 * x: 이 줄은 함수의 본문(body)을 정의합니다. 주어진 x를 사용하여 함수가 수행할 계산을 기술합니다. 여기서는 입력 x를 이용하여 다음의 계산을 수행합니다:
    • x를 제곱한 후 3을 곱하고,
    • x를 4 곱한 다음 뺍니다.

이 함수는 주어진 x 값에 대한 결과를 반환합니다. 예를 들어, f(2)를 호출하면 x에 2를 대입하여 3 * 2 ** 2 - 4 * 2를 계산하고, 결과로 -4를 반환할 것입니다.

이 함수를 사용하면 주어진 입력값 x에 대한 함수의 출력을 계산할 수 있으며, 이러한 함수 정의는 미적분 및 수학적 모델링과 같은 다양한 수학적 응용 분야에서 사용됩니다.

 

Setting x=1, we see that f(x+ℎ)− f(x)/ℎ approaches 2 as  approaches 0. While this experiment lacks the rigor of a mathematical proof, we can quickly see that indeed f′(1)=2.

 

x=1로 설정하면 ℎ가 0에 가까워짐에 따라 f(x+ℎ)− f(x)/ℎ도 2에 가까워지는 것을 알 수 있습니다. 이 실험에는 수학적 증명의 엄격함이 부족하지만, 우리는 실제로 'f′(1)=2'라는 것을 빨리 알 수 있습니다.

 

for h in 10.0**np.arange(-1, -6, -1):
    print(f'h={h:.5f}, numerical limit={(f(1+h)-f(1))/h:.5f}')

주어진 코드는 파이썬의 반복문을 사용하여 함수 f(x)의 수치 미분(numerical derivative)을 계산하고 출력하는 작업을 수행합니다. 코드는 h 값의 범위를 설정하고, 각 h에 대해 f(x) 함수의 미분 값을 계산하고 출력합니다. 아래는 코드의 설명입니다:

  1. for h in 10.0**np.arange(-1, -6, -1): 이 줄은 h라는 변수를 사용하여 반복을 설정합니다. np.arange(-1, -6, -1)는 -1에서 -6까지 1씩 감소하는 수열을 생성합니다. 그리고 10.0**를 사용하여 각 수열의 값에 10의 지수를 적용하여 h 값을 생성합니다. 이렇게 함으로써 h는 0.1, 0.01, 0.001, 0.0001, 0.00001의 값을 순서대로 가지게 됩니다.
  2. print(f'h={h:.5f}, numerical limit={(f(1+h)-f(1))/h:.5f}'): 이 줄은 각 h 값에 대한 미분 값을 계산하고 출력합니다.
    • h={h:.5f}: h의 값을 소수 다섯 번째 자리까지 출력합니다.
    • numerical limit={(f(1+h)-f(1))/h:.5f}: f(1+h)에서 f(1)을 뺀 다음 h로 나눈 값을 소수 다섯 번째 자리까지 출력합니다. 이 값은 f(x) 함수의 수치 미분을 나타내며, h 값이 작을수록 정확한 미분 값을 얻을 수 있습니다.

따라서 이 코드는 서로 다른 h 값에 대해 f(x) 함수의 수치 미분 값을 계산하고 출력하여, h 값이 작아질수록 정확한 미분 값을 얻는 과정을 보여줍니다. 이러한 과정은 미분 근사를 이해하고 미분 값을 추정하는 데 사용됩니다.

 

h=0.10000, numerical limit=2.30000
h=0.01000, numerical limit=2.03000
h=0.00100, numerical limit=2.00300
h=0.00010, numerical limit=2.00030
h=0.00001, numerical limit=2.00003

 

There are several equivalent notational conventions for derivatives. Given y=f(x), the following expressions are equivalent:

 

derivatives 에 대한 몇 가지 동등한 표기 규칙이 있습니다. y=f(x)라고 가정하면 다음 표현식은 동일합니다.

 

 

where the symbols d/dx and D are differentiation operators. Below, we present the derivatives of some common functions:

 

여기서 기호 d/dx와 D는 미분 연산자 differentiation operators 입니다. 아래에서는 몇 가지 일반적인 함수의   derivatives 을 제시합니다.

 

 

Functions composed from differentiable functions are often themselves differentiable. The following rules come in handy for working with compositions of any differentiable functions f and g, and constant C.

 

미분 가능한 함수로 구성된 함수는 종종 그 자체로 미분 가능합니다. 다음 규칙은 미분 가능한 함수 f와 g 및 상수 C의 구성 작업에 유용합니다.

 

Using this, we can apply the rules to find the derivative of 3x**2 − 4x via

 

이를 사용하여 다음을 통해 3x**2 − 4x의 도함수를 찾는 규칙을 적용할 수 있습니다.

 

Plugging in x=1 shows that, indeed, the derivative equals 2 at this location. Note that derivatives tell us the slope of a function at a particular location.

 

x=1을 대입하면 실제로 이 위치에서 도함수는 2와 같다는 것을 알 수 있습니다. 도함수 derivatives  는 특정 위치에서 함수의 기울기를 알려줍니다.

 

2.4.2. Visualization Utilities

 

We can visualize the slopes of functions using the matplotlib library. We need to define a few functions. As its name indicates, use_svg_display tells matplotlib to output graphics in SVG format for crisper images. The comment #@save is a special modifier that allows us to save any function, class, or other code block to the d2l package so that we can invoke it later without repeating the code, e.g., via d2l.use_svg_display().

 

matplotlib 라이브러리를 사용하여 함수의 기울기를 시각화할 수 있습니다. 몇 가지 함수를 정의해야 합니다. 이름에서 알 수 있듯이 use_svg_display는 matplotlib에게 보다 선명한 이미지를 위해 SVG 형식으로 그래픽을 출력하도록 지시합니다. #@save 주석은 함수, 클래스 또는 기타 코드 블록을 d2l 패키지에 저장하여 나중에 코드를 반복하지 않고(예: d2l.use_svg_display()를 통해) 호출할 수 있도록 하는 특수 수정자 special modifier 입니다.

 

def use_svg_display():  #@save
    """Use the svg format to display a plot in Jupyter."""
    backend_inline.set_matplotlib_formats('svg')

주어진 코드는 Jupyter Notebook 환경에서 그래프나 그림을 SVG(Scalable Vector Graphics) 형식으로 표시하는 함수를 정의하는 파이썬 코드입니다. 아래는 코드의 설명입니다:

  1. def use_svg_display():: 이 코드는 use_svg_display라는 이름의 함수를 정의합니다. 이 함수는 그래프나 그림을 SVG 형식으로 표시하도록 설정하는 역할을 합니다.
  2. backend_inline.set_matplotlib_formats('svg'): 이 함수 내에서는 backend_inline 라이브러리의 set_matplotlib_formats 함수를 호출합니다. 이 함수는 Matplotlib 그래프의 출력 형식을 설정하는 역할을 합니다. 여기서 'svg'를 사용하여 SVG 형식으로 그래프를 설정합니다. SVG 형식은 확대하더라도 이미지가 깨지지 않고 고품질로 표시되며, Jupyter Notebook 환경에서 렌더링할 때 특히 유용합니다.

따라서 이 코드는 Jupyter Notebook 환경에서 그래프를 그릴 때 그래프의 형식을 SVG로 설정하여, 그래프가 화면에 고해상도로 표시되도록 하는 함수를 정의하고 있습니다. 이 함수를 사용하면 Jupyter Notebook에서 품질 좋은 그래프를 생성하고 시각화할 때 유용합니다.

 

 

Conveniently, we can set figure sizes with set_figsize. Since the import statement from matplotlib import pyplot as plt was marked via #@save in the d2l package, we can call d2l.plt.

 

편리하게도 set_figsize를 사용하여 그림 크기를 설정할 수 있습니다. matplotlib import pyplot as plt의 import 문이 d2l 패키지의 #@save를 통해 표시되었으므로 d2l.plt를 호출할 수 있습니다.

 

def set_figsize(figsize=(3.5, 2.5)):  #@save
    """Set the figure size for matplotlib."""
    use_svg_display()
    d2l.plt.rcParams['figure.figsize'] = figsize

주어진 코드는 Matplotlib를 사용하여 그림의 크기를 설정하는 함수를 정의하는 파이썬 코드입니다. 아래는 코드의 설명입니다:

  1. def set_figsize(figsize=(3.5, 2.5)):: 이 코드는 set_figsize라는 이름의 함수를 정의합니다. 이 함수는 그림의 크기를 설정하는 역할을 합니다. figsize 매개변수를 사용하여 원하는 그림 크기를 지정할 수 있으며, 기본값은 (3.5, 2.5)로 설정되어 있습니다.
  2. use_svg_display(): use_svg_display 함수를 호출하여 그래프를 SVG 형식으로 표시하도록 설정합니다. 이전 질문에 설명한 대로, SVG 형식은 고품질 그래프를 표시하는 데 유용합니다.
  3. d2l.plt.rcParams['figure.figsize'] = figsize: Matplotlib의 rcParams를 사용하여 그림의 크기를 설정합니다. figsize 매개변수에 지정된 크기로 그림을 설정합니다. 이것은 Matplotlib 그래프의 기본 크기를 변경하는 것으로, figsize를 통해 그림의 가로와 세로 크기를 지정할 수 있습니다.

따라서 이 코드는 Matplotlib를 사용하여 그림의 크기를 설정하는 함수를 정의하고 있으며, 그림 크기를 사용자 지정하거나 기본 설정을 변경하는 데 사용됩니다. 이를 통해 생성되는 그림은 원하는 크기로 표시되며, 시각화 결과를 조절할 수 있습니다.

 

The set_axes function can associate axes with properties, including labels, ranges, and scales.

 

set_axes 함수는 축을 레이블, 범위, 스케일 등의 속성과 연결할 수 있습니다.

 

#@save
def set_axes(axes, xlabel, ylabel, xlim, ylim, xscale, yscale, legend):
    """Set the axes for matplotlib."""
    axes.set_xlabel(xlabel), axes.set_ylabel(ylabel)
    axes.set_xscale(xscale), axes.set_yscale(yscale)
    axes.set_xlim(xlim),     axes.set_ylim(ylim)
    if legend:
        axes.legend(legend)
    axes.grid()

주어진 코드는 Matplotlib 그래프의 축(axis) 설정을 수행하는 함수를 설명하는 파이썬 코드입니다. 이 함수를 사용하면 그래프의 축 레이블, 범위, 스케일, 범례, 그리드 등을 설정할 수 있습니다. 아래는 코드의 설명입니다:

  1. def set_axes(axes, xlabel, ylabel, xlim, ylim, xscale, yscale, legend):: 이 코드는 set_axes라는 이름의 함수를 정의합니다. 이 함수는 Matplotlib 그래프의 축 설정을 담당합니다. 함수는 다음과 같은 매개변수를 사용합니다:
    • axes: 설정할 축(axis) 객체.
    • xlabel: x-축 레이블.
    • ylabel: y-축 레이블.
    • xlim: x-축 범위.
    • ylim: y-축 범위.
    • xscale: x-축 스케일.
    • yscale: y-축 스케일.
    • legend: 범례 설정.
  2. axes.set_xlabel(xlabel), axes.set_ylabel(ylabel): x-축과 y-축의 레이블을 설정합니다.
  3. axes.set_xscale(xscale), axes.set_yscale(yscale): x-축과 y-축의 스케일을 설정합니다. 스케일은 "linear" 또는 "log"와 같은 값으로 설정할 수 있으며, 스케일을 변경하면 축의 데이터 표시 방식이 변경됩니다.
  4. axes.set_xlim(xlim), axes.set_ylim(ylim): x-축과 y-축의 범위를 설정합니다. 범위는 그래프에서 보여질 데이터의 최솟값과 최댓값을 지정합니다.
  5. if legend: axes.legend(legend): 만약 legend 매개변수가 주어지면 그래프에 범례를 추가합니다. 범례는 그래프에서 각 선 또는 데이터 시리즈를 설명하는 레이블을 표시하는 데 사용됩니다.
  6. axes.grid(): 그리드를 추가하여 그래프에 격자 눈금을 표시합니다. 격자 눈금은 데이터의 위치를 더 쉽게 파악할 수 있도록 도와줍니다.

이 함수를 사용하면 Matplotlib 그래프의 축을 사용자 정의하고, 그래프를 보다 명확하게 표시하는 데 도움이 됩니다.

 

With these three functions, we can define a plot function to overlay multiple curves. Much of the code here is just ensuring that the sizes and shapes of inputs match.

 

이 세 가지 함수를 사용하면 여러 곡선을 오버레이하는 플롯 함수를 정의할 수 있습니다. 여기 코드의 대부분은 입력의 크기와 모양이 일치하는지 확인하는 것입니다.

 

#@save
def plot(X, Y=None, xlabel=None, ylabel=None, legend=[], xlim=None,
         ylim=None, xscale='linear', yscale='linear',
         fmts=('-', 'm--', 'g-.', 'r:'), figsize=(3.5, 2.5), axes=None):
    """Plot data points."""

    def has_one_axis(X):  # True if X (tensor or list) has 1 axis
        return (hasattr(X, "ndim") and X.ndim == 1 or isinstance(X, list)
                and not hasattr(X[0], "__len__"))

    if has_one_axis(X): X = [X]
    if Y is None:
        X, Y = [[]] * len(X), X
    elif has_one_axis(Y):
        Y = [Y]
    if len(X) != len(Y):
        X = X * len(Y)

    set_figsize(figsize)
    if axes is None:
        axes = d2l.plt.gca()
    axes.cla()
    for x, y, fmt in zip(X, Y, fmts):
        axes.plot(x,y,fmt) if len(x) else axes.plot(y,fmt)
    set_axes(axes, xlabel, ylabel, xlim, ylim, xscale, yscale, legend)

주어진 코드는 데이터 포인트를 그리는 함수를 설명하는 파이썬 코드입니다. 이 함수를 사용하면 데이터 포인트를 그래프로 표시할 수 있으며, 그래프의 모양, 축, 범위, 스케일, 범례, 그리드 등을 설정할 수 있습니다. 아래는 코드의 설명입니다:

  1. plot(X, Y=None, xlabel=None, ylabel=None, legend=[], xlim=None, ylim=None, xscale='linear', yscale='linear', fmts=('-', 'm--', 'g-.', 'r:'), figsize=(3.5, 2.5), axes=None): 이 함수는 데이터 포인트를 그리는 함수로, 다양한 설정 옵션을 제공합니다. 이 함수는 다음과 같은 매개변수를 사용합니다:
    • X: x-축에 대한 데이터 포인트 또는 데이터 포인트 리스트.
    • Y: y-축에 대한 데이터 포인트 또는 데이터 포인트 리스트. 기본값은 None이며, 이 경우 X가 y-축 데이터로 사용됩니다.
    • xlabel: x-축 레이블.
    • ylabel: y-축 레이블.
    • legend: 범례 설정. 여러 데이터 시리즈에 대한 범례를 지정할 수 있습니다.
    • xlim: x-축 범위 설정.
    • ylim: y-축 범위 설정.
    • xscale: x-축 스케일 설정. 기본값은 "linear"로 설정되어 있습니다.
    • yscale: y-축 스케일 설정. 기본값은 "linear"로 설정되어 있습니다.
    • fmts: 그래프의 스타일 설정. 여러 다른 선 스타일을 제공하며, 기본값은 ('-', 'm--', 'g-.', 'r:')로 설정되어 있습니다.
    • figsize: 그래프의 크기 설정. 기본값은 (3.5, 2.5)로 설정되어 있습니다.
    • axes: 그래프를 그릴 Matplotlib 축 객체. 기본값은 None으로 설정되어 있으며, 필요한 경우 사용자가 직접 설정할 수 있습니다.
  2. def has_one_axis(X): 이 내부 함수는 주어진 데이터(X)가 1차원 배열 또는 리스트인지 확인합니다. 1차원이면 True를 반환하고, 그렇지 않으면 False를 반환합니다.
  3. if has_one_axis(X): X = [X]: 만약 X가 1차원 배열이라면, X를 원소가 하나인 리스트로 변환합니다. 이렇게 함으로써 여러 데이터 시리즈를 다룰 때 편리하게 처리할 수 있습니다.
  4. if Y is None: X, Y = [[]] * len(X), X: 만약 Y가 주어지지 않았다면, X를 y-축 데이터로 사용하기 위해 Y를 X로 설정합니다. 그리고 X를 원소가 비어 있는 리스트로 설정합니다.
  5. set_figsize(figsize): 그래프의 크기를 figsize에 지정된 크기로 설정하는 함수를 호출합니다.
  6. if axes is None: axes = d2l.plt.gca(): 만약 축(axes)가 주어지지 않았다면, 현재 활성화된 Matplotlib 축 객체를 가져와서 사용합니다.
  7. axes.cla(): 축 객체를 초기화하여 이전에 그려진 그래프를 지우고 새로운 그래프를 그릴 준비를 합니다.
  8. for x, y, fmt in zip(X, Y, fmts): axes.plot(x, y, fmt) if len(x) else axes.plot(y, fmt): X와 Y에 대한 데이터 시리즈와 스타일(fmt)을 순회하면서 그래프를 그립니다. 만약 x 데이터 시리즈가 비어 있다면(len(x) == 0), y 데이터 시리즈를 그래프로 그립니다.
  9. set_axes(axes, xlabel, ylabel, xlim, ylim, xscale, yscale, legend): set_axes 함수를 호출하여 축의 레이블, 범위, 스케일, 범례, 그리드 등을 설정합니다.

이 함수를 사용하면 주어진 데이터 포인트를 그래프로 시각화하고, 그래프의 모양과 설정을 유연하게 조절할 수 있습니다. 이는 데이터 시각화 및 그래프 생성에 유용한 도구입니다.

 

Now we can plot the function u=f(x) and its tangent line y=2x−3 at x=1, where the coefficient 2 is the slope of the tangent line.

 

이제 x=1에서 함수 u=f(x)와 접선 y=2x−3을 그릴 수 있습니다. 여기서 계수 2는 접선의 기울기입니다.

 

x = np.arange(0, 3, 0.1)
plot(x, [f(x), 2 * x - 3], 'x', 'f(x)', legend=['f(x)', 'Tangent line (x=1)'])

주어진 코드는 주어진 범위에서 함수 f(x)와 x=1에서의 접선을 그래프로 표시하는 예제 코드입니다. 아래는 코드의 설명입니다:

  1. x = np.arange(0, 3, 0.1): 이 코드는 0에서 3까지의 범위에서 0.1 간격으로 숫자를 생성하여 x에 할당합니다. 이렇게 생성된 x 값은 함수 f(x)와 접선을 그래프로 그릴 때 x-축 값으로 사용됩니다.
  2. plot(x, [f(x), 2 * x - 3], 'x', 'f(x)', legend=['f(x)', 'Tangent line (x=1)']): plot 함수를 호출하여 그래프를 그립니다. 이때, 다음 매개변수들이 사용됩니다:
    • x: x-축 데이터로 사용될 범위(0에서 3까지의 값).
    • [f(x), 2 * x - 3]: y-축 데이터로 사용될 값. 여기서 f(x)는 함수 f(x)의 값이고, 2 * x - 3은 x=1에서의 접선의 방정식입니다.
    • 'x': x-축 레이블로 사용될 문자열.
    • 'f(x)': y-축 레이블로 사용될 문자열.
    • legend=['f(x)', 'Tangent line (x=1)']: 범례 설정으로, 각 데이터 시리즈에 대한 설명을 제공합니다.

이 코드는 x 범위에서 f(x) 함수와 x=1에서의 접선을 그래프로 그립니다. 이를 통해 함수와 해당 지점에서의 기울기를 시각화할 수 있습니다.

 

2.4.3. Partial Derivatives and Gradients

Thus far, we have been differentiating functions of just one variable. In deep learning, we also need to work with functions of many variables. We briefly introduce notions of the derivative that apply to such multivariate functions.

 

지금까지 우리는 단 하나의 변수에 대한 함수를 차별화해 왔습니다. 딥러닝에서는 다양한 변수의 함수를 다루어야 합니다. 우리는 그러한 다변량 함수에 적용되는 미분의 개념을 간략하게 소개합니다.

 

Let y=f(x1,x2,…,xn) be a function with n variables. The partial derivative of y with respect to its i th parameter xi is

 

y=f(x1,x2,…,xn)을 n개의 변수를 갖는 함수로 둡니다. i 번째 매개변수 xi에 대한 y의 편도함수 multivariate functions는 다음과 같습니다.

 

 

To calculate ∂y/ xi, we can treat x1,…,xi−1,xi+1,…,xn as constants and calculate the derivative of y with respect to xi. The following notational conventions for partial derivatives are all common and all mean the same thing:

 

∂y/ ∂xi를 계산하려면 x1,…,xi−1,xi+1,…,xn을 상수로 처리하고 xi에 대한 y의 도함수를 계산할 수 있습니다. 부분 도함수에 대한 다음 표기 규칙은 모두 공통적이며 모두 같은 의미입니다.

 

 

We can concatenate partial derivatives of a multivariate function with respect to all its variables to obtain a vector that is called the gradient of the function. Suppose that the input of function f: ℝ**n  is an n-dimensional vector x=[x1,x2,…,xn]**⊤ and the output is a scalar. The gradient of the function f with respect to x is a vector of n partial derivatives:

 

모든 변수에 대해 다변량 함수의 부분 도함수를 연결하여 함수의 기울기라고 하는 벡터를 얻을 수 있습니다. 함수 f: ℝ**n→ ℝ의 입력이 n차원 벡터 x=[x1,x2,…,xn]**⊤이고 출력이 스칼라라고 가정합니다. x에 대한 함수 f의 기울기는 n 편도함수의 벡터입니다.

 

When there is no ambiguity, xf(x) is typically replaced by ∇f(x). The following rules come in handy for differentiating multivariate functions:

 

모호성 ambiguity 이 없으면 ∇xf(x)는 일반적으로 ∇f(x)로 대체됩니다. 다변량 함수를 차별화하는 데 다음 규칙이 유용합니다.

 

 

Similarly, for any matrix X, we have x|X|2F=2X.

 

마찬가지로, 임의의 행렬 X에 대해 ∇x|X|2F=2X가 됩니다.

 

2.4.4. Chain Rule

In deep learning, the gradients of concern are often difficult to calculate because we are working with deeply nested functions (of functions (of functions…)). Fortunately, the chain rule takes care of this. Returning to functions of a single variable, suppose that y=f(g(x)) and that the underlying functions y=f(u) and u=g(x) are both differentiable. The chain rule states that

 

딥 러닝에서는 깊게 중첩된 함수(함수 중(함수…))로 작업하기 때문에 관심 기울기를 계산하기 어려운 경우가 많습니다. 다행히도 체인 규칙이 이를 처리합니다. 단일 변수의 함수로 돌아가서, y=f(g(x))와 기본 함수 y=f(u) 및 u=g(x)가 모두 미분 가능하다고 가정합니다. 체인 규칙은 다음과 같이 명시합니다.

 

 

Turning back to multivariate functions, suppose that y=f(u) has variables u1,u2,…,un, where each ui=gi(X) has variables x1,x2,…,xn, i.e., u=g(x). Then the chain rule states that

 

다변량 함수로 돌아가서, y=f(u)에 변수 u1,u2,…,un이 있다고 가정합니다. 여기서 각 ui=gi(X)에는 변수 x1,x2,…,xn이 있습니다. 즉, u=g(x) . 그런 다음 체인 규칙은 다음과 같이 명시합니다.

 

where A∈ n×m is a matrix that contains the derivative of vector u with respect to vector x. Thus, evaluating the gradient requires computing a vector–matrix product. This is one of the key reasons why linear algebra is such an integral building block in building deep learning systems.

 

여기서 A∈ ℝn×m은 벡터 x에 대한 벡터 u의 도함수를 포함하는 행렬입니다. 따라서 기울기를 평가하려면 벡터-행렬 곱을 계산해야 합니다. 이것이 선형 대수학이 딥 러닝 시스템을 구축하는 데 필수적인 구성 요소인 주요 이유 중 하나입니다.

 

2.4.5. Discussion

While we have just scratched the surface of a deep topic, a number of concepts already come into focus: first, the composition rules for differentiation can be applied routinely, enabling us to compute gradients automatically. This task requires no creativity and thus we can focus our cognitive powers elsewhere. Second, computing the derivatives of vector-valued functions requires us to multiply matrices as we trace the dependency graph of variables from output to input. In particular, this graph is traversed in a forward direction when we evaluate a function and in a backwards direction when we compute gradients. Later chapters will formally introduce backpropagation, a computational procedure for applying the chain rule.

 

우리는 단지 깊은 주제의 표면만 긁었을 뿐이지만 이미 여러 가지 개념에 초점을 맞추고 있습니다. 첫째, 미분을 위한 합성 규칙을 일상적으로 적용하여 기울기를 자동으로 계산할 수 있습니다. 이 작업에는 창의성이 필요하지 않으므로 인지 능력을 다른 곳에 집중할 수 있습니다. 둘째, 벡터 값 함수의 도함수를 계산하려면 출력에서 입력까지 변수의 종속성 그래프를 추적하면서 행렬을 곱해야 합니다. 특히, 이 그래프는 함수를 평가할 때 정방향으로 이동하고 기울기를 계산할 때 역방향으로 이동합니다. 이후 장에서는 체인 규칙을 적용하기 위한 계산 절차인 역전파를 공식적으로 소개할 것입니다.

 

From the viewpoint of optimization, gradients allow us to determine how to move the parameters of a model in order to lower the loss, and each step of the optimization algorithms used throughout this book will require calculating the gradient.

 

최적화 관점에서 기울기를 사용하면 손실을 낮추기 위해 모델의 매개변수를 이동하는 방법을 결정할 수 있으며, 이 책 전체에서 사용되는 최적화 알고리즘의 각 단계에서는 기울기 계산이 필요합니다.

 

2.4.6. Exercises

 

 

 

반응형