인공지능 개발자가 반드시 알아야 할 Python 디자인 패턴 5가지

인공지능 개발자가 반드시 알아야 할 Python 디자인 패턴 5가지
Cozy CodingPosted On Aug 21, 202420 min read

AI 개발의 빠르게 변화하는 세계에서는 깔끔하고 효율적이며 확장 가능한 코드를 작성하는 것이 이전보다 더 중요합니다. AI 프로젝트가 복잡해지면서, 개발자는 작업 흐름을 최적화할 뿐만 아니라 코드베이스가 견고하고 유지 관리 가능하도록 유지하는 도구와 전략이 필요합니다. 여기서 디자인 패턴이 중요한 역할을 합니다.

디자인 패턴은 일반적인 코딩 문제에 대한 검증된 해결책으로, 문제 해결에 구조화된 방법을 제공합니다. AI에 맞게 조정된 이러한 패턴을 사용하면 코드의 품질을 크게 향상시킬 수 있습니다. 코드를 관리, 확장, 최적화하기가 더 쉬워집니다. 이 블로그에서는 모든 AI 개발자가 알아야 할 필수 Python 디자인 패턴을 살펴보고, 이러한 패턴이 어떻게 더 스마트하고 효율적인 AI 시스템을 구축하는 데 도움이 되는지 알아보겠습니다.

이미지

이 블로그에서는 AI에 특별히 맞춤화된 13가지 필수 디자인 패턴을 탐구하며, 각각의 독특한 이점과 응용 사례를 배울 수 있습니다. 이러한 패턴은 Creational(생성), Structural(구조), Behavioral(행위) 세 가지 주요 카테고리로 나뉘며, 각 카테고리가 소프트웨어 디자인의 다른 측면을 다루는 방식을 이해하면 AI 솔루션을 설계할 때 정보에 기반한 결정을 내릴 수 있습니다.

생성 패턴

생성 패턴은 객체 생성 프로세스에 중점을 두며, 객체를 생성하는 다양한 방법을 제공합니다. 이러한 패턴들은 시스템을 객체가 어떻게 생성되고 구성되며 표현되는지로부터 분리하는 데 주안점을 두고 있습니다. 이러한 패턴들은 AI 시스템이 성장함에 따라 유연하고 확장 가능하게 유지되도록 보장하는 데 중요합니다. 예시로는 한 클래스가 하나의 인스턴스만 가지도록 하는 싱글턴 패턴, 특정 클래스를 명시하지 않고 객체를 생성할 수 있게 하는 팩토리 메소드 패턴, 복잡한 객체의 생성 과정을 그 표현으로부터 분리하는 빌더 패턴이 있습니다.

구조 패턴

구조 패턴은 주로 클래스와 객체의 구성에 관련되어 있으며, 작은 구조로부터 큰 구조를 생성하는 데 도움이 됩니다. 이러한 패턴들은 AI에서 여러 구성 요소를 효율적으로 통합하고 간소화하는 데 유용합니다. 예시로는 한 클래스의 인터페이스를 다른 인터페이스로 변환하는 어댑터 패턴과 객체에 동적으로 책임을 추가하여 AI 모델의 기능을 확장할 수 있게 하는 데코레이터 패턴이 있습니다.

행동 패턴

행동 패턴은 객체 간 상호 작용과 통신을 강조하며 효과적으로 협력하는 방식을 정의합니다. 이러한 패턴들은 데이터 흐름 및 의사 결정을 관리하는 데 중요하며, 인공지능 시스템 내에서 미래를 모델링하고 예측하는 것에 필수적입니다. 예시로는 Observer 패턴이 있습니다. 이 패턴은 객체 간의 일대다 관계를 설정하며, Strategy 패턴은 서로 교체 가능하도록 서로 다른 방법이나 접근 방식을 캡슐화 합니다. 또한 Command 패턴은 요청을 객체로 캡슐화하여 클라이언트가 다양한 요청으로 구성될 수 있도록 합니다. 저는 본 글에서 이와 같은 행동 패턴과 기타 패턴을 자세히 살펴보겠습니다. 이를 통해 인공지능 시스템 설계에서의 역할을 이해할 것입니다.

이러한 디자인 패턴의 세 가지 카테고리 — 생성 패턴, 구조 패턴, 행동 패턴 — 는 소프트웨어 디자인의 다양한 측면을 다룹니다. 생성 패턴은 객체 생성에 대해 다루고, 구조 패턴은 객체가 어떻게 결합되고 상호 작용하여 더 큰 구조를 형성하는지에 초점을 맞춥니다. 그리고 행동 패턴은 객체가 어떻게 통신하고 협력하는지를 조절합니다. 이러한 구분을 이해하는 것이 특정 AI 프로젝트에서 특정 도전에 대한 가장 적합한 디자인 패턴을 선택하는 데 중요하며, 결과적으로 보다 견고하고 유지보수 가능하며 확장 가능한 솔루션으로 이어질 것입니다.

다음 섹션에서는 각 디자인 패턴을 깊이 있게 살펴보며, 효과적으로 적용할 수 있는 잠재적인 영역을 탐색할 것입니다. 각 패턴에 대해 이 패턴이 활용될 수 있는 구체적인 AI 사용 사례나 시나리오를 조명하며, 시각적 설명과 기능에 대한 자세한 설명이 포함될 것입니다. 또한 각 패턴은 이 블로그 게시물에 연결된 공유 리포지토리에서 제공되는 코드 예제와 함께 제시될 것입니다.

싱글톤 패턴

싱글톤 패턴은 클래스가 하나의 인스턴스만 가지고 있도록 보장하여 해당 인스턴스에 대한 전역 접근 지점을 제공합니다. AI 시스템에서는 모델, 구성 설정 또는 계산 리소스와 같은 공유 리소스가 일반적이기 때문에 싱글톤 패턴은 매우 유용합니다. 클래스의 인스턴스화를 제한함으로써 싱글톤은 리소스를 더 효율적으로 관리하고 시스템 전체에 걸쳐 대규모 모델을 로드하거나 설정을 다시 구성하는 데 따르는 오버헤드를 줄여줍니다. 이 패턴은 AI 워크플로우에서 모델 수명 주기, 추론 엔진 또는 구성 관리자를 관리하는 데 특히 유용합니다.

이미지

위의 예시 그림에서 ModelConfig 클래스는 new 메서드를 오버라이딩하여 싱글톤 패턴을 구현합니다. 이 메서드는 ModelConfig의 인스턴스가 이미 존재하는지 확인합니다. 인스턴스가 없는 경우 새 인스턴스가 생성되고, 이미 존재하는 경우 기존 인스턴스가 반환됩니다. 싱글톤 패턴은 모델 설정과 같은 구성을 관리하는 데 이상적이며, 응용 프로그램 전체에서 일관된 설정이 중요한 경우에 유용합니다. 이 패턴을 적용함으로써 동일한 구성이 전역적으로 공유되어 일관된 설정을 보장하고 리소스 부담을 줄일 수 있습니다. 이를 지원하는 코드 샘플은 여기에서 찾을 수 있습니다. 싱글톤은 생성 패턴입니다.

2. 팩토리 패턴

**팩토리 패턴(Factory Pattern)**은 객체를 생성하기 위한 유연한 인터페이스를 제공하는 생성 디자인 패턴으로, 하위 클래스가 생성되는 객체의 유형을 정의할 수 있습니다. 인공지능 분야에서는 객체 생성이 복잡하거나 다양한 모델 또는 처리 파이프라인을 구성해야 하는 경우에 유용합니다. 생성 논리를 중앙 집중화함으로써 팩토리 패턴은 유연성과 재사용성을 향상시켜 AI 시스템에서 기존 코드를 수정하지 않고 구성 요소를 교체하거나 업그레이드하기 쉽게 만듭니다.

위 그림에서는 특정 작업에 따라 다양한 모델 인스턴스를 생성하기 위해 팩토리 패턴이 사용됩니다. BaseModel 클래스는 추상 베이스 클래스로 작용하여 어떤 하위 클래스에서도 predict 메서드의 구현을 강제합니다. TextClassificationModel, SummarizationModel, TranslationModel과 같은 구체적인 하위 클래스는 각각 이 메서드를 구현하여 해당 작업에 대한 특정 동작을 제공합니다.

ModelFactory 클래스에는 이러한 모델 인스턴스를 생성하기 위한 중앙 허브 역할을 하는 create_model라는 정적 메서드가 포함되어 있습니다. 제공된 task_type에 기초하여, 팩토리 메서드는 미리 정의된 매핑에서 적절한 모델 클래스를 동적으로 선택하고 해당 클래스의 인스턴스를 반환합니다. 이 디자인은 시스템을 기존 코드를 변경하지 않고 쉽게 새로운 모델이나 작업으로 확장할 수 있도록 해줍니다. 이러한 접근 방식은 개방/폐쇄 원칙을 준수하게 됩니다.

이 패턴은 서로 다른 작업에 서로 다른 모델이 필요한 AI 애플리케이션에서 특히 유용합니다. 모델 인스턴스를 효과적으로 관리하는 깔끔하고 확장 가능한 방법을 제공합니다. 지원 코드 샘플은 여기에서 찾을 수 있습니다.

3. Observer Pattern

옵저버 패턴은 객체가 종속 객체 목록을 유지하고 상태 변경을 자동으로 종속 객체에 알리는 것을 허용합니다. 실시간 업데이트가 중요한 AI 시스템에서 유용하며, 모델 모니터링, 데이터 동기화 또는 이벤트 처리와 같은 작업에서 특히 유용합니다. 구성 요소 간 통신을 분리함으로써 옵저버 패턴은 업데이트가 효율적으로 시스템 전체에 효과적으로 전파되도록 보장하여 확장성과 유지보수성을 향상시킵니다.

이미지

위의 그림에서 관찰자 패턴은 다른 모델의 성능을 모니터링하기 위해 적용되었습니다. 동적 관찰자 목록을 유지하고 업데이트에 대한 알림을받을 수 있는 ModelMonitor 클래스가 Subject 역할을 합니다. 각각이 특정 모델과 관련된 관찰자의 컬렉션을 관리합니다. ModelPerformanceObserver 클래스의 인스턴스로 나타낸 Observers는 모델의 성능 지표(정확도 및 손실과 같은)가 업데이트 될 때마다 알림을 받습니다.

ModelMonitor 클래스에는 관찰자를 첨부하고 분리하는 데 사용되는 메서드가 포함되어 있어, 어떤 모델이 관찰되는지를 유연하게 관리할 수 있습니다. 모델의 성능 지표가 업데이트 되면 notify 메서드가 해당 관찰자의 업데이트 메서드를 트리거하여, 지표를 기록하고 필요한 경우에는 임계값이 초과되었을 때 경고를 발생시킵니다. 이 디자인 패턴은 서로 다른 학습 단계에서 AI 모델 성능을 모니터링해야 하는 경우와 같이 상태 변화에 대응해야 하는 여러 구성 요소가 있는 시나리오에 특히 유용합니다.

Observer 패턴은 모니터링 로직을 모델의 핵심 기능과 분리함으로써, 더 깨끗하고 모듈화된 코드를 가능하게 하고 쉽게 확장하거나 수정할 수 있습니다. 지원 코드 샘플은 여기에서 찾을 수 있습니다.

4. Decorator Pattern

데코레이터 패턴은 개별 객체에 동적 동작을 추가할 수 있도록 하는 패턴으로, 다른 객체에 영향을 미치지 않습니다. 이는 특히 AI에서 유용하며, 모델이나 데이터 처리기에 전처리 단계, 로깅 기능 또는 보안 검사를 추가해야 할 때 기본 구조를 수정하지 않고 구현할 수 있습니다. 데코레이터 패턴은 단일 책임 원칙을 준수하여 각 구성 요소가 특정 관심사를 다루도록 보장함으로써 AI 시스템을 보다 모듈식으로 유지하고 유지보수하기 쉽게 만듭니다.

image

위 그림에서 데코레이터 패턴은 핵심 데이터 처리 기능의 기능성을 향상시키는 데 사용됩니다. validate_data와 augment_data 데코레이터는 preprocess_data 함수를 래핑하여 각각 검증 및 증강 로직을 추가합니다.

validate_data 데코레이터는 전처리 데이터 함수가 실행되기 전에 입력 데이터가 비어 있지 않은 문자열인지 확인합니다. 유효성 검사 실패 시 오류가 기록되고 ValueError가 발생하여 잘못된 입력으로 함수가 진행되지 않도록 합니다. 반면 augment_data 데코레이터는 핵심 함수가 반환한 데이터를 처리하고 추가 정보를 추가하여 출력을 증강합니다.

이러한 장식자는 입력 데이터를 정리하는 preprocess_data 함수에 적용됩니다. 장식자들의 결합 효과로 데이터가 구조화되고 모듈화된 방식으로 유효성을 검사하고 처리되며 보강됩니다. 이 접근 방식은 장식자 패턴이 제공하는 유연성과 재사용성을 강조하며 행동을 함수에 동적으로 추가하여 깨끗하고 유지보수 가능한 방식으로 구현할 수 있습니다. 지원 코드 샘플은 여기에서 확인할 수 있습니다.

5. 전략 패턴

전략 패턴은 각각을 캡슐화하고 런타임에서 동적 선택을 허용하는 교환 가능한 전략 패밀리를 정의합니다. 인공 지능에서는 추론 방법, 데이터 처리 기술 또는 리소스 관리 전략과 같이 다양한 전략이 컨텍스트에 따라 적용되어야 하는 상황에 이 패턴이 이상적입니다. 전략 패턴은 전략 구현을 선택 프로세스로부터 분리함으로써 코드 재사용성과 향상된 유지보수성을 촉진합니다.

위 그림은 전략 디자인 패턴을 활용한 예제를 보여줍니다. 이 패턴은 알고리즘 패밀리를 정의하고, 각각을 캡슐화하여 서로 교환 가능하게 만듭니다. 이 패턴은 알고리즘을 사용하는 클라이언트와 독립적으로 변할 수 있도록 하여 유연성과 유지보수성을 촉진합니다.

이 그림에서 InferenceStrategy 추상 베이스 클래스는 기계 학습 모델에 적용할 수 있는 다양한 추론 전략에 대한 인터페이스를 정의합니다. 이 클래스에는 모든 구체적인 전략 하위 클래스에서 구현해야 하는 infer라는 추상 메서드가 포함되어 있습니다. 두 가지 구체적인 전략이 구현되어 있습니다:

  • BatchInference: 이 전략은 데이터 일괄 처리에 대한 추론을 수행합니다. 이 클래스의 infer 메서드에서는 모델에서 predict_batch 메서드를 호출하여 일괄 처리 추론을 시뮬레이션합니다.
  • StreamInference: 이 전략은 스트리밍 데이터에 대한 추론을 수행합니다. 이 클래스의 infer 메서드에서는 모델에서 predict_stream 메서드를 호출하여 스트림 추론을 시뮬레이션합니다. InferenceContext 클래스는 추론 전략을 사용하는 컨텍스트 역할을 합니다. 이 클래스는 InferenceStrategy 객체에 대한 참조를 보유하고 이 전략으로 추론 작업을 위임합니다. 이 컨텍스트를 사용하여 set_strategy 메서드를 통해 실행 중에 추론 전략을 변경할 수 있으며, 이를 통해 다양한 전략 간의 동적 전환이 가능합니다. Model 클래스는 일괄 처리 및 스트림 예측을 시뮬레이션하는 메서드를 사용하여 기계 학습 모델을 나타냅니다. 이러한 메서드는 해당하는 전략 클래스에서 호출되어 추론을 수행합니다. 메인 실행 흐름에서 InferenceContext가 BatchInference의 초기 전략으로 생성됩니다. 그런 다음 이 컨텍스트는 이 전략을 사용하여 추론을 실행합니다. 나중에 전략은 StreamInference로 전환되고, 컨텍스트는 새 전략을 사용하여 다시 추론을 실행합니다.

이 패턴은 런타임에 서로 다른 알고리즘 또는 전략을 선택하고 전환해야 하는 경우에 특히 유용합니다. 전략 패턴을 사용하면 알고리즘과 클라이언트 코드 사이에 명확한 분리를 제공하여 쉬운 유지 관리, 테스트 및 다양한 추론 전략의 확장을 가능하게 합니다. 지원 코드 샘플은 여기에서 찾을 수 있습니다.

6. Adapter Pattern

어댑터 패턴은 호환되지 않는 인터페이스 간의 통신을 가능케 하는 다리 역할로 작용하여 함께 작동할 수 있게 합니다. 이는 AI 시스템에서 특히 유용하며, 호환되지 않는 인터페이스를 가진 다양한 구성 요소, 라이브러리 또는 서비스를 통합해야 하는 경우에 활용됩니다. 어댑터 패턴을 사용하면 데이터 형식이나 모델 인터페이스를 표준화하여 기존 구성 요소를 확장적인 리팩토링 없이 신속하게 통합하고 재사용할 수 있습니다.

image

위 그림에서는 전략 패턴이 적용되어 여러 유추 전략을 컨텍스트에 따라 교환 가능하게 정의합니다. 유추 전략 추상 베이스 클래스는 유추 메소드에 대한 인터페이스를 정의하며, 어떠한 구체적인 전략에서도 구현되어야 합니다. 두 가지 구체적인 전략, BatchInference와 StreamInference가 제공되며, 각각 배치 및 스트림 데이터 처리를 다르게 처리하기 위해 infer 메소드를 구현합니다.

InferenceContext 클래스는 유추에 사용할 전략을 관리합니다. set_strategy 메소드를 통해 런타임에 전략을 동적으로 변경할 수 있도록 하여, 상황에 따라 가장 적합한 유추 방법을 선택할 수 있게 합니다. execute_inference 메소드는 현재 전략을 사용하여 유추를 실행하는 데 책임이 있으며, 실제 유추 작업은 전략의 infer 메소드에 위임됩니다. 이 패턴은 데이터나 운영 요구 사항에 따라 데이터 또는 스트림 유추 유형이 필요한 경우에 AI 시스템에서 특히 유용합니다. 이러한 전략을 캡슐화함으로써 코드는 유연하고 확장 가능하며, 기존 인프라 구조를 수정하지 않고 새로운 유추 메소드를 추가할 수 있습니다. 지원되는 코드 샘플은 여기에서 찾을 수 있습니다.

7. 빌더 패턴

빌더 패턴은 복잡한 객체를 단계별로 유연하게 구성하는 방법을 제공하여 구성 프로세스를 최종 표현과 분리합니다. 인공지능(AI)에서 이 패턴은 기계 학습 모델, 데이터 파이프라인 또는 구성 설정을 구축할 때 구성 프로세스에 정확한 제어가 필요한 경우에 특히 유용합니다. 빌더 패턴은 유연성을 향상시켜 동일한 구성 프로세스를 사용하여 다양한 표현이나 구성을 가능하게 합니다.

위 그림에서 빌더 패턴은 여러 구성 요소를 단계적으로 조합하여 기계 학습 파이프라인을 구축하기 위해 사용됩니다. PipelineBuilder 클래스는 데이터 로더, 전처리기, 모델 트레이너 및 평가자와 같은 다른 구성 요소를 추가하는 것을 허용하여 파이프라인을 유연하고 모듈식으로 생성하는 방법을 제공합니다.

각 구성 요소는 add_data_loader, add_preprocessor, add_model_trainer, add_evaluator와 같은 전용 메서드를 통해 파이프라인에 추가됩니다. 이러한 메서드는 파이프라인 빌더 인스턴스를 반환하며, 구성 프로세스를 간단하게하는 유창한 인터페이스를 제공합니다. 필요한 모든 구성 요소가 추가되면 build 메서드가 구성을 완료하고 완전한 파이프라인을 나타내는 딕셔너리를 반환합니다.

구성 요소 - DataLoader, Preprocessor, ModelTrainer 및 Evaluator -은 머신러닝 워크플로우 내에서 특정 작업을 담당합니다. 예를 들어, DataLoader는 데이터를 로드하고, Preprocessor는 데이터를 처리하며, ModelTrainer는 모델을 훈련시키고, Evaluator는 모델의 성능을 평가합니다.

이 설계 패턴은 파이프라인이 다른 구성이나 요구 사항에 기반하여 동적으로 구성되어야 하는 복잡한 시나리오에서 특히 유용합니다. 이는 파이프라인 생성 로직을 캡슐화하여 코드베이스를 보다 깨끗하고 유지보수하기 쉽고, 추가 구성 요소나 기능을 확장하기 쉽게 만듭니다. 지원하는 코드 샘플은 여기에서 찾을 수 있습니다.

8. Command Pattern

Command Pattern은 요청을 객체로 캡슐화하여 클라이언트에게 대기열, 요청 및 작업을 매개변수화할 수 있게 합니다. 이 패턴은 특히 AI 시스템에서 작업을 실행하거나 큐에 넣거나 동적으로 반전해야 하는 경우에 유용합니다. 예를 들어, 작업 스케줄링, 모델 훈련 또는 워크플로우 자동화 등입니다. 요청의 보낸 사람과 수신인을 분리함으로써 Command Pattern은 AI 워크플로우의 유연성과 유지보수성을 향상시킵니다.

위의 그림에서 Command 패턴은 머신 러닝 모델을 훈련하고 배포하는 데 필요한 작업을 개별 명령 객체로 캡슐화하는 데 사용됩니다. 이 패턴은 명령을 발행하는 발신자와 명령을 실행하는 수신자를 분리해야 하는 시나리오에서 특히 유용합니다.

Command 인터페이스는 모든 구체적인 명령 클래스에 의해 구현되어야 하는 execute 메서드를 포함한 추상 기본 클래스로 정의됩니다. 이 경우 Train 및 Deploy 클래스는 Command 인터페이스의 구체적인 구현체입니다. Train 클래스는 모델을 훈련하는 데 필요한 로직을 캡슐화하고, Deploy 클래스는 모델 배포를 처리합니다.

Workflow 클래스는 일련의 명령을 추가된 순서대로 관리하고 실행하는 호출자 역할을 합니다. 이 설계는 복잡한 워크플로우를 관리하는 유연성을 제공하며, 명령을 추가하거나 제거하거나 다른 순서로 실행하여 워크플로우의 핵심 로직을 변경하지 않고 작업을 수행할 수 있습니다.

마지막으로 Model 클래스는 머신 러닝 모델을 표현하며, 훈련 및 배포를 시뮬레이션하는 메서드를 가지고 있습니다. 사용 예제는 Train 및 Deploy 명령의 인스턴스를 생성하고 워크플로우에 추가하여 워크플로우를 실행함으로써 모델을 훈련하고 배포하는 프로세스를 트리거하는 로직으로부터 분리하는 방법을 보여줍니다.

이 방식은 시스템을 새로운 명령어로 확장하거나 기존 워크플로우를 수정할 수 있게 해주는 명확하고 모듈화된 구조를 제공합니다. 코드 샘플은 여기에서 찾을 수 있습니다.

9. 프록시 패턴

프록시 패턴은 다른 객체에 대한 대리자 또는 자리 표시자를 제공하여 그에 대한 액세스를 제어합니다. 이 패턴은 객체에 직접적으로 액세스하는 것이 비용이 많이 들거나 제한되는 인공지능 시스템에서 특히 유용합니다. 프록시 패턴은 캐싱, 액세스 제어 또는 로깅을 통해 성능을 최적화할 수 있어, 기존 로직을 변경하지 않고도 인공지능 시스템을 효율적이고 안전하게 만들 수 있습니다.

이미지

위의 그림에서 Proxy 패턴이 사용되어 언어 모델과의 상호 작용을 최적화하기 위해 예측 결과를 캐싱하고 중복된 계산을 줄입니다. LLMProxy 클래스는 Model 클래스의 대리자 역할을 하며, 모델의 predict 메서드 호출을 가로챕니다. 이 패턴은 특히 이 경우에서 모델 같은 기본 객체가 반복적으로 사용할 때 자원이 많이 소요되는 경우에 유용합니다. 예측 결과를 캐싱하여 빠른 미래 검색을 가능케합니다.

LLMProxy 클래스는 입력 텍스트와 해당 예측 결과를 저장하는 사전 형태의 캐시를 유지합니다. predict 메서드를 통해 예측이 요청되면, 프록시는 먼저 입력 텍스트가 이미 처리되어 캐시에 저장되었는지 확인합니다. 캐시 히트(입력 텍스트가 캐시에 있는 경우)가 발생하면, 프록시는 캐시된 결과를 반환하여 모델을 다시 호출할 필요 없이 처리합니다. 입력 텍스트가 캐시에 없는 경우(캐시 미스), 프록시는 요청을 모델로 위임하고 결과를 캐시에 저장한 후 예측을 반환합니다.

Model 클래스는 입력 텍스트를 기반으로 응답을 생성하는 predict 메서드가 있는 간단한 예측 모델을 시뮬레이션합니다. 예제 사용법은 프록시가 예측을 처리하는 방식을 보여줍니다 - 먼저 모델과 직접 상호 작용(캐시 미스)한 다음 반복된 입력에 대해 캐시된 결과를 사용하는 방법(캐시 히트).

이 패턴은 모델 추론이 비용이 많이 드거나 시간이 오래 걸리는 경우를 포함한 반복된 계산을 처리하는 깔끔하고 효율적인 방법을 제공합니다. 프록시 패턴을 활용하여 시스템 성능을 향상시켜 지연 시간과 자원 사용을 줄일 수 있습니다. 지원하는 코드 샘플은 여기에서 찾을 수 있습니다.

10. 중재자 패턴

중재자 패턴은 객체들이 상호 작용하는 방식을 캡슐화하며, 그들의 통신을 중앙 집중화하여 의존성을 줄입니다. 이 패턴은 AI 시스템에서 여러 구성 요소나 서비스가 강하게 결합되지 않고 조화롭게 상호 작용해야 하는 경우에 특히 가치가 있습니다. 중재자 패턴은 구성 요소 간 상호 작용을 단순화하여 AI 시스템을 모듈식으로 만들어 더 쉽게 확장하거나 수정할 수 있게 돕습니다.

푸시 모델

푸시 모델에서 중재자는 새로운 정보를 받거나 생성하는 즉시, 관리하는 구성 요소에게 업데이트나 메시지를 적극적으로 전송합니다. 구성 요소들은 데이터를 요청하지 않고, 중재자로부터 자동으로 수신합니다. 데이터나 메시지는 중재자로부터 구성 요소로 적극적으로 푸시됩니다.

Python Design Patterns

위의 그림은 중재자 디자인 패턴 내에서 푸시 기반 메커니즘을 보여줍니다. 이 패턴에서 Workflow 클래스는 중재자 역할을 하며 DataAgent, InferenceAgent 및 EvaluationAgent와 같은 다른 구성 요소 또는 에이전트 간의 상호 작용을 조정합니다. 각 에이전트는 작업을 수행한 다음 특정 이벤트가 발생할 때 중재자에게 알림을 적극적으로 전달합니다. 예를 들어, DataAgent가 데이터를 처리한 후, 데이터가 준비되었음을 나타내기 위해 notify 메서드를 호출하여 중재자에게 알립니다. 그럼 중재자는 이 데이터를 처리하기 위해 InferenceAgent로 전달합니다. 마찬가지로, 추론이 완료되면 InferenceAgent가 중재자에게 알림을 보내고, 그럼 EvaluationAgent가 평가를 진행합니다. 이러한 푸시 기반 접근 방식은 각 에이전트가 중재자에게 알림을 보내어 프로세스를 전진시키도록 하므로, 역할의 명확한 분리를 유지하고 에이전트 간의 느슨한 결합을 촉진합니다.

풀 모델

풀 모델에서 구성 요소는 필요할 때 중재자로부터 정보를 요청합니다. 중재자는 적극적으로 업데이트를 보내지 않고, 대신 구성 요소가 데이터를 요청할 때까지 기다립니다. 구성 요소들은 명시적으로 중재자에게 데이터나 정보를 요청하며, 중재자는 요청 시에만 데이터를 제공합니다.

위 그림은 미디에이터 디자인 패턴 내에서 Pull 기반 메커니즘을 보여줍니다. 이 패턴에서 Workflow 클래스는 미디에이터 역할을 하며 DataAgent, InferenceAgent, EvaluationAgent와 같은 다른 구성 요소 또는 에이전트 사이의 상호 작용을 관리합니다. Pull 기반 메커니즘의 핵심은 에이전트들이 데이터가 자동으로 전달되기를 기다리는 것이 아니라, 미디에이터를 통해 서로 메시지를 보내어 정보를 요청하거나 작업을 트리거할 수 있다는 것입니다. 예를 들어, DataAgent가 데이터 처리를 마치고 데이터가 준비되었다는 알림을 미디에이터에게 보낸 후에, InferenceAgent는 이 데이터를 미디에이터나 직접 DataAgent로부터 가져올 수 있습니다. 마찬가지로 추론이 완료된 후에 EvaluationAgent는 InferenceAgent로부터 결과를 가져올 수 있거나 필요한 경우 추가 데이터를 요청하기 위해 메시지를 보낼 수 있습니다. 미디에이터의 send_message 메소드는 에이전트 간의 이러한 통신을 용이하게 하며, 필요에 따라 데이터를 요청하고 수신할 수 있도록 합니다. 이 Pull 기반 접근 방식은 에이전트들이 서로에게 적극적으로 쿼리하거나 데이터를 요청할 수 있도록 함으로써 보다 동적인 상호 작용 모델을 유지할 수 있도록 해줍니다. 미디에이터는 이러한 상호 작용을 조정하여 각 에이전트가 필요한 정보를 필요한 시점에 얻을 수 있도록 하여, 디커플 및 확장 가능한 아키텍처를 촉진합니다.

미디에이터 패턴의 Push 및 Pull 변형에 대한 샘플 코드는 여기에서 찾을 수 있습니다.

11. State Pattern

State 패턴을 사용하면 객체가 내부 상태가 변경될 때 동작을 변경할 수 있습니다. 이는 특히 인공지능 시스템에서 다른 상태나 모델, 데이터셋 또는 파이프라인의 단계마다 다른 동작이 필요한 경우에 관련이 있습니다. State 패턴은 상태별 동작을 각각의 클래스로 캡슐화하여 복잡한, 상태에 의존하는 로직을 AI 시스템의 핵심 구성 요소를 혼란스럽게 하지 않고 더 쉽게 관리할 수 있습니다.

State Pattern

제공된 그림은 내부 상태에 따라 변경되는 객체의 동작을 관리하는 State 디자인 패턴을 보여줍니다. 이 패턴에서 Context 클래스는 현재 상태에 따라 동작이 변경되는 엔티티를 나타냅니다. 상태 클래스는 State 추상 기본 클래스의 하위 클래스로 정의되며, 각각이 특정 동작을 정의하기 위해 handle 메서드를 구현합니다.

이 그림에서는 학습 과정을 일련의 상태로 모델링합니다: DataLoadingState는 데이터를 로드하고 데이터가 로드되면 Context를 TrainingState로 전환합니다. TrainingState에서 모델을 훈련하며 훈련이 완료되면 Context를 ValidationState로 이동시킵니다. ValidationState는 모델의 유효성을 검사하며 유효성 검사에 성공하면 Context를 DeploymentState로 전환합니다. 마지막으로 DeploymentState는 모델을 배포하는 곳이며 배포 후 과정은 완료됩니다.

Context 클래스는 현재 상태를 관리하고 해당 상태에 동작을 위임합니다. Context가 다양한 상태를 거치면서 동작이 변경됩니다. 이 접근 방식을 사용하면 상태에 따른 동작을 처리하는 명확하고 조직적인 방법을 제공하여 코드를 유지보수하고 확장하기 쉽게 만듭니다. State 패턴을 사용함으로써, 이 그림은 각 상태 클래스 내에서 상태별 로직을 효과적으로 캡슐화하여 Context가 학습 프로세스의 다양한 단계를 거치면서 동적으로 동작을 변경할 수 있게 합니다. request 메서드를 호출할 때마다 현재 상태가 동작을 처리하고 그 다음 적절한 상태로 Context를 전환합니다. State 패턴에 대한 샘플 코드는 여기에서 확인할 수 있습니다.

12. 책임 연쇄 (Chain of Responsibility, CoR) 패턴

책임 연쇄 패턴은 요청을 핸들러 체인을 따라 전달하고, 각 핸들러가 요청을 처리하거나 다음 핸들러로 전달할 수 있는 패턴입니다. AI에서 이 패턴은 모델, 데이터셋 또는 요청에 수행해야 하는 단계, 유효성 검사 또는 작업을 처리하는 데 유용합니다. 이 패턴의 유연성을 통해 처리 순서를 동적으로 조정할 수 있어 데이터 전처리 파이프라인, 모델 유효성 검사 또는 AI 시스템에서의 요청 처리에 이상적입니다.

PythonDesignPatternsEveryAIDeveloperShouldKnow_9

이 그림은 책임 연쇄(Chain of Responsibility) 디자인 패턴을 보여주는데요, 이 패턴은 일련의 핸들러 객체가 요청을 처리할 수 있는 기회를 줍니다. 이 패턴에서 각 핸들러는 요청을 처리할지 다음 핸들러에게 전달할지 결정하며, 하나 이상의 객체가 독립적으로 요청을 처리할 수 있도록 발신자와 수신자 간의 느슨한 결합을 유도합니다.

이 그림에서는 EvaluationHandler 추상 기본 클래스가 평가 체인의 핸들러의 일반 구조를 나타냅니다. 이 클래스는 다음 핸들러에 대한 참조를 유지하고, 구체적인 핸들러에 의해 구현되어야 하는 추상 메서드 evaluate를 정의합니다. evaluate 메서드는 현재 핸들러가 요청을 완전히 처리하지 않기로 결정할 경우 체인 내의 다음 핸들러에게 제어를 전달합니다.

두 개의 구체적인 핸들러가 제공됩니다:

  • AccuracyHandler는 모델의 정확도를 평가합니다. 이 경우 정확도가 지정된 임계값(이 경우 0.7) 이하인 경우, 다음 핸들러에 제어를 전달하지 않고 평가 프로세스를 중단합니다. 충분한 정확도를 갖는 경우, 평가를 체인 내의 다음 핸들러에게 전달합니다.
  • F1ScoreHandler는 모델의 F1 스코어를 평가합니다. F1 스코어를 계산하고, 후속자가 존재하는 경우 체인을 따라 제어를 전달합니다.

run_evaluation_pipeline 함수는 체인을 설정하고 실행하는 방법을 보여줍니다. 여기서 AccuracyHandler가 체인의 시작에 배치되고 F1ScoreHandler가 이어집니다. 평가 과정은 AccuracyHandler로 시작되고 모델의 정확도가 필요한 임계값을 충족한다면 F1ScoreHandler로 계속됩니다.

이 패턴은 일련의 체크 또는 처리 단계를 순차적으로 적용해야 하지만 중간 단계의 결과에 따라 체인을 동적으로 조정하거나 일찍 종료해야 하는 시나리오에서 특히 유용합니다. Chain of Responsibility 패턴을 사용함으로써 이 그림은 각 핸들러가 특정 작업에 책임을 지고 작업을 체인 아래로 전달할지 여부를 결정할 수 있는 유연하고 확장 가능한 평가 파이프라인을 가능하게 합니다. CoR 패턴의 샘플 코드는 여기에서 확인할 수 있습니다.

13. Visitor Pattern

Visitor Pattern을 사용하면 객체의 구조를 변경하지 않고 객체에 작업을 추가할 수 있으며 알고리즘을 작용하는 객체로부터 분리할 수 있습니다. AI 시스템에서 이 패턴은 모델 해석, 평가 또는 변환과 같은 다양한 작업을 모델 또는 데이터셋에 적용할 때 유용합니다. 방문자 클래스에서 연산의 로직을 중앙 집중화함으로써 Visitor Pattern은 핵심 구조를 변경하지 않고 복잡한 AI 워크플로를 관리하고 확장하는 것을 간소화합니다.

아래는 Visitor design pattern을 보여주는 이미지입니다:

Visitor Design Pattern

Visitor design pattern은 알고리즘을 객체에서 분리하는 데 사용됩니다. 이 패턴을 사용하면 객체의 구조를 변경하지 않고 객체에 추가적인 작업을 수행할 수 있으며, 특히 일련의 객체에 대해 상관없는 다양한 작업을 수행해야 할 때 유용합니다. 이 이미지에서 Model 클래스는 방문자를 수용할 수 있는 추상 AI 모델을 나타냅니다. Concrete ClassificationModel 클래스는 이 모델을 구현하고 구체적인 작업을 수행하는 다양한 방문자와 상호 작용할 수 있습니다. Visitor 추상 클래스는 ClassificationModel을 방문하는 방법을 정의합니다. SHAPVisitor 및 LIMEVisitor와 같은 Concrete visitor는 ClassificationModel을 방문하여 특정 작업을 수행하기 위한 방법을 구현합니다.

  • SHAPVisitor: 이 visitor는 분류 모델의 예측을 설명하기 위해 SHAP (SHapley Additive exPlanations)을 적용합니다. 이 visitor는 visit_classification_model 메서드를 포함하며, 모델과의 상호 작용을 로깅하고 실제 SHAP 로직을 나타내는 apply_shap을 호출합니다.
  • LIMEVisitor: 이 visitor는 분류 모델의 예측을 설명하기 위해 LIME (Local Interpretable Model-agnostic Explanations)을 적용합니다. SHAP visitor와 유사하게, 작업을 로깅하는 visit_classification_model 메서드를 가지고 있으며, 실제 LIME 로직을 나타내는 apply_lime을 호출합니다.

주요 실행 흐름에서 ClassificationModel 객체가 생성되고, 그런 다음 모델에 SHAPVisitor 및 LIMEVisitor과 같은 두 가지 visitor가 적용됩니다. 모델이 visitor를 수락할 때 visitor의 특정 설명 기술(SHAP 또는 LIME)이 실행됩니다. Visitor 패턴을 사용하면 객체 자체를 변경하지 않고 다른 작업이나 알고리즘을 적용해야 할 때 특히 유용합니다. Visitor pattern을 사용하면 관심사를 분리하여 기존 모델 구조를 변경하지 않고 시스템을 쉽게 확장하거나 수정할 수 있습니다.

Visitor pattern의 샘플 코드는 여기에서 찾을 수 있습니다.

마무리

디자인 패턴은 복잡한 시스템을 만들 때 발생하는 일반적인 디자인 도전 과제에 대한 잘 알려진 해결책을 제공하여 AI 개발에서 귀중한 도구입니다. 이 토론을 통해 AI 시스템의 유연성, 확장성 및 유지보수성을 크게 향상시킬 수 있는 13가지 핵심 디자인 패턴을 다뤘습니다. 이러한 패턴을 적용함으로써, 귀하의 AI 솔루션이 현대 AI 워크플로우의 다양하고 요구가 많은 요구사항을 처리할 수 있을 만큼 견고해질 수 있습니다. 자원을 관리하고 성능을 최적화하며 원활한 통합 가능성을 제공하며 깨끗하고 모듈화된 코드를 유지하는 것까지 이어지는 것입니다.

이 13가지 패턴은 AI 개발에 가장 중요한 기법 중 일부를 나타내지만, 유일한 패턴은 아닙니다. 디자인 패턴의 세계는 방대하며, AI 및 소프트웨어 엔지니어링에서 다양한 문제를 해결하는 데 적용할 수 있는 많은 패턴이 존재합니다. AI 시스템을 계속 발전하고 정제하는 동안 여러분은 특정한 요구에 맞는 추가 패턴을 탐색하거나 여기서 논의한 패턴을 결합하는 새로운 방법을 발견할 수 있을 것입니다.

여러분이 제공해주시는 독특한 이야기나 디자인 패턴을 사용하는 독특한 접근법이 있다면, 특히 새롭거나 예상치 못한 영역에서, 댓글에 공유해 주시기 바랍니다. 여러분의 경험은 커뮤니티의 다른 사람들에게 영감을 주고 이끌어주며, 지식을 증진시키고 AI 개발 분야를 발전시키는 데 기여할 수 있습니다. 디자인 패턴이 제공하는 다양한 가능성을 탐험하고 고품질 혁신적인 AI 솔루션을 만드는 데 오퍼하는 대화를 이어나가요.

해당 글을 읽어주셔서 감사합니다. 참여해 주셔서도 감사합니다. 팔로우와 박수가 많은 도움이 됩니다. 내용이나 공유된 노트북에 대해 궁금한 점이나 의문 사항이 있다면 arunpshankar@google.com 또는 shankar.arunp@gmail.com으로 언제든지 문의해 주세요. 또한 https://www.linkedin.com/in/arunprasath-shankar/에서 저를 찾을 수도 있습니다.

모든 피드백과 제안을 환영합니다. 대규모 머신 러닝, 자연어 처리 또는 자연어 이해에 관심이 있고 협업을 원하시는 경우 기쁜 마음으로 연락드리겠습니다. 또한 Google Cloud, VertexAI 및 다양한 생성 모델 AI 구성 요소 및 자연어 처리/머신 러닝에서의 응용 프로그램을 이해하려는 개인, 스타트업 또는 기업이시라면 도와드릴 준비가 되어 있습니다. 언제든지 연락 주시기 바랍니다.