815人工神经网络笔记

今天更新815第三节tutorial的内容。
本次tutorial主要包括:
1.回顾构建人工神经网络的步骤(本文不讲,自己复习)
2.使用Keras包构建人工神经网络的基本方法
3.以华氏度和摄氏度之间的关系为例,以有限的数据构建人工神经网络
4.比较不同宽度和深度的人工神经网络模型

首先是本次tutorial编程所需要的包:

# -*- coding: utf-8 -*-
"""
Created on Fri Feb 11 13:01:57 2022

@author: Pamplemousse
"""

import numpy as np
import pandas as pd
import seaborn as sns
from matplotlib import pyplot as plt
sns.set()
#add:
#get_ipython().run_line_magic('config', "InlineBackend.figure_format = 'retina'")
#if you are using pyCharm, as I'm using python, I didn't add it into my code.

# In[1]:

import keras
import keras.backend as kb #引入了但没有使用
import tensorflow as tf  #这个包是需要安装的,我之前安装时遇到过一些冲突问题
#然而我已经忘记具体情况了,如果有同学安装了仍有问题,可联系我
from keras import backend as K #引入了但没有使用
from keras.models import Sequential
from keras.layers import Dense

from sklearn.model_selection import train_test_split
#这是一个常用的分离训练集和测试集的工具

其中keras.backend的作用,我不了解,所以
我给大家偷了一个大佬的CSDN文章

如何使用keras来声明一个模型
第一个方法
为了简单这里考虑的是一个三层模型(原本的代码里也有描述,但是它的描述和它写的不太一样,就很迷惑)
第一层64个结点
第二层共32个结点
第三层共1个结点
个人认为前两个是隐藏层,第三个是输出层
这个模型的输入是1个变量,输出是1个变量

P.S. 关于结点和节点有什么差别,我经常分不清


# In[2]:

model = keras.Sequential([keras.layers.Dense(64,activation=tf.nn.relu, input_shape=[1]),
#这里input_shape是指上一层的输出,本层的输入,故该模型的输入是1个变量
                          keras.layers.Dense(32,activation=tf.nn.relu),
#这边就是说因为是在一个模型里,本层的输入自然是上一层的输出,所以不需要在特别注明input_shape,但是需要知道input大小是64个变量
                          keras.layers.Dense(1)])
                          

print(model.summary())

得到的结果如下
在这里插入图片描述
这个param是怎么算出来的呢
比如64个结点那层,输入是1,结点64,所以输出也是64,其中1个变量输入64个结点,需要64个权重,然后在64个结点上需要有64个系数用于调整内部计算的过程,64+64=128。请记住模型不一定是线性的,已经输入不一定大小是1,所以输入和结点内部都需要调参(这段请自行理解一下)
然后是32个结点那层,输入是64,输出32,对64个输入需要64*32=2048个参数,对于32个结点,需要32个参数,故这一层需要2048+32=2080个参数。
以此类推,后面不再解释了。

刚刚我们看到的是三层一起声明的方式,那么第二种方式就是分开声明的方式


# In[3]:

model = Sequential()
model.add(Dense(64, input_dim = 1, activation='relu'))
model.add(Dense(32, activation = 'relu'))
model.add(Dense(1))

print(model.summary())

我们得到的结果如下
在这里插入图片描述
大家注意这个模型叫“sequential_2”啊,我没有用同一张图忽悠大家啊。虽然这个model还是刚刚的那个model,但是它是重新声明了一次的新模型。(不重要)

在定义好结构后,下一步就应该决定
1.optimizer
关于优化器,给大家偷了一片CSDN文章
2.损失函数
3.拟合优度的矩阵

# In[4]:


opt = tf.keras.optimizers.Adam(learning_rate=0.001)
model.compile(optimizer="Adam",loss="mse",metrics=["mse"])

因为没有重新定义model,所以现在这个model还是刚刚的sequential_2,这里为该模型设定学习率为0.001,优化器为ADAM方式,想要明白ADAM的可以参考上面的链接,不过不重要,不需要明白。损失函数使用Mean Squared Error,拟合优度也使用均方差表示。

随后是华氏度和摄氏度的关系

# In[5]:

#首先是自己伪造一些数据,请记住这些数据长度应当相同,且一一对应
Fahrenheit = np.array([-140,-136,-124,-112,-105,-96,-88,-75,-63,-60,-58,-40,-20,-10,0,30,35,48,55,69,81,89,95,99,105,110,120,135,145,158,160],dtype=float)
Celsius = np.array([-95.55,-93.33,-86.66,-80,-76.11,-71.11,-66.66,-59.44,-52.77,-51.11,-50,-40,-28.88,-23.33,-17.77,-1.11,1.66,8.88,12,20,27.22,31.66,35,37.22,40.55,43.33,48.88,57.22,62.77,70,71.11], dtype=float)

# In[6]:

plt.plot(Fahrenheit)
plt.plot(Celsius)
plt.legend(['FH','Cel'])
plt.show()

得到华氏度和摄氏度的图像为:
在这里插入图片描述

训练模型,然后以华氏度200来测试摄氏度的输出

# In[9]:

model.fit(Fahrenheit,Celsius,epochs=1000,verbose=0);
#拟合模型,以华氏度为输入,摄氏度为输出拟合model,这个model就是刚刚的sequential_2
# In[10]:

model.predict([200])

得道如下输出:
Out[7]: array([[81.97642]], dtype=float32)
即模型给出的华氏度200对应的摄氏度大约为82。(但实际是大约93
你们不一定得到这个输出,也有可能很贴近
这我没办法解释啊,差太多了,一个原因是epochs,就是重复训练的次数太少;另一个原因是数据太少了。于是我把epochs改成10000,咱多跑10倍吧,然后得到了91.137375,挺好,相当接近了。(就是有点费时费力
其实这种线性的关系用线性模型来拟合就很好了
在这里插入图片描述

然后我们终于发现用非线性模型来处理线性问题不对劲了,于是我们构造一些非线性的数据


# In[11]:

X=np.random.randn(200,1)
#这是一个长度为200的随机单变量,符合正态分布
epsilon=np.random.randn(200,1)
#这也是一个正态分布的变量,看起来是用作随机扰动项的。
Y=np.square(X)+epsilon
#构建一个Y,使得Y=X²+随机扰动项

X_train,X_test,y_train,y_test=train_test_split(X,Y,test_size=0.5)
#使用sklearn的训练集测试集分离器将数据随机分为训练集和测试集比例为1:1
#这个也可以手动做,思维就是,比如我们把测试集的大小定为0.3
#因为我们有200个数,所以要进行200次循环
#对第i个x和y,生成一个0到1的随机数,如果这个随机数大于0.3就将这对x和y划分到训练集,否则划分到测试集

#请注意train_test_split的输出就是(用于训练的自变量,用于测试的自变量,用于训练的因变量,用于测试的因变量)
#所以设计好变量名,不要搞错。

这里插播一句,一般来说我们使用的训练集不可小于测试集,通常我们会选择训练集比测试集7:3这样的比例。

然后定义一个非线性的人工神经网络

# In[12]:


model_nonlinear=keras.Sequential([
    keras.layers.Dense(64,activation=tf.nn.relu,input_shape=[X.shape[1]]),
    keras.layers.Dense(64,activation=tf.nn.relu),
    keras.layers.Dense(1)])
#X.shape->(200,1),X.shape[1]->1

print(model_nonlinear.summary())

model_nonlinear.compile(loss="mse",optimizer="Adam",metrics=["mse"])

得到如下的模型:
在这里插入图片描述
这里不再对模型多做解释。

随后,为了对比,生成一个线性的人工神经网络

# In[13]:

model_linear=keras.Sequential([
    keras.layers.Dense(64,activation=tf.keras.activations.linear,input_shape=[X.shape[1]]),
    keras.layers.Dense(64,activation=tf.keras.activations.linear),
    keras.layers.Dense(1)])


print(model_linear.summary())

model_linear.compile(loss="mse",optimizer="Adam",metrics=["mse"])

在这里插入图片描述
使用训练集分别拟合线性和非线性两个模型,然后使用测试集进行测试。

# In[14]:

history=model_linear.fit(X_train,y_train,validation_data=(X_test,y_test),epochs=1000,verbose=0)
#这是线性模型,使用训练集拟合,使用测试集校验

# In[15]:
history2=model_nonlinear.fit(X_train,y_train,validation_data=(X_test,y_test),epochs=1000,verbose=0)
#这是非线性模型

# In[16]:

plt.plot(history.history['loss'],label="Training loss")
#训练后的模型在训练集上的损失
plt.plot(history.history['val_loss'],label="Validation loss")
#训练后的模型在测试集上的损失
plt.title('Val/Test loss for Example')
plt.xlabel('No. epoch')
#学习的次数
plt.legend(loc="upper left")
#自动加上图例
plt.show()

# In[17]:
#我就不明白干嘛要画两张一样的图,而且前面那张图它要写MAE,
#明明他损失函数用的MSE,哪来的MAE,如果要MAE,请在model compile的时候将loss="mse"改为loss="mae"
plt.plot(history.history['mse'],label='Mse (testing data)')
plt.plot(history.history['val_mse'],label='MSE (validation data)')
plt.title('MSE for example')
plt.ylabel('MSE value')
plt.xlabel('No. epoch')
plt.legend(loc="upper left")
plt.show()

# In[18]:
#下面两幅图是非线性模型的
plt.plot(history2.history['loss'],label="Training loss")
plt.plot(history2.history['val_loss'],label="Validation loss")
plt.title('Val/Test loss for Example')
plt.xlabel('No. epoch')
plt.legend(loc="upper left")
plt.show()

# In[19]:

plt.plot(history2.history['mse'],label='Mse (testing data)')
plt.plot(history2.history['val_mse'],label='MSE (validation data)')
plt.title('MSE for example')
plt.ylabel('MSE value')
plt.xlabel('No. epoch')
plt.legend(loc="upper left")
plt.show()

这里只放两张图,第一张是线性模型,第二张是非线性模型
在这里插入图片描述
这是线性模型的结果,可以看到无论是样本内还是样本外结果都不好,而且样本内结果远优于样本外结果,我们拟合模型的目的是希望样本外结果尽量和样本内的结果一样好,这样预测的结果才能更加具有可信度。

在这里插入图片描述
这是非线性模型的结果,可以看到随着迭代次数的增加,损失逐渐减小,且样本内外的结果差别不大,但是很神奇的一点是样本外的结果居然要比样本内要好???很难解释,我不理解。

然后全样本进行一个预测

g_hat_nl=model_nonlinear.predict(X)
#这是非线性模型的预测结果
g_hat_l=model_linear.predict(X)
#这是线性模型的预测结果

# In[21]:

plt.plot(g_hat_nl)
#第一条线非线性模型的预测结果
plt.plot(Y)
#第二条线应该是Y,不知道为什么他要用X方
plt.plot(g_hat_l)
#第三条线线性模型的预测结果
plt.legend(['estimate','real','linear'],loc="upper left")
#添加图例,第一条线改名为estimate,第二条线改名为real,第三条线改名为linear,图例画在左上方
plt.title('Non-linear model')#加标题
plt.show()

在这里插入图片描述

可以看到estimate,就是非线性模型和real更加地贴近。

然后我们继续探索人工神经网络
首先我们构建一个比较浅的人工神经网络,第一层的神经元数量是可以修改的
(其实是告诉大家可以把这个num换一下,看看不一样的神经元有什么区别)

num=50
model_nonlinear=keras.Sequential([
    keras.layers.Dense(num,activation=tf.nn.relu,input_shape=[X.shape[1]]),
    keras.layers.Dense(1)])
print(model_nonlinear.summary())

model_nonlinear.compile(loss='mse',optimizer='Adam',metrics=['mse'])

history2=model_nonlinear.fit(X_train,y_train,validation_data=(X_test,y_test),epochs=1000,verbose=0)
#拟合模型,history2已经是我们新模型的结果了

这个模型是这样的
在这里插入图片描述

然后我们看看这个模型的拟合优度

# In[23]:

plt.plot(history2.history['loss'],label="Training loss")
plt.plot(history2.history['val_loss'],label="Validation loss")
plt.title('Val/Test loss for Example')
plt.xlabel('No. epoch')
plt.legend(loc="upper left")
plt.show()

在这里插入图片描述

其实迭代次数多了以后,效果还不错

下面是相似的对比操作

# In[24]:

g_hat_nl=model_nonlinear.predict(X)
#浅-非线性模型
g_hat_l=model_linear.predict(X)
#线性模型

# In[25]:

plt.plot(g_hat_nl)
plt.plot(Y)
plt.plot(g_hat_l)
plt.legend(['estimate','real','linear'],loc="upper left")
plt.title('Non-linear model')
plt.show()

感觉这里新的非线性模型应该新定义一个模型,然后不是和非线性模型比较,而是和刚刚的旧的非线性模型比较,这样可以比较明显地看出差异,但是我懒得改了
在这里插入图片描述

可以看出这个浅的非线性模型比线性模型好

于是我们想弄一个深的非线性模型

model_nonlinear_deep=keras.Sequential([
    keras.layers.Dense(64,activation=tf.nn.relu,input_shape=[X.shape[1]]),
    keras.layers.Dense(64,activation=tf.nn.relu),
    keras.layers.Dense(64,activation=tf.nn.relu),
    keras.layers.Dense(64,activation=tf.nn.relu),
    keras.layers.Dense(1)])

print(model_nonlinear_deep.summary())

model_nonlinear_deep.compile(loss='mse',optimizer='Adam',metrics=['mse'])

这个模型真的超~复杂哒
在这里插入图片描述
然后是看看这个模型的均方差

# In[27]:

history2=model_nonlinear_deep.fit(X_train,y_train,validation_data=(X_test,y_test),epochs=1000,verbose=0)
#拟合、校验
#别的小朋友都回溯1000次,这里
# In[28]:

plt.plot(history2.history['loss'],label="Training loss")
plt.plot(history2.history['val_loss'],label="Validation loss")
plt.title('Val/Test loss for Example')
plt.xlabel('No. epoch')
plt.legend(loc="upper left")
plt.show()

在这里插入图片描述
看起来也不错,嗯,但是到后面不太平稳,就是起伏很大的样子,可能有些问题在的

然后我们比较一下深浅非线性模型的结果


# In[29]:

ghat_nl=model_nonlinear_deep.predict(X)
#深非线性模型
ghat=model_nonlinear.predict(X)
浅非线性模型

plt.plot(ghat_nl)
#深
plt.plot(Y)
plt.plot(ghat)
#浅
plt.legend(['deep','real','nonlinear'],loc="upper left")
plt.title('Non-linear model')
plt.show()

在这里插入图片描述
就看到,什么也看不出来,这边建议画两个图,都是先画Y然后两个图分别画深和浅,这样可以对比深和浅对实际数据的贴合度

后面这段咱其实没看懂他想干嘛,但是咱们还是来看看

from keras import regularizers as regularizers
#正则化的工具,关于正则化,在后面给大家找了个链接
# In[31]:

model_nonlinear_deep_l1=keras.Sequential([
    keras.layers.Dense(64,activation=tf.nn.relu,kernel_regularizer=regularizers.l1(1e-4),input_shape=[X.shape[1]]),
    #出现了新的参数kernel_regularizer,关于这个在后面也偷了个链接
    keras.layers.Dense(64,activation=tf.nn.relu),
    keras.layers.Dense(64,activation=tf.nn.relu),
    keras.layers.Dense(64,activation=tf.nn.relu),
    keras.layers.Dense(1)])

print(model_nonlinear_deep_l1.summary())

# In[32]:

model_nonlinear_deep_l1.compile(loss='mse',optimizer='Adam',metrics=['mse'])


history2=model_nonlinear_deep_l1.fit(X_train,y_train,validation_data=(X_test,y_test),epochs=1000,verbose=0)

# In[33]:
#看看MSE
plt.plot(history2.history['loss'],label="Training loss")
plt.plot(history2.history['val_loss'],label="Validation loss")
plt.title('Val/Test loss for Example')
plt.xlabel('No. epoch')
plt.legend(loc="upper left")
plt.show()

# In[34]:

#对比新的深层模型和之前的浅层模型
ghat_nl=model_nonlinear_deep_l1.predict(X)
ghat=model_nonlinear.predict(X)

plt.plot(ghat_nl)
plt.plot(Y)
plt.plot(ghat)
plt.legend(['deep','real','nonlinear'],loc="upper left")
plt.title('Non-linear model')
plt.show()

偷了一个关于正则化的博客

偷了一个关于kernel_regularizer的CSDN文章
下面贴上最后这段代码的结果
在这里插入图片描述
在这里插入图片描述

跟之前的就的深层非线性模型有什么区别?可能是这个波动更大?不理解
在这里插入图片描述

还是啥都看不出来。。。可能是想说深层没有那么好?

主要是老师的代码从很早就出现问题了,搞后面这一堆明显没必要,他的结果也不能说明什么问题,可能是想说太深的模型对简单的数据来说结果反而不好,实际上这里也不怎么看得出来,我甚至不知道为什么他的结果那么奇怪。
然后简单说一下最后这一段,这一段是想限制第一层系数的大小……
算了,我无力吐槽了,累了,我完全不懂这节tutorial的意义了。

我宣布,下班!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

端午节放纸鸢

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值