版本記錄
| 版本號 | 時間 |
|---|---|
| V1.0 | 2018.10.16 星期二 |
前言
目前世界上科技界的所有大佬一致認為人工智能是下一代科技革命,蘋果作為科技界的巨頭,當然也會緊跟新的科技革命的步伐,其中ios API 就新出了一個框架
Core ML。ML是Machine Learning的縮寫,也就是機器學習,這正是現(xiàn)在很火的一個技術(shù),它也是人工智能最核心的內(nèi)容。感興趣的可以看我寫的下面幾篇。
1. Core ML框架詳細解析(一) —— Core ML基本概覽
2. Core ML框架詳細解析(二) —— 獲取模型并集成到APP中
3. Core ML框架詳細解析(三) —— 利用Vision和Core ML對圖像進行分類
4. Core ML框架詳細解析(四) —— 將訓練模型轉(zhuǎn)化為Core ML
5. Core ML框架詳細解析(五) —— 一個Core ML簡單示例(一)
6. Core ML框架詳細解析(六) —— 一個Core ML簡單示例(二)
7. Core ML框架詳細解析(七) —— 減少Core ML應(yīng)用程序的大?。ㄒ唬?/a>
8. Core ML框架詳細解析(八) —— 在用戶設(shè)備上下載和編譯模型(一)
9. Core ML框架詳細解析(九) —— 用一系列輸入進行預測(一)
10. Core ML框架詳細解析(十) —— 集成自定義圖層(一)
11. Core ML框架詳細解析(十一) —— 創(chuàng)建自定義圖層(一)
12. Core ML框架詳細解析(十二) —— 用scikit-learn開始機器學習(一)
開始
首先看一下本文的寫作環(huán)境
Swift 4, iOS 11, Xcode 9
Apple的Core ML和Vision框架已經(jīng)讓開發(fā)人員進入了一個勇敢的機器學習新世界,并帶來了令人興奮的可能性。Vision允許您檢測和跟蹤面部,Apple的Machine Learning page提供檢測對象和場景的即用型模型,以及用于自然語言處理的NSLinguisticTagger。如果您想構(gòu)建自己的模型,請嘗試使用Apple的新Turi Create來擴展其使用您的數(shù)據(jù)預先訓練的模型之一。
但是,如果您想要做什么需要更加個性化的東西?然后,是時候進入機器學習(ML),使用谷歌,微軟,亞馬遜或伯克利的眾多框架之一。而且,為了讓生活更加精彩,您需要選擇一種新的編程語言和一套新的開發(fā)工具。
在這個Keras機器學習教程中,您將學習如何訓練深度學習卷積神經(jīng)網(wǎng)絡(luò)模型,將其轉(zhuǎn)換為Core ML,并將其集成到iOS應(yīng)用程序中。您將學習一些ML術(shù)語,使用一些新工具,并在此過程中學習一些Python。
示例項目使用ML的Hello-World示例 - 一種對手寫數(shù)字進行分類的模型,在MNIST dataset上進行訓練。
Why Use Keras? - 為什么使用Keras?
ML模型涉及許多復雜的代碼,操縱數(shù)組和矩陣。但ML已經(jīng)存在了很長時間,研究人員已經(jīng)創(chuàng)建了庫,使像我們這樣的人更容易創(chuàng)建ML模型。其中許多是用Python編寫的,盡管研究人員還使用R,SAS,MATLAB和其他軟件。但您可能會在基于Python的工具中找到所需的一切:
-
scikit-learn提供了一種運行許多經(jīng)典ML算法的簡便方法,例如線性回歸和支持向量機。 - 另一方面是
PyTorch和Google的TensorFlow,它可以讓您更好地控制深度學習模型的內(nèi)部工作。 - 微軟的
CNTK和Berkeley的Caffe是類似的深度學習框架,它們使用Python API來訪問他們的C ++引擎。
那么Keras在哪里適合?這是TensorFlow和CNTK的包裝,亞馬遜的MXN??et即將推出。 (它也與Theano合作,但蒙特利爾大學于2017年9月停止了這項工作。)它提供了一個易于使用的API,用于構(gòu)建模型,您可以在一個后端訓練,并在另一個后端部署。
使用Keras而不是直接使用TensorFlow的另一個原因是coremltools包括Keras轉(zhuǎn)換器,但不包括TensorFlow轉(zhuǎn)換器 - 盡管存在TensorFlow to CoreML converter和MXNet to CoreML converter。雖然Keras支持CNTK作為后端,但coremltools僅適用于Keras + TensorFlow。
注意:在使用這些工具之前,您是否需要學習Python?好吧,我沒有。當你完成本教程時,你會發(fā)現(xiàn)Python語法與Swift類似:更加簡化,縮進是語法的重要部分。如果您感到緊張,請在瀏覽器選項卡中保持打開狀態(tài),以便快速參考:Crash Course in Python for Machine Learning Developers。
另一個注意事項:研究人員同時使用
Python 2和Python 3,但coremltools在Python 2.7中運行得更好。
開始進入正題
打開項目起始文件夾:它包含一個入門iOS應(yīng)用程序,您將在其中添加ML模型和代碼以使用它。 它還包含一個docker-keras文件夾,其中包含本教程的Jupyter筆記本。
1. Setting Up Docker - 設(shè)置Docker
Docker是一個容器平臺,允許您在自定義環(huán)境中部署應(yīng)用程序 - 有點像虛擬機,但different。 通過安裝Docker,您可以訪問大量的ML資源,這些資源主要作為Docker鏡像中的交互式Jupyter notebooks分發(fā)。
注意:安裝Docker并構(gòu)建映像需要幾分鐘,因此請在等待時閱讀
ML in a Nutshell。
下載,安裝和啟動Docker Community Edition for Mac。 在終端中,一次輸入以下命令:
cd <where you unzipped starter>/starter/docker-keras
docker build -t keras-mnist .
docker run --rm -it -p 8888:8888 -v $(pwd)/notebook:/workspace/notebook keras-mnist
最后一個命令將Docker容器的notebook文件夾映射到本地notebook文件夾,因此即使在您注銷Docker服務(wù)器之后,您也可以訪問notebook所寫的文件。
在命令輸出的最后是包含token的URL。 它看起來像這樣,但具有不同的標記值:
http://0.0.0.0:8888/?token=7b189c8e200f49dcc33845d39101e8a0ab257db5f3b539a7
將此URL粘貼到瀏覽器中以登錄Docker容器的notebook服務(wù)器。
打開notebook文件夾,然后打開keras_mnist.ipynb。 點擊Not Trusted按鈕將其更改為Trusted:這樣您就可以在notebook文件夾中保存對notebook以及模型文件所做的更改。
2. ML in a Nutshell - Nutshell中的ML
Arthur Samuel將機器學習定義為“研究領(lǐng)域,讓計算機具有無需明確編程即可學習的能力”。 您有數(shù)據(jù),它具有一些可用于對數(shù)據(jù)進行分類的功能,或者用它來進行一些預測,但是您沒有用于這種計算的明確的公式,因此您無法編寫程序來執(zhí)行此操作。 如果您有“足夠”的數(shù)據(jù)樣本,則可以訓練計算機模型以識別此數(shù)據(jù)中的模式,然后將其學習應(yīng)用于新數(shù)據(jù)。 當您知道所有訓練數(shù)據(jù)的正確結(jié)果時,它被稱為監(jiān)督學習:然后模型僅根據(jù)已知結(jié)果檢查其預測,并調(diào)整自身以減少誤差并提高準確性。 無監(jiān)督學習超出了本教程的范圍。
Weights & Threshold - 權(quán)重和閾值

假設(shè)您想和一群朋友一起選擇一家餐廳共進晚餐。 有幾個因素會影響您的決定:飲食限制,公共交通,價格范圍,食物類型,兒童友好等。您為每個因素分配一個權(quán)重,以表明其對您決定的重要性。 然后,對于選項列表中的每個餐館,您可以根據(jù)餐廳滿足該因素的程度為每個因素分配一個值。 您將每個因子值乘以系數(shù)的權(quán)重,然后將它們相加以獲得加權(quán)和。 結(jié)果最高的餐廳是最佳選擇。 使用此模型的另一種方法是生成二進制輸出:是或否。 您設(shè)置了一個閾值,并從列表中刪除任何加權(quán)總和低于此閾值的餐館。
Training an ML Model - 訓練ML模型
提出權(quán)重并不是一件容易的事。 但幸運的是,您有很多以前的晚餐數(shù)據(jù),包括選擇了哪家餐廳,因此您可以訓練ML模型來計算產(chǎn)生相同結(jié)果的權(quán)重,盡可能接近。 然后將這些計算出的權(quán)重應(yīng)用于未來的決策。
要訓練ML模型,首先要使用隨機權(quán)重,將它們應(yīng)用于訓練數(shù)據(jù),然后將計算出的輸出與已知輸出進行比較以計算誤差。 這是一個具有最小值的多維函數(shù),訓練的目標是確定非常接近此最小值的權(quán)重。 權(quán)重也需要處理新數(shù)據(jù):如果大量驗證數(shù)據(jù)的誤差高于訓練數(shù)據(jù)的誤差,那么模型就會過度擬合 - 權(quán)重對訓練數(shù)據(jù)越適合,表明訓練錯誤檢測到一些不會推廣到新數(shù)據(jù)的功能。
Stochastic Gradient Descent - 隨機梯度下降
要計算減少誤差的權(quán)重,可以在當前圖形位置計算誤差函數(shù)的梯度,然后調(diào)整權(quán)重以“降低”斜率。 這稱為梯度下降,在訓練期間多次發(fā)生。 對于大型數(shù)據(jù)集,使用所有數(shù)據(jù)計算梯度需要很長時間。 隨機梯度下降(Stochastic gradient descent - SGD)從隨機選擇的小批量訓練數(shù)據(jù)中估計梯度 - 例如在選舉日之前對選民進行調(diào)查:如果您的樣本代表整個數(shù)據(jù)集,則調(diào)查結(jié)果可準確預測最終結(jié)果。

Optimizers - 優(yōu)化器
錯誤函數(shù)是塊狀的:你必須小心不要走得太遠,否則你可能會錯過最低限度。 你的步數(shù)也需要有足夠的動力來推動你擺脫任何虛假的最低限度。 ML研究人員為設(shè)計優(yōu)化算法付出了很多努力。 目前最受歡迎的是Adam(Adaptive Moment estimation - 自適應(yīng)力矩估計),它結(jié)合了以前最受歡迎的RMSprop(Root Mean Square propagation - 均方根傳播)和AdaGrad(Adaptive Gradient algorithm - 自適應(yīng)梯度算法)的特征。
Keras Code Time! - Keras代碼時間!
好的,Docker容器現(xiàn)在應(yīng)該準備就緒:返回并按照說明打開notebook。 是時候?qū)懸恍?code>Keras代碼了!
在具有匹配標題的keras_mnist.ipynb單元格中輸入以下代碼。 在每個單元格中輸入代碼后,按Control-Enter運行它。 代碼運行時,In []:標簽中會出現(xiàn)一個星號,然后會出現(xiàn)一個數(shù)字,以顯示運行單元格的順序。 當您登錄notebook時,所有內(nèi)容都會保留在內(nèi)存中。 每隔一段時間,點擊Save and Checkpoint按鈕。

注意:雙擊
markdown單元格以添加自己的注釋;按Control-Enter以呈現(xiàn)markdown并運行Python代碼。 您還可以使用其他筆記本按鈕添加或復制粘貼單元格,以及移動單元格。
Import Utilities & Dependencies - 導入實用項和依賴項
輸入以下代碼,然后運行它以檢查Keras版本。
from __future__ import print_function
from matplotlib import pyplot as plt
import keras
from keras.datasets import mnist
from keras.models import Sequential
from keras.layers import Dense, Dropout, Flatten
from keras.layers import Conv2D, MaxPooling2D
from keras.utils import np_utils
from keras import backend as K
import coremltools
# coremltools supports Keras version 2.0.6
print('keras version ', keras.__version__)

__future__是Python 2和Python 3之間的兼容層:Python 2有一個print命令(沒有括號),但Python 3需要print()函數(shù)。 導入print_function允許您在Python 2代碼中使用print()語句。
Keras使用NumPy數(shù)學庫來操作數(shù)組和矩陣。 Matplotlib是NumPy的繪圖庫:您將使用它來檢查訓練數(shù)據(jù)項。
注意:由于due to NumPy 1.14,您可能會看到FutureWarning。
導入keras后,打印其版本:coremltools支持2.0.6版,如果使用更高版本,將發(fā)出警告。 Keras已經(jīng)擁有MNIST數(shù)據(jù)集,因此您可以導入它。 然后接下來的三行導入模型組件。 您導入NumPy實用程序,并為后端提供帶有import backend as K的標簽,您將使用它來檢查image_data_format。
最后,導入coremltools,您將在此notebook的末尾使用它。
Load & Pre-Process Data - 加載和預處理數(shù)據(jù)
1. Training & Validation Data Sets - 訓練和驗證數(shù)據(jù)集
首先,獲取您的數(shù)據(jù)! 輸入以下代碼并運行它:下載數(shù)據(jù)需要一段時間。
(x_train, y_train), (x_val, y_val) = mnist.load_data()
這將從https://s3.amazonaws.com/img-datasets/mnist.npz下載數(shù)據(jù),對數(shù)據(jù)項進行混洗,并在訓練數(shù)據(jù)集和驗證數(shù)據(jù)集之間進行拆分。 驗證數(shù)據(jù)有助于檢測模型過度擬合到訓練數(shù)據(jù)的問題。 訓練步驟使用訓練的參數(shù)來計算驗證數(shù)據(jù)的輸出。 您將設(shè)置回調(diào)以監(jiān)控驗證丟失和準確性,以保存對驗證數(shù)據(jù)執(zhí)行最佳的模型,并且如果驗證丟失或準確性未能在太多時期(重復)中提高,則可能提前停止。
2. Inspect x & y Data - Inspect x&y數(shù)據(jù)
下載完成后,在下一個單元格中輸入以下代碼,然后運行它以查看您獲得的內(nèi)容。
注意:您不必輸入以#開頭的行。 這些是注釋,其中大部分都是為了向您展示運行單元格時
notebook應(yīng)顯示的內(nèi)容。
# Inspect x data
print('x_train shape: ', x_train.shape)
# Displays (60000, 28, 28)
print(x_train.shape[0], 'training samples')
# Displays 60000 train samples
print('x_val shape: ', x_val.shape)
# Displays (10000, 28, 28)
print(x_val.shape[0], 'validation samples')
# Displays 10000 validation samples
print('First x sample\n', x_train[0])
# Displays an array of 28 arrays, each containing 28 gray-scale values between 0 and 255
# Plot first x sample
plt.imshow(x_train[0])
plt.show()
# Inspect y data
print('y_train shape: ', y_train.shape)
# Displays (60000,)
print('First 10 y_train elements:', y_train[:10])
# Displays [5 0 4 1 9 2 1 3 1 4]
您有60,000個28×28像素的訓練樣本和10,000個驗證樣本。 第一個訓練樣本是一個包含28個數(shù)組的數(shù)組,每個數(shù)組包含0到255之間的28個灰度值。查看非零值,您可以看到類似數(shù)字5的形狀。

果然,plt代碼顯示第一個訓練樣本是手寫的5:

y數(shù)據(jù)是一個60000元素的數(shù)組,包含訓練樣本的正確分類:第一個訓練樣本為5,下一個為0,依此類推。
3. Set Input & Output Dimensions - 設(shè)置輸入和輸出尺寸
輸入這兩行,然后運行單元格以設(shè)置x輸入和y輸出的基本尺寸。
img_rows, img_cols = x_train.shape[1], x_train.shape[2]
num_classes = 10
MNIST數(shù)據(jù)項是28×28像素的圖像,您希望將每個數(shù)據(jù)分類為0到9之間的數(shù)字。
您可以使用x_train.shape值來設(shè)置圖像行和列的數(shù)量。 x_train.shape是一個包含3個元素的數(shù)組:
- 0) 數(shù)據(jù)樣本數(shù):60000
- 1) 每個數(shù)據(jù)樣本的行數(shù):28
- 2) 每個數(shù)據(jù)樣本的列數(shù):28
4. Reshape x Data & Set Input Shape
該模型需要略有不同的“shape”的數(shù)據(jù)。 輸入以下代碼,然后運行它。
# Set input_shape for channels_first or channels_last
if K.image_data_format() == 'channels_first':
x_train = x_train.reshape(x_train.shape[0], 1, img_rows, img_cols)
x_val = x_val.reshape(x_val.shape[0], 1, img_rows, img_cols)
input_shape = (1, img_rows, img_cols)
else:
x_train = x_train.reshape(x_train.shape[0], img_rows, img_cols, 1)
x_val = x_val.reshape(x_val.shape[0], img_rows, img_cols, 1)
input_shape = (img_rows, img_cols, 1)
卷積神經(jīng)網(wǎng)絡(luò)認為圖像具有寬度,高度和深度。 深度維度稱為通道,并包含顏色信息。 灰度圖像有1個通道;RGB圖像有3個通道。
像TensorFlow和CNTK這樣的Keras后端,期望圖像數(shù)據(jù)采用channels-last format (rows, columns, channels) 或 channels-first format (channels, rows, columns)。 reshape函數(shù)將通道插入正確的位置。
您還可以在正確的末尾設(shè)置初始input_shape和通道。
5. Inspect Reshaped x Data
輸入下面的代碼,然后運行它以查看形狀的變化情況。
print('x_train shape:', x_train.shape)
# x_train shape: (60000, 28, 28, 1)
print('x_val shape:', x_val.shape)
# x_val shape: (10000, 28, 28, 1)
print('input_shape:', input_shape)
# input_shape: (28, 28, 1)
TensorFlow圖像數(shù)據(jù)格式是最后一個通道,因此x_train.shape和x_val.shape現(xiàn)在最后有一個新元素1。
6. Convert Data Type & Normalize Values - 轉(zhuǎn)換數(shù)據(jù)類型和規(guī)范化值
模型需要特定格式的數(shù)據(jù)值。 輸入以下代碼,然后運行它。
x_train = x_train.astype('float32')
x_val = x_val.astype('float32')
x_train /= 255
x_val /= 255
MNIST圖像數(shù)據(jù)值的類型為uint8,范圍為[0,255],但Keras需要float32類型的值,范圍為[0,1]。
7. Inspect Normalized x Data
輸入以下代碼,然后運行它以查看對x數(shù)據(jù)的更改。
print('First x sample, normalized\n', x_train[0])
# An array of 28 arrays, each containing 28 arrays, each with one value between 0 and 1
現(xiàn)在每個值都是一個數(shù)組,值是浮點數(shù),非零值介于0和1之間。

8. Reformat y Data
y數(shù)據(jù)是一個60000個元素的數(shù)組,包含訓練樣本的正確分類,但是只有10個類別并不明顯。 輸入以下代碼,僅運行一次以重新格式化y數(shù)據(jù)。
print('y_train shape: ', y_train.shape)
# (60000,)
print('First 10 y_train elements:', y_train[:10])
# [5 0 4 1 9 2 1 3 1 4]
# Convert 1-dimensional class arrays to 10-dimensional class matrices
y_train = np_utils.to_categorical(y_train, num_classes)
y_val = np_utils.to_categorical(y_val, num_classes)
print('New y_train shape: ', y_train.shape)
# (60000, 10)
y_train是一維數(shù)組,但該模型需要一個60000 x 10矩陣來表示10個類別。 您還必須為10000元素的y_val數(shù)組進行相同的轉(zhuǎn)換。
9. Inspect Reformatted y Data - 檢查重新格式化的y數(shù)據(jù)
輸入以下代碼,然后運行它以查看y數(shù)據(jù)的更改方式。
print('New y_train shape: ', y_train.shape)
# (60000, 10)
print('First 10 y_train elements, reshaped:\n', y_train[:10])
# An array of 10 arrays, each with 10 elements,
# all zeros except at index 5, 0, 4, 1, 9 etc.
y_train現(xiàn)在是一個包含10個元素數(shù)組的數(shù)組,每個數(shù)組都包含除了圖像匹配的索引之外的所有零。

Define Model Architecture - 定義模型架構(gòu)

模型架構(gòu)是煉金術(shù)的一種形式,如完美燒烤醬或garam masala的秘密家庭食譜。 您可以從通用架構(gòu)開始,然后調(diào)整它以利用輸入數(shù)據(jù)中的對稱性,或者生成具有特定特征的模型。
以下是來自兩位研究人員的模型:Sri Raghu Malireddi和Keras作者的Fran?ois Chollet。 Chollet是通用的,Malireddi's旨在生產(chǎn)適合移動應(yīng)用的小模型。
輸入以下代碼,然后運行它以查看模型摘要。
1. Malireddi’s Architecture
model_m = Sequential()
model_m.add(Conv2D(32, (5, 5), input_shape=input_shape, activation='relu'))
model_m.add(MaxPooling2D(pool_size=(2, 2)))
model_m.add(Dropout(0.5))
model_m.add(Conv2D(64, (3, 3), activation='relu'))
model_m.add(MaxPooling2D(pool_size=(2, 2)))
model_m.add(Dropout(0.2))
model_m.add(Conv2D(128, (1, 1), activation='relu'))
model_m.add(MaxPooling2D(pool_size=(2, 2)))
model_m.add(Dropout(0.2))
model_m.add(Flatten())
model_m.add(Dense(128, activation='relu'))
model_m.add(Dense(num_classes, activation='softmax'))
# Inspect model's layers, output shapes, number of trainable parameters
print(model_m.summary())
2. Chollet’s Architecture
model_c = Sequential()
model_c.add(Conv2D(32, (3, 3), input_shape=input_shape, activation='relu'))
# Note: hwchong, elitedatascience use 32 for second Conv2D
model_c.add(Conv2D(64, (3, 3), activation='relu'))
model_c.add(MaxPooling2D(pool_size=(2, 2)))
model_c.add(Dropout(0.25))
model_c.add(Flatten())
model_c.add(Dense(128, activation='relu'))
model_c.add(Dropout(0.5))
model_c.add(Dense(num_classes, activation='softmax'))
# Inspect model's layers, output shapes, number of trainable parameters
print(model_c.summary())
雖然Malireddi的架構(gòu)比Chollet有更多的卷積層(Conv2D),但它的運行速度要快得多,而且結(jié)果模型要小得多。
3. Model Summaries - 模型摘要
快速瀏覽這兩個模型的模型摘要:
model_m:
Layer (type) Output Shape Param #
=================================================================
conv2d_6 (Conv2D) (None, 24, 24, 32) 832
_________________________________________________________________
max_pooling2d_5 (MaxPooling2 (None, 12, 12, 32) 0
_________________________________________________________________
dropout_6 (Dropout) (None, 12, 12, 32) 0
_________________________________________________________________
conv2d_7 (Conv2D) (None, 10, 10, 64) 18496
_________________________________________________________________
max_pooling2d_6 (MaxPooling2 (None, 5, 5, 64) 0
_________________________________________________________________
dropout_7 (Dropout) (None, 5, 5, 64) 0
_________________________________________________________________
conv2d_8 (Conv2D) (None, 5, 5, 128) 8320
_________________________________________________________________
max_pooling2d_7 (MaxPooling2 (None, 2, 2, 128) 0
_________________________________________________________________
dropout_8 (Dropout) (None, 2, 2, 128) 0
_________________________________________________________________
flatten_3 (Flatten) (None, 512) 0
_________________________________________________________________
dense_5 (Dense) (None, 128) 65664
_________________________________________________________________
dense_6 (Dense) (None, 10) 1290
=================================================================
Total params: 94,602
Trainable params: 94,602
Non-trainable params: 0
model_c:
Layer (type) Output Shape Param #
=================================================================
conv2d_4 (Conv2D) (None, 26, 26, 32) 320
_________________________________________________________________
conv2d_5 (Conv2D) (None, 24, 24, 64) 18496
_________________________________________________________________
max_pooling2d_4 (MaxPooling2 (None, 12, 12, 64) 0
_________________________________________________________________
dropout_4 (Dropout) (None, 12, 12, 64) 0
_________________________________________________________________
flatten_2 (Flatten) (None, 9216) 0
_________________________________________________________________
dense_3 (Dense) (None, 128) 1179776
_________________________________________________________________
dropout_5 (Dropout) (None, 128) 0
_________________________________________________________________
dense_4 (Dense) (None, 10) 1290
=================================================================
Total params: 1,199,882
Trainable params: 1,199,882
Non-trainable params: 0
底線Total params是尺寸差異的主要原因:Chollet的1,199,882比Malireddi的94,602多12.5倍。 而這正是模型尺寸的差異:4.8MB對380KB。
Malireddi的模型有三個Conv2D圖層,每個圖層后跟一個MaxPooling2D圖層,它將圖層的寬度和高度減半。 這使得第一個密集層的參數(shù)數(shù)量遠遠小于Chollet,并解釋了為什么Malireddi的模型要小得多并且訓練速度要快得多。 卷積層的實現(xiàn)是高度優(yōu)化的,因此額外的卷積層提高了準確性,而不會增加訓練時間。 但較小的致密層比Chollet的運行速度快得多。
在等待下一步完成運行時,我將在Explanations部分告訴您有關(guān)圖層,輸出形狀和參數(shù)編號的信息。
后記
本篇主要講述了使用Keras和Core ML開始機器學習,感興趣的給個贊或者關(guān)注~~~
