Научите, как использовать PyTorch для реализации классификации изображений

PyTorch
Научите, как использовать PyTorch для реализации классификации изображений

Написано впереди: полный код можно получить, подписавшись на мою официальную учетную запись [Thumb Note] и ответив на «softmax_py» в фоновом режиме.

Эффект узнавания:

1. Регрессия Softmax

Эта часть разделена на четыре части: концепция регрессионной модели softmax, концепция набора данных классификации изображений, реализация регрессионной модели softmax и реализация регрессионной модели softmax на основе pytorch framework.

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

1.1 Проблемы классификации

Например, простая задача классификации изображений, входная графика имеет высоту и ширину 2 пикселя, а цвет — оттенки серого (значение пикселя изображения в градациях серого может быть представлено скаляром). Обозначим значения четырех пикселей изображения как x1,x2,x3,x4. Предположим, что реальными метками изображений в обучающем наборе данных являются собаки, кошки и куры, и эти метки соответствуют дискретным значениям y1, y2 и y3 соответственно.

Обычно мы используем дискретные значения для представления категорий, таких как y1=1, y2=2, y3=3. Изображение помечено одним из значений 1, 2 и 3. Для такого рода задач мы обычно используем модель, которая больше подходит для дискретного вывода, чтобы решить проблему классификации.

1.2 модель регрессии softmax

Как и в модели регрессии softmax, входные признаки и веса накладываются линейно. Основное отличие от линейной регрессии в том, что количество выходных значений регрессии softmax равно количеству категорий в метке.

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

Метки дискретных значений (o). Итак, содержит 12 весов (w) и 3 смещения (b).

o_1=w_{11}x_1+w_{21}x_2+w_{31}x_3+w_{41}x_4+b_1, \\o_2=w_{12}x_1+w_{22}x_2+w_{32}x_3+w_{42}x_4+b_2, \\o_3=w_{13}x_1+w_{23}x_2+w_{33}x_3+w_{43}x_4+b_3, \\w下标命名规则: \\不同列代表不同输出类型,不同行代表不同像素点。 \\列数代表真实输出的类别数;行数代表特征数。

Регрессия Softmax также является однослойной нейронной сетью, и расчет каждого выхода o зависит от всех входов x, поэтому выходной слой регрессии softmax также является полносвязным слоем.

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

arg_imaxo_i

Например, o1, o2 и o3 равны соответственно 0,1, 10 и 0,1. Поскольку o2 является наибольшим, прогнозируемая категория равна 2.

Но есть две проблемы с этим подходом

  1. Диапазон выходных значений выходного слоя неопределен, и трудно просто судить о значении этих значений

    Например, когда три значения равны 0,1, 10 и 0,1, 10 означает «очень уверенно», а когда три значения — 1000, 10 и 1000, 10 означает «невероятно».

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

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

\hat{y_1},\hat{y_2},\hat{y_3}=softmax(o_1,o_2,o_3)

в

\hat{y_1}=\frac{exp(0_1)}{\sum_{i=1}^3exp(xi)},\ \  \hat{y_2}=\frac{exp(0_2)}{\sum_{i=1}^3exp(xi)},\ \  \hat{y_3}=\frac{exp(0_3)}{\sum_{i=1}^3exp(xi)}

очень легко увидеть

\hat{y_1}+\hat{y_2}+\hat{y_3}=1 \\且0\leq\hat{y_1},\hat{y_2},\hat{y_3}\leq1

На основе двух приведенных выше уравнений y1, y2 и y3 являются допустимыми распределениями вероятностей. Например: y2=0,8, то неважно, какие y1 и y3, мы все знаем, что вероятность быть второй категорией составляет 80%

так как

arg_imaxo_i = arg_imax\hat{y_i}

Известно, что операция softmax не изменяет вывод прогнозируемой категории.

1.3 Выражение векторного расчета для одновыборочной классификации

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

W =  \left\{ \begin{matrix} w_{11}\ w_{12} \ w_{13} \\w_{21}\ w_{22} \ w_{23} \\w_{31}\ w_{32} \ w_{33} \\w_{41}\ w_{42} \ w_{43} \end{matrix} \right\} ,\ \ b=[b_1 \ b_2\ b_3]

Пусть характеристики образца изображения i высотой и шириной 2 пикселя соответственно равны

x^{(i)}=[x^{(i)}_1 \ x^{(i)}_2 \ x^{(i)}_3 \ x^{(i)}_4]

Выход выходного слоя

o^{i} = [o_1^{i} \ o_2^{i} \ o_3^{i}]

Прогнозируемое распределение вероятностей

\hat{y}^{(i)}=[\hat{y}^{(i)}_1 \ \hat{y}^{(i)}_2 \ \hat{y}^{(i)}_3]

Наконец, выражение векторного расчета для классификации выборки i с помощью регрессии softmax:

o^{(i)}=x^{(i)}W+b \\ \hat{y}^{(i)}=softmax(o^{(i)})

Для данного образца мини-партии существует

O = XW+b \\\hat{Y}=softmax(O)

1.4 Функция кросс-энтропийных потерь

После использования операции softmax удобнее считать ошибку на дискретной метке. Истинная метка также может быть преобразована в допустимое распределение вероятностей, то есть: для выборки (изображения), чей истинный класс y_i, мы устанавливаем y_i равным 1, а остальные равными 0. Если изображение кошки (второе), его y = [0 1 0]. Это делает \hat{y} ближе к y.

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

Мы используем функцию кросс-энтропии для расчета потерь.

H(y^{(i)},\hat{y}^{(i)})=-\sum_{j=1}^q y_j^{(i)}log\ \hat{y}^{(i)}_j

В этой формуле y^(i) _j — элемент истинной вероятности метки, равной 1, а \hat{y}^{(i)}_j — соответствующий элемент предсказанной вероятности класса.

Поскольку в y ^ (i) есть только одна метка, в y ^ {i} все элементы, кроме y ^ (i) _j, равны 0, поэтому получается упрощенное уравнение приведенной выше формулы.

H(y^{(i)},\hat{y}^{(i)}) =- log\  \hat{y}^{(i)}_j

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

Для всей выборки функция кросс-энтропийных потерь определяется как

l(\theta) =\frac{1}{n} \sum_{i=1}^n H(y^{(i)},\hat{y}^{(i)})

Где \theta представляет параметры модели, если у каждого образца есть только одна метка, приведенную выше формулу можно упростить как

l(\theta) =-\frac{1}{n} \sum_{i=1}^nlog\  \hat{y}^{(i)}_j

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

2. Набор данных классификации изображений (Fashion-MNIST)

Для этой главы требуется пакет torchvision, для которого я переустановил

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

В этом разделе в основном используется пакет torchvision, который в основном используется для построения моделей компьютерного зрения.

Основные компоненты пакета torchvision Функции
torchvision.datasets Некоторые функции для загрузки данных и общие интерфейсы наборов данных
torchvision.madels Содержит часто используемые структуры моделей (включая предварительно обученные модели)
torchvision.transforms Общие преобразования изображений (обрезка, поворот)
torchvision.utils Другие методы

2.1 Получить набор данных

Сначала импортируйте необходимые пакеты

import torch 
import torchvision
import torchvision.transforms as transforms
import matplotlib.pyplot as plt
import time
import sys
sys.path.append("..")	
#调用库时,sys.path会自动搜索路径,为了导入d2l这个库,所以需要添加".."
#import d2lzh_pytorch as d2l	这个库找不到不用了
from IPython import display
#在这一节d2l库仅仅在绘图时被使用,因此使用这个库做替代

** Загрузите этот набор данных, вызвав torchvision.datasets в torchvision. **Первый вызов автоматически извлекает данные из Интернета.

Установив параметр train, вы можете указать получение набора данных для обучения или набора тестовых данных (набор тестов: используется для оценки производительности модели, не используется для обучения модели).

Преобразуйте все данные в тензор, установив параметр transfrom = transforms.ToTensor(), если нет, верните изображение PIL.

Функция transforms.ToTensor() преобразует изображение PIL размером (H*W*C) и данные между [0,255] или массив NumPy с типом данных np.uint8 в размер (C*H*W) и тензор данных. типа torch.float32 в [0,0,1.0]

C представляет количество каналов, а количество каналов в изображении в градациях серого равно 1.

Изображение PIL является стандартом для Python для обработки изображений.

Примечание. Функция transforms.ToTensor() по умолчанию устанавливает тип ввода uint8.

#获取训练集
mnist_train = torchvision.datasets.FashionMNIST(root='~/Datasets/FashionMNIST',train=True,download = True,transform = transforms.ToTensor())
#获取测试集
mnist_test = torchvision.datasets.FashionMNIST(root='~/Datasets/FashionMNIST',train=True,download = True,transform = transforms.ToTensor())

Среди них mnist_train и mnist_test могут использовать len() для получения размера набора данных, а также могут использовать индексы для получения конкретной выборки.

И обучающий набор, и тестовый набор имеют по 10 категорий, количество изображений в каждой категории в обучающем наборе равно 6000, а количество изображений в каждой категории в тестовом наборе равно 1000, то есть в наборе 60 000 образцов. обучающий набор и 10 000 образцов в тестовом наборе.

len(mnist_train)	#输出训练集的样本数
mnist_train[0]		#通过下标访问任意一个样本,返回值为两个torch,一个特征tensor和一个标签tensor

В наборе данных Fashion-MNIST имеется десять категорий, а именно: футболка (футболка), брюки (брюки), пуловер (пуловер), платье (платье), пальто (пальто), сандалии (сандалии), рубашка (рубашка ), кроссовки (кроссовки), сумка (сумка) и ботильоны (сапоги).

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

def get_fashion_mnist_labels(labels):
    text_labels = ['t-shirt', 'trouser', 'pullover', 'dress', 'coat',
                   'sandal', 'shirt', 'sneaker', 'bag', 'ankle boot']
    return [text_labels[int(i)] for i in labels]
	#labels是一个列表
	#数值标签转文本标签

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

def show_fashion_mnist(images, labels):
    d2l.use_svg_display()
   	#绘制矢量图
    _, figs = plt.subplots(1, len(images), figsize=(12, 12))
    #创建子图,一行len(images)列,图片大小12*12
    for f, img, lbl in zip(figs, images, labels):
        #zip函数将他们压缩成由多个元组组成的列表
        f.imshow(img.view((28, 28)).numpy())
        #将img转形为28*28大小的张量,然后转换成numpy数组
        f.set_title(lbl)
        #设置每个子图的标题为标签
        f.axes.get_xaxis().set_visible(False)
        f.axes.get_yaxis().set_visible(False)
        #关闭x轴y轴
    plt.show()

Использование вышеуказанных функций

X,y = [],[]
#初始化两个列表
for i in range(10):
	X.append(mnist_train[i][0])
	#循环向X列表添加图像
	y.append(mnist_train[i][1])
	#循环向y列表添加标签
show_fashion_mnist(X,get_fashion_mnist_labels(y))
#显示图像和列表

2.2 Чтение небольших партий

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

Загрузчик данных также поддерживает многопоточное чтение данных, устанавливая свой параметр num_workers.

batch_size = 256
#小批量数目
train_iter = torch.utils.data.DataLoader(mnist_train,batch_size=batch_size,shuffle = True,num_workers = 0)
#num_workers=0,不开启多线程读取。
test_iter = torch.utils.data.DataLoader(mnist_test,batch_size = batch_size,shuffle=False,num_workers=0)

3. Используйте pytorch для реализации модели регрессии softmax.

Использование pytorch может быть более удобным для реализации модели регрессии softmax.

3.1 Получение и чтение данных

Как читать небольшие пакеты данных:

  1. Во-первых, это получение данных. pytorch может легко получить набор данных Fashion-MNIST с помощью следующего кода.

    mnist_train = torchvision.datasets.FashionMNIST(root='~/Datasets/FashionMNIST',train=True,download=True,transform=transforms.ToTensor())
    
    mnist_test = torchvision.datasets.FashionMNIST(root='~/Datasets/FashionMNIST',train=False,download=True,transform=transforms.ToTensor())
    
    #参数
    
    #root : processed/training.pt 和 processed/test.pt 的主目录 
    #train : True = 训练集, False = 测试集
    #download : True = 从互联网上下载数据集,并把数据集放在root目录下. 如果数据集之前下载过,将处理过的数据(minist.py中有相关函数)放在processed文件夹下
    #transform = transforms.ToTensor():使所有数据转换为Tensor
    
  2. Затем создайте итератор для чтения данных

    #生成迭代器
    train_iter = torch.utils.data.DataLoader(mnist_train,batch_size=batch_size,shuffle = True,num_workers = 0)
    
    test_iter = torch.utils.data.DataLoader(mnist_test,batch_size = batch_size,shuffle=False,num_workers=0)
    #参数
    
    #dataset:Dataset类型,从其中加载数据
    #batch_size:int类型,每个批量加载多少个数
    #shuffle:bool类型,每个学习周期都打乱顺序
    #num_workers:int类型,加载数据时使用多少子进程。默认值为0.
    #collate_fn:定义如何取样本,可通过定义自己的函数来实现。
    #pin_memory:锁页内存处理。
    #drop_last:bool类型,如果有剩余的样本,True表示丢弃;Flase表示不丢弃
    

3.2 Определение и инициализация модели

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

o_1=w_{11}x_1+w_{21}x_2+w_{31}x_3+w_{41}x_4+b_1, \\o_2=w_{12}x_1+w_{22}x_2+w_{32}x_3+w_{42}x_4+b_2, \\o_3=w_{13}x_1+w_{23}x_2+w_{33}x_3+w_{43}x_4+b_3,
  1. Сначала определите сеть, регрессия softmax представляет собой двухслойную сеть, поэтому необходимо определить только входной и выходной слои.
num_inputs = 784
num_outputs = 10

class LinearNet(nn.Module):
    def __init__(self,num_inputs,num_outputs):
        super(LinearNet,self).__init__()
        self.linear = nn.Linear(num_inputs,num_outputs)
        #定义一个输入层
        
    #定义向前传播(在这个两层网络中,它也是输出层)
    def forward(self,x):
        y = self.linear(x.view(x.shape[0],-1))
        #将x换形为y后,再继续向前传播
        return y
    
net = LinearNet(num_inputs,num_outputs)
  1. Параметры инициализации

Используйте init в torch.nn для быстрой инициализации параметров. Мы устанавливаем параметр веса как нормальное распределение со средним значением 0 и стандартным отклонением 0,01. Смещение равно 0.

init.normal_(net.linear.weight, mean=0, std=0.01)
init.constant_(net.linear.bias, val=0) 

3.3 операция softmax и функция потери перекрестной энтропии

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

loss = nn.CrossEntropyLoss()

3.4 Определение алгоритма оптимизации

Все еще использую мини-пакетный стохастический градиентный спуск в качестве алгоритма оптимизации. Определите скорость обучения как 0,1.

optimizer = torch.optim.SGD(net.parameters(),lr=0.01)

3.5 Расчет точности классификации

Принцип расчета показателя точности:

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

Сначала нам нужно получить прогнозируемый результат.

Найдите индекс, соответствующий наибольшей вероятности, из набора предсказанных вероятностей (переменная y_hat) (индекс представляет категорию)

#argmax(f(x))函数,对f(x)求最大值所对应的点x。我们令f(x)= dim=1,即可实现求所有行上的最大值对应的索引。
A = y_hat.argmax(dim=1)	
#最终输出结果为一个行数与y_hat相同的列向量

Затем нам нужно сравнить категорию, соответствующую полученной максимальной вероятности, с реальной категорией (y), чтобы определить, верен ли прогноз.

B = (y_hat.argmax(dim=1)==y).float()
#由于y_hat.argmax(dim=1)==y得到的是ByteTensor型数据,所以我们通过.float()将其转换为浮点型Tensor()

Наконец, нам нужно рассчитать точность классификации

Мы знаем, что количество строк y_hat соответствует общему количеству выборок, поэтому среднее значение B является точностью классификации.

(y_hat.argmax(dim=1)==y).float().mean()

Окончательные данные, полученные на предыдущем шаге, имеют вид тензора(х), и чтобы получить итоговое число pytorch, необходимо выполнить над ним следующую операцию.

(y_hat.argmax(dim=1)==y).float().mean().item()
#pytorch number的获取统一通过.item()实现

Разберитесь и получите рассчитанную функцию точности классификации

def accuracy(y_hat,y):
    return (y_hat.argmax(dim=1).float().mean().item())

В качестве расширения эта функция также может оценивать точность сети модели в наборе данных data_iter.

def net_accurary(data_iter,net):
    right_sum,n = 0.0,0
    for X,y in data_iter:
    #从迭代器data_iter中获取X和y
        right_sum += (net(X).argmax(dim=1)==y).float().sum().item()
        #计算准确判断的数量
        n +=y.shape[0]
        #通过shape[0]获取y的零维度(列)的元素数量
    return right_sum/n

3.6 Обучение модели

num_epochs = 5
#一共进行五个学习周期

def train_softmax(net,train_iter,test_iter,loss,num_epochs,batch_size,optimizer,net_accurary):
    for epoch in range(num_epochs):
        #损失值、正确数量、总数 初始化。
        train_l_sum,train_right_sum,n= 0.0,0.0,0
        
        for X,y in train_iter:
            y_hat = net(X)
            l = loss(y_hat,y).sum()
            #数据集损失函数的值=每个样本的损失函数值的和。            
            optimizer.zero_grad()			#对优化函数梯度清零
            l.backward()	#对损失函数求梯度
            optimizer(params,lr,batch_size)
            
            train_l_sum += l.item()
            train_right_sum += (y_hat.argmax(dim=1) == y).sum().item()
            n += y.shape[0]
            
        test_acc = net_accurary(test_iter, net)	#测试集的准确率
        print('epoch %d, loss %.4f, train right %.3f, test acc %.3f' % (epoch + 1, train_l_sum / n, train_right_sum / n, test_acc))
        
train_softmax(net,train_iter,test_iter,cross_entropy,num_epochs,batch_size,optimizernet_accurary,net_accurary)

тренировочный эффект

3.7 Классификация изображений

Используйте обученную модель, чтобы делать прогнозы на тестовом наборе

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

#将样本的类别数字转换成文本
def get_Fashion_MNIST_labels(labels):
    text_labels = ['t-shirt', 'trouser', 'pullover', 'dress', 'coat',
                   'sandal', 'shirt', 'sneaker', 'bag', 'ankle boot']
    return [text_labels[int(i)] for i in labels]
    #labels是一个列表,所以有了for循环获取这个列表对应的文本列表

#显示图像
def show_fashion_mnist(images,labels):
    display.set_matplotlib_formats('svg')
    #绘制矢量图
    _,figs = plt.subplots(1,len(images),figsize=(12,12))
    #设置添加子图的数量、大小
    for f,img,lbl in zip(figs,images,labels):
        f.imshow(img.view(28,28).numpy())
        f.set_title(lbl)
        f.axes.get_xaxis().set_visible(False)
        f.axes.get_yaxis().set_visible(False)
    plt.show()

#从测试集中获得样本和标签
X, y = iter(test_iter).next()

true_labels = get_Fashion_MNIST_labels(y.numpy())
pred_labels = get_Fashion_MNIST_labels(net(X).argmax(dim=1).numpy())

#将真实标签和预测得到的标签加入到图像上
titles = [true + '\n' + pred for true, pred in zip(true_labels, pred_labels)]

show_fashion_mnist(X[0:9], titles[0:9])

добиться эффекта

Первая строка — это метка истинности, а вторая — идентификационная метка.