2026년 1월 7일 수요일

Windows + WSL + TensorFlow + CUDA 설치하기

 아쉽게도 tensorflow가 native로 윈도우를 더 이상 지원하지 않기로 한 것 같다. 여기 저기 검색해 본 결과 JAX랑 PyTorch 쓰라고 하네. 당장 짜놓은 Tensorflow+keras 조합을 바꾸진 못할 것 같다.

당분간은 본업용 윈도우 시스템과 실험용 리눅스 시스템을 동시에 굴려서 실험을 해야 잘못된 실험(결과값을 reverse scaling하지 못해서 ....)을 다시 할 수 있을 것 같다. 

그럼 본업은 유지해야 하기 때문에 윈도우를 갈아 업을 순 없고 가능한 조합은 Windows + WSL + CUDA + Tensorflow + Keras 인것 같다.

그래서 먼저 WSL 설치하고 CUDA 설치하고 tensorflow를 설치해야 겠다.

1. WSL 설치

1.1. linux용 windows 하위 시스템 설치

PS C:\Windows\system32> wsl --install

재부팅하라니 재부팅을 해주어야 겠다.

1.2. 사용가능한 linux 배포판 확인하기

PS C:\Windows\system32> wsl --list --online

1.3. linux 배포판 설치

나는 자주 갈아 업는 배포판은 귀찮기 때문에 Ubuntu 24.04 LTS 버전을 설치하도록 하겠다.

PS C:\Windows\system32> wsl --install Ubuntu-24.04

1.4. Ubuntu 환경 업데이트

PS C:\Windows\system32> wsl 

user@DESKTOP:/mnt/c/Users/user$ sudo apt update

user@DESKTOP:/mnt/c/Users/user$ sudo apt upgrade


2. CUDA 환경 설치

Nvidia의 드라이버 구조와 cuda 는 다소 난잡하다. 

2.1. Nvidia 드라이버 설치

윈도우 시스템에 nvidia 드라이버가 설치된 상태로 wsl을 설치해서 그런지, 이미 설치되어 있는 듯 싶다. 확인만 하고 넘어 가자.

...$ nvidia-smi

드라이버 버전 확인 요망(내껀 드라이버 버전 576.88이다. CUDA도 설치 되어 있네 12.9)

2.2. CUDA Toolkit 설치

앞서 이야기 했듯이 난잡하다. nvidia 드라이버 버전을 기준으로 다른 패키지들 tensorflow와 cuda-toolkit의 매칭되는 버전을 찾아 보도록 해야 겠다. 다시 설치하고 그러기 싫다.

우선 시스템이 제공해 줄 수 있는 버전을 확인해 본다.

...$ sudo apt search nvidia-cuda-tool

nvidia-cuda-toolkit이 설치할 수 있게 검색되며 버전은 12.0.140 이다.

그럼 설치한다.

...$ sudo apt install nvidia-cuda-toolkit

오래 걸린다. 잠깐 정리하고 넘어가자.

nvidia 드라이버 버전(576.88), CUDA 버전(12.9), nvidia-cuda-toolkit 버전(12.0.140)

설치된 nvidia관련 패키지들 리스트들이다.

...$ apt list --installed | grep nvidia

libnvidia-compute-535/noble-updates,noble-security,now 535.274.02-0ubuntu0.24.04.2 amd64 [installed,automatic]

libnvidia-ml-dev/noble,now 12.0.140~12.0.1-4build4 amd64 [installed,automatic]

nvidia-cuda-dev/noble,now 12.0.146~12.0.1-4build4 amd64 [installed,automatic]

nvidia-cuda-gdb/noble,now 12.0.140~12.0.1-4build4 amd64 [installed,automatic]

nvidia-cuda-toolkit-doc/noble,now 12.0.1-4build4 all [installed,automatic]

nvidia-cuda-toolkit/noble,now 12.0.140~12.0.1-4build4 amd64 [installed]

nvidia-opencl-dev/noble,now 12.0.140~12.0.1-4build4 amd64 [installed,automatic]

nvidia-profiler/noble,now 12.0.146~12.0.1-4build4 amd64 [installed,automatic]

nvidia-visual-profiler/noble,now 12.0.146~12.0.1-4build4 amd64 [installed,automatic]

어 근데 cudnn은 없네 이것도 필요한 것으로 기억하는데 이것도 설치해야 겠다.

...$ sudo apt install nvidia-cudnn

현재 설치버전은 8.9.2.26이다. 버전이 무슨 암호 같다. 그 전에 너무 길다.

이젠 python 설치와 관련 패키지 설치인것 같다.


3. python 설치

다행이도 이미 설치된 버전은 3.12.3이다.

...$ python3

Python 3.12.3 (main, Nov  6 ...)

>>> quit()

그럼 관련 조합을 정리해 보자.

tensorflow-2.15 + cuda-12.2 + cudnn-8.9 -> corresponding NVIDIA Driver 535

약간 다르긴 하지만 이 조합 밖에 없다. 이걸로 밀어 부치자.

3.1. 가상 환경 설치하기

개발환경의 패키지 버전과 시스템이 관리하는 버전의 충돌을 경험해 보고 싶지 않으면 python 가상환경을 설치하자. 

...$ sudo apt install python3-venv

3.2. tensorflow를 위한 가상환경 생성

그럼 하얀 도화지를 준비하자.

...$ python3 -m venv tf-env

3.3. 생성된 가상 환경 활성화 하기

...$ source ./tf-env/bin/activate

(tf-env) ...$ 

가상환경 종료는 맨 마지막에 해주어야 하지만, 참고로 다음과 같이

(tf-env) ...$ deactivate

아무튼 가상환경 하에서 필요한 tensorflow-2.15버전을 설치한다.

3.4. tensorflow 2.15 설치

(tf-env) ...$ pip install tensorflow[and-cuda]==2.15

에휴 없다. 다시 호환표를 보자.

https://www.tensorflow.org/install/source?hl=ko#gpu

....

텐서플로우-2.17.0 3.9-3.12 클랭 17.0.6 바젤 6.5.0 8.9 12.3

텐서플로우-2.16.1 3.9-3.12 클랭 17.0.6 바젤 6.5.0 8.9 12.3

텐서플로우-2.15.0 3.9-3.11 클랭 16.0.0 바젤 6.1.0 8.9 12.2

...

맞는 조합이 없다. python 3.12이고 cuDNN 8.9고 CUDA는 12.9다.

모른겠다. 2.17버전 설치한다.

(tf-env) ...$ pip install tensorflow[and-cuda]==2.17

엉망 진창이지만 설치가 된다. 근데 오래 걸린다.

3.6. 설치 확인

(tf-env) ...$ python3 -c "import tensorflow as tf; print(tf.config.list_physical_devices('GPU'))"

너무 오래 걸린다. 윈도우 환경으로 넘어가서 visual studio code 환경 설정해야 겠다.

4. visual studio code 환경 설정

visual studio code는 윈도우에 설치하고 python과 tensorflow는 윈도우 안에 있는 리눅스 시스템에 설치되어 있다. 이 둘 간의 OS를 넘나드는 다리를 만들어 주어야 한다.

visual studio code를 실행하고 좌측 탭의 extensions를 선택하고 "Remote - WSL"을 검색한다.

근데 WSL 밖에 없다. 설명을 보아 하니 WSL에 있는 폴더를 열 수 있다고 한다. 이것 설치한다.

그리고 좌측 하단의 원격 연결 버튼 ( >< 모양 아이콘)을 클릭하고 "Connect to WSL"을 선택한다.

뭔가 설치한 Ubuntu-24.04와 연결하는 것 같다.

File -> Open Folder 하고  WSL 디렉토리 선택하고 test.py 파일을 하나 만들면 필요한 extensions들을 추천해 주는데 다 설치하자. 그럼 또 가상 환경 만들라고 한다. 이미 만들어 놓은 건 어쩌고 만들라고 하는지 기존것 로딩하는 것은 없나 보다. 

아 귀찬다. /mnt/c/Users/usr/tf-env를 /home/user로 복사해 오자. 나머지는 내일 하는 것으로.



집중력과 나이 그리고 귀찮음.

 나이가 들면 집중력이 전반적으로 줄어 드는 것 같다. 체력이 먼저 줄어 드는 것으로 대부분 느끼지만 이건 집중력이 전반적으로 줄어 들면서 활력이 줄어 결과적으로 나타나는 현상에 불가하다. 그래서 무엇 보다도 집중력 저하가 나이가 들어서 나타나는 가장 중요한 유실이 아닌가 싶다. 

좀더 그 근원을 쫒아 가면 귀찮음이 늘어서 집중력이 줄어드는 것 아닌가 하는 생각도 든다.

 

"집중력 + 귀찮음" 총량의 법칙

2026년 1월 4일 일요일

[책] Hands-On Machine Learning with Scikit-Learn, Keras, and TensorFlow

 3판까지 나온 상태인 것 같다. 가격이 제법 나가서 사서 살펴보진 못했다. (원서는 10만원 선이고, 번역서는 5만원 선으로 검색된다.) 둘다 사서보기 부담 스럽다. 강의에 써보고 싶은데 접근하기가 쉽지 않다.

이론적으로 매몰되지 않고 그렇다고 따라 하기 식으로 매뉴얼 처럼되어 있는 책도 아닌 그 사이 어딘가에 있는 책같다. 들여다 봐야 할 것 도 많고 할일도 많은데 선 듯 움직여 지지 않는다. 그래서 되세김하기 위해 여기에 기록으로 남겨 볼때 마다 기억나게 남겨둔다. 

2025년 12월 9일 화요일

Pixies - Greens and Blues


 너바나들의 노래가 불의의 사고에 의해서 종결형으로 멈춰져 버려서 갈증이 해소되기는 커녕

죽은 자식 끌어 않고 한탄하는 듯한 허무함이 많다.

죽지 않고 버텨서 더러운 꼴 이것저것 다 겪고 난 후의 노래들은 어땠을까 궁금하기도 하다.

말해봐야 뭐하겠는가? 그 대체제로 요즘 Pixies의 노래를 자주 듣는다.

더욱이 아직 살아있어서 근래의 활동하는 모습도 볼 수 있어서 위안되기도 한다.

드러머의 티셔츠의 일장기가 영 거슬기는 하지만, 노래만은 위안이된다.

나이 들어 가면서 어쩔 수 없이 부끄럽거나 불편한 자리 싫어도 해야 할때,

이런 감정도 있었다는 것을 상기 시켜줘서 편안하다. 

"잠시 있다가 갈게 내가 알아서 갈게 너무 신경 쓰지마."


2025년 12월 7일 일요일

Python 코드의 성능을 높일 수 있는 10가지 영리한 방법

[출처: https://blog.jetbrains.com/pycharm/2025/11/10-smart-performance-hacks-for-faster-python-code/ ]

1. 내부항목 검사(Membership Test)에 효과적인 Set(집합) 활용하기

배열형 자료형의 내부항목을 검사는 다음과 같은 "내부항목 in 배열형" 연산자와 if문을 조합하여 처리한다.



하지만, 가장 손쉽게 사용하는 list를 검색하는 것은 특히 비효율적이다. list의 크기가 커질수록 내부항목검사(x in some_list)는 각 내부항목을 하나씩 스캔해서 비교해야 하므로 S/W time complexity는 선형 시간 복잡도 (O(n))를 가집니다(여기서, n은 내부항목의 개수).


위와 같이 최악의 경우를 상정한 것이기는 하지만, 총 1M 개를 내부항목으로 갖는 list와 set의 내부항목 검사에 소요되는 시간은 다음과 같다. 

True

List lookup: 0.005432s

True

Set lookup: 0.000081s


파이썬의 set은 내부항목 관리를 해시 테이블로 구현되어 평균적으로 상수 시간(O(1)) 조회 성능을 제공하여 특히 대규모 데이터셋을 다룰 때 set 내 값 존재 여부 확인할때 훨씬 빠르다.

통상적으로 set보다 list를 고민없이 사용하는 경우들이 많은데  set가 list보다 훨씬 효율적이다; set는 내부항목 검사 속도를 높일 뿐만 아니라 합집합, 교집합, 차집합과 같은 연산을 훨씬 빠르고 간결하게 수행합니다.

내부항목 검사에 list 대신 set를 사용하면(특히 성능이 중요한 코드에서) 로직을 최소한으로 변경하면서도 상당한 속도 향상을 달성할 수 있다.


2. 불필요한 복사 행위를 피하라.

list, dict 또는 array 같은 큰 객체를 복사하는 것은 시간과 메모리 측면에서 비용이 많이 들 수 있다. 복사 작업은 메모리에 새로운 객체를 생성하며, 이는 특히 대규모 데이터셋을 다루거나 많은 반복 작업을 수행해야하는 반복문 내에서 작업할 때 상당히 부담스러운 오버헤드가 된다. 

가능한 경우 객체를 복제하지 말고 그 자리에서 수정하여 새 구조체를 할당하고 채우는 오버헤드를 피하자.(메모리 사용량을 줄이고 성능을 향상시킵니다.) 파이썬의 많은 내장 데이터 구조들은 복사 작업이 필요 없는 인플레이스 메서드(예: sort, append, update)를 제공하고 이를 적극 활용하자.


당연하게도 in-place(복사행위 없는) 작업이 훨씬 속도가 빠르다.

In-place: 0.0000s
Copy: 0.0049s

성능이 중요한 코드에서는 객체가 언제, 어떻게 복제되는지 주의 깊게 살펴보고 reference(new_list = list)와 in-place 연산을 활용하면 크거나 복잡한 데이터 구조를 다룰 때 더 효율적이고 메모리 친화적인 코드를 작성할 수 있다.


3. 메모리 효율성을 위해서 객체의 구성요소관리에 __slots__ 를 사용하자.

기본적으로 Python 클래스는 인스턴스 속성을 동적 사전(__dict__)에 저장한다. 이는 유연성을 제공하지만 메모리 오버헤드가 발생하고 속성 접근 속도가 약간 느려진다.

__slots__를 사용하면 클래스에 대해 고정된 속성 집합을 명시적으로 선언할 수 있습니다. 이는 __dict__의 필요성을 없애 메모리 사용량을 줄여주며, 특히 클래스의 인스턴스를 많이 생성할 때 유용합니다. 또한 간소화된 내부 구조 덕분에 속성 접근 속도가 약간 빨라집니다.

__slots__는 동적 속성 할당을 제한하지만, 메모리 제약 환경이나 성능에 민감한 애플리케이션에서는 효율적이다. 경량 클래스나 데이터 컨테이너의 경우 __slots__를 적용하는 것이 코드를 더 효율적으로 만드는 간단한 방법이다.


하지만, 결과는 들쑥 날쑥이다. 우선 이론상 동적 메모리 관리가 정적 메모리 관리보다 훨씬 시간이 더 든다는 것은 당연한 사실이니 나름 합리적인 내용이다. 하지만 결과는 들쑥날쑥.... 

Without slots: 0.6076s
With slots: 0.5399s
...
Without slots: 0.4644s
With slots: 0.6735s

마무튼 이 내용은 보류.


4. 기본 연산자 대신 math 패키지를 사용하자.

수치 계산의 경우, Python의 math 모듈은 C로 구현된 함수를 제공하여 순수 Python으로 작성된 동일한 연산보다 더 나은 성능과 정밀도를 제공한다. 

예를 들어, math.sqrt()를 사용하는 것이 지수 연산자(**)를 사용하여 숫자를 0.5제곱하는 것보다 일반적으로 더 빠르고 정확합니다. 마찬가지로, math.sin(), math.exp(), math.log()와 같은 함수들은 속도와 신뢰성을 위해 고도로 최적화되어 있습니다.

이러한 성능 향상 효과는 특히 반복 작업을 수행하는 반복문이나 대규모 계산에서 두드러지게 나타난다. 수치 연산이 많은 작업에 수학 모듈을 활용하면 더 빠른 실행 속도와 더 일관된 결과를 동시에 달성할 수 있어, 과학적 계산, 시뮬레이션 또는 수학 연산이 많은 코드에 최적의 선택이다.


결과를 보면 명확해 진다.

Math sqrt: 0.4781s
Operator: 0.6468s


5. 공간의 크기가 명확히 정해져 있다면 메모리를 사전에 할당해서 사용하자.

동적으로 list나 array을 생성할 때 파이썬은 내부적으로 크기가 커짐에 따라 자동으로 크기를 조정한다. 편리하지만, 이러한 크기 조정은 새로운 크기의 메모리 할당과 데이터 복사 그리고 기존의 메모리 반납을 수반하여 오버헤드를 발생시킨다. 특히 대규모 루프나 성능이 중요한 루프에서 더욱 그렇다.

데이터 구조의 최종 크기를 미리 알고 있다면 매번 필요시에 동적할당을 수행하는 방식이 아닌 사전에 메모리를 미리 할당해서 사용하여 성능 향상시킬 수 있다. list나 array를 고정된 크기로 초기화하면 반복적으로 발생할 수 있는 (동적할당->복사->메모리반환) 크기 조정을 피할 수 있으며, 파이썬(또는 NumPy 같은 라이브러리)이 메모리를 더 효율적으로 관리할 수 있다.

이 기법은 수치 계산, 시뮬레이션, 대규모 데이터 처리에서 특히 유용하며 이런 작은 최적화조차도 연쇄적인 누적 효과를 낼 수 있다. 메모리를 사전 할당해서 사용하면 메모리 파편화(Memory Fragmentation)를 줄이고 캐시 지역성을 개선하며 더 예측 가능한 성능을 보장한다.


Pre-allocated: ~0.0300s
Dynamic: ~0.0400s


6. 집중 연산 구간에서 예외처리를 사용하지 말자.

파이썬의 예외 처리는 예상치 못한 동작을 관리하는 데 강력하고 깔끔하지만, 성능이 중요한 루프 내에서 적합하도록 설계된 것은 아니다. 예외 발생 및 포착에는 스택 추적(unwinding)과 컨텍스트 전환이 수반되며, 이는 상대적으로 비용이 많이 드는 작업이다.

hot loop(반복적으로 실행되거나 대량의 데이터를 처리하는 코드 구간)에서 제어 흐름을 위해 예외를 사용하면 성능이 크게 저하된다. 대신 오류가 발생하기 전에 이를 방지하기 위해 조건부 검사(if, in, is 등)를 사용하면, 훨씬 빠를 뿐만 아니라 더 예측 가능한 실행을 수행한다.

예상되는 제어 흐름보다는 진정으로 예외적인 경우에만 예외를 허용하면, 특히 성능이 중요한 타이트한 루프나 실시간 애플리케이션에서 더 깔끔하고 빠른 코드를 얻을 수 있다.


Conditional: 0.8241s
Exception: 1.3350s


7. 반복 수행과정에서 local 함수를 사용하자.

함수 내에서 특정 논리 블록이 반복적으로 수행해야 할 경우, 이를 지역(중첩) 함수(closure라고도 함)로 정의하면 성능과 가독성을 향상시킬 수 있다. 지역 함수는 이름 탐색 속도가 더 빠릅니다. 당연하게도 파이썬이 전역 범위보다 지역 범위에서 변수 혹은 함수를 조회하는 것이 더 빠르기 때문이다.

이 기법은 루프, 데이터 변환 또는 재귀적 프로세스와 같이 동일한 작업을 여러 번 적용하는 함수에서 특히 유용하고, 자주 사용되는 로직을 로컬로 유지함으로써 런타임 오버헤드와 인지 부하를 모두 줄일 수 있다.



Local function: 0.3879s
Global function: 0.6965s


8. 조합 연산에는 itertools를 사용하자.

개인적인 경험상 이를 통해 잃을 수 있는 손해가 더 많다고 생각하고 실행 속도의 실요성도 없어 보여서 제외함.


9. 정렬된 list 다룰 때 bisect를 사용하자.

정렬된 목록을 다룰 때 선형 검색이나 수동 삽입 로직을 사용하면 비효율적이다. 특히 목록이 커질수록 더욱 심해진다. Python의 bisect 모듈은 이진 검색을 사용하여 정렬된 순서를 유지하는 빠르고 효율적인 도구를 제공한다.

bisect_left(), bisect_right(), insort() 같은 함수를 사용하면 단순 스캔의 O(n) 복잡도와 달리 O(log n) 시간에 삽입 및 검색을 수행할 수 있다. 이는 리더보드 유지 관리, 이벤트 타임라인 관리, 효율적인 범위 쿼리 구현 같은 시나리오에서 특히 유용하다.

bisect 모듈을 사용하면 list 변경 후 매번 재정렬할 필요가 없어지며, 동적 정렬 데이터 작업 시 상당한 성능 향상을 얻을 수 있습니다. 이는 가볍고 강력한 도구로, 일반적인 list 작업에 알고리즘적 효율성을 제공합니다.



Bisect: 0.0004s
Loop: 0.0027s


10.  루프 내에서 반복된 함수 호출을 피하라.

이해할 수 없어서 개인적으로 제외한다.


요약

itertools, bisect, collections와 같은 특수 모듈은 복잡한 작업을 더욱 간소화하며, 전역 변수 사용 최소화, 메모리 사전 할당, 캐싱 구현과 같은 모범 사례 준수는 간결하고 효율적인 코드 실행을 보장합니다. 

2025년 11월 29일 토요일

c++에서 decltype(...)의 용도

 예전에 c언어에서 함수를 매개변수로 사용하기 위한 함수 타입을 추출하기 위해서 다음과 같은 작업을 수행해 왔다.


위와 같이 typedef로 함수 타입을 일일히 적시해 주어야 한다. 이러한 주어진 표현식(변수, 함수 등..)의 정확한 타입을 추출해서 컴파일 시점에 알려주는 기능이 decltype()이다.



2025년 11월 25일 화요일

Kanade 알고리즘(C++17 기반) - Maximum Sum Subarray Problem(최대 합을 갖는 부분 배열 찾기?)

0. 이건 뭔고?

연속된 시간 상의 영상 간의 optical flow를 추정하는데 유용하다고 하며, stereo imaging에서 depth map을 산출 할때 신뢰할 수 있는 기준점(ground control points)을 확보하는데 유용하다고 한다. 우선 이렇게 알아 두고 차츰 어떻게 적용되는지 알아 보도록 하자.

1. 내부변수

possible_subsum : 최대 부분합이 될 가능성이 있는 부분합

restart : possible_subsum 이 갱신되는 시점의 시작지점

max_subsum : 최대 부분합으로 possible_subsum과 항시 비교하여 최대값으로 유지된다.

start : max_subsum이 갱신되는 시점의 restart의 저장 변수

finish : max_subsum이 갱신되는 시점의 내부항목의 현재 위치

2. 사용법

    vector<int> a = { -8, -3, -6, -2, -5, -4 };

    auto [subsum, i, j] = kanade(a);

3. 코드


4. 컴파일 

$ g++ -std=c++17 kanada.cc -o kanada

$ ./kanada