1. 程式人生 > >使用 .NET 5 體驗大資料和機器學習

使用 .NET 5 體驗大資料和機器學習

> 翻譯:精緻碼農-王亮 > 原文:http://dwz.win/XnM .NET 5 旨在提供統一的執行時和框架,使其在各平臺都有統一的執行時行為和開發體驗。微軟釋出了與 .NET 協作的大資料(.NET for Spark)和機器學習(ML.NET)工具,這些工具共同提供了富有成效的端到端體驗。在本文中,我們將介紹 .NET for Spark、大資料、ML.NET 和機器學習的基礎知識,我們將研究其 API 和功能,向你展示如何開始構建和消費你自己的 Spark 作業和 ML.NET 模型。 ## 什麼是大資料 大資料是一個幾乎不言自明的行業術語。該術語指的是大型資料集,通常涉及 TB 甚至 PB 級的資訊,這些資料集被用作分析的輸入,以揭示資料中的模式和趨勢。大資料與傳統工作負載之間的關鍵區別在於,大資料往往過於龐大、複雜或多變,傳統資料庫和應用程式無法處理。一種流行的資料分類方式被稱為 "3V"(譯註:即3個V,Volume 容量、Velocity 速度、Variety 多樣性)。 > 大資料解決方案是為適應高容量、處理複雜多樣的資料結構而定製的,並通過批處理(靜態)和流處理(動態)來管理速度。 大多數大資料解決方案都提供了在資料倉庫中儲存資料的方式,資料倉庫通常是一個為快速檢索和為並行處理而優化的分散式叢集。處理大資料往往涉及多個步驟,如下圖所示: ![Figure 1: The big data process](https://w-share.oss-cn-shanghai.aliyuncs.com/20201115230221.png) .NET 5 開發人員如果需要基於大型資料集進行分析和洞察,可以使用基於流行的大資料解決方案 Apache Spark 的 .NET 實現:.NET for Spark。 ## .NET for Spark .NET for Spark 基於 Apache Spark,這是一個用於處理大資料的開源分析引擎。它被設計為在記憶體中處理大量資料,以提供比其他依賴持久化儲存的解決方案更好的效能。它是一個分散式系統,並行處理工作負載。它為載入資料、查詢資料、處理資料和輸出資料提供支援。 Apache Spark 支援 Java、Scala、Python、R 和 SQL。微軟建立了 .NET for Spark 以增加對 .NET 的支援。該解決方案提供了免費、開放、跨平臺的工具,用於使用 .NET 所支援的語言(如 C#和 F#)構建大資料應用程式,這樣你就可以使用現有的 .NET 庫,同時利用 SparkSQL 等 Spark 特性。 ![Figure 2: Architecture for .NET for Spark](https://w-share.oss-cn-shanghai.aliyuncs.com/20201115230222.png) 以下程式碼展示了一個小而完整的 .NET for Spark 應用程式,它讀取一個文字檔案並按降序輸出字數。 ```csharp using Microsoft.Spark.Sql; namespace MySparkApp { class Program { static void Main(string[] args) { // Create a Spark session. SparkSession spark = SparkSession.Builder().AppName("word_count_sample").GetOrCreate(); // Create initial DataFrame. DataFrame dataFrame = spark.Read().Text("input.txt"); // Count words. DataFrame words = dataFrame.Select(Functions.Split(Functions.Col("value"), " ").Alias("words")) .Select(Functions.Explode(Functions .Col("words")) .Alias("word")) .GroupBy("word") .Count() .OrderBy(Functions.Col("count").Desc()); // Show results. words.Show(); // Stop Spark session. spark.Stop(); } } } ``` 在開發機器上配置 .NET for Spark 需要安裝幾個依賴,包括 Java SDK 和 Apache Spark。你可以在這裡([https://aka.ms/go-spark-net](https://aka.ms/go-spark-net))檢視手把手的入門指南。 Spark for .NET 可在多種環境中執行,並可部署到雲中執行。可部署目標包括 Azure HDInsight、Azure Synapse、AWS EMR Spark 和 Databricks 等。如果資料作為專案可用的一部分,你可以將其與其他 `project` 檔案一起提交。 大資料通常與機器學習一起使用,以獲得關於資料的洞察。 ## 什麼是機器學習 首先,我們先來介紹一下人工智慧和機器學習的基本知識。 人工智慧(AI)是指計算機模仿人類智慧和能力,如推理和尋找意義。典型的人工智慧技術通常是從規則或邏輯系統開始的。作為一個簡單的例子,想一想這樣的場景:你想把某樣東西分類為“麵包”或“不是麵包”。當你開始時,這似乎是一個簡單的問題,例如“如果它有眼睛,它就不是麵包”。然而,你很快就會開始意識到,有很多不同的特徵可以將某物定性為麵包與非麵包,而且特徵越多,一系列的 if 語句就會越長越複雜,如下圖所示: ![Figure 3: Determining “bread or not bread?” with AI if statements](https://w-share.oss-cn-shanghai.aliyuncs.com/20201115230223.png) 從上圖中的例子可以看出,傳統的、基於規則的人工智慧技術往往難以擴充套件。這就是機器學習的作用。機器學習(ML)是人工智慧的一個子集,它能在過去的資料中找到模式,並從經驗中學習,以對新資料採取行動。ML 允許計算機在沒有明確的邏輯規則程式設計的情況下進行預測。因此,當你有一個難以(或不可能)用基於規則的程式設計解決的問題時,你可以使用 ML。你可以把 ML 看作是 "對不可程式設計的程式設計"。 為了用 ML 解決“麵包”與“非麵包”的問題,你提供麵包的例子和非麵包的例子(如下圖所示),而不是實現一長串複雜的 if 語句。你將這些例子傳遞給一個演算法,該演算法在資料中找到模式,並返回一個模型,然後你可以用這個模型來預測尚未被模型“看到”的影象是“麵包”還是“不是麵包”。 ![Figure 4: Determining “bread or not bread?” with ML](https://w-share.oss-cn-shanghai.aliyuncs.com/20201115230224.png) 上圖展示了 AI 與 ML 的另一種思考方式。AI 將規則和資料作為輸入,預期輸出基於這些規則的答案。而 ML 則是將資料和答案作為輸入,輸出可用於對新資料進行歸納的規則。 ![Figure 5: Artificial intelligence compared to machine learning](https://w-share.oss-cn-shanghai.aliyuncs.com/20201115230225.png) > AI 將規則和資料作為輸入,並根據這些規則輸出預期的答案。ML 將資料和答案作為輸入,並輸出可用於概括新資料的規則。 ## ML.NET 微軟在 2019 年 5 月的 Build 上釋出了 ML.NET,這是一個面向.NET 開發人員的開源、跨平臺 ML 框架。在過去的九年裡,微軟的團隊已經廣泛使用該框架的內部版本來實現流行的 ML 驅動功能;一些例子包括 Dynamics 365 欺詐檢測、PowerPoint 設計理念和 Microsoft Defender 防病毒威脅保護。 ML.NET 允許你在.NET 生態系統中構建、訓練和消費 ML 模型,而不需要 ML 或資料科學的背景。ML.NET 可以在任何.NET 執行的地方執行。Windows、Linux、macOS、on-prem、離線場景(如 WinForms 或 WPF 桌面應用)或任何雲端(如 Azure)中。你可以將 ML.NET 用於各種場景,如表 1 所述。 ML.NET 使用自動機器學習(或稱 AutoML)來自動構建和訓練 ML 模型的過程,以根據提供的場景和資料找到最佳模型。你可以通過 AutoML.NET API 或 ML.NET 工具來使用 ML.NET 的 AutoML,其中包括 Visual Studio 中的 Model Builder 和跨平臺的 ML.NET CLI,如圖 6 所示。除了訓練最佳模型外,ML.NET 工具還生成在終端使用者.NET 應用程式中消費模型所需的檔案和 C#程式碼,該應用程式可以是任何.NET 應用程式(桌面、Web、控制檯等)。所有 AutoML 方案都提供了本地訓練選項,影象分類也允許你利用雲的優勢,使用 Model Builder 中的 Azure ML 進行訓練。 ![Figure 6: ML.NET tooling is built on top of the AutoML.NET API, which is on top of the ML.NET API.](https://w-share.oss-cn-shanghai.aliyuncs.com/20201115230226.png) 你可以在 Microsoft Docs 中瞭解更多關於 ML.NET 的資訊,網址是:[https://aka.ms/mlnetdocs](https://aka.ms/mlnetdocs)。 ## ML 和大資料結合 大資料和 ML 可以很好地結合在一起。讓我們構建一個同時使用 Spark for .NET 和 ML.NET 的管道,以展示大資料和 ML 如何一起工作。Markdown 是一種用於編寫文件和建立靜態網站的流行語言,它使用的語法不如 HTML 複雜,但提供的格式控制比純文字更多。這是從 .NET 文件庫中的摘取一段 markdown 檔案內容: ```markdown --- title: Welcome to .NET description: Getting started with the .NET family of technologies. ms.date: 12/03/2019 ms.custom: "updateeachrelease" --- # Welcome to .NET See [Get started with .NET Core](core/get-started.md) to learn how to create .NET Core apps. Build many types of apps with .NET, such as cloud ,IoT, and games using free cross-platform tools... ``` 破折號之間的部分稱為**前頁**(front matter),是使用 YAML 描述的有關文件的元資料。以井號(#)開頭的部分是標題。兩個雜湊(##)表示二級標題。“ .NET Core 入門”是一個超連結。 我們的目標是處理大量文件,新增諸如字數和估計的閱讀時間之類的元資料,並將相似的文章自動分組在一起。 這是我們將構建的管道: - 為每個文件建立字數統計; - 估計每個文件的閱讀時間; - 根據“ TF-IDF”或“術語頻率/反向文件頻率”為每個文件建立前 20 個單詞的列表(這將在後面說明)。 第一步是拉取文件儲存庫和需引用的應用程式。你可以使用任何包含 Markdown 檔案的儲存庫及資料夾結構。本文使用的示例來自 .NET 文件儲存庫,可從 [https://aka.ms/dot-net-docs](https://aka.ms/dot-net-docs) 克隆。 為.NET 和 Spark 準備本地環境之後,可以從[https://aka.ms/spark-ml-example](https://aka.ms/spark-ml-example)拉取專案。 解決方案資料夾包含一個批處理命令(在倉庫中有提供),你可以使用該命令來執行所有步驟。 ### 處理 Markdown DocRepoParser 專案以遞迴方式遍歷儲存庫中的子資料夾,以收集各文件有關的元資料。Common 專案包含幾個幫助程式類。例如,`FilesHelper` 用於所有檔案 I/O。它跟蹤儲存檔案和檔名的位置,並提供諸如為其他專案讀取檔案的服務。建構函式需要一個標籤(一個唯一標識工作流的數字)和包含文件的 repo 或頂級資料夾的路徑。預設情況下,它在使用者的本地應用程式資料資料夾下建立一個資料夾。如有必要,可以將其覆蓋。 `MarkdownParser`利用 `Microsoft.Toolkit.Parsers`解析 Markdown 的庫。該庫有兩個任務:首先,它必須提取標題和子標題;其次,它必須提取單詞。Markdown 檔案以 "塊 "的形式暴露出來,代表標題、連結和其他 Markdown 特徵。塊又包含承載文字的“Inlines”。例如,這段程式碼通過迭代行和單元格來解析一個 TableBlock,以找到 Inlines。 ```cs case TableBlock table: table.Rows.SelectMany(r => r.Cells) .SelectMany(c => c.Inlines) .ForEach(i => candidate = RecurseInline(i, candidate, words, titles)); break; ``` 此程式碼提取超連結的文字部分: ```cs case HyperlinkInline hyper: if (!string.IsNullOrWhiteSpace(hyper.Text)) { words.Append(hyper.Text.ExtractWords()); } break; ``` 結果是一個 CSV 檔案,如下圖所示: ![圖7:生成的CSV檔案](https://w-share.oss-cn-shanghai.aliyuncs.com/20201115230227.png) 第一步只是準備要處理的資料。下一步使用 Spark for .NET 作業確定每個文件的字數,閱讀時間和前 20 個術語。 ### 構建 Spark Job `SparkWordsProcessor`專案用來執行 Spark 作業。雖然該應用程式是一個控制檯專案,但它需要 Spark 來執行。`runjob.cmd`批處理命令將作業提交到正確配置的 Windows 計算機上執行。典型作業的模式是建立一個會話或“應用程式”,執行一些邏輯,然後停止會話。 ```cs var spark = SparkSession.Builder() .AppName(nameof(SparkWordsProcessor)) .GetOrCreate(); RunJob(); spark.Stop(); ``` 通過將其路徑傳遞給 Spark 會話,可以輕鬆讀取上一步的檔案。 ```cs var docs = spark.Read().HasHeader().Csv(filesHelper.TempDataFile); docs.CreateOrReplaceTempView(nameof(docs)); var totalDocs = docs.Count(); ``` `docs`變數解析為一個`DataFrame`。**Data Frame 本質上是一個帶有一組列和一個通用介面的表,用於與資料互動,而不管其底層來源是什麼。**可以從其他 data frame 中引用一個 data frame。SparkSQL 也可以用來查詢 data frame。你必須建立一個臨時檢視,該檢視為 data frame 提供別名,以便從 SQL 中引用它。通過`CreateOrReplaceTempView`方法,可以像這樣從 data frame 中查詢行: ```sql SELECT * FROM docs ``` `totalDocs`變數檢索文件中所有行的計數。Spark 提供了一個名為`Split`的將字串分解為陣列的函式。`Explode`函式將每個陣列項變成一行: ```cs var words = docs.Select(fileCol, Functions.Split(nameof(FileDataParse.Words) .AsColumn(), " ") .Alias(wordList)) .Select(fileCol, Functions.Explode(wordList.AsColumn()) .Alias(word)); ``` 該查詢為每個單詞或術語生成一行。這個 data frame 是生成**術語頻率**(TF)或者說每個文件中每個詞的計數的基礎。 ```cs var termFrequency = words .GroupBy(fileCol, Functions.Lower(word.AsColumn()).Alias(word)) .Count() .OrderBy(fileCol, count.AsColumn().Desc()); ``` Spark 有內建的模型,可以確定“術語頻率/反向文件頻率”。在這個例子中,你將手動確定術語頻率來演示它是如何計算的。術語在每個文件中以特定的頻率出現。一篇關於 wizard 的文件可能有很高的“wizard”一詞計數。同一篇文件中,"the "和 "is "這兩個詞的出現次數可能也很高。對我們來說,很明顯,“wizard”這個詞更重要,也提供了更多的語境。另一方面,Spark 必須經過訓練才能識別重要的術語。為了確定什麼是真正重要的,我們將總結**文件頻率**(document frequency),或者說一個詞在 repo 中所有文件中出現的次數。這就是“按不同出現次數分組”: ```cs var documentFrequency = words .GroupBy(Functions.Lower(word.AsColumn()) .Alias(word)) .Agg(Functions.CountDistinct(fileCol) .Alias(docFrequency)); ``` 現在是計算的時候了。一個特殊的方程式可以計算出所謂的**反向文件頻率**(inverse document frequency),即 IDF。將總文件的自然對數(加一)輸入方程,然後除以該詞的文件頻率(加一)。 ```cs static double CalculateIdf(int docFrequency, int totalDocuments) => Math.Log(totalDocuments + 1) / (docFrequency + 1); ``` 在所有文件中出現的詞比出現頻率較低的詞賦值低。例如,給定 1000 個文件,一個在每個文件中出現的詞與一個只在少數文件中出現的詞(約 1 個)相比,IDF 為 0.003。Spark 支援使用者定義的函式,你可以這樣註冊。 ```cs spark.Udf().Register(nameof(CalculateIdf), CalculateIdf); ``` 接下來,你可以使用該函式來計算 data frame 中所有單詞的 IDF: ```cs var idfPrep = documentFrequency.Select(word.AsColumn(), docFrequency.AsColumn()) .WithColumn(total, Functions.Lit(totalDocs)) .WithColumn(inverseDocFrequency, Functions.CallUDF(nameof(CalculateIdf), docFrequency.AsColumn(), total.AsColumn() ) ); ``` 使用文件頻率 data frame,增加兩列。第一列是文件的單詞總數量,第二列是呼叫你的 UDF 來計算 IDF。還有一個步驟,就是確定“重要詞”。重要詞是指在所有文件中不經常出現,但在當前文件中經常出現的詞,用 TF-IDF 表示,這只是 IDF 和 TF 的產物。考慮“is”的情況,IDF 為 0.002,在文件中的頻率為 50,而“wizard”的 IDF 為 1,頻率為 10。相比頻率為 10 的“wizard”,“is”的 TF-IDF 計算結果為 0.1。這讓 Spark 對重要性有了更好的概念,而不僅僅是原始字數。 到目前為止,你已經使用程式碼來定義 data frame。讓我們嘗試一下 SparkSQL。為了計算 TF-IDF,你將文件頻率 data frame 與反向文件頻率 data frame 連線起來,並建立一個名為`termFreq_inverseDocFreq`的新列。下面是 SparkSQL: ```cs var idfJoin = spark.Sql($"SELECT t.File, d.word, d.{docFrequency}, d.{inverseDocFrequency}, t.count, d.{inverseDocFrequency} * t.count as {termFreq_inverseDocFreq} from {nameof(documentFrequency)} d inner join {nameof(termFrequency)} t on t.word = d.word"); ``` 探索程式碼,看看最後的步驟是如何實現的。這些步驟包括: 到目前為止所描述的所有步驟都為 Spark 提供了一個模板或定義。像 LINQ 查詢一樣,實際的處理在結果被具體化之前不會發生(比如計算出總文件數時)。最後一步呼叫 Collect 來處理和返回結果,並將其寫入另一個 CSV。然後,你可以使用新檔案作為 ML 模型的輸入,下圖是該檔案的一部分: ![圖8:已準備好進行ML訓練的已處理元資料。](https://w-share.oss-cn-shanghai.aliyuncs.com/20201115230228.png) Spark for .NET 使你能夠查詢和塑造資料。你在同一個資料來源上建立了多個 data frame,然後新增它們以獲得關於重要術語、字數和閱讀時間的洞察。下一步是應用 ML 來自動生成類別。 ### 預測類別 最後一步是對文件進行分類。`DocMLCategorization`專案包含了 ML.NET 的`Microsoft.ML`包。雖然 Spark 使用的是 data frame,但 data view 在 ML.NET 中提供了類似的概念。 這個例子為 ML.NET 使用了一個單獨的專案,這樣就可以將模型作為一個獨立的步驟進行訓練。對於許多場景,可以直接從你的.NET for Spark 專案中引用 ML.NET,並將 ML 作為同一工作的一部分來執行。 首先,你必須對類進行標記,以便 ML.NET 知道源資料中的哪些列對映到類中的屬性。在`FileData` 類使用` LoadColumn` 註解,就像這樣: ```cs [LoadColumn(0)] public string File { get; set; } [LoadColumn(1)] public string Title { get; set; } ``` 然後,你可以為模型建立上下文,並從上一步中生成的檔案中載入 data view: ```cs var context = new MLContext(seed: 0); var dataToTrain = context.Data .LoadFromTextFile(path: filesHelper.ModelTrainingFile, hasHeader: true, allowQuoting: true, separatorChar: ','); ``` ML 演算法對數字的處理效果最好,所以文件中的文字必須轉換為數字向量。ML.NET 為此提供了`FeaturizeText`方法。在一個步驟中,模型分別: - 檢測語言 - 將文字標記為單個單詞或標記 - 規範化文字,以便對單詞的變體進行標準化和大小寫相似化 - 將這些術語轉換為一致的數值或準備處理的“特徵向量” 以下程式碼將列轉換為特徵,然後建立一個結合了多個特徵的“Features”列。 ```csharp var pipeline = context.Transforms.Text.FeaturizeText( nameof(FileData.Title).Featurized(), nameof(FileData.Title)).Append(context.Transforms.Text.FeaturizeText(nameof(FileData.Subtitle1).Featurized(), nameof(FileData.Subtitle1))).Append(context.Transforms.Text.FeaturizeText(nameof(FileData.Subtitle2).Featurized(), nameof(FileData.Subtitle2))).Append(context.Transforms.Text.FeaturizeText(nameof(FileData.Subtitle3).Featurized(), nameof(FileData.Subtitle3))).Append(context.Transforms.Text.FeaturizeText(nameof(FileData.Subtitle4).Featurized(), nameof(FileData.Subtitle4))).Append(context.Transforms.Text.FeaturizeText(nameof(FileData.Subtitle5).Featurized(), nameof(FileData.Subtitle5))).Append(context.Transforms.Text.FeaturizeText(nameof(FileData.Top20Words).Featurized(), nameof(FileData.Top20Words))).Append(context.Transforms.Concatenate(features, nameof(FileData.Title).Featurized(), nameof(FileData.Subtitle1).Featurized(), nameof(FileData.Subtitle2).Featurized(), nameof(FileData.Subtitle3).Featurized(), nameof(FileData.Subtitle4).Featurized(), nameof(FileData.Subtitle5).Featurized(), nameof(FileData.Top20Words).Featurized()) ); ``` 此時,資料已經為訓練模型做了適當的準備。訓練是無監督的,這意味著它必須用一個例子來推斷資訊。你沒有將樣本類別輸入到模型中,所以演算法必須通過分析特徵如何聚類來找出資料的相互關聯。你將使用**k-means 聚類**演算法。該演算法使用特徵計算文件之間的“距離”,然後圍繞分組後的文件“繪製”邊界。該演算法涉及隨機化,因此兩次執行結果會是不相同的。主要的挑戰是確定訓練的最佳聚類大小。不同的文件集最好有不同的最佳類別數,但演算法需要你在訓練前輸入類別數。 程式碼在 2 到 20 個簇之間迭代,以確定最佳大小。對於每次執行,它都會獲取特徵資料並應用演算法或訓練器。然後,它根據預測模型對現有資料進行轉換。對結果進行評估,以確定每個簇中文件的平均距離,並選擇平均距離最小的結果。 ```cs var options = new KMeansTrainer.Options { FeatureColumnName = features, NumberOfClusters = categories, }; var clusterPipeline = pipeline.Append(context.Clustering.Trainers.KMeans(options)); var model = clusterPipeline.Fit(dataToTrain); var predictions = model.Transform(dataToTrain); var metrics = context.Clustering.Evaluate(predictions); distances.Add(categories, metrics.AverageDistance); ``` 經過培訓和評估後,你可以儲存最佳模型,並使用它對資料集進行預測。將生成一個輸出檔案以及一個摘要,該摘要顯示有關每個類別的一些元資料並在下面列出標題。標題只是幾個功能之一,因此有時需要仔細研究細節才能使類別有意義。在本地測試中,教程之類的文件歸於一組,API 文件歸於另一組,而例外歸於它們自己的組。 > ML zip 檔案可與 Prediction Engine 一起用於其他專案中的新資料。 機器學習模型另存為單個 zip 檔案。該檔案可以包含在其他專案中,與 Prediction Engine 一起使用以對新資料進行預測。例如,你可以建立一個 WPF 應用程式,該應用程式允許使用者瀏覽目錄,然後載入並使用經過訓練的模型對文件進行分類,而無需先對其進行訓練。 ## 下一步是什麼 Spark for .NET 計劃與.NET 5 同時在 GA(譯註:GA=General Availability,正式釋出的版本)釋出。請訪問 https://aka.ms/spark-net-roadmap 閱讀路線圖和推出功能的計劃。(譯註:.NET 5 正式釋出時間已過,Spark for .NET 已隨 .NET 5 正式釋出) 本文著重於本地開發體驗,為了充分利用大資料的力量,你可以將 Spark 作業提交到雲中。有各種各樣的雲主機可以容納 PB 級資料,併為你的工作負載提供數十個核的計算能力。Azure Synapse Analytics 是一項 Azure 服務,旨在承載大量資料,提供用於執行大資料作業的群集,並允許通過基於圖表的儀表盤進行互動式探索。若要了解如何將 Spark for .NET 作業提交到 Azure Synapse,請閱讀官方文件(https://aka.ms/spark-net-synapse)。 下面這張表列舉了 ML.NET 機器學習的常見任務和場景: | 任務 | 示例場景 | | ----------------------------- | ------------------------------------------------------------------------------------ | | 分類(基於文字) Classification | 將郵件資訊分類為垃圾郵件或非垃圾郵件,或根據內容將調查評論分為不同的組別。 | | 迴歸 Regression | 根據二手車的品牌、型號、里程數來預測二手車的價格,或者根據廣告預算來預測產品的銷量。 | | 預測 Forecasting | 根據過去的銷售情況來預測未來產品的銷售情況,或天氣預報。 | | 異常檢測 Anomaly detection | 檢測產品在一段時間內的銷售高峰或檢測斷電情況。 | | 排名 Ranking | 預測搜尋引擎結果的最佳顯示順序,或為使用者的新聞排序。 | | 聚類 Clustering | 對客戶進行細分。 | | 推薦 Recommendation | 根據使用者之前看的電影向用戶推薦電影,或者推薦經常一起購買的產品。 | | 影象分類 Image classification | 對機器零件的影象進行分類。 | | 物件檢測 Object detection | 檢測汽車影象上的車牌。 |