OpenSearch 조사

OpenSearch 에 대해 공부하기 위해 조사한 사항. GPT 4.1

질문
elasticsearch 와 opensearch 에 대해 공부하고 싶은데 검색엔진에 대해 내가 피상적으로 알고 있는 사항을 얘기할 테니 맞는지 틀린건 어떤건지 알려줘. 또한 검색엔진에 대해 알아야 할 기반 지식도 같이 알려줘.

검색엔진은 비정형 텍스트 데이터를 전문 검색하기 위해 일반적으로 사용 됨.

또는 여러 종류의 데이터를 구분해서 입력 할 수 있으며 메타데이터 설정을 해야 함. 예를 들어 상품 검색을 하기 위해서 ‘_product’ 인덱스를 만들고 [가격, 상품설명, 성별, 카테고리 이름]으로 구성된 데이터를 입력 할 수 있어.

이렇게 구성된것은 ranking 함수를 사용해서 결과 정렬에 이용 할 수 있어.

전문 검색은 전문검색을 위한 알고리즘을 이용해 순위를 생성하고 인덱스를 생성해. 전문검색의 대표적인 알고리즘은 BM25 야.


아주 정확하게 개념을 잡으셨고, 일부는 더 깊게 들어갈 수 있습니다. 말씀해주신 내용을 사실 여부와 근거를 중심으로 하나씩 피드백하고, 검색엔진(특히 Elasticsearch, OpenSearch)에서 반드시 알아야 할 기반 지식도 추가로 정리해드립니다.


5.	Query / Filter
•	Query: 점수(스코어)가 붙는 검색 (ex: “~와 비슷한 문서”)
•	Filter: 스코어 없음, 딱 맞는 값만 필터링 (ex: 가격 < 10000)

1. “검색엔진은 비정형 텍스트 데이터를 전문 검색하기 위해 일반적으로 사용 됨.”

  • 맞음.

    • 검색엔진(Elasticsearch/OpenSearch 등)은 로그, 문서, 게시글 등 비정형 텍스트 데이터의 “전문(full-text)” 검색을 위해 널리 쓰입니다.

    • 참고: Elastic 공식문서

    • 비정형: 스키마가 고정되어 있지 않거나, 텍스트 기반의 데이터(문장, 단락 등).


2.

“여러 종류의 데이터를 구분해서 입력할 수 있으며 메타데이터 설정을 해야 함.”

  • 맞음.

    • 인덱스는 ‘테이블’과 유사한 개념이고, 각 인덱스에는 다양한 필드(메타데이터 포함)를 가질 수 있습니다.

    • 상품 인덱스에 [가격, 상품설명, 성별, 카테고리] 등 원하는 필드 구성 가능.

    • 필드마다 타입을 지정(예: keyword, text, integer, date 등)해야 검색 성능에 최적화됨.

    • 참고: Elasticsearch Mapping


3.

“이렇게 구성된 것은 ranking 함수를 사용해서 결과 정렬에 이용 할 수 있어.”

  • 맞음.

    • “랭킹 함수”는 사용자의 질의(query)에 얼마나 잘 맞는지를 “점수(score)”로 계산하고, 이 점수에 따라 결과를 정렬합니다.

    • 기본 랭킹 알고리즘은 BM25.

    • 필요하다면, 사용자 정의 랭킹(score script) 도 가능.


4.

“전문 검색은 전문검색을 위한 알고리즘을 이용해 순위를 생성하고 인덱스를 생성해.”

  • 절반만 맞음.

    • 인덱스 생성과 랭킹 알고리즘은 분리된 개념입니다.

    • 인덱스 생성: 데이터를 빠르게 찾기 위한 자료구조(역색인, inverted index)를 만드는 것.

    • 랭킹 알고리즘: 검색 시 질의와 문서의 유사도(점수)를 계산해 결과를 정렬하는 것.

    • 실제로는 인덱싱 단계에서 역색인을 만들고, 검색 단계에서 BM25(혹은 다른 알고리즘)를 써서 랭킹.


5.

“전문검색의 대표적인 알고리즘은 BM25 야.”

  • 맞음.

    • BM25는 현재까지 실무에서 가장 널리 쓰이는 “문서-쿼리 간 유사도 점수” 산정 알고리즘입니다.

    • Elasticsearch, OpenSearch의 기본(full-text) 스코어링 알고리즘.

    • 참고: BM25 - Wikipedia, Elasticsearch - Relevance


검색엔진(Elasticsearch, OpenSearch) 기초적으로 알아야 할 개념

  1. Index / Document / Field

    • Index: 데이터 집합(=RDB의 테이블).

    • Document: 한 개의 레코드/row.

    • Field: Document의 속성(=RDB의 컬럼).

  2. Mapping (매핑)

    • 각 필드의 데이터 타입 및 인덱싱 옵션 정의.

    • text(전문검색용), keyword(정확 매칭용), integer, date 등.

    • RDBMS의 Schema 에 대응

  3. Inverted Index (역색인)

    • 텍스트를 빠르게 검색하기 위한 핵심 자료구조.

    • 각 “단어”가 어디 문서에 있는지 역방향으로 매핑.

  4. Analyzer / Tokenizer

    • 텍스트를 “토큰(단어)” 단위로 쪼개고, 소문자화, 불용어(stopword) 제거 등 전처리.

    • 한글, 영어, 기타 언어마다 Analyzer가 다름.

    • 예시: “여성 청바지” → [여성, 청바지]로 분해

  5. Query / Filter

    • Query: 점수(스코어)가 붙는 검색 (ex: “~와 비슷한 문서”)

    • Filter: 스코어 없음, 딱 맞는 값만 필터링 (ex: 가격 < 10000)

    • 둘의 차이를 이해하는 것이 중요

  6. Scoring (BM25 등)

    • 검색 결과의 순위를 결정하는 알고리즘 (BM25, TF-IDF 등)

    • 쿼리와 문서의 관련도를 수치화

  7. Aggregation (집계)

    • SQL의 GROUP BY와 유사. 카테고리별 상품 수, 가격대 분포 등 집계 질의 지원
  8. 분산 구조

    • 데이터 샤딩(shard), 레플리카(replica) 구조. 수평 확장 지원
  9. OpenSearch vs Elasticsearch

    • OpenSearch는 AWS 주도로 만들어진 Elasticsearch 오픈소스 분기(fork).

    • 대부분의 기본 사용법은 동일하나, 플러그인 및 일부 기능에서 차이 존재.

    • 참고: 공식 FAQ


실용 예시

상품 인덱스 생성 (Elasticsearch 예시, OpenSearch도 거의 동일)

1
2
3
4
5
6
7
8
9
10
11
12
PUT /products
{
"mappings": {
"properties": {
"name": { "type": "text" },
"description": { "type": "text" },
"price": { "type": "integer" },
"gender": { "type": "keyword" },
"category": { "type": "keyword" }
}
}
}

상품 검색 예시 (쿼리 + 필터)

1
2
3
4
5
6
7
8
9
10
11
12
13
POST /products/_search
{
"query": {
"bool": {
"must": [
{ "match": { "description": "청바지" } }
],
"filter": [
{ "term": { "gender": "female" } }
]
}
}
}

추천 학습 자료


요약

  • 전체적으로 개념 잘 잡으셨고, 인덱스 구조와 랭킹 함수의 차이만 조금 보완하면 더 완벽.

  • 반드시 알아야 할 기반 개념은 역색인, 매핑, analyzer, query/filter, scoring 등.

  • Elasticsearch와 OpenSearch는 거의 동일하지만, 오픈소스 분기로 약간의 차이 존재.

더 구체적으로 궁금한 주제(예: 한글 분석기, 쿼리 최적화, 랭킹 커스터마이즈 등) 있으면 추가로 질문 주셔도 됩니다.


추가 질문
1. 언어별 형태소 분석기의 대표적인 예(한글, 영어, 일본어, 범용)
2. 형태소 분석기를 통한 데이터를 입력해야 하는지, 데이터를 입력 할 때 형태소 분석기를 지정하면 되는지?
3. 쿼리 최적화가 RDBMS와 다른점은?

1. 언어별 형태소 분석기의 대표적인 예

형태소 분석기(Morphological Analyzer)는 언어마다 다릅니다.

Elasticsearch/OpenSearch에서 자주 쓰이는 대표적인 분석기를 기준으로 정리합니다.

한글

  • Nori:

    • Elasticsearch/Opensearch의 공식 한글 형태소 분석기

    • 공식 문서

  • Mecab:

    • 오픈소스 한글(및 일본어) 형태소 분석기. Python, Java 등 바인딩 많음

    • 공식 깃허브

    • Elastic/Opensearch 직접 연동은 제한적(플러그인 필요)

  • OpenKoreanText (구 Twitter Korean Text):

영어

  • Standard analyzer (Elasticsearch 기본):

    • 토크나이저 + 불용어(stopwords) 처리 등 내장
  • Snowball:

    • 어간 추출(stemming) 지원, 여러 언어 지원
  • Porter:

    • 고전적인 어간 추출 알고리즘

일본어

  • Kuromoji:

    • Elasticsearch/Opensearch 공식 일본어 형태소 분석기

    • 공식 문서

  • Mecab:

    • 일본어 분석에 가장 널리 쓰임

범용

  • Standard analyzer:

    • 영어 및 라틴계 언어에 적합
  • ICU analyzer:

    • 다양한 언어 지원(Unicode 기반), Elastic 공식 플러그인

    • 공식 문서

  • NLP 라이브러리

    • Elasticsearch와 직접 연동은 아니지만, spaCy, NLTK, Stanza 등도 범용 형태소 분석 지원

2. 형태소 분석기 적용:

입력 데이터 vs 인덱스 매핑

요점

  • 데이터를 입력할 때 미리 형태소 분석한 결과를 저장하는 게 아님!

  • 인덱스를 만들 때(매핑 정의 시) “어떤 analyzer(형태소 분석기)”를 쓸지 필드별로 지정

  • 이후 문서가 인덱싱(저장)될 때 자동으로 analyzer가 동작

  • 쿼리할 때도 analyzer 지정 가능 (ex: 검색어도 같은 분석기로 쪼갬)

실제 예시

1. 인덱스 매핑 시 분석기 지정

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
PUT /korean_docs
{
"settings": {
"analysis": {
"analyzer": {
"my_korean_analyzer": {
"type": "nori"
}
}
}
},
"mappings": {
"properties": {
"content": {
"type": "text",
"analyzer": "my_korean_analyzer"
}
}
}
}
  • 이러면 content 필드는 입력할 때마다 Nori 형태소 분석기가 자동 적용

2. 쿼리 시 analyzer 지정

1
2
3
4
5
6
7
8
9
10
11
GET /korean_docs/_search
{
"query": {
"match": {
"content": {
"query": "청바지를 샀어요",
"analyzer": "my_korean_analyzer"
}
}
}
}
  • 보통 인덱스 시에 지정한 분석기가 쿼리에도 자동 적용되므로 명시하지 않아도 됨

결론:

  • 데이터를 사전에 형태소 분석해서 넣는 게 아니라, 인덱스 필드에 분석기를 지정하면 Elasticsearch/OpenSearch가 알아서 처리

  • 특별한 경우(예: pre-tokenized field 등)만 미리 토큰화된 데이터를 입력할 때가 있음


3. 쿼리 최적화: RDBMS와의 차이점

RDBMS 쿼리 최적화

  • 인덱스, 조인, 정규화/비정규화, 쿼리 플랜 등이 중심

  • 일반적으로 정확한 값 기반 필터링(where, join, group by 등)이 많음

  • 관계형 데이터의 최적화(중복 최소화, 데이터 일관성)가 주 목적

Elasticsearch/OpenSearch 쿼리 최적화의 차이

주요 차이점

  • 1. 스코어 기반 검색과 랭킹 중심

    • “정확하게 일치”보다 “얼마나 비슷한가”(relevance)가 더 중요함

    • 쿼리 튜닝의 목표가 정확도와 속도의 균형

  • 2. 역색인(inverted index) 기반 구조

    • 대부분의 최적화는 “역색인 구조에 적합한 쿼리 작성”

    • 불필요한 scoring을 피하고, filter 쿼리로 분리(필터는 빠름, 점수 없음)

  • 3. 분산(샤드, 레플리카) 기반

    • 데이터가 여러 서버로 나뉘어 저장됨

    • 샤드 수, 레플리카 구성에 따라 성능 달라짐

  • 4. Analyzer/Tokenizer 영향

    • 쿼리 성능에 텍스트 분석기(형태소 분석, ngram, edge ngram 등)의 영향이 매우 큼

    • 잘못된 analyzer 설정 → 인덱스 폭증/검색 속도 저하

  • 5. Aggregation/집계 쿼리 최적화

    • 집계(aggregation)는 RDB의 group by와 유사하나, 분산환경에서 성능 튜닝 필요

예시: 쿼리 최적화 팁

  • filtermust 구분 사용 (filter는 scoring하지 않아 속도 빠름)

  • source 필드 최소화 (_source: false 또는 필요한 필드만 요청)

  • 샤드/레플리카 튜닝

  • 쿼리 프로파일링 (_search/profile 사용)

  • Bulk indexing(대량 인덱싱은 한번에)

참고


정리/요약

  1. 언어별 형태소 분석기

    • 한글: Nori, Mecab, OpenKoreanText

    • 영어: Standard, Snowball, Porter

    • 일본어: Kuromoji, Mecab

    • 범용: ICU, spaCy 등

  2. 형태소 분석기 지정:

    • 입력 데이터 자체를 분석해서 저장하는 것이 아님

    • 인덱스 매핑에서 analyzer 지정 → Elasticsearch/OpenSearch가 자동 적용

  3. 쿼리 최적화의 차이:

    • RDBMS는 인덱스/정확매칭 중심

    • 검색엔진은 역색인, 랭킹, 분산 구조, analyzer 영향이 크고, filter/must 구분, aggregation 튜닝 등이 중심

필요하면 각 주제별 더 깊은 예제/튜닝 방법도 제공 가능합니다!

궁금한 부분 있으면 더 구체적으로 질문 주세요.


참고:


Stopword 에 관해

https://github.com/apache/lucene/blob/main/lucene/analysis/common/src/resources/org/apache/lucene/analysis/cjk/stopwords.txt
기본적으로 한중일에 대해서 불용어 처리가 없다.

stop word(불용어) 처리기는 검색엔진에서 “의미 없는 단어”(예: 영어의 “the”, “is”, “at” 또는 한국어의 “은”, “는”, “이”, “가” 등)를 인덱스와 쿼리에서 자동으로 제거하여 검색 효율과 정확도를 높이는 데 사용합니다.

아래는 Elasticsearch / OpenSearch에서 stop word 처리기를 사용하는 방법을 설명합니다.


1.

stop word의 기본 원리

  • 인덱싱 시:

    Analyzer가 텍스트를 토큰(단어)으로 분리할 때, stop word에 해당하는 단어는 자동으로 제거됨 → 인덱스 크기 및 검색 속도 향상.

  • 검색(쿼리) 시:

    입력 쿼리에서도 stop word가 제거되어, 실제로 검색에 의미 있는 단어만 남음.


2.

Elasticsearch/OpenSearch에서 stop word 적용 방법

A. 내장 analyzer 사용 (자동 적용)

  • 영어의 경우:

    standard, english analyzer 등은 기본적으로 stop word 처리가 내장되어 있음.

  • 예시

1
2
3
4
5
6
7
8
9
10
11
PUT /myindex
{
"mappings": {
"properties": {
"content": {
"type": "text",
"analyzer": "english"
}
}
}
}
  • → english analyzer에는 불용어 리스트가 이미 포함되어 있음.

B. 커스텀 analyzer에서 stop word 처리기 지정

  • 직접 원하는 불용어 리스트를 지정하거나, 내장 stop word filter를 명시적으로 추가할 수 있음.

예시 1: 영어 커스텀 불용어 처리기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
PUT /customstopindex
{
"settings": {
"analysis": {
"analyzer": {
"my_english_analyzer": {
"type": "custom",
"tokenizer": "standard",
"filter": [
"lowercase",
"english_stop"
]
}
},
"filter": {
"english_stop": {
"type": "stop",
"stopwords": "_english_" // 내장 영어 불용어
}
}
}
},
"mappings": {
"properties": {
"text": {
"type": "text",
"analyzer": "my_english_analyzer"
}
}
}
}

예시 2: 한글 커스텀 불용어 처리기

  • 한글은 내장 불용어 리스트가 제한적이므로 직접 지정하는 것이 일반적
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
PUT /koreanindex
{
"settings": {
"analysis": {
"analyzer": {
"my_korean_analyzer": {
"type": "custom",
"tokenizer": "nori_tokenizer",
"filter": [
"lowercase",
"my_korean_stop"
]
}
},
"filter": {
"my_korean_stop": {
"type": "stop",
"stopwords": ["은", "는", "이", "가", "를", "을", "와", "과", "의"]
}
}
}
},
"mappings": {
"properties": {
"content": {
"type": "text",
"analyzer": "my_korean_analyzer"
}
}
}
}

3. 동작 확인 (예시)

분석 API로 동작 확인

1
2
3
4
5
POST /koreanindex/_analyze
{
"analyzer": "my_korean_analyzer",
"text": "이 상품은 청바지입니다"
}

→ 결과 토큰에서 “이”, “은” 등은 제거됨.

실제로 쿼리 시에도 동일하게 처리되어, “청바지” 같은 의미 있는 단어만 인덱싱/검색됨.


4.

참고자료


정리

  • stop word 처리기는 analyzer 설정에 filter로 추가
  • 영어 등 일부 언어는 내장 stopword set 사용 가능
  • 한글 등은 직접 리스트 지정 필요
  • 인덱스 및 쿼리 양쪽 모두에서 stopword가 제거되어 의미 있는 검색 결과를 얻을 수 있음
  • Nori 는 기본 설치, 은전한닢은 플러그인 설치 필요

기타 더 읽어본 것

RAG 질의 확장과 재순위화

질의 확장(Query Expansion), 재순위화(Re-ranking)은 RAG (Retrieval-Augmented Generation) 시스템에서 검색 정확도와 관련 응답 품질을 높이기 위해 사용됨

🔍 1. 질의 확장 (Query Expansion)

✅ 정의

사용자의 원래 질의(Query)를 더 풍부한 의미를 가진 형태로 확장(augmentation)하여 검색 성능(Recall/Precision)을 높이기 위한 기법입니다.

✅ 목적
• 동의어, 유의어, 관련 개념 등을 추가함으로써 더 많은 관련 문서나 정보를 검색할 수 있도록 함.
• 질의가 너무 짧거나 모호할 때 검색 성능 향상.

✅ 방법 종류

방법 설명 예시
동의어 기반 확장 WordNet 등 사용 car → automobile
임베딩 기반 유사어 확장 Word2Vec, BERT 임베딩을 이용해 유사 단어 검색 laptop → notebook
LLM 기반 질의 재작성 GPT 등으로 자연어로 질의 재작성 “How to fix Macbook?” → “What are common solutions for Macbook hardware issues?”
사용자 로그 기반 확장 과거 검색/클릭 이력 기반 추천 “apple” → “apple fruit”, “apple inc.” 구분

✅ RAG에서의 활용
• 검색 파이프라인 이전 단계에서 query → expanded queries로 확장 후 각각에 대해 벡터 검색 수행
• Recall 향상 목적 → 더 많은 후보 문서를 회수

🧠 2. 재순위화 (Re-ranking)

✅ 정의

초기 검색 단계(Retriever)에서 얻은 문서 후보들을 정확도(Precision) 기준으로 다시 정렬하는 후처리 단계입니다.

✅ 목적
초기 검색(보통 BM25, 벡터 검색)은 빠르지만 정확도가 낮을 수 있음
• 후보 중 LLM이나 랭킹 모델을 통해 더 적합한 문서를 위로 올림

✅ 방법 종류

  • BM25 + BERT ranker
    • BM25로 검색 → BERT 기반 CrossEncoder로 유사도 재계산

  • ColBERT
    • 토큰 수준으로 질의-문서간 연산하여 정교하게 점수화

  • LLM Scoring
    • GPT에 “질문과 문서 중 얼마나 관련 있는가?”를 직접 평가하도록 지시

  • Semantic Matching + Rule
    • 특정 키워드 포함 여부, 문서 길이 등을 조건으로 보정

✅ RAG에서의 활용

  • Retriever → top-k candidates 중에서 Re-ranker가 다시 top-k를 결정
  • 최종적으로 LLM에 넣는 문서 순서를 조정 → 응답 품질 향상

🎯 요약

기술 목적 방법 RAG 파이프라인 내 위치
질의 확장 Recall 향상 동의어, 임베딩, LLM 기반 질의 재작성 검색 전
재순위화 Precision 향상 BERT, ColBERT, LLM scoring 검색 후

📌 예시 워크플로우 (하이브리드)
1. 사용자가 “청바지 추천” 질의
2. 질의 확장 → “청바지 추천”, “데님 바지 추천”, “남성용 청바지”
3. 각 질의로 vector 검색 → top 30 문서 회수
4. Re-ranking → GPT나 CrossEncoder로 relevance 점수 부여
5. 상위 5개 문서 LLM에 전달 → 답변 생성

대형 추론모델의 한계 분석

애플에서 공개한 추론(Reasoning) 모델의 한계에 대한 논문

원본 : https://machinelearning.apple.com/research/illusion-of-thinking

NotebookLM 링크 : https://notebooklm.google.com/notebook/270c9f32-28a6-4031-8c43-6b50b7c600e9?_gl=1*1sze845*_up*MQ..*_ga*OTI5ODMyODAzLjE3NDk1NDAxOTQ.*_ga_W0LDH41ZCB*czE3NDk1NDAxOTMkbzEkZzAkdDE3NDk1NDAxOTMkajYwJGwwJGgw&original_referer=https:%2F%2Fnotebooklm.google%23&pli=1

주요 한계 요약: 위 모델들의 공통적인 한계로, 문제 복잡도가 높아질수록 정답률이 급격히 떨어지는 현상(accuracy collapse)이 보고됩니다 . 또한 난도가 올라갈 때 모델이 생각해야 할 단계를 충분히 밟지 못하고 일찍 포기하는 경향이 있어 , 이를 “사고 노력 감소”로 지적합니다. 반대로, 쉬운 문제에서는 과도한 추론 과정이 오히려 방해가 되어 성능이 저하되기도 합니다 . 마지막으로, 현세대 모델들은 정확한 산술 계산이나 알고리즘적 문제 해결에 근본적 한계를 보여주고 있으며, 논리 퍼즐에서 추론의 일관성 부족도 관찰됩니다.

단, 이 연구는 제어된 퍼즐 환경에 초점을 맞추고 있어 실제 세계의 복잡한 추론 문제를 완전히 포착하지 못할 수 있습니다. 또한, 폐쇄형 LRM에 대한 블랙박스 API 접근에 의존하여 내부 상태 분석에 한계가 있습니다.


대형 추론 모델 비교: Apple 연구 기반 주요 한계와 성능

모델 (출시 시기) 특징 및 강점 주요 한계 / 이슈
GPT-4 (OpenAI, 2023) - 수조 개 파라미터를 지닌 초대형 LLM
- 뛰어난 언어 이해력, 다양한 분야에서 최고 수준 성능
- 제한적이나마 논리적 추론 가능
- 정확도 붕괴: 복잡도가 증가하면 급격한 성능 저하 발생
- 사고 노력 감소: 난이도 증가 시 사고 단계 수 감소
- 계산 취약: 정확한 알고리즘 수행에 취약
- 과도한 사고: 간단한 문제에 지나친 추론으로 성능 저하
OpenAI O1 (2024 Preview) - GPT-4 기반 강화학습 기반 추론 특화 모델
- RL을 통해 사고 과정을 체계적으로 학습
- 복잡 문제에서 GPT-4보다 향상된 성능
- 최신 Preview 모델로 실사용 최적화는 미완
- 복잡 추론의 완전 일반화는 미해결
Claude 3.7 Sonnet (Anthropic, 2025) - 일반 모드 + 확장 추론 모드를 통합한 하이브리드 추론 모델
- API를 통해 사고 토큰 제어 가능
- 중간 복잡도 문제에서 강세
- 수학 정확도 약점: 계산 문제에서 다소 낮은 정답률
- 복잡 추론 한계: 특정 고난도 퍼즐에서 실패율 존재
Gemini 2.5 Pro (Google, 2024) - 멀티모달 지원, 도구 활용 기반 추론 가능
- “Deep Think” 모드로 인간 유사 사고 유도
- 상식/지식 문제에서 강세
- 수학/논리 경시 분야 일부 열세
- AGI 추론력까지는 미도달
DeepSeek R1 (DeepSeek, 2025) - RL만으로 학습된 오픈소스 추론 특화 모델
- 자기 검증, 반성, CoT 등을 자발적 수행
- OpenAI O1 수준의 성능 목표
- 안정성 및 신뢰도 검증 진행 중
- 일반화된 고난도 추론 능력은 추가 연구 필요

GPT 피셜 최신 연구 동향 요약: 한계 해결을 위한 접근법

✅ 강화학습을 통한 추론 능력 강화: OpenAI와 DeepSeek 등은 강화학습(RL)을 활용해 모델이 스스로 생각하는 법을 배우도록 훈련했습니다. OpenAI는 GPT-4를 발전시킨 O1 모델에 거대 규모 RL 알고리즘을 적용하여, 체계적인 사고 과정을 학습시키고 복잡한 문제에서 GPT-4보다 향상된 성능을 얻었습니다  . 이 모델은 추론에 더 많은 연산 시간을 투입할수록 성능이 향상되는 특징을 보여주어, 추론 과정의 스케일업 가능성을 확인시켰습니다 . 오픈소스 진영의 DeepSeek-R1도 유사하게 전적으로 RL로 학습한 모델을 선보여, 자기 검증과 반성, 연쇄 추론 등을 자연스럽게 수행하며 최신 폐쇄형 모델과 견줄 성능을 달성했다고 보고했습니다

✅ 추론 모드의 통합 및 하이브리드화: 기존에는 복잡한 추론에 특화된 모델(LRM)과 일반 대화형 LLM이 구분되는 경향이 있었으나, 이 둘을 통합하려는 움직임이 있습니다. Anthropic의 Claude 3.7 Sonnet은 한 모델 안에 즉각 답변 모드와 심층 사고 모드를 모두 내장하여, 사람처럼 필요에 따라 빠르게 답하거나 숙고하는 능력을 한데 구현했습니다 . 사용자는 모델이 생각에 할애하는 토큰량을 조절할 수도 있어, 간단한 질문에는 빠르게 답하고 어려운 문제는 신중히 추론하도록 유도할 수 있습니다 . Google의 Gemini Pro 역시 2025년 I/O 행사에서 “Deep Think”라는 심층 추론 기능을 소개했는데, 추가 연산 시간을 투입해 문제를 인간처럼 단계적으로 해부하고 해결하는 방식으로 성능을 높였습니다 . 이러한 하이브리드 추론 접근은 간단한 질의에는 불필요한 장황한 풀이를 피하면서, 복잡한 문제에는 충분한 사고를 부여해 과도한 사고로 인한 성능 저하를 완화하려는 의도입니다.

✅ 체인-오브-띵크(CoT) 개선 기법들: “연쇄적 사고” 기법은 복잡 문제에서 모델의 정확도를 높였지만, 이유 과정이 불필요하게 길어지는 비효율이 문제였습니다. 이를 개선하기 위해 연구자들은 트리-오브-띵크(Tree-of-Thought)와 같이 분기 탐색으로 다양한 경로를 모색하여 최선의 해법을 찾는 방법을 고안했습니다. 이 접근은 성능을 높였으나 추론에 막대한 토큰 비용이 들었습니다 . 2024년 NeurIPS에서는 선호도 사슬 최적화(CPO) 기법이 제안되어, 트리 탐색을 통해 얻은 최적 경로를 모델이 학습하도록 미세튜닝함으로써, 추론 성능 향상과 추론 비용 절감을 동시에 달성했습니다 . 결과적으로 CPO로 훈련한 모델은 추가 검색 없이도 기존 다중 탐색과 맞먹는 성능 향상을 보였습니다 . 또한 Algorithm-of-Thoughts 기법도 등장하여, 알고리즘적 예시들을 프롬프트에 온전히 포함시키는 방식으로 한 번의 시도만으로도 모델이 폭넓은 아이디어 탐색을 하게끔 유도했습니다  . 이는 복잡한 검색 없이도 모델 내재의 반복적 사고 능력을 활용하여 성능을 높이는 전략으로, 일부 경우 알고리즘 자체보다도 높은 효율을 보이는 흥미로운 결과를 내기도 했습니다 .

`✅ 인터리브드(interleaved) 추론 및 부분 답변: Apple 연구팀은 문제 풀이 중간에 부분적인 해답을 내놓으며 추론을 지속하는 인터리브드 추론 방법을 2025년에 발표했습니다. 이는 한 번에 긴 사슬을 모두 생각한 뒤 답을 내는 전통적 CoT와 달리, 생각과 답변을 교차하는 접근입니다. 강화학습을 통해 모델이 중간 단계별로 답을 검증받도록 보상을 주었더니, 중간 결과를 확인하며 올바른 경로로 유도되는 효과가 나타났습니다 . 그 결과, 이 방식은 첫 토큰 출력 지연(TTFT)을 80% 이상 감소시키고 최종 정확도를 최대 19.3%까지 개선하는 성과를 보였습니다 . 외부 도구 없이도 달성된 개선이어서, 긴 사고로 인한 비효율 문제를 모델 훈련 기법으로 해결한 사례로 주목받고 있습니다.

`✅ 외부 도구 및 프로그램 연계: 모델 자체의 계산 한계를 극복하기 위해, 모델에게 계산을 맡기지 않고 도구를 사용하게 하는 연구도 활발합니다. Meta의 Toolformer(2023)는 LLM 스스로 API 호출 시점과 방법을 배우게 하여, 필요한 경우 계산기나 검색 엔진을 불러 쓰도록 했습니다 . 이러한 아이디어는 OpenAI의 코드 인터프리터 기능(2023) 등 실용 제품에도 적용되어, ChatGPT가 Python으로 수치를 계산하고 정확한 결과를 응답하게 만들었습니다. 실제로 LLM은 확률적으로 단어를 예측할 뿐 내부에 계산 기능이 없기 때문에 순수 언어 모델만으로는 복잡 산술에 약한데 , 파이썬 REPL이나 WolframAlpha 같은 외부 계산 도구를 결합하면 수학 문제 정답률이 크게 향상됩니다 . 이러한 툴 사용 능력은 모델의 한계를 보완하는 현실적인 해결책으로 떠올랐습니다.

2025년: 대형 추론 모델에 대한 냉정한 평가와 개선 동시 진행. Apple은 “The Illusion of Thinking” 연구 논문을 통해 최신 모델들이 여전히 문제 난도 증가 시 추론 성능이 붕괴한다는 사실을 밝혔고 , 추론 흔적을 심층 분석하여 일관성 부족과 계산 한계를 지적했습니다 . 한편으로 OpenAI는 ChatGPT에 O1-preview를 통합 배포하여 사용자들이 강화학습 기반 추론 모델을 시험해볼 수 있게 했고, Anthropic도 Claude 3.7 (Sonnet)을 출시해 하나의 모델로 경량 응답과 심층 추론을 모두 처리하는 새 경험을 제공했습니다 . Google은 I/O 2025에서 Gemini 업그레이드판에 “Deep Think” 모드를 도입, 추론 과정의 질을 한층 높이는 비법을 시연했습니다 . 또한 Apple은 Interleaved Reasoning 연구를 통해 추론 단계 출력과 응답을 교차하는 방법으로 응답 지연을 5분의1 수준으로 줄이고 정확도도 개선할 수 있음을 보여주었습니다 . 오픈소스 커뮤니티에서도, 앞서 언급한 DeepSeek R1이 공개되어 최첨단 폐쇄 모델들과 어깨를 나란히 하면서 AI 연구의 개방성을 높였습니다. 2025년 현재, 대형 모델의 사고 능력을 인간에 가깝게 만들기 위한 경쟁이 가속화되고 있으며, 추론 효율성과 정확도라는 두 마리 토끼를 잡기 위한 다양한 기법들이 실험되고 있습니다


후기. 개인적으로 Cursor, Aider 등 Agent 를 이용해 자동 모드로 두고 코딩을 계속 실행하게 할 때 한번 잘 못된 길로 빠져들거나 환경 설정에 의해 잘못된 작업을 수행하면 극복하지 못하면서 계속 실행하던 현상이 있었습니다. 그러나 Cursor 만 하더라도 이러한 현상이 적어들고 있었습니다. 사용 모델은 o1 , claude sonnet 3.5 등이었습니다. 이것이 위 사례와 같은것은 아니지만 CoT, Agentic 을 통해서 극복 되고 있는 것으로 보입니다.

1. RAG

Retrieval-Augmented Generation (RAG)

RAG 의 개념에 대해서는 잘 설명된 것이 있으니 링크로 대체.
이 문서들은 각 LLM 들의 Deep Research 를 활용하여 자료를 수집하고 이해한 것을 기억에 남기기 위해 재구성하였다.
따라서 포맷도 글 스타일도 일관성은 없을 것이다.

https://aws.amazon.com/ko/what-is/retrieval-augmented-generation/

https://www.elastic.co/kr/what-is/retrieval-augmented-generation

RAG는 대규모 언어 모델(LLM)과 검색 기술을 결합하여 실시간으로 정확하고 맥락에 맞는 답변을 생성하는 기술입니다.
RAG는 데이터 준비 단계와 실시간 질의응답 단계로 구성됩니다.
RAG는 데이터 준비 단계에서 데이터를 처리하고, 실시간 질의응답 단계에서 사용자의 질문에 대한 답변을 생성합니다.
RAG의 데이터 준비 단계는 텍스트 추출, 청킹, 벡터 임베딩 생성 및 데이터베이스 저장으로 구성되며, 실시간 질의응답 단계는 사용자 질문 처리, 관련 정보 검색 및 LLM을 활용한 답변 생성으로 이루어집니다.
RAG의 데이터 준비 단계와 실시간 질의응답 단계는 상호 보완적으로 작동하여, 사용자가 필요로 하는 정보를 신속하고 정확하게 제공합니다.
RAG는 이러한 과정을 통해 사용자가 필요로 하는 정보를 제공하며, 다양한 응용 분야에서 활용될 수 있습니다.
……는 IDE에서 그냥 오토 컴플릿으로 생성한 문구이다.

RAG 구현을 위해 다음과 같은 단계를 거칠 예정이다.
먼저 RAG 시스템 구현은 이미 좋은 구조가 널리 알려져 있다. AWS, GCP, Azure와 같은 클라우드 플랫폼에서도 이를 지원한다.
다만 어떻게 구현할지에 따라 성능과 효율성이 크게 달라질 수 있다.
그리고 학습하는 입장에서는 어떤식으로 해야 효율적일지도 생각해야 한다.

  1. 이미 잘 알려진 구조를 참고하여 기본적인 RAG 시스템을 이용하여 시스템을 구성한다. 각 클라우드 회사에서는 기본적인 템플릿들을 제공한다. 이것은 RAG 의 기본 요소를 이해하기 위함이다.
  2. 몇가지 컴포넌트를 내가 원하는 것으로 변경해본다.
  3. RAG 시스템의 성능을 테스트하고, 결과를 분석하여 끊임없이 성능 개선이 가능한 시스템 구현

RAG 데이터 추츨을 위한 단계

RAG 은 데이터를 준비하는 것이 첫 단계라 할 수 있다.
이를 위해서 다양한 데이터 소스에서 정보를 추출하고, 이를 처리 및 변환하여 활용 가능한 형태로 준비해야 한다.
소스에서 데이터를 추출 하는 것을 파싱이라 하고, 파싱된 결과를 가지고 LLM 에서 사용하기 좋은 단위로 다시 나누는 것을 청킹이라 한다.

  • 파싱 (Parsing)

    • 텍스트 정제: 추출된 텍스트에서 불필요한 공백, 제어 문자, 특수 문자 등을 제거하여 데이터의 노이즈를 줄입니다.10 HTML 태그나 마크다운 문법이 포함된 경우, 이를 제거하거나 텍스트로 변환하는 과정이 필요할 수 있습니다.
    • 한국어 문서 처리: 한국어 문서의 경우, 의미 단위의 정확한 분석과 처리를 위해 형태소 분석기를 적용하는 것을 고려할 수 있습니다. Mecab-ko, KoNLPy (Okt, Kkma 등 포함)와 같은 라이브러리를 사용하여 명사, 동사 등 주요 품사를 추출하거나, 불용어를 제거하는 등의 전처리를 수행할 수 있습니다. 사용자가 GUI를 통해 형태소 분석기 적용 여부나 특정 분석기 라이브러리를 선택할 수 있도록 유연성을 제공하는 것이 좋습니다.
  • 청킹 (Chunking)

    • 정제된 텍스트를 임베딩 모델과 LLM의 컨텍스트 윈도우 크기를 고려하여 적절한 크기의 조각(청크)으로 나누는 과정입니다. 효과적인 청킹은 검색 정확도와 LLM의 답변 품질에 직접적인 영향을 미칩니다.
    • 청킹 전략 선택: 사용 사례와 데이터 특성에 따라 적합한 청킹 전략을 선택합니다
      • 고정 크기 청킹 (Fixed-size Chunking): 가장 간단한 방식으로, 텍스트를 지정된 문자 수 또는 토큰 수로 자릅니다. 구현이 쉽지만, 문맥이 중간에 끊어질 위험이 있습니다.
      • 재귀적 문자 분할 (Recursive Character Text Splitting): Langchain에서 제공하는 방식으로, 문단(\n\n), 문장(.), 공백() 등 지정된 구분자 목록을 순차적으로 시도하며 텍스트를 분할합니다. 의미론적 경계를 최대한 유지하려는 시도입니다.
      • 의미 기반 청킹 (Semantic Chunking): 문장이나 작은 텍스트 조각들의 임베딩 유사도를 기반으로 의미적으로 유사한 부분들을 하나의 청크로 묶습니다. 문맥적 일관성을 높이는 데 효과적일 수 있으나, 계산 비용이 더 들 수 있습니다.
      • 문서 구조 기반 청킹 (Document-specific Chunking): Markdown의 제목, HTML 태그, 코드의 함수/클래스 정의 등 문서 자체의 구조적 요소를 활용하여 청크를 나눕니다. 문서의 논리적 흐름을 유지하는 데 유리합니다.

주요 구성 및 데이터 흐름 요소

  1. 사용자 인터페이스 (GUI)
    1. 관리 GUI (M): 사용자는 이 인터페이스를 통해 원본 문서(D)를 업로드하고, 파싱/청킹 전략(F), 임베딩 모델(G), 사용할 LLM(K) 등을 선택 및 설정합니다. 모니터링과 모델 관리등 시스템 전반적인 관리 모듈이 추가되야 합니다.
    2. RAG 챗봇 GUI (L): 사용자는 이 인터페이스를 통해 시스템에 자연어 질의(A)를 입력하고, RAG 파이프라인을 통해 생성된 답변과 그 출처를 받습니다.
  2. 데이터 준비 파이프라인
    1. 데이터 로더/파서 (E): 업로드된 다양한 형식의 문서를 로드하고 텍스트를 추출합니다.
    2. 청킹 모듈 (F): 추출된 텍스트를 의미 있는 단위의 청크(Chunk)로 분할합니다. 사용자가 선택한 전략과 파라미터를 따릅니다.
    3. 임베딩 모델 (G): 분할된 텍스트 청크를 고차원 벡터로 변환(임베딩)합니다. 사용자가 선택한 모델(Hugging Face, Ollama, OpenAI API 등)을 사용합니다.
    4. 벡터 데이터베이스 (H): 생성된 임베딩 벡터와 원본 청크 정보를 저장하고, 유사도 기반 검색을 지원합니다.
    5. 그래프 데이터베이스 (I) (선택적 확장): 문서 내/간 엔티티 및 관계 정보를 저장하여, 보다 심층적인 컨텍스트 검색을 지원합니다.
  3. 실시간 질의응답 파이프라인
    1. 질의 처리 모듈 (B): 사용자 질의(A)를 분석하고, 필요한 경우 질의를 재작성(Rewriting)하거나 확장(Expansion)한 후, 선택된 임베딩 모델을 사용하여 벡터로 변환합니다.
    2. 정보 검색 모듈 (C): 변환된 질의 벡터를 사용하여 벡터 데이터베이스(H)에서 유사한 청크들을 검색합니다. 필요한 경우 그래프 데이터베이스(I)를 활용하여 추가적인 관계 정보를 검색합니다 (Hybrid Search). 검색된 정보는 관련도에 따라 순위가 매겨지고 필터링됩니다.
    3. LLM 기반 답변 생성 모듈 (J): 검색된 컨텍스트 정보와 사용자 질의를 바탕으로, 사용자가 선택한 LLM(K)을 사용하여 최종 답변을 생성합니다. 이 과정에서 효과적인 프롬프트 엔지니어링이 적용됩니다. 생성된 답변은 출처 정보와 함께 사용자 인터페이스(L)로 전달됩니다.
flowchart TD
    M["관리 GUI (M)"] -- 문서 업로드/설정 --> E["데이터 로더/파서 (E)"]
    M -- 파싱/청킹/임베딩/LLM 선택 --> F["청킹 모듈 (F)"]
    M -- 임베딩 모델 선택 --> G["임베딩 모델 (G)"]
    L["RAG 챗봇 GUI (L)"] -- 자연어 질의 입력 A --> B["질의 처리 모듈 (B)"]
    E -- 텍스트 추출 --> F
    F -- 청크 분할 --> G
    G -- 임베딩 벡터 생성 --> H["벡터 데이터베이스 (H)"]
    G -- 엔티티/관계 추출 --> I["그래프 데이터베이스 (I)"]
    B -- 질의 임베딩 --> C["정보 검색 모듈 (C)"]
    C -- 벡터 검색 --> H
    C -- 관계 검색 --> I
    C -- 관련 청크 전달 --> J["LLM 기반 답변 생성 모듈 (J)"]
    J -- 최종 답변/출처 --> L

RAG Flowchart

청킹

  1. 토크나이저 이용
  2. LLM 이용
  3. ** PLM Based(Fine-tuning) ** : T5 와 같은 모델로부터 학습하도록 한 후 임계값으로 조절. Langchain 의 Semantic Chunker 업글판.
  4. 합성 데이터 방식. QA, Antrophic Context Retrieval, RAPTOR

다시 블로그를 시작하며

배움이란 때가 있는가? 없는가? 나에게는 지금 한 때가 돌아온 것 같다.
ML 충격이 처음 시작되었을 때 Python 에 익숙하지도 않고 수학적인 문턱이 높아서 접근하기 쉽지 않았다.
그러나 LLM 전문 분야에 대한 관심이 점점 커지면서 이를 배우고자 하는 열망이 생겼다.
이제부터 블로그를 통해 배운 것들을 정리하고 공유하려고 한다.

OpenAI 의 Deep Research 기능이 출시된 후 그렇게 많이 사용하지 않았는데 이제 Google Gemini 가 2.5 이후에 더욱 강력한 기능을 제공하며 많은 도움을 받았다.
AI 를 배우기 위해 AI의 도움을 받는 것이 가장 좋은 시대가 되었다.

RAG 으로 시작해서 추천 시스템 그리고 요즘에는 더 저수준이라고 할 수 있는 TensorFlow와 PyTorch 같은 프레임워크까지 깊게 배우는 것이 목표이다.
단순히 배움에서 끝나는게 아니라 이를 통해 실제로 무언가를 만들어내는 것이 목표이다.
최종적으로 Agent 까지 구현해야 하는데, 얼마나 걸릴 것인가.

ps
다시 하면서 jekyll 에서 hexo 로 변경하였다.
jekyll 이 너무 오래 된 버전이라 업그레이드 하는데 이상하게 꼬이고, gem update 도 잘 안되고…
다행히 hexo 는 훨씬 간단하고 빠르게 설정할 수 있었다.

용어 Tensorflow

tensorflow 의 tensor 는 무슨 뜻이야? 뭐를 비유하거나 함축하려 한거지?

대충 Claude 피셜

“Tensor”의 의미와 TensorFlow 이름의 기원
“TensorFlow”에서 “Tensor”는 수학적 의미를 담고 있으며, 머신러닝 연산의 핵심 개념을 함축합니다.
Tensor의 수학적 의미
“Tensor”는 수학에서 다차원 배열을 일반화한 개념입니다:
스칼라 (0차원 텐서): 단일 숫자 예: 42
벡터 (1차원 텐서): 숫자의 배열 예: [1, 2, 3]
행렬 (2차원 텐서): 2차원 배열 예: [[1, 2], [3, 4]]
3차원 텐서: 3차원 배열 예: [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]
n차원 텐서: n개 인덱스로 접근하는 배열
물리학적 기원
“텐서” 개념은 물리학, 특히 상대성 이론과 연속체 역학에서 유래했습니다:

물리학에서 텐서는 좌표계가 변경되어도 물리 법칙이 불변하도록 표현하는 수학적 객체입니다.
예를 들어, 응력 텐서(stress tensor)는 물체에 가해지는 힘의 방향과 크기를 좌표계에 무관하게 표현합니다.

TensorFlow 이름의 함축적 의미
Google이 “TensorFlow”라는 이름을 선택한 이유는 두 가지 핵심 개념의 조합입니다:

Tensor: 다차원 데이터 배열 - 인공신경망의 입력, 출력 및 중간 표현이 모두 텐서 형태입니다.
Flow: 계산 그래프를 통한 데이터 흐름 - 텐서가 연산 노드들로 구성된 그래프를 따라 “흐르면서” 변환됩니다.

python# TensorFlow에서의 텐서 흐름 예시
import tensorflow as tf

텐서 생성

a = tf.constant([1, 2, 3]) # 1차원 텐서(벡터)
b = tf.constant([[1, 2], [3, 4]]) # 2차원 텐서(행렬)

텐서가 연산을 통해 “흐름”

c = tf.matmul(b, [[10], [20]]) # 행렬 곱셈 연산
d = tf.add(tf.reshape(a, [3, 1]), c) # 추가 변환과 덧셈
이름은 신경망에서 일어나는 핵심 프로세스를 정확히 표현합니다: 다차원 데이터(텐서)가 계산 그래프를 “흐르면서(flow)” 점진적으로 변환되어 최종 결과에 도달하는 과정입니다.
TensorFlow 창시자들은 물리학과 수학의 개념을 차용하여, 복잡한 딥러닝 연산의 본질을 간결하게 표현하는 이름을 만들었습니다.

Perplexity 피셜

TensorFlow에서 “tensor(텐서)”는 단순히 하나의 의미만 갖는 것이 아니라, 수학적 개념과 딥러닝 프레임워크의 구조적 특징을 모두 함축하고 있습니다.

텐서의 뜻과 비유
텐서란?

텐서는 0차원의 스칼라(숫자 하나), 1차원의 벡터(리스트), 2차원의 행렬(테이블), 그리고 그 이상의 고차원 배열까지 모두 포괄하는 다차원 배열을 의미합니다.

즉, 텐서는 데이터를 표현하는 가장 일반적이고 확장된 구조로, 딥러닝에서 입력 데이터, 가중치, 출력 등 모든 정보를 담는 기본 단위입니다.

TensorFlow에서의 비유와 함축

TensorFlow라는 이름은 *Tensor(데이터의 다차원 배열)*와 *Flow(흐름, 데이터의 이동)*를 합친 말입니다. 즉, “텐서가 흐른다”는 의미로, 텐서(데이터)가 연산 그래프(operations, 노드)를 따라 이동하며 계산이 이루어지는 구조를 나타냅니다.

이때 그래프의 각 노드는 연산(예: 더하기, 곱하기 등)을 의미하고, 노드 사이를 연결하는 엣지(edge)는 바로 텐서 객체, 즉 데이터를 의미합니다.

텐서플로우의 핵심은 “데이터(텐서)가 연산 그래프를 따라 흐르면서 계산이 진행된다”는 점을 비유적으로 표현한 것입니다.

요약
Tensor: 벡터, 행렬, 그 이상의 다차원 배열까지 아우르는 데이터 구조.

TensorFlow: 텐서(데이터)가 연산 그래프를 따라 흐르며 계산이 이루어지는 구조를 비유적으로 표현한 이름.

“딥러닝에서 데이터를 의미하는 Tensor와 데이터 플로 그래프를 따라 연산이 수행되는 형태를 합쳐 TensorFlow라고 하는것이다.

즉, TensorFlow의 “tensor”는 단순한 배열이 아니라, 딥러닝에서 모든 데이터를 담아내는 그릇이자, 수학적·구조적 확장성을 상징하는 용어입니다. “흐름(flow)”과 결합해, 데이터가 그래프를 따라 이동하며 연산되는 과정을 함축적으로 표현한 것이 바로 TensorFlow입니다.

Core Image Kernal Language

Core Image Kernal Language

Core Image Kernal Language는 사용자 정의 이미지 처리 필터를 위한 함수, 데이터 타입을 제공한다.
이미지 처리를 위해 OpenGL Shading Language(glslang)도 사용 할 수 있다.
다시 말하면 이 문서는 Core Image Kernal 파일을 만들기 위한 언어에 대한 것이다.

함수

compare

genType compare (genType x, genType y, genType z)

x < 0 ? y : z 값을 반환.
genType은 임의의 벡터 타입.

cos_

genType cos_ (genType x)

x가 [-pi,pi] 사이 값이어야 한다는 점만 빼면 cos (x) 과 유사하다.
genType은 임의의 벡터 타입.

cossin

vec2 cossin (float x)

vec2 (cos (x), sin (x)) 값을 반환한다.

cossin_

vec2 cossin_ (float x)

vec2 (cos (x), sin (x)) 값을 반환한다.
x 는 [–pi, pi] 범위에 있어야 한다.

destCoord

varying vec2 destCoord ()

현재 계산되고 있는 픽셀의 현재 작업 영역 좌표계에 해당하는 위치를 반환한다.
목표 공간(destination space)은 이미지가 렌더링되는 좌표 공간을 가리킨다.

premultiply

vec4 premultiply (vec4 color)

색상 파라미터의 RGB 요소를 그것의 알파 컴포넌트만큼 곱한다.
Multiplies the red, green, and blue components of the color parameter by its alpha component.

sample

vec4 sample (uniform sampler src, vec2 point)

샘플러 src 의 point 위치로부터 생성된 픽셀 값을 반환한다. point 는 sampler 공간에 기술되어 있다.

samplerCoord

varying vec2 samplerCoord (uniform sampler src)

샘플러 공간에 존재하는 샘플러 src의 좌표를 반환한다. 샘플러 src 는 현재 출력 픽셀과 연관이 있다. 어떤 행렬 변형 연산이 src 에 적용된 출력 픽셀이라도 말이다. 샘플 공간은 텍스쳐가 시작된 좌표 공간을 지시한다.
Returns the position, in sampler space, of the sampler src that is associated with the current output pixel (that is, after any transformation matrix associated with src is applied). The sample space refers to the coordinate space of that you are texturing from.

만약 데이터가 타일 모양이라면, 샘플 좌표는 (dx/dy)의 오프셋을 가질 것이다. samplerTransform 함수를 이용해서 샘플러 위치를 대상 위치로 변환 할 수 있다.
Note that if your source data is tiled, the sample coordinate will have an offset (dx/dy). You can convert a destination location to the sampler location using the samplerTransform function.

samplerExtent

uniform vec4 samplerExtent (uniform sampler src)

전체 좌표계(world coordinates)에 있는 샘플러 영역을 반환한다. 반환값 형식을 [x, y, width, height] 이다.

samplerOrigin

uniform vec2 samplerOrigin (uniform sampler src)

samplerExtent (src).xy. 와 동일하다.

samplerSize

uniform vec2 samplerSize (uniform sampler src)

samplerExtent (src).zw. 와 동일하다.

samplerTransform

vec2 samplerTransform (uniform sampler src, vec2 point)

첫번째 아규먼트에서 원본 공간의 좌표 공간에 해당하는 위치를 반환한다. 원본은 두번째 아규먼트인 point 가 속한 작업 공간(working-space)에 정의된 위치와 연관되어 있다. (작업 공간 좌표는 그것에 적용된 어떤 변형이라도 모두 반영함을 명심하라.)
Returns the position in the coordinate space of the source (the first argument) that is associated with the position defined in working-space coordinates (the second argument). (Keep in mind that the working space coordinates reflect any transformations that you applied to the working space.)

예를 들어, 작업 공간의 픽셀 하나를 수정한다면, 원본 이미지의 해당 픽셀을 둘러싸고 있는 픽셀들을 순회해야 한다. 아마 다음과 같은 명령과 비슷한 것을 할 것이다. d 는 작업 공간의 수정한 픽셀위 위치이다. 이미지는 픽셀들의 원본 이미지이다.

For example, if you are modifying a pixel in the working space, and you need to retrieve the pixels that surround this pixel in the original image, you would make calls similar to the following, where d is the location of the pixel you are modifying in the working space, and image is the image source for the pixels.

samplerTransform(image, d + vec2(-1.0,-1.0));
samplerTransform(image, d + vec2(+1.0,-1.0));
samplerTransform(image, d + vec2(-1.0,+1.0));
samplerTransform(image, d + vec2(+1.0,+1.0));

sin_

genType sin_ (genType x)

x가 [-pi,pi] 사이의 값이어야 하는 것을 제외하면 sin (x) 와 비슷하다. genType 은 임의의 벡터 타입이다.

sincos

vec2 sincos (float x)

vec2 (sin (x), cos (x)) 값 반환.

sincos_

vec2 sincos_ (float x)

vec2 (sin (x), cos (x)) 반환. x는 [–pi, pi] 범위여야 한다.

tan_

genType tan_ (genType x)

tan (x) 와 같다. 단, x 는 [–pi, pi] 범위 이어야 한다. genType 은 임의의 벡터 타입이다.

unpremultiply

vec4 unpremultiply (vec4 color)

만약 color 파라미터의 알파가 0보다 크면, RGB 컴포넌트를 알파로 나눈다. 만약 알파가 0이면 color 를 반환한다.

데이터 타입

sampler

CISampler 에서 전해진 샘플러를 명세한다. CISampler 는 데이터에서 샘플을 얻기 위해 사용된다.

__color

현재 CIContext 작업 공간 영역과 색을 맞추기 위해 필요한 커널 파라미터 타입을 명세한다.

__table

Lookup 테이블에서 값을 가져오는 샘플러를 위한 특별한 기호(flag)
__table 은 샘플러 타입보다 무조건 앞에 와야 한다. 이 기호를 보고 Core Image 가 World 좌표계를 이용한 테이블 값을 샘플링하지 않게 한다.
The __table flag must precede the sampler type. The flag ensures that Core Image does not sample the table values using world coordinates.

예를 들어, shadematerial 이라고 명명된 커널에서 Lookup 테이블 샘플러를 이용하기 위해, 커널 정의를 이렇게 하면…

kernel vec4 shadedmaterial(sampler heightfield, __table sampler envmap, float surfaceScale, vec2 envscaling)

__table 기호가 envmap 샘플러 값이 변형되지 않도록 방지한다. 만약 음영처리 kernel 이 아핀 변형의 연속상에 있는 경우라도 그러하다. 만약 샘플러에 이런식으로 표시하지 않는다면, 음영 처리 필터가 회전을 위한 아핀 변환을 하고, 회전된 값에서 환경 맵에 있는 lookup table 의 값을 참조하게 된다. 그러면 lookup table 은 단순히 데이터의 집합이기 때문에 틀린 값이 된다.
Using the __table flag prevents the envmap sampler values from being transformed, even if the shaded material kernel gets inserted into a filter chain with an affine transform. If you don’t tag the sampler this way and you chain the shaded material filter to an affine transform for rotation, then looking up values in the environment map results in getting rotated values, which is not correct because the lookup table is simply a data collection

예약어(Keywords)

kernel

커널 루틴을 명세한다. 커널 루틴은 CIKernel class 에 의해 추출되고 컴파일 된다. 커널은 출력 이미지의 단일 픽셀을 계산하기 위해 필요한 계산식을 캡슐화 한다.
Specifies a kernel routine. Kernel routines are extracted and compiled by the CIKernel class. A kernel encapsulates the computation required to compute a single pixel in the output image.

모든 커널은 그것의 반환 타입에 대한 커널 키워드에 의해 표시된다. 커널의 내재된 반환 타입은 vec4 이어야 한다. Core Image 는 현재 평가된 입력 픽셀에 대해 출력 픽셀을 반환하기 위하여 이 타입을 필요로 한다.
커널에 대한 모든 파라미터는 묵시적으로 uniform 으로 표시된다.(implicitly marked uniform) 파라미터가 out 이나 inout으로 선언 할 수 없다.

커널 루틴에 다음 타입을 건넬 수 있다

  • sampler: 커널을 적용 할 때 CISampler Object 가 필요하다.
  • __table: 샘플러 타입에 대한 수식어 A qualifier for a sampler type. float, vec2, vec3, vec4: NSNumber 나 CIVector 에 필요
  • __color: 프로그램에 전달 될 때 CIContext 작업 색상 공간에 일치되는 색상. 커널에 적용 할 때 CIColor 객체가 필요하다. 커널 프로그램에서는 미리 곱셈 된 RGBA 형식의 vec4 형식가 된다.

지원하지 않는 것

OpenGL Shading 언어 소스 코드 전처리기를 지원하지 않는다. 또한 다음 타입도 구현되지 않았다.

  • Data types : mat2, mat3, mat4, struct, arrays

  • 구문: continue, break, discard. 다른 제어문은 지원한다. (if, for, while, do while) 단, 컴파일 시에 반복문을 추론 할 수 있을 경우에만.

  • 표현식 : % << >> | & ^ || && ^^ ~

  • 내장 함수: ftransform, matrixCompMult, dfdx, dfdy, fwidth, noise1, noise2, noise3, noise4, refract

출처

Core Image Kernal Language

참조

Core Graphics - Quartz 2D 실전 예제

Graphic Context

그래픽 컨텍스트는 그리기의 목적지다. 모든 그리기 함수는 그래픽 컨텍스트에 적용된다. 그래픽 컨텍스트는 그리기와 관련된 환경 변수를 저장하고 있다. 색 공간, 색 영역, 메모리, 잘라내기 영역, 선 두께, 스타일, 폰트 등.

  • 클리핑 Clipping : 특정 영역만 남기고 잘라내는 동작.

iOS 에서 그리기

UIView 객체가 생성되고 화면에 보여야 할 때, drawRect 가 호출된다. 이것이 호출되기 전에 그리기와 관련된 환경이 자동으로 생성되어 불투명한 속성의 CGContextRef 가 생성된다.
이렇게 생성된 그래픽 컨텍스트는 UIGraphicGetCurrentContext() 함수를 호출해서 획득 할 수 있다.
이전 문서에서 설명했듯이 UIKit 과 Quartz 는 좌표계가 다르다. 이 둘을 맞추기 위해서 UIKit 에서 CTM 의 Y에 -1을 곱하여 Y 축을 뒤집는다.

Bitmap 컨텍스트 생성하기

비트맵 컨텍스트는 이미지를 저장할 메모리 버퍼에 대한 포인터를 갖는다. 그래픽 컨텍스트에 그리기를 하면 이 메모리 버퍼가 업데이트 된다. 그래픽 컨텍스트를 해제 한 후, 지정했던 포맷의 비트맵 데이터를 얻을 수 있다.

iOS 에서는 UIGraphicsBeginImageContextWithOptions를 이용해야 한다.

MacOS 에서는 CGBitmapContextCreate 를 이용한다.


그리기 경로Path 이용하기

그리기 경로는 여러 선으로 이루어진 도형을 그리는 작업이다. 선이 아주 세부적으로 정의되어 있다면 마치 손으로 그린듯이 매끄러운 표현도 할 수 있을 것이다.
그리기 경로는 ‘그리기 경로 만들기’와 ‘그리기 경로 칠하기’의 두가지 작업으로 분리되어 있다. 먼저 그리기 경로를 만들고 그 다음에 선을 그린다. 그리기 경로가 만들어지면 닫힌 경로 내부를 어떤 색으로 채울 수도 있다.

그리기 위해 필요한 것들

그리기 경로는 선, 호, 구부러진 경로로 이루어 질 수 있다.

  • 점 Point : 점을 그리거나 선을 그리기 위해선 먼저 그리기 시작점을 이동해야 한다.
    CGContextMoveToPoint 함수를 이용해 이동한다.

  • 선 Line : 위와 같이 그리기 시작점을 지정했으면 CGContextAddLineToPoint 함수로 선의 다른 지점을 지정한다. (선은 두 점을 잇는 가장 짧은 구간이다)
    또는 CGContextAddLines 함수에 CGPoint 배열을 넘겨서 여러 선을 한번에 그을 수도 있다.

  • 호 Arc : 호는 원의 일부분이다. CGContextAddArc 함수를 통해 그릴 수 있다. 시작점, 반지름, 호의 시작 각도와 마지막 각도, 그릴 방향(시계, 반시계)을 정 할 수 있다. 각도는 라디안을 이용한다.
    CGContextAddArcToPoint 함수는 2개의 탄젠트 라인을 이용해서 호를 그리는 방법을 제공한다. 그림에서 분홍색이 실제 그려지는 부분이다.
    CGContextAddArcToPoint

  • 곡선 Curve : Quartz는 베이지어 커브를 제공한다. CGContextAddCurveToPoint

그리기 영역 자르기 Clipping to a Path

특정 그리기 영역을 제외한 나머지 부분은 그리지 않게 할 수도 있다.

원형으로 자르기 예제
CGContextBeginPath (context);
CGContextAddArc (context, w/2, h/2, ((w>h) ? h : w)/2, 0, 2*PI, 0);
CGContextClosePath (context);
CGContextClip (context);

이 뒤는 지겨워서 잠시 보류. -_-/~


참고

Quartz 2D Programming

Core Graphics - Quartz 2D 기본편

이 문서에서는 Quartz 를 이용하여 출력하는 방법을 소개합니다.
그리기 위치 설정, 회전, 확대, 축소에 관한 내용이 담겨 있습니다.
이번에는 기초적인 부분을 설명하고 다음 장에 더욱 자세한 사용법을 소개하겠습니다.

Core Graphics

https://developer.apple.com/documentation/coregraphics

Quartz 기반의 2D 그리기 도구로 Path , 안티얼라이싱, 그레디언트, 이미지, 색 관리, PDF 등등의 기능을 제공한다.
접두사로 CG를 사용한다.


용어 정리

CGContext

https://developer.apple.com/documentation/coregraphics/cgcontext

Quartz 의 2D 출력 대상이다. 그래픽 컨텍스트는 그리기 데이터와 그리기 위한 모든 장치 정보를 가지고 있다. 그리기 대상은 어플리케이션의 윈도, 비트맵 이미지, PDF, 프린터가 될 수 있다.

CGLayer

https://developer.apple.com/documentation/coregraphics/cglayer
그리기 행위를 재활용하기 위해서 Core Graphics 에서 쓰는 장치이다. View는 CGLayer 를 가지고 있고, 실제 그리기는 CGLayer 에 그린다. 저수준 API 라 속도가 빠르다.

Quartz

쿼츠 프레임워크는 2D 그리기 프레임워크이며 해상도와 장치에 독립적이다.
투명한 레이어, 패쓰 기반 그리기, 메모리(offscreen)에 그리기 : 더블 렌더링, 향상된 색 제어, 안티 얼라이싱, PDF 생성, 출력, 파싱 기능을 제공한다.
여담으로 iOS 11부터 PDFKit 이 제공된다. 그 이전에도 제공하던 API가 있지만 기능이 너무 제한적이었다.


iOS 에서 Quartz 사용하기

QuartzCore 를 import 한다.

Quartz 2D 그리기 모델은 두가지 좌표계가 있다.

  • User Space Coordinate 사용자 좌표계
  • 도큐먼트 페이지를 표시하는 좌표계. 사용자 좌표계는 실제 디바이스와 관계없는 부동소수점으로 표시된다. 어떤 문서를 실제 화면에 출력하거나 프린트 할 때, 쿼츠가 사용자 좌표계를 디바이스 좌표계로 맵핑해준다.
  • Device space 디바이스 좌표계
  • 실제 기기의 해상도를 표시하는 좌표계.

또한, 일반적인 모니터나 문서의 좌표계는 X 가 오른쪽으로 증가하고, Y가 아래로 증가한다. 그러나 Quartz CTM 은 X가 오른쪽으로 증가하고 Y가 위로 증가한다. Quartz CTM 을 변형시키면 아래 그림의 방향대로 움직인 다는 것을 염두에 두어야 한다.

CTM coordinate{:class=”img-responsive”}

CTM

사용자 영역의 그리기를 수정하기 위하여 CTM - the Current Transform Matrix 에 특정 연산을 할 수 있다. 그래픽 컨텍스트의 초기 CTM 은 단위행렬identity matrix 로 생성된다. CTM 을 수정하기 위하여 Quartz 의 변환 함수를 쓸 수 있다. 그러면 사용자 영역에 그리는 동작이 변경 된다. 바꿔 말하면 사용자 영역에 그리는 행위는 CTM 을 수정하는 행위가 수반된다.
CTM 은 행렬이니, 선형대수학의 행렬 계산을 알면 이해하는데 도움이 된다.

아래 예제 코드는 Objective-C 기준으로 작성되어 있다. Objective-C 는 C 와 호환되며, Quartz 코드는 구조적 프로그램 스타일로 작성되어 있다. Swift 최신 버전에 대응하는 Quatz 코드는 객체지향 방식으로 되어있다. 따라서 Objective-C 에서 CGContextXXX 로 쓸 수 있는 함수를 Swift 에서는 CGContext 인스턴스 메소드에서 대응하는 메소드를 찾을 수 있다.

예를 들면 아래 처럼 대응 할 수 있다.

Objective-C Swift
CGContextSaveGState(CGContextRef context) let context = CGContext…….
context.saveGState()

용어

  • Translate : 그리는 위치를 이동한다.
  • Rotate : 회전
  • Scale : 확대 , 축소
  • Concatenate : 두개의 행렬을 연결하는 것으로 행렬 곱연산을 통해 이루어진다.

CTM 변환

CTM을 변환하는 것은 컨텐츠를 변형시키는 것이 아니라 좌표계를 움직이는 것이다. 예를 들어, CTM 에 (10,10) 만큼 변화를 준다면 그리기 기준점이 (10,10)으로 이동하는 것이다. 그러므로 CTM 에 변형을 하기 전에 그 전의 상태를 기억해둬야 한다.

CGContextSaveGState(context)
CGContextRestoreGState(context)

이동(Translate)

CGContextTranslateCTM (myContext, 100, 50);

회전

회전의 단위는 radian 이다. 라디안 - 위키페디아
회전축의 기본 점은 (0,0) 이다. 만약 CTM을 이동했다면 이동한 지점이 회전축이 될 것이다.

CGContextRotateCTM (myContext, radians(–45.));  

// 라디안 - 각 변환
#include <math.h>
static inline double radians (double degrees) \
 {return degrees * M_PI/180;}

확대 축소

확대 축소 파라미터 X, Y 가 0~1사이면 축소가 되고, 1보다 크면 확대가 된다. X, Y 가 0보다 작을 경우 축으로 뒤집게 된다.

CGContextScaleCTM (myContext, .5, .75);

행렬 연결

CTM 변환을 연속적으로 수행하는 것인데, CTM에 행렬 곱을 함으로써 수행 할 수 있다.

void CGContextConcatCTM(CGContextRef c, CGAffineTransform transform);

다른 방법으로는, CTM 의 스테이트를 저장하지 않고(CGContextSaveGState를 호출 하지 않고) 연속적으로 CTM 변환 함수들을 호출 하면 된다.

예)
CGContextTranslateCTM (myContext, w,h);
CGContextRotateCTM (myContext, radians(-180.));

아핀 변형 Affine Transforms

Function Use
CGAffineTransformMakeTranslation 원점에서 x,y 만큼 이동하는 행렬을 만드는 함수
CGAffineTransformTranslate 기존에 있는 아핀 변형 행렬에 이동을 수행하는 함수
CGAffineTransformMakeRotation 좌표계를 얼만큼 회전 시킬 지 새로 정하는 행렬을 만드는 함수. 파라미터는 라디안.
CGAffineTransformRotate 기존에 있는 아핀 변형 행렬에 회전을 추가하는 함수
CGAffineTransformMakeScale 좌표계를 X축, Y축으로 각각 확대/축소를 하는 아핀 변환 행렬을 만드는 함수
CGAffineTransformScale 기존에 있는 아핀 변환 행렬에 확대/축소를 추가하는 함수
CGAffineTransformInvert 기존에 수행했던 변환을 되돌리고 싶을 때 사용. 일반적으로는 State를 저장했다 복원하기 때문에 잘 사용하지 않는다.
CGPointApplyAffineTransform 전체 공간에 대해 변환을 수행하는게 아닌 특정 포인트에 대해서 수행하는 함수
CGSizeApplyAffineTransform 사이즈에 대해서 위와 대응되는 함수
CGRectApplyAffineTransform 사각 영역에 대해 위와 대응되는 함수
CGAffineTransformMake 변환 행렬을 직접 만들 때 사용하는 함수

아핀 행렬의 수학적 기초

아핀 행렬은 3x3 행렬로 구성된다. 가장 오른쪽 열은 0, 0, 1 이 되는데 이것은 concatenation 을 위해 필요한 부분이다. 변환 행렬식은 2 * 3 행렬이면 되지만, 행렬곱은 선행 행렬의 열의 갯수와 후행 행렬의 행의 갯수가 같아야 하기 때문에 변환을 연쇄하기 위해서 3 * 3 행렬로 했다.

x,y 값을 아핀 변환 한 결과를 x’, y’ 라고 하고 아핀 행렬이 다음과 같이 되어있다면

Affine Matrics

x’ = ax+cy+tx
y’ = bx+dy+ty

이 된다.

단위 행렬

단위 행렬


1 0 0
0 1 0
0 0 1


위 식에 입력해보면

x’ = x1 + y0 + 0 = x
y’ = x1 + y1 + 0 = y

아핀 이동


1 0 0
0 1 0
tx ty 1


x’ = x + tx
y’ = y + ty

아핀 확대 축소


sx 0 0
0 sy 0
0 0 1


x’ = x * sx
y’ = y * sy

회전


cosa | sina | 0
-sina | cosa | 0
0 | 0 | 1


x’ = xcosa-ysina
y’ = xsina + ycosa

Concatenate

둘 이상의 행렬을 연환하여 계산하는 것인데, 행렬 곱과 같다. 사칙연산의 곱셈과는 다르게 행렬 곱은 비가환적이므로(a * b 와 b * a 가 같지 않다) 순서에 주의해야 한다.

위 내용은 위키페디아의 아핀 행렬을 보면 직관적으로 알 수 있습니다.
애플 문서 Quartz : The Math behind the Matrics 에도 설명되어 있으니, 도표만 보면 바로 이해가 가실겁니다.

참고

Quartz Introduction

Draing printing iOS

Drawing with Quartz 2d

CTM 변형

https://github.com/kimjj81/SwiftWorkshopAlpha

스위프트 4 베타 딱지 붙어있을 때 시작한 번역인데, 약 1달 정도 걸렸습니다. 번역의 어려움을 다시 한번 깨달았고, 그동안 역자들에게 역정냈던 걸 반성도 하게 됩니다. ^^;

각 챕터별로 나눠서 Swift Playground 로 만들었습니다.

문서에 있는 예제도 같이 수록해서 볼 수 있게 하였고, IPad Swift Playground 에도 잘 들어가네요.

Screen Recording 2017-09-22 at 12.11 오전.gif

다음엔 또 뭘 해볼까나…