1. Explication détaillée du réseau AlexNet
AlexNet est le réseau champion du concours ISLVRC 2012 (ImageNet Large Scale Visual Recognition Challenge) en 2012, et sa précision de classification est passée du traditionnel 70%+ à 80%+. Il a été conçu par Hinton et son élève Alex Krizhevsky. C'est également après cette année que l'apprentissage en profondeur a commencé à se développer rapidement.
Les points forts du réseau sont :
(1) Pour la première fois, le GPU est utilisé pour l'entraînement à l'accélération du réseau.
(2) La fonction d'activation ReLU est utilisée à la place de la fonction d'activation Sigmoïde traditionnelle et de la fonction d'activation Tanh.
(3) La normalisation de la réponse locale LRN est utilisée.
(4) Le fonctionnement du neurone de désactivation aléatoire d'abandon est utilisé dans les deux premières couches de la couche entièrement connectée pour réduire le surajustement.
1. Fonction d'activation ReLU
Visant le problème de la convergence lente de la formation causée par la saturation du gradient sigmoïde sigmoïde, ReLU a été introduit dans AlexNet. ReLU est une fonction linéaire par morceaux, la sortie est 0 si elle est inférieure ou égale à 0 ; la sortie est identique si elle est supérieure à 0. Par rapport au sigmoïde-sigmoïde, ReLU présente les avantages suivants :
- La surcharge de calcul est faible. La propagation vers l'avant de sigmoidsigmoid a un fonctionnement exponentiel et un fonctionnement réciproque, et ReLu est une sortie linéaire ; en rétropropagation, sigmoidsigmoid a un fonctionnement exponentiel, et ReLU a une partie de sortie, et la dérivée est toujours 1.
- problème de saturation du gradient
- parcimonie. Relu rendra la sortie de certains neurones 0, ce qui provoque la parcimonie du réseau, réduit l'interdépendance des paramètres et atténue l'apparition de problèmes de surajustement.
2. Utilisez le décrochage
Sur-ajustement : la cause principale est qu'il y a trop de dimensions d'entités, des hypothèses de modèle trop complexes, trop de paramètres, trop peu de données d'apprentissage et trop de bruit, ce qui conduit la fonction d'ajustement à prédire parfaitement l'ensemble d'apprentissage, mais à prédire le résultat de l'ensemble de test de nouvelles données Différence. Surajustement des données d'entraînement sans tenir compte de la généralisation.
L'introduction de Dropout vise principalement à éviter le surajustement. Dans le réseau de neurones, Dropout est réalisé en modifiant la structure du réseau de neurones lui-même.Pour un neurone d'une certaine couche, le neurone est mis à 0 par une probabilité définie, et ce neurone ne participe pas à la propagation avant et arrière, juste comme dans le réseau est supprimé, tout en gardant inchangé le nombre de neurones dans la couche d'entrée et la couche de sortie, puis mettre à jour les paramètres selon la méthode d'apprentissage du réseau de neurones. À l'itération suivante, certains neurones sont à nouveau supprimés de manière aléatoire (mis à 0) jusqu'à la fin de l'apprentissage.
Le décrochage doit être considéré comme une grande innovation dans AlexNet, et c'est maintenant l'une des structures nécessaires dans les réseaux de neurones. L'abandon peut également être considéré comme une combinaison de modèles. La structure de réseau générée à chaque fois est différente. En combinant plusieurs modèles, le surajustement peut être efficacement réduit. L'abandon n'a besoin que de deux fois plus de temps de formation pour obtenir une combinaison de modèles (similaire à l'effet de la moyenne), très efficace.
3. La formule de calcul de la taille de la matrice après convolution est :
N = (W - F + 2P ) / S + 1
① Taille de l'image d'entrée L×L
② Taille du filtre F×F
③ Pas de taille S
④ Nombre de pixels de rembourrage P
4. Explication détaillée de chaque couche de réseau
Conv1 : | Maxpool1 : | Conv2 : | Maxpool2 : | Conv3 : | Conv4 : |
---|---|---|---|---|---|
noyaux : 96 | noyaux : 256 | noyaux :=384 | noyaux : 384 | ||
taille_noyau : 11 | taille_noyau : 3 | kernel_size:5 | taille_noyau : 3 | taille_noyau : 3 | taille_noyau : 3 |
rembourrage : [1, 2] | pages : 0 | rembourrage : [2, 2] | pages : 0 | rembourrage : [1, 1] | rembourrage : [1, 1] |
foulée : 4 | foulée : 2 | foulée : 1 | foulée : 2 | foulée : 1 | foulée : 1 |
taille_sortie : | taille_sortie : | taille_sortie : | taille_sortie : | taille_sortie : | taille_sortie : |
[55, 55, 96] | [27, 27, 96] | [27, 27, 256] | [13, 13, 256] | [13, 13, 384] | [13, 13, 384] |
nom_couche | taille_noyau | kernel_num | rembourrage | foulée |
---|---|---|---|---|
Conv1 | 11 | 96 | [1, 2] | 4 |
Maxpool1 | 3 | Aucun | 0 | 2 |
Conv2 | 5 | 256 | [2, 2] | 1 |
Maxpool2 | 3 | Aucun | 0 | 2 |
Conv3 | 3 | 384 | [1, 1] | 1 |
Conv4 | 3 | 384 | [1, 1] | 1 |
Conv5 | 3 | 256 | [1, 1] | 1 |
Maxpool3 | 3 | Aucun | 0 | 2 |
FC1 | 2048 | Aucun | Aucun | Aucun |
FC2 | 2048 | Aucun | Aucun | Aucun |
FC3 | 1000 | Aucun | Aucun | Aucun |
2. Formation et tests
Tout d'abord, ce modèle utilise un ensemble de données de fleurs à 5 catégories, si vous le souhaitez, vous pouvez m'envoyer un message privé
1. Écrivez le code du modèle net.py
import torch
from torch import nn
import torch.nn.functional as F
class MyAlexNet(nn.Module):
def __init__(self):
super(MyAlexNet, self).__init__()
self.c1 = nn.Conv2d(in_channels=3, out_channels=48, kernel_size=11, stride=4, padding=2)
self.ReLU = nn.ReLU()
self.c2 = nn.Conv2d(in_channels=48, out_channels=128, kernel_size=5, stride=1, padding=2)
self.s2 = nn.MaxPool2d(2)
self.c3 = nn.Conv2d(in_channels=128, out_channels=192, kernel_size=3, stride=1, padding=1)
self.s3 = nn.MaxPool2d(2)
self.c4 = nn.Conv2d(in_channels=192, out_channels=192, kernel_size=3, stride=1, padding=1)
self.c5 = nn.Conv2d(in_channels=192, out_channels=128, kernel_size=3, stride=1, padding=1)
self.s5 = nn.MaxPool2d(kernel_size=3, stride=2)
self.flatten = nn.Flatten()
self.f6 = nn.Linear(4608, 2048)
self.f7 = nn.Linear(2048, 2048)
self.f8 = nn.Linear(2048, 1000)
self.f9 = nn.Linear(1000, 5)
def forward(self, x):
x = self.ReLU(self.c1(x))
x = self.ReLU(self.c2(x))
x = self.s2(x)
x = self.ReLU(self.c3(x))
x = self.s3(x)
x = self.ReLU(self.c4(x))
x = self.ReLU(self.c5(x))
x = self.s5(x)
x = self.flatten(x)
x = self.f6(x)
x = F.dropout(x, p=0.5)
x = self.f7(x)
x = F.dropout(x, p=0.5)
x = self.f8(x)
x = F.dropout(x, p=0.5)
x = self.f9(x)
return x
if __name__ == '__mian__':
x = torch.rand([1, 3, 224, 224])
model = MyAlexNet()
y = model(x)
2. Écrivez le modèle train.py
import os
import json
import torch
from PIL import Image
from torchvision import transforms
from model_v3 import mobilenet_v3_large
def main():
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
data_transform = transforms.Compose(
[transforms.Resize(256),
transforms.CenterCrop(224),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])])
# load image
# 指向需要遍历预测的图像文件夹
imgs_root = r"D:/other/ClassicalModel/data/flower_datas/train/tulips"
assert os.path.exists(imgs_root), f"file: '{
imgs_root}' dose not exist."
# 读取指定文件夹下所有jpg图像路径
img_path_list = [os.path.join(imgs_root, i) for i in os.listdir(imgs_root) if i.endswith(".jpg")]
# read class_indict
json_path = r"D:/other/ClassicalModel/ResNet/class_indices.json"
assert os.path.exists(json_path), f"file: '{
json_path}' dose not exist."
json_file = open(json_path, "r")
class_indict = json.load(json_file)
# create model
model = mobilenet_v3_large(num_classes=5).to(device)
# load model weights
weights_path = r"D:/other/ClassicalModel/MobileNet/runs12/mobilenet_v3_large.pth"
assert os.path.exists(weights_path), f"file: '{
weights_path}' dose not exist."
model.load_state_dict(torch.load(weights_path, map_location=device))
#save predicted img
filename = 'record.txt'
save_path = 'detect'
path_num = 1
while os.path.exists(save_path + f'{
path_num}'):
path_num += 1
os.mkdir(save_path + f'{
path_num}')
f = open(save_path + f'{
path_num}/' + filename, 'w')
f.write("imgs_root:"+imgs_root+"\n")
f.write("weights_path:"+weights_path+"\n")
actual_classes="tulips"
acc_num=0
all_num=len(img_path_list)
# prediction
model.eval()
batch_size = 8 # 每次预测时将多少张图片打包成一个batch
with torch.no_grad():
for ids in range(0, len(img_path_list) // batch_size):
img_list = []
for img_path in img_path_list[ids * batch_size: (ids + 1) * batch_size]:
assert os.path.exists(img_path), f"file: '{
img_path}' dose not exist."
img = Image.open(img_path)
img = data_transform(img)
img_list.append(img)
# batch img
# 将img_list列表中的所有图像打包成一个batch
batch_img = torch.stack(img_list, dim=0)
# predict class
output = model(batch_img.to(device)).cpu()
predict = torch.softmax(output, dim=1)
probs, classes = torch.max(predict, dim=1)
for idx, (pro, cla) in enumerate(zip(probs, classes)):
print("image: {} class: {} prob: {:.3}".format(img_path_list[ids * batch_size + idx],
class_indict[str(cla.numpy())],
pro.numpy()))
f.write("image: {} class: {} prob: {:.3}\n".format(img_path_list[ids * batch_size + idx],
class_indict[str(cla.numpy())],
pro.numpy()))
if class_indict[str(cla.numpy())]==actual_classes:
acc_num+=1
print("classes:{},acc_num:{:d},all_num:{:d},accuracy: {:.3f}".format(actual_classes,acc_num,all_num,acc_num/all_num))
f.write("classes:{},acc_num:{:d},all_num:{:d},accuracy: {:.3f}".format(actual_classes,acc_num,all_num,acc_num/all_num))
f.close()
if __name__ == '__main__':
main()