寫在前面:
在2017年的WWDC大會上,隨著iOS 11的發(fā)布,隨之而來的還有一系列新的特性和功能,同樣也帶來了獨特的布局適配問題。在這次大會中,蘋果推出了CoreML框架,能夠?qū)C器學習應用在移動端上,這等于在一些online的基礎(chǔ)上提供了offline方式,可以說在實際的開發(fā)過程中,能在一些特定的業(yè)務(wù)需求上能提供極大的幫助。
什么是機器學習?
機器學習,也就是目前被大家經(jīng)常提起的Machine Learning,也可以說是現(xiàn)在很火的一個技術(shù),它也是人工智能最核心的內(nèi)容。比如說橫掃世界棋壇大名鼎鼎的阿爾法狗(AlphaGo),或者已經(jīng)深入大家生活場景的圖片識別、語言翻譯、云歌曲推薦等等,這其實都是機器學習的具體實際應用的結(jié)果。
機器學習就是一種能讓計算機不需要進行不斷人工手動編程添加功能,而能自己學習的人工智能技術(shù)。它不是通過具體的編碼算法,而是在大量的模型數(shù)據(jù)中找到一個合適的模式從而讓計算機能夠不斷的發(fā)展和完善自身算法。
這個技術(shù)所要模擬的就是一個龐大而復雜的‘神經(jīng)網(wǎng)絡(luò)’,這個'神經(jīng)網(wǎng)絡(luò)'就需要大量的訓練好的模型(model)來提供數(shù)據(jù),使得這個'神經(jīng)網(wǎng)絡(luò)'能對各種輸入(inputs)產(chǎn)生出一個對應的輸出結(jié)果(outputs),并且還能通過不斷的訓練數(shù)據(jù)來提高自己的算法準確性。
這里的核心其實就是訓練各種模型(model)來處理各種不同的情況和需求。比如說有了一個專門識別人臉的模型,給一個輸入圖片他就能把人臉位置輸出出來等等等等,最后如果將無限多的訓練好的模型都結(jié)合起來,那這個計算機可能就能像人一樣應對各種情況還能不斷地自我完善。下圖是機器學習的一些應用場景:

CoreML是什么

Core ML根據(jù)官方文檔里的這張圖就可以看出,其實它的作用就是將一個訓練好的ML模型,轉(zhuǎn)換成我們的app工程可以直接使用的對象。利用該模型可以基于新的輸入數(shù)據(jù)而進行預測,也就是利用了機器學習的結(jié)果。比如,如果一個模型在一個地區(qū)的歷史房價數(shù)據(jù)上進行了訓練,那么它就可能能夠根據(jù)房子的臥室或客廳數(shù)量來預測房價。
Core ML 為設(shè)備性能進行了優(yōu)化,從而減少了內(nèi)存占用和功耗。嚴格在設(shè)備上運行能夠確保用戶數(shù)據(jù)的隱私,并且能保證你的應用在沒有網(wǎng)絡(luò)連接時也能夠工作和響應。構(gòu)建完成的Core ML又作為其他更高級框架的基礎(chǔ),比如支持用于圖像分析的 Vision 框架,用于自然語言處理的 Foundation類,以及用于評估已經(jīng)學習到的決策樹的 GameplayKit。如下圖:

- vision:高性能的圖像分析和圖像識別。這部分應用于人臉追蹤,人臉識別,文本識別,區(qū)域識別,二維碼識別,物體追蹤,圖像識別等。
- Nattural Language processing:自然語言處理。用于語言識別,分詞,詞性還原,詞性判定等。
- GamePlayKit:游戲制作,構(gòu)建游戲。用于常見的游戲行為如隨機數(shù)生成、人工智能、尋路、和代理行為。
Vision是什么
Vision是一個高性能的圖片分析庫,他能識別在圖片和視頻中的人臉、特征、場景分類等。你如果打開Vision的官方文檔看,官方對他包含的所有類做了分類,比如有Face Detection and Recognition(人臉檢測識別)、Machine Learning Image Analysis(機器學習圖片分析)、Barcode Detection(條形碼檢測)、Text Detection(文本檢測)等等。
大概可以這樣去理解:Vision庫里就已經(jīng)自帶了很多訓練好的模型,這些模型是針對上面提到的人臉識別、條形碼檢測等等功能,如果你要實現(xiàn)的功能剛好是Vision庫本身就能實現(xiàn)的,那么你直接使用Vision庫自帶的一些類和方法就行。
而當你要使用一個你在網(wǎng)上找的訓練好的模型或者你自己訓練好的模型的時候,才需要CoreML來將這個相當于‘第三方’模型轉(zhuǎn)換成app認得的類,之后才能使用這個模型,同時也結(jié)合上面提到的Vision的Machine Learning Image Analysis(機器學習圖片分析)分類下的類和方法來使用這個模型進行圖形分析或者Vision其它的一些模型進行一系列分析操作。
CoreML Samples
下面給大家介紹官網(wǎng)給出的一個Mars Habitat Pricer sample,用以預測火星上的殖民地價值

1.給項目中添加model
將已經(jīng)編譯好的一個以.modelc為后綴的model添加到Resources項目文件夾中,然后設(shè)置這個文件夾下所有文件的build action為BundleResource

2.加載model
在我們使用model之前,我們需要使用MLModel.Create這個靜態(tài)方法去加載model
var bundle = NSBundle.MainBundle;
var assetPath = bundle.GetUrlForResource("MarsHabitatPricer", "mlmodelc");
NSError mlErroe;
model = MLModel.Create(assetPath, out mlErroe);
3.設(shè)置參數(shù)

當我們開始使用這個模型之前,我們需要用Xcode打開我們的model,查看需要相應的inputs和outputs分別是什么,同時傳入模型參數(shù)以及獲取結(jié)果時都需要使用一個繼承IMLFeatureProvider的容器類,這個類相當于一個字典,其中包含string的key,以及與之相對應的MLFeatureValues,每個feature value可以是string,number,array,data或者image buffer。
public class MarsHabitatPricerInput : NSObject, IMLFeatureProvider
{
public double SolarPanels { get; set; }
public double Greenhouses { get; set; }
public double Size { get; set; }
public NSSet<NSString> FeatureNames => new NSSet<NSString>(new NSString("solarPanels"), new NSString("greenhouses"), new NSString("size"));
public MLFeatureValue GetFeatureValue(string featureName)
{
switch (featureName)
{
case "solarPanels":
return MLFeatureValue.Create(SolarPanels);
case "greenhouses":
return MLFeatureValue.Create(Greenhouses);
case "size":
return MLFeatureValue.Create(Size);
default:
return MLFeatureValue.Create(0);
}
}
}
通過以上這種方式,我們的輸入?yún)?shù)就可以被CoreML所識別,其中public NSSet<NSString> FeatureNames => new NSSet<NSString>(new NSString("solarPanels"), new NSString("greenhouses"), new NSString("size"));中的FeatureNames NSSet必須跟model所要求的輸入保持相同。
4.使用model
使用model需要實例化我們自定義的繼承了IMLFeatureProvider的容器類,將pickerview中三列的值傳入MarsHabitatPricerInput,然后調(diào)用GetPrediction方法,然后通過調(diào)用GetFeatureValue方法,獲取到相應的輸出
void updatePredictedPrice()
{
var pricerInput = new MarsHabitatPricerInput()
{
SolarPanels = datasource.GetValue(pickerView.SelectedRowInComponent(0), Feature.SolarPanels),
Greenhouses = datasource.GetValue(pickerView.SelectedRowInComponent(1), Feature.Greenhouses),
Size = datasource.GetValue(pickerView.SelectedRowInComponent(2), Feature.Size)
};
// Use the ML model
NSError prErr;
var outFeatures = model.GetPrediction(pricerInput, out prErr);
var result = outFeatures.GetFeatureValue("price").DoubleValue;
priceLabel.Text = "Predicted Price (millions) " + priceFormatter.StringFor(new NSNumber(result));
Console.WriteLine(prErr == null ? $"result was {result}" : "Unexpected runtime error " + prErr.Description);
}
CoreML With Vision Framework Samples
CoreML也可以與Vision框架結(jié)合使用對圖像進行操作,例如形狀識別,人臉識別等其它操作。下面這個CoreML With Vision Samples中采用了CoreML和Vision 。該示例將Vision框架中的rectangles recognition與MNINSTClassifier.mlmodelc相結(jié)合,以識別照片中的手寫數(shù)字。

1.創(chuàng)建一個Vision CoreML model
使用CoreML加載MNISTClassifier模型后,將其包裝在一個VNCoreMLModel 模型中,使得該模型可用于圖片處理。以下代碼還創(chuàng)建了兩個Vision請求:首先用于在圖像中查找矩形,然后用CoreML模型處理矩形獲取其中的數(shù)字:
// Load the ML model
var bundle = NSBundle.MainBundle;
var assetPath = bundle.GetUrlForResource("MNISTClassifier", "mlmodelc");
NSError mlErr, vnErr;
var mlModel = MLModel.Create(assetPath, out mlErr);
var model = VNCoreMLModel.FromMLModel(mlModel, out vnErr);
// Initialize
RectangleRequest = new VNDetectRectanglesRequest(HandleRectangles);
ClassificationRequest = new VNCoreMLRequest(model, HandleClassification);
2.開始Vision處理
// Run the rectangle detector, which upon completion runs the ML classifier.
var handler = new VNImageRequestHandler(ciImage, uiImage.Orientation.ToCGImagePropertyOrientation(), new VNImageOptions());
DispatchQueue.DefaultGlobalQueue.DispatchAsync(()=>{
NSError error;
handler.Perform(new VNRequest[] {RectangleRequest}, out error);
});
});
通過傳入一個CIImage對象給Vision Framework,之后根據(jù)第一步創(chuàng)建的VNDetectRectanglesRequest請求,當矩形識別完畢后會執(zhí)行相應的HandleRectangles回調(diào)函數(shù)。
3.處理Vision操作的結(jié)果
當開始執(zhí)行HandleRectangles回調(diào)函數(shù)之后,裁剪圖像以提取第一個矩形,將矩形圖像轉(zhuǎn)換為灰度,并將其傳遞給CoreML模型。
void HandleRectangles(VNRequest request, NSError error) {
var observations = request.GetResults<VNRectangleObservation>();
// ... omitted error handling ...
var detectedRectangle = observations[0]; // first rectangle
// ... omitted cropping and greyscale conversion ...
// Run the Core ML MNIST classifier -- results in handleClassification method
var handler = new VNImageRequestHandler(correctedImage, new VNImageOptions());
DispatchQueue.DefaultGlobalQueue.DispatchAsync(() => {
handler.Perform(new VNRequest[] { ClassificationRequest }, out NSError err);
});
}
4.使用CoreML
通過傳入處理完成之后的CIImage對象給MNISTClassifier后,根據(jù)第一步創(chuàng)建的VNCoreMLRequest請求,當數(shù)字識別完畢后會執(zhí)行相應的HandleClassification回調(diào)函數(shù)。
void HandleClassification(VNRequest request, NSError error){
var observations = request.GetResults<VNClassificationObservation>();
... omitted error handling ...
var best = observations[0]; // first/best classification result
// render in UI
DispatchQueue.MainQueue.DispatchAsync(()=>{
ClassificationLabel.Text = $"Classification: {best.Identifier} Confidence: {best.Confidence * 100f:#.00}%";
});
}
傳入的request參數(shù)中包含CoreML Request的詳細信息,通過調(diào)用GetResults<VNClassificationObservation>()方法返回可能的結(jié)果結(jié)合。
寫在最后:
到此在Xamarin.iOS中使用CoreML和Vision的案例介紹就完成了,之后也會給大家?guī)?strong>CoreML with Azure Custom Vision Service的介紹,包括使用工具轉(zhuǎn)化第三方Model的介紹??梢钥闯鰧τ诩?strong>CoreML來說,其實不是特別復雜,但是其中的算法可以說是非常高深的,我也會繼續(xù)保持對CoreML的關(guān)注,分享更多的相關(guān)內(nèi)容給大家。
到這里Xamarin.iOS CoreML和Vision的介紹就完成了,希望能對您有所幫助。
——End 有問題可以加我微信,大家一起討論,加好友前請備注您的簡稱,謝謝!
