继开 | 博客

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


  • 短诗的序

  • 迷途自渡

  • 寒星三两

  • 林深见鹿

  • 记昨日书

  • 顾探往昔

Python Paddlepaddle使用mnist数据集训练图片识别并且验证

发表于 2023-05-18
字数统计: 836 字 | 阅读时长 ≈ 4 min

环境准备

python3.7
paddlepaddle

训练代码

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
import paddle
from paddle.vision.transforms import Compose, Normalize
from paddle.metric import Accuracy



# 使用transform对数据集做归一化
transform = Compose([Normalize(mean=[127.5], std=[127.5], data_format='CHW')])
# 使用MNIST数据集,第一次使用,会从网络下载,地址为国外服务器,速度可能较慢
train_dataset = paddle.vision.datasets.MNIST(mode='train', transform=transform)
test_dataset = paddle.vision.datasets.MNIST(mode='test', transform=transform)



model = paddle.Model(paddle.vision.models.LeNet()) # 使用内置的LeNet网络创建模型

optim = paddle.optimizer.Adam(learning_rate=0.001, parameters=model.parameters())

# 配置模型
model.prepare(
optim,
paddle.nn.CrossEntropyLoss(),
Accuracy()
)


# 训练模型
model.fit(train_dataset,
epochs=10,
batch_size=64,
verbose=1
)
# 若想保存训练模型中的过程量则可以新增save_dir参数,
# model.fit(train_dataset,
# epochs=10,
# batch_size=64,
# save_dir='./testfive/mnist_checkpoint',
# verbose=1
# )
# 保存模型 ./testfive/mnist_checkpoint/为保存模型的路径 test为保存模型的名称
# 若只使用model.save('test', training=False) 则模型保存在当前运行目录下
model.save('./testfive/mnist_checkpoint/test', training=False)

输出结果如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
The loss value printed in the log is the current step, and the metric is the average value of previous steps.
Epoch 1/10
step 938/938 [==============================] - loss: 0.0400 - acc: 0.9339 - 21ms/step
Epoch 2/10
step 938/938 [==============================] - loss: 0.0216 - acc: 0.9748 - 21ms/step
Epoch 3/10
step 938/938 [==============================] - loss: 0.0129 - acc: 0.9785 - 21ms/step
Epoch 4/10
step 938/938 [==============================] - loss: 0.0056 - acc: 0.9819 - 21ms/step
Epoch 5/10
step 938/938 [==============================] - loss: 0.0246 - acc: 0.9833 - 21ms/step
Epoch 6/10
step 938/938 [==============================] - loss: 0.0951 - acc: 0.9849 - 21ms/step
Epoch 7/10
step 938/938 [==============================] - loss: 0.0317 - acc: 0.9861 - 21ms/step
Epoch 8/10
step 938/938 [==============================] - loss: 6.0844e-04 - acc: 0.9878 - 22ms/step
Epoch 9/10
step 938/938 [==============================] - loss: 0.0028 - acc: 0.9881 - 21ms/step
Epoch 10/10
step 938/938 [==============================] - loss: 0.0107 - acc: 0.9893 - 21ms/step
D:\MyWorkProgram\anaconda3\envs\paddle\lib\site-packages\paddle\hapi\model.py:2199: UserWarning: 'inputs' was not specified when Model initialization, so the input shape
to be saved will be the shape derived from the user's actual inputs. The input shape to be saved is [[64, 1, 28, 28]]. For saving correct input shapes, please provide 'inputs' for Model initialization.
% self._input_info[0]

最后输出的结果可能仅仅为警告,忽略即可,不影响结果

获得最终的模型文件

1
2
3
D:\vsCodeWorkspace\pythonpaddleNumber\testfive\mnist_checkpoint\test.pdmodel
D:\vsCodeWorkspace\pythonpaddleNumber\testfive\mnist_checkpoint\test.pdiparams.info
D:\vsCodeWorkspace\pythonpaddleNumber\testfive\mnist_checkpoint\test.pdiparams

验证模型

从数据集的测试集中随机获取一张图片,进行预测,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

import paddle
from paddle.vision.transforms import Compose, Normalize
from paddle.metric import Accuracy
import numpy as np

m = paddle.jit.load("./testfive/mnist_checkpoint/test")
m.eval() # 设置为预测模型

# 使用transform对数据集做归一化
transform = Compose([Normalize(mean=[127.5], std=[127.5], data_format='CHW')])
test_dataset = paddle.vision.datasets.MNIST(mode='test', transform=transform)
# train_dataset = paddle.vision.datasets.MNIST(mode='train', transform=transform)

img1,label1 = test_dataset[1];


pre = m(np.array([img1])) # 预测结果
print("预测数字:", np.argmax(pre)) # 输出预测数字

print("真实数字:", label1) # 输出真实数字

输出结果如下

1
2
预测数字: 2  
真实数字: [2]

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

Python paddlepaddle读取MNIST数据集,并且显示出图片格式

发表于 2023-05-17
字数统计: 414 字 | 阅读时长 ≈ 2 min

环境准备

python3.7
paddlepaddle

代码如下

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
import paddle
from paddle.vision.transforms import Compose, Normalize
from paddle.metric import Accuracy
import numpy as np
from PIL import Image

# 使用transform对数据集做归一化
transform = Compose([Normalize(mean=[127.5], std=[127.5], data_format='CHW')])
# mode='test' 选择测试数据集,mode='train'选择训练数据集
test_dataset = paddle.vision.datasets.MNIST(mode='test', transform=transform)
# train_dataset = paddle.vision.datasets.MNIST(mode='train', transform=transform)

#选择数据集中随机一个元素,test_dataset 中每一个数据元素代表一个 图片和它的 标签,
# test_dataset[1] 为取数组中的第二个元素,其中1可以换成 别的元素下标;
# 其中 img1 = test_dataset[1][0] label1 = test_dataset[1][1] 简写如下
img1,label1 = test_dataset[1];
print("打印出实际值");
print(label1);

# 此方法是是将图片由二位数组转化为可读取的格式的,并且展示
#unit8(无符号的整数,unit8是0~255
def img_show(img):
pil_img = Image.fromarray(np.uint8(img))#Image.fromarray图像数据转换为PIL数据对象
pil_img.show()#显示图片


# 读取图片所占空间大小(1,28,28)
print(img1.shape)
# 把图像的形状变为原来的尺寸,由上面的数据可知为28,28
img = img1.reshape(28, 28)
# 读取图片所占空间大小# (28, 28)
print(img.shape)
#将图片展示出来
img_show(img)

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

Python Paddlepaddle打docker镜像包发布服务

发表于 2023-05-16
字数统计: 2,883 字 | 阅读时长 ≈ 15 min

环境准备

linux 环境
docker 环境
docker-compose 环境
python3.7

打包准备

dockerfile 文件夹下有四个文件,将相应文件放到linux 的dockerfile文件夹下

1
2
3
4
5
6
dockerfile 
├─Dockerfile #为打包使用的Dockerfile的文件
├─flask_model_zcy.py #为启动的主函数的文件
├─paddlezcy.yml #为docker-compose 的启动文件 打包之后启动使用
├─requirements.txt #为python 的相关依赖
└─save_dir_final.pdparams #为训练出的模型文件
Dockerfile
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
#基于的基础镜像
FROM python:3.7
#解决 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 sed -i s@/archive.ubuntu.com/@/mirrors.aliyun.com/@g /etc/apt/sources.list
RUN apt-get clean
RUN apt-get update
RUN apt-get install ffmpeg libsm6 libxext6 -y

#设置上海时间
ENV TZ=Asia/Shanghai
RUN cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
#中文乱码en_US.utf8
ENV LANG en_US.utf8


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

注意 model__state_dict = paddle.load(‘./save_dir_final.pdparams’) 此处模型位置写正确

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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
import io
from flask import Flask, jsonify, request, abort
import json
import base64
import numpy as np

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

# 引入需要的模块
import os
import zipfile
import random
import json
import paddle
import sys
import numpy as np
from PIL import Image
import matplotlib.pyplot as plt
from paddle.io import Dataset

app = Flask(__name__)

#所有的标签,以及数字对应的标签
label_dic = {'0': 'baihe', '1': 'dangshen', '2': 'gouqi', '3': 'huaihua', '4': 'jinyinhua'}
#所有的标签数量
class_dim = 0
for key in label_dic:
class_dim =class_dim+1
print(class_dim)



@app.route('/zcy', 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'])

# decode_base64_matplot_img(j_data['base64'])
# return ""
return getAnalysis(j_data['base64'])


def getAnalysis(imgbase64):



# 加载训练过程保存的最后一个模型
model__state_dict = paddle.load('./save_dir_final.pdparams')
model_predict = VGGNet()
model_predict.set_state_dict(model__state_dict)
model_predict.eval()

infer_img = load_image2(imgbase64)
infer_img = infer_img[np.newaxis,:, : ,:] #reshape(-1,3,224,224)
infer_img = paddle.to_tensor(infer_img)
result = model_predict(infer_img)
print(result.numpy())
lab = np.argmax(result.numpy())
print("样本: {},被预测为:{}".format("1",label_dic[str(lab)]))
return "样本被预测为:{}".format(label_dic[str(lab)])

# def getbase64(imgbase64):


# # 传入为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




# 定义卷积池化网络
class ConvPool(paddle.nn.Layer):
'''卷积+池化'''
def __init__(self,
num_channels,
num_filters,
filter_size,
pool_size,
pool_stride,
groups,
conv_stride=1,
conv_padding=1,
):
super(ConvPool, self).__init__()

# groups代表卷积层的数量
for i in range(groups):
self.add_sublayer( #添加子层实例
'bb_%d' % i,
paddle.nn.Conv2D( # layer
in_channels=num_channels, #通道数
out_channels=num_filters, #卷积核个数
kernel_size=filter_size, #卷积核大小
stride=conv_stride, #步长
padding = conv_padding, #padding
)
)
self.add_sublayer(
'relu%d' % i,
paddle.nn.ReLU()
)
num_channels = num_filters


self.add_sublayer(
'Maxpool',
paddle.nn.MaxPool2D(
kernel_size=pool_size, #池化核大小
stride=pool_stride #池化步长
)
)

def forward(self, inputs):
x = inputs
for prefix, sub_layer in self.named_children():
# print(prefix,sub_layer)
x = sub_layer(x)
return x

# VGG网络
class VGGNet(paddle.nn.Layer):
def __init__(self):
super(VGGNet, self).__init__()
# 5个卷积池化操作
self.convpool01 = ConvPool(
3, 64, 3, 2, 2, 2) #3:通道数,64:卷积核个数,3:卷积核大小,2:池化核大小,2:池化步长,2:连续卷积个数
self.convpool02 = ConvPool(
64, 128, 3, 2, 2, 2)
self.convpool03 = ConvPool(
128, 256, 3, 2, 2, 3)
self.convpool04 = ConvPool(
256, 512, 3, 2, 2, 3)
self.convpool05 = ConvPool(
512, 512, 3, 2, 2, 3)
self.pool_5_shape = 512 * 7* 7
# 三个全连接层
self.fc01 = paddle.nn.Linear(self.pool_5_shape, 4096)
self.drop1 = paddle.nn.Dropout(p=0.5)
self.fc02 = paddle.nn.Linear(4096, 4096)
self.drop2 = paddle.nn.Dropout(p=0.5)
self.fc03 = paddle.nn.Linear(4096, class_dim)

def forward(self, inputs, label=None):
# print('input_shape:', inputs.shape) #[8, 3, 224, 224]
"""前向计算"""
out = self.convpool01(inputs)
# print('convpool01_shape:', out.shape) #[8, 64, 112, 112]
out = self.convpool02(out)
# print('convpool02_shape:', out.shape) #[8, 128, 56, 56]
out = self.convpool03(out)
# print('convpool03_shape:', out.shape) #[8, 256, 28, 28]
out = self.convpool04(out)
# print('convpool04_shape:', out.shape) #[8, 512, 14, 14]
out = self.convpool05(out)
# print('convpool05_shape:', out.shape) #[8, 512, 7, 7]

out = paddle.reshape(out, shape=[-1, 512*7*7])
out = self.fc01(out)
out = self.drop1(out)
out = self.fc02(out)
out = self.drop2(out)
out = self.fc03(out)

if label is not None:
acc = paddle.metric.accuracy(input=out, label=label)
return out, acc
else:
return out





def load_image(img_path):
'''
预测图片预处理
'''
img = Image.open(img_path)
if img.mode != 'RGB':
img = img.convert('RGB')
img = img.resize((224, 224), Image.BILINEAR)
img = np.array(img).astype('float32')
img = img.transpose((2, 0, 1)) / 255 # HWC to CHW 及归一化
return img

def load_image2(img_base64):


'''
预测图片预处理
'''
# byte_data = base64.b64decode(img_base64)#将base64转换为二进制
# img = np.fromstring(byte_data, np.uint8) # 转换np序列



# img = np.asarray(bytearray(byte_data), dtype="uint8")# 二进制转换为一维数组
# img = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))

# plt.imshow(img)
# plt.axis('off')
# plt.show()
# sys.stdout.flush()

img = base64.b64decode(img_base64)
buffer = io.BytesIO()
img = Image.open(io.BytesIO(img))
# img = Image.open(img_base64)
if img.mode != 'RGB':
img = img.convert('RGB')
img = img.resize((224, 224), Image.BILINEAR)
img = np.array(img).astype('float32')
print('numpy: ', img.shape)
img = img.transpose((2, 0, 1)) / 255 # HWC to CHW 及归一化
return img

# 解码base64字符串为matplot图像
def decode_base64_matplot_img(base64_data):
img = base64.b64decode(base64_data)
img_array = np.fromstring(img, np.uint8) # 转换np序列
img_raw = cv2.imdecode(img_array, cv2.IMREAD_COLOR) # 转换Opencv格式BGR
img_matplot = cv2.cvtColor(img_raw, cv2.COLOR_BGR2RGB) # BGR转RGB

img_gray = cv2.imdecode(img_array, cv2.IMREAD_GRAYSCALE) # 转换灰度图
imggray_matplot = cv2.cvtColor(img_gray, cv2.COLOR_GRAY2RGB) # 灰度图转RGB
plt.figure()
plt.title("Matplot RGB Origin Image")
plt.axis("off")
plt.imshow(img_matplot)

plt.figure()
plt.title("Matplot Gray Origin Image")
plt.axis("off")
plt.imshow(imggray_matplot)
plt.show()

if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, debug = False)

#json模块编码: json.dumps()
#json模块解码:解码python json格式,用json.loads()
paddlezcy.yml
1
2
3
4
5
6
7
8
9
10
#docker-compose -f paddlezcy.yml up -d
#paddlezcy.yml 配置文件如下
version: "3"
services:
paddlezcy:
image: paddlezcy:v1
container_name: paddlezcy
privileged: true
ports:
- 5001:5000
requirements.txt

可由 pip freeze > requirements.txt 命令生成

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
astor==0.8.1
certifi==2022.12.7
charset-normalizer==3.1.0
click==8.1.3
colorama==0.4.6
cycler==0.11.0
decorator==5.1.1
Flask==2.2.5
fonttools==4.38.0
idna==3.4
importlib-metadata==6.6.0
itsdangerous==2.1.2
Jinja2==3.1.2
kiwisolver==1.4.4
MarkupSafe==2.1.2
matplotlib==3.5.3
numpy==1.21.6
opencv-python==4.3.0.38
opt-einsum==3.3.0
packaging==23.1
paddle-bfloat==0.1.7
paddlepaddle==2.4.2
Pillow==9.5.0
protobuf==3.20.0
pyparsing==3.0.9
python-dateutil==2.8.2
requests==2.29.0
six==1.16.0
torch==1.13.1
typing_extensions==4.5.0
urllib3==1.26.15
Werkzeug==2.2.3
zipp==3.15.0

开始打包

下载依赖到本地

1
pip download -d py_pkgs -r requirements.txt -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com

注意需要在linux 下执行,因打包docker 的基础镜像也为linux的系统
依赖比较多下载时间比较长,建议在网络环境较好的情况下进行

执行之后生成 py_pkgs 文件夹,内为需要的python 依赖包

执行打包命令

1
docker build -t paddlezcy:v1 .

docker 打包命令注意不要漏掉命令的最后“.”
打包时间比较长,建议在网络环境较好的情况进行

查看镜像包

1
2
(paddle) [root@localhost dockerfile]# docker images  
paddlezcy v1 228d20fd403d 1 hours ago 7.96GB

启动服务

使用docker-compose启动服务

1
docker-compose -f paddlezcy.yml up -d

查看服务

1
2
3
(paddle) [root@localhost dockerfile]# docker ps 
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
741fba797df6 paddlezcy:v1 "python /code/flask_…" 13 hours ago Up About an hour 0.0.0.0:5001->5000/tcp, :::5001->5000/tcp paddlezcy

问题解决

注意,这些问题在服务启动,或则调用的时候出现,需要在打包的时候进行处理,
docker logs -f 服务id 进行查看日志

问题1
1
2
3
4
5
6
7
8
9
10
C++ Traceback (most recent call last):
--------------------------------------
No stack trace in paddle, may be caused by external reasons.

----------------------
Error Message Summary:
----------------------
FatalError: `Segmentation fault` is detected by the operating system.
[TimeInfo: *** Aborted at 1684242600 (unix time) try "date -d @1684242600" if you are using GNU date ***]
[SignalInfo: *** SIGSEGV (@0x10) received by PID 1 (TID 0x7f26a3395700) from PID 16 ***]
解决方式

1.降低 opencv-python版本,从4.4版本降低到4.2版本,

1
sudo pip install --upgrade opencv-python==4.2.0.32

此处把requirements.txt 中的依赖调低
若opencv-python 调低之后显示无版本,则按照提示版本进行调整

2.通常很难出现这样的错误。只能一点点排除:
1.磁盘空间满了。 比如/tmp, /var 或者是/分区满了。
2.文件读写错误,在临时目录里,某些文件被锁,无法读写导致
3.内存不足(这个可能性小),你可以将占用内存多的程序去掉
4.你是在虚拟机里运行,可能内存访问函数不能正确使用
5.有防火墙的问题
6.可能是权限的问题,比如某些程序需要超级用户的权限
7.程序本身有BUG,它预留的计算空间不够。你可以检查一下配置什么的,看看有没有设置预加载内存的配置。

内存不足,本次运行的时候正好遇到,建议将多余的程序进行关闭

问题2
1
2
from .cv2 import *
ImportError: libGL.so.1: cannot open shared object file: No such file or directory
解决方式

ubuntu 系统

1
2
3
4
5
apt install libgl1-mesa-glx
```
Centos,yum没有找到这个安装包

通过yum list | grep libgl 发现有两个包相关性比较强

mesa-libglapi.x86_64 18.3.4-12.el7_9
pygtk2-libglade.x86_64 2.24.0-9.el7

1
进行安装

yum install mesa-libglapi.x86_64 pygtk2-libglade.x86_64

1
2
3
4

## 验证服务

外部使用postman调用该地址,注意将ip 换成启动服务的机器地址

http://192.168.23.134:5001/zcy

1
调用参数

{
“base64”:”/9j/2wCEA…..
}

1
2
3
4
5
base64 传入的为图片的base64位编码,注意将data:image/jpeg;base64,前缀去掉

可用于图片转换base64的网站 https://c.runoob.com/front-end/59/

调用返回

样本被预测为:gouqi

```
则验证服务调用成功

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

Python Python下载依赖包,并且从本地安装依赖

发表于 2023-05-15
字数统计: 195 字 | 阅读时长 ≈ 1 min

说明

需要在断网环境启动python 项目,就需要提前安装python 相关依赖,可用此方案下载安装

打包python项目所需的依赖:

1
pip freeze > requirements.txt

下载python项目所需依赖包到指定文件夹py_pkgs:

在有网络环境下执行

1
pip download -d py_pkgs -r requirements.txt -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com

安装离线的包

将py_pkg复制到无网络的环境下,执行

1
pip install --no-index --find-links=py_pkgs  -r requirements.txt

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

Python Python 对图像进行Base64编码及解码读取为numpy、opencv、matplot需要的格式

发表于 2023-05-14
字数统计: 691 字 | 阅读时长 ≈ 4 min

说明

Python 对图像进行base64编码及解码读取为numpy、opencv、matplot需要的格式

代码

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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# 对图片进行base64编码,解码,解码为numpy,opencv,matplot照片
# USAGE
# python base64_2_jpg.py

import base64

import cv2
import numpy as np
from matplotlib import pyplot as plt


# 将字符串写入文字
# name 图片名
# base64_data 图片二进制编码后string流
def write2txt(name, base64_data):
# 写入_base64.txt
print(name)
print(name,len(base64_data))
basef = open(name + '_base64.txt', 'w')
data = 'data:image/jpg;base64,%s' % base64_data
# print(data)
basef.write(base64_data)
basef.close()


# 编码图像为base64字符串
def encode_base64(file):
with open(file, 'rb') as f:
img_data = f.read()
base64_data = base64.b64encode(img_data)
print(type(base64_data))
# print(base64_data)
# 如果想要在浏览器上访问base64格式图片,需要在前面加上:data:image/jpeg;base64,
base64_str = str(base64_data, 'utf-8')
# print(base64_str)
print(len(base64_data))
write2txt(file.replace(".jpg", ""), base64_str)
return base64_data


# 解码base64字符串为图像,并保存
def decode_base64(base64_data):
with open('./images/base64.jpg', 'wb') as file:
img = base64.b64decode(base64_data)
file.write(img)


# 解码base64字符串为numpy图像、opencv、matplot图像

# 解码base64字符串为numpy图像
def decode_base64_np_img(base64_data):
img = base64.b64decode(base64_data)
img_array = np.fromstring(img, np.uint8) # 转换np序列
print('numpy: ', img_array.shape)
cv2.imshow("img", img_array)
cv2.waitKey(0)


# 解码base64字符串为opencv图像
def decode_base64_cv_img(base64_data):
img = base64.b64decode(base64_data)
img_array = np.fromstring(img, np.uint8) # 转换np序列
img_raw = cv2.imdecode(img_array, cv2.IMREAD_COLOR) # 转换Opencv格式BGR
img_gray = cv2.imdecode(img_array, cv2.IMREAD_GRAYSCALE) # 转换灰度图

print('opencv bgr: ', img_raw.shape)
print('opencv gray: ', img_gray.shape)

cv2.imshow("img bgr", img_raw)
cv2.imshow("img gray", img_gray)
cv2.waitKey(0)


# 解码base64字符串为matplot图像
def decode_base64_matplot_img(base64_data):
img = base64.b64decode(base64_data)
img_array = np.fromstring(img, np.uint8) # 转换np序列
img_raw = cv2.imdecode(img_array, cv2.IMREAD_COLOR) # 转换Opencv格式BGR
img_matplot = cv2.cvtColor(img_raw, cv2.COLOR_BGR2RGB) # BGR转RGB

img_gray = cv2.imdecode(img_array, cv2.IMREAD_GRAYSCALE) # 转换灰度图
imggray_matplot = cv2.cvtColor(img_gray, cv2.COLOR_GRAY2RGB) # 灰度图转RGB
plt.figure()
plt.title("Matplot RGB Origin Image")
plt.axis("off")
plt.imshow(img_matplot)

plt.figure()
plt.title("Matplot Gray Origin Image")
plt.axis("off")
plt.imshow(imggray_matplot)
plt.show()
print("111")


if __name__ == '__main__':
img_path = './testworkfour/data/Chinese Medicine/dangshen/dangshen_6.jpg'
base64_data = encode_base64(img_path)
decode_base64(base64_data)

decode_base64_np_img(base64_data)
decode_base64_cv_img(base64_data)
decode_base64_matplot_img(base64_data)



# base64 的 Image.open
# from PIL import Image
# import io
# img = base64.b64decode(img_base64)
# buffer = io.BytesIO()
# img = Image.open(io.BytesIO(img))

# base64 的 Image.open等价于如下代码
# img = Image.open(img_path)

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

Python paddlepaddle基于图像分类网络VGG实现中草药识别并发布成应用

发表于 2023-05-13
字数统计: 7,854 字 | 阅读时长 ≈ 42 min

paddlepaddle基于图像分类网络VGG实现中草药识别并发布成应用

本文仅对代码进行记录,详细了解请看原文
原文链接:https://aistudio.baidu.com/aistudio/projectdetail/2310126?channelType=0&channel=0

原数据集地址: https://bj.bcebos.com/ai-studio-online/3c0c4d559b9941c38892855470a26bea17371e1938b34731acde5407a7c60410?authorization=bce-auth-v1%2F5cfe9a5e1454405eb2a975c43eace6ec%2F2022-09-04T15%3A26%3A48Z%2F-1%2F%2F0723b1538c1ae02efb5301af77b9a715e7702678611a09030dd53e0e602b48eb&responseContentDisposition=attachment%3B%20filename%3DChinese%20Medicine.zip

数据集集下载之后名称: Chinese Medicine.zip

模型训练的代码

若是进了解过程,不追求准确率,建议将每种类型的图像数据,删减到20张图片,训练速度不会那么慢
即,这里这个解压函数运行一次,之后去删除多余数据,然后将此处注掉,然后再运行后面的代码

1
2
# 调用解压函数解压数据集
#unzip_data(src_path,target_path)

完整训练代码如下

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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
# 引入需要的模块
import os
import zipfile
import random
import json
import paddle
import sys
import numpy as np
from PIL import Image
import matplotlib.pyplot as plt
from paddle.io import Dataset
random.seed(200)

train_parameters = {
"src_path":"./testworkfour/Chinese Medicine.zip", #原始数据集路径
"target_path":"./testworkfour/data/", #要解压的路径
"train_list_path": "./testworkfour/data/train.txt", #train.txt路径
"eval_list_path": "./testworkfour/data/eval.txt", #eval.txt路径
"label_dict":{}, #标签字典
"readme_path": "./testworkfour/data/readme.json", #readme.json路径
"class_dim": -1, #分类数
}
src_path=train_parameters['src_path']
target_path=train_parameters['target_path']
train_list_path=train_parameters['train_list_path']
eval_list_path=train_parameters['eval_list_path']


def unzip_data(src_path,target_path):
if(not os.path.isdir(target_path + "Chinese Medicine")):
z = zipfile.ZipFile(src_path, 'r')
z.extractall(path=target_path)
z.close()



def get_data_list(target_path,train_list_path,eval_list_path):
'''
生成数据列表
'''
#存放所有类别的信息
class_detail = []
#获取所有类别保存的文件夹名称
data_list_path=target_path+"Chinese Medicine/"
class_dirs = os.listdir(data_list_path)
#总的图像数量
all_class_images = 0
#存放类别标签
class_label=0
#存放类别数目
class_dim = 0
#存储要写进eval.txt和train.txt中的内容
trainer_list=[]
eval_list=[]
#读取每个类别,['baihe', 'gouqi','jinyinhua','huaihua','dangshen']
for class_dir in class_dirs:
if class_dir != ".DS_Store":
class_dim += 1
#每个类别的信息
class_detail_list = {}
eval_sum = 0
trainer_sum = 0
#统计每个类别有多少张图片
class_sum = 0
#获取类别路径
path = data_list_path + class_dir
# 获取所有图片
img_paths = os.listdir(path)
for img_path in img_paths: # 遍历文件夹下的每个图片
name_path = path + '/' + img_path # 每张图片的路径
if class_sum % 8 == 0: # 每8张图片取一个做验证数据
eval_sum += 1 # test_sum为测试数据的数目
eval_list.append(name_path + "\t%d" % class_label + "\n")
else:
trainer_sum += 1
trainer_list.append(name_path + "\t%d" % class_label + "\n")#trainer_sum测试数据的数目
class_sum += 1 #每类图片的数目
all_class_images += 1 #所有类图片的数目

# 说明的json文件的class_detail数据
class_detail_list['class_name'] = class_dir #类别名称
class_detail_list['class_label'] = class_label #类别标签
class_detail_list['class_eval_images'] = eval_sum #该类数据的测试集数目
class_detail_list['class_trainer_images'] = trainer_sum #该类数据的训练集数目
class_detail.append(class_detail_list)
#初始化标签列表
train_parameters['label_dict'][str(class_label)] = class_dir
class_label += 1

#初始化分类数
train_parameters['class_dim'] = class_dim

#乱序
random.shuffle(eval_list)
with open(eval_list_path, 'a') as f:
for eval_image in eval_list:
f.write(eval_image)

random.shuffle(trainer_list)
with open(train_list_path, 'a') as f2:
for train_image in trainer_list:
f2.write(train_image)

# 说明的json文件信息
readjson = {}
readjson['all_class_name'] = data_list_path #文件父目录
readjson['all_class_images'] = all_class_images
readjson['class_detail'] = class_detail
jsons = json.dumps(readjson, sort_keys=True, indent=4, separators=(',', ': '))
with open(train_parameters['readme_path'],'w') as f:
f.write(jsons)
print ('生成数据列表完成!')





# 调用解压函数解压数据集
# unzip_data(src_path,target_path)


# 划分训练集与验证集,乱序,生成数据列表
#每次生成数据列表前,首先清空train.txt和eval.txt
with open(train_list_path, 'w') as f:
f.seek(0)
f.truncate()
with open(eval_list_path, 'w') as f:
f.seek(0)
f.truncate()
#生成数据列表
get_data_list(target_path,train_list_path,eval_list_path)




# 定义数据读取器
class dataset(Dataset):
def __init__(self, data_path, mode='train'):
"""
数据读取器
:param data_path: 数据集所在路径
:param mode: train or eval
"""
super().__init__()
self.data_path = data_path
self.img_paths = []
self.labels = []

if mode == 'train':
with open(os.path.join(self.data_path, "train.txt"), "r", encoding="utf-8") as f:
self.info = f.readlines()
for img_info in self.info:
img_path, label = img_info.strip().split('\t')
self.img_paths.append(img_path)
self.labels.append(int(label))

else:
with open(os.path.join(self.data_path, "eval.txt"), "r", encoding="utf-8") as f:
self.info = f.readlines()
for img_info in self.info:
img_path, label = img_info.strip().split('\t')
self.img_paths.append(img_path)
self.labels.append(int(label))


def __getitem__(self, index):
"""
获取一组数据
:param index: 文件索引号
:return:
"""
# 第一步打开图像文件并获取label值
img_path = self.img_paths[index]
img = Image.open(img_path)
if img.mode != 'RGB':
img = img.convert('RGB')
img = img.resize((224, 224), Image.BILINEAR)
#img = rand_flip_image(img)
img = np.array(img).astype('float32')
img = img.transpose((2, 0, 1)) / 255
label = self.labels[index]
label = np.array([label], dtype="int64")
return img, label

def print_sample(self, index: int = 0):
print("文件名", self.img_paths[index], "\t标签值", self.labels[index])

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






#训练数据加载
train_dataset = dataset('./testworkfour/data',mode='train')
train_loader = paddle.io.DataLoader(train_dataset, batch_size=32, shuffle=True)
#评估数据加载
eval_dataset = dataset('./testworkfour/data',mode='eval')
eval_loader = paddle.io.DataLoader(eval_dataset, batch_size = 8, shuffle=False)


# 定义卷积池化网络
class ConvPool(paddle.nn.Layer):
'''卷积+池化'''
def __init__(self,
num_channels,
num_filters,
filter_size,
pool_size,
pool_stride,
groups,
conv_stride=1,
conv_padding=1,
):
super(ConvPool, self).__init__()

# groups代表卷积层的数量
for i in range(groups):
self.add_sublayer( #添加子层实例
'bb_%d' % i,
paddle.nn.Conv2D( # layer
in_channels=num_channels, #通道数
out_channels=num_filters, #卷积核个数
kernel_size=filter_size, #卷积核大小
stride=conv_stride, #步长
padding = conv_padding, #padding
)
)
self.add_sublayer(
'relu%d' % i,
paddle.nn.ReLU()
)
num_channels = num_filters


self.add_sublayer(
'Maxpool',
paddle.nn.MaxPool2D(
kernel_size=pool_size, #池化核大小
stride=pool_stride #池化步长
)
)

def forward(self, inputs):
x = inputs
for prefix, sub_layer in self.named_children():
# print(prefix,sub_layer)
x = sub_layer(x)
return x



# VGG网络
class VGGNet(paddle.nn.Layer):
def __init__(self):
super(VGGNet, self).__init__()
# 5个卷积池化操作
self.convpool01 = ConvPool(
3, 64, 3, 2, 2, 2) #3:通道数,64:卷积核个数,3:卷积核大小,2:池化核大小,2:池化步长,2:连续卷积个数
self.convpool02 = ConvPool(
64, 128, 3, 2, 2, 2)
self.convpool03 = ConvPool(
128, 256, 3, 2, 2, 3)
self.convpool04 = ConvPool(
256, 512, 3, 2, 2, 3)
self.convpool05 = ConvPool(
512, 512, 3, 2, 2, 3)
self.pool_5_shape = 512 * 7* 7
# 三个全连接层
self.fc01 = paddle.nn.Linear(self.pool_5_shape, 4096)
self.drop1 = paddle.nn.Dropout(p=0.5)
self.fc02 = paddle.nn.Linear(4096, 4096)
self.drop2 = paddle.nn.Dropout(p=0.5)
self.fc03 = paddle.nn.Linear(4096, train_parameters['class_dim'])

def forward(self, inputs, label=None):
# print('input_shape:', inputs.shape) #[8, 3, 224, 224]
"""前向计算"""
out = self.convpool01(inputs)
# print('convpool01_shape:', out.shape) #[8, 64, 112, 112]
out = self.convpool02(out)
# print('convpool02_shape:', out.shape) #[8, 128, 56, 56]
out = self.convpool03(out)
# print('convpool03_shape:', out.shape) #[8, 256, 28, 28]
out = self.convpool04(out)
# print('convpool04_shape:', out.shape) #[8, 512, 14, 14]
out = self.convpool05(out)
# print('convpool05_shape:', out.shape) #[8, 512, 7, 7]

out = paddle.reshape(out, shape=[-1, 512*7*7])
out = self.fc01(out)
out = self.drop1(out)
out = self.fc02(out)
out = self.drop2(out)
out = self.fc03(out)

if label is not None:
acc = paddle.metric.accuracy(input=out, label=label)
return out, acc
else:
return out



# 折线图,用于观察训练过程中loss和acc的走势
def draw_process(title,color,iters,data,label):
plt.title(title, fontsize=24)
plt.xlabel("iter", fontsize=20)
plt.ylabel(label, fontsize=20)
plt.plot(iters, data,color=color,label=label)
plt.legend()
plt.grid()
plt.show()



# 参数配置,要保留之前数据集准备阶段配置的参数,所以使用update更新字典
train_parameters.update({
"input_size": [3, 224, 224], #输入图片的shape
"num_epochs": 10, #训练轮数
"skip_steps": 10, #训练时输出日志的间隔
"save_steps": 100, #训练时保存模型参数的间隔
"learning_strategy": { #优化函数相关的配置
"lr": 0.0001 #超参数学习率
},
"checkpoints": "./testworkfour/checkpoints" #保存的路径
})




model = VGGNet()
model.train()
# 配置loss函数
cross_entropy = paddle.nn.CrossEntropyLoss()
# 配置参数优化器
optimizer = paddle.optimizer.Adam(learning_rate=train_parameters['learning_strategy']['lr'],
parameters=model.parameters())

steps = 0
Iters, total_loss, total_acc = [], [], []

for epo in range(train_parameters['num_epochs']):
print('开始第{}次训练'.format(epo))
for _, data in enumerate(train_loader()):
steps += 1
x_data = data[0]
y_data = data[1]
predicts, acc = model(x_data, y_data)
loss = cross_entropy(predicts, y_data)
loss.backward()
optimizer.step()
optimizer.clear_grad()
if steps % train_parameters["skip_steps"] == 0:
Iters.append(steps)
total_loss.append(loss.numpy()[0])
total_acc.append(acc.numpy()[0])
#打印中间过程
print('epo: {}, step: {}, loss is: {}, acc is: {}'\
.format(epo, steps, loss.numpy(), acc.numpy()))
#保存模型参数
if steps % train_parameters["save_steps"] == 0:
save_path = train_parameters["checkpoints"]+"/"+"save_dir_" + str(steps) + '.pdparams'
print('save model to: ' + save_path)
paddle.save(model.state_dict(),save_path)
paddle.save(model.state_dict(),train_parameters["checkpoints"]+"/"+"save_dir_final.pdparams")
draw_process("trainning loss","red",Iters,total_loss,"trainning loss")
draw_process("trainning acc","green",Iters,total_acc,"trainning acc")

模型验证的代码

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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
# 引入需要的模块
import os
import zipfile
import random
import json
import paddle
import sys
import numpy as np
from PIL import Image
import matplotlib.pyplot as plt
from paddle.io import Dataset

train_parameters = {
"src_path":"./testworkfour/Chinese Medicine.zip", #原始数据集路径
"target_path":"./testworkfour/data/", #要解压的路径
"train_list_path": "./testworkfour/data/train.txt", #train.txt路径
"eval_list_path": "./testworkfour/data/eval.txt", #eval.txt路径
"label_dict":{}, #标签字典
"readme_path": "./testworkfour/data/readme.json", #readme.json路径
"class_dim": -1, #分类数
}

src_path=train_parameters['src_path']
target_path=train_parameters['target_path']
train_list_path=train_parameters['train_list_path']
eval_list_path=train_parameters['eval_list_path']


def get_data_list(target_path,train_list_path,eval_list_path):
'''
生成数据列表
'''
#存放所有类别的信息
class_detail = []
#获取所有类别保存的文件夹名称
data_list_path=target_path+"Chinese Medicine/"
class_dirs = os.listdir(data_list_path)
#总的图像数量
all_class_images = 0
#存放类别标签
class_label=0
#存放类别数目
class_dim = 0
#存储要写进eval.txt和train.txt中的内容
trainer_list=[]
eval_list=[]
#读取每个类别,['baihe', 'gouqi','jinyinhua','huaihua','dangshen']
for class_dir in class_dirs:
if class_dir != ".DS_Store":
class_dim += 1
#每个类别的信息
class_detail_list = {}
eval_sum = 0
trainer_sum = 0
#统计每个类别有多少张图片
class_sum = 0
#获取类别路径
path = data_list_path + class_dir
# 获取所有图片
img_paths = os.listdir(path)
for img_path in img_paths: # 遍历文件夹下的每个图片
name_path = path + '/' + img_path # 每张图片的路径
if class_sum % 8 == 0: # 每8张图片取一个做验证数据
eval_sum += 1 # test_sum为测试数据的数目
eval_list.append(name_path + "\t%d" % class_label + "\n")
else:
trainer_sum += 1
trainer_list.append(name_path + "\t%d" % class_label + "\n")#trainer_sum测试数据的数目
class_sum += 1 #每类图片的数目
all_class_images += 1 #所有类图片的数目

# 说明的json文件的class_detail数据
class_detail_list['class_name'] = class_dir #类别名称
class_detail_list['class_label'] = class_label #类别标签
class_detail_list['class_eval_images'] = eval_sum #该类数据的测试集数目
class_detail_list['class_trainer_images'] = trainer_sum #该类数据的训练集数目
class_detail.append(class_detail_list)
#初始化标签列表
train_parameters['label_dict'][str(class_label)] = class_dir
class_label += 1

#初始化分类数
train_parameters['class_dim'] = class_dim

#乱序
random.shuffle(eval_list)
with open(eval_list_path, 'a') as f:
for eval_image in eval_list:
f.write(eval_image)

random.shuffle(trainer_list)
with open(train_list_path, 'a') as f2:
for train_image in trainer_list:
f2.write(train_image)

# 说明的json文件信息
readjson = {}
readjson['all_class_name'] = data_list_path #文件父目录
readjson['all_class_images'] = all_class_images
readjson['class_detail'] = class_detail
jsons = json.dumps(readjson, sort_keys=True, indent=4, separators=(',', ': '))
with open(train_parameters['readme_path'],'w') as f:
f.write(jsons)
print ('生成数据列表完成!')


# 划分训练集与验证集,乱序,生成数据列表
#每次生成数据列表前,首先清空train.txt和eval.txt
with open(train_list_path, 'w') as f:
f.seek(0)
f.truncate()
with open(eval_list_path, 'w') as f:
f.seek(0)
f.truncate()
#生成数据列表
get_data_list(target_path,train_list_path,eval_list_path)


def load_image(img_path):
'''
预测图片预处理
'''
img = Image.open(img_path)
if img.mode != 'RGB':
img = img.convert('RGB')
img = img.resize((224, 224), Image.BILINEAR)
img = np.array(img).astype('float32')
img = img.transpose((2, 0, 1)) / 255 # HWC to CHW 及归一化
return img


label_dic = train_parameters['label_dict']









# 定义卷积池化网络
class ConvPool(paddle.nn.Layer):
'''卷积+池化'''
def __init__(self,
num_channels,
num_filters,
filter_size,
pool_size,
pool_stride,
groups,
conv_stride=1,
conv_padding=1,
):
super(ConvPool, self).__init__()

# groups代表卷积层的数量
for i in range(groups):
self.add_sublayer( #添加子层实例
'bb_%d' % i,
paddle.nn.Conv2D( # layer
in_channels=num_channels, #通道数
out_channels=num_filters, #卷积核个数
kernel_size=filter_size, #卷积核大小
stride=conv_stride, #步长
padding = conv_padding, #padding
)
)
self.add_sublayer(
'relu%d' % i,
paddle.nn.ReLU()
)
num_channels = num_filters


self.add_sublayer(
'Maxpool',
paddle.nn.MaxPool2D(
kernel_size=pool_size, #池化核大小
stride=pool_stride #池化步长
)
)

def forward(self, inputs):
x = inputs
for prefix, sub_layer in self.named_children():
# print(prefix,sub_layer)
x = sub_layer(x)
return x






# VGG网络
class VGGNet(paddle.nn.Layer):
def __init__(self):
super(VGGNet, self).__init__()
# 5个卷积池化操作
self.convpool01 = ConvPool(
3, 64, 3, 2, 2, 2) #3:通道数,64:卷积核个数,3:卷积核大小,2:池化核大小,2:池化步长,2:连续卷积个数
self.convpool02 = ConvPool(
64, 128, 3, 2, 2, 2)
self.convpool03 = ConvPool(
128, 256, 3, 2, 2, 3)
self.convpool04 = ConvPool(
256, 512, 3, 2, 2, 3)
self.convpool05 = ConvPool(
512, 512, 3, 2, 2, 3)
self.pool_5_shape = 512 * 7* 7
# 三个全连接层
self.fc01 = paddle.nn.Linear(self.pool_5_shape, 4096)
self.drop1 = paddle.nn.Dropout(p=0.5)
self.fc02 = paddle.nn.Linear(4096, 4096)
self.drop2 = paddle.nn.Dropout(p=0.5)
self.fc03 = paddle.nn.Linear(4096, train_parameters['class_dim'])

def forward(self, inputs, label=None):
# print('input_shape:', inputs.shape) #[8, 3, 224, 224]
"""前向计算"""
out = self.convpool01(inputs)
# print('convpool01_shape:', out.shape) #[8, 64, 112, 112]
out = self.convpool02(out)
# print('convpool02_shape:', out.shape) #[8, 128, 56, 56]
out = self.convpool03(out)
# print('convpool03_shape:', out.shape) #[8, 256, 28, 28]
out = self.convpool04(out)
# print('convpool04_shape:', out.shape) #[8, 512, 14, 14]
out = self.convpool05(out)
# print('convpool05_shape:', out.shape) #[8, 512, 7, 7]

out = paddle.reshape(out, shape=[-1, 512*7*7])
out = self.fc01(out)
out = self.drop1(out)
out = self.fc02(out)
out = self.drop2(out)
out = self.fc03(out)

if label is not None:
acc = paddle.metric.accuracy(input=out, label=label)
return out, acc
else:
return out


# 定义数据读取器
class dataset(Dataset):
def __init__(self, data_path, mode='train'):
"""
数据读取器
:param data_path: 数据集所在路径
:param mode: train or eval
"""
super().__init__()
self.data_path = data_path
self.img_paths = []
self.labels = []

if mode == 'train':
with open(os.path.join(self.data_path, "train.txt"), "r", encoding="utf-8") as f:
self.info = f.readlines()
for img_info in self.info:
img_path, label = img_info.strip().split('\t')
self.img_paths.append(img_path)
self.labels.append(int(label))

else:
with open(os.path.join(self.data_path, "eval.txt"), "r", encoding="utf-8") as f:
self.info = f.readlines()
for img_info in self.info:
img_path, label = img_info.strip().split('\t')
self.img_paths.append(img_path)
self.labels.append(int(label))


def __getitem__(self, index):
"""
获取一组数据
:param index: 文件索引号
:return:
"""
# 第一步打开图像文件并获取label值
img_path = self.img_paths[index]
img = Image.open(img_path)
if img.mode != 'RGB':
img = img.convert('RGB')
img = img.resize((224, 224), Image.BILINEAR)
#img = rand_flip_image(img)
img = np.array(img).astype('float32')
img = img.transpose((2, 0, 1)) / 255
label = self.labels[index]
label = np.array([label], dtype="int64")
return img, label

def print_sample(self, index: int = 0):
print("文件名", self.img_paths[index], "\t标签值", self.labels[index])

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



#评估数据加载
eval_dataset = dataset('./testworkfour/data',mode='eval')
eval_loader = paddle.io.DataLoader(eval_dataset, batch_size = 8, shuffle=False)



# 模型评估
# 加载训练过程保存的最后一个模型
model__state_dict = paddle.load('./testworkfour/checkpoints/save_dir_final.pdparams')
model_eval = VGGNet()
model_eval.set_state_dict(model__state_dict)
model_eval.eval()
accs = []
# 开始评估
for _, data in enumerate(eval_loader()):
x_data = data[0]
y_data = data[1]
predicts = model_eval(x_data)
acc = paddle.metric.accuracy(predicts, y_data)
accs.append(acc.numpy()[0])
print('模型在验证集上的准确率为:',np.mean(accs))

模型使用的代码

批量的预测

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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
# 引入需要的模块
import os
import zipfile
import random
import json
import paddle
import sys
import numpy as np
from PIL import Image
import matplotlib.pyplot as plt
from paddle.io import Dataset

train_parameters = {
"src_path":"./testworkfour/Chinese Medicine.zip", #原始数据集路径
"target_path":"./testworkfour/data/", #要解压的路径
"train_list_path": "./testworkfour/data/train.txt", #train.txt路径
"eval_list_path": "./testworkfour/data/eval.txt", #eval.txt路径
"label_dict":{}, #标签字典
"readme_path": "./testworkfour/data/readme.json", #readme.json路径
"class_dim": -1, #分类数
}

src_path=train_parameters['src_path']
target_path=train_parameters['target_path']
train_list_path=train_parameters['train_list_path']
eval_list_path=train_parameters['eval_list_path']


def get_data_list(target_path,train_list_path,eval_list_path):
'''
生成数据列表
'''
#存放所有类别的信息
class_detail = []
#获取所有类别保存的文件夹名称
data_list_path=target_path+"Chinese Medicine/"
class_dirs = os.listdir(data_list_path)
#总的图像数量
all_class_images = 0
#存放类别标签
class_label=0
#存放类别数目
class_dim = 0
#存储要写进eval.txt和train.txt中的内容
trainer_list=[]
eval_list=[]
#读取每个类别,['baihe', 'gouqi','jinyinhua','huaihua','dangshen']
for class_dir in class_dirs:
if class_dir != ".DS_Store":
class_dim += 1
#每个类别的信息
class_detail_list = {}
eval_sum = 0
trainer_sum = 0
#统计每个类别有多少张图片
class_sum = 0
#获取类别路径
path = data_list_path + class_dir
# 获取所有图片
img_paths = os.listdir(path)
for img_path in img_paths: # 遍历文件夹下的每个图片
name_path = path + '/' + img_path # 每张图片的路径
if class_sum % 8 == 0: # 每8张图片取一个做验证数据
eval_sum += 1 # test_sum为测试数据的数目
eval_list.append(name_path + "\t%d" % class_label + "\n")
else:
trainer_sum += 1
trainer_list.append(name_path + "\t%d" % class_label + "\n")#trainer_sum测试数据的数目
class_sum += 1 #每类图片的数目
all_class_images += 1 #所有类图片的数目

# 说明的json文件的class_detail数据
class_detail_list['class_name'] = class_dir #类别名称
class_detail_list['class_label'] = class_label #类别标签
class_detail_list['class_eval_images'] = eval_sum #该类数据的测试集数目
class_detail_list['class_trainer_images'] = trainer_sum #该类数据的训练集数目
class_detail.append(class_detail_list)
#初始化标签列表
train_parameters['label_dict'][str(class_label)] = class_dir
class_label += 1

#初始化分类数
train_parameters['class_dim'] = class_dim

#乱序
random.shuffle(eval_list)
with open(eval_list_path, 'a') as f:
for eval_image in eval_list:
f.write(eval_image)

random.shuffle(trainer_list)
with open(train_list_path, 'a') as f2:
for train_image in trainer_list:
f2.write(train_image)

# 说明的json文件信息
readjson = {}
readjson['all_class_name'] = data_list_path #文件父目录
readjson['all_class_images'] = all_class_images
readjson['class_detail'] = class_detail
jsons = json.dumps(readjson, sort_keys=True, indent=4, separators=(',', ': '))
with open(train_parameters['readme_path'],'w') as f:
f.write(jsons)
print ('生成数据列表完成!')


# 划分训练集与验证集,乱序,生成数据列表
#每次生成数据列表前,首先清空train.txt和eval.txt
with open(train_list_path, 'w') as f:
f.seek(0)
f.truncate()
with open(eval_list_path, 'w') as f:
f.seek(0)
f.truncate()
#生成数据列表
get_data_list(target_path,train_list_path,eval_list_path)


def load_image(img_path):
'''
预测图片预处理
'''
img = Image.open(img_path)
if img.mode != 'RGB':
img = img.convert('RGB')
img = img.resize((224, 224), Image.BILINEAR)
img = np.array(img).astype('float32')
img = img.transpose((2, 0, 1)) / 255 # HWC to CHW 及归一化
return img


label_dic = train_parameters['label_dict']
print(label_dic)







# 定义卷积池化网络
class ConvPool(paddle.nn.Layer):
'''卷积+池化'''
def __init__(self,
num_channels,
num_filters,
filter_size,
pool_size,
pool_stride,
groups,
conv_stride=1,
conv_padding=1,
):
super(ConvPool, self).__init__()

# groups代表卷积层的数量
for i in range(groups):
self.add_sublayer( #添加子层实例
'bb_%d' % i,
paddle.nn.Conv2D( # layer
in_channels=num_channels, #通道数
out_channels=num_filters, #卷积核个数
kernel_size=filter_size, #卷积核大小
stride=conv_stride, #步长
padding = conv_padding, #padding
)
)
self.add_sublayer(
'relu%d' % i,
paddle.nn.ReLU()
)
num_channels = num_filters


self.add_sublayer(
'Maxpool',
paddle.nn.MaxPool2D(
kernel_size=pool_size, #池化核大小
stride=pool_stride #池化步长
)
)

def forward(self, inputs):
x = inputs
for prefix, sub_layer in self.named_children():
# print(prefix,sub_layer)
x = sub_layer(x)
return x






# VGG网络
class VGGNet(paddle.nn.Layer):
def __init__(self):
super(VGGNet, self).__init__()
# 5个卷积池化操作
self.convpool01 = ConvPool(
3, 64, 3, 2, 2, 2) #3:通道数,64:卷积核个数,3:卷积核大小,2:池化核大小,2:池化步长,2:连续卷积个数
self.convpool02 = ConvPool(
64, 128, 3, 2, 2, 2)
self.convpool03 = ConvPool(
128, 256, 3, 2, 2, 3)
self.convpool04 = ConvPool(
256, 512, 3, 2, 2, 3)
self.convpool05 = ConvPool(
512, 512, 3, 2, 2, 3)
self.pool_5_shape = 512 * 7* 7
# 三个全连接层
self.fc01 = paddle.nn.Linear(self.pool_5_shape, 4096)
self.drop1 = paddle.nn.Dropout(p=0.5)
self.fc02 = paddle.nn.Linear(4096, 4096)
self.drop2 = paddle.nn.Dropout(p=0.5)
self.fc03 = paddle.nn.Linear(4096, train_parameters['class_dim'])

def forward(self, inputs, label=None):
# print('input_shape:', inputs.shape) #[8, 3, 224, 224]
"""前向计算"""
out = self.convpool01(inputs)
# print('convpool01_shape:', out.shape) #[8, 64, 112, 112]
out = self.convpool02(out)
# print('convpool02_shape:', out.shape) #[8, 128, 56, 56]
out = self.convpool03(out)
# print('convpool03_shape:', out.shape) #[8, 256, 28, 28]
out = self.convpool04(out)
# print('convpool04_shape:', out.shape) #[8, 512, 14, 14]
out = self.convpool05(out)
# print('convpool05_shape:', out.shape) #[8, 512, 7, 7]

out = paddle.reshape(out, shape=[-1, 512*7*7])
out = self.fc01(out)
out = self.drop1(out)
out = self.fc02(out)
out = self.drop2(out)
out = self.fc03(out)

if label is not None:
acc = paddle.metric.accuracy(input=out, label=label)
return out, acc
else:
return out








import time
# 加载训练过程保存的最后一个模型
model__state_dict = paddle.load('./testworkfour/checkpoints/save_dir_final.pdparams')
model_predict = VGGNet()
model_predict.set_state_dict(model__state_dict)
model_predict.eval()
#infer_imgs_path = os.listdir("infer")
infer_imgs_path = os.listdir("./testworkfour/data/Chinese Medicine/dangshen")


# print(infer_imgs_path)

# 预测所有图片
for infer_img_path in infer_imgs_path:
infer_img = load_image("./testworkfour/data/Chinese Medicine/dangshen/"+infer_img_path)
infer_img = infer_img[np.newaxis,:, : ,:] #reshape(-1,3,224,224)
infer_img = paddle.to_tensor(infer_img)
result = model_predict(infer_img)
lab = np.argmax(result.numpy())
print("样本: {},被预测为:{}".format(infer_img_path,label_dic[str(lab)]))
# img = Image.open("./testworkfour/data/Chinese Medicine/baihe/"+infer_img_path)
# plt.imshow(img)
# plt.axis('off')
# plt.show()
# sys.stdout.flush()
# time.sleep(0.5)

单个图片的预测

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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153

# 引入需要的模块
import os
import zipfile
import random
import json
import paddle
import sys
import numpy as np
from PIL import Image
import matplotlib.pyplot as plt
from paddle.io import Dataset

#所有的标签,以及数字对应的标签
label_dic = {'0': 'baihe', '1': 'dangshen', '2': 'gouqi', '3': 'huaihua', '4': 'jinyinhua'}
#所有的标签数量
class_dim = 0
for key in label_dic:
class_dim =class_dim+1
print(class_dim)



# 定义卷积池化网络
class ConvPool(paddle.nn.Layer):
'''卷积+池化'''
def __init__(self,
num_channels,
num_filters,
filter_size,
pool_size,
pool_stride,
groups,
conv_stride=1,
conv_padding=1,
):
super(ConvPool, self).__init__()

# groups代表卷积层的数量
for i in range(groups):
self.add_sublayer( #添加子层实例
'bb_%d' % i,
paddle.nn.Conv2D( # layer
in_channels=num_channels, #通道数
out_channels=num_filters, #卷积核个数
kernel_size=filter_size, #卷积核大小
stride=conv_stride, #步长
padding = conv_padding, #padding
)
)
self.add_sublayer(
'relu%d' % i,
paddle.nn.ReLU()
)
num_channels = num_filters


self.add_sublayer(
'Maxpool',
paddle.nn.MaxPool2D(
kernel_size=pool_size, #池化核大小
stride=pool_stride #池化步长
)
)

def forward(self, inputs):
x = inputs
for prefix, sub_layer in self.named_children():
# print(prefix,sub_layer)
x = sub_layer(x)
return x

# VGG网络
class VGGNet(paddle.nn.Layer):
def __init__(self):
super(VGGNet, self).__init__()
# 5个卷积池化操作
self.convpool01 = ConvPool(
3, 64, 3, 2, 2, 2) #3:通道数,64:卷积核个数,3:卷积核大小,2:池化核大小,2:池化步长,2:连续卷积个数
self.convpool02 = ConvPool(
64, 128, 3, 2, 2, 2)
self.convpool03 = ConvPool(
128, 256, 3, 2, 2, 3)
self.convpool04 = ConvPool(
256, 512, 3, 2, 2, 3)
self.convpool05 = ConvPool(
512, 512, 3, 2, 2, 3)
self.pool_5_shape = 512 * 7* 7
# 三个全连接层
self.fc01 = paddle.nn.Linear(self.pool_5_shape, 4096)
self.drop1 = paddle.nn.Dropout(p=0.5)
self.fc02 = paddle.nn.Linear(4096, 4096)
self.drop2 = paddle.nn.Dropout(p=0.5)
self.fc03 = paddle.nn.Linear(4096, class_dim)

def forward(self, inputs, label=None):
# print('input_shape:', inputs.shape) #[8, 3, 224, 224]
"""前向计算"""
out = self.convpool01(inputs)
# print('convpool01_shape:', out.shape) #[8, 64, 112, 112]
out = self.convpool02(out)
# print('convpool02_shape:', out.shape) #[8, 128, 56, 56]
out = self.convpool03(out)
# print('convpool03_shape:', out.shape) #[8, 256, 28, 28]
out = self.convpool04(out)
# print('convpool04_shape:', out.shape) #[8, 512, 14, 14]
out = self.convpool05(out)
# print('convpool05_shape:', out.shape) #[8, 512, 7, 7]

out = paddle.reshape(out, shape=[-1, 512*7*7])
out = self.fc01(out)
out = self.drop1(out)
out = self.fc02(out)
out = self.drop2(out)
out = self.fc03(out)

if label is not None:
acc = paddle.metric.accuracy(input=out, label=label)
return out, acc
else:
return out





def load_image(img_path):
'''
预测图片预处理
'''
img = Image.open(img_path)
if img.mode != 'RGB':
img = img.convert('RGB')
img = img.resize((224, 224), Image.BILINEAR)
img = np.array(img).astype('float32')
print('numpy: ', img.shape)
img = img.transpose((2, 0, 1)) / 255 # HWC to CHW 及归一化
return img

# 加载训练过程保存的最后一个模型
model__state_dict = paddle.load('./testworkfour/checkpoints/save_dir_final.pdparams')
model_predict = VGGNet()
model_predict.set_state_dict(model__state_dict)
model_predict.eval()


infer_img_path = "dangshen_6.jpg"
infer_img = load_image("./testworkfour/data/Chinese Medicine/dangshen/"+infer_img_path)
infer_img = infer_img[np.newaxis,:, : ,:] #reshape(-1,3,224,224)
infer_img = paddle.to_tensor(infer_img)
result = model_predict(infer_img)
lab = np.argmax(result.numpy())
print("样本: {},被预测为:{}".format(infer_img_path,label_dic[str(lab)]))

发布成服务

发布成服务之后使用图片的base64 编码进行传输,返回预测结果

flask 安装

1
pip install flask -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com

启动模型

1
python model_test_zcy.py

model_test_zcy.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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
import io
from flask import Flask, jsonify, request, abort
import json
import base64
import numpy as np

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

# 引入需要的模块
import os
import zipfile
import random
import json
import paddle
import sys
import numpy as np
from PIL import Image
import matplotlib.pyplot as plt
from paddle.io import Dataset

app = Flask(__name__)

#所有的标签,以及数字对应的标签
label_dic = {'0': 'baihe', '1': 'dangshen', '2': 'gouqi', '3': 'huaihua', '4': 'jinyinhua'}
#所有的标签数量
class_dim = 0
for key in label_dic:
class_dim =class_dim+1
print(class_dim)



@app.route('/zcy', 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'])

# decode_base64_matplot_img(j_data['base64'])
# return ""
return getAnalysis(j_data['base64'])


def getAnalysis(imgbase64):



# 加载训练过程保存的最后一个模型
model__state_dict = paddle.load('./testworkfour/checkpoints/save_dir_final.pdparams')
model_predict = VGGNet()
model_predict.set_state_dict(model__state_dict)
model_predict.eval()

infer_img = load_image2(imgbase64)
infer_img = infer_img[np.newaxis,:, : ,:] #reshape(-1,3,224,224)
infer_img = paddle.to_tensor(infer_img)
result = model_predict(infer_img)
print(result.numpy())
lab = np.argmax(result.numpy())
print("样本: {},被预测为:{}".format("1",label_dic[str(lab)]))
return "样本被预测为:{}".format(label_dic[str(lab)])

# def getbase64(imgbase64):


# # 传入为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




# 定义卷积池化网络
class ConvPool(paddle.nn.Layer):
'''卷积+池化'''
def __init__(self,
num_channels,
num_filters,
filter_size,
pool_size,
pool_stride,
groups,
conv_stride=1,
conv_padding=1,
):
super(ConvPool, self).__init__()

# groups代表卷积层的数量
for i in range(groups):
self.add_sublayer( #添加子层实例
'bb_%d' % i,
paddle.nn.Conv2D( # layer
in_channels=num_channels, #通道数
out_channels=num_filters, #卷积核个数
kernel_size=filter_size, #卷积核大小
stride=conv_stride, #步长
padding = conv_padding, #padding
)
)
self.add_sublayer(
'relu%d' % i,
paddle.nn.ReLU()
)
num_channels = num_filters


self.add_sublayer(
'Maxpool',
paddle.nn.MaxPool2D(
kernel_size=pool_size, #池化核大小
stride=pool_stride #池化步长
)
)

def forward(self, inputs):
x = inputs
for prefix, sub_layer in self.named_children():
# print(prefix,sub_layer)
x = sub_layer(x)
return x

# VGG网络
class VGGNet(paddle.nn.Layer):
def __init__(self):
super(VGGNet, self).__init__()
# 5个卷积池化操作
self.convpool01 = ConvPool(
3, 64, 3, 2, 2, 2) #3:通道数,64:卷积核个数,3:卷积核大小,2:池化核大小,2:池化步长,2:连续卷积个数
self.convpool02 = ConvPool(
64, 128, 3, 2, 2, 2)
self.convpool03 = ConvPool(
128, 256, 3, 2, 2, 3)
self.convpool04 = ConvPool(
256, 512, 3, 2, 2, 3)
self.convpool05 = ConvPool(
512, 512, 3, 2, 2, 3)
self.pool_5_shape = 512 * 7* 7
# 三个全连接层
self.fc01 = paddle.nn.Linear(self.pool_5_shape, 4096)
self.drop1 = paddle.nn.Dropout(p=0.5)
self.fc02 = paddle.nn.Linear(4096, 4096)
self.drop2 = paddle.nn.Dropout(p=0.5)
self.fc03 = paddle.nn.Linear(4096, class_dim)

def forward(self, inputs, label=None):
# print('input_shape:', inputs.shape) #[8, 3, 224, 224]
"""前向计算"""
out = self.convpool01(inputs)
# print('convpool01_shape:', out.shape) #[8, 64, 112, 112]
out = self.convpool02(out)
# print('convpool02_shape:', out.shape) #[8, 128, 56, 56]
out = self.convpool03(out)
# print('convpool03_shape:', out.shape) #[8, 256, 28, 28]
out = self.convpool04(out)
# print('convpool04_shape:', out.shape) #[8, 512, 14, 14]
out = self.convpool05(out)
# print('convpool05_shape:', out.shape) #[8, 512, 7, 7]

out = paddle.reshape(out, shape=[-1, 512*7*7])
out = self.fc01(out)
out = self.drop1(out)
out = self.fc02(out)
out = self.drop2(out)
out = self.fc03(out)

if label is not None:
acc = paddle.metric.accuracy(input=out, label=label)
return out, acc
else:
return out





def load_image(img_path):
'''
预测图片预处理
'''
img = Image.open(img_path)
if img.mode != 'RGB':
img = img.convert('RGB')
img = img.resize((224, 224), Image.BILINEAR)
img = np.array(img).astype('float32')
img = img.transpose((2, 0, 1)) / 255 # HWC to CHW 及归一化
return img

def load_image2(img_base64):


'''
预测图片预处理
'''
# byte_data = base64.b64decode(img_base64)#将base64转换为二进制
# img = np.fromstring(byte_data, np.uint8) # 转换np序列



# img = np.asarray(bytearray(byte_data), dtype="uint8")# 二进制转换为一维数组
# img = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))

# plt.imshow(img)
# plt.axis('off')
# plt.show()
# sys.stdout.flush()

img = base64.b64decode(img_base64)
buffer = io.BytesIO()
img = Image.open(io.BytesIO(img))
# img = Image.open(img_base64)
if img.mode != 'RGB':
img = img.convert('RGB')
img = img.resize((224, 224), Image.BILINEAR)
img = np.array(img).astype('float32')
print('numpy: ', img.shape)
img = img.transpose((2, 0, 1)) / 255 # HWC to CHW 及归一化
return img

# 解码base64字符串为matplot图像
def decode_base64_matplot_img(base64_data):
img = base64.b64decode(base64_data)
img_array = np.fromstring(img, np.uint8) # 转换np序列
img_raw = cv2.imdecode(img_array, cv2.IMREAD_COLOR) # 转换Opencv格式BGR
img_matplot = cv2.cvtColor(img_raw, cv2.COLOR_BGR2RGB) # BGR转RGB

img_gray = cv2.imdecode(img_array, cv2.IMREAD_GRAYSCALE) # 转换灰度图
imggray_matplot = cv2.cvtColor(img_gray, cv2.COLOR_GRAY2RGB) # 灰度图转RGB
plt.figure()
plt.title("Matplot RGB Origin Image")
plt.axis("off")
plt.imshow(img_matplot)

plt.figure()
plt.title("Matplot Gray Origin Image")
plt.axis("off")
plt.imshow(imggray_matplot)
plt.show()

if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, debug = False)

#json模块编码: json.dumps()
#json模块解码:解码python json格式,用json.loads()

label_dic是模型的所有标签,将数据处理的那个地方直接拿取出来的,可直接使用
class_dim 是所有的标签数量

若没有报错则可正常启动

1
2
3
4
5
6
7
8
(base) [root@localhost paddle]# python model_test_zct.py 
* Serving Flask app 'model_test_zcy'
* Debug mode: off
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
* Running on all addresses (0.0.0.0)
* Running on http://127.0.0.1:5000
* Running on http://192.168.23.134:5000
Press CTRL+C to quit

则可以使用代码外部调用

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

Python Centos系统下模型训练yolov5环境搭建

发表于 2023-05-11
字数统计: 893 字 | 阅读时长 ≈ 4 min

模型训练yolov5环境搭建

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

yolov5下载

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

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

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

然后运行

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

就会自动把这些依赖安装好了。

flask 安装

1
pip install flask -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com

启动模型

1
python model_test_aqm.py

若没有报错则可正常启动

1
2
3
4
5
6
7
8
(base) [root@localhost yolov5-master]# python model_test_aqm.py 
* Serving Flask app 'model_test_aqm'
* Debug mode: off
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
* Running on all addresses (0.0.0.0)
* Running on http://127.0.0.1:5000
* Running on http://192.168.23.134:5000
Press CTRL+C to quit

问题处理

1.出现这个错误 ModuleNotFoundError: No module named ‘cv2’

报错

1
2
3
4
 Traceback (most recent call last):
File "/data/python/yolov5/yolov5-master/model_test_aqm.py", line 9, in <module>
import cv2
ModuleNotFoundError: No module named 'cv2'

解决方法
安装这个两个库即可

1
pip install opencv-python-headless -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com
1
pip install opencv-contrib-python -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com

2.出现这个错误 libGL.so.1: cannot open shared object file: No such file or directory

报错

1
2
3
File "/usr/local/lib/python3.6/dist-packages/cv2/__init__.py", line 8, in <module>
from .cv2 import *
ImportError: libGL.so.1: cannot open shared object file: No such file or directory

解决安装 ffmpeg libsm6 libxext6

安装libsm6 libxext6如下命令直接安装则可

1
2
3
4
5
6
7
8
9
yum install libSM-1.2.2-2.el7.x86_64 --setopt=protected_multilib=false

yum install libXrender-0.9.10-1.el7.x86_64 --setopt=protected_multilib=false

yum install libXext-1.3.3-3.el7.x86_64 --setopt=protected_multilib=false
```
安装ffmpeg

前提准备:使用yum安装编译工具 gcc cc cl

yum -y install gcc cc cl

1
2
3
1.安装ffmpeg时需要提前安装yasm插件

1)下载

wget http://www.tortall.net/projects/yasm/releases/yasm-1.3.0.tar.gz

1
2)解压

tar -xvf yasm-1.3.0.tar.gz

1
3)进入解压后的文件夹路径下,执行安装

cd yasm-1.3.0/

1
2
```
./configure && make && make install

2.安装FFmpeg

1)下载

1
wget http://www.ffmpeg.org/releases/ffmpeg-4.3.2.tar.gz

2)解压

1
tar -xvf ffmpeg-4.3.2.tar.gz

3)进入解压后的文件夹路径下,执行安装

1
cd ffmpeg-4.3.2/
1
./configure && make && make install

耗时相对长些…耐心等待….

3.查看安装结果

1
ffmpeg -version

出现如下类似结果,则安装成功

1
2
3
4
5
6
7
8
9
10
11
(yolo) [root@localhost ffmpeg-4.3.2]# ffmpeg -version
ffmpeg version 4.3.2 Copyright (c) 2000-2021 the FFmpeg developers
built with gcc 4.8.5 (GCC) 20150623 (Red Hat 4.8.5-44)
configuration:
libavutil 56. 51.100 / 56. 51.100
libavcodec 58. 91.100 / 58. 91.100
libavformat 58. 45.100 / 58. 45.100
libavdevice 58. 10.100 / 58. 10.100
libavfilter 7. 85.100 / 7. 85.100
libswscale 5. 7.100 / 5. 7.100
libswresample 3. 7.100 / 3. 7.100

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

Linux centos安装Anaconda

发表于 2023-05-09
字数统计: 1,471 字 | 阅读时长 ≈ 7 min

安装Anaconda

下载anaconda的安装包

这里需要在官网上查找自己需要的版本,地址链接在下面:

https://repo.anaconda.com/archive/

以linux最新安装的版本为例:
Anaconda3-2023.03-1-Linux-x86_64.sh
选择需要的版本,鼠标右键复制链接信息,复制出来就是链接地址
https://repo.anaconda.com/archive/Anaconda3-2023.03-1-Linux-x86_64.sh

选择的版本,然后在linux控制台输入这句话:

1
wget https://repo.anaconda.com/archive/Anaconda3-2023.03-1-Linux-x86_64.sh

如果没有出现问题就是下面图示:

1
2
3
4
5
6
7
8
9
[root@localhost train]# wget https://repo.anaconda.com/archive/Anaconda3-2023.03-1-Linux-x86_64.sh
--2023-05-09 11:09:48-- https://repo.anaconda.com/archive/Anaconda3-2023.03-1-Linux-x86_64.sh
正在解析主机 repo.anaconda.com (repo.anaconda.com)... 104.16.131.3, 104.16.130.3, 2606:4700::6810:8303, ...
正在连接 repo.anaconda.com (repo.anaconda.com)|104.16.131.3|:443... 已连接。
已发出 HTTP 请求,正在等待回应... 200 OK
长度:902411137 (861M) [application/x-sh]
正在保存至: “Anaconda3-2023.03-1-Linux-x86_64.sh”

5% [=======>

若下载较慢,可以选择使用迅雷进行下载,然后复制到相关目录下

解决安装出现的bug

当输入上面的那一条命令时,有些人可能会出现下面这样的错误:

1
bash: wget: command not found

具体解决办法如下:

Debian/Ubuntu系统,需要执行以下命令:

1
apt-get install -y wget

相反,CentOS系统则需要输入下面指令:

1
yum install wget -y

安装anaconda

赋权并且进行安装

接下来需要首先赋权再执行安装程序,依次输入下面两句命令:

1
chmod +x Anaconda3-2023.03-1-Linux-x86_64.sh
1
./Anaconda3-2023.03-1-Linux-x86_64.sh

然后出现下面图所示:

1
2
3
4
5
6
7
8
[root@localhost anaconda]# ll
总用量 881264
-rw-r--r-- 1 root root 902411137 5月 9 11:31 Anaconda3-2023.03-1-Linux-x86_64.sh
[root@localhost anaconda]# chmod +x Anaconda3-2023.03-1-Linux-x86_64.sh
[root@localhost anaconda]# ll
总用量 881264
-rwxr-xr-x 1 root root 902411137 5月 9 11:31 Anaconda3-2023.03-1-Linux-x86_64.sh
[root@localhost anaconda]# ./Anaconda3-2023.03-1-Linux-x86_64.sh

点击Enter(回车键)

此时显示Anaconda的信息,并且会出现More,继续按Enter,直到如下图所示:

1
2
3
4
The following packages listed on https://www.anaconda.com/cryptography are included in the repository accessible through Anaconda Distribution that relate to cryptography.
Last updated February 25, 2022
Do you accept the license terms? [yes|no]
[no] >>>

输入 yes

1
2
3
4
5
6
7
Do you accept the license terms? [yes|no]
>>> yes
Anaconda3 will now be installed into this location:
/root/anaconda3
- Press ENTER to confirm the location
- Press CTRL-C to abort the installation
- Or specify a different location below

继续点击 Enter

1
2
3
4
5
6
7
/root/anaconda3
- Press ENTER to confirm the location
- Press CTRL-C to abort the installation
- Or specify a different location below
[/root/anaconda3] >>>
PREFIX=/root/anaconda3
Unpacking payload ...

输入 yes,添加环境变量

1
2
3
4
5
6
installation finished.
Do you wish the installer to initialize Anaconda3
by running conda init? [yes|no]
[no] >>> yes
no change /root/anaconda3/condabin/conda
no change /root/anaconda3/bin/conda

这里需要注意点的就是如果设置环境变量出错的话:
必须手动设置环境变量

1
vim ~/.bashrc

需要找到anaconda3这个文件夹设置安装Anaconda路径
/root/anaconda3/
在最后一行添加:

1
export PATH=/root/anaconda3/bin:$PATH

需要把之前的那句话给注释掉如下所示:

1
2
# export PATH=/usr/local/nvidia/bin:/usr/local/cuda/bin:/usr/local/sbin:/usr/sbin:/sbin:$PATH
export PATH=/root/anaconda3/bin:$PATH

这里只是个示例,具体的还是要看具体安装的路径。
然后保存更改,输入下面这句指令:

1
source ~/.bashrc

检测是否安装成功

查看版本

打开新的终端后,进入自己的文件夹目录下,输入anaconda -V(注意a要小写,V要大写),conda -V ,显示版本信息,若显示则表示安装成功。

1
2
root@:# conda -V
conda 4.5.11

Anaconda安装虚拟环境

创建虚拟环境

1
conda create -n yolo python=3.8 (yolo 是自己取的名字)

激活环境
使用下面这条命令,激活环境:

1
2
# To activate this environment, use
# $ conda activate yolo

使用下面这条命令,退出环境:

1
2
# To deactivate an active environment, use
# $ conda deactivate

conda配置镜像源:

使用conda进行安装时,访问的是国外的网络,所以下载和安装包时会特别慢。需要更换到国内镜像源地址,这里更换到国内的清华大学地址。(永久添加镜像)

Windows和Linux 对于conda修改镜像源的方法一样

查看anaconda中已经存在的镜像源

1
conda config --show channels

添加镜像源(永久添加)

1
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/
1
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/
1
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/

3
设置搜索时显示通道地址

1
conda config --set show_channel_urls yes

若不想按照上述步骤添加镜像,可使用以下命令直接指定安装时使用的镜像地址(以opencv为例):

1
conda install opencv -c https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/

pip使用国内镜像源
一般在使用conda install安装时会出现包无法找到或者安装失败的情况,此时可以使用pip install来尝试安装(以opencv为例):

1
pip install opencv

若安装速度过慢可单独指定安装镜像加快安装:

1
pip install opencv -i https://mirrors.aliyun.com/pypi/simple/

此处列举国内常用pip安装镜像:

清华:https://pypi.tuna.tsinghua.edu.cn/simple
阿里云:https://mirrors.aliyun.com/pypi/simple/
中国科技大学: https://pypi.mirrors.ustc.edu.cn/simple/
华中理工大学:https://pypi.hustunique.com/
山东理工大学:https://pypi.sdutlinux.org/
豆瓣:https://pypi.douban.com/simple/

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

1…789…38

继开

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

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