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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

动手学PaddlePaddle(5):迁移学习

發布時間:2023/12/10 编程问答 50 豆豆
生活随笔 收集整理的這篇文章主要介紹了 动手学PaddlePaddle(5):迁移学习 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

本次練習,用遷移學習思想,結合paddle框架,來實現圖像的分類。

相關理論:

1. 原有模型作為一個特征提取器:

使用一個用ImageNet數據集提前訓練(pre-trained)好的CNN,再除去最后一層全連接層(fully-connected layer),即除去原有的分類器部分。然后再用剩下的神經網絡作為特征提取器應用在新的數據集上。我們只需要用新的訓練集訓練一個嫁接到這個特征提取器上的分類器即可。

2.fine-turning原有模型

這種方法要求不僅僅除去原有模型的分類器,再用新的數據集訓練新的分類器,還要求微調(fine-tune)本身神經網絡的參數(weights)。和方式1的區別是:方式1要求固定原有神經網絡的參數,而fine-tune允許訓練新的數據集時對原有神經網絡的參數進行更改。為了防止過擬合,有時可以要求固定某些層的參數,只微調剩下的一些層。

本次實驗總共分兩個steps

  • step-1: 在step-1中,加載在imagenet數據集上訓練好的Resnet50模型,作為預訓練模型,并且凍結除fc層之外的參數,只訓練fc層。得到step_1_model;

拿到新數據集,想要用預訓練模型處理的時候,通常都會先用step-1的方法看看預訓練模型在新數據上的表現怎么樣,摸個底。如果表現不錯,還想看看能不能進一步提升,就可以試試Fine-tune(即解鎖比較少的卷積層繼續訓練),但是不要期待會有什么質的飛躍。如果由于新數據集與原數據集(例如ImageNet數據集)的差別太大導致表現很糟,那么一方面可以考慮從頭訓練模型,另一方面也可以考慮解鎖比較多層的訓練,亦或干脆只用預訓練模型的參數作為初始值,對模型進行完整訓練。

  • step-2: 在step-2中,把step_1_model作為預訓練模型,并在此基礎上重新訓練,得到最終的模型step_2_model。

但是要注意:
事實上,step-2必須在已經進行過‘凍結特征提取器參數的訓練之后再嘗試訓練模型,這時分類器的參數已經經過一次訓練。如果從隨機生成的分類器參數開始直接訓練,在做參數更新迭代過程中梯度將很可能過大,而導致模型的崩潰,使模型忘記學到的所有東西。

在finetune時,batch_size設置最好不要太大,以便于加速模型收斂。學習率也適當小一些。


目錄

step-1:

1. 導入庫

2. 定義ResNet網絡

3.訓練前準備

4.開始訓練

step-2:

5. 導入庫

6.定義ResNet網絡

7.訓練前準備


step-1:

在step-1中,加載在imagenet數據集上訓練好的Resnet50模型,作為預訓練模型,并且凍結除fc層之外的參數,只訓練fc層。得到step_1_model。

1. 導入庫

實驗第一步,導入需要的庫,本實驗中專門定義了一個 reader.py文件,用來對數據集進行讀取和預處理,所以也需要把reader.py文件import進來。

import os import shutil import paddle as paddle import paddle.fluid as fluid from paddle.fluid.param_attr import ParamAttr import reader # 獲取flowers數據 train_reader = paddle.batch(reader.train(), batch_size=16) test_reader = paddle.batch(reader.val(), batch_size=16)

2. 定義ResNet網絡

  • 本次實驗使用ResNet50這個殘差神經網絡,所以,接下來需要定義一個殘差神經網絡。
  • PaddlePaddle官方已經提供了ResNet以及其他經典的網絡模型。鏈接:https://github.com/PaddlePaddle/models/blob/develop/PaddleCV/image_classification/models/resnet.py
  • 網絡定義時,每一個層都由指定參數名字。
# 定義殘差神經網絡(ResNet) def resnet50(input):def conv_bn_layer(input, num_filters, filter_size, stride=1, groups=1, act=None, name=None):conv = fluid.layers.conv2d(input=input,num_filters=num_filters,filter_size=filter_size,stride=stride,padding=(filter_size - 1) // 2,groups=groups,act=None,param_attr=ParamAttr(name=name + "_weights"),bias_attr=False,name=name + '.conv2d.output.1')if name == "conv1":bn_name = "bn_" + nameelse:bn_name = "bn" + name[3:]return fluid.layers.batch_norm(input=conv,act=act,name=bn_name + '.output.1',param_attr=ParamAttr(name=bn_name + '_scale'),bias_attr=ParamAttr(bn_name + '_offset'),moving_mean_name=bn_name + '_mean',moving_variance_name=bn_name + '_variance', )def shortcut(input, ch_out, stride, name):ch_in = input.shape[1]if ch_in != ch_out or stride != 1:return conv_bn_layer(input, ch_out, 1, stride, name=name)else:return inputdef bottleneck_block(input, num_filters, stride, name):conv0 = conv_bn_layer(input=input,num_filters=num_filters,filter_size=1,act='relu',name=name + "_branch2a")conv1 = conv_bn_layer(input=conv0,num_filters=num_filters,filter_size=3,stride=stride,act='relu',name=name + "_branch2b")conv2 = conv_bn_layer(input=conv1,num_filters=num_filters * 4,filter_size=1,act=None,name=name + "_branch2c")short = shortcut(input, num_filters * 4, stride, name=name + "_branch1")return fluid.layers.elementwise_add(x=short, y=conv2, act='relu', name=name + ".add.output.5")depth = [3, 4, 6, 3]num_filters = [64, 128, 256, 512]conv = conv_bn_layer(input=input, num_filters=64, filter_size=7, stride=2, act='relu', name="conv1")conv = fluid.layers.pool2d(input=conv, pool_size=3, pool_stride=2, pool_padding=1, pool_type='max')for block in range(len(depth)):for i in range(depth[block]):conv_name = "res" + str(block + 2) + chr(97 + i)conv = bottleneck_block(input=conv,num_filters=num_filters[block],stride=2 if i == 0 and block != 0 else 1,name=conv_name)pool = fluid.layers.pool2d(input=conv, pool_size=7, pool_type='avg', global_pooling=True)return pool

本次實驗,使用的圖片數據集是flowers。圖片是3通道寬高都是224的彩色圖,總類別是5種,每一個種類大約有六百多張。

3.訓練前準備

接下來,開始做訓練前的準備工作。首先,定義圖片數據和標簽數據的輸入層:

# 定義輸入層 image = fluid.layers.data(name='image', shape=[3, 224, 224], dtype='float32') label = fluid.layers.data(name='label', shape=[1], dtype='int64')

利用stop_gradient,使得pool以上的層停止梯度傳遞,相當于keras中的freeze。這樣就可以只訓練最后的fc層,但是要注意:數據集是5分類,所以size要設為5.

# 獲取分類器的上一層 pool = resnet50(image) # 停止梯度下降 pool.stop_gradient = True # 由這里創建一個基本的主程序 base_model_program = fluid.default_main_program().clone()# 這里再重新加載網絡的分類器,大小為本項目的分類大小 model = fluid.layers.fc(input=pool, size=5, act='softmax')

接下來,要做的工作有:

  • 定義損失函數;
  • 求準確率;
  • 定義優化器;
  • 設定訓練場所;
  • 定義執行器,并且完成參數初始化;
# 獲取損失函數和準確率函數 cost = fluid.layers.cross_entropy(input=model, label=label) avg_cost = fluid.layers.mean(cost) acc = fluid.layers.accuracy(input=model, label=label)# 定義優化方法 optimizer = fluid.optimizer.AdamOptimizer(learning_rate=1e-3) opts = optimizer.minimize(avg_cost)# 定義訓練場所 place = fluid.CUDAPlace(0)#用GPU訓練 #place = fluid.CPUPlace() #用CPU訓練 exe = fluid.Executor(place) # 進行參數初始化 exe.run(fluid.default_startup_program())
  • 接下來加載預訓練模型,使用paddle官網上訓練好的ResNet50模型,這個模型存儲在“./ResNet50_pretrained/”,也可以去官網上下載,鏈接:http://paddle-imagenet-models-name.bj.bcebos.com/ResNet50_pretrained.tar
  • 通過if_exist函數判斷網絡所需的模型文件是否存在,然后再通過調用fluid.io.load_vars加載存在的模型文件。
# 官方提供的原預訓練模型 src_pretrain_model_path = './ResNet50_pretrained/'# 通過這個函數判斷模型文件是否存在 def if_exist(var):path = os.path.join(src_pretrain_model_path, var.name)exist = os.path.exists(path)return exist# 加載模型文件,只加載存在模型的模型文件 fluid.io.load_vars(executor=exe, dirname=src_pretrain_model_path, predicate=if_exist, main_program=base_model_program)

4.開始訓練

接下來就定義一個雙層循環來開始訓練模型,并且還可以把訓練過程中的cost值和acc值打印出來,以此來直觀的感受訓練效果。

# 優化內存 # optimized = fluid.transpiler.memory_optimize(input_program=fluid.default_main_program(), print_log=False)# 定義輸入數據維度 feeder = fluid.DataFeeder(place=place, feed_list=[image, label])# 訓練10次 for pass_id in range(10):# 進行訓練for batch_id, data in enumerate(train_reader()):train_cost, train_acc = exe.run(program=fluid.default_main_program(),feed=feeder.feed(data),fetch_list=[avg_cost, acc])# 每100個batch打印一次信息if batch_id % 100 == 0:print('Pass:%d, Batch:%d, Cost:%0.5f, Accuracy:%0.5f' %(pass_id, batch_id, train_cost[0], train_acc[0]))

訓練結束之后,使用fluid.io.save_param保存訓練好的參數。

到這里為止,把從imagenet數據集上訓練好的的原預訓練模型,結合數據集,把最后一層fc進行了訓練。接下來就是使用這個已經處理過的模型正式訓練了。

# 保存參數模型 save_pretrain_model_path = 'models/step-1_model/'# 刪除舊的模型文件 shutil.rmtree(save_pretrain_model_path, ignore_errors=True) # 創建保持模型文件目錄 os.makedirs(save_pretrain_model_path) # 保存參數模型 fluid.io.save_params(executor=exe, dirname=save_pretrain_model_path)

step-2:

5. 導入庫

import os import shutil import paddle as paddle import paddle.dataset.flowers as flowers import paddle.fluid as fluid from paddle.fluid.param_attr import ParamAttr import reader# 獲取flowers數據 train_reader = paddle.batch(reader.train(), batch_size=16) test_reader = paddle.batch(reader.val(), batch_size=16)

6.定義ResNet網絡

仍然需要定義一個殘差神經網絡,這個殘差神經網絡跟第一步時的基本一樣的,只是把分類器(也就是fc層)也加進去了,這是一個完整的神經網絡。

?

?

?

?

?

?

?

?

?

?

?

?

?

?

# 定義殘差神經網絡(ResNet) def resnet50(input, class_dim):def conv_bn_layer(input, num_filters, filter_size, stride=1, groups=1, act=None, name=None):conv = fluid.layers.conv2d(input=input,num_filters=num_filters,filter_size=filter_size,stride=stride,padding=(filter_size - 1) // 2,groups=groups,act=None,param_attr=ParamAttr(name=name + "_weights"),bias_attr=False,name=name + '.conv2d.output.1')if name == "conv1":bn_name = "bn_" + nameelse:bn_name = "bn" + name[3:]return fluid.layers.batch_norm(input=conv,act=act,name=bn_name + '.output.1',param_attr=ParamAttr(name=bn_name + '_scale'),bias_attr=ParamAttr(bn_name + '_offset'),moving_mean_name=bn_name + '_mean',moving_variance_name=bn_name + '_variance', )def shortcut(input, ch_out, stride, name):ch_in = input.shape[1]if ch_in != ch_out or stride != 1:return conv_bn_layer(input, ch_out, 1, stride, name=name)else:return inputdef bottleneck_block(input, num_filters, stride, name):conv0 = conv_bn_layer(input=input,num_filters=num_filters,filter_size=1,act='relu',name=name + "_branch2a")conv1 = conv_bn_layer(input=conv0,num_filters=num_filters,filter_size=3,stride=stride,act='relu',name=name + "_branch2b")conv2 = conv_bn_layer(input=conv1,num_filters=num_filters * 4,filter_size=1,act=None,name=name + "_branch2c")short = shortcut(input, num_filters * 4, stride, name=name + "_branch1")return fluid.layers.elementwise_add(x=short, y=conv2, act='relu', name=name + ".add.output.5")depth = [3, 4, 6, 3]num_filters = [64, 128, 256, 512]conv = conv_bn_layer(input=input, num_filters=64, filter_size=7, stride=2, act='relu', name="conv1")conv = fluid.layers.pool2d(input=conv, pool_size=3, pool_stride=2, pool_padding=1, pool_type='max')for block in range(len(depth)):for i in range(depth[block]):conv_name = "res" + str(block + 2) + chr(97 + i)conv = bottleneck_block(input=conv,num_filters=num_filters[block],stride=2 if i == 0 and block != 0 else 1,name=conv_name)pool = fluid.layers.pool2d(input=conv, pool_size=7, pool_type='avg', global_pooling=True)output = fluid.layers.fc(input=pool, size=class_dim, act='softmax')return output

7.訓練前準備

接下來,開始做訓練前的準備工作:

  • 定義圖片數據和標簽數據的輸入層;
  • 定義損失函數;
  • 求準確率;
  • 定義優化器;
  • 設定訓練場所;
  • 定義執行器,并且完成參數初始化;
# 定義輸入層 image = fluid.layers.data(name='image', shape=[3, 224, 224], dtype='float32') label = fluid.layers.data(name='label', shape=[1], dtype='int64')# 獲取分類器 model = resnet50(image, 5)# 獲取損失函數和準確率函數 cost = fluid.layers.cross_entropy(input=model, label=label) avg_cost = fluid.layers.mean(cost) acc = fluid.layers.accuracy(input=model, label=label)# 獲取訓練和測試程序 test_program = fluid.default_main_program().clone(for_test=True)# 定義優化方法 optimizer = fluid.optimizer.AdamOptimizer(learning_rate=1e-3) opts = optimizer.minimize(avg_cost)# 定義一個使用GPU的執行器 place = fluid.CUDAPlace(0) #place = fluid.CPUPlace() exe = fluid.Executor(place) # 進行參數初始化 exe.run(fluid.default_startup_program())

加載經過step-1訓練好的模型,作為新的預訓練模型。并在此基礎上進行重新訓練:

# 經過step-1處理后的的預訓練模型 pretrained_model_path = 'models/step-1_model/'# 加載經過處理的模型 fluid.io.load_params(executor=exe, dirname=pretrained_model_path)

接下來就定義一個雙層循環來開始訓練模型,并且還可以把訓練過程中的cost值和acc值打印出來,以此來直觀的感受訓練效果。

# 定義輸入數據維度 feeder = fluid.DataFeeder(place=place, feed_list=[image, label])# 訓練10次 for pass_id in range(10):# 進行訓練for batch_id, data in enumerate(train_reader()):train_cost, train_acc = exe.run(program=fluid.default_main_program(),feed=feeder.feed(data),fetch_list=[avg_cost, acc])# 每100個batch打印一次信息if batch_id % 100 == 0:print('Pass:%d, Batch:%d, Cost:%0.5f, Accuracy:%0.5f' %(pass_id, batch_id, train_cost[0], train_acc[0]))# 進行測試test_accs = []test_costs = []for batch_id, data in enumerate(test_reader()):test_cost, test_acc = exe.run(program=test_program,feed=feeder.feed(data),fetch_list=[avg_cost, acc])test_accs.append(test_acc[0])test_costs.append(test_cost[0])# 求測試結果的平均值test_cost = (sum(test_costs) / len(test_costs))test_acc = (sum(test_accs) / len(test_accs))print('Test:%d, Cost:%0.5f, Accuracy:%0.5f' % (pass_id, test_cost, test_acc))

訓練結束之后,可以保存預測模型用于之后的預測使用。

# 保存預測模型 save_path = 'models/step_2_model/'# 刪除舊的模型文件 shutil.rmtree(save_path, ignore_errors=True) # 創建保持模型文件目錄 os.makedirs(save_path) # 保存預測模型 fluid.io.save_inference_model(save_path, feeded_var_names=[image.name], target_vars=[model], executor=exe)

?

總結

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

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。