Skip to content

Latest commit

 

History

30 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Mini NPU 시뮬레이터

입력받은 2차원 배열 패턴과 필터간에 mac 연산을 통해 유사도 점수를 구해서 어떤 필터의 모양에 더 가까운지 계산하는 프로그램

파일 구조

파일은 main 과 npu, 2개로 이루어져있는데 main 은 상호작용과 출력같은 인터페이스 역할을 하고 npu 는 json 에서 필터나 패턴을 추출하거나 mac 연산을 하는 등 핵심 로직을 담당한다.

codyssey-e1-3/
├── main.py
├── npu.py
├── data.json
└── README.md
파일 역할
main.py 메뉴, 사용자 입력, 결과 및 성능 표 출력
npu.py MAC 계산, 검증, JSON 분석, 패턴 생성, 성능 측정
data.json 크기별 필터와 테스트 패턴

판정 원리

패턴과 필터의 같은 위치에 있는 값을 곱하고 그 결과를 모두 더하는 MAC(Multiply-Accumulate) 연산을 통해 점수를 계산한다

score = pattern[0][0] × filter[0][0]
      + pattern[0][1] × filter[0][1]
      + ...

3×3 Cross 패턴을 Cross 필터와 계산하면 점수는 5이고, X 필터와 계산하면 점수는 1이다. 패턴과 필터에 대한 두 점수를 각각 구한 다음 더 큰 쪽을 판정 결과로 사용한다. AI 모델은 큰 행렬에서 이런 MAC 연산을 수많이 반복하고, NPU는 여러 MAC 연산을 병렬로 처리하는 데 특화되어 있다.

그리고 실수는 컴퓨터 내부에서 정확히 표현되지 않을 수 있다. 그래서 두 점수의 차이가 1e-9보다 작으면 어느 한쪽이 더 크다고 보지 않고 UNDECIDED로 판정한다. 사용자 입력 모드에서는 같은 결과를 판정 불가라고 표시한다.

실행 방법

main.py, npu.py, data.json이 있는 프로젝트 폴더에서 실행한다.

python3 main.py

세 가지 모드를 선택할 수 있는데 직접 입력, data.json 분석, 패턴 생성과 MAC 접근 방식 비교를 실행할 수 있다.

입력 모드 내용
1 사용자 입력 3×3 필터 A·B를 입력하고, 패턴은 직접 입력하거나 Cross/X로 자동 생성한다.
2 JSON 분석 data.json의 5×5, 13×13, 25×25 패턴을 일괄 분석한다.
3 패턴 생성기 크기 N과 Cross/X를 입력해 패턴을 만들고 2차원·1차원 MAC 시간을 비교한다.
0 종료 프로그램을 종료한다.

각 모드의 실행이 끝나면 모드 선택 화면으로 돌아오므로, 종료할 때까지 여러 작업을 이어서 실행할 수 있다.

1. 사용자 입력 모드

필터 A와 필터 B를 입력한 뒤 패턴 입력 방식을 선택한다. 패턴은 숫자 3개씩 직접 입력하거나, Cross·X 라벨을 입력해 3×3으로 자동 생성할 수 있다 직접 입력할 때는 각 행에 숫자 3개를 공백으로 구분해 적는다. 열 개수가 맞지 않거나 숫자가 아닌 값이 있으면 안내 메시지가 나오고, 입력 중이던 행렬을 처음부터 다시 받는다.

[패턴 입력 방식]
1. 직접 입력
2. Cross/X 자동 생성
선택: 2
패턴 종류 (Cross/X): X

아래처럼 A에 Cross 필터, B에 X 필터, 패턴에 X를 넣으면 A 점수는 1, B 점수는 5가 된다.

필터 A       필터 B       패턴
0 1 0        1 0 1        1 0 1
1 1 1        0 1 0        0 1 0
0 1 0        1 0 1        1 0 1

A 점수: 1.0000000000000000
B 점수: 5.0000000000000000
판정: B

마지막에는 입력 패턴과 필터 A의 mac()을 10회 측정해 3×3 MAC의 대표 시간을 출력한다. 필터 B도 점수와 판정을 구할 때 사용하지만 성능 측정에는 포함하지 않으며, 표의 연산 횟수는 필터 하나의 MAC을 기준으로 3² = 9이다.

2. JSON 분석 모드

data.json의 최상위 filterspatterns를 읽는다. 패턴 키는 size_{N}_{idx} 형식이며, 여기서 꺼낸 N으로 size_N 필터를 찾는다.

JSON에 쓰인 표기는 계산 전에 다음 두 표준 라벨로 맞춘다.

JSON의 값 프로그램 내부 라벨
expected의 +, 필터 키의 cross Cross
expected와 필터 키의 x X

같은 Cross를 expected에서는 +, 필터 키에서는 cross로 표현하므로 문자열을 그대로 비교하면 서로 다른 라벨로 처리될 수 있다. 이런 잘못된 FAIL을 막기 위해 계산과 정답 비교 전에 라벨을 Cross와 X로 통일한다.

패턴과 두 필터가 모두 N×N인지, 각 값이 숫자인지도 MAC 계산 전에 확인한다. JSON 모드의 경우 케이스의 키나 배열에 문제가 있으면 그 케이스만 FAIL로 기록하고 다음 케이스를 계속 처리한다.

케이스 하나가 처리되는 순서는 다음과 같다.

키에서 크기 확인 → 라벨 정규화 → 행렬 검증 → MAC 점수 계산
→ epsilon 기준 판정 → expected와 비교 → PASS/FAIL

3. 패턴 생성기와 MAC 최적화 비교

같은 패턴 생성 함수는 사용자 입력 모드와 패턴 생성기 모드에서 함께 사용한다. 사용자 입력 모드에서는 3×3 패턴을 만들고 기존 A/B 점수·판정·성능 분석에 바로 사용한다. 패턴 생성기 모드에서는 1 이상의 크기 N과 Cross 또는 X를 입력한다. Cross는 가운데 행과 열을 1로 만들고, X는 두 대각선을 1로 만든다. 짝수 크기의 Cross는 가운데가 한 칸으로 정해지지 않으므로 가운데 두 행과 두 열을 1로 만든다.

N = 3, Cross

0 1 0
1 1 1
0 1 0

생성한 2차원 패턴은 행 순서대로 읽어 길이 N²인 1차원 배열로 바꾼다.

0 1 0 1 1 1 0 1 0

그다음 같은 입력과 같은 반복 횟수로 기존 이중 반복문 MAC과 1차원 배열 MAC을 각각 측정한다.

결과 리포트

이렇게 케이스별 크로스 & X 점수와 판정과 결과를 콘솔로 확인할 수 있다.

케이스 Cross 점수 X 점수 판정 expected 결과
size_5_1 0.9000000000000000 0.8999999999999999 UNDECIDED X FAIL
size_5_2 8.9000000000000004 0.1000000000000000 Cross Cross PASS
size_13_1 0.3000000000000000 14.7000000000000082 X X PASS
size_13_2 7.4999999999999973 7.5000000000000000 UNDECIDED Cross FAIL
size_25_1 4.9000000000000004 4.8999999999999986 UNDECIDED X FAIL
size_25_2 52.8999999999999986 0.1000000000000000 Cross Cross PASS

전체 6개 중 3개가 PASS이고 3개가 FAIL이다.

실패 원인과 결과 해석

  • 여섯 케이스 모두 키 형식과 행렬 크기가 맞아서 스키마 문제로 실패한 항목은 없다.
  • +, cross, x를 먼저 Cross와 X로 통일했기 때문에 표기 차이로 생긴 실패도 없다.
  • 나머지 세 케이스는 수학적으로 계산한 Cross와 X의 MAC 점수가 각각 0.9와 0.9, 7.5와 7.5, 4.9와 4.9로 같다.
  • 하지만 Python의 float는 일부 소수를 정확히 표현하지 못하므로, 실제 합산 결과에는 약 1e-16에서 1e-15 정도의 차이가 생긴다.
  • 이 차이는 모양의 차이가 아니라 부동소수점 표현 오차라서, compare_scores()는 차이가 1e-9보다 작으면 UNDECIDED를 반환한다.
  • data.json의 expected 원본은 + 또는 x이고, 정규화하면 Cross 또는 X가 된다.
  • 동점인 세 케이스의 판정 결과는 UNDECIDED이지만, expected에는 Cross 또는 X가 지정되어 있어 일치하지 않아 모두 FAIL이 된다.
  • 세 FAIL은 MAC 계산이나 스키마 오류가 아니라 동점 판정과 정답 라벨 사이의 불일치에서 생겼다.

실패가 발생하면 검증 메시지, 계산된 점수, 두 점수의 차이 순서로 확인한다.

원인 판단 기준 확인하거나 고칠 부분
데이터·스키마 점수를 계산하기 전에 키, 라벨, 배열 크기 오류가 발생한다. data.json의 키 형식, 필수 값, N×N 크기와 라벨을 수정한다.
로직 검증은 통과했지만 점수나 판정 과정이 예상과 다르다. 크기에 맞는 필터를 골랐는지, MAC 반복문과 Cross/X 연결이 맞는지 확인한다.
수치 비교 두 점수의 차이가 epsilon보다 작아 UNDECIDED가 된다. 부동소수점 오차인지 확인하고, epsilon과 expected의 동점 처리 기준이 서로 맞는지 검토한다.

현재 세 FAIL은 세 번째 경우에 해당한다.

성능 측정

사용자 입력 모드와 JSON 분석 모드는 같은 measure_mac()으로 입출력을 제외한 필터 하나의 MAC을 10회 반복 측정한다. 구현 원리는 같고, 입력 데이터와 비교 범위만 다르다. 사용자 입력 모드는 방금 입력한 패턴과 필터 A의 3×3 MAC 시간을 측정하고, JSON 분석 모드는 준비된 대표 패턴과 Cross 필터로 여러 크기의 MAC 시간을 비교한다.

구분 사용자 입력 모드 JSON 분석 모드
측정 목적 직접 입력하거나 자동 생성한 3×3 MAC 시간 확인 행렬 크기에 따른 MAC 시간 비교
측정 함수 measure_mac() measure_mac()
측정 데이터 직접 입력하거나 자동 생성한 패턴과 필터 A 3×3 예제와 크기별 첫 번째 패턴·Cross 필터
입력 크기 3×3 고정 3×3, 5×5, 13×13, 25×25
출력 시간 필터 A MAC 10회 평균 크기별 Cross MAC 10회 평균
연산 횟수 기준 필터 하나의 필터 하나의

입력, 출력, 파일 읽기 시간을 제외하고 Cross 필터 하나의 mac()을 크기별로 10회 측정한 평균이다. 따라서 평균 시간과 연산 횟수 모두 필터 하나를 기준으로 하며, 연산 횟수는 이다.

크기 평균 MAC 시간(ms) MAC 연산 횟수(N²)
3×3 실행 환경에 따라 다름 9
5×5 실행 환경에 따라 다름 25
13×13 실행 환경에 따라 다름 169
25×25 실행 환경에 따라 다름 625

N×N 행렬에서 mac()은 모든 칸을 한 번씩 방문하므로 필터 하나의 연산 횟수는 N²이고 시간 복잡도는 O(N²)이다. 실제 판정은 Cross와 X 필터를 모두 계산하므로 위치별 연산이 2N²번 필요하지만, 과제의 성능 표는 필터 하나의 MAC과 을 기준으로 한다. 상수 2를 제외하면 전체 판정의 시간 복잡도도 O(N²)이다. 실제 측정 시간도 크기가 커질수록 증가했다.


CPU와 NPU의 병렬화 및 병목

현재 프로그램은 Python 반복문을 사용하므로 CPU가 행렬의 각 위치를 차례로 계산한다. 반면 NPU는 여러 MAC 연산을 동시에 처리하도록 만들어져 큰 행렬을 반복 계산할 때 유리하다.

다만 작은 행렬은 NPU로 데이터를 옮기고 연산을 준비하는 시간이 실제 계산 시간보다 더 클 수 있다. 큰 행렬에서도 메모리에서 데이터를 읽어 오는 속도가 계산 속도를 따라가지 못하면 병목이 생길 수 있다. NPU를 사용한다고 항상 빨라지는 것은 아니며 행렬 크기와 데이터 이동 비용도 함께 고려해야 한다.

대형 행렬 처리와 최적화 방향

행렬이 커지면 계산량은 에 비례하고, 패턴과 두 필터를 저장하는 메모리 사용량도 함께 증가한다. 현재 코드는 JSON 파일 전체를 한 번에 읽고 Python 반복문으로 계산하므로 매우 큰 데이터에는 비효율적일 수 있다.

대형 데이터를 처리하려면 다음과 같은 방법을 고려할 수 있다.

  • 예를 들어 10,000×10,000 행렬 전체를 한꺼번에 읽지 않고 100행씩 읽어 부분 점수를 구한 뒤 합산한다.
  • 여러 패턴을 처리할 때는 한 패턴의 계산이 끝날 때마다 해당 데이터를 정리해 메모리를 다음 패턴에 재사용한다.
  • Python의 이중 반복문 대신 NumPy의 배열 곱셈과 sum()을 사용해 여러 위치의 MAC 연산을 한 번에 처리한다.
  • 여러 패턴에 같은 필터를 적용한다면 필터를 처음 한 번만 메모리에 올려 두고 반복해서 사용한다.

새로운 라벨을 추가할 때 코드 수정 순서

예를 들어 triangle을 추가한다면 다음 순서로 확장한다.

  1. 데이터에 크기별 triangle 필터와 triangle 정답 라벨을 추가한다.
  2. 대소문자가 달라도 같은 라벨로 처리하도록 표준 라벨에 Triangle을 등록한다.
  3. 입력 패턴과 Triangle 필터의 MAC 점수도 기존 라벨과 같은 방식으로 계산한다.
  4. 두 라벨간의 비교가 아니라, 모든 라벨의 점수를 비교해 가장 높은 라벨을 선택하고, 비슷한 점수는 UNDECIDED로 처리한다.
  5. 출력에 새 라벨의 점수가 표시되는지 확인하고 정상 판정, 필터 누락, 동점 상황을 테스트한다.

데이터 추가 → 라벨 인식 → 점수 계산과 판정 → 결과 확인

About

Mini NPU 시뮬레이터 — 2차원 패턴과 필터의 MAC 연산 유사도로 필터를 분류하는 Python 터미널 프로그램

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages