Microsoft MVP성태의 닷넷 이야기
닷넷: 2247. C# - tensorflow 연동 (MNIST 예제) [링크 복사], [링크+제목 복사],
조회: 11055
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
(연관된 글이 1개 있습니다.)

C# - tensorflow 연동 (MNIST 예제)

요즘 접하기 쉬운 예제로 MNIST 손글씨 인식을 C#에서 tensorflow와 연동해 만들어 보겠습니다. 여기서 중요한 것은, Model을 구해야 하는 것인데요 ^^ 그 부분은 그냥 파이썬 환경에서 자유롭게 코딩해 구하기만 하면 됩니다.

예를 들어, 아래의 MNIST 예제는 my_mnist_model.keras 파일로 모델을 저장하고 있습니다.

// 케라스 창시자에게 배우는 딥러닝
// https://github.com/gilbutITbook/080315/blob/main/chapter02_mathematical-building-blocks.ipynb

import setuptools.dist
from tensorflow.keras.datasets import mnist
(train_images, train_labels), (test_images, test_labels) = mnist.load_data()

from tensorflow import keras
from tensorflow.keras import layers

model = keras.Sequential([
    layers.Dense(512, activation='relu'),
    layers.Dense(10, activation='softmax')
    ])

model.compile(optimizer='rmsprop', loss='sparse_categorical_crossentropy', metrics=['accuracy'])

train_images = train_images.reshape((60000, 28 * 28))
train_images = train_images.astype('float32') / 255

test_images = test_images.reshape((10000, 28 * 28))
test_images = test_images.astype('float32') / 255

model.fit(train_images, train_labels, epochs=5, batch_size=128)

test_loss, test_acc = model.evaluate(test_images, test_labels)
print(f'{test_acc}')

# https://www.tensorflow.org/tutorials/keras/save_and_load?hl=ko
model.save('my_mnist_model.keras')

my_mnist_model.keras 파일의 크기는 3MB 정도 됩니다. 이렇게 구한 Model 파일은 C# 프로젝트에 추가/배포해, 실행 시 C#에서 Python.NET을 이용해 저 Model 파일을 로드해 활용할 것입니다.




자, 그럼 본격적으로 위에서 만든 MNIST 필기체 인식 Model을 C#에서 Python과 연동해 볼까요? ^^

이를 위해, 모델을 이용한 predict 코드를 호출하는 파이썬 코드를 다음과 같이 만들어 줍니다.

# mnist_predict.py

import setuptools.dist
import tensorflow as tf
import numpy as np

model = tf.keras.models.load_model('my_mnist_model.keras')

def predict(img):
    imgs = np.expand_dims(img, axis=0)
    predictions = model.predict(imgs, verbose=0)
    predict_number = np.argmax(predictions[0])
    return (predict_number.item(), predictions[0][predict_number].item())

위의 predict 함수는 model.predict 호출 시 해당 이미지로 판정되는 숫자와 그 확률을 반환합니다.

그럼, 이제 Python.NET을 이용한 C# 코드에서는 이를 호출하는 코드만 다음과 같이 작성해 주면 됩니다.

using Python.Runtime;

namespace ConsoleApp3;

internal class Program
{
    static void Main(string[] args)
    {
        Runtime.PythonDLL = @".\python\python312.dll";

        PythonEngine.Initialize();

        using (_ = Py.GIL())
        {
            DisableTensorflowLog();

            dynamic npModule = Py.Import("numpy");

            {
                dynamic sys = Py.Import("sys");
                string dirPath = Path.GetDirectoryName(typeof(Program).Assembly.Location) ?? Environment.CurrentDirectory;
                sys.path.append(dirPath);
            }

            float[]? testImgArray = // ... 28x28 크기의 이미지 데이터 ...;
            dynamic npArray = npModule.array(testImgArray);

            {
                var pyFile = Py.Import(Path.GetFileNameWithoutExtension("mnist_predict"));

                dynamic results = pyFile.InvokeMethod("predict", npArray);

                int expected = results[0];
                double percentage = results[1];

                Console.WriteLine($"{expected}: {percentage:P0}");
            }
        }

        PythonEngine.Shutdown();
    }
}

만약 testImgArray에 7과 비슷한 숫자의 이미지를 담고 있는 28x28 크기의 버퍼가 있다면 위의 프로그램을 실행 시 "7: 100%"와 유사한 출력이 나옵니다.

(첨부 파일은 이 글의 예제 코드를 포함합니다.)

만약 지난 글에 설명한 대로 CopyToOutputDirectory 설정을 했다면, 위의 예제를 실행했을 때 "C:\temp\ConsoleApp3\net8.0" 디렉터리에 출력이 모였을 것입니다. 해당 출력 파일만 다른 컴퓨터에 그대로 복사하면 (당연히 별도의 파이썬 설치 없이) 정상적으로 실행까지 됩니다.

한 가지 문제점이라면, 위의 경우 net8.0 출력에 있는 전체 바이너리의 크기가 (python + tensorflow까지 포함하므로) 1.6GB 정도, 압축하면 480MB 정도 됩니다. 만약 대상 컴퓨터에 파이썬 tensorflow 환경이 설치돼 있다면 이 용량을 없앨 수 있지만 그렇지 않은 경우라면... 뭔가 있어 보이는 ^^ 응용 프로그램의 크기를 자랑합니다.




참고로, 위의 코드를 Windows 10+ 환경에서 Python 3.12.0 버전으로 실행하면 load_model 시에 다음과 같은 오류가 발생합니다.

Traceback (most recent call last):
  File "C:\temp\ConsoleApp3\net8.0\python\test.py", line 36, in <module>
    model2 = tf.keras.models.load_model('my_mnist_model.keras')
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\temp\ConsoleApp3\net8.0\python\Lib\site-packages\keras\src\saving\saving_api.py", line 176, in load_model
    return saving_lib.load_model(
           ^^^^^^^^^^^^^^^^^^^^^^
  File "C:\temp\ConsoleApp3\net8.0\python\Lib\site-packages\keras\src\saving\saving_lib.py", line 152, in load_model
    return _load_model_from_fileobj(
           ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\temp\ConsoleApp3\net8.0\python\Lib\site-packages\keras\src\saving\saving_lib.py", line 207, in _load_model_from_fileobj
    _raise_loading_failure(error_msgs)
  File "C:\temp\ConsoleApp3\net8.0\python\Lib\site-packages\keras\src\saving\saving_lib.py", line 295, in _raise_loading_failure
    raise ValueError(msg)
ValueError: A total of 1 objects could not be loaded. Example error message for object <keras.src.optimizers.adam.Adam object at 0x000001CBB0BCFBF0>:

The shape of the target variable and the shape of the target value in `variable.assign(value)` must match. variable.shape=(10,), Received: value.shape=(512, 10). Target variable: <KerasVariable shape=(10,), dtype=float32, path=adam/dense_1_bias_momentum>

List of objects that could not be loaded:
[<keras.src.optimizers.adam.Adam object at 0x000001CBB0BCFBF0>]))

3.12.2 이상의 버전에서 하면 오류가 발생하지 않습니다.




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]

[연관 글]






[최초 등록일: ]
[최종 수정일: 4/24/2024]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 




... 76  77  78  79  80  81  82  83  84  85  [86]  87  88  89  90  ...
NoWriterDateCnt.TitleFile(s)
11822정성태2/20/201920741오류 유형: 517. docker에 설치한 MongoDB 서버로 연결이 안 되는 경우
11821정성태2/20/201921522오류 유형: 516. Visual Studio 2019 - This extension uses deprecated APIs and is at risk of not functioning in a future VS update. [1]
11820정성태2/20/201924590오류 유형: 515. 윈도우 10 1809 업데이트 후 "User Profiles Service" 1534 경고 발생
11819정성태2/20/201923770Windows: 158. 컴퓨터와 사용자의 SID(security identifier) 확인 방법
11818정성태2/20/201921763VS.NET IDE: 131. Visual Studio 2019 Preview의 닷넷 프로젝트 빌드가 20초 이상 걸리는 경우 [2]
11817정성태2/17/201917749오류 유형: 514. WinDbg Preview 실행 오류 - Error : DbgX.dll : WindowsDebugger.WindowsDebuggerException: Could not load dbgeng.dll
11816정성태2/17/201921668Windows: 157. 윈도우 스토어 앱(Microsoft Store App)을 명령행에서 직접 실행하는 방법
11815정성태2/14/201919802오류 유형: 513. Visual Studio 2019 - VSIX 설치 시 "The extension cannot be installed to this product due to prerequisites that cannot be resolved." 오류 발생
11814정성태2/12/201918335오류 유형: 512. VM(가상 머신)의 NT 서비스들이 자동 시작되지 않는 문제
11813정성태2/12/201919340.NET Framework: 809. C# - ("Save File Dialog" 등의) 대화 창에 확장 속성을 보이는 방법
11812정성태2/11/201916719오류 유형: 511. Windows Server 2003 VM 부팅 후 로그인 시점에 0xC0000005 BSOD 발생
11811정성태2/11/201922590오류 유형: 510. 서버 운영체제에 NVIDIA GeForce Experience 실행 시 wlanapi.dll 누락 문제
11810정성태2/11/201919526.NET Framework: 808. .NET Profiler - GAC 모듈에서 GAC 비-등록 모듈을 참조하는 경우의 문제
11809정성태2/11/201922332.NET Framework: 807. ClrMD를 이용해 메모리 덤프 파일로부터 특정 인스턴스를 참조하고 있는 소유자 확인
11808정성태2/8/201923772디버깅 기술: 123. windbg - 닷넷 응용 프로그램의 메모리 누수 분석
11807정성태1/29/201921517Windows: 156. 가상 디스크의 용량을 복구 파티션으로 인해 늘리지 못하는 경우 [4]
11806정성태1/29/201920681디버깅 기술: 122. windbg - 덤프 파일로부터 PID와 환경 변수 등의 정보를 구하는 방법
11805정성태1/28/201923395.NET Framework: 806. C# - int []와 object []의 차이로 이해하는 제네릭의 필요성 [4]파일 다운로드1
11804정성태1/24/201920972Windows: 155. diskpart - remove letter 이후 재부팅 시 다시 드라이브 문자가 할당되는 경우
11803정성태1/10/201919956디버깅 기술: 121. windbg - 닷넷 Finalizer 스레드가 멈춰있는 현상
11802정성태1/7/201921575.NET Framework: 805. 두 개의 윈도우를 각각 실행하는 방법(Windows Forms, WPF)파일 다운로드1
11801정성태1/1/201922631개발 환경 구성: 427. Netsh의 네트워크 모니터링 기능 [3]
11800정성태12/28/201821999오류 유형: 509. WCF 호출 오류 메시지 - System.ServiceModel.CommunicationException: Internal Server Error
11799정성태12/19/201823920.NET Framework: 804. WPF(또는 WinForm)에서 UWP UI 구성 요소 사용하는 방법 [3]파일 다운로드1
11798정성태12/19/201822526개발 환경 구성: 426. vcpkg - "Building vcpkg.exe failed. Please ensure you have installed Visual Studio with the Desktop C++ workload and the Windows SDK for Desktop C++"
11797정성태12/19/201818229개발 환경 구성: 425. vcpkg - CMake Error: Problem with archive_write_header(): Can't create '' 빌드 오류
... 76  77  78  79  80  81  82  83  84  85  [86]  87  88  89  90  ...