作為圖像識別與機(jī)器視覺界的 "hello world!" ,
MNIST ("Modified National Institute of Standards and Technology")
數(shù)據(jù)集有著舉足輕重的地位?;旧厦勘?a target="_blank">人工智能、機(jī)器學(xué)習(xí)相關(guān)的書上都以它作為開始。
下面我們會用 TensorFlow 搭建一個淺層的神經(jīng)網(wǎng)絡(luò)來運(yùn)行 "hello world!" 模型。 以下內(nèi)容和模塊的運(yùn)算,均在矩池云平臺進(jìn)行。
本次教程分五步:
第一步:數(shù)據(jù)預(yù)處理,包括提取數(shù)據(jù)標(biāo)簽、查看圖片數(shù)據(jù)、數(shù)據(jù)可視化、查看數(shù)據(jù)是否平衡等
第二步:數(shù)據(jù)加載,打亂數(shù)據(jù)集
第三步:構(gòu)建模型,簡單介紹網(wǎng)絡(luò)卷積模型和激活函數(shù),定義訓(xùn)練函數(shù)和學(xué)習(xí)率
第四步:模型訓(xùn)練,查看訓(xùn)練過程和結(jié)果,使用圖表查看模型精確度和學(xué)習(xí)率變化
第五步:嘗試提升精準(zhǔn)度,不斷探索和優(yōu)化
在搭建開始前,我們需要加載以下對應(yīng)的模塊:
第一步:數(shù)據(jù)預(yù)處理
1.1查看數(shù)據(jù)標(biāo)簽
在任何模型建立之前,應(yīng)當(dāng)優(yōu)先查看數(shù)據(jù)的情況。例如數(shù)據(jù)集的大小、訓(xùn)練集和測試集的數(shù)據(jù)數(shù)量、標(biāo)簽的數(shù)據(jù)數(shù)量分布等。
下方為訓(xùn)練集和測試集的數(shù)據(jù)查看代碼:
train = pd.read_csv('mnist/mnist_train.csv') # read train
test = pd.read_csv('mnist/mnist_test.csv') # read train
下方為訓(xùn)練集和測試集的數(shù)量結(jié)果:
train.shape (6000,785)
test.shape (10000,785)
我們可以看到 train 訓(xùn)練集里面有6000條數(shù)據(jù),test 測試集里面有10000條數(shù)據(jù),兩個測試集每行都有785個數(shù)據(jù)。
接下來,我們來看下數(shù)據(jù)集的預(yù)覽:其中第一列是標(biāo)簽列,剩余784列則為像素點(diǎn)數(shù)據(jù),由該784列數(shù)據(jù)組成一張28*28的像素圖片。
1.2 提取數(shù)據(jù)標(biāo)簽
接下來,我們進(jìn)行數(shù)據(jù)標(biāo)簽的提取和處理。先來看下標(biāo)簽數(shù)據(jù)的提取代碼:
train_labels = np.array(train.pop('label'))
test_labels = np.array(test.pop('label'))
查看標(biāo)簽種類,我們可以看出標(biāo)簽表示了從0~9的數(shù)字,沒有其他的錯誤數(shù)據(jù)。
由于運(yùn)算需要,我們需要將一維的圖片數(shù)據(jù)轉(zhuǎn)換成二維圖片數(shù)據(jù)。將圖片數(shù)據(jù)轉(zhuǎn)換成長28,寬28,通道為1的格式,方便卷積計(jì)算。
第二步:數(shù)據(jù)可視化
2.1 隨機(jī)生成數(shù)據(jù)匹配
現(xiàn)在隨機(jī)選取一些我們已經(jīng)轉(zhuǎn)換好的圖片數(shù)據(jù),用 matplot 來查看下標(biāo)簽和圖片是否能夠?qū)ι稀?/p>
方框內(nèi)是隨機(jī)生成的一些非規(guī)則寫法,圖片上方正中間則為對應(yīng)的數(shù)字。
2.2 查看數(shù)據(jù)是否平衡
分類器的設(shè)計(jì)都是基于類分布大致平衡這一假設(shè),通常假定用于訓(xùn)練的數(shù)據(jù)是平衡的,即各類所含樣本數(shù)大致相當(dāng)。
下面我們來看下標(biāo)簽的分布情況,查看每個標(biāo)簽種類的數(shù)據(jù)量是否分布均勻。
在 MINST 數(shù)據(jù)集中,我們的數(shù)據(jù)是處于一個均勻分布的狀態(tài)。
sns.distplot(train_labels, kde=False, bins=10)
2.3 數(shù)據(jù)加載
在建立模型之前,我們需要先定義一些常量:
# 圖像寬度
width = 28
# 圖像高度
height = 28
# batch size
batch_size = 100
# 訓(xùn)練圖片數(shù)量
train_images_num = train.shape[0]
下一步,我們?yōu)槟P徒?shù)據(jù)集。TensorFlow 提供了 Dataset 類可以方便加載訓(xùn)練的數(shù)據(jù),使用方式為 tf.data.Dataset。
其中,訓(xùn)練集的數(shù)據(jù),我們進(jìn)行了隨機(jī)打亂。
train = tf.cast(train, tf.float32)
test = tf.cast(test, tf.float32)
train_ds = tf.data.Dataset.from_tensor_slices((train, train_labels)).shuffle(train_images_num).batch(batch_size)
test_ds = tf.data.Dataset.from_tensor_slices((test, test_labels)).batch(batch_size)
第三步:模型構(gòu)建
3.1 構(gòu)建模型的網(wǎng)絡(luò)層次結(jié)構(gòu)
數(shù)字識別作為入門工程,我們的模型也會相對的簡單。當(dāng)前構(gòu)建模型,采用了以下幾層網(wǎng)絡(luò)層次結(jié)構(gòu):
- 第一層二維卷積層
- Flatten 層:這層的作用是將第一層的卷積曾平坦壓縮成一維,常用在從卷積層到全連接曾的過度,當(dāng)然 Flatten 不影響 batch 的大小
- Dense 層:全連接神經(jīng)網(wǎng)絡(luò)層
- Dense 層:全連接神經(jīng)網(wǎng)絡(luò)層
每一層對應(yīng)的激活函數(shù)如下:
- 第一層使用 ReLU 函數(shù)
- Flatten 層( 無 )
- Dense 層 ReLU 函數(shù)
- Dense 層使用 softmax 損失函數(shù)進(jìn)行輸出
3.2 關(guān)于激活函數(shù)的解釋說明
ReLU函數(shù)
ReLU 函數(shù)全名為線性整流函數(shù)(Rectified Linear Unit, ReLU),又稱修正線性單元,是一種人工神經(jīng)網(wǎng)絡(luò)中常用的激活函數(shù)(activation function),通常指代以斜坡函數(shù)及其變種為代表的非線性函數(shù)。
從函數(shù)的表達(dá)可以看出,函數(shù)抑制了比 0 小的輸入,這個激活函數(shù)有以下特點(diǎn):
- 收斂快
- 在[ 0, x ]區(qū)間內(nèi)不會飽和,即它可以對抗梯度消失問題
- 求導(dǎo)簡單,也就是它的計(jì)算效率很高
softmax 函數(shù)
softmax 用于多分類過程中,它將多個神經(jīng)元的輸出映射到(0,1)區(qū)間內(nèi),可以看成概率來理解,從而來進(jìn)行多分類。
我們來看下它的數(shù)學(xué)表達(dá)式,假設(shè)我們有一個數(shù)組,?V,??Vi 表示 ?V 中的第 ?i 個元素,那么這個元素的 softmax 值就是:
在我們的數(shù)字識別的模型中,我們將最后的輸出成一個10個元素的數(shù)組,數(shù)組從0下標(biāo)開始到9,分別表示對應(yīng)的標(biāo)簽。
然后對這個輸出進(jìn)行 softmax 計(jì)算,取出 softmax 值最大的那個元素對應(yīng)的標(biāo)簽作為我們的分類結(jié)果。
class MNIST(Model):
def __init__(self):
super(MNIST, self).__init__()
self.conv1 = Conv2D(width, 3, activation='relu')
self.flatten = Flatten()
self.d1 = Dense(128, activation='relu')
self.d2 = Dense(10, activation='softmax')
def call(self, x):
x = self.conv1(x)
x = self.flatten(x)
x = self.d1(x)
return self.d2(x)
model = MNIST()
model.build(input_shape=train.shape
3.3 查看模型的構(gòu)建情況
本文利用 summary 接口來查看模型的情況,可以看到我們的每層網(wǎng)絡(luò)的類型、輸出、參數(shù)的個數(shù),最下面還是統(tǒng)計(jì)了可訓(xùn)練參數(shù),全部參數(shù)的情況。
我們選用交叉熵函數(shù)作為我們的損失函數(shù),基本公式如下:
batch 公式:
用隨機(jī)梯度下降算法作為我們的優(yōu)化器:
loss_object = tf.keras.losses.SparseCategoricalCrossentropy()
optimizer = tf.keras.optimizers.SGD()
train_loss = tf.keras.metrics.Mean(name='train_loss')
train_accuracy = tf.keras.metrics.SparseCategoricalAccuracy(name='train_accuracy')
test_loss = tf.keras.metrics.Mean(name='test_loss')
test_accuracy = tf.keras.metrics.SparseCategoricalAccuracy(name='test_accuracy')
定義 train_step 函數(shù):
@tf.function
def train_step(images, labels):
with tf.GradientTape() as tape:
predictions = model(images)
loss = loss_object(labels, predictions)
gradients = tape.gradient(loss, model.trainable_variables)
optimizer.apply_gradients(zip(gradients, model.trainable_variables))
train_loss(loss)
train_accuracy(labels, predictions)
定義 test_step 函數(shù):
@tf.function
def test_step(images, labels):
predictions = model(images)
t_loss = loss_object(labels, predictions)
test_loss(t_loss)
test_accuracy(labels, predictions)
一般情況下,學(xué)習(xí)率 ( learning rate ) 不適合設(shè)置為常數(shù)。在訓(xùn)練不斷迭代的情況下,常量的學(xué)習(xí)率會導(dǎo)致模型收斂性變差。
在不斷的迭代過程中,損失函數(shù) ( loss ) 越來越小,因此我們希望學(xué)習(xí)率也越來越小,從而能夠讓模型收斂到一個更好的局部最優(yōu)點(diǎn)。
這里我們簡單的讓學(xué)習(xí)率在每 epoch 中都以一定大小遞減。
def lr_fn(epoch, lr):
if epoch == 0:
return 0.001
return lr * 0.9
設(shè)定一個較大的 epoch,我們在模型訓(xùn)練的時候做了 early stop 策略。當(dāng)訓(xùn)練精度小于上一次 epoch 的精度,我們認(rèn)為模型進(jìn)入了過擬合了。
我們會停止訓(xùn)練這個也是一種防止過擬合的策略。
第四步:模型訓(xùn)練
我們在訓(xùn)練中記錄下了每一次 epoch 的訓(xùn)練集和測試集精度的統(tǒng)計(jì)以及學(xué)習(xí)率,為了訓(xùn)練完成后查看訓(xùn)練過程的效果。
我們可以看到的訓(xùn)練結(jié)果:
然后我們把訓(xùn)練中的記錄下來的訓(xùn)練集和測試集的精確度結(jié)果放到圖表中,用以查看我們的訓(xùn)練情況:綠色為測試集曲線,藍(lán)色為訓(xùn)練集曲線。
plt.plot(epoch_range, train_accuracy_total, '-b', label= "training")
plt.plot(epoch_range, test_accuracy_total, '-g', label= "test")
plt.legend()
plt.xlabel('epoch')
plt.ylabel('accuracy')
從圖表中可以看出,在經(jīng)過不斷的 epoch 迭代以后,模型的精度在開始的幾個 epoch 后迅速提升(這表示收斂速度很快)。后面的幾個 epoch 模型的精度曲線趨向于平穩(wěn),收斂速度放緩。
查看學(xué)習(xí)率的遞減情況:
plt.plot(epoch_range, lr_total, '-b', label= "training")
plt.legend()
plt.xlabel('epoch')
plt.ylabel('learning rate')
第五步:探索和優(yōu)化
后續(xù)讀者可以從以下這幾個方面來進(jìn)行嘗試,嘗試提高模型的準(zhǔn)確率。
- 更深的網(wǎng)絡(luò)層次,可以更換模型,比如使用 VGG16,ResNet 等更深的網(wǎng)絡(luò),或者在現(xiàn)有的網(wǎng)絡(luò)中添加更多的卷積層進(jìn)行嘗試
- 更多的訓(xùn)練數(shù)據(jù),數(shù)據(jù)量的增長能極大的提高模型的精度跟泛化能力
- 使用別的優(yōu)化器,比如:adam
- 調(diào)整學(xué)習(xí)率
矩池云現(xiàn)在已經(jīng)全線上架 “機(jī)器圖像識別” 鏡像;
選擇 “ 圖像識別demo ” 鏡像,機(jī)器啟動后,在 JupyterLab 目錄中選擇
digit-recognizer 文件夾,矩池云已經(jīng)將數(shù)據(jù)集和腳本都集成在其中,執(zhí)行其中的 ipynb 文件,即可運(yùn)行上述識別腳本。
審核編輯 黃昊宇
-
人工智能
+關(guān)注
關(guān)注
1791文章
47352瀏覽量
238774 -
人工神經(jīng)網(wǎng)絡(luò)
+關(guān)注
關(guān)注
1文章
119瀏覽量
14635 -
機(jī)器學(xué)習(xí)
+關(guān)注
關(guān)注
66文章
8422瀏覽量
132724 -
python
+關(guān)注
關(guān)注
56文章
4797瀏覽量
84758 -
tensorflow
+關(guān)注
關(guān)注
13文章
329瀏覽量
60537
發(fā)布評論請先 登錄
相關(guān)推薦
評論