4 совета по улучшению производительности модели глубокого обучения

глубокое обучение

вводить

Большую часть последних двух лет я довольно много работал в области глубокого обучения. Это был довольно хороший опыт, во время которого я работал над несколькими проектами, связанными с изображениями и видеоданными.

До этого я был на периферии, избегая таких концепций глубокого обучения, как обнаружение объектов и распознавание лиц. Только в конце 2017 года началось углубленное изучение. За это время я столкнулся со всевозможными трудностями. Я хотел бы коснуться четырех наиболее распространенных проблем, с которыми сталкиваются большинство практиков и энтузиастов глубокого обучения на своем пути.

Если вы уже работали над проектами глубокого обучения, вы можете быстро понять эти барьеры. Хорошая новость заключается в том, что преодолеть их не так сложно, как вы думаете!

В этой статье мы будем использовать очень практичный подход. Во-первых, мы будем основываться на четырех общих головоломках, о которых я упоминал выше. Затем мы погрузимся прямо в код Python, чтобы изучить ключевые советы и приемы для борьбы и преодоления этих проблем. Здесь есть что распаковать, так что давайте начнем!

содержание

  1. Общая дилемма для моделей глубокого обучения
  2. Обзор тематического исследования по классификации транспортных средств
  3. Узнайте о каждой проблеме и о том, как ее преодолеть, чтобы повысить производительность моделей глубокого обучения.
  4. Практический пример: повышение эффективности нашей модели классификации транспортных средств

Общая дилемма для моделей глубокого обучения

Модели глубокого обучения обычно очень хорошо работают с большинством данных. Когда дело доходит до данных изображения, модели глубокого обучения, особенно сверточные нейронные сети (CNN), превосходят почти все другие модели.

Мой обычный подход заключается в использовании модели CNN при столкновении с проектами, связанными с изображениями, такими как проекты классификации изображений.

Этот подход работает хорошо, но в некоторых случаях CNN или другие модели глубокого обучения не работают. Я сталкивался с этим несколько раз. Мои данные в порядке, архитектура модели определена правильно, функция потерь и оптимизатор настроены правильно, но моя модель не делает того, что я ожидаю.

Это распространенная дилемма, с которой сталкивается большинство из нас при работе с моделями глубокого обучения.

Как было сказано выше, я решу четыре таких головоломки:

  • Отсутствие данных для обучения
  • переоснащение
  • недооснащение
  • долгое время обучения

Прежде чем углубиться в эти загадки и разобраться в них, давайте кратко рассмотрим тематические исследования, которые мы рассмотрим в этой статье.

Обзор тематического исследования по классификации транспортных средств

Эта статья является частью серии статей о PyTorch для начинающих, которую я пишу. Вы можете ознакомиться с первыми тремя статьями здесь (мы приведем некоторые из них):

  • Начало работы с PyTorch
  • Построение моделей классификации изображений с использованием сверточных нейронных сетей в PyTorch
  • Перенос обучения с PyTorc

Мы продолжим чтение тематического исследования, которое мы видели в предыдущей статье. Цель здесь состоит в том, чтобы классифицировать изображения транспортных средств как срочные или несрочные.

Во-первых, давайте быстро построим модель CNN и используем ее в качестве эталона. Мы также постараемся улучшить производительность этой модели. Эти шаги очень просты, и мы видели их несколько раз в предыдущих статьях.

Поэтому я не буду вдаваться в каждый шаг здесь. Вместо этого мы сосредоточимся на коде, который вы всегда можете изучить более подробно в предыдущей статье, ссылку на которую я дал выше.Вы можете получить набор данных здесь: https://drive.Google.com/file//1EB vi send JP0FQ can B1 Axinba 7K Q26YP TW Mn EAP J/view.

Вот полный код для построения модели CNN для нашего проекта классификации транспортных средств.

библиотека импорта

# 导入库
import pandas as pd
import numpy as np
from tqdm import tqdm

# 用于读取和显示图像
from skimage.io import imread
from skimage.transform import resize
import matplotlib.pyplot as plt
%matplotlib inline

# 用于创建验证集
from sklearn.model_selection import train_test_split

# 用于评估模型
from sklearn.metrics import accuracy_score

# PyTorch库和模块
import torch
from torch.autograd import Variable
from torch.nn import Linear, ReLU, CrossEntropyLoss, Sequential, Conv2d, MaxPool2d, Module, Softmax, BatchNorm2d, Dropout
from torch.optim import Adam, SGD

# 预训练模型
from torchvision import models

Загрузить набор данных

# 加载数据集
train = pd.read_csv('emergency_train.csv')

# 加载训练图片
train_img = []
for img_name in tqdm(train['image_names']):
    # 定义图像路径
    image_path = '../Hack Session/images/' + img_name
    # 读取图片
    img = imread(image_path)
    # 标准化像素值
    img = img/255
    img = resize(img, output_shape=(224,224,3), mode='constant', anti_aliasing=True)
    # 转换为浮点数
    img = img.astype('float32')
    # 添加图片到列表
    train_img.append(img)

# 转换为numpy数组
train_x = np.array(train_img)
train_x.shape

Создание обучающих и проверочных наборов

# 定义目标
train_y = train['emergency_or_not'].values

# 创建验证集
train_x, val_x, train_y, val_y = train_test_split(train_x, train_y, test_size = 0.1, random_state = 13, stratify=train_y)
(train_x.shape, train_y.shape), (val_x.shape, val_y.shape)

Преобразование изображения в формат факела

# 转换训练图片到torch格式
train_x = train_x.reshape(1481, 3, 224, 224)
train_x  = torch.from_numpy(train_x)

# 转换目标到torch格式
train_y = train_y.astype(int)
train_y = torch.from_numpy(train_y)

# 转换验证图像到torch格式
val_x = val_x.reshape(165, 3, 224, 224)
val_x  = torch.from_numpy(val_x)

#  转换目标到torch格式
val_y = val_y.astype(int)
val_y = torch.from_numpy(val_y)

Определить архитектуру модели

torch.manual_seed(0)

class Net(Module):   
    def __init__(self):
        super(Net, self).__init__()

        self.cnn_layers = Sequential(
            # 定义2D卷积层
            Conv2d(3, 16, kernel_size=3, stride=1, padding=1),
            ReLU(inplace=True),
            MaxPool2d(kernel_size=2, stride=2),
            # 另一个2D卷积层
            Conv2d(16, 32, kernel_size=3, stride=1, padding=1),
            ReLU(inplace=True),
            MaxPool2d(kernel_size=2, stride=2)
        )

        self.linear_layers = Sequential(
            Linear(32 * 56 * 56, 2)
        )

    # 前项传播
    def forward(self, x):
        x = self.cnn_layers(x)
        x = x.view(x.size(0), -1)
        x = self.linear_layers(x)
        return x

Задайте параметры модели

# 定义模型
model = Net()
# 定义优化器
optimizer = Adam(model.parameters(), lr=0.0001)
# 定义损失函数
criterion = CrossEntropyLoss()
# 检查GPU是否可用
if torch.cuda.is_available():
    model = model.cuda()
    criterion = criterion.cuda()

print(model)

Обучите модель

torch.manual_seed(0)

# 模型batch大小
batch_size = 128

# epoch数
n_epochs = 25

for epoch in range(1, n_epochs+1):

    # 保持记录训练与验证集损失
    train_loss = 0.0
        
    permutation = torch.randperm(train_x.size()[0])

    training_loss = []
    for i in tqdm(range(0,train_x.size()[0], batch_size)):

        indices = permutation[i:i+batch_size]
        batch_x, batch_y = train_x[indices], train_y[indices]
        
        if torch.cuda.is_available():
            batch_x, batch_y = batch_x.cuda(), batch_y.cuda()
        
        optimizer.zero_grad()
        
        outputs = model(batch_x)
        loss = criterion(outputs,batch_y)

        training_loss.append(loss.item())
        loss.backward()
        optimizer.step()
        
    training_loss = np.average(training_loss)
    print('epoch: \t', epoch, '\t training loss: \t', training_loss)

Прогноз на тренировочном наборе

# 训练集预测
prediction = []
target = []
permutation = torch.randperm(train_x.size()[0])
for i in tqdm(range(0,train_x.size()[0], batch_size)):
    indices = permutation[i:i+batch_size]
    batch_x, batch_y = train_x[indices], train_y[indices]

    if torch.cuda.is_available():
        batch_x, batch_y = batch_x.cuda(), batch_y.cuda()

    with torch.no_grad():
        output = model(batch_x.cuda())

    softmax = torch.exp(output).cpu()
    prob = list(softmax.numpy())
    predictions = np.argmax(prob, axis=1)
    prediction.append(predictions)
    target.append(batch_y)
    
# 训练集精度
accuracy = []
for i in range(len(prediction)):
    accuracy.append(accuracy_score(target[i],prediction[i]))
    
print('training accuracy: \t', np.average(accuracy))

Прогноз на проверочном наборе

# 验证集预测
prediction_val = []
target_val = []
permutation = torch.randperm(val_x.size()[0])
for i in tqdm(range(0,val_x.size()[0], batch_size)):
    indices = permutation[i:i+batch_size]
    batch_x, batch_y = val_x[indices], val_y[indices]

    if torch.cuda.is_available():
        batch_x, batch_y = batch_x.cuda(), batch_y.cuda()

    with torch.no_grad():
        output = model(batch_x.cuda())

    softmax = torch.exp(output).cpu()
    prob = list(softmax.numpy())
    predictions = np.argmax(prob, axis=1)
    prediction_val.append(predictions)
    target_val.append(batch_y)
    
# 验证集精度
accuracy_val = []
for i in range(len(prediction_val)):
    accuracy_val.append(accuracy_score(target_val[i],prediction_val[i]))
    
print('validation accuracy: \t', np.average(accuracy_val))

Это наша модель CNN. Точность обучения составляет около 88%, а точность проверки близка к 70%.

Мы будем усердно работать, чтобы улучшить производительность этой модели. Но перед этим давайте на минутку разберемся в загадках, которые могут быть причиной такой низкой производительности.

Загадки глубокого обучения

Загадка глубокого обучения 1: отсутствие доступных данных для обучения наших моделей

Модели глубокого обучения обычно требуют больших объемов обучающих данных. Как правило, чем больше данных, тем лучше производительность модели. Проблема с нехваткой данных заключается в том, что наша модель глубокого обучения может быть не в состоянии изучить шаблоны или функции из данных, поэтому она может не дать хорошей производительности на невидимых данных.

Если вы посмотрите на пример классификации автомобилей, у нас есть только около 1650 изображений, поэтому эта модель не очень хорошо работает на проверочном наборе. Трудности с меньшим количеством данных распространены при работе с компьютерным зрением и моделями глубокого обучения.

Как вы понимаете, сбор данных вручную — утомительная и трудоемкая задача. Поэтому мы можем использоватьТехнология увеличения данныхВместо того, чтобы тратить дни на сбор данных.

Увеличение данных — это процесс создания новых данных или дополнения данных для обучения модели без фактического сбора новых данных.

Существуют различные методы улучшения данных для данных изображения, и обычно используемые методы улучшения включают вращение, сдвиг и отражение.

Это настолько хорошая тема, что я решил написать целую статью. Я планирую обсудить эти методы и их реализацию в PyTorch в следующей статье.

2: Переоснащение модели

Я уверен, что вы слышали о подгонке. Это одна из самых распространенных головоломок (и ошибок), которую допускают специалисты по данным, когда они плохо знакомы с машинным обучением. Но проблема на самом деле выходит за рамки области, и она также применима к глубокому обучению.

Когда модель очень хорошо работает на тренировочном наборе, но ухудшается на проверочном наборе (или невидимых данных), она считается переоснащенной.

Например, предположим, что у нас есть набор для обучения и набор для проверки. Мы используем обучающие данные для обучения модели и проверки ее производительности на обучающем и проверочном наборах (показатель оценки — точность). Точность обучения составляет 95 %, а точность проверочного набора — 62 %. Звучит знакомо?

Поскольку точность проверки намного ниже точности обучения, можно сделать вывод, что у модели есть проблема переобучения.. Следующий пример поможет вам лучше понять, что такое переобучение:

Часть, отмеченная синим цветом на рисунке выше, является моделью переобучения, потому что ошибка обучения очень мала, а ошибка теста очень высока. Причина переобучения заключается в том, что модель даже извлекает ненужную информацию из обучающих данных, поэтому она очень хорошо работает на обучающем наборе.

Однако он не будет выполняться при вводе новых данных.Мы можем ввести Dropout в архитектуру модели, чтобы решить проблему переобучения..

С помощью Dropout мы случайным образом отключаем определенные нейроны нейросети. Допустим, мы добавляем слой Dropout с вероятностью 0,5 к слою, в котором изначально было 20 нейронов, поэтому 10 из этих 20 нейронов будут подавлены, и в итоге мы получим менее сложную архитектуру.

Таким образом, модель не будет изучать слишком сложные закономерности и сможет избежать переобучения. Теперь добавим в нашу архитектуру слой Dropout и проверим его работоспособность.

Архитектура модели

torch.manual_seed(0)

class Net(Module):   
    def __init__(self):
        super(Net, self).__init__()

        self.cnn_layers = Sequential(
            # 定义2D卷积层
            Conv2d(3, 16, kernel_size=3, stride=1, padding=1),
            ReLU(inplace=True),
            MaxPool2d(kernel_size=2, stride=2),
            # Dropout层
            Dropout(),
            #另一个2D卷积层
            Conv2d(16, 32, kernel_size=3, stride=1, padding=1),
            ReLU(inplace=True),
            MaxPool2d(kernel_size=2, stride=2),
            # Dropout层
            Dropout(),
        )

        self.linear_layers = Sequential(
            Linear(32 * 56 * 56, 2)
        )

    # 前向传播  
    def forward(self, x):
        x = self.cnn_layers(x)
        x = x.view(x.size(0), -1)
        x = self.linear_layers(x)
        return x

Здесь я добавляю слой Dropout к каждому сверточному блоку. Значение по умолчанию равно 0,5, что означает, что половина нейронов будет отключена случайным образом. Это гиперпараметр, вы можете выбрать любое значение от 0 до 1.

Далее мы определим параметры модели, такие как функция потерь, оптимизатор и скорость обучения.

Параметры модели

# 定义模型
model = Net()
# 定义优化器
optimizer = Adam(model.parameters(), lr=0.0001)
# 定义损失函数
criterion = CrossEntropyLoss()
# 检查GPU是否可用
if torch.cuda.is_available():
    model = model.cuda()
    criterion = criterion.cuda()

print(model)

Здесь вы можете видеть, что значение по умолчанию в Dropout равно 0,5. Наконец, давайте обучим модель после добавления слоя Dropout:

Обучите модель

torch.manual_seed(0)

# 模型batch大小
batch_size = 128

# epoch数
n_epochs = 25

for epoch in range(1, n_epochs+1):

    # 保持记录训练与验证集损失
    train_loss = 0.0
        
    permutation = torch.randperm(train_x.size()[0])

    training_loss = []
    for i in tqdm(range(0,train_x.size()[0], batch_size)):

        indices = permutation[i:i+batch_size]
        batch_x, batch_y = train_x[indices], train_y[indices]
        
        if torch.cuda.is_available():
            batch_x, batch_y = batch_x.cuda(), batch_y.cuda()
        
        optimizer.zero_grad()
        
        outputs = model(batch_x)
        loss = criterion(outputs,batch_y)

        training_loss.append(loss.item())
        loss.backward()
        optimizer.step()
        
    training_loss = np.average(training_loss)
    print('epoch: \t', epoch, '\t training loss: \t', training_loss)

Теперь давайте проверим точность обучения и проверки, используя эту обученную модель.

Проверить работоспособность модели

# 
prediction = []
target = []
permutation = torch.randperm(train_x.size()[0])
for i in tqdm(range(0,train_x.size()[0], batch_size)):
    indices = permutation[i:i+batch_size]
    batch_x, batch_y = train_x[indices], train_y[indices]

    if torch.cuda.is_available():
        batch_x, batch_y = batch_x.cuda(), batch_y.cuda()

    with torch.no_grad():
        output = model(batch_x.cuda())

    softmax = torch.exp(output).cpu()
    prob = list(softmax.numpy())
    predictions = np.argmax(prob, axis=1)
    prediction.append(predictions)
    target.append(batch_y)
    
# 训练集精度
accuracy = []
for i in range(len(prediction)):
    accuracy.append(accuracy_score(target[i],prediction[i]))
    
print('training accuracy: \t', np.average(accuracy))

Опять же, давайте проверим точность набора проверки:

# 验证集预测
prediction_val = []
target_val = []
permutation = torch.randperm(val_x.size()[0])
for i in tqdm(range(0,val_x.size()[0], batch_size)):
    indices = permutation[i:i+batch_size]
    batch_x, batch_y = val_x[indices], val_y[indices]

    if torch.cuda.is_available():
        batch_x, batch_y = batch_x.cuda(), batch_y.cuda()

    with torch.no_grad():
        output = model(batch_x.cuda())

    softmax = torch.exp(output).cpu()
    prob = list(softmax.numpy())
    predictions = np.argmax(prob, axis=1)
    prediction_val.append(predictions)
    target_val.append(batch_y)
    
# 验证集精度
accuracy_val = []
for i in range(len(prediction_val)):
    accuracy_val.append(accuracy_score(target_val[i],prediction_val[i]))
    
print('validation accuracy: \t', np.average(accuracy_val))

Сравним с предыдущими результатами:

точность тренировочного набора
Проверка правильности набора
нет отсева
87.80 69.72
Имеет отсев
73.56 70.29

В приведенной выше таблице представлена ​​точность без выпадения и с выпадением. Если вы посмотрите на точность обучения и проверки моделей без пропусков, они не синхронизированы. Точность обучения слишком высока, а точность проверки низка. Так что это может быть примером переобучения.

Когда мы представили Dropout, точность набора для обучения и проверки была синхронизирована.Поэтому, если ваша модель переоснащена, вы можете попробовать добавить отсевающие слои, чтобы уменьшить сложность модели..

Количество добавляемых исключений — это гиперпараметр, которым вы можете управлять с помощью этого значения. Теперь давайте рассмотрим еще одну головоломку.

Задача глубокого обучения 3: Недообучение модели

Модели глубокого обучения также могут не соответствовать требованиям, как бы маловероятно это ни звучало.

Недообучение — это когда модель не может изучить шаблоны из самих обучающих данных и, следовательно, имеет более низкую производительность на обучающем наборе.

Это может быть связано с разными причинами, например, с недостатком данных для обучения, слишком простой архитектурой, обучением модели реже и т. д.

Чтобы решить проблему недообучения, вы можете попробовать следующие решения:

  1. добавить тренировочные данные
  2. сделать сложную модель
  3. Увеличить эпоху обучения

Для нашей задачи недообучение не является проблемой, поэтому мы перейдем к следующему способу повышения производительности моделей глубокого обучения.

Задача глубокого обучения 4: слишком долгое время обучения

В некоторых случаях вы можете обнаружить, что вашей нейронной сети требуется много времени для сходимости. Основная причина этого заключается в том, что изменилось распределение входных данных для слоев нейронной сети.

В процессе обучения меняются веса каждого слоя нейронной сети, а также активация. Теперь эти активации являются входными данными для следующего уровня, поэтому каждая последующая итерация меняет распределение.

Из-за этого изменения распределения каждый слой должен адаптироваться к изменяющимся входным данным, поэтому время обучения увеличивается.

Чтобы преодолеть эту проблему, мы можем применить пакетную нормализацию, при которой мы нормализуем активацию скрытых слоев и пытаемся создать такое же распределение.

Теперь добавим в схемуbatchnormслой и проверить его работоспособность на задаче классификации транспортных средств:

torch.manual_seed(0)

class Net(Module):   
    def __init__(self):
        super(Net, self).__init__()

        self.cnn_layers = Sequential(
            # 定义2D卷积层
            Conv2d(3, 16, kernel_size=3, stride=1, padding=1),
            ReLU(inplace=True),
            # BN层
            BatchNorm2d(16),
            MaxPool2d(kernel_size=2, stride=2),
            #另一个2D卷积层
            Conv2d(16, 32, kernel_size=3, stride=1, padding=1),
            ReLU(inplace=True),    
            # BN层
            BatchNorm2d(32),
            MaxPool2d(kernel_size=2, stride=2),
        )

        self.linear_layers = Sequential(
            Linear(32 * 56 * 56, 2)
        )

    # 前向传播  
    def forward(self, x):
        x = self.cnn_layers(x)
        x = x.view(x.size(0), -1)
        x = self.linear_layers(x)
        return x

Задайте параметры модели

# 定义模型
model = Net()
# 定义优化器
optimizer = Adam(model.parameters(), lr=0.00005)
# 定义损失函数
criterion = CrossEntropyLoss()
# 检查GPU是否可用
if torch.cuda.is_available():
    model = model.cuda()
    criterion = criterion.cuda()

print(model)

Давайте обучим модель

torch.manual_seed(0)

# 模型batch大小
batch_size = 128

# epoch数
n_epochs = 5

for epoch in range(1, n_epochs+1):

    # 保持记录训练与验证集损失
    train_loss = 0.0
        
    permutation = torch.randperm(train_x.size()[0])

    training_loss = []
    for i in tqdm(range(0,train_x.size()[0], batch_size)):

        indices = permutation[i:i+batch_size]
        batch_x, batch_y = train_x[indices], train_y[indices]
        
        if torch.cuda.is_available():
            batch_x, batch_y = batch_x.cuda(), batch_y.cuda()
        
        optimizer.zero_grad()
        
        outputs = model(batch_x)
        loss = criterion(outputs,batch_y)

        training_loss.append(loss.item())
        loss.backward()
        optimizer.step()
        
    training_loss = np.average(training_loss)
    print('epoch: \t', epoch, '\t training loss: \t', training_loss)

Очевидно, что модель способна очень быстро обучаться. В эпоху 5 наши потери при обучении составляют 0,3386, а после 25 эпох, когда мы не используем пакетную нормализацию, наши потери при обучении составляют 0,3851.

Поэтому введение пакетной нормализации определенно сокращает время обучения. Давайте проверим производительность на обучающем и проверочном наборах:

prediction = []
target = []
permutation = torch.randperm(train_x.size()[0])
for i in tqdm(range(0,train_x.size()[0], batch_size)):
    indices = permutation[i:i+batch_size]
    batch_x, batch_y = train_x[indices], train_y[indices]

    if torch.cuda.is_available():
        batch_x, batch_y = batch_x.cuda(), batch_y.cuda()

    with torch.no_grad():
        output = model(batch_x.cuda())

    softmax = torch.exp(output).cpu()
    prob = list(softmax.numpy())
    predictions = np.argmax(prob, axis=1)
    prediction.append(predictions)
    target.append(batch_y)
    
# 训练集精度
accuracy = []
for i in range(len(prediction)):
    accuracy.append(accuracy_score(target[i],prediction[i]))
    
print('training accuracy: \t', np.average(accuracy))

# 验证集预测
prediction_val = []
target_val = []
permutation = torch.randperm(val_x.size()[0])
for i in tqdm(range(0,val_x.size()[0], batch_size)):
    indices = permutation[i:i+batch_size]
    batch_x, batch_y = val_x[indices], val_y[indices]

    if torch.cuda.is_available():
        batch_x, batch_y = batch_x.cuda(), batch_y.cuda()

    with torch.no_grad():
        output = model(batch_x.cuda())

    softmax = torch.exp(output).cpu()
    prob = list(softmax.numpy())
    predictions = np.argmax(prob, axis=1)
    prediction_val.append(predictions)
    target_val.append(batch_y)
    
# 验证集精度
accuracy_val = []
for i in range(len(prediction_val)):
    accuracy_val.append(accuracy_score(target_val[i],prediction_val[i]))
    
print('validation accuracy: \t', np.average(accuracy_val))

Добавление пакетной нормализации может сократить время обучения, но здесь есть проблема. Вы можете понять, что это такое? Теперь модель переобучена, так как точность обучения составляет 91 %, а проверочного набора — 63 %. Помните, что мы не добавили выпадающий слой в последнюю модель.

Вот некоторые приемы, которые мы можем использовать для повышения производительности наших моделей глубокого обучения. Теперь давайте объединим все методы, которые мы уже изучили.

Практический пример: повышение эффективности модели классификации транспортных средств

Мы видели, как отсев и нормализация партии могут помочь уменьшить переоснащение и ускорить процесс обучения. Настало время объединить все эти методы и построить модель.

torch.manual_seed(0)

class Net(Module):   
    def __init__(self):
        super(Net, self).__init__()

        self.cnn_layers = Sequential(
            # 定义2D卷积层
            Conv2d(3, 16, kernel_size=3, stride=1, padding=1),
            ReLU(inplace=True),
            # BN层
            BatchNorm2d(16),
            MaxPool2d(kernel_size=2, stride=2),
            # 添加dropout
            Dropout(),
            #另一个2D卷积层
            Conv2d(16, 32, kernel_size=3, stride=1, padding=1),
            ReLU(inplace=True),
            # BN层
            BatchNorm2d(32),
            MaxPool2d(kernel_size=2, stride=2),
            # 添加dropout
            Dropout(),
        )

        self.linear_layers = Sequential(
            Linear(32 * 56 * 56, 2)
        )

    # 前向传播  
    def forward(self, x):
        x = self.cnn_layers(x)
        x = x.view(x.size(0), -1)
        x = self.linear_layers(x)
        return x

Теперь определим параметры модели:

# 定义模型
model = Net()
# 定义优化器
optimizer = Adam(model.parameters(), lr=0.00025)
# 定义损失函数
criterion = CrossEntropyLoss()
# 检查GPU是否可用
if torch.cuda.is_available():
    model = model.cuda()
    criterion = criterion.cuda()

print(model)

Наконец, давайте обучим модель:

torch.manual_seed(0)

# 模型batch大小
batch_size = 128

# epoch数
n_epochs = 10

for epoch in range(1, n_epochs+1):

    # 保持记录训练与验证集损失
    train_loss = 0.0
        
    permutation = torch.randperm(train_x.size()[0])

    training_loss = []
    for i in tqdm(range(0,train_x.size()[0], batch_size)):

        indices = permutation[i:i+batch_size]
        batch_x, batch_y = train_x[indices], train_y[indices]
        
        if torch.cuda.is_available():
            batch_x, batch_y = batch_x.cuda(), batch_y.cuda()
        
        optimizer.zero_grad()
        
        outputs = model(batch_x)
        loss = criterion(outputs,batch_y)

        training_loss.append(loss.item())
        loss.backward()
        optimizer.step()
        
    training_loss = np.average(training_loss)
    print('epoch: \t', epoch, '\t training loss: \t', training_loss)

Далее проверим работоспособность модели:

prediction = []
target = []
permutation = torch.randperm(train_x.size()[0])
for i in tqdm(range(0,train_x.size()[0], batch_size)):
    indices = permutation[i:i+batch_size]
    batch_x, batch_y = train_x[indices], train_y[indices]

    if torch.cuda.is_available():
        batch_x, batch_y = batch_x.cuda(), batch_y.cuda()

    with torch.no_grad():
        output = model(batch_x.cuda())

    softmax = torch.exp(output).cpu()
    prob = list(softmax.numpy())
    predictions = np.argmax(prob, axis=1)
    prediction.append(predictions)
    target.append(batch_y)
    
# 训练集精度
accuracy = []
for i in range(len(prediction)):
    accuracy.append(accuracy_score(target[i],prediction[i]))
    
print('training accuracy: \t', np.average(accuracy))

# 验证集预测
prediction_val = []
target_val = []
permutation = torch.randperm(val_x.size()[0])
for i in tqdm(range(0,val_x.size()[0], batch_size)):
    indices = permutation[i:i+batch_size]
    batch_x, batch_y = val_x[indices], val_y[indices]

    if torch.cuda.is_available():
        batch_x, batch_y = batch_x.cuda(), batch_y.cuda()

    with torch.no_grad():
        output = model(batch_x.cuda())

    softmax = torch.exp(output).cpu()
    prob = list(softmax.numpy())
    predictions = np.argmax(prob, axis=1)
    prediction_val.append(predictions)
    target_val.append(batch_y)
    
# 验证集精度
accuracy_val = []
for i in range(len(prediction_val)):
    accuracy_val.append(accuracy_score(target_val[i],prediction_val[i]))
    
print('validation accuracy: \t', np.average(accuracy_val))

Точность проверки значительно улучшилась до 73%. чудесный!

конец

В этом посте мы рассмотрим различные проблемы, с которыми можно столкнуться при использовании моделей глубокого обучения, таких как CNN. Мы также узнали решения всех этих сложных проблем и, в конце концов, построили модель, используя эти решения.

После того, как мы добавили эти методы в модель, точность модели на проверочном наборе улучшилась. Всегда есть место для улучшения, вот несколько вещей, которые вы можете попробовать:

  • Отрегулируйте процент отсева
  • Увеличьте или уменьшите количество сверточных слоев
  • Увеличьте или уменьшите количество плотных слоев
  • Отрегулируйте количество нейронов в скрытом слое и т. д.