Python GUI를 실행파일로 만들어본 후기

JEONGYUJIN·2025년 8월 27일

Python

목록 보기
4/4

🔧 연구용 기술 스택

  • GUI: PyQt5 (크로스 플랫폼, 연구용 위젯 풍부)
  • 하드웨어 통신: pySerial (Arduino/Teensy와 시리얼 통신)
  • AI: PyTorch + CNN (MNIST 분류, 확장 가능)
  • 시각화: PyQtGraph (실시간 플롯, 빠른 렌더링)
  • 빌드: PyInstaller + .spec 파일
  • 데이터: NumPy + 자체 CSV # 연구용 16x16 어레이 제어 시스템

🚀 프로젝트 시작계기

최근에 신소재 연구실에서 잠깐 작업할 일이 생겼다. 16x16 광학 센서 어레이를 이용한 실험 시스템을 만드는 건데, 연구진이 매번 Python 코드를 직접 실행하면서 실험하기엔 너무 번거로워 보였다.

평소에 연구실용 도구를 만드는 걸 좋아해서 제대로 된 GUI 프로그램을 만들어보자고 마음먹었다. 연구자들이 복잡한 코드 신경 안 쓰고 그냥 버튼 클릭으로 실험할 수 있게 하는 게 목표였다.

근데 문제가 있더라. 연구실 컴퓨터마다 Python 환경이 다르고, 매번 패키지 설치하고 경로 설정하고... 다른 연구실에서 협업할 때도 설명서를 따로 써줘야 하는 것도 많고, 새로운 학생이 들어와서 실험하려면 또 환경 세팅을 해야 했다.

그냥 연구진들이 쉽게 쓸 수 있는 실행 파일을 만들어보자 싶어서 시작했다.

💡 연구용 시스템 요구사항

요구사항은 연구실 상황에 맞춰 정했다.

Python 설치 없이도 쓸 수 있고, 복잡한 환경 설정 안 해도 되고, 16x16 어레이에서 실시간으로 데이터를 수집하면서 AI 분류 결과를 볼 수 있으면 됐다. 주피터 노트북처럼 매번 코드를 수정하고 실행하고 싶지는 않았다.

연구실 특성상 필요한 기능들

  • 16x16 광학 센서 어레이와 시리얼 통신
  • 실시간 데이터 수집 및 시각화
  • AI 기반 MNIST 숫자 분류
  • 실험 파라미터 실시간 조정
  • 데이터 저장 및 성능 분석
  • 하드웨어 없이도 테스트 가능한 시뮬레이션 모드

아이디어 자체는 복잡하지 않았지만 실제 연구에 쓸 수 있을 만큼 안정적으로 만드는 게 중요했다. 실험 중에 프로그램이 죽으면 데이터를 다 잃어버릴 수도 있거든요...
(유진님 이거 죽었서요..🤔)

PyQt5로 슥슥 만들었다.

기술적 고민들

문제는 구체적인 기술 요소들을 정하는 거였다. GUI 프레임워크 뭐 쓸지, 모델 저장 형식은 어떻게 할지, 실행 파일 빌드는 어떻게 할지... 이런 것들 고민하는데 시간이 오래 걸렸다.

특히 PyInstaller vs cx_Freeze vs Nuitka 선택에서 고민이 많았다. 각각 장단점이 다른데

  • PyInstaller: 가장 유명하고 안정적. 하지만 파일 크기가 큰 편
  • cx_Freeze: 크로스 플랫폼 지원 좋음. 설정이 복잡함
  • Nuitka: 성능 최고. 하지만 복잡한 의존성에서 문제 생기기 쉬움

결국 PyInstaller로 결정했다. 문서도 많고 PyTorch 같은 라이브러리와 호환성도 검증되어 있어서.

특히 하드웨어 통신 부분이 까다로웠다. Arduino/Teensy와 시리얼 통신으로 16x16 어레이를 제어해야 하는데, 연결이 끊어지거나 데이터 전송 오류가 생기면 실험 전체가 망가질 수 있다.

# 시리얼 통신 안정성을 위한 처리
class SerialManager:
    def __init__(self):
        self.connection = None
        self.reconnect_attempts = 0
        
    def safe_write(self, data):
        try:
            if self.connection and self.connection.is_open:
                self.connection.write(data)
                return True
        except serial.SerialException:
            self.attempt_reconnect()
        return False

모델 파일 경로 처리도 연구실 환경에 맞춰 신경써야 했다. 개발할 때는 상대 경로로 models/mnist_cnn_model.pth 이렇게 썼는데, 실행 파일로 만들면 경로가 달라진다. 특히 연구실 컴퓨터들이 OS가 다 달라서...

import sys
import os

def get_resource_path(relative_path):
    if hasattr(sys, '_MEIPASS'):
        return os.path.join(sys._MEIPASS, relative_path)
    return os.path.join(os.path.dirname(__file__), relative_path)

이런 식으로 경로 처리 함수를 만들어서 해결했다.

🚧 연구용 시스템 개발 과정

완성하고 나서 연구실에서 실제로 테스트해보니까 생각보다 문제가 많았다.

개발 환경에서는 잘 돌아가던 게 실제 실험 장비와 연결하면 여러 오류가 터져나왔다. 특히 PyTorch의 CUDA 설정이 꼬이면서 GPU 가속이 안되고, 시리얼 포트 권한 문제로 하드웨어 통신이 안 되는 경우가 발생했다.

연구실 특성상 생기는 문제들도 있었다.

  • 장비별 시리얼 포트 설정: 각 실험 장비마다 포트 번호가 다름
  • 데이터 수집 속도: 실시간 처리를 위해 최적화 필요
  • 장시간 실험 안정성: 몇 시간씩 돌려도 메모리 누수 없어야 함
  • 다중 사용자 환경: 여러 연구자가 동시에 사용 가능해야 함

급하게 .spec 파일을 수정해가면서 연구실 환경에 맞는 설정을 추가했다.

# ArrayControlSystem.spec - 연구실 환경 최적화
a = Analysis(['array_control_system.py'],
            pathex=['.'],
            binaries=[],
            datas=[('models', 'models'), 
                   ('mnist_cnn_model.py', '.'),
                   ('configs', 'configs')],  # 실험 설정 파일들 포함
            hiddenimports=['torch', 'torchvision', 'PyQt5', 
                          'serial', 'pyqtgraph', 'numpy'],
            hookspath=[],
            runtime_hooks=[],
            excludes=['tkinter'],  # 불필요한 GUI 라이브러리 제외
            win_no_prefer_redirects=False,
            win_private_assemblies=False,
            cipher=block_cipher)

연구실에서 중요한 건 재현 가능성이었다. 같은 실험을 다른 날, 다른 컴퓨터에서 해도 동일한 결과가 나와야 한다. 그래서 실험 파라미터들을 모두 설정 파일로 저장하고, 실행 파일에 포함시켰다.

🎨 연구용 UI/UX 설계

사용자 인터페이스는... 솔직히 말하면 처음에는 기능만 돌아가게 만드는 데 집중했다. 연구자들이 쓸 거니까 예쁠 필요는 없다고 생각했는데, 막상 써보니까 가독성이 떨어져서 실험하기 불편할 것 같았다. 그래서 뭐 사용성 높은 걸 가능한 위로 아닌 것을 아래로 내렸다.

연구실 환경에 맞는 UI 요구사항들:

  • 16x16 히트맵 시각화: 센서 어레이 상태를 한눈에 파악
  • 실시간 성능 지표: 분류 정확도, 응답 시간 등 모니터링
  • 실험 로그 시스템: 모든 실험 과정 자동 기록
  • 파라미터 조정 패널: 전압, 샘플 수 등 실시간 변경
  • 시뮬레이션 모드: 하드웨어 없이도 알고리즘 테스트
/* 연구용 대시보드 스타일 */
QMainWindow {
    background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
                stop:0 #1e3c72, stop:1 #2a5298);
}

QGroupBox {
    font-weight: bold;
    border: 2px solid #3498db;
    border-radius: 8px;
    margin: 5px;
    padding-top: 10px;
    background-color: rgba(255, 255, 255, 0.1);
}

/* 실험 상태에 따른 색상 변화 */
QPushButton[status="connected"] {
    background-color: #27ae60;
}
QPushButton[status="disconnected"] {
    background-color: #e74c3c;
}

연구실에서 중요한 건 정보의 밀도였다. 한 화면에 최대한 많은 정보를 담으면서도 가독성을 유지해야 했다. 16x16 히트맵, 성능 지표 테이블, 로그 창을 모두 실시간으로 업데이트하면서도 UI가 느려지면 안디는데...

🛠️ 연구실 환경 배포

PyInstaller로 실행 파일 만들고, 내 드라이브에 dmg와 exe를 배포했다.

# 연구실별 빌드 스크립트
# macOS (주로 분석용)
pyinstaller --onefile --windowed ArrayControlSystem.spec

# Windows (실험 장비 제어용)  
pyinstaller --onefile --windowed ArrayControlSystem.spec

# Linux (서버 환경)
docker run --rm -v $(pwd):/app python:3.9 bash -c "cd /app && pip install -r requirements.txt && pyinstaller ArrayControlSystem.spec"

연구실 특성상 여러 OS가 섞여 있다. 실험 장비는 Windows, 분석은 macOS, 서버는 Linux... 각각 빌드해서 배포해야 했다.
버전 관리는 파일명에 날짜를 넣어ArrayControlSystem_v1.2_20241215.exe 이런 식으로 했다.

📊 연구용 성능 최적화

파일 크기가 생각보다 컸다. macOS 기준으로 1.9GB나 나왔다.

연구실에서는 파일 크기보다는 안정성이 더 중요했다. 실험 중에 프로그램이 죽으면 몇 시간 분량의 데이터를 잃을 수 있거든. 그래서 파일 크기는 좀 크더라도 모든 의존성을 포함시키기로 했다.

주원인은 PyTorch였다. 연구용이라 GPU 가속이 필요할 수도 있어서 CUDA 버전을 포함시켰는데, 이게 용량을 많이 차지했다.

연구실 환경에 맞춘 최적화:

# 연구용 최적화 설정
# GPU 가속 필요한 경우
pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118

# CPU만 쓰는 경우  
pip install torch torchvision --index-url https://download.pytorch.org/whl/cpu

# 연구용 필수 모듈만 포함
pyinstaller --exclude-module=matplotlib --exclude-module=scipy ArrayControlSystem.spec

실행 속도는 연구 환경에서 치명적이다.
실시간 데이터 수집하면서 AI 분류까지 해야 하는데, 처리가 느리면 데이터 손실이 생길 수 있다.

멀티스레딩으로 해결했다:

  • 메인 스레드: GUI 업데이트 (60fps)
  • DAQ 스레드: 센서 데이터 수집 (100Hz)
  • AI 스레드: 분류 작업 (실시간)
  • 로그 스레드: 데이터 저장 (백그라운드)

프론트엔드는 PyQt5로 구성했다. tkinter도 고려했는데 UI가 너무 단조롭고, Kivy는 모바일 중심이라 데스크톱용으로는 PyQt5가 최적이었다.

AI 모델은 간단한 CNN으로 만들었다. 차후 연구에 맞춰서 바꿔나갈 예정이다ㅏ.

🎉 결과와 배운 점

AI를 개발에 활용하는 방법을 좀 더 구체적으로 알게 됐다. 코드 전체를 짜달라고 하는 것보다는 내가 고민하고 있는 기술적 선택지들에 대해 조언을 구하거나, UI 디자인 같은 내가 약한 부분을 보완하는 용도로 쓰는 게 효과적이었다.

그리고 요즘 나온 빌드 도구들이 정
말 좋아졌다는 걸 실감했다. 예전에는 실행 파일 하나 만들려면 복잡한 설정 파일 작성하고 이것저것 해야 했는데, 지금은 몇 줄 명령어면 끝이다.

개발 환경과 실제 사용 환경의 차이도 다시 한번 느꼈다. 혼자 테스트할 때는 문제없던 게 다른 컴퓨터에서는 여러 문제가 생기더라. 특히 라이브러리 의존성이 복잡한 경우 패키징을 더 꼼꼼하게 해야겠다는 생각이 들었다.

처음에 기술 스택 고민하는데 시간을 너무 많이 썼다. tkinter가 익숙해서 만들었는데 너무 단조로웠다. 그냥 빨리 만들어보고 바꾸길 잘했다. 완벽한 설계보다는 일단 돌아가는 걸 만드는 게 중요하다는 걸 또 한 번 느꼈다.

결과적으로는 만족스럽다. 내가 원하던 기능은 다 구현했고, 배포도 잘 됐고, 실제로 다른 사람들도 쓰고 있다. AI 모델을 실제 프로그램으로 만들어서 배포까지 해볼 수 있는 좋은 경험이었다.

📁 프로젝트 파일들

핵심 파일

  • array_control_system.py - 메인 GUI 애플리케이션
  • mnist_cnn_model.py - CNN 모델 정의
  • models/mnist_cnn_model.pth - 훈련된 모델 가중치
  • ArrayControlSystem.spec - PyInstaller 빌드 설정

빌드 스크립트

  • build_all_platforms.yml - GitHub Actions CI/CD
  • requirements.txt - Python 패키지 의존성
  • README.md - 사용법 및 설치 가이드

앞으로는 더 복잡한 AI 모델도 실행 파일로 만들어보고 싶다. 그리고 웹 버전도 만들어서 브라우저에서 바로 쓸 수 있게 해보는 것도 재밌을 것 같다! 🎯

profile
일단 하고 보자 (펠리컨적 마인드 ㅠㅠ)

0개의 댓글