一、卷積神經(jīng)網(wǎng)絡(luò)
卷積神經(jīng)網(wǎng)絡(luò)(Convolutional Neural Networks, CNN 是一類包含卷積計算且具有深度結(jié)構(gòu)的前饋神經(jīng)網(wǎng)絡(luò)(Feedforward Neural Networks),是深度學(xué)習(xí)(deep learning)的代表算法之一 。卷積神經(jīng)網(wǎng)絡(luò)具有表征學(xué)習(xí)(representation learning)能力,能夠按其階層結(jié)構(gòu)對輸入信息進(jìn)行平移不變分類(shift-invariant classification),因此也被稱為“平移不變?nèi)斯ど窠?jīng)網(wǎng)絡(luò)(Shift-Invariant Artificial Neural Networks, SIANN)”
卷積神經(jīng)網(wǎng)絡(luò)CNN的結(jié)構(gòu)一般包含這幾個層:
- 輸入層:用于數(shù)據(jù)的輸入
- 卷積層:使用卷積核進(jìn)行特征提取和特征映射
- 激勵層:由于卷積也是一種線性運(yùn)算,因此需要增加非線性映射
- 池化層:進(jìn)行下采樣,對特征圖稀疏處理,減少數(shù)據(jù)運(yùn)算量
- 全連接層:通常在CNN的尾部進(jìn)行重新擬合,減少特征信息的損失
CNN的三個特點:
- 局部連接:這個是最容易想到的,每個神經(jīng)元不再和上一層的所有神經(jīng)元相連,而只和一小部分神經(jīng)元相連。這樣就減少了很多參數(shù)
- 權(quán)值共享:一組連接可以共享同一個權(quán)重,而不是每個連接有一個不同的權(quán)重,這樣又減少了很多參數(shù)。
- 下采樣:可以使用Pooling來減少每層的樣本數(shù),進(jìn)一步減少參數(shù)數(shù)量,同時還可以提升模型的魯棒性。
卷積層:
如圖是33的卷積核(卷積核一般采用33和2*2 )與上一層的結(jié)果(輸入層)進(jìn)行卷積的過程
池化層:
- 在卷積層進(jìn)行特征提取后,輸出的特征圖會被傳遞至池化層進(jìn)行特征選擇和信息過濾。
- 池化層包含預(yù)設(shè)定的池化函數(shù),其功能是將特征圖中單個點的結(jié)果替換為其相鄰區(qū)域的特征圖統(tǒng)計量。
- 池化層選取池化區(qū)域與卷積核掃描特征圖步驟相同,由池化大小、步長和填充控制。
最大池化,它只是輸出在區(qū)域中觀察到的最大輸入值
均值池化,它只是輸出在區(qū)域中觀察到的平均輸入值
兩者最大區(qū)別在于卷積核的不同(池化是一種特殊的卷積過程)。
全連接層:
- 全連接層位于卷積神經(jīng)網(wǎng)絡(luò)隱含層的最后部分,并只向其它全連接層傳遞信號。
- 特征圖在全連接層中會失去空間拓?fù)浣Y(jié)構(gòu),被展開為向量并通過激勵函數(shù)。
- 全連接層的作用則是對提取的特征進(jìn)行非線性組合以得到輸出,即全連接層本身不被期望具有特征提取能力,而是試圖利用現(xiàn)有的高階特征完成學(xué)習(xí)目標(biāo)。
輸出層:
- 卷積神經(jīng)網(wǎng)絡(luò)中輸出層的上游通常是全連接層,因此其結(jié)構(gòu)和工作原理與傳統(tǒng)前饋神經(jīng)網(wǎng)絡(luò)中的輸出層相同。
- 對于圖像分類問題,輸出層使用邏輯函數(shù)或歸一化指數(shù)函數(shù)(softmax function)輸出分類標(biāo)簽。
- 在物體識別(object detection)問題中,輸出層可設(shè)計為輸出物體的中心坐標(biāo)、大小和分類。
- 在圖像語義分割中,輸出層直接輸出每個像素的分類結(jié)果。
二、環(huán)境配置及數(shù)據(jù)集準(zhǔn)備
配置TensorFlow、Keras
打開 cmd 命令終端,創(chuàng)建虛擬環(huán)境。
conda create -n tf1 python=3.6
#tf1是自己為創(chuàng)建虛擬環(huán)境取的名字,后面python的版本可以根據(jù)自己需求進(jìn)行選擇
激活環(huán)境:
activate
conda activate tf1
安裝tensorflow和keras:
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple tensorflow==1.14.0
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple keras==2.2.5
安裝 nb_conda_kernels 包
conda install nb_conda_kernels
數(shù)據(jù)集的下載
kaggle網(wǎng)站的數(shù)據(jù)集下載地址:
https://www.kaggle.com/lizhensheng/-2000
三、貓狗數(shù)據(jù)分類建模
1、貓狗圖像預(yù)處理
代碼如下:
import tensorflow as tf
import keras
import os, shutil
# 原始目錄所在的路徑
original_dataset_dir = 'D:\\Desktop\\Cat_And_Dog\\kaggle\\train\\'
# 數(shù)據(jù)集分類后的目錄
base_dir = 'D:\\Desktop\\Cat_And_Dog\\kaggle\\cats_and_dogs_small'
os.mkdir(base_dir)
# # 訓(xùn)練、驗證、測試數(shù)據(jù)集的目錄
train_dir = os.path.join(base_dir, 'train')
os.mkdir(train_dir)
validation_dir = os.path.join(base_dir, 'validation')
os.mkdir(validation_dir)
test_dir = os.path.join(base_dir, 'test')
os.mkdir(test_dir)
# 貓訓(xùn)練圖片所在目錄
train_cats_dir = os.path.join(train_dir, 'cats')
os.mkdir(train_cats_dir)
# 狗訓(xùn)練圖片所在目錄
train_dogs_dir = os.path.join(train_dir, 'dogs')
os.mkdir(train_dogs_dir)
# 貓驗證圖片所在目錄
validation_cats_dir = os.path.join(validation_dir, 'cats')
os.mkdir(validation_cats_dir)
# 狗驗證數(shù)據(jù)集所在目錄
validation_dogs_dir = os.path.join(validation_dir, 'dogs')
os.mkdir(validation_dogs_dir)
# 貓測試數(shù)據(jù)集所在目錄
test_cats_dir = os.path.join(test_dir, 'cats')
os.mkdir(test_cats_dir)
# 狗測試數(shù)據(jù)集所在目錄
test_dogs_dir = os.path.join(test_dir, 'dogs')
os.mkdir(test_dogs_dir)
# 將前1000張貓圖像復(fù)制到train_cats_dir
fnames = ['cat.{}.jpg'.format(i) for i in range(1000)]
for fname in fnames:
src = os.path.join(original_dataset_dir, fname)
dst = os.path.join(train_cats_dir, fname)
shutil.copyfile(src, dst)
# 將下500張貓圖像復(fù)制到validation_cats_dir
fnames = ['cat.{}.jpg'.format(i) for i in range(1000, 1500)]
for fname in fnames:
src = os.path.join(original_dataset_dir, fname)
dst = os.path.join(validation_cats_dir, fname)
shutil.copyfile(src, dst)
# 將下500張貓圖像復(fù)制到test_cats_dir
fnames = ['cat.{}.jpg'.format(i) for i in range(1500, 2000)]
for fname in fnames:
src = os.path.join(original_dataset_dir, fname)
dst = os.path.join(test_cats_dir, fname)
shutil.copyfile(src, dst)
# 將前1000張狗圖像復(fù)制到train_dogs_dir
fnames = ['dog.{}.jpg'.format(i) for i in range(1000)]
for fname in fnames:
src = os.path.join(original_dataset_dir, fname)
dst = os.path.join(train_dogs_dir, fname)
shutil.copyfile(src, dst)
# 將下500張狗圖像復(fù)制到validation_dogs_dir
fnames = ['dog.{}.jpg'.format(i) for i in range(1000, 1500)]
for fname in fnames:
src = os.path.join(original_dataset_dir, fname)
dst = os.path.join(validation_dogs_dir, fname)
shutil.copyfile(src, dst)
# 將下500張狗圖像復(fù)制到test_dogs_dir
fnames = ['dog.{}.jpg'.format(i) for i in range(1500, 2000)]
for fname in fnames:
src = os.path.join(original_dataset_dir, fname)
dst = os.path.join(test_dogs_dir, fname)
shutil.copyfile(src, dst)
分類前:
分類后:
查看分類后,對應(yīng)目錄下圖片數(shù)量
#輸出數(shù)據(jù)集對應(yīng)目錄下圖片數(shù)量
print('total training cat images:', len(os.listdir(train_cats_dir)))
print('total training dog images:', len(os.listdir(train_dogs_dir)))
print('total validation cat images:', len(os.listdir(validation_cats_dir)))
print('total validation dog images:', len(os.listdir(validation_dogs_dir)))
print('total test cat images:', len(os.listdir(test_cats_dir)))
print('total test dog images:', len(os.listdir(test_dogs_dir)))
2、貓狗分類的實例——基準(zhǔn)模型
1、構(gòu)建網(wǎng)絡(luò)模型
#網(wǎng)絡(luò)模型構(gòu)建
from keras import layers
from keras import models
#keras的序貫?zāi)P?/span>
model = models.Sequential()
#卷積層,卷積核是3*3,激活函數(shù)relu
model.add(layers.Conv2D(32, (3, 3), activation='relu',
input_shape=(150, 150, 3)))
#最大池化層
model.add(layers.MaxPooling2D((2, 2)))
#卷積層,卷積核2*2,激活函數(shù)relu
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
#最大池化層
model.add(layers.MaxPooling2D((2, 2)))
#卷積層,卷積核是3*3,激活函數(shù)relu
model.add(layers.Conv2D(128, (3, 3), activation='relu'))
#最大池化層
model.add(layers.MaxPooling2D((2, 2)))
#卷積層,卷積核是3*3,激活函數(shù)relu
model.add(layers.Conv2D(128, (3, 3), activation='relu'))
#最大池化層
model.add(layers.MaxPooling2D((2, 2)))
#flatten層,用于將多維的輸入一維化,用于卷積層和全連接層的過渡
model.add(layers.Flatten())
#全連接,激活函數(shù)relu
model.add(layers.Dense(512, activation='relu'))
#全連接,激活函數(shù)sigmoid
model.add(layers.Dense(1, activation='sigmoid'))
查看模型各層的參數(shù)狀況
#輸出模型各層的參數(shù)狀況
model.summary()
2、配置訓(xùn)練方法
model.compile(optimizer = 優(yōu)化器,
loss = 損失函數(shù),
metrics = ["準(zhǔn)確率”])
其中,優(yōu)化器和損失函數(shù)可以是字符串形式的名字,也可以是函數(shù)形式。
from keras import optimizers
model.compile(loss='binary_crossentropy',
optimizer=optimizers.RMSprop(lr=1e-4),
metrics=['acc'])
3、文件中圖像轉(zhuǎn)換成所需格式
將訓(xùn)練和驗證的圖片,調(diào)整為150*150
from keras.preprocessing.image import ImageDataGenerator
# 所有圖像將按1/255重新縮放
train_datagen = ImageDataGenerator(rescale=1./255)
test_datagen = ImageDataGenerator(rescale=1./255)
train_generator = train_datagen.flow_from_directory(
# 這是目標(biāo)目錄
train_dir,
# 所有圖像將調(diào)整為150x150
target_size=(150, 150),
batch_size=20,
# 因為我們使用二元交叉熵?fù)p失,我們需要二元標(biāo)簽
class_mode='binary')
validation_generator = test_datagen.flow_from_directory(
validation_dir,
target_size=(150, 150),
batch_size=20,
class_mode='binary')
查看處理結(jié)果
#查看上面對于圖片預(yù)處理的處理結(jié)果
for data_batch, labels_batch in train_generator:
print('data batch shape:', data_batch.shape)
print('labels batch shape:', labels_batch.shape)
break
4、模型訓(xùn)練并保存生成的模型
#模型訓(xùn)練過程
history = model.fit_generator(
train_generator,
steps_per_epoch=100,
epochs=30,
validation_data=validation_generator,
validation_steps=50)
#保存訓(xùn)練得到的的模型
model.save('D:\\Desktop\\Cat_And_Dog\\kaggle\\cats_and_dogs_small_1.h5')
5、結(jié)果可視化
#對于模型進(jìn)行評估,查看預(yù)測的準(zhǔn)確性
import matplotlib.pyplot as plt
acc = history.history['acc']
val_acc = history.history['val_acc']
loss = history.history['loss']
val_loss = history.history['val_loss']
epochs = range(len(acc))
plt.plot(epochs, acc, 'bo', label='Training acc')
plt.plot(epochs, val_acc, 'b', label='Validation acc')
plt.title('Training and validation accuracy')
plt.legend()
plt.figure()
plt.plot(epochs, loss, 'bo', label='Training loss')
plt.plot(epochs, val_loss, 'b', label='Validation loss')
plt.title('Training and validation loss')
plt.legend()
plt.show()
由可視化結(jié)果,可以發(fā)現(xiàn)訓(xùn)練的loss是成上升趨勢,模型過擬合。
過擬合:
過擬合(overfitting)是指模型在訓(xùn)練集上表現(xiàn)很好,但在測試集或未見過的數(shù)據(jù)上表現(xiàn)較差的情況。
過擬合的原因可能包括:
- 模型復(fù)雜度過高:過于復(fù)雜的模型可以靈活地適應(yīng)訓(xùn)練數(shù)據(jù)中的噪聲和異常,但泛化能力較差。
- 數(shù)據(jù)噪聲:訓(xùn)練集中存在大量噪聲或異常值,導(dǎo)致模型過度擬合這些不代表真實規(guī)律的數(shù)據(jù)。
- 數(shù)據(jù)量過少:當(dāng)訓(xùn)練集的樣本數(shù)量較少時,模型容易記憶住訓(xùn)練數(shù)據(jù)的細(xì)節(jié)而無法泛化到新樣本。
避免過擬合的方法包括:
- 簡化模型:降低模型的復(fù)雜度,減少模型的參數(shù)量,限制模型的學(xué)習(xí)能力。
- 數(shù)據(jù)清洗:去除異常值和噪聲,確保訓(xùn)練數(shù)據(jù)的質(zhì)量。
- 數(shù)據(jù)增強(qiáng):通過旋轉(zhuǎn)、縮放、平移等方式擴(kuò)充訓(xùn)練數(shù)據(jù),增加樣本的多樣性。
- 正則化技術(shù):如L1、L2正則化,通過對模型參數(shù)的約束,減小模型的過擬合風(fēng)險。
- 交叉驗證:使用交叉驗證來評估模型在不同數(shù)據(jù)集上的性能,選擇表現(xiàn)最好的模型。
數(shù)據(jù)增強(qiáng):
數(shù)據(jù)增強(qiáng)是在機(jī)器學(xué)習(xí)和深度學(xué)習(xí)中一種常用的技術(shù),用于擴(kuò)充訓(xùn)練數(shù)據(jù)集的大小和多樣性。通過對原始數(shù)據(jù)進(jìn)行一系列的隨機(jī)變換和合成操作,可以生成與原始數(shù)據(jù)具有相似特征但又稍有差異的新樣本。數(shù)據(jù)增強(qiáng)的目的在于提高模型的魯棒性和泛化能力,減少過擬合現(xiàn)象。通過引入更多的變化和多樣性,模型可以更好地學(xué)習(xí)到數(shù)據(jù)的各種特征和變化模式,從而提高其在真實世界中的適應(yīng)能力。
常見的數(shù)據(jù)增強(qiáng)技術(shù)包括但不限于以下幾種:
- 隨機(jī)翻轉(zhuǎn):例如圖像的水平或垂直翻轉(zhuǎn),可以擴(kuò)充數(shù)據(jù)集,并對模型具有平移不變性的任務(wù)(如物體識別)有幫助。
- 隨機(jī)裁剪和縮放:通過隨機(jī)裁剪和縮放圖像,可以模擬不同的尺度和視角,增加數(shù)據(jù)的多樣性,并改善模型對于目標(biāo)的檢測和識別能力。
- 隨機(jī)旋轉(zhuǎn)和仿射變換:對于圖像數(shù)據(jù),進(jìn)行隨機(jī)旋轉(zhuǎn)、平移、縮放和傾斜等仿射變換,可以增加數(shù)據(jù)的多樣性,提高模型對于旋轉(zhuǎn)、平移和形變等變化的魯棒性。
- 增加噪聲:向數(shù)據(jù)中添加隨機(jī)噪聲,如高斯噪聲、椒鹽噪聲等,可以提高模型對于噪聲環(huán)境下的穩(wěn)定性和魯棒性。
- 數(shù)據(jù)mixup:將兩個或多個不同的樣本進(jìn)行線性組合,生成新的樣本。這樣可以使得模型對于不同類別之間的邊界更加清晰,從而提高泛化性能。
3、基準(zhǔn)模型的調(diào)整
1、圖像增強(qiáng)
利用圖像生成器定義一些常見的圖像變換,圖像增強(qiáng)就是通過對于圖像進(jìn)行變換,從而,增強(qiáng)圖像中的有用信息。
#該部分代碼及以后的代碼,用于替代基準(zhǔn)模型中分類后面的代碼(執(zhí)行代碼前,需要先將之前分類的目錄刪掉,重寫生成分類,否則,會發(fā)生錯誤)
from keras.preprocessing.image import ImageDataGenerator
datagen = ImageDataGenerator(
rotation_range=40,
width_shift_range=0.2,
height_shift_range=0.2,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True,
fill_mode='nearest')
①rotation_range
一個角度值(0-180),在這個范圍內(nèi)可以隨機(jī)旋轉(zhuǎn)圖片
②width_shift和height_shift
范圍(作為總寬度或高度的一部分),在其中可以隨機(jī)地垂直或水平地轉(zhuǎn)換圖片
③shear_range
用于隨機(jī)應(yīng)用剪切轉(zhuǎn)換
④zoom_range
用于在圖片內(nèi)部隨機(jī)縮放
⑤horizontal_flip
用于水平隨機(jī)翻轉(zhuǎn)一半的圖像——當(dāng)沒有假設(shè)水平不對稱時(例如真實世界的圖片)
⑥fill_mode
用于填充新創(chuàng)建像素的策略,它可以在旋轉(zhuǎn)或?qū)挾?高度移動之后出現(xiàn)
2、查看增強(qiáng)后的圖像
import matplotlib.pyplot as plt
# This is module with image preprocessing utilities
from keras.preprocessing import image
fnames = [os.path.join(train_cats_dir, fname) for fname in os.listdir(train_cats_dir)]
# We pick one image to "augment"
img_path = fnames[3]
# Read the image and resize it
img = image.load_img(img_path, target_size=(150, 150))
# Convert it to a Numpy array with shape (150, 150, 3)
x = image.img_to_array(img)
# Reshape it to (1, 150, 150, 3)
x = x.reshape((1,) + x.shape)
# The .flow() command below generates batches of randomly transformed images.
# It will loop indefinitely, so we need to `break` the loop at some point!
i = 0
for batch in datagen.flow(x, batch_size=1):
plt.figure(i)
imgplot = plt.imshow(image.array_to_img(batch[0]))
i += 1
if i % 4 == 0:
break
plt.show()
3、網(wǎng)絡(luò)模型增加一層dropout
#網(wǎng)絡(luò)模型構(gòu)建
from keras import layers
from keras import models
#keras的序貫?zāi)P?/span>
model = models.Sequential()
#卷積層,卷積核是3*3,激活函數(shù)relu
model.add(layers.Conv2D(32, (3, 3), activation='relu',
input_shape=(150, 150, 3)))
#最大池化層
model.add(layers.MaxPooling2D((2, 2)))
#卷積層,卷積核2*2,激活函數(shù)relu
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
#最大池化層
model.add(layers.MaxPooling2D((2, 2)))
#卷積層,卷積核是3*3,激活函數(shù)relu
model.add(layers.Conv2D(128, (3, 3), activation='relu'))
#最大池化層
model.add(layers.MaxPooling2D((2, 2)))
#卷積層,卷積核是3*3,激活函數(shù)relu
model.add(layers.Conv2D(128, (3, 3), activation='relu'))
#最大池化層
model.add(layers.MaxPooling2D((2, 2)))
#flatten層,用于將多維的輸入一維化,用于卷積層和全連接層的過渡
model.add(layers.Flatten())
#退出層
model.add(layers.Dropout(0.5))
#全連接,激活函數(shù)relu
model.add(layers.Dense(512, activation='relu'))
#全連接,激活函數(shù)sigmoid
model.add(layers.Dense(1, activation='sigmoid'))
#輸出模型各層的參數(shù)狀況
model.summary()
from keras import optimizers
model.compile(loss='binary_crossentropy',
optimizer=optimizers.RMSprop(lr=1e-4),
metrics=['acc'])
添加dropout后的網(wǎng)絡(luò)結(jié)構(gòu)
4、訓(xùn)練模型
train_datagen = ImageDataGenerator(
rescale=1./255,
rotation_range=40,
width_shift_range=0.2,
height_shift_range=0.2,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True,)
# Note that the validation data should not be augmented!
test_datagen = ImageDataGenerator(rescale=1./255)
train_generator = train_datagen.flow_from_directory(
# This is the target directory
train_dir,
# All images will be resized to 150x150
target_size=(150, 150),
batch_size=32,
# Since we use binary_crossentropy loss, we need binary labels
class_mode='binary')
validation_generator = test_datagen.flow_from_directory(
validation_dir,
target_size=(150, 150),
batch_size=32,
class_mode='binary')
history = model.fit_generator(
train_generator,
steps_per_epoch=100,
epochs=100,
validation_data=validation_generator,
validation_steps=50)
model.save('D:\\Desktop\\Cat_And_Dog\\kaggle\\cats_and_dogs_small_2.h5')
5、結(jié)果可視化
acc = history.history['acc']
val_acc = history.history['val_acc']
loss = history.history['loss']
val_loss = history.history['val_loss']
epochs = range(len(acc))
plt.plot(epochs, acc, 'bo', label='Training acc')
plt.plot(epochs, val_acc, 'b', label='Validation acc')
plt.title('Training and validation accuracy')
plt.legend()
plt.figure()
plt.plot(epochs, loss, 'bo', label='Training loss')
plt.plot(epochs, val_loss, 'b', label='Validation loss')
plt.title('Training and validation loss')
plt.legend()
plt.show()
可以發(fā)現(xiàn)訓(xùn)練曲線更加緊密地跟蹤驗證曲線,波動的幅度也降低了些,訓(xùn)練效果更好了。
總結(jié)
通過使用TensorFlow和Keras搭建卷積神經(jīng)網(wǎng)絡(luò)完成狗貓數(shù)據(jù)集的分類實驗,我深刻理解到了數(shù)據(jù)預(yù)處理、模型設(shè)計和超參數(shù)選擇對于模型性能的重要影響。這個實驗為我進(jìn)一步深入學(xué)習(xí)和應(yīng)用深度學(xué)習(xí)提供了寶貴的經(jīng)驗和啟示。文章來源:http://www.zghlxwxcb.cn/news/detail-529159.html
參考鏈接
【TensorFlow&Keras】入門貓狗數(shù)據(jù)集實驗–理解卷積神經(jīng)網(wǎng)絡(luò)CNN
基于Tensorflow和Keras實現(xiàn)卷積神經(jīng)網(wǎng)絡(luò)CNN文章來源地址http://www.zghlxwxcb.cn/news/detail-529159.html
到了這里,關(guān)于基于卷積神經(jīng)網(wǎng)絡(luò)的目標(biāo)分類案例的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!