CoreML 공부 정리

준우·2023년 12월 12일
0

Swift 이야기

목록 보기
2/19
post-thumbnail

만들어진 CoreML 사용해보기

참고 블로그 : https://ios-daniel-yang.tistory.com/29

참고 사항 : https://developer.apple.com/kr/machine-learning/models/#text

  • 위 블로그에서 사용한 Flower MLModel 을 사용하지 않고, 위 참고 사항 링크(=애플 공식 제공 MLModel) 을 사용하였습니다.

CoreML의 특징

  • 네트워크 없이 사용 가능
  • OnDevice 형식 ML 이기 때문에 보안측면에서 안전합니다.
  • Apple 기기와의 빠른 호환성

사용 방법

1. CoreML & Vision 을 import 합니다.

2. 카메라를 사용하기 위해 UIImagePicker 변수를 생성합니다.

var imagePicker: UIImagePickerController {
    let picker = UIImagePickerController()
    picker.delegate = self
    picker.sourceType = .camera    // 기본값은 카메라 라이브러리, 이미지를 찍을 수 있게 설정
    picker.allowsEditing = true    // 선택한 이미지나 동영상 편집 여부를 설정(Bool)

    return picker
}

3. CoreML 과 Vision 으로 이미지를 처리하기 위한 detect(image: CIImage)란 함수를 만듭니다.

  • CoreML 의 이미지를 읽기 위해서는 꼭 CIImage(Core Image) 타입으로 변환해야 합니다.

  • 훈련된 모델을 요청(Request) 한 후 handler 로 처리해서 분석을 합니다.

  • 사용 예시

// CoreML의 CIImage를 처리하고 해석하기 위한 메서드 생성, 이것은 모델의 이미지를 분류하기 위해 사용 됩니다.
func detect(image: CIImage) {
    // CoreML의 모델인 FlowerClassifier를 객체를 생성 후,
    // Vision 프레임워크인 VNCoreMLModel 컨터이너를 사용하여 CoreML의 model에 접근합니다.
    guard let coreMLModel = try? MobileNetV2(configuration: MLModelConfiguration()),
          let visionModel = try? VNCoreMLModel(for: coreMLModel.model) else {
        fatalError("Loading CoreML Model Failed")
    }
    // Vision을 이용해 이미치 처리를 요청
    let request = VNCoreMLRequest(model: visionModel) { request, error in
        guard error == nil else {
            fatalError("Failed Request")
        }
        // 식별자의 이름(꽃 이름)을 확인하기 위해 VNClassificationObservation로 변환해줍니다.
        guard let classification = request.results as? [VNClassificationObservation] else {
            fatalError("Faild convert VNClassificationObservation")
        }
        // 머신러닝을 통한 결과값 프린트
        print(classification)
    }

    // 이미지를 받아와서 perform을 요청하여 분석합니다. (Vision 프레임워크)
    let handler = VNImageRequestHandler(ciImage: image)
    do {
        try handler.perform([request])
    } catch {
        print(error)
    }
}

4. UIImagePickerControllerDelegate 를 통해 훈련된 모델과 이미지랑 비교를 합니다.

  • 위에서 만들어준 메서드로 CIImage 를 분석을 합니다.

  • 사용 예시

// 사진을 찍은 후 이미지를 갖고 할 일들을 정의
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {

    picker.dismiss(animated: true)

    // info의 키 값으로 수정한 사진 이미지 받아옵니다.
    guard let userPickedImage = info[UIImagePickerController.InfoKey.editedImage] as? UIImage else {
        fatalError("Failed Original Image pick")
    }

    // 위에서 받은 이미지를 이미지 뷰에 저장
    imageView.image = userPickedImage

    // Core모델 이미지로 사용하기 위해 CIImage로 변환
    guard let coreImage = CIImage(image: userPickedImage) else {
        fatalError("Faild convert CIImage")
    }

    // 변환 된 CIImage를 갖고 이미지를 처리하는 메서드 호출
    detect(image: coreImage)
}
  • 출력 후 확인해야 하는 부분
    • Confidence : 정확도
    • Idntifier : 이름
  • 필요한 정보
    • VNClassificationObservation 배열 중 정확도(=Confidence) 와 이름(=Identifier) 이 가장 높은 값, 즉 첫 번째 값만 확인하면 됩니다.

4.1 타이틀 값을 바꿔줍니다.

  • Print 값 대신 VNClassificationObservation 배열의 첫 번째 타이틀을 identifier 로 설정해 줍니다.

  • 사용 예시

// 👉 타이틀을 가장 정확도 높은 이름으로 설정
if let fitstItem = classification.first {
    self.navigationItem.title = fitstItem.identifier.capitalized
}

애플에서 제공한 MobileNetV2 사용시, 유의할 점

  • 기린 & 치타 & 가젤 사진에서 부정확한 결과가 매우 많이 발생합니다.
  • 그 외의 얼룩말, 호랑이 등등 동물에서는 매우 정확한 결과가 발생합니다.

결론

  • CoreML과 Vision을 사용하려면,
  1. CoreML & Vision 을 import 합니다.
  2. 카메라를 사용하기 위해 UIImagePicker 변수를 생성합니다.
  3. CoreML 과 Vision 으로 이미지를 처리하기 위한 detect(image: CIImage)란 함수를 만듭니다.
  4. UIImagePickerControllerDelegate 를 통해 훈련된 모델과 이미지랑 비교를 합니다.
  • 전체 코드
import CoreML
import UIKit
import Vision // CoreML 과 작업을 할 때 이미지를 보다 쉽게 처리할 수 있게 도와주는 프레임워크

class ViewController: UIViewController {
    @IBOutlet weak var imageView: UIImageView!

    var imagePicker: UIImagePickerController {
        let picker = UIImagePickerController()
        picker.delegate = self
        picker.sourceType = .camera // 기본값은 카메라 라이브러리, 이미지를 찍을 수 있게 설정
        picker.allowsEditing = true // 선택한 이미지나 동영상 편집 여부를 설정(Bool
        return picker
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
    }

    @IBAction func cameraTapped(_ sender: UIBarButtonItem) {
        // UIImagePickerController 도 ViewController 이므로 present로 불러와야 한다.
        present(imagePicker, animated: true)
    }
}

// MARK: - CoreML 이미지 분류

extension ViewController {
    // CoreML 의 CIImage를 처리하고 해석하기 위한 메서드 생성, 이것은 모델의 이미지를 분류하기 위해 사용 됩니다.
    func detectImage(image: CIImage) {
        // CoreML의 모델인 FlowerClassifier를 객체를 생성 후,
        // Vision 프레임워크인 VNCoreMLModel 컨테이너를 사용하여 CoreML의 model에 접근한다.
        guard let coreMLModel = try? MobileNetV2(configuration: MLModelConfiguration()),
              let visionModel = try? VNCoreMLModel(for: coreMLModel.model)
        else {
            fatalError("Loading CoreML Model Failed")
        }

        // Vision 을 이용해 이미지 처리를 요청
        let request = VNCoreMLRequest(model: visionModel) { request, error in
            guard error == nil else {
                fatalError("Failed Request")
            }

            // 식별자의 이름(꽃 이름)을 확인하기 위해 VNClassificationObservation 로 변환해준다.
            guard let classification = request.results as? [VNClassificationObservation] else {
                fatalError("Failed convert VNClassificationObservation")
            }

            // 타이틀을 가장 정확도 높은 이름으로 설정
            if let firstItem = classification.first {
                self.navigationItem.title = firstItem.identifier.capitalized
            }

            // 머신러닝을 통한 결과값 프린트
            print("#### \(classification)")
        }

        // 이미지를 받아와서 perform을 요청하여 분석한다. (Vision 프레임워크)
        let handler = VNImageRequestHandler(ciImage: image)

        do {
            try handler.perform([request])
        } catch {
            print(error)
        }
    }
}

// MARK: - UIImagePickerControllerDelegate & UINavigationControllerDelegate

extension ViewController: UIImagePickerControllerDelegate & UINavigationControllerDelegate {
    // 사진을 찍은 후 이미지를 갖고 할 일들을 정의
    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) {
        picker.dismiss(animated: true)

        // info의 키 값으로 수정한 사진 이미지 받아온다.
        guard let userPickedImage = info[UIImagePickerController.InfoKey.editedImage] as? UIImage else {
            fatalError("Failed Original Image pick")
        }

        // 위에서 받은 이미지를 이미지 뷰에 저장
        imageView.image = userPickedImage

        // Core모델 이미지로 사용하기 위해 CIImage로 변환
        guard let coreImage = CIImage(image: userPickedImage) else {
            fatalError("Faild convert CIImage")
        }

        // 변환 된 CIImage를 갖고 이미지를 처리하는 메서드 호출
        detectImage(image: coreImage)
    }
}

0개의 댓글