之前训练出来的loss是比较离谱的,形如
后来改了线性层和激活层的一些维度,但是loss还是上面的图像,后来经过检查原因,原来是:
交叉熵写错了,giao
贴一个改过来之后的loss
嗯。。看着还挺好看的,这里面实现的还没有那个验证(没学到呢)只是一开始的训练,训练了800个epoch,不过对于梯度啥玩意的有了一定了解,嗯,,是这样的

import paddle
import matplotlib.pyplot as plt
# 两个线性层,一个激活层
from data import make_moons#通过这个引入数据,一共两个特征,为二分类问题
class linear(object):def __init__(self, inputdim, outputdim, name):# [1, 3, 3, 9] 形状的张量# 通过 nn.Linear(9, 18) 的线性层,# 其输出的形状是 [1, 3, 3, 18]self.params = {}self.params['w'] = paddle.rand(shape=[inputdim, outputdim])#在这里假设w是一个n*1的列向量,n的大小取决于有几个特征self.params['b'] = paddle.rand(shape=[1, outputdim])#这块的偏置是对于一个隐藏层的偏置(一组w)self.name = nameself.grad={}self.grad['w']=Noneself.grad['b']=Noneself.inputs = None##定义前向传播函数def forward(self,input):#这里传入的imput就是一个矩阵,要放进来然后和w进行相乘self.input=inputself.output=paddle.matmul(input,self.params['w'])+self.params['b']  #800*2 2*6return self.outputdef backward(self,grad):self.grad['w']=paddle.matmul(self.input.T,grad)a=self.input.shape[0]self.grad['b']=paddle.matmul(paddle.ones(shape=[1,800]),grad)  #paddle.matmul(grad.T,paddle.ones(shape=(a,self.params['w'].shape[1])))#800*6return paddle.matmul(grad,self.params['w'].T)#800*6 6*2# 激活层,使用的是sigmoid函数
#sigmoid=1/(1+e^(-x))
class logistic(object):def __init__(self,name):self.input=Noneself.output=Noneself.grad=Noneself.name=name##定义前向传播函数def forward(self,input):self.input=inputself.func=paddle.nn.functional.sigmoidself.output=self.func(input)return self.func(input)##这个输出函数的导数我可得纪念一下,免得之后再忘了def backward(self,grad):##首先通过激活函数的输入为x,那么出来的函数值就是1/(1+e^(-x))##经过化简也就是,e^x/(1+e^x)##之后再对它求导就是:e^x/(1+e^x)^2,也就是1/(e^x+2+e^(-x))##然后看了一遍答案结果是out*(1-out) //out就是输出##为啥呢,out=e^x/(1+e^x),那么out*(1-out)就是[1/(1+e^x)]*[e^x/(1+e^x)],就是上面那个#  @ self.grad= 1/(paddle.exp(output)+2+paddle.exp(-output))//这么写是错的#然后再来看上面的这一行,他的梯度不是把output放进去,是后面的层向前传播(backward)的时候##把后面带来的错误传给这一层,所以应该是输出一个output,然后外面有一个对output的导数,然后再用output来对input求导数##最后把一个loss对output的偏导×一个output对input的偏导,这个input又是前面一层的output,就是一个递推self.grad=grad*self.output*(1-self.output)#这个就背下来吧,这个梯度一定要留下,以便于后面optmizer的更新参数return self.gradclass BinaryCrossEntryLoss(object):def __init__(self):#这个model应该是整个网络self.predicts=Noneself.labels=Noneself.num=Nonedef forward(self,label,predict):self.labels=labelself.predicts=predictN=label.shape[0]self.num=N##损失函数的定义loss=(-1/N)*(paddle.matmul(label.t(),paddle.log(predict))+paddle.matmul(1-label.t(),paddle.log((1-predict))))return loss#这块的loss是一个标量,然后导数是一个向量def backward(self):return (-1/self.num)*((self.labels/self.predicts)-((self.labels-1)/(self.predicts-1)))#这里得到的应该是一个列向量
#网络形状:一个线性层(linear),一个激活层,一个线性层,一个激活层,然后计算交叉熵
class model(object):def __init__(self,number_of_symbol,hidden_size,output_size):#hidden_size为隐藏层大小,# number_of_symbol是输入样本的特征数目#输入数据形状:n*2self.fc1=linear(number_of_symbol,hidden_size,'fc1')self.sig1=logistic('sig1')self.fc2=linear(hidden_size,output_size,'fc2')self.sig2=logistic('sig2')self.layer=[self.fc1,self.sig1,self.fc2,self.sig2]def forward(self,input,label):self.input=inputself.label=labela=self.fc1.forward(input)a=self.sig1.forward(a)a=self.fc2.forward(a)a=self.sig2.forward(a)return adef backward(self,grad):grad=self.sig2.backward(grad)grad=self.fc2.backward(grad)grad=self.sig1.backward(grad)grad=self.fc1.backward(grad)
class runner(object):def __init__(self,net,loss_fn,dataset,y,epoch,alpha):self.model=netself.loss_fn=loss_fnself.dataset=datasetself.labels=yself.epoch=epochself.train_loss=[]self.opt=optimizer(alpha,self.model)def train(self):for i in range(self.epoch):predict=self.model.forward(self.dataset,self.labels)# print("p",predict,"l",self.labels)loss=self.loss_fn.forward(self.labels,predict)self.train_loss.append(loss.item())print(loss.item())grad=self.loss_fn.backward()self.model.backward(grad)self.opt.step()return self.train_lossclass optimizer(object):def __init__(self,alpha,model):self.alpha=alpha  #定义学习率self.model=modeldef step(self):for layer in self.model.layer:if(layer.name=='fc1' or layer.name=='fc2'):layer.params['w']=layer.params['w']-layer.grad['w']*self.alphalayer.params['b']=layer.params['b']-layer.grad['b']*self.alphaX,y1=make_moons(n_samples=1000, shuffle=True, noise=0.5)
X=X[0:800,0:2]#这个作为数据集进行预测
y=paddle.rand(shape=[800,1])
for i in range(800):y[i]=y1[i][0]
#取切片的时候是左闭右开
number_of_symbol=2
hidden_size=6
output_size=1
alpha=0.1
epoch=800
net=model(number_of_symbol,hidden_size,output_size)
loss_fn=BinaryCrossEntryLoss()
net_running=runner(net,loss_fn,X,y,epoch,alpha)
y=net_running.train()x=[i for i in range(epoch)]
plt.figure()
plt.plot(x,y,color='blue',linestyle='--')
plt.legend(labels='loss')
plt.show()

又是一波手撕网络,网课地址及资料地址:
https://aistudio.baidu.com/aistudio/projectdetail/4485001
这是飞桨推出的课程,使用的也是paddle的API
数据集的生成,dataset是一个N2的list(N个样本,2个特征)
然后label就是一个N
1的列向量
然后这里面让我印象比较深刻的就是线性层的w和b

对于线性层而言
设其输出为y,输入为X矩阵,隐藏层维度为6
那么这一层的输出应该是y=Xw+b,对于X而言,在这里我们设X是一个800*2的矩阵(800个样本,每个样本2个特征)
也就是输入X形如:

然后由于隐藏层维度是6,所以第一个线性层的w矩阵为
得到一个800*6的矩阵,对于梯度grad来说,只要知道这个梯度都是相对于后一层的输入而言的,那么对于这一层而言就应该是本层的输出,也就是得到的800*6,而这个800*6的矩阵应该形如(Xw)

在这种情况下还要和一个偏置相加,这个时候就设偏置为c了
可以看到这个时候的偏置是一个行向量,而不是一个800*6的矩阵.
接下来又有问题了,如何对输入的a求梯度(backward)
对于结果的第一行来说,应该有(为了书写方便,转换成列向量来看)
对左右矩阵进行求和则有:
所以只要把梯度相加在乘以w的和即可
grad的形状为800
6,w的形状为26,为了对8002的矩阵求梯度只需要grad*w.T
对应代码就是在Linear类->backward函数的return语句:

 return paddle.matmul(grad,self.params['w'].T)

注意matmul是做矩阵乘法,乘号是对应元素相乘
公式在线编辑器:https://www.latexlive.com/##

后记:
数据集生成的代码

import math
import copy
import paddledef make_moons(n_samples=1000, shuffle=True, noise=None):"""生成带噪音的弯月形状数据输入:- n_samples:数据量大小,数据类型为int- shuffle:是否打乱数据,数据类型为bool- noise:以多大的程度增加噪声,数据类型为None或float,noise为None时表示不增加噪声输出:- X:特征数据,shape=[n_samples,2]- y:标签数据, shape=[n_samples]"""n_samples_out = n_samples // 2n_samples_in = n_samples - n_samples_out# 采集第1类数据,特征为(x,y)# 使用'paddle.linspace'在0到pi上均匀取n_samples_out个值# 使用'paddle.cos'计算上述取值的余弦值作为特征1,使用'paddle.sin'计算上述取值的正弦值作为特征2outer_circ_x = paddle.cos(paddle.linspace(0, math.pi, n_samples_out))outer_circ_y = paddle.sin(paddle.linspace(0, math.pi, n_samples_out))inner_circ_x = 1 - paddle.cos(paddle.linspace(0, math.pi, n_samples_in))inner_circ_y = 0.5 - paddle.sin(paddle.linspace(0, math.pi, n_samples_in))print('outer_circ_x.shape:', outer_circ_x.shape, 'outer_circ_y.shape:', outer_circ_y.shape)print('inner_circ_x.shape:', inner_circ_x.shape, 'inner_circ_y.shape:', inner_circ_y.shape)# 使用'paddle.concat'将两类数据的特征1和特征2分别延维度0拼接在一起,得到全部特征1和特征2# 使用'paddle.stack'将两类特征延维度1堆叠在一起X = paddle.stack([paddle.concat([outer_circ_x, inner_circ_x]),paddle.concat([outer_circ_y, inner_circ_y])],axis=1)print('after concat shape:', paddle.concat([outer_circ_x, inner_circ_x]).shape)print('X shape:', X.shape)# 使用'paddle. zeros'将第一类数据的标签全部设置为0# 使用'paddle. ones'将第一类数据的标签全部设置为1y = paddle.concat([paddle.zeros(shape=[n_samples_out]), paddle.ones(shape=[n_samples_in])])print('y shape:', y.shape)# 如果shuffle为True,将所有数据打乱if shuffle:# 使用'paddle.randperm'生成一个数值在0到X.shape[0],随机排列的一维Tensor做索引值,用于打乱数据idx = paddle.randperm(X.shape[0])X = X[idx]y = y[idx]# 如果noise不为None,则给特征值加入噪声if noise is not None:# 使用'paddle.normal'生成符合正态分布的随机Tensor作为噪声,并加到原始特征上X += paddle.normal(mean=0.0, std=noise, shape=X.shape)return X, y

使用简易网络实现二分类相关推荐

  1. 模拟数据集上训练神经网络,网络解决二分类问题练习

    #2018-06-24 395218 June Sunday the 25 week, the 175 day SZ ''' 模拟数据集上训练神经网络,网络解决二分类问题.'''import tens ...

  2. Qt开发——QWebEngineView简易网络浏览器(二)

    这个太简陋了,新写了一个:https://blog.csdn.net/qq_41895747/article/details/104225043 QNetwork做的简直太辣眼睛,延时还长! 换QWe ...

  3. 是否所有二分类神经网络的准确率都能无限趋近100%?

    制作一个二分类的神经网络验证是否只要经过足够的迭代都能使准确率无限上升并接近1. r1 r2     <1 <1 吸引子 c >1 >1 排斥子 p >1 <1 鞍 ...

  4. 带卷积核二分类网络的输出是不是有方向的?

    做一个二分类网络分类0,1, 让0向0,1收敛,让1向1,0收敛, 与让0向1,0收敛,让1向0,1收敛 这两种做法是不是一样的?如果不同表明网络的输出是区分方向的. 做一个网络输入minst的0和1 ...

  5. Lesson 8.38.4 二分类神经网络torch.nn.functional实现单层二分类网络的正向传播

    二.二分类神经网络:逻辑回归 1 二分类神经网络的理论基础 线性回归是统计学经典算法,它能够拟合出一条直线来描述变量之间的线性关系.但在实际中,变量之间的关系通常都不是一条直线,而是呈现出某种曲线关系 ...

  6. 【五一创作】使用Resnet残差网络对图像进行分类(猫十二分类,模型定义、训练、保存、预测)(二)

    使用Resnet残差网络对图像进行分类 (猫十二分类,模型定义.训练.保存.预测)(二) 目录 (6).数据集划分 (7).训练集增强 (8).装载数据集 (9).初始化模型 (10).模型训练 (1 ...

  7. 经典网络vgg应用于 图像二分类的训练代码

    1 目的:使用VGG16网络 进行对图片二分类  (不同插值方法的图片 纹理不同) vgg16 网络结构的连接 https://blog.csdn.net/weixin_44576543/articl ...

  8. 【五一创作】使用Resnet残差网络对图像进行分类(猫十二分类,模型定义、训练、保存、预测)(一)

    使用Resnet残差网络对图像进行分类 (猫十二分类,模型定义.训练.保存.预测)(一) 目录 一.项目简介 二.环境说明 1.安装库 2.导入需要的库 三.分类过程 (1).解压数据集 (2).相关 ...

  9. 猫狗二分类实战(PyTorch)

    PyTorch实战指南 文章目录 PyTorch实战指南 比赛介绍 文件组织架构 关于`__init__.py` 数据加载 模型定义 工具函数 配置文件 main.py 训练 验证 测试 帮助函数 使 ...

  10. 【神经网络】(7) 迁移学习(CNN-MobileNetV2),案例:乳腺癌二分类

    各位同学好,今天和大家分享一下Tensorflow2.0中如何使用迁移学习的方法构造神经网络.需要数据集的在评论区留个言. 1. 迁移学习 官方文档:Module: tf.keras.applicat ...

最新文章

  1. html 设置div占位符,HTML5+CSS3 一组文本输入框占位符动效
  2. raft论文 中文 pdf_八篇论文总结BERT+KG:预训练模型与知识图谱相结合的研究进展...
  3. 为什么说产品经理都该懂一点机器学习?
  4. elementUI的container布局设置全屏宽度
  5. 常用代码生成工具介绍
  6. ASP.NET 2.0中CSS失效的问题总结
  7. leetcode hot 1-2
  8. ZOJ Monthly, March 2018
  9. Java编程:排序算法
  10. JAVA面向对象编程---学生管理系统
  11. 通过淘宝司法拍卖购买房子,需要注意些什么?
  12. 笔记本插入耳机没反应 必须重启前插入再启动才行 启动后拔下再插入依旧外放
  13. Java虚拟机(JVM)学习合集
  14. 王者荣耀服务器维护多久结束,王者荣耀健康系统重置时间 时间限制规则详解...
  15. 【渝粤教育】电大中专电子商务网站建设与维护 (28)作业 题库
  16. 截取Chrome下载的mp3
  17. QSystemTrayIcon退出后系统托盘图标不消失问题
  18. Linux通过stty命令操作串口设备(linux串口操作命令)
  19. html5 语音导航,TeleNav提供基于HTML5技术的浏览器级turn-by-turn语音导航服务
  20. 病毒传播建模SEIR与网络传播

热门文章

  1. 你还在纠结智能开关?这款人体传感器,一起开启HomeKit新大门
  2. 花 6 小时,写了份 Toad For SQL 指南,助你乘风破浪
  3. 冠达管理:登记日和除息日的区别?
  4. python-openpyxl设置单元格填充颜色及字体颜色
  5. android svg 和png,使用svg图片和png图片的差别
  6. 量化投资学习-29:从历史中学习
  7. 自媒体文章可以多平台分发吗?
  8. 当智商高到一定程度,情商就不重要了——牛逼顿的一生
  9. 1161 Problem J 《C语言程序设计》江宝钏主编-习题3-9-利滚利
  10. 京东宣布进军二手市场;滴滴完成超40亿美元融资;Instagram营收今年将达41亿美元丨价值早报