1. 程式人生 > 其它 >tensorflow學習022——自定義訓練綜合貓狗資料例項訓練

tensorflow學習022——自定義訓練綜合貓狗資料例項訓練

點選檢視程式碼
import tensorflow as tf
from tensorflow import keras
import matplotlib.pyplot as plt
import numpy as np
import glob
import os

# 資料讀取
# print(os.path.exists(r"E:\WORK\tensorflow\dataset\dc\train"))
train_image_path = glob.glob(r'E:\WORK\tensorflow\dataset\dc_2000\train\*\*.jpg')
print(train_image_path[:5])
train_image_label = [int(p.split('\\')[-2] == 'cat') for p in train_image_path]  # 狗0 貓1
print(train_image_label[:5])
def load_preprosess_image(path, label):
    image = tf.io.read_file(path)  # 讀取圖片檔案
    image = tf.image.decode_jpeg(image,channels=3)  # 對圖片進行解碼
    image = tf.image.resize(image, [256,256])  # 將圖片縮放到統一大小
    image = tf.cast(image,tf.float32)  # 更改資料型別,模型圖片的資料元素型別為uint8
    image = image / 255  # 歸一化
    label = tf.reshape(label, [1])  # 將[0,1,0] 轉換為[[0],[1],[0]]格式
    return image, label

# 建立dataset
train_image_ds = tf.data.Dataset.from_tensor_slices((train_image_path,train_image_label))
AUTOTUNE = tf.data.experimental.AUTOTUNE
train_image_ds = train_image_ds.map(load_preprosess_image,num_parallel_calls=AUTOTUNE)
BATVH_SIZE = 32
train_count = len(train_image_path)
train_image_ds = train_image_ds.shuffle(train_count).batch(BATVH_SIZE)
train_image_ds = train_image_ds.prefetch(AUTOTUNE)  # 當訓練一部分資料的時候,會在後臺提前讀取一部分資料

# 建立模型
# model = keras.Sequential([
#     tf.keras.layers.Conv2D(64,(3,3),input_shape=(256,256,3)),
#     tf.keras.layers.BatchNormalization(), # 批標準化,可以用於防止過擬合,使得網路可以建的更深,有正則化的效果
#     tf.keras.layers.Activation('relu'),
#     tf.keras.layers.MaxPooling2D(),
#     tf.keras.layers.Conv2D(128,(3,3)),
#     tf.keras.layers.BatchNormalization(),
#     tf.keras.layers.Activation('relu'),
#     tf.keras.layers.MaxPooling2D(),
#     tf.keras.layers.Conv2D(256, (3, 3)),
#     tf.keras.layers.BatchNormalization(),
#     tf.keras.layers.Activation('relu'),
#     tf.keras.layers.MaxPooling2D(),
#     tf.keras.layers.Conv2D(512, (3, 3)),
#     tf.keras.layers.BatchNormalization(),
#     tf.keras.layers.Activation('relu'),
#     tf.keras.layers.MaxPooling2D(),
#     tf.keras.layers.Conv2D(1024, (3, 3)),
#     tf.keras.layers.BatchNormalization(),
#     tf.keras.layers.Activation('relu'),
#     tf.keras.layers.GlobalAveragePooling2D(),  # 再得到的(12,12)上兩維進行求平均值得到一個值
#     tf.keras.layers.Dense(1024),
#     tf.keras.layers.BatchNormalization(),
#     tf.keras.layers.Activation('relu'),
#     tf.keras.layers.Dense(256),
#     tf.keras.layers.BatchNormalization(),
#     tf.keras.layers.Activation('relu'),
#     tf.keras.layers.Dense(1)  # 這裡可以不寫啟用函式,因為對於二分類問題而言,不啟用的畫最後認為輸出結果大於0使一種結果,小於0使一種結果,啟用的畫只是進行歸一化
#     # np.array[p[0].numpy() for p in tf.cast(pred>0,tf.int32)]  就可以將最後的結果轉換為0 1格式
# ])

model = keras.Sequential([
    tf.keras.layers.Conv2D(64,(3,3),input_shape=(256,256,3)),

    tf.keras.layers.Activation('relu'),
    tf.keras.layers.MaxPooling2D(),
    tf.keras.layers.Conv2D(128,(3,3)),

    tf.keras.layers.Activation('relu'),
    tf.keras.layers.MaxPooling2D(),
    tf.keras.layers.Conv2D(256, (3, 3)),

    tf.keras.layers.Activation('relu'),
    tf.keras.layers.MaxPooling2D(),
    tf.keras.layers.Conv2D(512, (3, 3)),

    tf.keras.layers.Activation('relu'),
    tf.keras.layers.MaxPooling2D(),
    tf.keras.layers.Conv2D(1024, (3, 3)),

    tf.keras.layers.Activation('relu'),
    tf.keras.layers.GlobalAveragePooling2D(),  # 再得到的(12,12)上兩維進行求平均值得到一個值

    tf.keras.layers.Dense(256),

    tf.keras.layers.Activation('relu'),
    tf.keras.layers.Dense(1)  # 這裡可以不寫啟用函式,因為對於二分類問題而言,不啟用的畫最後認為輸出結果大於0使一種結果,小於0使一種結果,啟用的畫只是進行歸一化
    # np.array[p[0].numpy() for p in tf.cast(pred>0,tf.int32)]  就可以將最後的結果轉換為0 1格式
])

# 損失函式與優化器
optimizer = tf.keras.optimizers.Adam()
epoch_loss_avg = tf.keras.metrics.Mean("train_loss")
train_accuracy = tf.keras.metrics.Accuracy('train_acc')
def train_step(model,images,labels):
    with tf.GradientTape() as t:
        pred = model(images)
        loss_step = tf.keras.losses.BinaryCrossentropy(from_logits=True)(labels,pred)
    grads = t.gradient(loss_step,model.trainable_variables)
    optimizer.apply_gradients(zip(grads,model.trainable_variables))
    epoch_loss_avg(loss_step)
    train_accuracy(labels,tf.cast(pred>0,tf.int32))

# 新增驗證資料
test_image_path = glob.glob(r'E:\WORK\tensorflow\dataset\dc_2000\test\*\*.jpg')
test_image_label = [int(p.split('\\')[-2] == 'cat') for p in test_image_path]  # 狗0 貓1
# print(len(test_image_path))
# print(len(test_image_label))
# print(test_image_path[:3])
# print(test_image_label[:3])
# exit(0)
test_image_ds = tf.data.Dataset.from_tensor_slices((test_image_path,test_image_label))
test_image_ds = test_image_ds.map(load_preprosess_image,num_parallel_calls=AUTOTUNE)
test_image_ds = test_image_ds.batch(BATVH_SIZE)
test_image_ds = test_image_ds.prefetch(AUTOTUNE)

epoch_loss_avg_test = tf.keras.metrics.Mean("test_loss")
test_accuracy = tf.keras.metrics.Accuracy("test_acc")

def test_step(model,images,labels):
    pred = model.predict(images)  # 這裡不能直接使用model(image),因為這樣雖然也能返回預測結果,但是同時會對網路進行訓練
    loss_step = tf.keras.losses.BinaryCrossentropy(from_logits=True)(labels,pred)
    epoch_loss_avg_test(loss_step)
    test_accuracy(labels,tf.cast(pred>0,tf.int32))

def train(epoches):
    train_loss_results = []
    train_acc_results = []
    test_loss_results = []
    test_acc_results = []
    for epoch in range(epoches):
        for imgs_,labels_ in train_image_ds:
            train_step(model,imgs_,labels_)
            print(".",end='')
        print()

        train_loss_results.append(epoch_loss_avg.result())
        train_acc_results.append(train_accuracy.result())

        for imgs_,labels_ in test_image_ds:
            test_step(model,imgs_,labels_)
        test_loss_results.append(epoch_loss_avg_test.result())
        test_acc_results.append(test_accuracy.result())

        print('Epoch:{}/{}  train_loss:{:.3f}  train_acc:{:.3f}  test_loss:{:.3f}  test_acc:{:.3f}'.format(
            epoch+1,epoches,epoch_loss_avg.result(),train_accuracy.result(),epoch_loss_avg_test.result(),test_accuracy.result()))

        epoch_loss_avg.reset_states()
        train_accuracy.reset_states()
        epoch_loss_avg_test.reset_states()
        test_accuracy.reset_states()
    return train_acc_results, train_acc_results

train(20)

# 影象增強,可以將圖片左右反轉,上下翻轉,甚至可以擷取一部分,這樣就增加了圖片的數量,增加了訓練集的數量,並且考慮到了更多的情況
# 甚至可以改變圖片的亮度


作者:孫建釗
出處:http://www.cnblogs.com/sunjianzhao/
本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段宣告,且在文章頁面明顯位置給出原文連線,否則保留追究法律責任的權利。