动手学深度学习(二十七)——微调(fine turning)

一、微调(fine tuning)

1. 微调的四个步骤:

  1. 在源数据集(如ImageNet数据集)上预训练一个神经网络模型,即源模型。
  2. 创建一个新的神经网络模型,即目标模型。它复制了源模型上除了输出层外的所有模型设计及其参数。我们假设这些模型参数包含了源数据集上学习到的知识,且这些知识同样适用于目标数据集。我们还假设源模型的输出层与源数据集的标签紧密相关,因此在目标模型中不予采用。
  3. 为目标模型添加一个输出大小为目标数据集类别个数的输出层,并随机初始化该层的模型参数。
  4. 在目标数据集(如椅子数据集)上训练目标模型。我们将从头训练输出层,而其余层的参数都是基于源模型的参数微调得到的。

2. 微调的训练过程

  1. 是一个目标数据集上的正常训练任务
  2. 使用了更强的正则化:
    • 更小的学习率(大stride在初始模型中已走过了,相当于已经有一个比较好的模型了)
    • 更少的迭代次数
      3.源数据集远复杂于目标数据,通常得到的微调效果更好

3. 常用的微调技术

  1. 重用分类器权重(对最后的分类层进行的处理哦!!!)
    • 源数据可能也有目标数据中的部分标号
    • 可以使用预训练好的模型分类器中对应标号对应的向量作初始化值
  2. 固定一些层
    • 神经网络通常学习有层次的特征表示(底层描述的特征更加通用,而高层的特征和数据集相关性更强)
    • 可以固定相对底部的层,不参与参数更新(应用了更强的正则化)

4. 总结

  1. 微调通过使用在大数据上得到的预训练模型来初始化权重来提高精度
  2. 预训练模型质量非常重要
  3. 微调通常速度更快、精度更高

二、动手实现和测试微调

%matplotlib inline
import os 
import torch 
import torchvision 
from torch import nn 
from d2l import torch as d2l 

1. 数据准备

# 下载热狗数据集
d2l.DATA_HUB['hotdog'] = (d2l.DATA_URL+'hotdog.zip',
                          'fba480ffa8aa7e0febbb511d181409f899b9baa5')
data_dir = d2l.download_extract('hotdog')
# 加载数据
train_imgs = torchvision.datasets.ImageFolder(os.path.join(data_dir, 'train'))
test_imgs = torchvision.datasets.ImageFolder(os.path.join(data_dir, 'test'))
# 查看数据
'''展示了8张热狗数据和非热狗的数据,图像的大小和横纵比例都不尽相同'''
hotdogs = [train_imgs[i][0] for i in range(8)] # hotdogs
not_hotdogs = [train_imgs[-i-1][0] for i in range(8)] # not hotdogs
d2l.show_images(hotdogs + not_hotdogs, 2, 8, scale=1.4);
# 数据增广使数据规整变多
'''
在训练期间,我们首先从图像中裁切随机大小和随机长宽比的区域,然后将该区域缩放为 224x224 输入图像。
在测试过程中,我们将图像的高度和宽度都缩放到 256 像素,然后裁剪中央 224 x 224 区域作为输入。
此外,对于三个 RGB(红、绿和蓝)颜色通道,我们标准化每个通道。
具体而言,通道的平均值将从该通道的每个值中减去,然后将结果除以该通道的标准差。
'''
# 在Imagenet上使用的Normalize直接搬过来,参数第一个是mean,第二个是std;image = (image-mean)/std;这里是三通道
normalize = torchvision.transforms.Normalize([0.485, 0.456, 0.406],
                                             [0.229, 0.224, 0.225]) 
train_augs = torchvision.transforms.Compose([
    torchvision.transforms.RandomResizedCrop(224),
    torchvision.transforms.RandomHorizontalFlip(),
    torchvision.transforms.ToTensor(),
    normalize,   
])

test_augs = torchvision.transforms.Compose([
    torchvision.transforms.Resize(256),
    torchvision.transforms.CenterCrop(224),
    torchvision.transforms.ToTensor(), normalize])

2. 模型微调

定义和初始化模型

# 定义和初始化模型
'''
使用ImageNet数据集预训练的ResNet-18作为源模型;
指pretrained =True,以保存模型参数
'''
pretrained_net = torchvision.models.resnet18(pretrained=True)

Check原始模型参数

# 源模型包含多个要素图层和一个输出图层,对除了输出图层之外的层进行微调
'''查看源模型的输出图层参数'''
pretrained_net.fc
Linear(in_features=512, out_features=1000, bias=True)
# 初始化微调图层
finetune_net = torchvision.models.resnet18(pretrained=True)
finetune_net.fc = nn.Linear(finetune_net.fc.in_features, 2)
nn.init.xavier_uniform_(finetune_net.fc.weight);

定义训练函数,便于更多参数的调整

# 如果 `param_group=True`,输出层中的模型参数将使用十倍的学习率
def train_fine_tuning(net, learning_rate, batch_size=128, num_epochs=5,
                      param_group=True):
    train_iter = torch.utils.data.DataLoader(
        torchvision.datasets.ImageFolder(os.path.join(data_dir, 'train'),
                                         transform=train_augs),
        batch_size=batch_size, shuffle=True)
    test_iter = torch.utils.data.DataLoader(
        torchvision.datasets.ImageFolder(os.path.join(data_dir, 'test'),
                                         transform=test_augs),
        batch_size=batch_size)
    devices = d2l.try_all_gpus()
    loss = nn.CrossEntropyLoss(reduction="none")
    if param_group:
        '''将所有层的参数都拿出来进行训练,最后一层的学习率是前面层的10倍'''
        params_1x = [
            param for name, param in net.named_parameters()
            if name not in ["fc.weight", "fc.bias"]]
        trainer = torch.optim.SGD([{
            'params': params_1x}, {
                'params': net.fc.parameters(),
                'lr': learning_rate * 10}], lr=learning_rate,
                                  weight_decay=0.001)
    else:
        '''全部参数一样地训练'''
        trainer = torch.optim.SGD(net.parameters(), lr=learning_rate,
                                  weight_decay=0.001)
    d2l.train_ch13(net, train_iter, test_iter, loss, trainer, num_epochs,
                   devices)
# 使用较小的学习率,通过微调预训练获得的模型参数
train_fine_tuning(finetune_net, 5e-5)
loss 0.181, train acc 0.932, test acc 0.935
228.9 examples/sec on [device(type='cuda', index=0)]

3. 对比不使用微调和不同的微调参数

如果不使用微调,直接从零开始训练:不使用微调的结果精度远远低于微调的结果

# 对比不使用微调
scratch_net = torchvision.models.resnet18()
scratch_net.fc = nn.Linear(scratch_net.fc.in_features, 2)
train_fine_tuning(scratch_net, 5e-4, param_group=False)
loss 0.384, train acc 0.831, test acc 0.814
229.5 examples/sec on [device(type='cuda', index=0)]

调整fine turning 的学习率发现:学习率变太高会降低训练的精度

# 调高fine turning 的学习率
finetune_net = torchvision.models.resnet18(pretrained=True)
finetune_net.fc = nn.Linear(finetune_net.fc.in_features, 2)
nn.init.xavier_uniform_(finetune_net.fc.weight);
train_fine_tuning(finetune_net, 4e-5)
loss 0.203, train acc 0.921, test acc 0.930
229.4 examples/sec on [device(type='cuda', index=0)]

4. 冻结层进行微调

冻结一部分的层进行训练:冻结层训练可以减少训练的时间,但是具体要冻结哪些层需要调整,我这里使用的方法也不确定是否正确,因为使用requires_grad没有使用成功,就找了个笨方法

# 如果不更新输出层之前的层的参数(冻结一些层)
# 我这里没有使用requires_grad = False,没有仔细探究是否真的冻结住了。是否需要将不计算梯度放到train函数之中
def train_fine_tuning_freeze(net, learning_rate, batch_size=128, num_epochs=5):
    train_iter = torch.utils.data.DataLoader(
        torchvision.datasets.ImageFolder(os.path.join(data_dir, 'train'),
                                         transform=train_augs),
        batch_size=batch_size, shuffle=True)
    test_iter = torch.utils.data.DataLoader(
        torchvision.datasets.ImageFolder(os.path.join(data_dir, 'test'),
                                         transform=test_augs),
        batch_size=batch_size)
    devices = d2l.try_all_gpus()
    loss = nn.CrossEntropyLoss(reduction="none")
    '''冻结一些层(只更新最后层的参数)'''
    trainer = torch.optim.SGD(net.fc.parameters(), lr=learning_rate,weight_decay=0.001)
    d2l.train_ch13(net, train_iter, test_iter, loss, trainer, num_epochs,devices)

finetune_net = torchvision.models.resnet18(pretrained=True)
finetune_net.fc = nn.Linear(finetune_net.fc.in_features, 2)
nn.init.xavier_uniform_(finetune_net.fc.weight);
train_fine_tuning_freeze(finetune_net, 5e-5,num_epochs=10)
loss 0.299, train acc 0.878, test acc 0.887
231.1 examples/sec on [device(type='cuda', index=0)]

如果有什么存在疑惑的地方可以在评论区提出,大家一起讨论!

智能家居是现代科技的重要应用之一,基于深度学习的智能家居系统可以自动化完成许多家庭任务,例如智能门锁、智能灯光、智能温控等。下面是一个基于深度学习的智能家居应用的代码实现: 1. 智能门锁 智能门锁可以使用深度学习算法进行人脸识别,从而识别合法的用户并自动开锁。 ```python import cv2 import numpy as np import os # 加载训练好的人脸识别模型 model = cv2.face.LBPHFaceRecognizer_create() model.read('face_model.xml') # 加载人脸数据集 path = 'face_dataset' face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml') (images, labels, names, id) = ([], [], {}, 0) for (subdirs, dirs, files) in os.walk(path): for subdir in dirs: names[id] = subdir subjectpath = os.path.join(path, subdir) for filename in os.listdir(subjectpath): if filename.startswith("."): continue label = id img_path = os.path.join(subjectpath, filename) image = cv2.imread(img_path) gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) faces = face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30)) for (x, y, w, h) in faces: images.append(gray[y:y + h, x:x + w]) labels.append(int(label)) id += 1 # 打开摄像头,实时人脸识别并控制门锁 cap = cv2.VideoCapture(0) while True: ret, frame = cap.read() gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) faces = face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30)) for (x, y, w, h) in faces: roi_gray = gray[y:y + h, x:x + w] id, confidence = model.predict(roi_gray) if confidence < 100: name = names[id] cv2.putText(frame, name, (x, y - 20), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2, cv2.LINE_AA) cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2) else: cv2.putText(frame, "Unknown", (x, y - 20), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2, cv2.LINE_AA) cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 0, 255), 2) cv2.imshow('frame', frame) # 识别到合法用户时,控制门锁开启 if cv2.waitKey(1) & 0xFF == ord('q'): if name != "Unknown": print("Door unlocked!") break cap.release() cv2.destroyAllWindows() ``` 2. 智能灯光 智能灯光可以使用深度学习算法进行语音识别和情感分析,从而根据用户的语音命令和情感状态自动调节灯光亮度和颜色。 ```python import speech_recognition as sr import pyttsx3 import numpy as np import imutils import cv2 # 初始化语音识别和语音合成引擎 r = sr.Recognizer() engine = pyttsx3.init() # 打开摄像头,实时情感分析和灯光控制 cap = cv2.VideoCapture(0) while True: ret, frame = cap.read() frame = imutils.resize(frame, width=500) gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) faces = face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30)) for (x, y, w, h) in faces: roi_gray = gray[y:y + h, x:x + w] id, confidence = model.predict(roi_gray) if confidence < 100: name = names[id] cv2.putText(frame, name, (x, y - 20), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2, cv2.LINE_AA) cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2) else: cv2.putText(frame, "Unknown", (x, y - 20), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2, cv2.LINE_AA) cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 0, 255), 2) cv2.imshow('frame', frame) # 使用语音识别和情感分析控制灯光 with sr.Microphone() as source: audio = r.listen(source) try: text = r.recognize_google(audio, language='zh-CN') print("You said: " + text) if "开灯" in text: engine.say("好的,灯已经打开了") engine.runAndWait() print("Light on!") elif "关灯" in text: engine.say("好的,灯已经关闭了") engine.runAndWait() print("Light off!") else: engine.say("抱歉,我没有听懂你的命令") engine.runAndWait() except sr.UnknownValueError: print("Google Speech Recognition could not understand audio") except sr.RequestError as e: print("Could not request results from Google Speech Recognition service; {0}".format(e)) if cv2.waitKey(1) & 0xFF == ord('q'): break cap.release() cv2.destroyAllWindows() ``` 3. 智能温控 智能温控可以使用深度学习算法进行温度预测和控制,从而自动调节室内温度。 ```python import numpy as np import tensorflow as tf import pandas as pd # 加载训练好的温度预测模型 model = tf.keras.models.load_model('temp_model.h5') # 加载历史温度数据 data = pd.read_csv('temp_data.csv') data = data.dropna() x = data['time'].values y = data['temp'].values # 每隔一段时间预测一次室内温度并控制温度 while True: time.sleep(60) # 每隔一分钟预测一次温度 x_new = np.array([time.time()]) y_new = model.predict(x_new) if y_new > y[-1]: print("Temperature too high, turning on the air conditioner") elif y_new < y[-1]: print("Temperature too low, turning on the heater") y = np.append(y, y_new) x = np.append(x, x_new) data = pd.DataFrame({'time': x, 'temp': y}) data.to_csv('temp_data.csv', index=False) ```
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

留小星

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值