ExternalError: CUBLAS error(3).
[Hint: Please search for the error code(3) on website (https://docs.nvidia.com/cuda/cublas/index.html#cublasstatus_t) to get Nvidia's official solution and advice about CUBLAS Error.] (at ..\paddle\phi\backends\gpu\gpu_resources.cc:156)
[operator < mul > error]
```python
#导入要用到的模块
import paddle
paddle.enable_static()
import paddle.fluid as fluid
import numpy as np
import sys
from multiprocessing import cpu_count
import matplotlib.pyplot as plt
from PIL import Image
import os
import math
from sklearn.metrics import confusion_matrix
import pandas as pd
# 数据加载
# 数据集中原本有章子怡、姜文、彭于晏三位明星的人脸图片,在其中加入赵丽颖、白敬亭和本人照片构成新的数据集。 总计630张图片,章子怡100张,
# 姜文103张,彭于晏114张,白敬亭104张,赵丽颖105张,本人104张。按照9:1的比例进行划分,90%用于训练,10%用于测试。 自定义的数据集,
# 首先要生成图像列表,把自定的图像分为测试集和训练集,并带有标签。下面的程序可以单独运行,只要把一个大类的文件夹路径传进去就可以了,
# 该程序会把里面的每个小类别都迭代,生成固定格式的列表.比如我们把人脸类别的根目录传进去../images/face。
# 最后会在指定目录下面生成三个文件,readme.json、trainer.list和test.list.
import os
import json
# 设置要生成文件的路径
data_root_path = 'X:/pyproject/images/face'
# 所有类别的信息
class_detail = []
# 获取所有类别保存的文件夹名称
class_dirs = os.listdir(data_root_path)
# 类别标签
class_label = 0
# 获取总类别的名称
father_paths = data_root_path.split('/') #['', 'home', 'aistudio', 'images', 'face']
while True:
if father_paths[father_paths.__len__() - 1] == '':
del father_paths[father_paths.__len__() - 1]
else:
break
father_path = father_paths[father_paths.__len__() - 1]
# 把生产的数据列表都放在自己的总类别文件夹中
data_list_path = 'X:/pyproject/%s/' % father_path
# 如果不存在这个文件夹,就创建
isexist = os.path.exists(data_list_path)
if not isexist:
os.makedirs(data_list_path)
# 清空原来的数据
with open(data_list_path + "test.list", 'w') as f:
pass
with open(data_list_path + "trainer.list", 'w') as f:
pass
# 总的图像数量
all_class_images = 0
# 读取每个类别
for class_dir in class_dirs:
# 每个类别的信息
class_detail_list = {}
test_sum = 0
trainer_sum = 0
# 统计每个类别有多少张图片
class_sum = 0
# 获取类别路径
path = data_root_path + "/" + class_dir
# 获取所有图片
img_paths = os.listdir(path)
for img_path in img_paths: # 遍历文件夹下的每个图片
name_path = path + '/' + img_path # 每张图片的路径
if class_sum % 10 == 0: # 每10张图片取一个做测试数据
test_sum += 1 #test_sum测试数据的数目
with open(data_list_path + "test.list", 'a') as f:
f.write(name_path + "\t%d" % class_label + "\n") #class_label 标签:0,1,2
else:
trainer_sum += 1 #trainer_sum测试数据的数目
with open(data_list_path + "trainer.list", 'a') as f:
f.write(name_path + "\t%d" % class_label + "\n")#class_label 标签:0,1,2
class_sum += 1 #每类图片的数目
all_class_images += 1 #所有类图片的数目
# 说明的json文件的class_detail数据
class_detail_list['class_name'] = class_dir #类别名称,如jiangwen
class_detail_list['class_label'] = class_label #类别标签,0,1,2,3,4,5
class_detail_list['class_test_images'] = test_sum #该类数据的测试集数目
class_detail_list['class_trainer_images'] = trainer_sum #该类数据的训练集数目
class_detail.append(class_detail_list)
class_label += 1 #class_label 标签:0,1,2
# 获取类别数量
all_class_sum = class_dirs.__len__()
# 说明的json文件信息
readjson = {}
readjson['all_class_name'] = father_path #文件父目录
readjson['all_class_sum'] = all_class_sum #
readjson['all_class_images'] = all_class_images
readjson['class_detail'] = class_detail
jsons = json.dumps(readjson, sort_keys=True, indent=4, separators=(',', ': '))
with open(data_list_path + "readme.json",'w') as f:
f.write(jsons)
print ('生成数据列表完成!')
# 自定义数据
# train_reader和test_reader分别用于获取训练集和测试集 paddle.reader.shuffle()表示每次缓存BUF_SIZE个数据项,并进行打乱 paddle.batch()表示每BATCH_SIZE组成一个batch
#
# 自定义数据集需要先定义自己的reader,把图像数据处理一些,并输出图片的数组和标签。
# 定义训练的mapper
# train_mapper函数的作用是用来对训练集的图像进行处理修剪和数组变换,返回img数组和标签
# sample是一个python元组,里面保存着图片的地址和标签。 ('../images/face/zhangziyi/20181206145348.png', 2)
def train_mapper(sample):
img, label = sample
# 进行图片的读取,由于数据集的像素维度各不相同,需要进一步处理对图像进行变换
img = paddle.dataset.image.load_image(img)
#进行了简单的图像变换,这里对图像进行crop修剪操作,输出img的维度为(3, 100, 100)
img = paddle.dataset.image.simple_transform(im=img, #输入图片是HWC
resize_size=100, # 剪裁图片
crop_size=100,
is_color=True, #彩色图像
is_train=True)
#将img数组进行进行归一化处理,得到0到1之间的数值
img= img.flatten().astype('float32')/255.0
return img, label
# 对自定义数据集创建训练集train的reader
def train_r(train_list, buffered_size=1024):
def reader():
with open(train_list, 'r') as f:
# 将train.list里面的标签和图片的地址方法一个list列表里面,中间用\t隔开'
#../images/face/jiangwen/0b1937e2-f929-11e8-8a8a-005056c00008.jpg\t0'
lines = [line.strip() for line in f]
for line in lines:
# 图像的路径和标签是以\t来分割的,所以我们在生成这个列表的时候,使用\t就可以了
img_path, lab = line.strip().split('\t')
yield img_path, int(lab)
# 创建自定义数据训练集的train_reader
return paddle.reader.xmap_readers(train_mapper, reader,cpu_count(), buffered_size)
# sample是一个python元组,里面保存着图片的地址和标签。 ('../images/face/zhangziyi/20181206145348.png', 2)
def test_mapper(sample):
img, label = sample
img = paddle.dataset.image.load_image(img)
img = paddle.dataset.image.simple_transform(im=img, resize_size=100, crop_size=100, is_color=True, is_train=False)
img= img.flatten().astype('float32')/255.0
return img, label
# 对自定义数据集创建验证集test的reader
def test_r(test_list, buffered_size=1024):
def reader():
with open(test_list, 'r') as f:
lines = [line.strip() for line in f]
for line in lines:
#图像的路径和标签是以\t来分割的,所以我们在生成这个列表的时候,使用\t就可以了
img_path, lab = line.strip().split('\t')
yield img_path, int(lab)
return paddle.reader.xmap_readers(test_mapper, reader,cpu_count(), buffered_size)
BATCH_SIZE = 128
BUF_SIZE = 512
# 把图片数据生成reader
trainer_reader = train_r(train_list="X:/pyproject/face/trainer.list")
train_reader = paddle.batch(
paddle.reader.shuffle(
reader=trainer_reader,buf_size=BUF_SIZE),
batch_size=BATCH_SIZE)
tester_reader = test_r(test_list="X:/pyproject/face/test.list")
test_reader = paddle.batch(
tester_reader, batch_size=BATCH_SIZE)
#打印看下数据是什么样的?PaddlePaddle接口提供的数据已经经过了归一化、居中等处理 尝试打印一下,观察一下自定义的数据集
# train_data = paddle.batch(trainer_reader,
# batch_size=3)
# sampledata=next(train_data())
# print(sampledata)
#激活函数选择
#激活函数为Relu
act_function = 'relu'
#激活函数为Sigmoid
#act_function = 'sigmoid'
#激活函数为Tanh
#act_function = 'tanh'
#CNN网络
def cnn(image, type_size):
# 第一个卷积--池化层
conv_pool_1 = fluid.nets.simple_img_conv_pool(input=image, # 输入图像
filter_size=3, # 滤波器的大小
num_filters=32, # filter 的数量。它与输出的通道相同
pool_size=2, # 池化层大小2*2
pool_stride=2, # 池化层步长
act=act_function) # 激活类型
# Dropout主要作用是减少过拟合,随机让某些权重不更新
# Dropout是一种正则化技术,通过在训练过程中阻止神经元节点间的联合适应性来减少过拟合。
# 根据给定的丢弃概率dropout随机将一些神经元输出设置为0,其他的仍保持不变。
drop = fluid.layers.dropout(x=conv_pool_1, dropout_prob=0.5)
# 第二个卷积--池化层
conv_pool_2 = fluid.nets.simple_img_conv_pool(input=drop,
filter_size=3,
num_filters=64,
pool_size=2,
pool_stride=2,
act=act_function)
# 减少过拟合,随机让某些权重不更新
drop = fluid.layers.dropout(x=conv_pool_2, dropout_prob=0.5)
# 第三个卷积--池化层
conv_pool_3 = fluid.nets.simple_img_conv_pool(input=drop,
filter_size=3,
num_filters=64,
pool_size=2,
pool_stride=2,
act=act_function)
# 减少过拟合,随机让某些权重不更新
drop = fluid.layers.dropout(x=conv_pool_3, dropout_prob=0.5)
# 全连接层
fc = fluid.layers.fc(input=drop, size=512, act=act_function)
# 减少过拟合,随机让某些权重不更新
drop = fluid.layers.dropout(x=fc, dropout_prob=0.5)
# 输出层 以softmax为激活函数的全连接输出层,输出层的大小为图像类别type_size个数
predict = fluid.layers.fc(input=drop, size=type_size, act='softmax')
return predict
# VGG网络
# 1.首先定义了一组卷积网络,即conv_block。卷积核大小为3x3,池化窗口大小为2x2,窗口滑动大小为2,groups决定每组VGG模块是几次连续的卷积
# 操作,dropouts指定Dropout操作的概率。所使用的img_conv_group是在paddle.networks中预定义的模块,
# 由若干组 Conv->BN->ReLu->Dropout 和 一组 Pooling 组成。
#
# 2.五组卷积操作,即 5个conv_block。 第一、二组采用两次连续的卷积操作。第三、四、五组采用三次连续的卷积操作。每组最后一个卷积后
# 面Dropout概率为0,即不使用Dropout操作。
#
# 3.最后接两层512维的全连接。
#
# 4.通过上面VGG网络提取高层特征,然后经过全连接层映射到类别维度大小的向量,再通过Softmax归一化得到每个类别的概率,也可称作分类器。
def vgg(image, type_size):
def conv_block(ipt, num_filter, groups, dropouts):
return fluid.nets.img_conv_group(
input=ipt, # 具有[N,C,H,W]格式的输入图像
pool_size=2,
pool_stride=2,
conv_num_filter=[num_filter] * groups, # 过滤器个数
conv_filter_size=3, # 过滤器大小
conv_act=act_function,
conv_with_batchnorm=True, # 表示在 Conv2d Layer 之后是否使用 BatchNorm
conv_batchnorm_drop_rate=dropouts, # 表示 BatchNorm 之后的 Dropout Layer 的丢弃概率
pool_type='max') # 最大池化
conv1 = conv_block(image, 64, 2, [0.0, 0])
conv2 = conv_block(conv1, 128, 2, [0.0, 0])
conv3 = conv_block(conv2, 256, 3, [0.0, 0.0, 0])
conv4 = conv_block(conv3, 512, 3, [0.0, 0.0, 0])
conv5 = conv_block(conv4, 512, 3, [0.0, 0.0, 0])
drop = fluid.layers.dropout(x=conv5, dropout_prob=0.5)
fc1 = fluid.layers.fc(input=drop, size=512, act=None)
bn = fluid.layers.batch_norm(input=fc1, act=act_function)
drop2 = fluid.layers.dropout(x=bn, dropout_prob=0.0)
fc2 = fluid.layers.fc(input=drop2, size=512, act=None)
predict = fluid.layers.fc(input=fc2, size=type_size, act='softmax')
return predict
# (2)定义数据层
#
# image 和 label 是通过 fluid.layers.data 创建的两个输入数据层。其中 image 是 [3, 100, 100] 维度的浮点数据; label 是 [1]
# 维度的整数数据。
#
# 这里需要注意的是: Fluid中默认使用 -1 表示 batch size 维度,默认情况下会在 shape 的第一个维度添加 -1 。 所以 上段代码中,
# 我们可以接受将一个 [-1, 3, 100, 100] 的numpy array传给 image 。Fluid中用来做类别标签的数据类型是 int64,并且标签从0开始。
image = fluid.layers.data(name='image', shape=[3, 100, 100], dtype='float32')#[3, 100, 100],表示为三通道,100*100的RGB图
label = fluid.layers.data(name='label', shape=[1], dtype='int64')
print('image_shape:',image.shape)
# 分类器选择
# 注:type_size要和需要分类的类别数量保持一致
#获取分类器,用cnn或者vgg网络进行分类type_size要和训练的类别一致
TYPESIZE = 6
#predict = cnn(image=image, type_size = TYPESIZE)
predict = vgg(image=image, type_size = TYPESIZE)
# 获取损失函数和准确率
cost = fluid.layers.cross_entropy(input=predict, label=label)
# 计算cost中所有元素的平均值
avg_cost = fluid.layers.mean(cost)
#计算准确率
acc = fluid.layers.accuracy(input=predict, label=label)
#学习率选择
# 学习率
#LEARNING_RATE = 0.1
LEARNING_RATE = 0.025
#LEARNING_RATE = 0.0005
#LEARNING_RATE = 0.0015
#LEARNING_RATE = 0.001
#优化器选择
# Adam 优化器
#optimizer = fluid.optimizer.Adam(learning_rate=LEARNING_RATE)
# SGD 优化器
optimizer = fluid.optimizer.SGD(learning_rate=LEARNING_RATE)
# RMSProp 优化器
#optimizer = fluid.optimizer.RMSProp(learning_rate=LEARNING_RATE)
# Adagrad 优化器
#optimizer = fluid.optimizer.AdagradOptimizer(learning_rate=LEARNING_RATE)
optimizer.minimize(avg_cost)
print(type(acc))
#Step3.模型训练 and Step4.模型评估
# 1)创建Executor
# 首先定义运算场所 fluid.CPUPlace()和 fluid.CUDAPlace(0)分别表示运算场所为CPU和GPU
# Executor:接收传入的program,通过run()方法运行program。
# 训练分为三步:第一步配置好训练的环境,第二步用训练集进行训练,并用验证集对训练进行评估,不断优化,第三步保存好训练的模型
# 使用CPU进行训练
# CPU
#place = fluid.CPUPlace()
# GPU
place = fluid.CUDAPlace(0)
test_program = fluid.default_main_program().clone(for_test=True)
# 创建一个executor
exe = fluid.Executor(place)
# 对program进行参数初始化1.网络模型2.损失函数3.优化函数
exe.run(fluid.default_startup_program())
# (2)定义数据映射器
# DataFeeder负责将数据提供器(train_reader,test_reader)返回的数据转成一种特殊的数据结构,使其可以输入到Executor中。
# feed_list设置向模型输入的向变量表或者变量表名
# 定义输入数据的维度,DataFeeder 负责将reader(读取器)返回的数据转成一种特殊的数据结构,使它们可以输入到 Executor
feeder = fluid.DataFeeder(feed_list=[image, label], place=place)#定义输入数据的维度,第一个是图片数据,第二个是图片对应的标签。
#(3)展示模型训练曲线
all_train_iter=0
all_train_iters=[]
all_train_costs=[]
all_train_accs=[]
def draw_train_process(title,iters,costs,accs,label_cost,lable_acc):
plt.title(title, fontsize=24)
plt.xlabel("iter", fontsize=20)
plt.ylabel("cost/acc", fontsize=20)
plt.plot(iters, costs,color='red',label=label_cost)
plt.plot(iters, accs,color='green',label=lable_acc)
plt.legend()
plt.grid()
plt.show()
#(4)训练并保存模型
# Executor接收传入的program,并根据feed map(输入映射表)和fetch_list(结果获取表) 向program中添加feed operators(数据输入算子)
# 和fetch operators(结果获取算子)。
# feed map为该program提供输入数据。fetch_list提供program训练结束后用户预期的变量。
# 这次训练5个Pass。每一个Pass训练结束之后,再使用验证集进行验证,并求出相应的损失值Cost和准确率acc。
# 训练的轮数
EPOCH_NUM = 25
print('开始训练...')
model_save_dir = "X:/pyproject/data/model"
for pass_id in range(EPOCH_NUM):
# train_cost = 0
for batch_id, data in enumerate(train_reader()): # 遍历train_reader的迭代器,并为数据加上索引batch_id
train_cost, train_acc = exe.run(
program=fluid.default_main_program(), # 运行主程序
feed=feeder.feed(data), # 喂入一个batch的数据
fetch_list=[avg_cost, acc]) # fetch均方误差和准确率
all_train_iter = all_train_iter + BATCH_SIZE
all_train_iters.append(all_train_iter)
all_train_costs.append(train_cost[0])
all_train_accs.append(train_acc[0])
if batch_id % 10 == 0: # 每10次batch打印一次训练、进行一次测试
print("\n轮数:%d, 次数:%d, 损失率:%f, 准确率:%f" %
(pass_id, batch_id, train_cost[0], train_acc[0]))
# 开始测试
test_accs = [] # 测试的损失值
test_costs = []
lists = [] # 测试的准确率
# 每训练一轮 进行一次测试
for batch_id, data in enumerate(test_reader()): # 遍历test_reader
test_cost, test_acc, data_predict = exe.run(program=test_program, # #运行测试测试程序
feed=feeder.feed(data), # 喂入一个batch的数据
fetch_list=[avg_cost, acc, predict]) # fetch均方误差、准确率
test_accs.append(test_acc[0]) # 记录每个batch的误差
test_costs.append(test_cost[0]) # 记录每个batch的准确率
if batch_id == 0:
all_predict = data_predict
all_data = data
else:
all_predict = np.vstack((all_predict, data_predict))
all_data = np.vstack((all_data, data))
# 求测试结果的平均值
test_cost = (sum(test_costs) / len(test_costs)) # 每轮的平均误差
test_acc = (sum(test_accs) / len(test_accs)) # 每轮的平均准确率
lists.append((pass_id, test_cost, test_acc))
print('第%d轮, 平均损失率:%0.5f, 平均准确率:%0.5f' % (pass_id, test_cost, test_acc))
# 如果保存路径不存在就创建
if not os.path.exists(model_save_dir):
os.makedirs(model_save_dir)
print ('save models to %s' % (model_save_dir))
# 保存训练的模型,executor 把所有相关参数保存到 dirname 中
fluid.io.save_inference_model(model_save_dir, #保存推理model的路径
['image'], #推理(inference)需要 feed 的数据
[predict], #保存推理(inference)结果的 Variables
exe) #executor 保存 inference model
best = sorted(lists, key=lambda list: list[1])[0]
print("最好为第 %d 轮数,平均损失率:%0.5f " % (best[0], best[1]))
print("分类准确度:%0.2f%%" % (best[2]*100))
#绘制准确率与损失率图
draw_train_process("training",all_train_iters,all_train_costs,all_train_accs,"trainning cost","trainning acc")
all_test_label = np.array([d[1] for d in all_data]).astype("float32")
#输出混淆矩阵
confusion_m = pd.DataFrame(confusion_matrix(all_test_label, np.argmax(all_predict, 1)), columns=[i for i in range(6)])
print(confusion_m)
###### 运行结果及详细报错内容

什么显卡,这个报错好像是现存不足。