Ver3.0 ๐ Core ML๊ณผ Vision Framework๋ก ๋ง๋๋ ์จ๋๋ฐ์ด์ค ๋จธ์ ๋ฌ๋์ ์ธ๊ณ

๐ Core ML๊ณผ Vision Framework๋ก ๋ง๋๋ ์จ๋๋ฐ์ด์ค ๋จธ์ ๋ฌ๋์ ์ธ๊ณ
๋ด ์์์ AI, ํด๋ผ์ฐ๋ ์์ด๋ ๋๋ํ๊ฒ ์๋ํ๋ ๋ง๋ฒ ๊ฐ์ ๊ธฐ์
์์ฆ ์ค๋งํธํฐ์ผ๋ก ์ฌ์ง ์ฐ์ผ๋ฉด ์๋์ผ๋ก ์ผ๊ตด ์ธ์๋๊ณ , ๋ฐฐ๊ฒฝ ํ๋ฆฌ๊ฒ ๋ง๋ค์ด์ฃผ๊ณ , ์ฌ์ง์ด ์ด๋ค ๋ฌผ์ฒด์ธ์ง ์์์ ๋ถ๋ฅํด์ฃผ์์? ๐คณ
์ด๊ฒ ๋ค ์ธํฐ๋ท ์ฐ๊ฒฐ ์์ด๋ ๋ด ํฐ ์์์ ๋๋ฑ๋๋ฑ ์ฒ๋ฆฌ๋๋ ๊ฑฐ๋ผ๋ ๊ฑฐ ์๊ณ ์์์ด?
๋ฐ๋ก ์ด๊ฒ ์จ๋๋ฐ์ด์ค ๋จธ์ ๋ฌ๋(On-Device Machine Learning)์ ํ์ด์ผ.
์ ํ์ด ๋ง๋ Core ML๊ณผ Vision Framework๋ ์ด๋ฐ ๋ง๋ฒ ๊ฐ์ ์ผ์ ๊ฐ๋ฅํ๊ฒ ํด์ฃผ๋ ํต์ฌ ๋๊ตฌ๋ค์ด์ง.
์ค๋์ ์ด ๋ ์น๊ตฌ๊ฐ ์ด๋ป๊ฒ ํ๋ ฅํด์ ์ฐ๋ฆฌ ์์์ ๊ธฐ๊ธฐ๋ฅผ ๋๋ํ๊ฒ ๋ง๋๋์ง,
๊ฐ๋ฐ์ ์
์ฅ์์ ์ด๋ป๊ฒ ํ์ฉํ ์ ์๋์ง ์น๊ตฌ์ฒ๋ผ ํธํ๊ฒ ์ด์ผ๊ธฐํด๋ณผ๊ฒ! โ
๐ฏ ์จ๋๋ฐ์ด์ค ๋จธ์ ๋ฌ๋์ด ๋ญ๊ธธ๋?
๋จผ์ ๊ธฐ๋ณธ ๊ฐ๋
๋ถํฐ ์ก๊ณ ๊ฐ์.
์ ํต์ ์ธ AI ์๋น์ค๋ค์ ๋๋ถ๋ถ ํด๋ผ์ฐ๋ ์๋ฒ์์ ์ฒ๋ฆฌ๋์ด.
์ฌ์ง์ ์
๋ก๋ํ๋ฉด ์๋ฒ๋ก ๋ณด๋ด์ ๋ถ์ํ๊ณ , ๊ฒฐ๊ณผ๋ฅผ ๋ค์ ๋ฐ์์ค๋ ๋ฐฉ์์ด์ง.
๊ทผ๋ฐ ์ด ๋ฐฉ์์๋ ๋ช ๊ฐ์ง ๋ฌธ์ ๊ฐ ์์ด:
โ ๏ธ ํด๋ผ์ฐ๋ ๊ธฐ๋ฐ AI์ ํ๊ณ
1. ์ธํฐ๋ท ์ฐ๊ฒฐ ํ์: ์์ดํ์ด๋ ๋ฐ์ดํฐ๊ฐ ์์ผ๋ฉด ์๋ ์ ํจ
2. ์๋ ๋ฌธ์ : ๋คํธ์ํฌ ์๋ณต ์๊ฐ ๋๋ฌธ์ ๋๋ฆผ
3. ํ๋ผ์ด๋ฒ์ ์ฐ๋ ค: ๋ด ์ฌ์ง์ด๋ ๋ฐ์ดํฐ๊ฐ ์๋ฒ๋ก ์ ์ก๋จ
4. ๋น์ฉ ๋ฐ์: ์๋ฒ ์ด์ ๋น์ฉ๊ณผ ๋ฐ์ดํฐ ์ ์ก ๋น์ฉ
๋ฐ๋ฉด ์จ๋๋ฐ์ด์ค ๋จธ์ ๋ฌ๋์ ์ด ๋ชจ๋ ๊ฑธ ๊ธฐ๊ธฐ ์์์ ํด๊ฒฐํด!
์ค๋งํธํฐ, ํ๋ธ๋ฆฟ, ์ฌ์ง์ด ์์น ๊ฐ์ ์์ ๊ธฐ๊ธฐ์์๋ AI ๋ชจ๋ธ์ด ์ง์ ๋์๊ฐ๋ ๊ฑฐ์ผ. ๐โโ๏ธ
๐ก ์จ๋๋ฐ์ด์ค ML์ ์ฅ์
์ฆ๊ฐ์ ์ธ ๋ฐ์: ๋คํธ์ํฌ ์ง์ฐ ์์ด ๋ฐ๋ฆฌ์ด ๋จ์๋ก ์ฒ๋ฆฌ
ํ๋ผ์ด๋ฒ์ ๋ณดํธ: ๋ฐ์ดํฐ๊ฐ ๊ธฐ๊ธฐ ๋ฐ์ผ๋ก ๋๊ฐ์ง ์์
์คํ๋ผ์ธ ์๋: ์ธํฐ๋ท ์์ด๋ ์๋ฒฝํ๊ฒ ๋์
๋ฐฐํฐ๋ฆฌ ํจ์จ: ๋คํธ์ํฌ ํต์ ์์ด์ ์ ๋ ฅ ์๋ชจ ๊ฐ์
๋น์ฉ ์ ๊ฐ: ์๋ฒ ์ธํ๋ผ ๋น์ฉ ์ ๋ก
๐ง Core ML: ์ ํ์ ๋จธ์ ๋ฌ๋ ์ฌ์ฅ
Core ML์ 2017๋
์ ํ์ด iOS 11๊ณผ ํจ๊ป ์ ๋ณด์ธ ํ๋ ์์ํฌ์ผ.
์ฝ๊ฒ ๋งํ๋ฉด ๋จธ์ ๋ฌ๋ ๋ชจ๋ธ์ iOS ๊ธฐ๊ธฐ์์ ์คํํ ์ ์๊ฒ ํด์ฃผ๋ ์์ง์ด๋ผ๊ณ ๋ณด๋ฉด ๋ผ.
Core ML์ ํต์ฌ ํน์ง
1. ๋ค์ํ ๋ชจ๋ธ ์ง์
Core ML์ ์ ๋ง ๋ค์ํ ์ข
๋ฅ์ ๋จธ์ ๋ฌ๋ ๋ชจ๋ธ์ ์ง์ํด:
โข ์ ๊ฒฝ๋ง(Neural Networks): ์ด๋ฏธ์ง ๋ถ๋ฅ, ์์ฑ ์ธ์ ๋ฑ
โข ํธ๋ฆฌ ์์๋ธ(Tree Ensembles): ์์ฌ๊ฒฐ์ ํธ๋ฆฌ, ๋๋ค ํฌ๋ ์คํธ
โข ์ํฌํธ ๋ฒกํฐ ๋จธ์ (SVM): ๋ถ๋ฅ ๋ฌธ์ ํด๊ฒฐ
โข ์ ํ ๋ชจ๋ธ: ํ๊ท ๋ถ์, ๋ก์ง์คํฑ ํ๊ท
โข ํ์ดํ๋ผ์ธ ๋ชจ๋ธ: ์ฌ๋ฌ ๋ชจ๋ธ์ ์ฐ๊ฒฐํ ๋ณตํฉ ๋ชจ๋ธ
๐ ์ค์ ํฌ์ธํธ
Core ML 3.0๋ถํฐ๋ ์จ๋๋ฐ์ด์ค ํ์ต(On-Device Training)๋ ๊ฐ๋ฅํด์ก์ด!
์ด๊ฑด ์ ๋ง ํ์ ์ ์ธ๋ฐ, ์ฌ์ฉ์์ ๋ฐ์ดํฐ๋ก ๋ชจ๋ธ์ ๊ฐ์ธํํ ์ ์๋ค๋ ๋ป์ด์ผ.
์๋ฅผ ๋ค์ด ์๊ธ์จ ์ธ์ ์ฑ์ด ๋ด ๊ธ์จ์ฒด๋ฅผ ํ์ตํด์ ์ ์ ๋ ์ ํํด์ง๋ ๊ฑฐ์ง. โ๏ธ
2. ํ๋์จ์ด ๊ฐ์
Core ML์ ์ง์ง ๊ฐ์ ์ ํ๋์จ์ด ์ต์ ํ์ผ.
์ ํ ๊ธฐ๊ธฐ์๋ ์ฌ๋ฌ ํ๋ก์ธ์๊ฐ ์์ด:
โข CPU: ๋ฒ์ฉ ์ฐ์ฐ ์ฒ๋ฆฌ
โข GPU: ๊ทธ๋ํฝ๊ณผ ๋ณ๋ ฌ ์ฐ์ฐ
โข Neural Engine: AI ์ ์ฉ ์นฉ (A11 ์ดํ)
Core ML์ ๋ชจ๋ธ์ ํน์ฑ์ ๋ถ์ํด์ ์ด ์ค ๊ฐ์ฅ ํจ์จ์ ์ธ ํ๋ก์ธ์๋ฅผ ์๋์ผ๋ก ์ ํํด.
๊ฐ๋ฐ์๊ฐ ์ ๊ฒฝ ์ธ ํ์ ์์ด ์์์ ์ต์ ํ๋๋ ๊ฑฐ์ง! ๐ฏ
Core ML ๋ชจ๋ธ ํ์
Core ML์ .mlmodel์ด๋ผ๋ ์์ฒด ํ์์ ์ฌ์ฉํด.
ํ์ง๋ง ๊ฑฑ์ ๋ง! ๋ค๋ฅธ ํ๋ ์์ํฌ์์ ๋ง๋ ๋ชจ๋ธ๋ ์ฝ๊ฒ ๋ณํํ ์ ์์ด.
์ง์ํ๋ ๋ณํ ๋๊ตฌ๋ค:
โข coremltools: TensorFlow, PyTorch, Keras ๋ชจ๋ธ ๋ณํ
โข Create ML: Xcode์์ ์ง์ ๋ชจ๋ธ ํ์ต
โข Turi Create: ํ์ด์ฌ์ผ๋ก ๋ชจ๋ธ ๋ง๋ค๊ณ ๋ณํ
์๋ฅผ ๋ค์ด TensorFlow๋ก ํ์ตํ ์ด๋ฏธ์ง ๋ถ๋ฅ ๋ชจ๋ธ์ด ์๋ค๋ฉด:
import coremltools as ct
# TensorFlow ๋ชจ๋ธ ๋ก๋
tf_model = tf.keras.models.load_model('my_model.h5')
# Core ML ํ์์ผ๋ก ๋ณํ
coreml_model = ct.convert(tf_model)
# ์ ์ฅ
coreml_model.save('MyImageClassifier.mlmodel')
์ด๋ ๊ฒ ๊ฐ๋จํ๊ฒ ๋ณํํ ์ ์์ด! ๐
Core ML ์ฌ์ฉํ๊ธฐ
์ค์ ๋ก ์ฑ์์ Core ML ๋ชจ๋ธ์ ์ฌ์ฉํ๋ ๊ฑด ์ ๋ง ์ฌ์.
Xcode์ .mlmodel ํ์ผ์ ๋๋๊ทธํ๋ฉด ์๋์ผ๋ก Swift ํด๋์ค๊ฐ ์์ฑ๋ผ.
import CoreML
// ๋ชจ๋ธ ์ธ์คํด์ค ์์ฑ
let model = try! MobileNetV2()
// ์์ธก ์คํ
let prediction = try! model.prediction(image: pixelBuffer)
// ๊ฒฐ๊ณผ ํ์ธ
print("๋ถ๋ฅ ๊ฒฐ๊ณผ: \(prediction.classLabel)")
print("ํ๋ฅ : \(prediction.classLabelProbs)")
๋ณด๋ค์ํผ ๋ช ์ค์ ์ฝ๋๋ง์ผ๋ก ์ต์ฒจ๋จ AI ๊ธฐ๋ฅ์ ๊ตฌํํ ์ ์์ด!
์ด๋ฐ ์ ๊ทผ์ฑ ๋๋ถ์ ์ฌ๋ฅ๋ท ๊ฐ์ ํ๋ซํผ์์๋ ๋ง์ ๊ฐ๋ฐ์๋ค์ด AI ๊ธฐ๋ฅ์ ํ์ฉํ ์๋น์ค๋ฅผ ๋ง๋ค๊ณ ์์ง. ๐
๐๏ธ Vision Framework: ์ปดํจํฐ ๋น์ ์ ๋ง๋ฒ์ฌ
์ด์ Vision Framework ์ด์ผ๊ธฐ๋ฅผ ํด๋ณผ๊น?
Vision์ ์ด๋ฏธ์ง์ ๋น๋์ค ๋ถ์์ ํนํ๋ ํ๋ ์์ํฌ์ผ.
Core ML๊ณผ ์๋ฒฝํ๊ฒ ํตํฉ๋์ด ์์ด์ ๋์ด ํจ๊ป ์ฐ๋ฉด ์ ๋ง ๊ฐ๋ ฅํด! ๐ช
Vision์ด ํ ์ ์๋ ์ผ๋ค
Vision Framework๋ ์ ๋ง ๋ค์ํ ์ปดํจํฐ ๋น์ ์์ ์ ์ง์ํด:
๐ญ ์ผ๊ตด ๊ด๋ จ ๊ธฐ๋ฅ
โข ์ผ๊ตด ๊ฐ์ง(Face Detection): ์ด๋ฏธ์ง์์ ์ผ๊ตด ์์น ์ฐพ๊ธฐ
โข ์ผ๊ตด ๋๋๋งํฌ(Face Landmarks): ๋, ์ฝ, ์
๋ฑ ์ธ๋ถ ์์น ํ์
โข ์ผ๊ตด ํ์ง(Face Quality): ์ผ๊ตด ์ฌ์ง์ ํ์ง ํ๊ฐ
โข ์ผ๊ตด ์บก์ฒ(Face Capture Quality): ์ ๋ถ์ฆ ์ดฌ์ ๋ฑ์ ์ต์ ํ
๐ ํ
์คํธ ๊ด๋ จ ๊ธฐ๋ฅ
โข ํ
์คํธ ๊ฐ์ง(Text Detection): ์ด๋ฏธ์ง ์ ํ
์คํธ ์์ญ ์ฐพ๊ธฐ
โข ํ
์คํธ ์ธ์(Text Recognition): OCR๋ก ์ค์ ํ
์คํธ ์ฝ๊ธฐ
โข ๋ฌธ์ ์ค์บ: ๋ฌธ์ ๊ฒฝ๊ณ ๊ฐ์ง ๋ฐ ์๊ทผ ๋ณด์
๐ ๊ฐ์ฒด ๋ฐ ์ฅ๋ฉด ๋ถ์
โข ๋ฐ์ฝ๋ ๊ฐ์ง: QR์ฝ๋, ๋ฐ์ฝ๋ ์ธ์
โข ์ด๋ฏธ์ง ๋ถ๋ฅ: ์ฌ์ง ์ ๊ฐ์ฒด๋ ์ฅ๋ฉด ๋ถ๋ฅ
โข ๊ฐ์ฒด ์ถ์ : ๋น๋์ค์์ ๊ฐ์ฒด ์์ง์ ์ถ์
โข ํ์ ์ฑ ๋ถ์(Saliency): ์ด๋ฏธ์ง์์ ์ค์ํ ๋ถ๋ถ ์ฐพ๊ธฐ
๐จ ์ด๋ฏธ์ง ์ฒ๋ฆฌ
โข ์ด๋ฏธ์ง ์ ๋ ฌ: ๋ ์ด๋ฏธ์ง ๊ฐ ๋ณํ ๊ด๊ณ ๊ณ์ฐ
โข ํธ๋ผ์ด์ฆ ๊ฐ์ง: ์ฌ์ง์ ์ํ์ ์ฐพ๊ธฐ
โข ์ค๊ณฝ์ ๊ฐ์ง: ๊ฐ์ฒด์ ๊ฒฝ๊ณ์ ์ถ์ถ
๐ก ์ฌ๋ฏธ์๋ ์ฌ์ค
iOS ์ฌ์ง ์ฑ์์ ์ฌ์ง์ ๊ฒ์ํ ๋ "๊ฐ", "๊ณ ์์ด", "์์" ๊ฐ์ ๋จ์ด๋ก ์ฐพ์ ์ ์์์?
์ด๊ฒ ๋ค Vision Framework๊ฐ ๋ฐฑ๊ทธ๋ผ์ด๋์์ ๋ชจ๋ ์ฌ์ง์ ๋ถ์ํ ๊ฒฐ๊ณผ์ผ!
์์ฒ ์ฅ์ ์ฌ์ง์ ์๋์ผ๋ก ๋ถ๋ฅํ๊ณ ํ๊ทธ๋ฅผ ๋ฌ์์ฃผ๋ ๊ฑฐ์ง. ๐ท๏ธ
Vision๊ณผ Core ML์ ํ์์ ์ธ ์กฐํฉ
Vision์ ์ง์ง ๊ฐ์ ์ Core ML๊ณผ์ ์๋ฒฝํ ํตํฉ์ด์ผ.
Vision์ ์ด๋ฏธ์ง ์ ์ฒ๋ฆฌ๋ถํฐ ํ์ฒ๋ฆฌ๊น์ง ๋ชจ๋ ๊ฑธ ์๋์ผ๋ก ํด์ค.
์๋ฅผ ๋ค์ด ์ด๋ฏธ์ง ๋ถ๋ฅ ๋ชจ๋ธ์ ์ฌ์ฉํ๋ค๊ณ ํด๋ณด์:
import Vision
import CoreML
// Core ML ๋ชจ๋ธ์ Vision ๋ชจ๋ธ๋ก ๋ํ
let model = try! VNCoreMLModel(for: MyClassifier().model)
// Vision ์์ฒญ ์์ฑ
let request = VNCoreMLRequest(model: model) { request, error in
guard let results = request.results as? [VNClassificationObservation] else {
return
}
// ๊ฒฐ๊ณผ ์ฒ๋ฆฌ
for result in results {
print("\(result.identifier): \(result.confidence)")
}
}
// ์ด๋ฏธ์ง ์ฒ๋ฆฌ
let handler = VNImageRequestHandler(cgImage: image)
try! handler.perform([request])
๋ณด๋ค์ํผ Vision์ด ์์์:
โข ์ด๋ฏธ์ง๋ฅผ ๋ชจ๋ธ์ ๋ง๋ ํฌ๊ธฐ๋ก ๋ฆฌ์ฌ์ด์ง
โข ํฝ์
ํ์ ๋ณํ
โข ์ ๊ทํ(Normalization)
โข ๋ฐฐ์น ์ฒ๋ฆฌ
์ด ๋ชจ๋ ๊ฑธ ์๋์ผ๋ก ํด์ค! ๐
์ค์ ์์ : ์ผ๊ตด ๊ฐ์ง์ ๋ถ์
๊ฐ์ฅ ๋ง์ด ์ฐ์ด๋ ๊ธฐ๋ฅ ์ค ํ๋์ธ ์ผ๊ตด ๊ฐ์ง๋ฅผ ๊ตฌํํด๋ณผ๊น?
import Vision
func detectFaces(in image: CGImage) {
// ์ผ๊ตด ๊ฐ์ง ์์ฒญ ์์ฑ
let faceDetectionRequest = VNDetectFaceRectanglesRequest { request, error in
guard let observations = request.results as? [VNFaceObservation] else {
return
}
print("๊ฐ์ง๋ ์ผ๊ตด ์: \(observations.count)")
for face in observations {
// ์ผ๊ตด ์์น (์ ๊ทํ๋ ์ขํ)
let boundingBox = face.boundingBox
print("์ผ๊ตด ์์น: \(boundingBox)")
// ์ ๋ขฐ๋
print("์ ๋ขฐ๋: \(face.confidence)")
}
}
// ์ผ๊ตด ๋๋๋งํฌ๋ ํจ๊ป ๊ฐ์ง
let landmarkRequest = VNDetectFaceLandmarksRequest { request, error in
guard let observations = request.results as? [VNFaceObservation] else {
return
}
for face in observations {
if let landmarks = face.landmarks {
// ๋, ์ฝ, ์
๋ฑ์ ์์น
if let leftEye = landmarks.leftEye {
print("์ผ์ชฝ ๋ ์์น: \(leftEye.normalizedPoints)")
}
if let nose = landmarks.nose {
print("์ฝ ์์น: \(nose.normalizedPoints)")
}
}
}
}
// ์์ฒญ ์คํ
let handler = VNImageRequestHandler(cgImage: image, options: [:])
try? handler.perform([faceDetectionRequest, landmarkRequest])
}
์ด ์ฝ๋๋ก ์ผ๊ตด์ ์์น๋ฟ๋ง ์๋๋ผ ๋, ์ฝ, ์
์ ์ ํํ ์์น๊น์ง ์ ์ ์์ด!
์ด๊ฑธ ํ์ฉํ๋ฉด AR ํํฐ, ์ผ๊ตด ์ธ์ ์ ๊ธ, ๊ฐ์ ๋ถ์ ๋ฑ ๋ค์ํ ๊ธฐ๋ฅ์ ๋ง๋ค ์ ์์ง. ๐ญ
๐ ์ฑ๋ฅ ํ
Vision ์์ฒญ์ ๋น๋๊ธฐ๋ก ์ฒ๋ฆฌ๋๊ธฐ ๋๋ฌธ์ UI๊ฐ ๋ฉ์ถ์ง ์์.
ํ์ง๋ง ์ค์๊ฐ ๋น๋์ค ์ฒ๋ฆฌ๋ฅผ ํ ๋๋ VNSequenceRequestHandler๋ฅผ ์ฌ์ฉํ๋ ๊ฒ ๋ ํจ์จ์ ์ด์ผ.
์ด์ ํ๋ ์์ ์ ๋ณด๋ฅผ ํ์ฉํด์ ์ฒ๋ฆฌ ์๋๋ฅผ ๋์ผ ์ ์๊ฑฐ๋ ! โก
๐จ ์ค์ ํ๋ก์ ํธ: ์ค๋งํธ ์ฌ์ง ๋ถ๋ฅ ์ฑ ๋ง๋ค๊ธฐ
์ด๋ก ์ ์ถฉ๋ถํ ๋ฐฐ์ ์ผ๋ ์ด์ ์ค์ ๋ก ๋ญ๊ฐ ๋ง๋ค์ด๋ณผ๊น?
์ฌ์ง์ ์ฐ์ผ๋ฉด ์๋์ผ๋ก ์นดํ
๊ณ ๋ฆฌ๋ฅผ ๋ถ๋ฅํด์ฃผ๋ ์ฑ์ ๋ง๋ค์ด๋ณด์! ๐ธ
ํ๋ก์ ํธ ๊ตฌ์กฐ
์ฐ๋ฆฌ๊ฐ ๋ง๋ค ์ฑ์ ๊ธฐ๋ฅ:
1. ์นด๋ฉ๋ผ๋ก ์ฌ์ง ์ดฌ์
2. Vision + Core ML๋ก ์ด๋ฏธ์ง ๋ถ์
3. ๊ฐ์ฒด ์ธ์ ๋ฐ ๋ถ๋ฅ
4. ์ ๋ขฐ๋ ์ ์์ ํจ๊ป ๊ฒฐ๊ณผ ํ์
5. ์๋์ผ๋ก ์จ๋ฒ์ ์นดํ
๊ณ ๋ฆฌ๋ณ ์ ์ฅ
1๋จ๊ณ: ๋ชจ๋ธ ์ค๋น
๋จผ์ ์ด๋ฏธ์ง ๋ถ๋ฅ ๋ชจ๋ธ์ด ํ์ํด.
์ ํ์ด ์ ๊ณตํ๋ MobileNetV2๋ ResNet50 ๊ฐ์ ์ฌ์ ํ์ต๋ ๋ชจ๋ธ์ ์ฌ์ฉํ ์ ์์ด.
Apple์ Core ML ๋ชจ๋ธ ๊ฐค๋ฌ๋ฆฌ์์ ๋ค์ด๋ก๋ํ๊ฑฐ๋,
Create ML๋ก ์ง์ ํ์ต์ํฌ ์๋ ์์ง!
// Xcode ํ๋ก์ ํธ์ .mlmodel ํ์ผ ์ถ๊ฐ
// ์๋์ผ๋ก Swift ํด๋์ค ์์ฑ๋จ
import CoreML
class ImageClassifier {
let model: VNCoreMLModel
init() {
// ๋ชจ๋ธ ๋ก๋
guard let mlModel = try? MobileNetV2(configuration: MLModelConfiguration()).model,
let visionModel = try? VNCoreMLModel(for: mlModel) else {
fatalError("๋ชจ๋ธ ๋ก๋ ์คํจ")
}
self.model = visionModel
}
}
2๋จ๊ณ: ์ด๋ฏธ์ง ๋ถ๋ฅ ๋ก์ง
import Vision
import UIKit
class ImageClassifier {
let model: VNCoreMLModel
init() {
guard let mlModel = try? MobileNetV2(configuration: MLModelConfiguration()).model,
let visionModel = try? VNCoreMLModel(for: mlModel) else {
fatalError("๋ชจ๋ธ ๋ก๋ ์คํจ")
}
self.model = visionModel
}
func classify(image: UIImage, completion: @escaping ([Classification]) -> Void) {
guard let ciImage = CIImage(image: image) else {
completion([])
return
}
// Vision ์์ฒญ ์์ฑ
let request = VNCoreMLRequest(model: model) { request, error in
guard let results = request.results as? [VNClassificationObservation] else {
completion([])
return
}
// ์์ 5๊ฐ ๊ฒฐ๊ณผ๋ง ์ถ์ถ
let topResults = results.prefix(5).map { observation in
Classification(
label: observation.identifier,
confidence: observation.confidence
)
}
completion(topResults)
}
// ์ด๋ฏธ์ง ๋ฐฉํฅ ์ค์
request.imageCropAndScaleOption = .centerCrop
// ์์ฒญ ์คํ
let handler = VNImageRequestHandler(ciImage: ciImage, options: [:])
DispatchQueue.global(qos: .userInitiated).async {
try? handler.perform([request])
}
}
}
struct Classification {
let label: String
let confidence: Float
var confidencePercentage: String {
return String(format: "%.1f%%", confidence * 100)
}
}
3๋จ๊ณ: UI ๊ตฌํ
์ด์ ์ฌ์ฉ์ ์ธํฐํ์ด์ค๋ฅผ ๋ง๋ค์ด๋ณด์:
import SwiftUI
struct ContentView: View {
@State private var selectedImage: UIImage?
@State private var classifications: [Classification] = []
@State private var isAnalyzing = false
@State private var showImagePicker = false
let classifier = ImageClassifier()
var body: some View {
VStack(spacing: 20) {
// ์ด๋ฏธ์ง ํ์
if let image = selectedImage {
Image(uiImage: image)
.resizable()
.scaledToFit()
.frame(maxHeight: 300)
.cornerRadius(12)
.shadow(radius: 5)
} else {
RoundedRectangle(cornerRadius: 12)
.fill(Color.gray.opacity(0.2))
.frame(height: 300)
.overlay(
Text("์ฌ์ง์ ์ ํํ์ธ์")
.foregroundColor(.gray)
)
}
// ๋ถ์ ๋ฒํผ
Button(action: {
showImagePicker = true
}) {
Label("์ฌ์ง ์ ํ", systemImage: "photo.on.rectangle")
.font(.headline)
.foregroundColor(.white)
.padding()
.background(Color.blue)
.cornerRadius(10)
}
// ๋ถ์ ์ค ํ์
if isAnalyzing {
ProgressView("๋ถ์ ์ค...")
.padding()
}
// ๊ฒฐ๊ณผ ํ์
if !classifications.isEmpty {
VStack(alignment: .leading, spacing: 12) {
Text("๋ถ์ ๊ฒฐ๊ณผ")
.font(.headline)
.padding(.top)
ForEach(classifications.indices, id: \.self) { index in
HStack {
Text("\(index + 1).")
.font(.caption)
.foregroundColor(.gray)
Text(classifications[index].label)
.font(.body)
Spacer()
Text(classifications[index].confidencePercentage)
.font(.caption)
.foregroundColor(.blue)
}
.padding(.vertical, 4)
}
}
.padding()
.background(Color.gray.opacity(0.1))
.cornerRadius(10)
}
Spacer()
}
.padding()
.sheet(isPresented: $showImagePicker) {
ImagePicker(image: $selectedImage, onImageSelected: analyzeImage)
}
}
func analyzeImage() {
guard let image = selectedImage else { return }
isAnalyzing = true
classifications = []
classifier.classify(image: image) { results in
DispatchQueue.main.async {
self.classifications = results
self.isAnalyzing = false
}
}
}
}
์ด๋ ๊ฒ ํ๋ฉด ์ฌ์ง์ ์ ํํ์๋ง์ ์๋์ผ๋ก ๋ถ์์ด ์์๋๊ณ ,
๋ช ์ด ์์ ๊ฒฐ๊ณผ๊ฐ ๋ํ๋! ๐
โก ์ฑ๋ฅ ์ต์ ํ ๋น๋ฒ
์จ๋๋ฐ์ด์ค ML์ ๊ฐ์ฅ ํฐ ์ฅ์ ์ ์๋์ง๋ง,
์ ๋๋ก ์ต์ ํํ์ง ์์ผ๋ฉด ๋ฐฐํฐ๋ฆฌ๋ฅผ ๋ง์ด ๋จน๊ฑฐ๋ ๋๋ ค์ง ์ ์์ด.
์ค์ ์์ ๊ผญ ์์์ผ ํ ์ต์ ํ ํ๋ค์ ์๋ ค์ค๊ฒ! ๐ฏ
๋ชจ๋ธ ํฌ๊ธฐ ์ต์ ํ
1. ์์ํ(Quantization)
๋ชจ๋ธ์ ๊ฐ์ค์น๋ฅผ 32๋นํธ ๋ถ๋์์์ ์์ 16๋นํธ๋ 8๋นํธ๋ก ์ค์ด๋ ๊ธฐ๋ฒ์ด์ผ.
import coremltools as ct
# ๋ชจ๋ธ ๋ก๋
model = ct.models.MLModel('MyModel.mlmodel')
# 16๋นํธ๋ก ์์ํ
model_fp16 = ct.models.neural_network.quantization_utils.quantize_weights(
model,
nbits=16
)
# ์ ์ฅ
model_fp16.save('MyModel_FP16.mlmodel')
์ด๋ ๊ฒ ํ๋ฉด ๋ชจ๋ธ ํฌ๊ธฐ๊ฐ ์ ๋ฐ์ผ๋ก ์ค์ด๋ค๊ณ ,
์๋๋ ๊ฑฐ์ ๊ทธ๋๋ก ์ ์ง๋ผ! ๐
2. ํ๋ฃจ๋(Pruning)
์ค์ํ์ง ์์ ๋ด๋ฐ ์ฐ๊ฒฐ์ ์ ๊ฑฐํด์ ๋ชจ๋ธ์ ๊ฐ๋ณ๊ฒ ๋ง๋๋ ๊ฑฐ์ผ.
๐ก ์ค์ ํ
Create ML๋ก ๋ชจ๋ธ์ ํ์ตํ ๋ ์๋์ผ๋ก ์ต์ ํ ์ต์
์ ์ ๊ณตํด.
"Optimize for size" ์ต์
์ ์ผ๋ฉด ์์์ ์์ํ์ ํ๋ฃจ๋์ ํด์ค!
์ ํ๋๋ 1-2% ์ ๋๋ง ๋จ์ด์ง๋๋ฐ ํฌ๊ธฐ๋ 75%๊น์ง ์ค์ด๋ค ์ ์์ด. ๐
๋ฐฐ์น ์ฒ๋ฆฌ ์ต์ ํ
์ฌ๋ฌ ์ด๋ฏธ์ง๋ฅผ ํ ๋ฒ์ ์ฒ๋ฆฌํ ๋๋ ๋ฐฐ์น ์ฒ๋ฆฌ๋ฅผ ํ์ฉํ์:
// ๋ฐฐ์น ์์ธก ์ค์
let model = try! MobileNetV2()
let batchProvider = try! MLArrayBatchProvider(array: images)
// ํ ๋ฒ์ ์ฒ๋ฆฌ
let predictions = try! model.predictions(from: batchProvider)
// ๊ฒฐ๊ณผ ํ์ธ
for i in 0..<predictions.count {
let prediction = predictions.features(at: i)
// ์ฒ๋ฆฌ...
}
๋ฐฐ์น ์ฒ๋ฆฌ๋ฅผ ํ๋ฉด GPU๋ Neural Engine์ด ๋ณ๋ ฌ๋ก ์ฒ๋ฆฌํด์
๊ฐ๋ณ ์ฒ๋ฆฌ๋ณด๋ค 3-5๋ฐฐ ๋น ๋ฅผ ์ ์์ด! โก
๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ
๋ชจ๋ธ์ ์ฌ๋ฌ ๋ฒ ๋ก๋ํ์ง ๋ง๊ณ ์ฑ๊ธํค ํจํด์ผ๋ก ์ฌ์ฌ์ฉํ์:
class ModelManager {
static let shared = ModelManager()
private let model: VNCoreMLModel
private init() {
// ์ฑ ์์ ์ ํ ๋ฒ๋ง ๋ก๋
guard let mlModel = try? MobileNetV2().model,
let visionModel = try? VNCoreMLModel(for: mlModel) else {
fatalError("๋ชจ๋ธ ๋ก๋ ์คํจ")
}
self.model = visionModel
}
func getModel() -> VNCoreMLModel {
return model
}
}
// ์ฌ์ฉ
let model = ModelManager.shared.getModel()
๋น๋๊ธฐ ์ฒ๋ฆฌ
UI๊ฐ ๋ฉ์ถ์ง ์๋๋ก ํญ์ ๋ฐฑ๊ทธ๋ผ์ด๋ ์ค๋ ๋์์ ์ฒ๋ฆฌํ์:
func processImage(_ image: UIImage) {
// ๋ฐฑ๊ทธ๋ผ์ด๋ ํ์์ ์ฒ๋ฆฌ
DispatchQueue.global(qos: .userInitiated).async {
// ๋ฌด๊ฑฐ์ด ์์
let result = self.analyzeImage(image)
// UI ์
๋ฐ์ดํธ๋ ๋ฉ์ธ ์ค๋ ๋์์
DispatchQueue.main.async {
self.updateUI(with: result)
}
}
}
โ ๏ธ ์ฃผ์์ฌํญ
์ค์๊ฐ ๋น๋์ค ์ฒ๋ฆฌ๋ฅผ ํ ๋๋ ํ๋ ์์ ๊ฑด๋๋ฐ๋ ๊ฒ๋ ๊ณ ๋ คํด์ผ ํด.
๋ชจ๋ ํ๋ ์์ ์ฒ๋ฆฌํ๋ ค๊ณ ํ๋ฉด ํ๊ฐ ์์ฌ์ ์ง์ฐ์ด ๋ฐ์ํ ์ ์๊ฑฐ๋ .
๋ณดํต ์ด๋น 10-15ํ๋ ์ ์ ๋๋ง ์ฒ๋ฆฌํด๋ ์ถฉ๋ถํ ๋ถ๋๋ฌ์ ๋ณด์ฌ! ๐น
๐ฅ ๊ณ ๊ธ ํ์ฉ ์ฌ๋ก๋ค
์ด์ Core ML๊ณผ Vision์ผ๋ก ์ด๋ค ๋ฉ์ง ๊ฒ๋ค์ ๋ง๋ค ์ ์๋์ง ์ดํด๋ณด์!
์ค์ ์ฑ์์ ์ฌ์ฉ๋๋ ์ฌ๋ก๋ค์ด์ผ. ๐
์ค์๊ฐ ๊ฐ์ฒด ์ถ์
๋น๋์ค์์ ํน์ ๊ฐ์ฒด๋ฅผ ๊ณ์ ๋ฐ๋ผ๊ฐ๋ ๊ธฐ๋ฅ์ด์ผ.
์คํฌ์ธ ์ฑ์ด๋ ๋ณด์ ์ฑ์์ ๋ง์ด ์ฐ์ด์ง.
import Vision
class ObjectTracker {
private var lastObservation: VNDetectedObjectObservation?
private let sequenceHandler = VNSequenceRequestHandler()
func track(in pixelBuffer: CVPixelBuffer) -> CGRect? {
guard let lastObservation = lastObservation else {
// ์ฒซ ํ๋ ์: ๊ฐ์ฒด ๊ฐ์ง
return detectInitialObject(in: pixelBuffer)
}
// ์ถ์ ์์ฒญ ์์ฑ
let request = VNTrackObjectRequest(
detectedObjectObservation: lastObservation
) { [weak self] request, error in
guard let observation = request.results?.first as? VNDetectedObjectObservation else {
return
}
// ๋ค์ ํ๋ ์์ ์ํด ์ ์ฅ
self?.lastObservation = observation
}
// ์ถ์ ์ ํ๋ ์ค์
request.trackingLevel = .accurate
// ์์ฒญ ์คํ
try? sequenceHandler.perform([request], on: pixelBuffer)
return lastObservation?.boundingBox
}
private func detectInitialObject(in pixelBuffer: CVPixelBuffer) -> CGRect? {
// ์ด๊ธฐ ๊ฐ์ฒด ๊ฐ์ง ๋ก์ง
// ...
return nil
}
}
VNSequenceRequestHandler๋ฅผ ์ฌ์ฉํ๋ฉด ์ด์ ํ๋ ์์ ์ ๋ณด๋ฅผ ํ์ฉํด์
ํจ์ฌ ๋น ๋ฅด๊ณ ์ ํํ๊ฒ ์ถ์ ํ ์ ์์ด! ๐ฏ
๋ฌธ์ ์ค์บ๊ณผ OCR
๋ช
ํจ์ด๋ ์์์ฆ์ ์ค์บํด์ ํ
์คํธ๋ฅผ ์ถ์ถํ๋ ๊ธฐ๋ฅ์ด์ผ.
์ฌ๋ฅ๋ท ๊ฐ์ ํ๋ซํผ์์ ํ๋กํ ์ ๋ณด๋ฅผ ๋น ๋ฅด๊ฒ ์
๋ ฅํ ๋ ์ ์ฉํ๊ฒ ์ง? ๐
import Vision
import VisionKit
class DocumentScanner {
func scanDocument(image: CGImage, completion: @escaping (String) -> Void) {
var recognizedText = ""
// ํ
์คํธ ์ธ์ ์์ฒญ
let request = VNRecognizeTextRequest { request, error in
guard let observations = request.results as? [VNRecognizedTextObservation] else {
completion("")
return
}
// ์ธ์๋ ํ
์คํธ ๊ฒฐํฉ
recognizedText = observations.compactMap { observation in
observation.topCandidates(1).first?.string
}.joined(separator: "\n")
completion(recognizedText)
}
// ์ธ์ ๋ ๋ฒจ ์ค์ (accurate๊ฐ ๋ ์ ํํ์ง๋ง ๋๋ฆผ)
request.recognitionLevel = .accurate
// ์ธ์ด ์ค์
request.recognitionLanguages = ["ko-KR", "en-US"]
// ์๋ ์ธ์ด ๊ฐ์ง
request.usesLanguageCorrection = true
// ์์ฒญ ์คํ
let handler = VNImageRequestHandler(cgImage: image, options: [:])
try? handler.perform([request])
}
}
iOS 13๋ถํฐ๋ ํ๊ธ ์ธ์๋ ์ง์ํด์
ํ๊ตญ์ด ๋ฌธ์๋ ์ ํํ๊ฒ ์ฝ์ ์ ์์ด! ๐ฐ๐ท
์คํ์ผ ํธ๋์คํผ
์ฌ์ง์ ์์ ์ํ ์คํ์ผ๋ก ๋ณํํ๋ ๊ธฐ๋ฅ์ด์ผ.
์ธ์คํ๊ทธ๋จ ํํฐ ๊ฐ์ ๊ฑฐ ์๊ฐํ๋ฉด ๋ผ! ๐จ
import CoreML
import CoreImage
class StyleTransfer {
let model: VNCoreMLModel
init() {
// ์คํ์ผ ํธ๋์คํผ ๋ชจ๋ธ ๋ก๋
guard let mlModel = try? StyleTransferModel().model,
let visionModel = try? VNCoreMLModel(for: mlModel) else {
fatalError("๋ชจ๋ธ ๋ก๋ ์คํจ")
}
self.model = visionModel
}
func applyStyle(to image: UIImage, completion: @escaping (UIImage?) -> Void) {
guard let ciImage = CIImage(image: image) else {
completion(nil)
return
}
let request = VNCoreMLRequest(model: model) { request, error in
guard let results = request.results as? [VNPixelBufferObservation],
let pixelBuffer = results.first?.pixelBuffer else {
completion(nil)
return
}
// ํฝ์
๋ฒํผ๋ฅผ UIImage๋ก ๋ณํ
let ciImage = CIImage(cvPixelBuffer: pixelBuffer)
let context = CIContext()
if let cgImage = context.createCGImage(ciImage, from: ciImage.extent) {
let styledImage = UIImage(cgImage: cgImage)
completion(styledImage)
} else {
completion(nil)
}
}
let handler = VNImageRequestHandler(ciImage: ciImage)
DispatchQueue.global(qos: .userInitiated).async {
try? handler.perform([request])
}
}
}
ํฌ์ฆ ์ถ์
์ฌ๋์ ์์ธ๋ฅผ ์ธ์ํ๋ ๊ธฐ๋ฅ์ด์ผ.
ํผํธ๋์ค ์ฑ์ด๋ AR ๊ฒ์์์ ๋ง์ด ์ฐ์ด์ง! ๐คธโโ๏ธ
import Vision
class PoseEstimator {
func detectPose(in image: CGImage, completion: @escaping ([VNHumanBodyPoseObservation]) -> Void) {
let request = VNDetectHumanBodyPoseRequest { request, error in
guard let observations = request.results as? [VNHumanBodyPoseObservation] else {
completion([])
return
}
completion(observations)
}
let handler = VNImageRequestHandler(cgImage: image)
try? handler.perform([request])
}
func analyzePose(_ observation: VNHumanBodyPoseObservation) {
// ์ฃผ์ ๊ด์ ์์น ๊ฐ์ ธ์ค๊ธฐ
guard let recognizedPoints = try? observation.recognizedPoints(.all) else {
return
}
// ์ผ์ชฝ ํ๊ฟ์น
if let leftElbow = recognizedPoints[.leftElbow] {
print("์ผ์ชฝ ํ๊ฟ์น ์์น: \(leftElbow.location)")
print("์ ๋ขฐ๋: \(leftElbow.confidence)")
}
// ์ค๋ฅธ์ชฝ ๋ฌด๋ฆ
if let rightKnee = recognizedPoints[.rightKnee] {
print("์ค๋ฅธ์ชฝ ๋ฌด๋ฆ ์์น: \(rightKnee.location)")
}
// ๊ฐ๋ ๊ณ์ฐ ๋ฑ ์ถ๊ฐ ๋ถ์ ๊ฐ๋ฅ
}
}
Vision Framework๋ 17๊ฐ์ ์ฃผ์ ๊ด์ ์์น๋ฅผ ๊ฐ์งํ ์ ์์ด.
์ด๊ฑธ ํ์ฉํ๋ฉด ์ด๋ ์์ธ ๊ต์ , ๋์ค ๊ฒ์, AR ์๋ฐํ ๋ฑ์ ๋ง๋ค ์ ์์ง! ๐
๐ ๏ธ ์ค์ ๊ฐ๋ฐ ํ๊ณผ ํธ๋ฌ๋ธ์ํ
์ค์ ๋ก ๊ฐ๋ฐํ๋ค ๋ณด๋ฉด ์ฌ๋ฌ ๋ฌธ์ ์ ๋ถ๋ชํ๊ฒ ๋ผ.
๋ด๊ฐ ๊ฒช์๋ ๋ฌธ์ ๋ค๊ณผ ํด๊ฒฐ ๋ฐฉ๋ฒ์ ๊ณต์ ํ ๊ฒ! ๐ง
์ผ๋ฐ์ ์ธ ๋ฌธ์ ๋ค
๋ฌธ์ 1: ๋ชจ๋ธ์ด ๋๋ฌด ๋๋ ค์
ํด๊ฒฐ์ฑ :
1. ๋ชจ๋ธ ํฌ๊ธฐ ํ์ธ: 50MB ์ด์์ด๋ฉด ์์ํ ๊ณ ๋ ค
2. ์
๋ ฅ ํฌ๊ธฐ ์ค์ด๊ธฐ: 224x224 ๋์ 192x192 ์ฌ์ฉ
3. Compute Units ์ค์ : .all ๋์ .cpuAndGPU ์๋
4. ๋ฐฐ์น ์ฒ๋ฆฌ: ์ฌ๋ฌ ์ด๋ฏธ์ง๋ฅผ ํ ๋ฒ์ ์ฒ๋ฆฌ
// Compute Units ์ค์ ์์
let config = MLModelConfiguration()
config.computeUnits = .cpuAndGPU // ๋๋ .cpuOnly, .all
let model = try! MobileNetV2(configuration: config)
๋ฌธ์ 2: ๋ฉ๋ชจ๋ฆฌ ๋ถ์กฑ ์๋ฌ
ํด๊ฒฐ์ฑ :
1. ์ด๋ฏธ์ง ๋ฆฌ์ฌ์ด์ง: ์ฒ๋ฆฌ ์ ์ ์ ์ ํ ํฌ๊ธฐ๋ก ์ค์ด๊ธฐ
2. ๋ชจ๋ธ ์ธ๋ก๋: ์ฌ์ฉ ์ ํ ๋๋ ๋ฉ๋ชจ๋ฆฌ์์ ํด์
3. Autorelease Pool: ๋ฐ๋ณต ์ฒ๋ฆฌ ์ ๋ฉ๋ชจ๋ฆฌ ์ ๋ฆฌ
4. ๋ฐฑ๊ทธ๋ผ์ด๋ ์ ํ: ๋ฐฑ๊ทธ๋ผ์ด๋์์๋ ์ฒ๋ฆฌ ์ค๋จ
// Autorelease Pool ์ฌ์ฉ
for image in images {
autoreleasepool {
let result = processImage(image)
// ์ฒ๋ฆฌ...
} // ์ฌ๊ธฐ์ ๋ฉ๋ชจ๋ฆฌ ์๋ ํด์
}
๋ฌธ์ 3: ์ ํ๋๊ฐ ๋ฎ์์
ํด๊ฒฐ์ฑ :
1. ์ ์ฒ๋ฆฌ ํ์ธ: ๋ชจ๋ธ ํ์ต ์ ์ฌ์ฉํ ์ ์ฒ๋ฆฌ์ ๋์ผํ๊ฒ
2. ์ด๋ฏธ์ง ํ์ง: ํ๋ฆฟํ๊ฑฐ๋ ์ด๋์ด ์ด๋ฏธ์ง๋ ์ ์ฒ๋ฆฌ ํ์
3. ๋ชจ๋ธ ์ฌํ์ต: ์ค์ ์ฌ์ฉ ํ๊ฒฝ์ ๋ฐ์ดํฐ๋ก ํ์ธํ๋
4. ์์๋ธ: ์ฌ๋ฌ ๋ชจ๋ธ์ ๊ฒฐ๊ณผ๋ฅผ ์กฐํฉ
๋๋ฒ๊น ํ
1. ๋ชจ๋ธ ์ ๋ณด ํ์ธํ๊ธฐ
let model = try! MobileNetV2()
// ๋ชจ๋ธ ๋ฉํ๋ฐ์ดํฐ
print("๋ชจ๋ธ ์ด๋ฆ: \(model.model.modelDescription.metadata[.description] ?? "")")
print("์
๋ ฅ ํ์: \(model.model.modelDescription.inputDescriptionsByName)")
print("์ถ๋ ฅ ํ์: \(model.model.modelDescription.outputDescriptionsByName)")
// ์์ ์
๋ ฅ ํฌ๊ธฐ
if let imageConstraint = model.model.modelDescription
.inputDescriptionsByName["image"]?
.imageConstraint {
print("์
๋ ฅ ํฌ๊ธฐ: \(imageConstraint.pixelsWide) x \(imageConstraint.pixelsHigh)")
}
2. ์ฑ๋ฅ ์ธก์ ํ๊ธฐ
import os.signpost
let log = OSLog(subsystem: "com.myapp.ml", category: "Performance")
func measurePerformance() {
let signpostID = OSSignpostID(log: log)
os_signpost(.begin, log: log, name: "ML Inference", signpostID: signpostID)
// ML ์์
์ํ
let result = model.prediction(image: image)
os_signpost(.end, log: log, name: "ML Inference", signpostID: signpostID)
}
// Instruments์์ ํ์ธ ๊ฐ๋ฅ!
3. ์ค๊ฐ ๊ฒฐ๊ณผ ์๊ฐํ
// Vision ์์ฒญ ๊ฒฐ๊ณผ๋ฅผ ์ด๋ฏธ์ง์ ๊ทธ๋ฆฌ๊ธฐ
func visualizeResults(_ observations: [VNRecognizedObjectObservation], on image: UIImage) -> UIImage {
let imageSize = image.size
let scale = UIScreen.main.scale
UIGraphicsBeginImageContextWithOptions(imageSize, false, scale)
image.draw(at: .zero)
let context = UIGraphicsGetCurrentContext()!
context.setStrokeColor(UIColor.red.cgColor)
context.setLineWidth(3.0)
for observation in observations {
let boundingBox = observation.boundingBox
// Vision ์ขํ๊ณ๋ฅผ UIKit ์ขํ๊ณ๋ก ๋ณํ
let rect = VNImageRectForNormalizedRect(
boundingBox,
Int(imageSize.width),
Int(imageSize.height)
)
// ๋ฐ์ค ๊ทธ๋ฆฌ๊ธฐ
context.stroke(rect)
// ๋ ์ด๋ธ ํ์
let label = observation.labels.first?.identifier ?? "Unknown"
let confidence = observation.labels.first?.confidence ?? 0
let text = "\(label) (\(String(format: "%.1f%%", confidence * 100)))"
let attributes: [NSAttributedString.Key: Any] = [
.font: UIFont.boldSystemFont(ofSize: 16),
.foregroundColor: UIColor.red
]
text.draw(at: CGPoint(x: rect.minX, y: rect.minY - 20), withAttributes: attributes)
}
let resultImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return resultImage
}
๐ ๋ฏธ๋ ์ ๋ง๊ณผ ์๋ก์ด ๊ธฐ๋ฅ๋ค
Core ML๊ณผ Vision์ ๊ณ์ ์งํํ๊ณ ์์ด.
์ต์ ๋ฒ์ ์์ ์ถ๊ฐ๋ ๊ธฐ๋ฅ๋ค๊ณผ ์์ผ๋ก์ ๋ฐฉํฅ์ ์ดํด๋ณด์! ๐ฎ
Core ML 5์ ์๋ก์ด ๊ธฐ๋ฅ
1. ์จ๋๋ฐ์ด์ค ํ์ต ๊ฐํ
์ด์ ๋ ๋ณต์กํ ๋ชจ๋ธ๋ ๊ธฐ๊ธฐ์์ ์ง์ ํ์ต์ํฌ ์ ์์ด.
2. ๋ชจ๋ธ ์ํธํ
๋ชจ๋ธ์ ์ํธํํด์ ์ง์ ์ฌ์ฐ๊ถ์ ๋ณดํธํ ์ ์์ด.
ํนํ ์์
์ฉ ์ฑ์์ ์ค์ํ์ง!
// ๋ชจ๋ธ ์ํธํ (Python)
import coremltools as ct
model = ct.models.MLModel('MyModel.mlmodel')
# ์ํธํ ํค ์์ฑ
encryption_key = "your-secret-key-here"
# ์ํธํ๋ ๋ชจ๋ธ ์ ์ฅ
model.save('EncryptedModel.mlmodelc',
encryption_key=encryption_key)
3. ๋ ๋์ ์ฑ๋ฅ
Neural Engine ํ์ฉ์ด ๋์ฑ ์ต์ ํ๋์ด์
๊ฐ์ ๋ชจ๋ธ์ด ์ด์ ๋ฒ์ ๋ณด๋ค 2-3๋ฐฐ ๋น ๋ฅด๊ฒ ์คํ๋ผ! โก
Vision Framework์ ๋ฐ์
1. ๋๋ฌผ ์ธ์
์ฌ๋๋ฟ๋ง ์๋๋ผ ๊ฐ, ๊ณ ์์ด ๋ฑ ๋๋ฌผ์ ํฌ์ฆ๋ ์ธ์ํ ์ ์์ด!
// ๋๋ฌผ ํฌ์ฆ ์ธ์
let request = VNDetectAnimalBodyPoseRequest { request, error in
guard let observations = request.results as? [VNAnimalBodyPoseObservation] else {
return
}
for observation in observations {
// ๋๋ฌผ์ ๊ด์ ์์น ๋ถ์
if let points = try? observation.recognizedPoints(.all) {
print("๊ฐ์ง๋ ๊ด์ : \(points.count)๊ฐ")
}
}
}
let handler = VNImageRequestHandler(cgImage: image)
try? handler.perform([request])
2. ์ ํฌ์ฆ ์ธ์
์๊ฐ๋ฝ ํ๋ํ๋์ ์์น๊น์ง ์ ํํ๊ฒ ๊ฐ์งํด!
์ํ ์ธ์์ด๋ ์ ์ค์ฒ ์ปจํธ๋กค์ ํ์ฉํ ์ ์์ง. ๐
3. 3D ํฌ์ฆ ์ถ์
2D ์ด๋ฏธ์ง์์ 3D ๊ณต๊ฐ์์ ์์น๋ฅผ ์ถ์ ํ ์ ์์ด.
AR ์ฑ ๊ฐ๋ฐ์ด ํจ์ฌ ์ฌ์์ก์ง!
์ค๋ฌด์์์ ํ์ฉ ํธ๋ ๋
์์ฆ ์ฌ๋ฅ๋ท ๊ฐ์ ํ๋ซํผ์์๋ AI ๊ธฐ๋ฅ์ ํ์ฉํ ์๋น์ค๋ค์ด ๋ง์ด ๋์ค๊ณ ์์ด:
โข ํฌํธํด๋ฆฌ์ค ์๋ ๋ถ๋ฅ: ์ํ ์ฌ์ง์ ์๋์ผ๋ก ์นดํ
๊ณ ๋ฆฌ๋ณ๋ก ์ ๋ฆฌ
โข ์คํฌ ๋งค์นญ: ํ๋กํ ์ฌ์ง์ด๋ ์ํ์ผ๋ก ์ ๋ฌธ ๋ถ์ผ ์ถ์ฒ
โข ํ์ง ๊ฒ์ฆ: ์
๋ก๋๋ ์ด๋ฏธ์ง์ ํ์ง ์๋ ์ฒดํฌ
โข ์ ์ฌ ์ํ ์ฐพ๊ธฐ: ๋น์ทํ ์คํ์ผ์ ์ํ์ด๋ ์ฌ๋ฅ ์ถ์ฒ
๐ก ๋น์ฆ๋์ค ์ธ์ฌ์ดํธ
์จ๋๋ฐ์ด์ค ML์ ๋จ์ํ ๊ธฐ์ ์ ์ด์ ๋ง ์๋ ๊ฒ ์๋์ผ.
์ฌ์ฉ์ ํ๋ผ์ด๋ฒ์๋ฅผ ๋ณดํธํ๋ฉด์๋ ๊ฐ์ธํ๋ ๊ฒฝํ์ ์ ๊ณตํ ์ ์์ด์
GDPR ๊ฐ์ ๊ฐ์ธ์ ๋ณด ๋ณดํธ ๊ท์ ์ ์ค์ํ๊ธฐ์๋ ์ ๋ฆฌํด!
ํนํ ์ ๋ฝ์ด๋ ๋ฏธ๊ตญ ์์ฅ์ ํ๊ฒ์ผ๋ก ํ๋ ์ฑ์ด๋ผ๋ฉด ํ์์ ์ด์ง. ๐
๐ ํ์ต ๋ฆฌ์์ค์ ์ปค๋ฎค๋ํฐ
Core ML๊ณผ Vision์ ๋ ๊น์ด ๊ณต๋ถํ๊ณ ์ถ๋ค๋ฉด?
์ ์ฉํ ๋ฆฌ์์ค๋ค์ ์ ๋ฆฌํด๋ดค์ด! ๐
๊ณต์ ๋ฌธ์์ ํํ ๋ฆฌ์ผ
์ ํ ๊ณต์ ์๋ฃ:
โข Core ML Documentation
โข Vision Framework Documentation
โข WWDC ์ธ์
๋น๋์ค๋ค
โข Machine Learning ์ํ ์ฝ๋
์ถ์ฒ WWDC ์ธ์
:
โข "Explore the Machine Learning Development Experience"
โข "Optimize Your Core ML Usage"
โข "Build Image and Video Style Transfer Models in Create ML"
์ค์ต ํ๋ก์ ํธ ์์ด๋์ด
์ง์ ๋ง๋ค์ด๋ณด๋ฉด์ ๋ฐฐ์ฐ๋ ๊ฒ ์ต๊ณ ์ผ! ์ด๋ฐ ํ๋ก์ ํธ๋ค์ ์ถ์ฒํด:
์ด๊ธ:
โข ์ด๋ฏธ์ง ๋ถ๋ฅ ์ฑ (๊ฝ, ์์, ๋๋ฌผ ๋ฑ)
โข ๋ฐ์ฝ๋/QR ์ค์บ๋
โข ๊ฐ๋จํ OCR ์ฑ
์ค๊ธ:
โข ์ค์๊ฐ ๊ฐ์ฒด ๊ฐ์ง ์ฑ
โข ์ผ๊ตด ํํฐ ์นด๋ฉ๋ผ
โข ๋ฌธ์ ์ค์บ๋ with ์๋ ๋ณด์
โข ํฌ์ฆ ๊ธฐ๋ฐ ํผํธ๋์ค ํธ๋์ปค
๊ณ ๊ธ:
โข ์ปค์คํ
๋ชจ๋ธ ํ์ต ๋ฐ ๋ฐฐํฌ
โข ์คํ์ผ ํธ๋์คํผ ์ฑ
โข AR + ML ํตํฉ ์ฑ
โข ์จ๋๋ฐ์ด์ค ํ์ต ๊ตฌํ
๐ ํ๋ก์ ํธ ํ
์ฒ์์๋ ์ ํ์ด ์ ๊ณตํ๋ ์ฌ์ ํ์ต๋ ๋ชจ๋ธ๋ก ์์ํด.
MobileNet, ResNet, SqueezeNet ๊ฐ์ ๋ชจ๋ธ๋ค์ ๋ฐ๋ก ์ฌ์ฉํ ์ ์์ด!
์ต์ํด์ง๋ฉด Create ML๋ก ์์ ๋ง์ ๋ชจ๋ธ์ ๋ง๋ค์ด๋ณด๊ณ ,
๋ง์ง๋ง์ผ๋ก TensorFlow๋ PyTorch๋ก ์ปค์คํ
๋ชจ๋ธ์ ๋ง๋ค์ด๋ด. ๐
์ปค๋ฎค๋ํฐ์ ์คํ์์ค
GitHub ์ ์ฅ์:
โข Awesome Core ML Models: ๋ค์ํ ์ฌ์ ํ์ต ๋ชจ๋ธ ๋ชจ์
โข Core ML Examples: ์ค์ ์์ ์ฝ๋๋ค
โข Vision Framework Samples: Vision ํ์ฉ ์ํ๋ค
์จ๋ผ์ธ ์ปค๋ฎค๋ํฐ:
โข Apple Developer Forums
โข Stack Overflow (coreml, vision ํ๊ทธ)
โข Reddit r/iOSProgramming
โข ํ๊ตญ iOS ๊ฐ๋ฐ์ ๋ชจ์
๐ฏ ๋ง๋ฌด๋ฆฌํ๋ฉฐ
์, ์ฌ๊ธฐ๊น์ง ์ ๋ง ๊ธด ์ฌ์ ์ด์์ง? ๐
Core ML๊ณผ Vision Framework์ ๋ํด ๊ฝค ๋ง์ ๊ฑธ ๋ค๋ค์ด!
ํต์ฌ์ ์ ๋ฆฌํ์๋ฉด:
๐ ํต์ฌ ์์ฝ
1. ์จ๋๋ฐ์ด์ค ML์ ์ฅ์ :
โข ๋น ๋ฅธ ์๋, ํ๋ผ์ด๋ฒ์ ๋ณดํธ, ์คํ๋ผ์ธ ์๋, ๋น์ฉ ์ ๊ฐ
2. Core ML:
โข ๋ค์ํ ML ๋ชจ๋ธ์ iOS์์ ์คํํ๋ ํ๋ ์์ํฌ
โข ํ๋์จ์ด ๊ฐ์ ์๋ ์ต์ ํ
โข ์จ๋๋ฐ์ด์ค ํ์ต๋ ๊ฐ๋ฅ
3. Vision Framework:
โข ์ด๋ฏธ์ง/๋น๋์ค ๋ถ์ ์ ๋ฌธ ํ๋ ์์ํฌ
โข Core ML๊ณผ ์๋ฒฝํ ํตํฉ
โข ์ผ๊ตด, ํ
์คํธ, ๊ฐ์ฒด, ํฌ์ฆ ๋ฑ ๋ค์ํ ์ธ์ ๊ธฐ๋ฅ
4. ์ต์ ํ:
โข ๋ชจ๋ธ ์์ํ์ ํ๋ฃจ๋
โข ๋ฐฐ์น ์ฒ๋ฆฌ์ ๋น๋๊ธฐ ์คํ
โข ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ์ ์ฑ๋ฅ ์ธก์
์ด์ ๋น์ ๋ ์์์ AI๋ฅผ ๋ง๋ค ์ค๋น๊ฐ ๋์ด! ๐
์ฒ์์๋ ์ด๋ ค์ ๋ณด์ผ ์ ์์ง๋ง, ํ๋์ฉ ๋ฐ๋ผํ๋ค ๋ณด๋ฉด
์๊ฐ๋ณด๋ค ์ฝ๊ฒ ๋ฉ์ง AI ๊ธฐ๋ฅ์ ๊ตฌํํ ์ ์์ ๊ฑฐ์ผ.
๊ธฐ์ตํด, ์๋ฒฝํ ์ฑ์ ํ ๋ฒ์ ๋ง๋ค์ด์ง์ง ์์.
์์ ํ๋ก์ ํธ๋ถํฐ ์์ํด์ ์ ์ ๋ณต์กํ ๊ธฐ๋ฅ์ ์ถ๊ฐํด ๋๊ฐ๋ฉด ๋ผ.
์คํจ๋ฅผ ๋๋ ค์ํ์ง ๋ง๊ณ ๊ณ์ ์คํํด๋ด! ๐ช
๊ทธ๋ฆฌ๊ณ ํผ์์ ๋งํ ๋๋ ์ปค๋ฎค๋ํฐ์ ๋์์ ๋ฐ๋ ๊ฒ๋ ์์ง ๋ง.
์ฌ๋ฅ๋ท ๊ฐ์ ํ๋ซํผ์์ ๋ค๋ฅธ ๊ฐ๋ฐ์๋ค๊ณผ ์ง์์ ๋๋๊ณ ,
ํจ๊ป ์ฑ์ฅํ๋ ๊ฒ๋ ์ ๋ง ์ค์ํด! ๐ค
์, ์ด์ Xcode๋ฅผ ์ด๊ณ ์ฒซ ๋ฒ์งธ ML ํ๋ก์ ํธ๋ฅผ ์์ํด๋ณผ๊น?
๋น์ ์ ์ฐฝ์์ ์ธ ์์ด๋์ด๊ฐ ํ์ค์ด ๋๋ ์๊ฐ์ ๊ธฐ๋ํ ๊ฒ! โจ
Happy Coding! ๐
๋น์ ์ AI ์ฌ์ ์ ์์ํฉ๋๋ค! ๐
๊ด๋ จ ํค์๋
๋๊ธ ์์ฑ
์ด ๊ธ์ ๋ํ ์ฌ๋ฌ๋ถ์ ์๊ฐ์ ๋ค๋ ค์ฃผ์ธ์
๋ก๊ทธ์ธ์ด ํ์ํฉ๋๋ค
๋๊ธ์ ์์ฑํ๋ ค๋ฉด ๋จผ์ ๋ก๊ทธ์ธํด์ฃผ์ธ์.
๋๊ธ 0
์ง์์ธ์ ์ฒ - ์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
- ์ ์๊ถ ๋ฐ ์์ ๊ถ: ๋ณธ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ๋ ์ AI ๊ธฐ์ ๋ก ์์ฑ๋์์ผ๋ฉฐ, ๋ํ๋ฏผ๊ตญ ์ ์๊ถ๋ฒ ๋ฐ ๊ตญ์ ์ ์๊ถ ํ์ฝ์ ์ํด ๋ณดํธ๋ฉ๋๋ค.
- AI ์์ฑ ์ปจํ ์ธ ์ ๋ฒ์ ์ง์: ๋ณธ AI ์์ฑ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ์ง์ ์ฐฝ์๋ฌผ๋ก ์ธ์ ๋๋ฉฐ, ๊ด๋ จ ๋ฒ๊ท์ ๋ฐ๋ผ ์ ์๊ถ ๋ณดํธ๋ฅผ ๋ฐ์ต๋๋ค.
- ์ฌ์ฉ ์ ํ: ์ฌ๋ฅ๋ท์ ๋ช ์์ ์๋ฉด ๋์ ์์ด ๋ณธ ์ปจํ ์ธ ๋ฅผ ๋ณต์ , ์์ , ๋ฐฐํฌ, ๋๋ ์์ ์ ์ผ๋ก ํ์ฉํ๋ ํ์๋ ์๊ฒฉํ ๊ธ์ง๋ฉ๋๋ค.
- ๋ฐ์ดํฐ ์์ง ๊ธ์ง: ๋ณธ ์ปจํ ์ธ ์ ๋ํ ๋ฌด๋จ ์คํฌ๋ํ, ํฌ๋กค๋ง, ๋ฐ ์๋ํ๋ ๋ฐ์ดํฐ ์์ง์ ๋ฒ์ ์ ์ฌ์ ๋์์ด ๋ฉ๋๋ค.
- AI ํ์ต ์ ํ: ์ฌ๋ฅ๋ท์ AI ์์ฑ ์ปจํ ์ธ ๋ฅผ ํ AI ๋ชจ๋ธ ํ์ต์ ๋ฌด๋จ ์ฌ์ฉํ๋ ํ์๋ ๊ธ์ง๋๋ฉฐ, ์ด๋ ์ง์ ์ฌ์ฐ๊ถ ์นจํด๋ก ๊ฐ์ฃผ๋ฉ๋๋ค.
์์ง ๋๊ธ์ด ์์ต๋๋ค.