使用神经网络模型,进行图像分类(数据集Data)
自己设计神经网络,或者使用现有网络,对训练数据进行训练
不许使用已经训练好的模型,需自己训练,然后将训练好的模型对测试数据进行测试
需自行调参
data数据集,三个标签数据(马,飞机,汽车)
import warnings
warnings.filterwarnings("ignore")
import datetime
import matplotlib.pyplot as plt
import time
starttime = datetime.datetime.now()
import numpy as np
#from sklearn.cross_validation import train_test_split
from sklearn.model_selection import train_test_split
from sklearn.metrics import confusion_matrix, classification_report
#error:UndefinedMetricWarning:
# Precision and F-score are ill-defined and being set to 0.0 in labels with no predicted samples.
# Use `zero_division` parameter to control this behavior.
# _warn_prf(average, modifier, msg_start, len(result))
#https://blog.csdn.net/qq_43391414/article/details/120543028
import os
import cv2
X = []
Y = []
width = 256
height = 256
# for i in range(0, 10):
for i in range(0+1, 3+1):
# 遍历文件夹,读取图片
# for f in os.listdir("./photo/%s" % i):
# for f in os.listdir("./data/data/train"):
# for f in os.listdir("./test2"):
for f in os.listdir("./data/data/train/%s" %i):
# for f in os.listdir("./data/data/train"):
# 打开一张图片并灰度化
# Images = cv2.imread("./photo/%s/%s" % (i, f))
# https: // blog.csdn.net / weixin_44015965 / article / details / 109547129
# Images = cv2.imread("./data/data/train/%s" % f)
Images = cv2.imread("./data/data/train/%s/%s" % (i,f))
#图片放缩
image = cv2.resize(Images, (256, 256), interpolation=cv2.INTER_CUBIC)
# cv2.calcHist()函数的作用:
# 通过直方图可以很好的对整幅图像的灰度分布有一个整体的了解,直方图的x轴是灰度值(0
# ~255),y轴是图片中具有同一个灰度值的点的数目。而calcHist()函数则可以帮助我们统计一幅图像的直方图
hist = cv2.calcHist([image], [0, 1], None, [256, 256], [0.0, 255.0, 0.0, 255.0])
X.append((hist / 255).flatten())
Y.append(i)
X = np.array(X)
Y = np.array(Y)
# 切分训练集和测试集
# X_train, X_test, y_train, y_test = train_test_split(X, Y, test_size=0.3, random_state=1)
X_train, X_test, y_train, y_test = train_test_split(X, Y, test_size=300, random_state=1)
# test_size 若在0~1之间,为测试集样本数目与原始样本数目之比;若为整数,则是测试集样本的数目。
# random_state 随机数种子
# X_train 划分出的训练集数据(返回值)
# X_test 划分出的测试集数据(返回值)
# y_train 划分出的训练集标签(返回值)
# y_test 划分出的测试集标签(返回值)
# X 待划分的样本特征集合
# y 待划分的样本标签
from sklearn.preprocessing import LabelBinarizer
import random
def logistic(x):
return 1 / (1 + np.exp(-x))
def logistic_derivative(x):
return logistic(x) * (1 - logistic(x))
class NeuralNetwork:
def predict(self, x):
# w , b
for b, w in zip(self.biases, self.weights):
# 计算权重相加再加上偏向的结果
z = np.dot(x, w) + b
# 计算输出值
x = self.activation(z)
return self.classes_[np.argmax(x, axis=1)]
# BP 算法是一个迭代算法,它的基本思想为:
# (1) 先计算每一层的状态和激活值,直到最后一层(即信号是前向传播的);
# (2) 计算每一层的误差,误差的计算过程是从最后一层向前推进的(这就是反向传播算法名字的由来);
# (3) 更新参数(目标是误差变小),迭代前面两个步骤,直到满足停止准则(比如相邻两次迭代的误差的差别很小)。
class BP(NeuralNetwork):
def __init__(self, layers, batch):
# 层
self.layers = layers
# 批处理
self.batch = batch
# 流
self.activation = logistic
#
self.activation_deriv = logistic_derivative
# length
self.num_layers = len(layers)
# 偏差 b
self.biases = [np.random.randn(x) for x in layers[1:]]
# 权重 w
self.weights = [np.random.randn(x, y) for x, y in zip(layers[:-1], layers[1:])]
def fit(self, X, y, learning_rate=0.2, epochs=1):
print(learning_rate)
# class sklearn.preprocessing.LabelBinarizer(neg_label=0, pos_label=1, sparse_output=False)
labelbin = LabelBinarizer()
# LabelBinarizer()
# 是sklearn.preprocessing中的一个函数,通过这个函数可以实现机器学习中国对图像标签的独热编码。
# 独热编码是一种二进制编码,通俗的讲独热编码主要满足以下几个条件:
#
# 图像有n类,则编码长度为n
# 对第i类编码,只有第i位置1,其余为0(1 ≤ i ≤ n
y = labelbin.fit_transform(y)
# fit_transform(self, y) 设定或者初始化二进制分类器并开始对y进行转换
self.classes_ = labelbin.classes_
training_data = [(x, y) for x, y in zip(X, y)]
n = len(training_data)
print(n)
for k in range(epochs):
t = time.localtime()
print(k,t)
# 每次迭代都循环一次训练
random.shuffle(training_data)
# 搅乱训练集,让其排序顺序发生变化
# print(self.batch)
batches = [training_data[k:k + self.batch] for k in range(0, n, self.batch)]
# print(batches)
# 批量梯度下降
for mini_batch in batches:
x = []
y = []
for a, b in mini_batch:
x.append(a)
y.append(b)
activations = [np.array(x)]
# 向前一层一层的走
for b, w in zip(self.biases, self.weights):
# 计算激活函数的参数,计算公式:权重.dot(输入)+偏向
z = np.dot(activations[-1], w) + b
# 计算输出值
output = self.activation(z)
# 将本次输出放进输入列表,后面更新权重的时候备用
activations.append(output)
# 计算误差值
error = activations[-1] - np.array(y)
# 计算输出层误差率
deltas = [error * self.activation_deriv(activations[-1])]
# 循环计算隐藏层的误差率,从倒数第2层开始
for l in range(self.num_layers - 2, 0, -1):
deltas.append(self.activation_deriv(activations[l]) * np.dot(deltas[-1], self.weights[l].T))
# 将各层误差率顺序颠倒,准备逐层更新权重和偏向
deltas.reverse()
# 更新权重和偏向
for j in range(self.num_layers - 1):
# 权重的增长量,计算公式,增长量 = 学习率 * (错误率.dot(输出值)),单个训练数据的误差
delta = learning_rate / self.batch * (
(np.atleast_2d(activations[j].sum(axis=0)).T).dot(np.atleast_2d(deltas[j].sum(axis=0))))
# 更新权重
self.weights[j] -= delta
# 偏向增加量,计算公式:学习率 * 错误率
delta = learning_rate / self.batch * deltas[j].sum(axis=0)
# 更新偏向
self.biases[j] -= delta
return self
# clf0 = BP([X_train.shape[1], 10], 10).fit(X_train, y_train, epochs=100)
clf0 = BP([X_train.shape[1], 3], 4).fit(X_train, y_train, epochs=100)
# def fit(self, X, y, learning_rate=0.1, epochs=1):
# def fit(self, X, y, learning_rate=0.2, epochs=10000):
# 设定epochs为循环的最高次数,即到最高时就直接结束循环 X = np.a...
predictions_labels = clf0.predict(X_test)
print(confusion_matrix(y_test, predictions_labels))
print(classification_report(y_test, predictions_labels))
# classification_report(
# y_true,
# y_pred,
# labels=None,
# target_names=None,
# sample_weight=None,
# digits=2,
# output_dict=False,
# zero_division=“warn”
# )
#
# 参数 描述
# y_true 真实值 ,一维数组形式(也可以是列表元组之类的)
# y_pred 预测值,一维数组形式(也可以是列表元组之类的)
# labels 标签索引列表,可选参数,数组形式
# target_names 与标签匹配的名称,可选参数,数组形式
# sample_weight 样本权重,数组形式
# digits 格式化输出浮点值的位数。默认为2。当“output_dict”为“True”时,这将被忽略,并且返回的值不会四舍五入。
# output_dict 是否输出字典。默认为False,如果为True则输出结果形式为字典。
# zero_division 设置存在零除法时返回的值。默认为warn。如果设置为“warn”,这相当于0,但也会引发警告。
endtime = datetime.datetime.now()
print(endtime - starttime)