물론 실제 마법이 Core ML에 있진 않지만, 여러분의 모델에 들어있다. 여러분이 시작할때 적절한 모델을 가지고 있지 않다면 Core ML은 소용없을 것이다. 그리고 모델을 설계하고 학습시키는것은 기계학습에서 어려운 부분이다.
앱은 아직 멋지지 않지만(단순히 정적인 이미지에대해 상위 5가지 예측의 아웃풋을 낸다) Core ML을 어떻게 쉽게 사용했는지 보여준다. 그냥 코드 몇줄만이 필요할 뿐이었다.
주의: 데모앱이 시뮬레이터에서는 잘 동작하지만 기기에서는 크래쉬가 난다. 읽어내려가서 왜 그런지 찾아내보자 ;-)
물론 안에서 무슨일이 일어나는지 알고싶었다. 실제로 mlmodel 파일이 mlmodelc 폴더에 컴파일되었으며 이 폴더는 여러분의 앱 번들 안에 있다. 이 폴더는 여러 다른 파일들, 몇몇 바이너리, 몇몇 JSON들을 가진다. 따라서 여러분의 앱에 실제로 넣기전에 Core ML이 어떻게 mlmodel을 변환하는지 볼 수 있다.
예를들어 MobileNet Caffe 모델은 소위 Batch Normalization 레이어라 불리는 것을 사용하며, 이것들이 변환된 mlmodel 파일안에 들어있다는 것을 확인했다. 그러나 컴파일된 mlmodelc에서는 Batch Normalization 레이어가 보이지 않았다. 이것은 Core ML이 모델을 최적화시켰다는 좋은 소식이다.
mlmodelc는 여전히 스케일링 레이어(scaling layer)를 포함하며 반드시 필요하지 않아 보이므로 좀 더 모델의 구조를 최적화할 수 있을것 같아 보인다.
물론 아직 iOS11 베타1버전이고 Core ML은 아마 더 개선될 것이다. 그 말은, Core ML에 넘겨주기전에 여러분의 모델을 최적화할 필요가 있다는 뜻이다. (“folding” the Batch Normaliza) 그러나 그렇게하면 특정 모델을위해 측정하고 비교해야할 것이다.
여러분의 모델이 CPU에서 실행될때와 GPU에서 실행될때 같은지도 확인해야할 것이다. 내가 언급한것처럼 Core ML은 모델을 CPU에서 돌릴지(Accelerate 프레임워크를 사용하여) GPU에서 돌릴지(Metal을 사용하여) 정한다. 결국 이 두 구현은 다르게 동작할 것이다. 그러니 둘 다 테스트해봐야한다!
예를들어 MobileNet은 "depthwise" 컨볼루션 레이어라 불리는 것을 사용한다. 이 원래 모델은 Caffe에서 학습되었고, 정규 컨볼루션의 groups 프로퍼티와 아웃풋 채널 수를 같게 만들어 depthwise 컨볼루션을 지원한다. 결과로나온 MobileNet.mlmodel 파일은 동일하지 않다. 이것이 iOS 시뮬레이터 안에서는 잘 동작하겠지만 실제 디바이스 위에서는 크래쉬가 난다!
시뮬레이터는 Accelerate 프레임워크를 사용하지만 실제 디바이스는 Metal Performance Shaders를 사용하여 생긴 문제이다. 그리고 Metal이 데이터를 인코딩하는 방법때문에 MPSCNNConvolution 커널은 제한되어 그룹의 수와 아웃풋 채널의 수를 같게 만들 수 없게 되었다. 아이고!
나는 애플에 버그리포팅을 제출했지만 내 요점은 이렇다. 시뮬레이터에서 모델이 잘 동작한다는게 디바이스에서 잘 동작할거라는 의미는 아니다. 테스트를 해보아라!
얼마나 빠른가?
나의 새로운 10.5" iPad Pro가 다음주까지 도착하지 않기 때문에(역자: 부럽습니다) Core ML의 속도를 시험해보지 못했다
나는 특별히 MobileNets을 실행시키는데 나의
Forge library를 이용할때와 Core ML을 이용할때 그 속도 차이가 어떻게 되는지 관심이 갔다(아직 초기 베타 단계에 있다).
채널을 고정하라! 공유할 데이터가 생기면 이 섹션을 업데이트 할 것이다.
Vision
다음으로 이야기할것은 새로나온 Vision 프레임워크이다.
여러분도 이름에서 추측했을지 모르겠지만, Vision은 컴퓨터비젼(computer vision) 테스크를 실행시켜준다. 과거에는 이를위해
OpenCV를 사용해야했었는데, 이제 iOS는 자신만의 API를 가지게 되었다.
Vision이 수행할 수 있는 일의 종류들이다
- 이미지안에서 얼굴 찾아내기. 각 얼굴에대해 사각형을 만들어준다.
- 안면의 세부적인 특징 찾아내기. 눈이나 입의 위치나, 머리의 모양 등.
- 이미지에서 사각형모양으로된 것을 찾아내기. 표지판같은것들.
- 비디오에서 움직이는 물체 추적하기.
- 수평성 각도 알아내기
- 두 이미지를 변형하여 그 내용을 정렬하기. 사진들을 합성할때 유용하다.
- 이미지안에 포함된 텍스트 영역 감지하기.
- 바코드 감지와 인지.
이 작업들중 몇몇은 이미 Core Image와 AVFoundation으로 가능하지만 이제 일관된 API로 한 프레임워크안에 들어왔다.
여러분의 앱이 이 컴퓨터비젼 작업중 하나가 필요할때, 더이상 여러분이 직접 구현하거나 다른 라이브러리를 사용할 필요가 없다. 그냥 Vision 프레임워크를 사용하면 된다. 더욱 강력한 이미지 처리를위해 Core Image 프레임워크와 합쳐서 사용할 수도 있다.
더 나은 것은, Core ML을 작동시키기위해 Vision을 사용할 수도 있다는 점이다. 그리하여 뉴럴 네트워크를 위한 전처리 단계로서 이런 컴퓨터 비젼 기술을 사용할 수 있게 해준다. 예를들어, 사람 얼굴의 위치와 크기를 감지하는데, 그 영역에 비디오 프레임을 자르는데, 이미지에서 얼굴이 있는 부분에 뉴럴럴 네트워크를 실행시키는데 Vision을 사용할 수 있다.
사실 이미지나 비디오와 함께 Core ML을 사용하면 항상 Vision을통해 가는것이 알맞은 방법이다. 가공되지않은 Core ML로는 여러분의 입력 이미지는 모델이 예상하는 포멧안에 있도록 해야하지만, Vision으로는 프레임워크가 이미지 리사이징 등에 주의해야한다. 이것으로 여러분의 추가 노력을 조금 절약해줄 것이다.
코드에서 Core ML을 작동시키기위한 Vision 사용은 다음과같이 생겼다.
// the Core ML machine learning model
let modelCoreML = ResNet50()
// link the Core ML model to Vision
let visionModel = try? VNCoreMLModel(for: modelCoreML.model)
let classificationRequest = VNCoreMLRequest(model: visionModel) {
request, error in
if let observations = request.results as? [VNClassificationObservation] {
/* do something with the prediction */
}
}
let handler = VNImageRequestHandler(cgImage: yourImage)
try? handler.perform([classificationRequest])
VNImageReuestHandler가 요청하는 오브젝트의 배열을 받아서, 아래처럼 여러 컴퓨터 비젼 작업을 함께 연결하여 할 수 있음을 인지하자.
try? handler.perform([faceDetectionRequest, classificationRequest])
Vision은 컴퓨터 비젼을 사용하기 아주 쉽게 만들어준다. 그러나 기계학습 사람들에게 멋진 일은 컴퓨터 비젼 작업의 아웃풋을 받아서 Core ML 모델에 넣을 수 있다는 점이다. Core Image의 파워와 합쳐지면 이미지 처리 파이프라인을 하나로 만들게된다!
Metal Performance Shaders
내가 말하고싶은 마지막 주제는 Metal이다. 이것은 애플의 GPU 프로그래밍 API이다.
올해 클라이언트를위한 많은 내 일거리는
Metal Performance Shaders (MPS)로 뉴럴 네트워크 구축과 최적화된 퍼포먼스로 맞추는 작업이 포함되있었다. 그러나 iOS10은 컨볼루션 네트워크를 생성하기위한 기본적인 몇 커널만을 제공했었다. 종종 이 갭을 채우기위해 커스터마이징한 커널을 짜야했다.
그러니 나는 iOS11에서 여러 이용가능한 커널 수가 늘었을때 행복했고, 그 이상의 기분이었다. 이제 그래프를 구축하는(building graphs) API를 가진다.
주의: 왜 Core ML 대신에 MPS를 사용할까? 좋은 질문이다! 가장 큰 이유는 Core ML이 여러분이 원하는 것을 지원하지 않거나, 프로세스 전체를 컨트롤 하고싶고 가능한 최대의 속도를 짜내고 싶을때 사용한다.
MPS에서 기계학습을위한 큰 변화들은 다음과 같다.
-
Recurrent neural networks. 이제 RNN, LSTM, GRU, MGU 레이어를 생성할 수 있다. 이것들이 MPSImage 오브젝트의 시퀀스에도 동작하고, MPSMatrix 오브젝트 시퀀스에도 동작한다. 이것이 흥미로운 이유는, 다른 모든 MPS 레이어들이 이미지만 다른다는 것이다(그러나 확실히 텍스트나 이미지가아닌 데이터와 작업할때는 매우 불편하다).
-
더 많은 데이터 타입들. 이전의 가중치는 32비트 부동소수라고 가정했었는데, 이제 16비트 소수, 8비트 정수, 심지어 바이너리까지 될 수 있다. 컨볼루션과 완전히 연결된 레이어들은 바이너리 가중치와 바이너리화된 인풋으로 할 수 있다.
-
더 많은 레이어들. 지금까지 우리는 plain-pld convolution과 max/average pooling으로 만들어야 했었다. 그러나 iOS11 MPS는 dilated convolution, subpixel convolution, transposed convolution, upsampling과 resampling, L2-norm pooling, dilated max pooling, 게다가 몇몇 새로운 활성 함수들(activation functions)을 가능하게 했다. 아직 MPS는 Keras나 Caffe 레이어 타입처럼 모든 타입을 가지진 않지만, 그 갭은 줄어들고 있다...
-
더욱 편리함. Metal은 항번에 채널 4개의 분할로 데이터를 구성하는데(이미지가 MTLTextrue 오브젝트에의해 돌아오기 때문에), 그것때문에 MPSImage으로 작업하는것은 항상 좀 이상하다. 그러나 이제 MPSImage는 데이터를 읽고 쓰는 메소드를 가지므로 한결 편해질것이다.또다른 편리함은 레이어에 batch normalization 파라미터를 설정하게 해주는 새로운 메소드를 가지는 것이다. 이 말은 더이상 여러분이 컨볼루션 레이어 가중치에 batch normalization을 접지 않아도 MPS가 알아서 다 해줄것이라는 의미다. 매우 편리하다!
-
성능 개선. 기존에 있던 커널들이 더 빨라졌다. 이 소식은 항상 좋다.
-
그래프 API. 내 생각에는 이것이 큰 소식이다. 모든 레이어와 (임시의) 이미지를 직접 생성하는것은 항상 성가신다. 이제 Keras에서처럼 그래프를 표현할 수 있다. MPS는 이미지가 얼마나 커져야하는지, 패딩을 어떻게 다뤄야하는지, MPS 커널의 offset을 어떻게 설정할지 등을 자동으로 계산한다. 뒷편에서는 퓨징 레이어(fusing layers)로 그래프까지도 최적화시킬 수 있다.
이제 모든 커널들이 NSSecureCoding으로 시리얼라이즈 가능해보이는데, 이 의미는 그래프를 파일로 저장하여 나중에 복구시킬 수 있다는 의미이다. 그리고 이 그래프로 인터페이스를 사용하면 이제 그냥 한 메소드 호출만 하면 된다. 아직 Core ML만큼 쉽지는 않지만, MPS 사용이 확실히 이전보다 작업이 많이 줄었다.
내가 생각하기에 아직 분명하지 않은 것은 자신만의 컴퓨트 커널을 작성할 수 있는지, 그래프에 이것을 붙일 수 있는지이다. 내 클라이언트 작업에서 나는 전처리 과정에서 종종 필요했었고, Metal Shading Language로 작성된 커스텀 shader를 필요로 했다. 내가 말할 수 있는 부분은, "MPSNNCustomKerneNode" 클래스가 될것 같진 않다. 더 조사할 필요가 있어보인다!
결론: 기계학습을 위한 Metal Performance Shaders은 iOS 11과함께 더 강력해졌지만, 아마 많은 개발자들이 (내부적으로 MPS를 사용해가며) Core ML와 붙여 사용할 수 있다.
주의: 여러분의 앱이 계속 iOS 10을 지원하지 않는한, 새로나온 그래프 API는 내
Forge library를 쓸모없게 만들었다. 곧 예제 앱을 새로나온 그래프 API로 포팅할 것이고, 그것에대한 세부적인 내용을 블로그에 포스팅할 예정이다.
남은것들
발표된 것 중에 다른 부분이다.
-
Accelerate: Accelerate 프레임워크에서 BNNS는 기능적 업데이트가 크게 일어나진 않았다. 결국 Softmax 레이어가 나왔지만, MPS가 얻은 새로운 레이어 타입은 없었다. 아마 맞을것이다. 딥 뉴럴 네트워크를위한 CPU 사용은 어쨌든 좋은 아이디어가 아닌것같다. 이 말은, 나는 Accelerate를 사랑하고, 이것으로 많은 즐거움이 있었다. 그리고 이번년도에 나는 스파스 메트릭스를 더 지원했었는데, 꽤 멋졌다.
-
자연어 처리(Natural Language Processing): Core ML은 이미지만을 위한게 아니라 텍스트를 포함한 수많은 종류의 데이터를 다룰 수 있다. 이 API에는 NSLinguisticTagger 클래스를 사용하는데, 얼마간 사용해봤지만 iOS 11이 나오면서 더욱 효과적게 되었다. 이제 NSLinguisticTagger는 언어 식별, 토큰화, part-of-speech tagging, lemmatization, Named Entity Recognition을 한다.
나는 NLP에 많은 경험이 없으므로 다른 NLP 프레임워크에대해 어떤식으로 stack up 되었는지 말할순 없을것 같지만, NSLinguisticTagger는 보기에 꽤 강력해 보인다. 여러분의 앱에 NLP를 넣고 싶으면 이 API로 시작하기에 좋아보인다.
이 모든게 좋은 소식인가?
애플이 개발자를위해 이 모든 새로운 툴을 제공하는것은 훌륭한 일이지만, 애플의 많은 API에는 중요한 "문제"가 있다.
- 오픈소스가 아니다
- 제한을 가진다
- 새로운 OS가 배포될때만 업데이트를 한다
이 세가지가 함게 있으면 애플의 API는 항상 다른 툴들에비해 뒤떨어질것이다. 만약 Keras가 멋진 새로운 레이어 타입을 추가하면 애플이 그 프레임워크와 OS를 업데이트 하기 전까지 Core ML로는 사용할 수 없을 것이다.
그리고 API의 어떤 부분은 여러분이 원하는대로 동작하지 않을때, 내부로 들어가서 고칠 수 없다. 여러분은 이것으로 작업해야하거나(항상 가능하진 않다) 다음 OS 배포까지 기다려야한다(모든 사용자들이 업그레이드하도록 해야한다).
물론 나는 애플이 비밀 소스를 줄거라 생각하진 않지만, 많은 다른 기계학습 툴킷들이 오픈소스니 Core ML도 오픈소스로 만드는 건 어떨까?🙏
애플이 이것을 아는것은 아마 빠른 시일안에 일어나진 않을 것이지만, 여러분의 앱에 기계학습을 넣기로 했을때는 적어도 위의 내용들을 마음에 담아주자.
더 읽을거리...