日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

TensorFlow2-迁移学习

發(fā)布時間:2024/4/11 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 TensorFlow2-迁移学习 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

TensorFlow2遷移學習

簡介

遷移學習的思路是指在較大的數(shù)據(jù)集(如ImageNet)上訓練模型,得到泛化能力較強的模型,將其應用到較小數(shù)據(jù)集上,繼續(xù)訓練微調(diào)參數(shù),從而可以在其他任務上使用。

自定義數(shù)據(jù)集

實際上,對于大型數(shù)據(jù)集而言,不可能采用之前的方法加載數(shù)據(jù)集。之前是將整個數(shù)據(jù)集讀入為一個張量,每次從中取出一個batch的子張量,由于深度學習數(shù)據(jù)集一般都比較大,將這樣大的數(shù)據(jù)集讀入內(nèi)存和顯存是不現(xiàn)實的,因此一般分批次io取出數(shù)據(jù)。

數(shù)據(jù)集格式

一般的CV數(shù)據(jù)集都是圖片,且圖片的存儲格式有固定的規(guī)則,常見的主要有兩種。第一種,分類別存放,每個類別一個目錄,目錄下放該類別的所有圖片,如果有子類別則類似上面遞歸存儲。另一種方法,所有文件在一個目錄下,用一個csv文件記錄所有圖片信息,每一行有文件的id(一般是文件的相對目錄),文件對應圖片類別,其他annotation信息。顯然第二種更加合理,現(xiàn)在,很多開放數(shù)據(jù)集都是綜合二者進行存儲。

數(shù)據(jù)處理

應對文件讀取,設(shè)計了如下的幾個函數(shù)(數(shù)據(jù)集采用第一種方式存儲,但是為了加載方便,生成了第二種存儲的包含文件路徑和標簽的csv文件)。可以看到,在TensorFlow2中,數(shù)據(jù)集的加載是非常靈活的,沒有固定的格式,按需讀入即可。

數(shù)據(jù)預處理對于數(shù)據(jù)集有時候是必要的。resize(圖片大小修改)大多數(shù)時候是必要的;Data Augmention(數(shù)據(jù)增廣)可以增加小數(shù)據(jù)集的數(shù)據(jù)量,緩解過擬合問題,常見的增廣手段有旋轉(zhuǎn)、翻轉(zhuǎn)、裁減等;標準化對于像素數(shù)值的處理可以使得模型的擬合更加容易。

下面的代碼包含自定義數(shù)據(jù)集加載的代碼,主要針對Caltech101的數(shù)據(jù)集存放格式。

import tensorflow as tf import pandas as pd import os os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2' # 不顯示警告 random_seed = 2019def preprocess(x, y):"""數(shù)據(jù)預處理:param x: 圖片路徑:param y: 圖片編碼:return:"""x = tf.io.read_file(x)x = tf.image.decode_jpeg(x, channels=3)x = tf.image.resize(x, [224, 224])x = tf.image.random_flip_left_right(x)# x: [0,255]=>[0,1]x = tf.cast(x, dtype=tf.float32) / 255.y = tf.convert_to_tensor(y)y = tf.one_hot(y, depth=102)return x, ydef load_data(desc_path, batch_size):"""加載csv文件讀入數(shù)據(jù)集:param desc_path: 描述文件的路徑:param batch_size: 批尺寸大小:return:"""df_desc = pd.read_csv(desc_path, encoding="utf8")sample_num = len(df_desc) # 所有訓練數(shù)據(jù)的樣本數(shù)目images = df_desc['file_id']labels = df_desc['label'].astype('int')idx = tf.random.shuffle(tf.range(sample_num), seed=random_seed)# 按照8:2取訓練集和驗證集train_images, train_labels = tf.gather(images, idx[:int(images.shape[0] * 0.8)]), tf.gather(labels, idx[:int(labels.shape[0]*0.8)])valid_images, valid_labels = tf.gather(images, idx[int(images.shape[0] * 0.8):]), tf.gather(labels, idx[int(labels.shape[0]*0.8):])db_train = tf.data.Dataset.from_tensor_slices((train_images, train_labels))db_valid = tf.data.Dataset.from_tensor_slices((valid_images, valid_labels))db_train = db_train.shuffle(1000).map(preprocess).batch(batch_size)db_valid = db_valid.map(preprocess).batch(batch_size)return db_train, db_validif __name__ == '__main__':load_data("../data/desc.csv", 32)

遷移學習實戰(zhàn)

在使用ResNet模型訓練小數(shù)據(jù)集,效果一般很差(具體代碼見文末Github),這是因為ResNet表示能力很強,很少的數(shù)據(jù)難以訓練模型的大量參數(shù)。這有兩種解決方法,第一種是采用較小的模型,第二種則是采用遷移學習方法,前者局限性很大,后者是相對更加常用的手段。

遷移學習的基本原理是CNN層次模型的下層學習到的特征是非常底層的紋理特征,同類型任務中這些特征是類似的,只需要重新學習高層特征即可(對于分類模型即只需要重新學習全連接分類器的特征)。經(jīng)典的網(wǎng)絡(luò)結(jié)構(gòu)及預訓練參數(shù)可以通過keras模塊獲取。

最終的訓練代碼如下,由于只有最后一層全連接層參與訓練,收斂較快。

import tensorflow as tf from model import vgg16, resnet50, densenet121 from data import load_data from visualize import plot_history print(tf.test.is_gpu_available())def load_db(batch_size):"""加載數(shù)據(jù)集:param batch_size::return:"""db_train, db_test = load_data("../data/desc.csv", batch_size)return db_train, db_testdef train(epochs):"""訓練模型:param epochs::return:"""vgg = vgg16((None, 224, 224, 3), 102)resnet = resnet50((None, 224, 224, 3), 102)densenet = densenet121((None, 224, 224, 3), 102)models = [vgg, resnet, densenet]train_db, valid_db = load_db(32)his = []for model in models:variables = model.trainable_variablesoptimizers = tf.keras.optimizers.Adam(1e-4)for epoch in range(epochs):# trainingtotal_num = 0total_correct = 0training_loss = 0for step, (x, y) in enumerate(train_db):with tf.GradientTape() as tape:# trainout = model(x)loss = tf.losses.categorical_crossentropy(y, out, from_logits=False)loss = tf.reduce_mean(loss)training_loss += lossgrads = tape.gradient(loss, variables)optimizers.apply_gradients(zip(grads, variables))# training accuracyy_pred = tf.cast(tf.argmax(out, axis=1), dtype=tf.int32)y_true = tf.cast(tf.argmax(y, axis=1), dtype=tf.int32)correct = tf.reduce_sum(tf.cast(tf.equal(y_pred, y_true), dtype=tf.int32))total_num += x.shape[0]total_correct += int(correct)if step % 100 == 0:print("loss is {}".format(loss))training_accuracy = total_correct / total_num# validationtotal_num = 0total_correct = 0for (x, y) in valid_db:out = model(x)y_pred = tf.argmax(out, axis=1)y_pred = tf.cast(y_pred, dtype=tf.int32)y_true = tf.argmax(y, axis=1)y_true = tf.cast(y_true, dtype=tf.int32)correct = tf.cast(tf.equal(y_pred, y_true), dtype=tf.int32)correct = tf.reduce_sum(correct)total_num += x.shape[0]total_correct += int(correct)validation_accuracy = total_correct / total_numprint("epoch:{}, training loss:{:.4f}, training accuracy:{:.4f}, validation accuracy:{:.4f}".format(epoch, training_loss, training_accuracy, validation_accuracy))his.append({'accuracy': training_accuracy, 'val_accuracy': validation_accuracy})return hisif __name__ == '__main__':training_history = train(50)plot_history(training_history)

具體的訓練日志可視化如下圖。

補充說明

本文介紹了加載自定義數(shù)據(jù)集和遷移學習在TensorFlow2中的實現(xiàn),更詳細的可以查看官方文檔。具體的代碼同步至我的Github倉庫歡迎star,如有疏漏,歡迎指正。

總結(jié)

以上是生活随笔為你收集整理的TensorFlow2-迁移学习的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。