This is the 16th day of my participation in Gwen Challenge

directory

I. Open Source Neural Network (AlexNet)

1. Obtain the data set

2. Neural network model

3. Train the neural network

4. Predict the model

Ii. Construction of flower Identification System (Flask)

1. Build the page:

2. Invoke the neural network model

3. System identification results

4. Start the system:

Third, summary

Why do we have this flower recognition system?

This semester, I took an optional course of machine vision, which was designed as a neural network for flower recognition. Therefore, I found the open source code on the Internet and modified it. Finally, I successfully ran it, with only one accuracy rate (94%).

Since we have run the code of this neural network, we should simply use this neural network. For this reason, I continue to write the code and make this neural network into a visual interface (flower recognition system).

I. Open Source Neural Network (AlexNet)

1. Obtain the data set

Using the steps below: * (1) under the data_set folder to create a new folder “flower_data” * (2) click the link to download the flower classification dataset download.tensorflow.org/example\_im… * (3) Unpack the dataset into flower_data folder * (4) execute the “split_data.py” script to automatically divide the dataset into train and val

split_data.py

import os
from shutil import copy, rmtree
import random
 
 
def mk_file(file_path: str) :
    if os.path.exists(file_path):
        If the folder exists, delete the original folder before creating a new one
        rmtree(file_path)
    os.makedirs(file_path)
 
 
def main() :
    # Guarantee random reproducibility
    random.seed(0)
 
    Divide 10% of the dataset into validation sets
    split_rate = 0.1
 
    # point to your unzipped flower_photos folder
    cwd = os.getcwd()
    data_root = os.path.join(cwd, "flower_data")
    origin_flower_path = os.path.join(data_root, "flower_photos")
    assert os.path.exists(origin_flower_path)
    flower_class = [cla for cla in os.listdir(origin_flower_path)
                    if os.path.isdir(os.path.join(origin_flower_path, cla))]
 
    Create a folder to save the training set
    train_root = os.path.join(data_root, "train")
    mk_file(train_root)
    for cla in flower_class:
        Create folders for each category
        mk_file(os.path.join(train_root, cla))
 
    Create a folder to save the validation set
    val_root = os.path.join(data_root, "val")
    mk_file(val_root)
    for cla in flower_class:
        Create folders for each category
        mk_file(os.path.join(val_root, cla))
 
    for cla in flower_class:
        cla_path = os.path.join(origin_flower_path, cla)
        images = os.listdir(cla_path)
        num = len(images)
        # Index of random sampling validation set
        eval_index = random.sample(images, k=int(num*split_rate))
        for index, image in enumerate(images):
            if image in eval_index:
                Copy the files assigned to the validation set to the appropriate directory
                image_path = os.path.join(cla_path, image)
                new_path = os.path.join(val_root, cla)
                copy(image_path, new_path)
            else:
                Copy the files assigned to the training set to the appropriate directory
                image_path = os.path.join(cla_path, image)
                new_path = os.path.join(train_root, cla)
                copy(image_path, new_path)
            print("\r[{}] processing [{}/{}]".format(cla, index+1, num), end="")  # processing bar
        print(a)print("processing done!")
 
 
if __name__ == '__main__':
    main()

Copy the code

2. Neural network model

model.py

import torch.nn as nn
import torch
 
class AlexNet(nn.Module) :
    def __init__(self, num_classes=1000, init_weights=False) :
        super(AlexNet, self).__init__()
        Package the network into a module with nn.sequential () to simplify code
        self.features = nn.Sequential(   # Convolutional layer extraction of image features
            nn.Conv2d(3.48, kernel_size=11, stride=4, padding=2),  # input[3, 224, 224] output[48, 55, 55]
            nn.ReLU(inplace=True), 									# Direct modification overwrites the original value, saving computational memory
            nn.MaxPool2d(kernel_size=3, stride=2),                  # output[48, 27, 27]
            nn.Conv2d(48.128, kernel_size=5, padding=2),           # output[128, 27, 27]
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=3, stride=2),                  # output[128, 13, 13]
            nn.Conv2d(128.192, kernel_size=3, padding=1),          # output[192, 13, 13]
            nn.ReLU(inplace=True),
            nn.Conv2d(192.192, kernel_size=3, padding=1),          # output[192, 13, 13]
            nn.ReLU(inplace=True),
            nn.Conv2d(192.128, kernel_size=3, padding=1),          # output[128, 13, 13]
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=3, stride=2),                  # output[128, 6, 6]
        )
        self.classifier = nn.Sequential(   # Fully connected layer classifies images
            nn.Dropout(p=0.5),			   # Dropout Randomly inactivates neurons with a default ratio of 0.5
            nn.Linear(128 * 6 * 6.2048),
            nn.ReLU(inplace=True),
            nn.Dropout(p=0.5),
            nn.Linear(2048.2048),
            nn.ReLU(inplace=True),
            nn.Linear(2048, num_classes),
        )
        if init_weights:
            self._initialize_weights()
            
	# Forward propagation process
    def forward(self, x) :
        x = self.features(x)
        x = torch.flatten(x, start_dim=1)	Flatten and pass in the full connection layer
        x = self.classifier(x)
        return x
        
	In fact, PyTorch automatically initializes the weights when building the network
    def _initialize_weights(self) :
        for m in self.modules():
            if isinstance(m, nn.Conv2d):                            # if the convolution layer
                nn.init.kaiming_normal_(m.weight, mode='fan_out'.Initialize weights with kaiming_normal_
                                        nonlinearity='relu')
                if m.bias is not None:
                    nn.init.constant_(m.bias, 0)                    Initialization bias is 0
            elif isinstance(m, nn.Linear):            # If fully connected layer
                nn.init.normal_(m.weight, 0.0.01)    # Normal distribution initialization
                nn.init.constant_(m.bias, 0)          Initialization bias is 0

Copy the code

3. Train the neural network

train.py

# import packages
import torch
import torch.nn as nn
from torchvision import transforms, datasets, utils
import matplotlib.pyplot as plt
import numpy as np
import torch.optim as optim
from model import AlexNet
import os
import json
import time
 
# Use GPU training
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
with open(os.path.join("train.log"), "a") as log:
    log.write(str(device)+"\n")
 
# Data preprocessing
data_transform = {
    "train": transforms.Compose([transforms.RandomResizedCrop(224),       Cut randomly and scale to 224×224
                                 transforms.RandomHorizontalFlip(p=0.5),  # Horizontal random flip, probability is 0.5, that is, half of the probability is flipped, half of the probability is not flipped
                                 transforms.ToTensor(),
                                 transforms.Normalize((0.5.0.5.0.5), (0.5.0.5.0.5))),"val": transforms.Compose([transforms.Resize((224.224)),  # cannot 224, must (224, 224)
                               transforms.ToTensor(),
                               transforms.Normalize((0.5.0.5.0.5), (0.5.0.5.0.5)))}# Import and load training set
# import training set
# train_set = torchvision. Datasets. CIFAR10 (root = '. / data, # dataset storage directory
# train=True, # indicates the training set in the data set
# download=True, # True for the first run, download the dataset, and then change to False when the download is complete
# transform=transform
Load the training set
# train_loader = torch. Utils. Data. The DataLoader (train_set, # import the training set
# batch_size=50, # number of samples per batch
# shuffle=False, # shuffle the training set
# num_workers=0) # num_workers=0 on Windows
 
 
Get the path to the image data set
data_root = os.path.abspath(os.path.join(os.getcwd(), ".. /.."))  		# get data root path return to the upper directory
image_path = data_root + "/jqsj/data_set/flower_data/"  				 		# flower data_set path
 
Import the training set and preprocess it
train_dataset = datasets.ImageFolder(root=image_path + "/train",		
                                     transform=data_transform["train"])
train_num = len(train_dataset)
 
Load training sets in batches according to batch_size
train_loader = torch.utils.data.DataLoader(train_dataset,	# imported training set
                                           batch_size=32.# Number of samples per batch of training
                                           shuffle=True.# Whether to shuffle the training set
                                           num_workers=0)	# Use thread count, set to 0 on Windows
 
Import and load the validation set
Import validation set and preprocess
validate_dataset = datasets.ImageFolder(root=image_path + "/val",
                                        transform=data_transform["val"])
val_num = len(validate_dataset)
 
Load the validation set
validate_loader = torch.utils.data.DataLoader(validate_dataset,	# Import validation set
                                              batch_size=32, 
                                              shuffle=True,
                                              num_workers=0)
 
Store index: a dictionary of tags
# dictionary, category: index {' Daisy ':0, 'Dandelion ':1,' Roses ':2, 'sunflower':3, 'Tulips ':4}
flower_list = train_dataset.class_to_idx
# swap key and val in flower_list
cla_dict = dict((val, key) for key, val in flower_list.items())
 
Write cla_dict to a JSON file
json_str = json.dumps(cla_dict, indent=4)
with open('class_indices.json'.'w') as json_file:
    json_file.write(json_str)
 
# Training process
net = AlexNet(num_classes=5, init_weights=True)  	  # instantiate network (output type 5, initialize weight)
net.to(device)									 	  Allocate network training to the specified device (GPU/CPU)
loss_function = nn.CrossEntropyLoss()			 	  # Cross entropy loss
optimizer = optim.Adam(net.parameters(), lr=0.0002)	  Optimizer (training parameters, learning rate)
 
save_path = './AlexNet.pth'
best_acc = 0.0
 
for epoch in range(150) :########################################## train ###############################################
    net.train()     					# Turn on Dropout during training
    running_loss = 0.0					Each epoch is zeroed out for running_loss
    time_start = time.perf_counter()	# Time training an epoch
    
    for step, data in enumerate(train_loader, start=0) :# Walk through the training set, step is calculated from 0
        images, labels = data   Get the image and label of the training set
        optimizer.zero_grad()	Clear historical gradients
        
        outputs = net(images.to(device))				 # Forward propagation
        loss = loss_function(outputs, labels.to(device)) # Calculate the loss
        loss.backward()								     # Backpropagation
        optimizer.step()								 Optimizer updates parameters
        running_loss += loss.item()
        
        # Print training progress (visualize training process)
        rate = (step + 1) / len(train_loader)           # Current Progress = current step/total steps required for training round epoch
        a = "*" * int(rate * 50)
        b = "." * int((1 - rate) * 50)
        with open(os.path.join("train.log"), "a") as log:
              log.write(str("\ rtrain loss: {: ^ 3.0 f} % [{} - > {}] {: 3 f}".format(int(rate * 100), a, b, loss))+"\n")
        print("\ rtrain loss: {: ^ 3.0 f} % [{} - > {}] {: 3 f}".format(int(rate * 100), a, b, loss), end="")
    print(a)with open(os.path.join("train.log"), "a") as log:
              log.write(str('%f s' % (time.perf_counter()-time_start))+"\n")
    print('%f s' % (time.perf_counter()-time_start))
 
    ########################################### validate ###########################################
    net.eval(a)# Turn off Dropout during validation
    acc = 0.0  
    with torch.no_grad():
        for val_data in validate_loader:
            val_images, val_labels = val_data
            outputs = net(val_images.to(device))
            predict_y = torch.max(outputs, dim=1) [1]  The index (label) corresponding to the maximum position of output is used as the forecast output
            acc += (predict_y == val_labels.to(device)).sum().item()    
        val_accurate = acc / val_num
        
        # Save the network parameters with the highest accuracy
        if val_accurate > best_acc:
            best_acc = val_accurate
            torch.save(net.state_dict(), save_path)
        with open(os.path.join("train.log"), "a") as log:
              log.write(str('[epoch %d] train_loss: %.3f test_accuracy: %.3f \n' %
              (epoch + 1, running_loss / step, val_accurate))+"\n")
        print('[epoch %d] train_loss: %.3f test_accuracy: %.3f \n' %
              (epoch + 1, running_loss / step, val_accurate))
with open(os.path.join("train.log"), "a") as log:
      log.write(str('Finished Training') +"\n")
print('Finished Training')

Copy the code

After the training, the accuracy rate was 94 percent

The training log is as follows:

4. Predict the model

predict.py

import torch from model import AlexNet from PIL import Image from torchvision import transforms import matplotlib.pyplot Transform = transforms.Compose([transforms.Resize((224, 224))), transforms.ToTensor(), Transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 1))]) # load image img = image.open ("pgy2.jpg") #plt.imshow(img) # W] img = data_transform(img) # expand batch dimension img = torch.unsqueeze(img, dim=0) # read class_indict try: json_file = open('./class_indices.json', 'r') class_indict = json.load(json_file) except Exception as e: print(e) exit(-1) # create model model = AlexNet(num_classes=5) # load model weights model_weight_path = "./AlexNet.pth"  #, map_location='cpu' model.load_state_dict(torch.load(model_weight_path, Map_location =' CPU ')) # Dropout model.eval() with torch. No_grad (): # predict class output = torch. Squeeze (model(img)) Predict = torch. Softmax (output, dim=0) predict_cla = torch.argmax(predict).numpy() print(class_indict[str(predict_cla)], predict[predict_cla].item()) plt.show()Copy the code

Then one of the flower pictures is recognized, and the results are as follows:

It can be seen that there is only one identification result (Daisy Daisy) and accuracy 1.0 is 100% (range is 0~1, so 1 corresponds to 100%).

To facilitate the use of this neural network, we then develop it into a visual interface operation

Ii. Construction of flower Identification System (Flask)

1. Build the page:

upload.html

<! DOCTYPEhtml>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Li Yunchen - Flower Identification System V1.0</title>
	<link rel="stylesheet" type="text/css" href=".. /static/css/bootstrap.min.css">
	<link rel="stylesheet" type="text/css" href=".. /static/css/fileinput.css">
    <script src=".. / static/js/jquery - 2.1.4. Min. Js. ""></script>
	
    <script src=".. /static/js/bootstrap.min.js"></script> 
	<script src=".. /static/js/fileinput.js"></script> 
	<script src=".. /static/js/locales/zh.js"></script> 
	
</head>
<body>
    <h1   align="center">Li Yunchen - Flower Identification System V1.0</h1>
	<div align="center">
    <form action="" enctype='multipart/form-data' method='POST'>
        <input type="file" name="file"  class="file"  data-show-preview="false" style="margin-top:20px;"/>
        <br>
        <input type="submit" value="Upload" class="btn btn-primary button-new " style="margin-top:15px;"/>
    </form>
	</div>
</body>
</html>

Copy the code

2. Invoke the neural network model

main.py

# coding:utf-8
 
from flask import Flask, render_template, request, redirect, url_for, make_response, jsonify
from werkzeug.utils import secure_filename
import os
import time
 
 
# # # # # # # # # # # # # # # # # # #
Library package required for the model
import torch
from model import AlexNet
from PIL import Image
from torchvision import transforms
import matplotlib.pyplot as plt
import json
 
# read class_indict
try:
    json_file = open('./class_indices.json'.'r')
    class_indict = json.load(json_file)
except Exception as e:
    print(e)
    exit(-1)
 
# create model
model = AlexNet(num_classes=5)
# load model weights
model_weight_path = "./AlexNet.pth"
#, map_location='cpu'
model.load_state_dict(torch.load(model_weight_path, map_location='cpu'))
 
Close # Dropout
model.eval(a)# # # # # # # # # # # # # # # # # # #
from datetime import timedelta
Set the file format to be allowed
ALLOWED_EXTENSIONS = set(['png'.'jpg'.'JPG'.'PNG'.'bmp'])
 
def allowed_file(filename) :
    return '. ' in filename and filename.rsplit('. '.1) [1] in ALLOWED_EXTENSIONS
 
app = Flask(__name__)
Set the static file cache expiration time
app.send_file_max_age_default = timedelta(seconds=1)
 
# Image install and replace operation
def tran(img_path) :
     # pretreatment
    data_transform = transforms.Compose(
        [transforms.Resize((224.224)),
         transforms.ToTensor(),
         transforms.Normalize((0.5.0.5.0.5), (0.5.0.5.0.5)))# load image
    img = Image.open("pgy2.jpg")
    #plt.imshow(img)
    # [N, C, H, W]
    img = data_transform(img)
    # expand batch dimension
    img = torch.unsqueeze(img, dim=0)
    return img
    
 
@app.route('/upload', methods=['POST'.'GET'])  # add route
def upload() :
    path=""
    if request.method == 'POST':
        f = request.files['file']
        if not (f and allowed_file(f.filename)):
            return jsonify({"error": 1001."msg": "Please check the type of images uploaded, PNG, PNG, JPG, JPG, BMP only"})
 
        basepath = os.path.dirname(__file__)  # Path of the current file
        path = secure_filename(f.filename)
        upload_path = os.path.join(basepath, 'static/images', secure_filename(f.filename))  # note: You must create a folder that does not exist, otherwise it will prompt you that the folder does not exist
        Upload_path = os.path.join(basepath, 'static/images','test.jpg') # upload_path = os.path.join(basepath, 'static/images','test.jpg'
        print(path)
 
        img = tran('static/images'+path)
        # # # # # # # # # # # # # # # # # # # # # # # # # #
        # Prediction picture
        with torch.no_grad():
            # predict class
            output = torch.squeeze(model(img))     The output is compressed, i.e. the batch dimension is compressed
            predict = torch.softmax(output, dim=0)
            predict_cla = torch.argmax(predict).numpy()
            res = class_indict[str(predict_cla)]
            pred = predict[predict_cla].item()
            #print(class_indict[str(predict_cla)], predict[predict_cla].item())
        res_chinese = ""
        if res=="daisy":
            res_chinese="Daisy"
        if res=="dandelion":
            res_chinese="Dandelion"
        if res=="roses":
            res_chinese="The rose"
        if res=="sunflower":
            res_chinese="Sunflower"
        if res=="tulips":
            res_chinese="Tulips"
 
        #print('result:', class_indict[str(predict_class)], 'accuracy:', prediction[predict_class])
        # # # # # # # # # # # # # # # # # # # # # # # # # #
        f.save(upload_path)
        pred = pred*100
        return render_template('upload_ok.html', path=path, res_chinese=res_chinese,pred = pred, val1=time.time())
 
    return render_template('upload.html')
 
if __name__ == '__main__':
    # app.debug = True
    app.run(host='127.0.0.1', port=80,debug = True)

Copy the code

3. System identification results

<! DOCTYPEhtml>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Li Yunchen - Flower Identification System V1.0</title>
	<link rel="stylesheet" type="text/css" href=".. /static/css/bootstrap.min.css">
	<link rel="stylesheet" type="text/css" href=".. /static/css/fileinput.css">
    <script src=".. / static/js/jquery - 2.1.4. Min. Js. ""></script>
	
    <script src=".. /static/js/bootstrap.min.js"></script> 
	<script src=".. /static/js/fileinput.js"></script> 
	<script src=".. /static/js/locales/zh.js"></script> 
</head>
<body>
    <h1  align="center">Li Yunchen - Flower Identification System V1.0</h1>
	<div align="center">
    <form action="" enctype='multipart/form-data' method='POST'>
        <input type="file" name="file" class="file"  data-show-preview="false" style="margin-top:20px;"/>
        <br>
        <input type="submit" value="Upload" class="button-new btn btn-primary" style="margin-top:15px;"/>
    </form>
	<p  style="size:15px; color:blue;">{{res_Chinese}}</p>
	</br>
	<p  style="size:15px; color:red;">Accuracy: {{Mr Pred}} %</p>
    <img src="{{ './static/images/'+path }}" width="400" height="400" alt=""/>
	</div>
</body>
</html>

Copy the code

4. Start the system:

python main.py
Copy the code

And then in the browser in the browser

http://127.0. 01./upload
Copy the code

The following interface is displayed:

Finally, a GIF of the identification process

Third, summary

Ok, this flower system has been built, isn’t it super simple, I also took advantage of this machine vision class, so I made such a system, review the previous knowledge, ha ha ha.

If you have any questions, feel free to comment below