[pytoch practice] use CNN image classification

Time:2021-8-21

[pytoch practice] use CNN image classification

demand

In 4 * 4 pictures, compare the number of black pixels on the periphery and the number of black pixels on the inner circle to classify the pictures

[pytoch practice] use CNN image classification

As shown in the figure above, 5 black pixels on the periphery of the picture are larger than 1 black pixel on the inner circle, which is divided into category 0 and category 1 on the contrary

idea

  1. 4 * 4 image data set is constructed through numpy and PIL
  2. Construct your own dataset class
  3. Read data set to reduce skew of data set selection
  4. CNN design is directly 1 * 1 convolution layer because of few features
  5. Or add padding around 4 * 4 to 6 * 6, design 2*The convolution kernel of 2 yields 3*3. Connect the full connection layer

code

import torch
import torchvision
import torchvision.transforms as transforms
import numpy as np
from PIL import Image

Construct dataset

import csv
import collections
import os
import shutil

def buildDataset(root,dataType,dataSize):
    "" "construct dataset" ""
    The constructed image is saved to root / {datatype} data
    Save the CSV file of image address and label to root / {datatype} datainfo.csv
    Args:
        root:str
            Project directory
        dataType:str
            'train 'or' test '
        dataNum:int
            data size
    Returns:
    """
    dataInfo = []
    dataPath = f'{root}/{dataType}Data'
    if not os.path.exists(dataPath):
        os.makedirs(dataPath)
    else:
        shutil.rmtree(dataPath)
        os.mkdir(dataPath)
        
    for i in range(dataSize):
        #Create 0, 1 array
        imageArray=np.random.randint(0,2,(4,4))
        #Calculate the quantity of 0 and 1 to get the label
        allBlackNum = collections.Counter(imageArray.flatten())[0]
        innerBlackNum = collections.Counter(imageArray[1:3,1:3].flatten())[0]
        label = 0 if (allBlackNum-innerBlackNum)>innerBlackNum else 1
        #Save picture
        path = f'{dataPath}/{i}.jpg'
        dataInfo.append([path,label])
        im = Image.fromarray(np.uint8(imageArray*255))
        im = im.convert('1') 
        im.save(path)
    #Save the picture address and label into CSV file
    filePath = f'{root}/{dataType}DataInfo.csv'
    with open(filePath, 'w') as f:
        writer = csv.writer(f)
        writer.writerows(dataInfo)
root=r'/Users/null/Documents/PythonProject/Classifier'
Construct training data set
buildDataset(root,'train',20000)
Construct test data set
buildDataset(root,'test',10000)

Read dataset

class MyDataset(torch.utils.data.Dataset):

    def __init__(self, root, datacsv, transform=None):
        super(MyDataset, self).__init__()
        with open(f'{root}/{datacsv}', 'r') as f:
            imgs = []
            #Read CSV information to IMGs list
            for path,label in map(lambda line:line.rstrip().split(','),f):
                imgs.append((path, int(label)))
        self.imgs = imgs
        self.transform = transform if transform is not None else lambda x:x
        
    def __getitem__(self, index):
        path, label = self.imgs[index]
        img = self.transform(Image.open(path).convert('1'))
        return img, label

    def __len__(self):
        return len(self.imgs)
trainData=MyDataset(root = root,datacsv='trainDataInfo.csv', transform=transforms.ToTensor())
testData=MyDataset(root = root,datacsv='testDataInfo.csv', transform=transforms.ToTensor())
Process the dataset so that the dataset is not skewed
import itertools

def chooseData(dataset,scale):
    #Sort items with category 1 to the front
    dataset.imgs.sort(key=lambda x:x[1],reverse=True)
    #Get the number of category 1, take the array of times scale, and get that the data is not so skewed
    trueNum =collections.Counter(itertools.chain.from_iterable(dataset.imgs))[1]
    end = min(trueNum*scale,len(dataset))
    dataset.imgs=dataset.imgs[:end]
scale = 4
chooseData(trainData,scale)
chooseData(testData,scale)
len(trainData),len(testData)
(2250, 1122)



import torch.utils.data as Data

#Super parameter
batchSize = 50
lr = 0.1
numEpochs = 20

trainIter = Data.DataLoader(dataset=trainData, batch_size=batchSize, shuffle=True)
testIter = Data.DataLoader(dataset=testData, batch_size=batchSize)

Define model

from torch import nn
from torch.autograd import Variable
from torch.nn import Module,Linear,Sequential,Conv2d,ReLU,ConstantPad2d
import torch.nn.functional as F
class Net(Module):   
    def __init__(self):
        super(Net, self).__init__()

        self.cnnLayers = Sequential(
            #Padding adds 1 layer constant 1 and sets the convolution kernel to 2 * 2
            ConstantPad2d(1, 1),
            Conv2d(1, 1, kernel_size=2, stride=2,bias=True)
        )
        self.linearLayers = Sequential(
            Linear(9, 2)
        )

    def forward(self, x):
        x = self.cnnLayers(x)
        x = x.view(x.shape[0], -1)
        x = self.linearLayers(x)
        return x
class Net2(Module):   
    def __init__(self):
        super(Net2, self).__init__()

        self.cnnLayers = Sequential(
            Conv2d(1, 1, kernel_size=1, stride=1,bias=True)
        )
        self.linearLayers = Sequential(
            ReLU(),
            Linear(16, 2)
        )

    def forward(self, x):
        x = self.cnnLayers(x)
        x = x.view(x.shape[0], -1)
        x = self.linearLayers(x)
        return x

Define loss function

#Cross entropy loss function
loss = nn.CrossEntropyLoss()
loss2 = nn.CrossEntropyLoss()

Define optimization algorithm

net = Net()
optimizer = torch.optim.SGD(net.parameters(),lr = lr)
net2 = Net2()
optimizer2 = torch.optim.SGD(net2.parameters(),lr = lr)

Training model

#Calculation accuracy
def evaluateAccuracy(dataIter, net):
    accSum, n = 0.0, 0
    with torch.no_grad():
        for X, y in dataIter:
            accSum += (net(X).argmax(dim=1) == y).float().sum().item()
            n += y.shape[0]
    return accSum / n
def train(net, trainIter, testIter, loss, numEpochs, batchSize,
             optimizer):
    for epoch in range(numEpochs):
        trainLossSum, trainAccSum, n = 0.0, 0.0, 0
        for X,y in trainIter:
            yHat = net(X)
            l = loss(yHat,y).sum()
            optimizer.zero_grad()
            l.backward()
            optimizer.step()
            #Calculate training accuracy and loss
            trainLossSum += l.item()
            trainAccSum += (yHat.argmax(dim=1) == y).sum().item()
            n += y.shape[0]
        #Evaluate test accuracy
        testAcc = evaluateAccuracy(testIter, net)
        print('epoch {:d}, loss {:.4f}, train acc {:.3f}, test acc {:.3f}'.format(epoch + 1, trainLossSum / n, trainAccSum / n, testAcc))
Net model training
train(net, trainIter, testIter, loss, numEpochs, batchSize,optimizer)
epoch 1, loss 0.0128, train acc 0.667, test acc 0.667
epoch 2, loss 0.0118, train acc 0.683, test acc 0.760
epoch 3, loss 0.0104, train acc 0.742, test acc 0.807
epoch 4, loss 0.0093, train acc 0.769, test acc 0.772
epoch 5, loss 0.0085, train acc 0.797, test acc 0.745
epoch 6, loss 0.0084, train acc 0.798, test acc 0.807
epoch 7, loss 0.0082, train acc 0.804, test acc 0.816
epoch 8, loss 0.0078, train acc 0.816, test acc 0.812
epoch 9, loss 0.0077, train acc 0.818, test acc 0.817
epoch 10, loss 0.0074, train acc 0.824, test acc 0.826
epoch 11, loss 0.0072, train acc 0.836, test acc 0.819
epoch 12, loss 0.0075, train acc 0.823, test acc 0.829
epoch 13, loss 0.0071, train acc 0.839, test acc 0.797
epoch 14, loss 0.0067, train acc 0.849, test acc 0.824
epoch 15, loss 0.0069, train acc 0.848, test acc 0.843
epoch 16, loss 0.0064, train acc 0.864, test acc 0.851
epoch 17, loss 0.0062, train acc 0.867, test acc 0.780
epoch 18, loss 0.0060, train acc 0.871, test acc 0.864
epoch 19, loss 0.0057, train acc 0.881, test acc 0.890
epoch 20, loss 0.0055, train acc 0.885, test acc 0.897

Net2 model training
# batchSize = 50 
# lr = 0.1
#Results at numepochs = 15
train(net2, trainIter, testIter, loss2, numEpochs, batchSize,optimizer2)
epoch 1, loss 0.0119, train acc 0.638, test acc 0.676
epoch 2, loss 0.0079, train acc 0.823, test acc 0.986
epoch 3, loss 0.0046, train acc 0.987, test acc 0.977
epoch 4, loss 0.0030, train acc 0.983, test acc 0.973
epoch 5, loss 0.0023, train acc 0.981, test acc 0.976
epoch 6, loss 0.0019, train acc 0.980, test acc 0.988
epoch 7, loss 0.0016, train acc 0.984, test acc 0.984
epoch 8, loss 0.0014, train acc 0.985, test acc 0.986
epoch 9, loss 0.0013, train acc 0.987, test acc 0.992
epoch 10, loss 0.0011, train acc 0.989, test acc 0.993
epoch 11, loss 0.0010, train acc 0.989, test acc 0.996
epoch 12, loss 0.0010, train acc 0.992, test acc 0.994
epoch 13, loss 0.0009, train acc 0.993, test acc 0.994
epoch 14, loss 0.0008, train acc 0.995, test acc 0.996
epoch 15, loss 0.0008, train acc 0.994, test acc 0.998

test

test = torch.Tensor([[[[0,0,0,0],[0,1,1,0],[0,1,1,0],[0,0,0,0]]],
                  [[[1,1,1,1],[1,0,0,1],[1,0,0,1],[1,1,1,1]]],
                  [[[0,1,0,1],[1,0,0,1],[1,0,0,1],[0,0,0,1]]],
                  [[[0,1,1,1],[1,0,0,1],[1,0,0,1],[0,0,0,1]]],
                  [[[0,0,1,1],[1,0,0,1],[1,0,0,1],[1,0,1,0]]],
                  [[[0,0,1,0],[0,1,0,1],[0,0,1,1],[1,0,1,0]]],
                  [[[1,1,1,0],[1,0,0,1],[1,0,1,1],[1,0,1,1]]]
                 ])

target=torch.Tensor([0,1,0,1,1,0,1])
test
tensor([[[[0., 0., 0., 0.],
          [0., 1., 1., 0.],
          [0., 1., 1., 0.],
          [0., 0., 0., 0.]]],

        [[[1., 1., 1., 1.],
          [1., 0., 0., 1.],
          [1., 0., 0., 1.],
          [1., 1., 1., 1.]]],

        [[[0., 1., 0., 1.],
          [1., 0., 0., 1.],
          [1., 0., 0., 1.],
          [0., 0., 0., 1.]]],

        [[[0., 1., 1., 1.],
          [1., 0., 0., 1.],
          [1., 0., 0., 1.],
          [0., 0., 0., 1.]]],

        [[[0., 0., 1., 1.],
          [1., 0., 0., 1.],
          [1., 0., 0., 1.],
          [1., 0., 1., 0.]]],

        [[[0., 0., 1., 0.],
          [0., 1., 0., 1.],
          [0., 0., 1., 1.],
          [1., 0., 1., 0.]]],

        [[[1., 1., 1., 0.],
          [1., 0., 0., 1.],
          [1., 0., 1., 1.],
          [1., 0., 1., 1.]]]])



with torch.no_grad():
    output = net(test)
    output2 = net2(test)
predictions =output.argmax(dim=1)
predictions2 =output2.argmax(dim=1)
#Comparison results
Print (f'net test results {predictions. EQ (target)} ')
Print (f'net2 test result {predictions2. EQ (target)} ')
Net test result tensor ([true, true, false, true, true, true])
Net2 test result tensor ([false, true, false, true, true, false, true])

Recommended Today

Swift advanced (XV) extension

The extension in swift is somewhat similar to the category in OC Extension can beenumeration、structural morphology、class、agreementAdd new features□ you can add methods, calculation attributes, subscripts, (convenient) initializers, nested types, protocols, etc What extensions can’t do:□ original functions cannot be overwritten□ you cannot add storage attributes or add attribute observers to existing attributes□ cannot add parent […]