1.制作数据
1.1 h5py简介
"""
训练数据集和测试数据集为:train_catvnoncat.h5、train_catvnoncat.h5
本例打开训练数据集中训练数据的第一个数据(更改索引号,查看其它数据)。测试集中测试数据同样课通过该方法打开
"""
import h5py # 工具
from PIL import Image
def read():
traindata = h5py.File("datasets/train_catvnoncat.h5", mode="r") # File:类
for key, value in traindata.items():
print(key, value)
datalist = traindata["train_set_x"]
print(datalist)
print(datalist.shape)
print(type(datalist[0]))
print(datalist[0])
image = Image.fromarray(datalist[5])#包含正样本和负样本
image.show()
# testdata=h5py.File("datasets/train_catvnoncat.h5","r")
# for key,value in testdata.items():
# print(key,value)
read()
1.2制作数据
#最终代码。(一)
import h5py
class Mydata():
def __init__(self,train_path,test_path):
self.traindata = h5py.File(train_path, "r")#File:类
self.testdata = h5py.File(test_path, "r")
def get_traindata(self):
get_traindataX = self.traindata["train_set_x"][:]/255.-0.5#归一化、去均值
get_traindataY = self.traindata["train_set_y"]
return get_traindataX, get_traindataY
def get_testdata(self):
get_testdataX = self.testdata["train_set_x"][:]/255.-0.5#归一化、去均值
get_testdataY = self.testdata["train_set_y"]
return get_testdataX,get_testdataY
2.制作网络
2.1 Sigmoid函数
2.1.1函数曲线
2.1.2函数公式
2.1.3函数导数
2.1.4代码实现
#源码
import numpy as np
def Sigmoig(z):
a=1/(1+np.exp(-z))
return a
2.2损失函数
2.2.1链式调用
#实例
class Person:
def name(self, name):
self.name = name
return self
def age(self, age):
self.age = age
return self
def show(self):
print("My name is", self.name, "and I am", self.age, "years old.")
p = Person()
p.name("Li Lei").age(15).show()
#打印结果
My name is Li Lei and I am 15 years old.
2.2.2单神经元反向求导
noncat 或cat
(1)输入矩阵X维度
假设输入图片维度为(64,64, 3),转化为一维特征向量为(12288,1)。 此特征向量x是列向量,维度一般记为n_x 。
如果训练样本共有m张图片,那么整个训练样本X组成了矩阵,维度是(n_x,m) 。其中。n_x 代表了每个样本x^(i)特征个数 , 列m代表了样本个数。 Andrew解释 该形式矩阵方便后边矩阵运行方便。
(2)权重矩阵W维度
(n_x ,1)
(3)常数b维度
常数
(4)输出矩阵Z维度
(1,m)
(5)计算维度分析
前向传播:
反向求导:
(6)代码实现
#源码
import numpy as np
from MyData import Dataset
import matplotlib.pyplot as plt
import pickle
from PIL import Image
def sigmoid(z):
a = 1 / (1 + np.exp(-z))
return a
class SingleNeural:
cache = []
def __init__(self, in_feature=None ,bias=True):
self.weight = np.random.randn(in_feature, 1) * 0.01
if bias:
self.bias = 0
def __call__(self, x):
return self.forward(x)
def forward(self, x):
x = x.reshape(-1, 64*64*3)
x = x.T # 先转置一下
SingleNeural.cache.append(x) # 保存x参数
z = np.dot(self.weight.T, x)
if hasattr(self, "bias"):
z += self.bias
a = sigmoid(z)
return a
class MSELoss:
def __call__(self, output, target):
self.A = output
self.Y = target
self.m = target.shape[0]
return self.forward(output,target)
def forward(self, A, Y):
self.loss = np.sum(np.square(A - Y)) / self.m
return self
def float(self):
return self.loss
def backward(self):
dA = 2 * (self.A - self.Y)
dZ = dA * (self.A * (1 - self.A)) # sigmoid的导数过来的
x = SingleNeural.cache[0]
dW = np.dot(x, dZ.T) / self.m
dB = np.sum(dZ) / self.m
return {"dW":dW, "dB":dB}
class Optimizer:
def __init__(self, net, lr=0.01):
self.net = net
self.lr = lr
def step(self, grads):
self.net.weight = self.net.weight - self.lr * grads["dW"]
if hasattr(self.net, "bias"):
self.net.bias = self.net.bias - self.lr * grads["dB"]
# 清空参数
SingleNeural.cache.clear()
2.3制作优化器
2.2.1梯度下降
J(w,b)是convex function,梯度下降算法是先随机选择一组参数w和b值,然后每次迭代的过程中分别沿着w和b的梯度(偏导数)的反方向前进一小步,不断修正w和b。每次迭代更新w和b后,都能让J(w,b)更接近全局最小值。梯度下降的过程如下图所示。
梯度下降算法每次迭代更新,w和b的修正表达式为:
原文链接: https://blog.csdn.net/red_stone1/article/details/77851177
2.2.2代码实现
#源代码
class Optimizer:
def __init__(self, net, lr=0.01):
self.net = net
self.lr = lr
def step(self, grads):
self.net.weight = self.net.weight - self.lr * grads["dW"]
if hasattr(self.net, "bias"):
self.net.bias = self.net.bias - self.lr * grads["dB"]
# 清空参数
SingleNeural.cache.clear()
2.4单个感知机制作
2.4.1call()
2.4.1.1概念
Python中有一个有趣的语法,只要定义类型的时候,实现<u>__</u>call__函数,这个类型就成为可调用的。换句话说,我们可以把这个类型的对象当作函数来使用,相当于 重载了括号运算符。
2.4.1.2示例
所有的函数都是可调用对象。一个类实例也可以变成一个可调用对象,只需要实现一个特殊方法call ,我们把 Person 类变成一个可调用对象:
#实例
class Person(object):
def __init__(self, name, gender):
self.name = name
self.gender = gender
def __call__(self, friend):
print('My name is %s...' % self.name)
print('My friend is %s...' % friend)
p=Person('Bob', 'male')
p('Tim')
#打印结果
My name is Bob...
My friend is Tim...
单看 p(‘Tim’) 你无法确定 p 是一个函数还是一个类实例,所以,在Python中,函数也是对象,对象和函数的区别并不显著。
2.4.2代码实现
#源码
class SingleNeural:
cache = []
def __init__(self, in_feature=None ,bias=True):
self.weight = np.random.randn(in_feature, 1) * 0.01
if bias:
self.bias = 0
def __call__(self, x):
return self.forward(x)
"""前向传播_后前部分"""
def forward(self, x):
x = x.reshape(-1, 64*64*3)
x = x.T
SingleNeural.cache.append(x) # 保存x参数
z = np.dot(self.weight.T, x)
if hasattr(self, "bias"):
z += self.bias
a = sigmoid(z)
return a
2.5制作训练模型
2.5.1序列化与反序列化
#实例
import pickle
class User:
def __init__(self,name,age):
self.name=name
self.age=age
def to_string(self):
return self.name , self.age
user=User("张三",20)
print(user.to_string())
#序列化对象
with open("user.pth","wb") as f:
pickle.dump(user,f)#生成一个user.pth文件
# 反序列化
with open("user.pth","rb") as f:
user=pickle.load(f)#加载对象
print(user.to_string())
2.5.2代码实现
#源码
class Trainer:
def __init__(self):
self.net = SingleNeural(64*64*3)
self.loss_func = MSELoss()
self.opt = Optimizer(self.net, lr=0.02)
dataset = Dataset("datasets/train_catvnoncat.h5","datasets/test_catvnoncat.h5")
self.trainset = dataset.get_train_set()
self.testset = dataset.get_test_set()
def save(self, net ,path):#保存网络结构
with open(path, "wb") as f:
data = pickle.dumps(net)
f.write(data)
def load(self, path):#加载网络结构
with open(path, "rb") as f:
data = f.read()
net = pickle.loads(data)
return net
def train(self):
x , y = self.trainset[0] , self.trainset[1]
print(x.shape)
losses = []
for i in range(10000):
out = self.net(x)
loss = self.loss_func(out,y)
if i % 100 == 0:
print("{}/{},loss:{}".format(i,5000, loss.float()))
losses.append(loss.float())
plt.clf()
plt.plot(losses)
plt.pause(0.01)
grads = loss.backward()
self.opt.step(grads)
self.save(self.net, "models/net.pth")
def test(self):
x, y = self.testset[0], self.testset[1]
net = self.load("models/net.pth")
# for i in range(x.shape[0]):
# img = ((x[i] + 0.5) * 255).astype(np.uint8)
# img = Image.fromarray(img)
# out = net(x[i])
# plt.clf()
# plt.axis("off")
# plt.text(0,-5,"The result of AI: {}".format("cat" if out.round() > 0 else "non-cat" ), color="red")
# plt.imshow(img)
# plt.pause(1)
"""
正负样本总共预测对了多少个
"""
print(y)
out = net(x)
print(out.round())
predict = (out.round() == y).sum()
print("预测对了{}个".format(predict))
def test_other(self):
img = Image.open("images/0.57.jpeg")
img = img.resize((64,64),Image.ANTIALIAS)
img = np.array(img) / 255. - 0.5
net = self.load("models/net.pth")
out = net(img)
print(out)
print(out.round())
2.6最终代码
#网络总代码(二)
import numpy as np
from MyData import Dataset
import matplotlib.pyplot as plt
import pickle
from PIL import Image
def sigmoid(z):
a = 1 / (1 + np.exp(-z))
return a
class SingleNeural:
cache = []
def __init__(self, in_feature=None ,bias=True):
"""
初始化神经元的参数
:param in_feature: 输入的特征数
:param bias: 是否要偏置
"""
self.weight = np.random.randn(in_feature, 1) * 0.01#w越靠近0,梯度更新越快。
if bias:
self.bias = 0
def __call__(self, x):
"""
模仿Pytorch的风格
:param x:
:return:
"""
return self.forward(x)
def forward(self, x):
"""
前向运算 动态构建网络的结构拓扑图
:param x: 输入的数据
:return: 结果
"""
x = x.reshape(-1, 64*64*3)
x = x.T # 先转置一下
SingleNeural.cache.append(x) # 保存x参数
z = np.dot(self.weight.T, x)
if hasattr(self, "bias"):
z += self.bias
a = sigmoid(z)
return a
class MSELoss:
"""
均方差损失函数
loss = Σ(A - Y)^2 / m
"""
def __call__(self, output, target):
self.A = output
self.Y = target
self.m = target.shape[0]
return self.forward(output,target)
def forward(self, A, Y):
self.loss = np.sum(np.square(A - Y)) / self.m
# 链式编程风格
return self
def float(self):
return self.loss
def backward(self):
"""
方向计算梯度,求导,
BP算法的核心代码
求导均是求 loss对参数的导数
此处运用了高数的链式法则
dL/dW = dL/dA * dA/dZ * dZ/dW
:return:
"""
dA = 2 * (self.A - self.Y)
dZ = dA * (self.A * (1 - self.A)) # sigmoid的导数过来的
x = SingleNeural.cache[0]
dW = np.dot(x, dZ.T) / self.m
dB = np.sum(dZ) / self.m
return {"dW":dW, "dB":dB}
class Optimizer:
def __init__(self, net, lr=0.01):
"""
初始化优化器的步长
:param net:
:param lr:
"""
self.net = net
self.lr = lr
def step(self, grads):
self.net.weight = self.net.weight - self.lr * grads["dW"]
if hasattr(self.net, "bias"):
self.net.bias = self.net.bias - self.lr * grads["dB"]
# 清空参数
SingleNeural.cache.clear()
class Trainer:
def __init__(self):
self.net = SingleNeural(64*64*3)
self.loss_func = MSELoss()
self.opt = Optimizer(self.net, lr=0.02)
dataset = Dataset("datasets/train_catvnoncat.h5","datasets/test_catvnoncat.h5")
self.trainset = dataset.get_train_set()
self.testset = dataset.get_test_set()
def save(self, net ,path):
"""
保存网络结构
:param net:
:param path:
:return:
"""
with open(path, "wb") as f:
data = pickle.dumps(net)
f.write(data)
def load(self, path):
with open(path, "rb") as f:
data = f.read()
net = pickle.loads(data)
return net
def train(self):
x , y = self.trainset[0] , self.trainset[1]
print(x.shape)
losses = []
for i in range(10000):
out = self.net(x)
loss = self.loss_func(out,y)
if i % 100 == 0:
print("{}/{},loss:{}".format(i,5000, loss.float()))
losses.append(loss.float())
plt.clf()
plt.plot(losses)
plt.pause(0.01)
grads = loss.backward()
self.opt.step(grads)
self.save(self.net, "models/net.pth")
def test(self):
x, y = self.testset[0], self.testset[1]
net = self.load("models/net.pth")
# for i in range(x.shape[0]):
# img = ((x[i] + 0.5) * 255).astype(np.uint8)
# img = Image.fromarray(img)
# out = net(x[i])
# plt.clf()
# plt.axis("off")
# plt.text(0,-5,"The result of AI: {}".format("cat" if out.round() > 0 else "non-cat" ), color="red")
# plt.imshow(img)
# plt.pause(1)
"""
正负样本总共预测对了多少个
"""
print(y)
out = net(x)
print(out.round())
predict = (out.round() == y).sum()#out.round():四舍五入
print("预测对了{}个".format(predict))
def test_other(self):
img = Image.open("images/0.57.jpeg")
img = img.resize((64,64),Image.ANTIALIAS)
img = np.array(img) / 255. - 0.5
net = self.load("models/net.pth")
out = net(img)
print(out)
print(out.round())
if __name__ == '__main__':
t = Trainer()
t.train()
t.test()
# t.test_other()
3.测试
#最终代码(三)
import h5py
from PIL import Image
def read():
trainData = h5py.File("datasets/train_catvnoncat.h5",mode="r")
for key , value in trainData.items():
print(key, value) # cat non_cat
datalist = trainData["train_set_x"]
print(datalist[:])
img = Image.fromarray(datalist[2])
# img.show()
target = trainData["train_set_y"]
print(target[:])
read()
四.总结
4.1最终代码
最终三个代码块:(一)(二)(三)。
4.2最终数据
数据:https://pan.baidu.com/s/1Tix5CRLVXjQO6tkPO_LiFw