소피it블로그
[Vision] VNCoreMLModel, VNCoreMLRequest 정리 본문
https://developer.apple.com/documentation/vision/vncoremlmodel
1. VNCoreMLModel
비전 요청에 사용되는 Core ML 모델의 컨테이너
class VNCoreMLModel : NSObject
코어 ML 모델은 비전 인식 요청에 사용되는 데이터 셋으로부터 트레이닝된 정보를 감싼다. 모델을 트레이닝한 후에 이 클래스를 사용하여 VNCoreMLRequest를 초기화하라.
https://developer.apple.com/documentation/vision/vncoremlrequest
2. VNCoreMLRequest
이미지를 처리하기 위해 Core ML 모델을 사용하는 이미지 분석 요청
class VNCoreMLRequest : VNImageBasedRequest
코어 ML에 기반한 이미지 분석 요청의 결과 배열(results array)은 요청을 생성한 MLModel의 객체의 종류에 따라 다른 옵저베이션 타입을 갖는다.
- 만약 모델이 하나의 특징만을 예측한다면, 즉 모델의 modelDescription 객체가 nil이 아닌 predictiedFeatureName 프라퍼티 값을 갖는다면, 비전은 해당 모델을 classifier로 여긴다: 결과는 VNClassificationObservation 객체이다.
- 모델의 결과 중 MLFeatureType.image를 포함하는 결과가 하나라도 있다면, 비전은 해당 모델을 image-to-image 모델로 취급한다: 결과는 VNPixelBufferObservation 객체이다.
- 이외의 경우 비전은 모델을 일반적인 predictor(예측) 모델로 취급한다: 결과는 VNCoreMLFeatureValueObservation 객체이다.
이상은 애플의 공식 문서를 대충 번역한 것이고, 내가 프로젝트를 진행하면서 배웠던 점을 간단하게 기록하자면 다음과 같다.
1. CoreML과 비전을 사용하여 이미지 분류를 하려고 하는 경우:
- 모델 생성: Create ML에서 Image Classification을 선택하여 모델을 학습시킨다.
- 프로젝트에 모델 불러오기: VNCoreMLModel을 생성하고 이에 대한 VNCoreMLRequest를 생성한다.
- results: 결과 배열에는 모델이 분류한 이미지의 카테고리가 내림차순으로 반영된다. 예를 들어 가장 확률 높은 예측을 가져오고 싶다면 results.first를 해주면 됨
- 대충 코드를 적자면 다음과 같다.
func classifyImage(image: CIImage) {
// 모델 생성
guard let model = try? VNCoreMLModel(for: Classifier().model) else {
return
}
// 리퀘스트 생성
// 리퀘스트 결과는 VNClassificationObservation의 배열
let request = VNCoreMLRequest(model: model) { request, error in
guard let result = request.results as? [VNClassificationObservation] else {
return
}
// 해당 배열에서 가장 첫 번째 요소(가장 확률 높은 카테고리) 이름 가져오기
self.textLabel.text = result.first?.identifier
}
// 리퀘스트를 처리해줄 핸들러 선언
let handler = VNImageRequestHandler(ciImage: image)
do {
try handler.perform([request])
} catch {
print(error)
}
}
2. CoreML과 비전을 사용하여 이미지 스타일 전환을 하려고 하는 경우:
- 모델 생성: Create ML에서 Style Transfer를 선택하여 모델을 학습시킨다.
- 프로젝트에 모델 불러오기: VNCoreMLModel을 생성하고 이에 대한 VNCoreMLRequest를 생성한다.
- results: 결과 배열에는 MLFeatureType.image라는 결과가 포함된다. 정확히 이해한 것인지는 모르겠지만, 내가 이해한 바로는 image가 모델의 결과 배열에 들어있으면 비전은 이를 image-to-image 모델로 본다는 뜻인 것 같다.
- 코드로 대강 구현하자면 다음과 같다.
func transferImageStyle(image: CIImage) {
// 모델 생성
guard let model = try? VNCoreMLModel(for: Transferer().model) else {
return
}
// 리퀘스트 생성
// 리퀘스트의 결과 배열에는 VNPixelBufferObservation 객체들이 담긴다.
let request = VNCoreMLRequest(model: model) { request, error in
guard let transfer = request.results as? [VNPixelBufferObservation] else {
return
}
guard let image = transfer.first?.pixelBuffer else {
return
}
// 이 부분은 익스텐션으로 pixelBuffer를 UIImage로 변경해준 것인데 해당 익스텐션 코드는 여기에 포함하지 않았다.
self.imageView.image = UIImage(pixelBuffer: image)
}
// 핸들러 선언
let handler = VNImageRequestHandler(ciImage: image)
do {
try handler.perform([request])
} catch {
print(error)
}
}
눈여겨볼 차이점이 있다면, 우선 결과 배열에 VNClassificationObservation이 담기느냐 혹은 VNPixelBufferObservation이 담기느냐의 차이가 있다. 또한 스타일 전환의 경우 전환된 스타일이 적용된 새로운 이미지는 pixelBuffer라는 이름으로 접근할 수 있는 것으로 보이는데, 이를 UIImage로 바로 변환해주는 것은 오류가 떴기 때문에 구글링의 힘을 빌려 익스텐션으로 처리 코드를 추가해주었다(여기에선 생략).
참고한 웹사이트:
https://www.udemy.com/course/ios-13-app-development-bootcamp/
섹션 24참조
'개발_iOS > iOS 기타' 카테고리의 다른 글
[iOS 개발] 앱 로컬라이징 관련 (1) | 2022.09.08 |
---|---|
[Vision] VNPixelBufferObservation, pixelBuffer 정리 (0) | 2022.08.29 |
[Dispatch] DispatchQueue, main, async 정리 (0) | 2022.08.24 |
[Combine] Published 정리 (1) | 2022.08.12 |
[Combine] ObservableObject 정리 (0) | 2022.08.12 |