深度學習筆記04-使用CNN進行天氣圖片識別(Tensorflow)

前言

一、我的環境

二、準備套件

三、GPU設置

四、導入數據

五、查看數據

六、數據預處理

七、可視化數據

八、配置數據集

九、建構CNN網路

十、編譯模型

十一、訓練模型

十二、模型評估

十三、預測

十四、總結


前言


一、我的環境

  • 電腦系統:Windows 10

  • 顯卡:NVIDIA Quadro P620

  • 語言環境:Python 3.7.0

  • 開發工具:Sublime Text,Command Line(CMD)

  • 深度學習環境:Tensorflow 2.5.0


二、準備套件

# 提供一些與操作系統交互的功能,例如文件路徑操作等
import os

# 用於圖像處理,例如打開、操作、保存圖像
import PIL

# 用於處理文件路徑的模塊,提供一種更加直觀和面向對象的操作文件路徑方式
import pathlib

# 用於繪圖,可以創建各種類型的圖表和圖形
import matplotlib.pyplot as plt

# 數值計算庫,用於處理大型多維數組和矩陣的
import numpy as np

# 開源的機器學習框架
import tensorflow as tf

# 導入 keras 模塊,為 tensorflow 的高級 API 之一,操作起來更加簡單、易用
from tensorflow import keras

# keras.layers,tensorflow 的子模塊,包含建構神經網路模型所需的各種層
# keras.models,tensorflow 的子模塊,包含建構神經網路模型的類和函數
from tensorflow.keras import layers,models

三、GPU設置

# 列出系統中的GPU裝置列表
gpus = tf.config.list_physical_devices("GPU")

# 如果有GPU
if gpus:
    # 挑選第一個 GPU
    gpu0 = gpus[0] 
    # 僅在需要的時候分配記憶體
    tf.config.experimental.set_memory_growth(gpu0, True)
    # 將 GPU0 設置為 TensorFlow 中可見的唯一 GPU ,將運算限制在特定的 GPU 上 
    tf.config.set_visible_devices([gpu0],"GPU") 

四、導入數據

# 設定數據目錄的相對路徑,也可以使用絕對路徑
# D:/AI/ai_note/weather_photos,這邊要注意斜線的方向
data_dir = "weather_photos/"
# 將路徑轉換成 pathlib.Path 對象,更易操作
data_dir = pathlib.Path(data_dir)

五、查看數據

數據集共分為四類,分別為 cloudy、rain、shine、sunrise

# 使用 glob 方法獲取指定目錄下所有以 '.jpg' 為副檔名的文件迭代器
# '*/*.jpg' 是一個通配符模式,表示所有直接位於子目錄中的以 .jpg 結尾的文件
# 第一個星號表示所有目錄
# 第二個星號表示所有檔名
image_count = len(list(data_dir.glob('*/*.jpg')))

# 印出圖片數量
print("圖片總數:",image_count)

共 1125 張 

 用程式來開看看圖片

# 使用 glob 方法獲得所有 sunrise 目錄下的以 .jpg 為副檔名的文件迭代器
sunrise = list(data_dir.glob('sunrise/*.jpg'))
# 使用 PIL 庫的 Image 模塊打開 sunrise 文件中的第一張圖
img = PIL.Image.open(str(sunrise[0]))
# 使用 matplotlib.pyplot 庫的 imshow() 函數顯示圖片,img 是已經打開的圖片對象
plt.imshow(img)
# 關閉座標軸,即不顯示座標軸
plt.axis('off')
# 顯示圖片
plt.show()


六、數據預處理

# 設置批量大小,即每次訓練模型時輸入到模型中的圖像數量
# 在每次訓練迭代時,模型將同時處理32張圖像
# 批量大小的選擇會影響訓練速度和內存需求
batch_size = 32
# 圖像的高度,在加載圖像數據時,將所有的圖像調整為相同的高度,這裡設定為 180 像素
img_height = 180
# 圖像的寬度,在加載圖像數據時,將所有的圖像調整為相同的寬度,這裡設定為 180 像素
img_width = 180

# 創建訓練集
# 使用 tf.keras.preprocessing.image_dataset_from_directory 函數從目錄中創建一個圖像數據集
# 會得到一個 tf.data.Dataset 對象,其中包含指定目錄中圖像的數據集,以及相應的標籤
# 返回的這個數據集可以直接用於模型的訓練和驗證
train_ds = tf.keras.preprocessing.image_dataset_from_directory(
    data_dir,	# 指定包含圖像的目錄路徑
    validation_split=0.2,	# 用來指定數據集中分割出多少比例數據當作驗證集,0.2 表示 20% 數據會被用來當驗證集
    subset="training",	# 指定是用於訓練還是驗證的數據子集,這裡設定為 training ,表示創建的是訓練數據集
    seed=123,	# 設定亂數種子,確保每次運行程式碼時得到的數據集都是相同的,以保持實驗的可重複性
    image_size=(img_height, img_width),	# 指定圖像的大小
    batch_size=batch_size) # 指定每個批次中包含的圖像樣本數量

# 創建驗證集
val_ds = tf.keras.preprocessing.image_dataset_from_directory(
    data_dir,
    validation_split=0.2,
    subset="validation",	# 指定是用於訓練還是驗證的數據子集,這裡設定為 validation ,表示創建的是驗證集
    seed=123,
    image_size=(img_height, img_width),
    batch_size=batch_size)

# class_names 是一個包含數據集中所有類別名稱的列表
class_names = train_ds.class_names
# 印出類別
print(class_names)


七、可視化數據

# 創建一個圖形對象,設置圖形大小寬度 20 英寸、高度 10 英寸
plt.figure(figsize=(20, 10))

# train_ds.take(1) 從訓練集中取出一個批次(batch)的數據
# 遍歷訓練數據集的第一個批次(batch)中的每張圖片
# images 是一個包含圖片數據的張量
# labels 是一個包含對應標籤的張量
for images, labels in train_ds.take(1):
	# 遍歷當前批次(batch)的前 20 張圖
    for i in range(20):
    	# 創建一個子圖,將圖形劃分成 5 行 10 列,當前子圖的索引為 i+1
        ax = plt.subplot(5, 10, i + 1)

        # 顯示第 i 張圖片
        # images[i] 是一個張量,使用 .numpy() 方法將其轉換為 NumPy 數組,
        # 使用 .astype("uint8") 方法將其轉換為無符號整型 8 位整數類型
        plt.imshow(images[i].numpy().astype("uint8"))

        # 設置當前子圖的標題為當前圖片的類別名稱
        # labels[i] 是當前圖片對應的標籤,通過索引 class_names 列表獲取對應的類別名稱 
        plt.title(class_names[labels[i]])
        
        # 關閉座標軸的顯示
        plt.axis("off")
# 顯示圖片
plt.show()

# 從 train_ds 中迭代獲取一個批次(batch)的圖像數據和標籤數據,印出他們的形狀
for image_batch, labels_batch in train_ds:
    print(image_batch.shape)
    print(labels_batch.shape)
    break  # 只印一批次(batch)即可

 (32, 180, 180, 3)  :印出當前批次 ( batch ) 的圖像數據的形狀,image_batch 是一個張量,.shape 屬性表示該張量的形狀,即每個維度的大小

(32,)  :印出當前批次 ( batch ) 的標籤數據的形狀,labels_batch 是一個張量,.shape 屬性表示該張量的形狀,即每個維度的大小 


八、配置數據集

# AUTOTUNE 表示自動調整緩衝區大小以優化性能
AUTOTUNE = tf.data.AUTOTUNE

# 使用 cache() 方法將訓練集緩存到內存中,這樣可以加快數據加載速度
# 當模型多次迭代訓練數據集時,可以重複使用已經加載到內存中的數據,而不必重新從磁盤加載
# 使用 shuffle() 方法對訓練數據集進行洗牌操作,打亂數據集中的樣本順序
# 參數 1000 指定了洗牌時使用的緩衝區大小,即每次從數據集中隨機選擇的樣本數量
# 通過洗牌操作,可以增加模型的訓練效果,使模型更好的學習數據的分布
# 使用 prefetch() 方法預取數據,以便在訓練過程中盡可能的減少數據加載時間
# 此方法可以在訓練模型的同時異步加載數據,從而提高 GPU 的利用率,減少數據加載造成的訓練時間損失
train_ds = train_ds.cache().shuffle(1000).prefetch(buffer_size=AUTOTUNE)

# 對驗證集進行和訓練集相同的緩存操作
val_ds = val_ds.cache().prefetch(buffer_size=AUTOTUNE)

九、建構CNN網路

卷積神經網絡(Convolutional Neural Network,CNN)是一種用於圖像識別和處理的深度學習模型

在CNN中,輸入數據通常是張量(Tensor)形式的,具體來說,輸入張量的形狀為(image_height,image_width,color_channels)

  • image_height:表示圖像的高度,即圖像在垂直方向上的像素數量
  • image_width:表示圖像的寬度,即圖像在水平方向上的像素數量
  • color_channels:表示圖像的顏色通道數,即圖像在每個像素點上包含的顏色信息的維度,通常情況下,彩色圖像有三個顏色通道,分別對應於紅色(R)、綠色(G)和藍色(B),因此 color_channels 為 3

CNN的輸入張量表示了圖像的結構和顏色信息,其中每個像素點都被表示為具有 color_channels 個數值的向量,在訓練過程中,CNN會通過一系列的卷積層、池化層和全連接層等操作來提取圖像的特徵,並最終輸出對圖像進行分類、識別或其他任務的結果

# 表示模型的輸出類別數量為 4 ,在這種情況下,模型的輸出層具有4個神經元,每個神經元對應一個類別
num_classes = 4

# 創建一個序列模型,這是一種線性堆疊模型,其中各個層按照他們被添加到模型中的順序來堆疊
model = models.Sequential([
	# 創建了一個對圖像進行重新縮放的預處理層
	# 將每個像素的數值除以 255,將像素值縮放到範圍 [0,1],即歸一化
	# 輸入的 img_height 和 img_width 分別表示圖像的高度和寬度,3 表示圖像的通道數,通常為 RGB 彩色圖像
    layers.experimental.preprocessing.Rescaling(1./255, input_shape=(img_height, img_width, 3)),
    
    # 創建一個卷積層
    # 16:表示該卷積層使用了 16 個卷積核
    # (3, 3):指定了每個卷積核的大小為 3x3
    # 使用ReLU(Rectified Linear Unit)作為激活函數,它是一種常用的非線性函數,能夠使模型具有更好的學習能力
    # 設置輸入形狀為(img_height, img_width, 3)
    # 表示輸入圖像的高度為img_height像素,寬度為img_width像素,通道數為3(RGB 彩色圖像)
    # 這個參數只需要在模型的第一層中指定,後續的層將自動推斷輸入形狀
    layers.Conv2D(16, (3, 3), activation='relu', input_shape=(img_height, img_width, 3)),
    # 創建一個平均池化層
    # 將原始特徵圖中的每個 2x2 區域的數值取平均,從而實現尺寸的縮小和特徵的抽取
    # (2, 2):指定了池化窗口的大小為 2x2 ,即將原始特徵圖劃分為 2x2 的子區域
    # 這個池化操作對每個子區域內的數值進行平均,得到新的特徵圖
    layers.AveragePooling2D((2, 2)), 
    # 創建第二個卷積層
    # 32 個卷積核
    # 每個卷積核的大小是 3x3
    # 本層沒有指定輸入形狀(input_shape),因為這是模型中的中間層,將繼承前一層的輸出形狀作為輸入形狀
    layers.Conv2D(32, (3, 3), activation='relu'),  
    # 創建第二個平均池化層
    # 作用是對輸入的特徵圖進行下採樣,以減少特徵圖的空間尺寸,同時保留主要的特徵
    # 指定池化窗口的大小為 2x2 ,這意味著對於每個 2x2 的區域,將計算其內像素的平均值作為輸出
    layers.AveragePooling2D((2, 2)),
	# 創建第三個卷積層
    # 64個卷積核
    # 每個卷積核的大小為 3x3
    layers.Conv2D(64, (3, 3), activation='relu'),  
    # 隨機失活層
    # 在模型訓練過程中以指定的概率丟棄(關閉)一定比例的神經元,以防止過擬合
    # 0.3 表示丟棄的神經元概率為 30%
    # 意味著每次訓練迭代中,有 30% 的神經元會被隨機丟棄,以防止模型過度擬合訓練數據
    layers.Dropout(0.3),                        
    # 展平層
    # 將多維輸入數據平坦化成一維數組
    # 將多維輸入數據(如卷積層的輸出)展平成一個一維數組,以便將其餵入全連接層
    layers.Flatten(),    
    # 全連接層
    # 包含 128 個神經元
    # 使用 ReLU 激活函數
    # 用於將之前卷積層和池化層提取的特徵進一步轉換和提取               
    layers.Dense(128, activation='relu'), 
    # 輸出層
    # 包含了 num_classes 個神經元
    # 其數量通常等於分類問題中的類別數量
    # 這一層的激活函數通常沒有指定,因為它用於輸出每個類別的原始分數或概率值
    layers.Dense(num_classes) 
])

# 印出模型結構
model.summary()


十、編譯模型

# 編譯模型的函數
# 編譯模型前要先進行配置,包括優化器(optimizer)、損失函數(loss function)、評估指標(metrics)
# 創建了一個 Adam 優化器的實例,設置了學習率為 0.001
# Adam 優化器是一種常用的梯度下降優化算法,用於更新模型的權重以最小化訓練過程中的損失函數
opt = tf.keras.optimizers.Adam(learning_rate=0.001)
# 設置了模型的優化器、損失函數和評估指標
# 優化器使用了上面定義的 Adam 優化器
# 損失函數使用了稀疏分類交叉熵(SparseCategoricalCrossentropy)
# from_logits=True ,表示模型的輸出是未經過 softmax 轉換的原始分數或概率值
# 評估指標指定了準確率(accuracy),用於在訓練過程中監控模型的性能
model.compile(optimizer=opt,
    loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
    metrics=['accuracy'])

十一、訓練模型

# 指定訓練過程中的迭代次數,即訓練模型的輪數
epochs = 10
# 使用 fit 方法開始訓練模型
# 訓練過程中的歷史記錄將保存在 history 變量中,可用於後續分析和可視化
history = model.fit(
    train_ds,   # 訓練集
    validation_data=val_ds, # 驗證集
    epochs=epochs   # 指定訓練的迭代次數
)


十二、模型評估

# 從訓練歷史中提取準確率
# acc 是訓練集準確率
# val_acc 是驗證集準確率
acc = history.history['accuracy']
val_acc = history.history['val_accuracy']

# 從訓練歷史中提取損失
# loss 是訓練集損失
# val_loss 是驗證集損失
loss = history.history['loss']
val_loss = history.history['val_loss']

# 定義了迭代次數範圍
epochs_range = range(epochs)

# 創建一個新的圖形,指定圖形的大小
plt.figure(figsize=(12, 4))
# 在圖形中創建 1 行 2 列的子圖,並選擇第一個子圖
plt.subplot(1, 2, 1)
# 繪製訓練集準確率隨迭代次數變化的曲線
plt.plot(epochs_range, acc, label='Training Accuracy')
# 繪製驗證集準確率隨迭代次數變化的曲線
plt.plot(epochs_range, val_acc, label='Validation Accuracy')
# 添加圖例,位置位於右下角
plt.legend(loc='lower right')
# 添加子圖的標題
plt.title('Training and Validation Accuracy')

# 在圖形中創建 1 行 2 列的子圖,並選擇第二個子圖
plt.subplot(1, 2, 2)
# 繪製訓練集損失函數的曲線
plt.plot(epochs_range, loss, label='Training Loss')
# 繪製驗證集損失函數的曲線
plt.plot(epochs_range, val_loss, label='Validation Loss')
# 添加圖例,位置位於右上角
plt.legend(loc='upper right')
# 添加子圖的標題
plt.title('Training and Validation Loss')

# 顯示圖片
plt.show()

  1. 準確率曲線(左側):

    • 顯示準確率隨著訓練輪數的變化情況
    • 曲線上升代表模型在訓練過程中的準確率提高,即模型更好地擬合了訓練數據
    • 藍色曲線表示訓練集的準確率,橙色曲線表示驗證集的準確率
    • 如果訓練集和驗證集的準確率都在增加,則表示模型沒有過擬合,並且在訓練和驗證數據上均取得了良好的表現
  2. 損失函數曲線(右側):

    • 顯示損失函數隨著訓練輪數的變化情況
    • 曲線下降代表模型在訓練過程中的損失函數下降,即模型更好地擬合了訓練數據
    • 藍色曲線表示訓練集的損失函數,橙色曲線表示驗證集的損失函數
    • 如果訓練集和驗證集的損失函數都在下降,則表示模型在訓練和驗證數據上均取得了良好的表現

十三、預測

# 創建一個新的圖形
plt.figure(figsize=(6, 4))
# 從驗證集中取出一個批次的資料
for images, labels in val_ds.take(1):
    # 顯示該批次的第一張圖片
    plt.imshow(images[0].numpy().astype("uint8"))
    # 顯示標籤
    plt.title(class_names[labels[0].numpy()])
    plt.axis("off")
    plt.show()

# 從驗證集中取出同一個批次的第一筆資料做預測
for images, labels in val_ds.take(1):
    # 預測
    predictions = model.predict(images)
    # 取出第一張圖片的預測結果
    prediction = predictions[0]
    # 輸出預測結果
    print("預測結果:", prediction)

預測結果:表示圖片可能是 cloudy、rain、shine、sunrise 中哪一類的機率,數字越大可能性越大,這裡是第三個值最大,所以可以判定該張圖片是 shine 類別,正確!


十四、總結

在本次深度學習項目中,使用了CNN(卷積神經網路)模型對天氣照片進行分類

以下是本次實作的總結:

  1. 數據準備與預處理:從給定的數據集中導入圖像數據,並進行了數據預處理,包括對圖像進行重新縮放、劃分訓練集和驗證集等操作,以確保模型訓練的準確性和效率
  2. 模型建構:構建一個CNN模型,包括多個卷積層、池化層、全連接層和隨機失活層,以提取圖像的特徵並進行分類
  3. 模型訓練與評估:使用訓練集對模型進行了訓練,並在驗證集上進行了評估,通過監控訓練過程中的損失函數和準確率,確保了模型的訓練效果
  4. 模型評估與預測:使用測試集對訓練好的模型進行了評估,並計算了模型在測試集上的準確率,同時,還對一些測試樣本進行了預測,觀察模型的預測效果
  5. 結果分析與優化:通過對模型在不同參數設置下的表現進行分析,可以進一步優化模型,提高其準確性和泛化能力

本次項目幫助我深入理解了CNN模型的構建與訓練過程,並對深度學習在圖像分類任務中的應用有了更深入的了解

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值