继开 | 博客

热爱生活,努力学习,实现自己的价值


  • 短诗的序

  • 迷途自渡

  • 寒星三两

  • 林深见鹿

  • 记昨日书

  • 顾探往昔

Python Tensorflow实现识别猫与狗

发表于 2023-05-04
字数统计: 1,426 字 | 阅读时长 ≈ 8 min

环境准备

1.python 环境,建议python3.8
2.anaconda
anaconda 安装
https://www.anaconda.com/products/individual#Downloads
下载对应版本anconda即可,这里不介绍anconda安装过程了。
安装可以参考:https://blog.csdn.net/qq_43674360/article/details/123396415

环境搭建

创建虚拟环境

1
conda create -n tf python=3.8
1
conda activate  tf

下载

1
pip install tensorflow -i https://pypi.tuna.tsinghua.edu.cn/simple

数据集准备

可下载数据集
https://www.kaggle.com/c/dogs-vs-cats/data

数据集目录如下

1
2
3
4
├─dogs-vs-cats
│ ├─test1.zip
│ ├─train.zip
│ └─sampleSubmission.csv

数据集处理

处理训练集的数据结构
data_read.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
import os

filenames = os.listdir('./dogs-vs-cats/train')
# 动物类型
categories = []
for filename in filenames:
category = filename.split('.')[0]
categories.append(category)





import pandas as pd
# 结构化数据
df = pd.DataFrame({
'filename':filenames,
'category':categories
})




#展示对应的数据
import random
from keras.preprocessing import image
import matplotlib.pyplot as plt
## 看看结构化之后的结果
# print(df.head())
# print(df.tail())
# print(df['category'].value_counts())
# df['category'].value_counts().plot(kind = 'bar')
# plt.show()

# 展示个图片看看
sample = random.choice(filenames)
#image = image.load_img('./dogs-vs-cats/train/' + sample)

# from keras.preprocessing import image
from keras.utils import image_utils

img_keras = image_utils.load_img('./dogs-vs-cats/train/' + sample)

# plt.imshow(img_keras)
# plt.show()













from sklearn.model_selection import train_test_split



# 切割训练集合

train_df, validate_df = train_test_split(df, test_size = 0.20, random_state = 42)

train_df = train_df.reset_index(drop=True)
validate_df = validate_df.reset_index(drop=True)

# print(train_df.head())
# print(validate_df.head())
print(train_df)
# print(validate_df)

total_train = train_df.shape[0]
total_validate = validate_df.shape[0]

print("Total number of example in training dataset : {0}".format(total_train))
print("Total number of example in validation dataset : {0}".format(total_validate))

运行查看,是否正确读取数据集

创建模型

创建一个模型代码如下
create_model.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Conv2D, MaxPooling2D, Dense, BatchNormalization, Flatten,Dropout
from tensorflow.keras import optimizers


## 创建第一个模型
class Model:
def __init__(self, IMG_WIDTH, IMG_HEIGHT, IMG_CHANNELS):
self.IMG_WIDTH = IMG_WIDTH
self.IMG_HEIGHT = IMG_HEIGHT
self.IMG_CHANNELS = IMG_CHANNELS

def create_model(self):
model = Sequential()
#第一层
#图像空间的2维卷积 32个卷积输出滤波器,卷积窗口的高度和宽度(3,3),输入像素150*150
model.add(Conv2D(32, (3,3), activation = 'relu', kernel_initializer='he_uniform',
padding='same',input_shape = (150, 150, 3)))

#卷积窗口的高度和宽度降低为(2,2)
model.add(MaxPooling2D((2,2)))

#第二层
model.add(Conv2D(64, (3,3), activation = 'relu'))
model.add(MaxPooling2D((2,2)))

#第三层
model.add(Conv2D(128, (3,3), activation = 'relu'))
model.add(MaxPooling2D((2,2)))

#第四层
model.add(Conv2D(128, (3,3), activation = 'relu'))
model.add(MaxPooling2D((2,2)))

#Flatten层用来将输入“压平”,即把多维的输入一维化
model.add(Flatten())
#全链接层,输出空间的维数
model.add(Dense(512, activation = 'relu'))
model.add(Dense(1, activation = 'sigmoid'))

from keras import optimizers
# 设置损失算法与优化
model.compile(loss = 'binary_crossentropy', optimizer = optimizers.RMSprop(lr = 1e-4), metrics =['acc'])
return model

运行之后,可在文件夹下找到my_model1.th 模型文件

训练模型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# import create_model as Model

from data_read import train_df,validate_df
from create_model import Model

# 初始化模型
IMG_WIDTH = 150
IMG_HEIGHT = 150
IMG_CHANNELS = 3

model = Model(IMG_WIDTH, IMG_HEIGHT, IMG_CHANNELS)
model_1 = model.create_model()
model_1.summary()


from keras.preprocessing.image import ImageDataGenerator

#原来是255的像素做 0与1的处理
train_imgdatagen = ImageDataGenerator(rescale = 1./255)
valid_imgdatagen = ImageDataGenerator(rescale = 1./255)


train_generator_m1 = train_imgdatagen.flow_from_dataframe(
train_df,
directory="./dogs-vs-cats/train",
x_col='filename',
y_col='category',
target_size = (150, 150), # resize image to 150x150
batch_size = 64,
class_mode = 'binary'
)

validation_generator_m1 = valid_imgdatagen.flow_from_dataframe(
validate_df,
directory="./dogs-vs-cats/test1",
x_col='filename',
y_col='category',
target_size = (150, 150), # resize image to 150x150
batch_size = 64,
class_mode = 'binary'
)


import numpy as np

# model 1 开始训练
history_1 = model_1.fit(
train_generator_m1,
epochs = 3,
steps_per_epoch = 100,
validation_data = validation_generator_m1,
validation_steps = 50
)



#保存模型
model_1.save('./model_1.h5')



#打印训练结果
print(np.mean(history_1.history['acc']))
print(np.mean(history_1.history['val_acc']))



#形成图像结果
#import matplotlib.pyplot as plt
# plt.plot(history_1.history['acc'], color = 'black')
# plt.plot(history_1.history['val_acc'], color = 'blue')
# plt.title('Training and validation accuracy of model 1')
# plt.xlabel('Epochs')
# plt.ylabel('Accuracy’)4
# plt.show()
# plt.plot(history_1.history['loss'], color = 'black')
# plt.plot(history_1.history['val_loss'], color = 'blue')
# plt.title('Training and validation loss of model 1')
# plt.xlabel('Epochs')
# plt.ylabel('Accuracy')
# plt.show()

验证模型

验证代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79

from numpy.core.fromnumeric import ptp
import pandas as pd
import os
import matplotlib.pyplot as plt

from keras.preprocessing.image import ImageDataGenerator
# from tensorflow.keras.models import load_model


from tensorflow import keras
from keras.layers import Dense
from keras.models import Sequential, load_model

model = load_model('model_1.h5')

test_filenames = os.listdir('./dogs-vs-cats/test2cat')

test_df = pd.DataFrame(
{
'id' : test_filenames
}
)


# print(test_df)


test_gen = ImageDataGenerator(rescale = 1./255)

# test_generator = test_gen.flow_from_dataframe(
# test_df,
# "./dogs-vs-cats/test1",
# x_col='id',
# y_col=None,
# target_size = (128, 128), # resize image to 150x150
# batch_size = 1,
# class_mode = None,
# shuffle=False,
# validate_filenames=False
# )


# test_generator = test_gen.flow_from_dataframe(
# test_df,
# directory="./dogs-vs-cats/test1",
# x_col='id',
# y_col=None,
# target_size = (150, 150), # resize image to 150x150
# batch_size = 1,
# class_mode = None,
# shuffle=False,
# validate_filenames=False
# )

test_generator = test_gen.flow_from_dataframe(
test_df,
directory="./dogs-vs-cats/test2cat",
x_col='id',
y_col=None,
target_size = (150, 150), # resize image to 150x150
batch_size = 1,
class_mode = None,
shuffle=False,
validate_filenames=False
)
print(test_generator)

predictions = model.predict(test_generator)

print(predictions)
pred = [1 if p > 0.5 else 0 for p in predictions]

test_df['category'] = pred

test_df['category'].value_counts().plot.bar()
plt.show()
plt.show()
plt.show()

一辈子很短,努力的做好两件事就好;
第一件事是热爱生活,好好的去爱身边的人;
第二件事是努力学习,在工作中取得不一样的成绩,实现自己的价值,而不是仅仅为了赚钱;

Python Pytorch实现图像识别

发表于 2023-04-24
字数统计: 1,843 字 | 阅读时长 ≈ 9 min

环境准备

1.python 环境,建议python3.8

环境搭建

pip install torch torchvision torchaudio

数据集准备

新建 pytorch_test 目录,并在目录下 新建RGB 文件夹及子目录,如下

1
2
3
4
5
6
7
8
9
└─RGB
├─train
│ ├─green
│ ├─red
│ └─yellow
└─validation
├─green
├─red
└─yellow

在green,red,yellow 文件中分别放好,相应底色的图片,每个文件夹,图片数量都需要大于1

数据集验证

查看数据集代码
data_read.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
import torch.utils.data
import numpy as np
import os, random, glob
from torchvision import transforms
from PIL import Image
import matplotlib.pyplot as plt


# 数据集读取
class MyDataSet(torch.utils.data.Dataset):
def __init__(self, img_dir, transform=None):
self.transform = transform
g_dir = os.path.join(img_dir, "green") #####要训练的.bmp上一级的名字,这里设你要区分的类别为N,这里的N=3.
r_dir = os.path.join(img_dir, "red") #####
y_dir = os.path.join(img_dir, "yellow") #####

imgsLib = []
imgsLib.extend(glob.glob(os.path.join(g_dir, "*.bmp"))) #####将图片的地址添加到列表
imgsLib.extend(glob.glob(os.path.join(r_dir, "*.bmp"))) #####
imgsLib.extend(glob.glob(os.path.join(y_dir, "*.bmp"))) #####
random.shuffle(imgsLib) # 打乱数据集
self.imgsLib = imgsLib

# 作为迭代器必须要有的
def __getitem__(self, index):
img_path = self.imgsLib[index]

label = 1 if 'green' in img_path.split('/')[-1] else 0 #####为类别做标签,三类就012
if label == 0: label = 2 if 'yellow' in img_path.split('/')[-1] else 0 #####

img = Image.open(img_path).convert("RGB")
img = self.transform(img)
return img, label

def __len__(self):
return len(self.imgsLib)

# 数据集读取
# class MyDataSet2(torch.utils.data.Dataset):

# 读取数据

if __name__ == "__main__":

CLASSES = {0: "red", 1: "green", 2: "yellow"} ###### 标号与类别名做好对应
#img_dir = "C:/Users/ASUS/Desktop/project/RGB/train" #####地址为你自己train的位置,最好是绝对寻址
img_dir = "./pytorch_test/RGB/train" #####地址为你自己train的位置,最好是绝对寻址
data_transform = transforms.Compose([
transforms.Resize(256), # resize到256 #####规定尺寸,直到运行这部分代码可以完全看见图片
transforms.CenterCrop(512), # crop到224 #####
transforms.ToTensor(),
])

dataSet = MyDataSet(img_dir=img_dir, transform=data_transform)
# dataLoader = torch.utils.data.DataLoader(dataSet, batch_size=8, shuffle=True, num_workers=4)
# dataLoader = torch.utils.data.DataLoader(dataSet, batch_size=8, shuffle=False, num_workers=4)
dataLoader = torch.utils.data.DataLoader(dataSet, batch_size=8, shuffle=False, num_workers=1)


#image_batch, label_batch = iter(dataLoader).next()
#image_batch, label_batch = next(dataLoader)
#image_batch, label_batch = next(iter(dataLoader))

image_batch, label_batch = next(iter(dataLoader))

for i in range(image_batch.data.shape[0]):
label = np.array(label_batch.data[i])
# print(label)
img = np.array(image_batch.data[i]*255, np.int32)
print(CLASSES[int(label)])
plt.imshow(np.transpose(img, [1, 2, 0]))
plt.show()

运行查看,是否正确读取数据集

报错处理

问题一

1
ValueError: num_samples should be a positive integer value, but got num_samples=0

代码调试时,显示ValueError: num_samples should be a positive integer value, but got num_samples=0
因为用的数据集是已经划分好的,所以不需要再shuffle。加载数据时将shuffle = False,错误即可消除。

1
# dataLoader = torch.utils.data.DataLoader(dataSet, batch_size=8, shuffle=True, num_workers=4)

修改为

1
2
3
dataLoader = torch.utils.data.DataLoader(dataSet, batch_size=8, shuffle=False, num_workers=4)
```
#### 问题二

AttributeError: ‘_MultiProcessingDataLoaderIter’ object has no attribute ‘next’

1
2
```
image_batch, label_batch = iter(dataLoader).next()

运行上述语句,报错:AttributeError: ‘_MultiProcessingDataLoaderIter’ object has no attribute ‘next’

先尝试将其改为单线程处理

1
2
3
4
5
6
7
8
9
trainloader = torch.utils.data.DataLoader(trainset, batch_size=4,
shuffle=True,num_workers=0)
```

发现问题并没有解决,又继续报错,AttributeError: '_SingleProcessingDataLoaderIter' object has no attribute 'next'

出现原因:pytorch版本关于next()的用法不一样

解决方法:

image_batch, label_batch = next(iter(dataLoader))

1
2
3
4
5
 即可成功运行


## 模型训练
训练代如下

from future import print_function, division
import numpy as np
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torch.autograd import Variable
from torch.utils.data import Dataset
from torchvision import transforms, datasets, models

from data_read1 import MyDataSet #####第一个.py文件名

配置参数

random_state = 1
torch.manual_seed(random_state) # 设置随机数种子,确保结果可重复
torch.cuda.manual_seed(random_state)
torch.cuda.manual_seed_all(random_state)
np.random.seed(random_state)

random.seed(random_state)

epochs = 20 # 训练次数
batch_size = 16 # 批处理大小
num_workers = 0 # 多线程的数目
use_gpu = torch.cuda.is_available()

对加载的图像作归一化处理, 并裁剪为[224x224x3]大小的图像

data_transform = transforms.Compose([
transforms.Resize(256), #####这部分尺寸最好一致
transforms.CenterCrop(512), #####
transforms.ToTensor(),

])

train_dataset = MyDataSet(img_dir=”./pytorch_test/RGB/train”, transform=data_transform) #####训练数据集的地址

#train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=batch_size, shuffle=True, num_workers=0)
train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=batch_size, shuffle=False, num_workers=0)

test_dataset = MyDataSet(img_dir=”./pytorch_test2/RGB/validation”, transform=data_transform)#####测试数据集的地址

#test_loader = torch.utils.data.DataLoader(train_dataset, batch_size=batch_size, shuffle=True, num_workers=0)
test_loader = torch.utils.data.DataLoader(train_dataset, batch_size=batch_size, shuffle=False, num_workers=0)

加载resnet18 模型,

net = models.resnet18(pretrained=False)
num_ftrs = net.fc.in_features
net.fc = nn.Linear(num_ftrs, 3) # 更新resnet18模型的fc模型,#####因为这里有三类,所以设置为3

if use_gpu:
net = net.cuda()
print(net)

‘’’
Net (
(conv1): Conv2d(3, 6, kernel_size=(5, 5), stride=(1, 1))
(maxpool): MaxPool2d (size=(2, 2), stride=(2, 2), dilation=(1, 1))
(conv2): Conv2d(6, 16, kernel_size=(5, 5), stride=(1, 1))
(fc1): Linear (44944 -> 2048)
(fc2): Linear (2048 -> 512)
(fc3): Linear (512 -> 2)
)
‘’’

定义loss和optimizer

cirterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.0001, momentum=0.9)

开始训练

net.train()
if name == ‘main‘:
for epoch in range(epochs):
running_loss = 0.0
train_correct = 0
train_total = 0
for i, data in enumerate(train_loader, 0):
inputs, train_labels = data
if use_gpu:
inputs, labels = Variable(inputs.cuda()), Variable(train_labels.cuda())
else:
inputs, labels = Variable(inputs), Variable(train_labels)
# inputs, labels = Variable(inputs), Variable(train_labels)
optimizer.zero_grad()
outputs = net(inputs)
_, train_predicted = torch.max(outputs.data, 1)
# import pdb
# pdb.set_trace()
train_correct += (train_predicted == labels.data).sum()
loss = cirterion(outputs, labels)
loss.backward()
optimizer.step()

        running_loss += loss.item()
        print("epoch: ",  epoch, " loss: ", loss.item())
        train_total += train_labels.size(0)

    print('train %d epoch loss: %.3f  acc: %.3f ' % (
    epoch + 1, running_loss / train_total * batch_size, 100 * train_correct / train_total))

    # 模型测试
    correct = 0
    test_loss = 0.0
    test_total = 0
    test_total = 0
    net.eval()
    for data in test_loader:
        images, labels = data
        if use_gpu:
            images, labels = Variable(images.cuda()), Variable(labels.cuda())
        else:
            images, labels = Variable(images), Variable(labels)
        outputs = net(images)
        _, predicted = torch.max(outputs.data, 1)
        loss = cirterion(outputs, labels)
        test_loss += loss.item()
        test_total += labels.size(0)
        correct += (predicted == labels.data).sum()

    print('test  %d epoch loss: %.3f  acc: %.3f ' % (epoch + 1, test_loss / test_total, 100 * correct / test_total))

torch.save(net, “./pytorch_test/my_model1.pth”) #####保存为一个my_model1.pth文件

1
2
3
4
5

运行之后,可在文件夹下找到my_model1.th 模型文件

## 验证模型
验证代码

from PIL import Image
import torch
from torchvision import transforms

图片路径

#save_path = ‘./my_model3.pth’ #####上一次训练生成的文件
save_path = ‘./pytorch_test/my_model1.pth’ #####上一次训练生成的文件

———————— 加载数据 —————————

Data augmentation and normalization for training

Just normalization for validation

定义预训练变换

preprocess_transform = transforms.Compose([
transforms.Resize(256), #####尺寸保持一致
transforms.CenterCrop(512), #####
transforms.ToTensor(), #####
# transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
])

class_names = [‘red’, ‘green’, ‘yellow’] #####类别的名字,按顺序

device = torch.device(“cuda:0” if torch.cuda.is_available() else “cpu”)

———————— 载入模型并且测试 —————————

model = torch.load(save_path)
model.eval()

print(model)

#image_PIL = Image.open(‘./pytorch_test/RGB/validation/green/1.bmp’) #####放入你要测试的图片位置
image_PIL = Image.open(‘./pytorch_test/RGB/validation/red/2.bmp’) #####放入你要测试的图片位置
#image_PIL = Image.open(‘./pytorch_test/RGB/validation/yellow/3.bmp’) #####放入你要测试的图片位置

image_tensor = preprocess_transform(image_PIL)

以下语句等效于 image_tensor = torch.unsqueeze(image_tensor, 0)

image_tensor.unsqueeze_(0)

没有这句话会报错

image_tensor = image_tensor.to(device)

out = model(image_tensor)

得到预测结果,并且从大到小排序

_, indices = torch.sort(out, descending=True)

返回每个预测值的百分数

percentage = torch.nn.functional.softmax(out, dim=1)[0]

print(out)
print(“图片预测为:{}”.format(class_names[int(out.argmax(1))]))

print([(class_names[idx], percentage[idx].item()) for idx in indices[0][:5]])

1
2

输出预测结果

tensor([[ 0.0585, -0.0298, -0.0243]], grad_fn=)
图片预测为:red
[(‘red’, 0.35260626673698425), (‘yellow’, 0.32458174228668213), (‘green’, 0.322812020778656)]

```

一辈子很短,努力的做好两件事就好;
第一件事是热爱生活,好好的去爱身边的人;
第二件事是努力学习,在工作中取得不一样的成绩,实现自己的价值,而不是仅仅为了赚钱;

Docker Dockerfile更新包报错处理

发表于 2023-04-19
字数统计: 371 字 | 阅读时长 ≈ 2 min

问题

编写dockerfile

1
2
3
4
#基于的基础镜像
FROM python:3.8.2
RUN apt-get update
RUN apt-get install ffmpeg libsm6 libxext6 -y

docker build 之后报错

E: Release file for http://security.ubuntu.com/ubuntu/dists/bionic-security/InRelease is not valid yet (invalid for another 11d 10min 50s). Updates for this repository will not be applied

遇到这个问题主要是时间没有更新导致的,首先要查看当前时区

1
2
root@bf8fc620bea2:/# date -R
Thu, 10 Mar 2023 02:38:36 +0800

// 很显然这不是东八区的时间,

解决

使用tzselect命令修改时区

tzelect 之后
先选数字5 Asia 回车
再选数字9 China 回车
最后选数字1 Beijing Time 回车
选1 yes 回车

查看是不是更改为东八区

1
2
[root@localhost bin]# date -R
Thu, 10 Mar 2023 11:25:57 +0800

设置系统时间为此刻的北京时间

设置时间为此刻北京时间

1
2
[root@localhost bin]# date -s "2022-03-10 11:29:46" 
2023年 03月 10日 星期四 11:29:46 CST

查看时间

1
2
[root@localhost bin]# date
2023年 03月 10日 星期四 11:29:50 CST

验证

再次执行 docker build 命令就可以成功了
此解决方案也适用于ubuntu次执行apt-get update命令

一辈子很短,努力的做好两件事就好;
第一件事是热爱生活,好好的去爱身边的人;
第二件事是努力学习,在工作中取得不一样的成绩,实现自己的价值,而不是仅仅为了赚钱;

Python yolov5加Flask打包docker镜像

发表于 2023-04-18
字数统计: 1,766 字 | 阅读时长 ≈ 9 min

yolov5加Flask打包docker镜像

将已经训练好的模型打包之后供外部使用

环境准备

1.python 环境,建议python3.8
2.已经搭建好的yolov5 环境
3.已经训练好的模型
4.已经搭建好的flask环境
5.已经搭建好的docker环境

将编写调用yolov5 代码放到yolov5 根目录
代码model_test.py示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
from flask import Flask, jsonify, request, abort
import json
import base64
import numpy as np

import torch
import os
from PIL import Image
import cv2
from io import BytesIO, StringIO


app = Flask(__name__)

@app.route('/ana', methods=['GET', 'POST'])
def call_analysis():
print("Hello, World!")

data1 = request.data #----获取的是字符串
#print(data1)
data2 = request.get_data() #----获取的是字符串
#print(data2)
j_data = json.loads(data2) #-----load将字符串解析成json
# print(j_data)
# print(j_data['base64'])

# return jsonify(j_data)
return getbase64(j_data['base64'])

def getbase64(imgbase64):
# print(img)
# os.environ["CUDA_VISIBLE_DEVICES"]
# model = torch.hub.load('./', 'custom', path='./yolov5s.pt', source='local')
model = torch.hub.load('./app/', 'custom', './app/runs/train/exp2/weights/last.pt', source='local')
# model.cuda()
# print(model)
# img1 = Image.open(BytesIO(img))


# 传入为RGB格式下的base64,传出为RGB格式的numpy矩阵
byte_data = base64.b64decode(imgbase64)#将base64转换为二进制
encode_image = np.asarray(bytearray(byte_data), dtype="uint8")# 二进制转换为一维数组
img_array = cv2.imdecode(encode_image, cv2.IMREAD_COLOR)# 用cv2解码为三通道矩阵
img_array = cv2.cvtColor(img_array, cv2.COLOR_BGR2RGB)# BGR2RGB

img1 = img_array
imgs = [img1]
#img2 = cv2.imread('./data/images/zidane.jpg')[:,:,::-1]
#imgs = [img2]

results = model(imgs, size=640)
print('识别成功')
results.ims
results.render()
base64_image = ''
for img in results.ims:
buffered = BytesIO()
img_base64 = Image.fromarray(img)
img_base64.save(buffered, format='JPEG')
base64_image = base64.b64encode(buffered.getvalue()).decode('utf-8')
# with open('./result.txt', 'a+') as f:
# f.write(base64_image)
# f.close()
print(results)
results.save()
base64_image = 'data:image/jpeg;base64,%s' % base64_image
return base64_image
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, debug = False)

./app/ 为yolov5根目录 ,根据实际情况调整
./app/runs/train/exp2/weights/last.pt 为训练好的模型文件 ,根据实际情况调整

切换环境(切换到Flask和yolov5相关依赖的环境,若安装到默认环境,则不需要)

1
activate yolo

在 yolov5 根目录打包python项目所需的依赖:

1
pip freeze > requirements.txt

编写dockerfile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#基于的基础镜像
FROM python:3.8.2
#解决 ImportError: libGL.so.1: cannot open shared object file: No such file or directory 问题
#RUN (apt-get update) && (apt-get install -y libgl1-mesa-dev ffmpeg libsm6 libxext6)
#ENV PYTHONUNBUFFERED 1

RUN apt-get update
RUN apt-get install ffmpeg libsm6 libxext6 -y

#代码添加到code文件夹
ADD . /code
# 设置code文件夹是工作目录
WORKDIR /code
# 安装支持
RUN pip install -r requirements.txt -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com
# 暴露对外端口
EXPOSE 5000
# 启动命令
CMD ["python", "/code/app/model_test.py"]

新建dockerBulid 文件夹
在文件夹内,放入Dockerfile,requirements.txt 两个文件
在文件夹内,新建app 文件夹,将yolov5 源码放到此目录下

进行打包

在dockerBulid 文件夹下运行打包命令

1
docker build -t cattest:v1 .

打包过程比较长,需要下载python 依赖和安装依赖,大约20-30分钟左右,只要不报错,可以继续执行

cattest:v1 cattest 为打包镜像名字,v1 为版本,都可以换
注意命令最后有个点”.”

打包完成完成之后可以查看到打包完成的镜像

1
docker images

打包问题处理

出现问题 The read operation timed out

Dockerfile 中将

1
RUN pip install -r requirements.txt

修改为

1
RUN pip install -r requirements.txt -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com

ERROR: Could not find a version that satisfies the requirement importlib-metadata==6.4.1 (from -r requirements.txt (line 55)) (from versions: 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 0.10, 0.11, 0.12, 0.13, 0.14, 0.15, 0.16, 0.17, 0.18, 0.19, 0.20, 0.21, 0.22, 0.23, 1.0.0, 1.1.0, 1.1.1, 1.1.2, 1.1.3, 1.2.0, 1.3.0, 1.4.0, 1.5.0, 1.5.1, 1.5.2, 1.6.0, 1.6.1, 1.7.0, 2.0.0, 2.1.0, 2.1.1, 2.1.2, 2.1.3, 3.0.0, 3.1.0, 3.1.1, 3.2.0, 3.3.0, 3.4.0, 3.5.0, 3.6.0, 3.7.0, 3.7.1, 3.7.2, 3.7.3, 3.8.0, 3.8.1, 3.8.2, 3.9.0, 3.9.1, 3.10.0, 3.10.1, 4.0.0, 4.0.1, 4.1.0, 4.2.0, 4.3.0, 4.3.1, 4.4.0, 4.5.0, 4.6.0, 4.6.1, 4.6.2, 4.6.3, 4.6.4, 4.7.0, 4.7.1, 4.8.0, 4.8.1, 4.8.2, 4.8.3, 4.9.0, 4.10.0, 4.10.1, 4.11.0, 4.11.1, 4.11.2, 4.11.3, 4.11.4, 4.12.0, 4.13.0, 5.0.0, 5.1.0, 5.2.0, 6.0.0, 6.0.1, 6.1.0)

将requirement中 importlib-metadata==6.4.1 修改为 importlib-metadata==6.1.0

这个根据实际情况修改,一版为python 的依赖版本不对

运行

启动

1
docker run -p 5000:5000 --name cattest -d cattest:v1

启动之后,可以访问ip:5000 接口查看效果

也可以通过postman 进行测试

查看是否正确的运行,有无报错
通过如下命令来获取容器的日志地址

1
docker inspect --format '{{.LogPath}}' d1f48d1606b9

通过cat 去查看

启动问题处理

启动之后访问不了

两个问题
1.注意需要Dockerfile 暴露端口

  1. run()设置为“0.0.0.0”以使服务器在外部可用
    Flask类的run()方法在本地开发服务器上运行应用程序。
    app.run(host, port, debug, options)
    全部参数都是可选的web

host:要监听的主机名。 默认为127.0.0.1(localhost)。设置为“0.0.0.0”以使服务器在外部可用
port :默认值为5000
debug:默认为false。 若是设置为true,则提供调试信息,能够自动重载代码并显示调试信息
options:要转发到底层的Werkzeug服务器。

File “/code/app/model_test.py”, line 9, in

启动报错

1
2
3
4
File "/code/app/model_test.py", line 9, in <module>
import cv2
File "/usr/local/lib/python3.8/site-packages/cv2/__init__.py", line 181, in <module>
bootstrap()

解决python版本与opencv版本不搭
修改requirements.txt

1
opencv_python==3.4.5

ImportError: libGL.so.1: cannot open shared object file: No such file or directory

启动报错 ImportError: libGL.so.1: cannot open shared object file: No such file or directory
解决,Dcokerfile 中增加

1
2
3
FROM python:3.8
RUN (apt-get update) && (apt-get install -y libgl1-mesa-dev ffmpeg libsm6 libxext6)
ENV PYTHONUNBUFFERED 1

“No such file or directory hubconf.py”‘

启动后报错
相对路径报错:”No such file or directory hubconf.py”‘原因及解决方法

取相对路径不是在主文件里,可能就会有相对路径问题
修改 ‘./yolov5-master/‘ ‘./yolov5-master/runs/train/exp2/weights/last.pt’ 从执行python 的目录开始计算
model = torch.hub.load(‘./yolov5-master/‘, ‘custom’, ‘./yolov5-master/runs/train/exp2/weights/last.pt’, source=’local’)

这个根据实际情况修改

一辈子很短,努力的做好两件事就好;
第一件事是热爱生活,好好的去爱身边的人;
第二件事是努力学习,在工作中取得不一样的成绩,实现自己的价值,而不是仅仅为了赚钱;

Python yolov5加Flask实现发布图像识别服务

发表于 2023-04-17
字数统计: 592 字 | 阅读时长 ≈ 3 min

yolov5加Flask实现发布图像识别服务

使用Flask作为后端,简单方便,接收到前端传过来的base64,再转为图片,输入到YOLOv5模型当中进行识别,然后会得到识别完成的base64图像,再返回给前端。
使用yolov5s.pt模型。直接使用torch.hub.load()进行模型加载。从本地加载可以避免由于github下载导致的问题。图像传递的过程为web->flask。传递方式都为base64。

加载模型,输入图片进行detect,返回图片的base64编码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
from flask import Flask, jsonify, request, abort
import json
import base64
import numpy as np

import torch
import os
from PIL import Image
import cv2
from io import BytesIO, StringIO


app = Flask(__name__)

@app.route('/ana', methods=['GET', 'POST'])
def call_analysis():
print("Hello, World!")

data1 = request.data #----获取的是字符串
#print(data1)
data2 = request.get_data() #----获取的是字符串
#print(data2)
j_data = json.loads(data2) #-----load将字符串解析成json
# print(j_data)
# print(j_data['base64'])

# return jsonify(j_data)
return getbase64(j_data['base64'])

def getbase64(imgbase64):
# print(img)
# os.environ["CUDA_VISIBLE_DEVICES"]
# model = torch.hub.load('./', 'custom', path='./yolov5s.pt', source='local')
model = torch.hub.load('./yolov5-master/', 'custom', './yolov5-master/runs/train/exp2/weights/last.pt', source='local')
# model.cuda()
# print(model)
# img1 = Image.open(BytesIO(img))


# 传入为RGB格式下的base64,传出为RGB格式的numpy矩阵
byte_data = base64.b64decode(imgbase64)#将base64转换为二进制
encode_image = np.asarray(bytearray(byte_data), dtype="uint8")# 二进制转换为一维数组
img_array = cv2.imdecode(encode_image, cv2.IMREAD_COLOR)# 用cv2解码为三通道矩阵
img_array = cv2.cvtColor(img_array, cv2.COLOR_BGR2RGB)# BGR2RGB

img1 = img_array
imgs = [img1]
#img2 = cv2.imread('./data/images/zidane.jpg')[:,:,::-1]
#imgs = [img2]

results = model(imgs, size=640)
print('识别成功')
results.ims
results.render()
base64_image = ''
for img in results.ims:
buffered = BytesIO()
img_base64 = Image.fromarray(img)
img_base64.save(buffered, format='JPEG')
base64_image = base64.b64encode(buffered.getvalue()).decode('utf-8')
# with open('./result.txt', 'a+') as f:
# f.write(base64_image)
# f.close()
print(results)
results.save()
base64_image = 'data:image/jpeg;base64,%s' % base64_image
return base64_image
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, debug = False)

注意:torch.hub.load() 方法中的路径问题

一辈子很短,努力的做好两件事就好;
第一件事是热爱生活,好好的去爱身边的人;
第二件事是努力学习,在工作中取得不一样的成绩,实现自己的价值,而不是仅仅为了赚钱;

Python Flask工具搭建web微服务

发表于 2023-04-16
字数统计: 1,600 字 | 阅读时长 ≈ 7 min

flask工具搭建web微服务

Flask是一个Python编写的Web 微框架,让咱们可使用Python语言快速实现一个网站或Web服务。
参考自Flask官方文档:https://flask.palletsprojects.com/en/0.12.x/
参考中文文档官方文档:https://dormousehole.readthedocs.io/en/latest/

1.安装flask

需要python 环境,这个自行安装

1
pip install flask

简单上手

最小的 Flask 应用以下flask_demo.py

1
2
3
4
5
6
7
8
9
from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello_world():
return 'Hello World'

if __name__ == '__main__':
app.run()

代码解析:
一、首先咱们导入了 Flask 类。 该类的实例将会成为咱们的 WSGI 应用。 , WSGI作为一个规范,定义了Web服务器如何与Python应用程序进行交互,使得使用Python写的Web应用程序可以和Web服务器对接起来。
二、接着咱们建立一个该类的实例。第一个参数是应用模块或者包的名称。若是你使用 一个单一模块(就像本例),那么应当使用 name ,由于名称会根据这个 模块是按应用方式使用仍是做为一个模块导入而发生变化(多是 ‘main’ , 也多是实际导入的名称)。这个参数是必需的,这样 Flask 才能知道在哪里能够 找到模板和静态文件等东西
三、而后咱们使用 route() 装饰器来告诉 Flask 触发函数的 URL 。
四、函数名称被用于生成相关联的 URL 。函数最后返回须要在用户浏览器中显示的信息

运行结果:

1
2
3
4
5
6
* Serving Flask app "flask_demo" (lazy loading)
* Environment: production
WARNING: This is a development server. Do not use it in a production deployment.
Use a production WSGI server instead.
* Debug mode: off
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

打开链接查看 访问:http://127.0.0.1:5000/

说明

1
app.route(rule, options)

rule 参数表示与该函数的URL绑定。
options 是要转发给基础Rule对象的参数列表。
在上面的示例中,’/ ‘ URL与hello_world()函数绑定。所以,当在浏览器中打开web服务器的主页时,将呈现该函数的输出。

Flask类的run()方法在本地开发服务器上运行应用程序。

1
app.run(host, port, debug, options)

全部参数都是可选的web

host:要监听的主机名。 默认为127.0.0.1(localhost)。设置为“0.0.0.0”以使服务器在外部可用
port :默认值为5000
debug:默认为False。 若是设置为True,则提供调试信息,能够自动重载代码并显示调试信息
options:要转发到底层的Werkzeug服务器。

注意,False 和True 首字母大写

默认状况下,Flask绑定IP为127.0.0.1,端口为5000。也能够经过下面的方式自定义

1
app.run(host='0.0.0.0', port=80, debug=True)

0.0.0.0表明电脑全部的IP。80是HTTP网站服务的默认端口。
什么是默认?好比,咱们访问网站http://www.example.com,实际上是访问的http://www.example.com:80,只不过:80能够省略不写。

Flask HTTP方法

Web 应用使用不一样的 HTTP 方法处理 URL 。当你使用 Flask 时,应当熟悉 HTTP 方法。 缺省状况下,一个路由只回应 GET 请求。 可使用 route() 装饰器的 methods 参数来处理不一样的 HTTP 方法:

方法 描述
GET 以未加密的形式将数据发送到服务器,最多见的方法。
HEAD 和GET方法相同,但没有响应体。
POST 用于将HTML表单数据发送到服务器,POST方法接收的数据不禁服务器缓存。
PUT 用上传的内容替换目标资源的全部当前表示。
DELETE 删除由URL给出的目标资源的全部当前表示。
默认状况下,Flask路由响应GET请求。可是,能够经过为route()装饰器提供方法参数来更改此首选项。

为了演示在URL路由中使用POST方法,首先让咱们建立一个HTML表单,并使用POST方法将表单数据发送到URL。
将如下脚本另存为login.html

1
2
3
4
5
6
7
8
9
10
11
<html>
<body>

<form action = "http://localhost:5000/login" method = "post">
<p>Enter Name:</p>
<p><input type = "text" name = "nm" /></p>
<p><input type = "submit" value = "submit" /></p>
</form>

</body>
</html>

运行如下代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from flask import Flask, redirect, url_for, request
app = Flask(__name__)

@app.route('/success/<name>')
def success(name):
return 'welcome %s' % name

@app.route('/login',methods = ['POST', 'GET'])
def login():
if request.method == 'POST':
user = request.form['nm']
return redirect(url_for('success',name = user))
else:
user = request.args.get('nm')
return redirect(url_for('success',name = user))

if __name__ == '__main__':
app.run(debug = True)

在浏览器中打开login.html,在文本字段中输入name,而后单击提交。
在这里插入图片描述
表单数据将POST到表单标签的action子句中的URL。

http://localhost/login映射到login()函数。因为服务器经过POST方法接收数据,所以经过如下步骤得到从表单数据得到的“nm”参数的值:
表单数据将POST到表单标签的action子句中的URL。

1
user = request.form['nm']

它做为变量部分传递给’/ success’ URL。浏览器在窗口中显示welcome消息。
在这里插入图片描述
在login.html中将方法参数更改成’GET’,而后在浏览器中再次打开它。服务器上接收的数据是经过GET方法得到的。经过如下的步骤得到’nm’参数的值:

1
User = request.args.get('nm')

这里,args是包含表单参数对及其对应值对的列表的字典对象。与’nm’参数对应的值将像以前同样传递到’/ success’ URL。

若是通过json 的方式获取数据,则直接使用data1 = request.get_data() 获取字符传,然后使用json.loads(data2)进行转换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from flask import Flask, jsonify, request, abort
import json
@app.route('/ana', methods=['GET', 'POST'])
def call_analysis():
print("Hello, World!")

data1 = request.data #----获取的是字符串
#print(data1)
data2 = request.get_data() #----获取的是字符串
#print(data2)
j_data = json.loads(data2) #-----load将字符串解析成json
# print(j_data)
# print(j_data['base64'])

# return jsonify(j_data)

一辈子很短,努力的做好两件事就好;
第一件事是热爱生活,好好的去爱身边的人;
第二件事是努力学习,在工作中取得不一样的成绩,实现自己的价值,而不是仅仅为了赚钱;

Python 模型训练Yolov5环境搭建

发表于 2023-04-15
字数统计: 2,799 字 | 阅读时长 ≈ 12 min

模型训练yolov5环境搭建

本文将介绍yolov5从环境搭建到模型训练的整个过程

目录

1.anconda环境搭建
2.yolov5下载
3.素材整理
4.模型训练
5.效果预测

建议提前下载的一些工具或安装包
anconda下载地址:https://www.anaconda.com/products/individual#Downloads
yolov5源码下载地址:https://github.com/ultralytics/yolov5

1.anconda环境搭建

提醒:所有操作都是在anconda的yolo的环境下进行的,在创建yolo环境后,之后每次进入CMD都需要切换到yolo环境中去(否则进入默认的base环境中)

https://www.anaconda.com/products/individual#Downloads
下载对应版本anconda即可,这里不介绍anconda安装过程了。
安装可以参考:https://blog.csdn.net/qq_43674360/article/details/123396415

anconda安装好后,conda可以创建多个运行环境,默认是base环境。这里为yolo创建一个环境。
打开CMD命令行,为yolov5创建一个环境,注意这里用的python版本是3.8,版本过低后面可能会报错

1
conda create -n yolo python=3.8

执行

1
conda info -e

即可看到刚刚创建的yolo环境

1
2
3
4
5
6
7
8
D:\vsCodeWorkspace\python_test_20230415>conda info -e
# conda environments:
#
fl C:\Users\dell\.conda\envs\fl
mind07py375 C:\Users\dell\.conda\envs\mind07py375
myenv C:\Users\dell\.conda\envs\myenv
yolo C:\Users\dell\.conda\envs\yolo
base C:\python20230415\Anaconda3

执行

1
activate yolo

即可切换到的yolo环境下了。记住退出CMD或者切换CMD窗口之后,如果想要进入yolo环境,都需要运行activate yolo指令。不然默认是在base环境下。
除此之外,进行yolo模型训练代码的编写需要用到jupyter notebook,所以需要在yolo环境下进行安装

1
conda install jupyter notebook

安装完成之后,只需要在yolo环境下输入

1
jupyter notebook

就会打开notebook,自动跳转到浏览器,打开notebook界面,之后会在notebook里进行训练yolo模型

yolov5下载

下载yolov5源码:https://github.com/ultralytics/yolov5
解压,可以看到里面有requirements.txt文件,里面记录了需要安装的包,这个txt文件可以帮助一键下载这些依赖包。

文件夹里也包含了train.py文件,这个也接下来训练yolo模型需要用到的启动文件。

接着上面的requirement.txt,介绍如何安装里面需要安装的依赖。首先打开下载好的yolov5_master 文件夹,在上面输入cmd回车,可以直接在该文件夹目录下打开命令行。

在cmd命令行打开之后,大家千万记得要切换到的yolo环境下,不然就安装到base环境中去了。

1
activate yolo

然后运行

1
pip install -r requirements.txt

就会自动把这些依赖安装好了。接下来开始训练yolo模型了。

整理yolov5模型

为了完成训练工作,需要将训练的图片按照指定的格式进行整理,
详细参照yolov5官方指南:
https://github.com/ultralytics/yolov5/wiki/Train-Custom-Data

这里也简要介绍一遍过程,然后也为大家避坑,在训练前首先需要采集图片样本,然后再对图片中的待识别物体进行标注。
首先需要建立如下的文件夹images,labels和A.yaml文件:
D:\VSCODEWORKSPACE\PYTHON_TEST_20230415\YOLO_A
├─images
└─labels
└─A.yaml
所有文件放在yolo_A文件夹下,子文件夹images用来存放样本图片,labels文件夹用来存储标注信息。A.yaml文件用来存放一些目录信息和标志物分类。

这次测试的检测哆啦A梦的头像,采集了50张哆啦A梦的样本,放到images文件夹下:

图片的标注

接下来就要进行图片的标注工作了,图片标注用到了一个名为labelimg的工具:
https://github.com/tzutalin/labelImg
大家下载解压之后,首先要做的是删除
labelImg-master\data\predefined_classes.txt
txt文件中的内容,不然等会标记的时候会自动添加一些奇怪的类别。

然后在labelImg-master文件夹下打开cmd,进入的yolo环境中,然后还需要在yolo环境中安装一些labelimg运行需要的依赖,依次输入

1
2
3
4
activate yolo
conda install pyqt=5
conda install -c anaconda lxml
pyrcc5 -o libs/resources.py resources.qrc

现在,已经在yolo环境中安装好labelimg的依赖环境了,输入

1
python labelimg.py

即可进入的界面中来。进入之后,首先先把一些选项勾上,便于标记。
然后,最重要的是把标记模式改为yolo。

1
2
3
4
5
6
7
8
View 中标记前五个
Auto Save mode
Single Class mode
Display Labels
Show/Hide Label Panel
Advanced Mode

在保存下面的标记模式改为yolo

之后点击Open dir选择图片所在的images文件夹,选择之后会弹窗让你选择labels所在的文件夹。当然如果选错了,也可以点change save dir进行修改。

然后软件右上角打开这个选项,当标记图片后,就会自动帮归类到A了

现在就可以开始进行标记了,常用的快捷键,用主要wad三个键

1
2
3
4
5
6
7
8
9
10
11
12
13
Ctrl + u	Load all of the images from a directory
Ctrl + r Change the default annotation target dir
Ctrl + s Save
Ctrl + d Copy the current label and rect box
Ctrl + Shift + d Delete the current image
Space Flag the current image as verified
w Create a rect box
d Next image
a Previous image
del Delete the selected rect box
Ctrl++ Zoom in
Ctrl-- Zoom out
↑→↓← | Keyboard arrows to move selected rect box

通过鼠标拖拽框选即可标注:

所有图片标注好之后,再来看的labels文件夹,可以看到很多txt文件。每个文件都对应着标记的类别和框的位置:

最后还要做的是建立yaml文件,文件的位置也不要放错:

文件里面内容如下,其中train和val都是images的目录,labels的目录不用写进去,会自动识别。nc代表识别物体的种类数目,names代表种类名称,如果多个物体种类识别的话,可以自行增加。

1
2
3
4
5
6
7
8
# train and val data as 1) directory: path/images/, 2) file: path/images.txt, or 3) list: [path1/images/, path2/images/]
train: ../yolo_A/images/
val: ../yolo_A/images/
# number of classes
nc: 1

# class names
names: ['A meng']

到目前,的训练的图片材料就已经准备好了。

出现问题解决

labelImg闪退的高效解决方法
解决方法:
1.labelImg软件安装路径中不能出现中文路径,如果出现,换个英文的路径,(一般这样情况比较多)。
2.进入到C:\Users\Administrator,将.labelImgSettings.pkl文件删除,重新运行即可。(找不到可以目录下进行搜索)
3:使用labelImg 所在 anaconda 终端环境中依次执行以下命令
pip install PyQt5 -i https://pypi.tuna.tsinghua.edu.cn/simple/
pip install pyqt5-tools -i https://pypi.tuna.tsinghua.edu.cn/simple/
pip install lxml -i https://pypi.tuna.tsinghua.edu.cn/simple/
pip install labelImg -i https://pypi.tuna.tsinghua.edu.cn/simple/
最后在中输入python labelimg.py启动。

yolov5模型训练

现在开始训练模型
首先进行模块导入

1
2
3
4
5
6
7
8
9
10
# 若是没有进行过下载,则进行下载yolov5源码进行
# git clone https://github.com/ultralytics/yolov5 # clone repo
# cd yolov5
# pip install -qr requirements.txt # install dependencies
# 云上环境需要,本地不需要进行,继续往后就行
# import torch
# from IPython.display import Image, clear_output # to display images

# clear_output()
# print('Setup complete. Using torch %s %s' % (torch.__version__, torch.cuda.get_device_properties(0) if torch.cuda.is_available() else 'CPU'))

后把的的素材yolo_A文件夹放到yolov5根目录

然后一下代码可以测试能否正常工作,顺带会下载yolov5s.pt文件,这个文件后面训练的时候会用到

1
2
 python detect.py --weights yolov5s.pt --img 640 --conf 0.25 --source data/images/
# Image(filename='runs/detect/exp/zidane.jpg', width=600)

然后在 yolov5/runs/detect/exp 文件夹可以看到识别结果

接下来就要开始训练模型了:

1
python train.py --img 640 --batch 50 --epochs 100 --data ../yolo_A/A.yaml --weights yolov5s.pt --nosave --cache

注意:../yolo_A/A.yaml 路径按照需要的路径进行调整

训练完成后,们可以看到训练结果保存的位置:

在对应exp文件下可以看到用训练集做预测的结果:

1
Image(filename='runs/train/exp2/test_batch0_pred.jpg', width=800)  # test batch 0 predictions

现在们用训练出来的结果找一张网图做测试(文件名和导出预测文件地址不一定相同,但是相似,自行寻找)

1
2
python detect.py --weights /content/yolov5/runs/train/exp2/weights/best.pt --img 640 --conf 0.25 --source ../test2.jpg
#Image(filename='runs/detect/exp4/test2.jpg', width=600)

出现问题解决

DLL load failed: 页面文件太小,无法完成操作

需要把电脑无用程序都关闭。还有python.exe注意不能同时被2个程序使用,

提示页面文件太小,说明虚拟内存不够了,可以关掉一些进程,

或者把虚拟内存往大调一下(此处参考网上修改) http://www.nndssk.com/xtwt/122595A9Q5mb.html

OSError: [WinError 1114] 动态链接库(DLL)初始化例程失败。 Error loading “C:\Users\dell.conda\envs\yolo\lib\site-packages\torch\lib\shm.dll” or one of its dependencies.

RuntimeError: [enforce fail at C:\actions-runner_work\pytorch\pytorch\builder\windows\pytorch\c10\core\impl\alloc_cpu.cpp:72] data. DefaultCPUAllocator: not enough memory: you tried to allocate 49152000 bytes.

修改train.py中 batchsize和worker,将数值减少,

1
2
3
4
5
6
7
8
9
10
parser.add_argument('--hyp', type=str, default=ROOT / 'data/hyps/hyp.scratch-low.yaml', help='hyperparameters path')
parser.add_argument('--epochs', type=int, default=100, help='total training epochs')
#parser.add_argument('--batch-size', type=int, default=16, help='total batch size for all GPUs, -1 for autobatch')
parser.add_argument('--batch-size', type=int, default=2, help='total batch size for all GPUs, -1 for autobatch')

parser.add_argument('--optimizer', type=str, choices=['SGD', 'Adam', 'AdamW'], default='SGD', help='optimizer')
parser.add_argument('--sync-bn', action='store_true', help='use SyncBatchNorm, only available in DDP mode')
#parser.add_argument('--workers', type=int, default=8, help='max dataloader workers (per RANK in DDP mode)')
parser.add_argument('--workers', type=int, default=2, help='max dataloader workers (per RANK in DDP mode)')
parser.add_argument('--project', default=ROOT / 'runs/train', help='save to project/name')

TabError: Inconsistent use of tabs and spaces in indentation

首先这个错误的意思是:在缩进的时候,使用了错误的空格和tab

造成这个错误的原因是代码前先用了空格然后再用tab完成了对齐,也就是说,这种错误产生的原因正是由于空格或者tab缩进造成的。

将空格删除,直接使用tab完成缩进,发现程序正常运行;

再试一下空格缩进,然后发现还是报错了,同样TabError: Inconsistent use of tabs and spaces in indentation。

注意,整个代码一定使用相同的,都用空格,或者都用tab

AssertionError: Label class 1 exceeds nc=1 in data/steel.yaml. Possible class labels are 0-0

仔细阅读报错内容可以发现:类别与标签序号不匹配(自定义数据集只有一类)
经过的仔细思考,猜测是在生成labels时出现了问题,通过阅读生成labels的脚本,找到问题如下:
查看 labels 首行首个字母是2 不是0 ,需要将2修改为 0

一辈子很短,努力的做好两件事就好;
第一件事是热爱生活,好好的去爱身边的人;
第二件事是努力学习,在工作中取得不一样的成绩,实现自己的价值,而不是仅仅为了赚钱;

Win10 Linux如何查看目录树

发表于 2023-03-22
字数统计: 377 字 | 阅读时长 ≈ 2 min

windows cmd 查看文件目录树

1.打开命令终端

点击底部栏 Windows图标,选择“Windows系统”中的“命令提示符”
右键以管理员身份运行

2.输入命令

tree:不输入任何参数,输出一棵目录树

1
tree
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
D:.
│ config.json
│
├─ets
│ ├─FormAbility
│ │ form.ts
│ │
│ ├─MainAbility
│ │ │ app.ets
│ │ │
│ │ └─pages
│ │ index.ets
│ │ SecondPage.ets
│ │
│ ├─model
│ │ Logger.ets
│ │
│ └─SecondAbility
│ │ app.ets
│ │
│ └─pages
│ index.ets
│
├─js
│ ├─widget
│ │ ├─common
│ │ ├─i18n
│ │ └─pages
│ │ └─index
│ │ index.css
│ │ index.hml
│ │ index.json
│ │
│ └─widget1
│ ├─common
│ │ widget.png
│ │
│ ├─i18n
│ │ zh-CN.json
│ │
│ └─pages
│ └─index
│ index.css
│ index.hml
│ index.json
│
└─resources
├─base
│ ├─element
│ │ color.json
│ │ string.json
│ │
│ └─media
│ icon.png
│
├─en_US
│ └─element
│ string.json
│
├─rawfile
└─zh_CN
└─element
string.json

注意的一点是,符号需要是英文格式,并且中间拥有空格,否则提示:参数无效,无法操作识别等情况发生。

3.提示

1
tree /?:命令提示

Linux查看目录树形结构

1.安装

安装tree。

1
yum -y install tree

2.验证

查看是否安装成功

1
yum list installed  tree

3.查看

执行tree命令查看目录树形结构

1
tree

一辈子很短,努力的做好两件事就好;
第一件事是热爱生活,好好的去爱身边的人;
第二件事是努力学习,在工作中取得不一样的成绩,实现自己的价值,而不是仅仅为了赚钱;

1…8910…38

继开

一辈子很短,努力的做好两件事就好:第一件事是热爱生活,好好的去爱身边的人;第二件事是努力学习,在工作中取得不一样的成绩,实现自己的价值,而不是仅仅为了赚钱。

303 日志
171 标签
RSS
gitee E-Mail
0%
鲁ICP备18007712号
© 2025 继开 | 站点字数统计: 262.2k
博客使用 Hexo 搭建
|
主题 — NexT.Mist v5.1.4
人访问 次查看