"com.unity.barracuda" : 2.0.0
추가해주자Asset > Models
폴더를 만들어서 다운 받은 파일을 드래그 앤 드롭으로 넣어준다Asset > Scripts
폴더를 만들어서 GetInferenceFromModel.cs
스크립트를 생성// Import packages
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq; // List 데이터 관련 소스를 간단하게 만들어줌
using Unity.Barracuda;
using UnityEngine;
public class GetInferenceFromModel : MonoBehaviour
{
public Texture2D texture; // Texture2D: 텍스쳐 생성, 수정을 위한 속성
// 아래는 바라쿠다에서 쓰이는 타입들
public NNModel modelAsset;
private Model _runtimeModel;
private IWorker _engine;
[Serializable]
public struct Prediction
{
// The most likely value for this prediction
public int predictedValue;
// The list of likelihoods for all the possible classes
public float[] predicted;
public void SetPrediction(Tensor t)
{
// 주어진 텐서 t에 대해 inference를 수행하는 과정
predicted = t.AsFloats();
// 가장 확률이 높은 클래스를 저장
predictedValue = Array.IndexOf(predicted, predicted.Max());
Debug.Log($"Predicted {predictedValue}");
}
}
public Prediction prediction;
// Start is called before the first frame update
void Start()
{
// 모델 실행을 위한 런타임과 엔진 로드
_runtimeModel = ModelLoader.Load(modelAsset);
_engine = WorkerFactory.CreateWorker(_runtimeModel, WorkerFactory.Device.GPU);
// Instantiate our prediction struct.
prediction = new Prediction();
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
// 그레이 스케일 텐서 만들기
var channelCount = 1; //grayscale, 3 = color, 4 = color+alpha
// Create a tensor for input from the texture.
var inputX = new Tensor(texture, channelCount);
// Peek at the output tensor without copying it.
Tensor outputY = _engine.Execute(inputX).PeekOutput();
// Set the values of our prediction struct using our output tensor.
prediction.SetPrediction(outputY);
// Dispose of the input tensor manually (not garbage-collected).
inputX.Dispose();
}
}
private void OnDestroy()
{
// Dispose of the engine manually (not garbage-collected).
_engine?.Dispose();
}
}
여기까지 작성했으면 DoInferencing
이라는 새로운 오브젝트를 만들어준다
다음으로 스크립트를 다시 드래그해서 오른쪽 Inspector 창에 던져두고 아래 코드를 마저 작성한다
파일 > 새 이미지 생성
메뉴에서 28*28 이미지를 만들어주고 페인트칠 도구와 브러시를 이용해 숫자 손글씨 이미지를 만들어준다Texture
에는 방금 넣은 텍스쳐를 드래그하고, Model Asset
에는 MNist 모델을 드래그한 다음에 스페이스!를 눌러주면 예측값과 각 클래스별 logit을 확인할 수 있다Plane
라는 이름을 붙여준다blank.png
로 저장한다음에 에셋에 추가해준다DrawOnTexture.cs
라고 지으면 됨using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DrawOnTexture : MonoBehaviour
{
public Texture2D baseTexture;
// Update is called once per frame
void Update()
{
DoMouseDrawing();
}
/// <summary>
/// 마우스로 텍스쳐를 그립니다
/// </summary>
/// <exception cref="Exception"></exception>
private void DoMouseDrawing()
{
// Don't bother trying to run if we can't find the main camera.
if (Camera.main == null)
{
throw new Exception("연결된 카메라를 찾을 수 없습니다");
}
// 마우스 버튼 눌렸는지 확인
if (!Input.GetMouseButton(0) && !Input.GetMouseButton(1)) return;
// 유니티에서 Ray는 지정한 위치에서 무한대로 발사되는 선 (광선!)
// -> 이걸 이용하면 Ray에 닿은 물체 정보 반환가능
// Cast a ray into the scene from screenspace where the mouse is.
Ray mouseRay = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
// 마우스 작동 안할 때 확인
// Do nothing if we aren't hitting anything.
if (!Physics.Raycast(mouseRay, out hit)) return;
// Do nothing if we didn't get hit.
if (hit.collider.transform != transform) return;
// 마우스 ray가 닿은 좌표 가져오기
// Get the UV coordinate that the mouseRay hit
Vector2 pixelUV = hit.textureCoord;
pixelUV.x *= baseTexture.width;
pixelUV.y *= baseTexture.height;
// 색깔 관련 작업
// Set the color as white if the lmb is being pressed, black if rmb.
Color colorToSet = Input.GetMouseButton(0) ? Color.white : Color.black;
// Update the texture and apply.
baseTexture.SetPixel((int)pixelUV.x, (int)pixelUV.y, colorToSet);
baseTexture.Apply();
}
}
Plane
에 만든 스크립트를 드래그 해두고, base Texture에는 아까만든 blank.png
이미지를 드래그 해준다DoInferencing
오브젝트로 다시 돌아가서 Play
를 누르고 마우스 오른쪽 버튼을 통해 숫자를 쓴다음 스페이스를 눌러주면 - 완성!