성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] Roll A Lisp In C - Reading ; https...
[정성태] Java - How to use the Foreign Funct...
[정성태] 제가 큰 실수를 했군요. ^^; Delegate를 통한 Bein...
[정성태] Working with Rust Libraries from C#...
[정성태] Detecting blocking calls using asyn...
[정성태] 아쉽게도, 커뮤니티는 아니고 개인 블로그입니다. ^^
[정성태] 질문이 잘 이해가 안 됩니다. 우선, 해당 소스코드에서 ILis...
[양승조
] var대신 dinamic으로 선언해서 해결은 했습니다. 맞는 해...
[양승조
] 또 막혔습니다. ㅠㅠ var list = props[i].Ge...
[양승조
] 아. 감사합니다. 어제는 안됐던것 같은데....정신을 차려야겠네...
글쓰기
제목
이름
암호
전자우편
HTML
홈페이지
유형
제니퍼 .NET
닷넷
COM 개체 관련
스크립트
VC++
VS.NET IDE
Windows
Team Foundation Server
디버깅 기술
오류 유형
개발 환경 구성
웹
기타
Linux
Java
DDK
Math
Phone
Graphics
사물인터넷
부모글 보이기/감추기
내용
<div style='display: inline'> <h1 style='font-family: Malgun Gothic, Consolas; font-size: 20pt; color: #006699; text-align: center; font-weight: bold'>C# - tensorflow 연동 (MNIST 예제)</h1> <p> 요즘 접하기 쉬운 예제로 MNIST 손글씨 인식을 C#에서 tensorflow와 연동해 만들어 보겠습니다. 여기서 중요한 것은, Model을 구해야 하는 것인데요 ^^ 그 부분은 그냥 파이썬 환경에서 자유롭게 코딩해 구하기만 하면 됩니다.<br /> <br /> 예를 들어, 아래의 MNIST 예제는 my_mnist_model.keras 파일로 모델을 저장하고 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // <a target='tab' href='https://product.kyobobook.co.kr/detail/S000061584677'>케라스 창시자에게 배우는 딥러닝</a> // <a target='tab' href='https://github.com/gilbutITbook/080315/blob/main/chapter02_mathematical-building-blocks.ipynb'>https://github.com/gilbutITbook/080315/blob/main/chapter02_mathematical-building-blocks.ipynb</a> 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}') # <a target='tab' href='https://www.tensorflow.org/tutorials/keras/save_and_load?hl=ko'>https://www.tensorflow.org/tutorials/keras/save_and_load?hl=ko</a> <span style='color: blue; font-weight: bold'>model.save('my_mnist_model.keras')</span> </pre> <br /> my_mnist_model.keras 파일의 크기는 3MB 정도 됩니다. 이렇게 구한 Model 파일은 C# 프로젝트에 추가/배포해, 실행 시 C#에서 Python.NET을 이용해 저 Model 파일을 로드해 활용할 것입니다.<br /> <br /> <hr style='width: 50%' /><br /> <br /> 자, 그럼 본격적으로 위에서 만든 MNIST 필기체 인식 Model을 C#에서 Python과 연동해 볼까요? ^^<br /> <br /> 이를 위해, 모델을 이용한 predict 코드를 호출하는 파이썬 코드를 다음과 같이 만들어 줍니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > # mnist_predict.py import setuptools.dist import tensorflow as tf import numpy as np <span style='color: blue; font-weight: bold'>model = tf.keras.models.load_model('my_mnist_model.keras')</span> <span style='color: blue; font-weight: bold'>def predict(img):</span> imgs = np.expand_dims(img, axis=0) <span style='color: blue; font-weight: bold'>predictions = model.predict(imgs, verbose=0)</span> predict_number = np.argmax(predictions[0]) return (predict_number.item(), predictions[0][predict_number].item()) </pre> <br /> 위의 predict 함수는 model.predict 호출 시 해당 이미지로 판정되는 숫자와 그 확률을 반환합니다.<br /> <br /> 그럼, 이제 Python.NET을 이용한 C# 코드에서는 이를 호출하는 코드만 다음과 같이 작성해 주면 됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 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); } <span style='color: blue; font-weight: bold'>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}"); }</span> } PythonEngine.Shutdown(); } } </pre> <br /> 만약 testImgArray에 7과 비슷한 숫자의 이미지를 담고 있는 28x28 크기의 버퍼가 있다면 위의 프로그램을 실행 시 "7: 100%"와 유사한 출력이 나옵니다.<br /> <br /> (<a target='tab' href='https://www.sysnet.pe.kr/bbs/DownloadAttachment.aspx?fid=2166&boardid=331301885'>첨부 파일은 이 글의 예제 코드를 포함</a>합니다.)<br /> <br /> 만약 <a target='tab' href='https://www.sysnet.pe.kr/2/0/13605#copy_to_dir'>지난 글에 설명한 대로 CopyToOutputDirectory</a> 설정을 했다면, 위의 예제를 실행했을 때 "C:\temp\ConsoleApp3\net8.0" 디렉터리에 출력이 모였을 것입니다. 해당 출력 파일만 다른 컴퓨터에 그대로 복사하면 (당연히 별도의 파이썬 설치 없이) 정상적으로 실행까지 됩니다.<br /> <br /> 한 가지 문제점이라면, 위의 경우 net8.0 출력에 있는 전체 바이너리의 크기가 (python + tensorflow까지 포함하므로) 1.6GB 정도, 압축하면 480MB 정도 됩니다. 만약 대상 컴퓨터에 파이썬 tensorflow 환경이 설치돼 있다면 이 용량을 없앨 수 있지만 그렇지 않은 경우라면... 뭔가 있어 보이는 ^^ 응용 프로그램의 크기를 자랑합니다.<br /> <br /> <hr style='width: 50%' /><br /> <br /> 참고로, 위의 코드를 Windows 10+ 환경에서 Python 3.12.0 버전으로 실행하면 load_model 시에 다음과 같은 오류가 발생합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 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>])) </pre> <br /> <a target='tab' href='https://github.com/tensorflow/tensorflow/issues/63365'>3.12.2 이상</a>의 버전에서 하면 오류가 발생하지 않습니다.<br /> </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
1610
(왼쪽의 숫자를 입력해야 합니다.)