感知机——鸢尾花 包含代码

感知机

1 人工智能三学派
 我们常说的人工智能,就是让机器具备人的思维和意识。人工智能主要有三个学派,即行为主义、符号主义和连接主义。
  行为主义:是基于控制论的,是在构建感知、动作的控制系统。单脚站立是行为主义一个典型例子,通过感知要摔倒的方向,控制两只手的动作,保持身体的平衡。这就构建了一个感知、动作的控制系统,是典型的行为主义。
   符号主义:基于算数逻辑表达式。即在求解问题时,先把问题描述为表达式,再求解表达式。例如在求解某个问题时,利用 if case 等条件语句和若干计算公式描述出来,即使用了符号主义的方法,如专家系统。符号主义是能用公式描述的人工智能,它让计算机具备了理性思维。
  连接主义:仿造人脑内的神经元连接关系,使人类不仅具备理性思维,还具备无法用公式描述的感性思维,如对某些知识产生记忆。
图 1.1 展示了人脑中的一根神经元,其中紫色部分为树突,其作为神经元的输入。黄色部分为轴突,其作为神经元的输出。人脑就是由 860 亿个这样的神经元首尾相接组成的网络。
在这里插入图片描述

                                      *图 1.1 神经元示意图* 

  基于连接主义的神经网络模仿上图的神经元,使计算机具有感性思维。
在这里插入图片描述

                        *图 1.2 人脑神经网络变化示意图*

 随着我们的成长,大量的数据通过视觉、听觉涌入大脑,使我们的神经网络
 连接,也就是这些神经元连接线上的权重发生了变化,有些线上的权重增强了, 有些线上的权重减弱了。如图 1.3 所示。

在这里插入图片描述

                      *图 1.3 神经网络权重变化示意图* 

2 神经网络设计过程
   我们要用计算机模仿刚刚说到的神经网络连接关系,让计算机具备感性思维。
  首先,需要准备数据,数据量越大越好,要构成特征和标签对。如要识别猫, 就要有大量猫的图片和这个图片是猫的标签,构成特征标签对。 随后,搭建神经网络的网络结构,并通过反向传播,优化连线的权重,直到 模型的识别准确率达到要求,得到最优的连线权重,把这个模型保存起来。
  最后,用保存的模型,输入从未见过的新数据,它会通过前向传播,输出概 率值,概率值最大的一个,就是分类或预测的结果。图 2.1 展示了搭建与使用神 经网络模型的流程。
在这里插入图片描述

                 *图 2.1 搭建与使用神经网络示意图2.1 数据集介绍* 

  采用鸢尾花数据集,此数据集包含鸢尾花花萼长、花萼宽、花瓣长、 花瓣宽及对应的类别。其中前 4 个属性作为输入特征,类别作为标签,0 代表狗尾草鸢尾,1 代表杂色鸢尾,2 代表弗吉尼亚鸢尾。人们通过对数据进行分析总结出了规律:通过测量花的花萼长、花萼宽、花瓣长、花瓣宽,可以得出鸢尾花的类别(如:花萼长>花萼宽且花瓣长/花瓣宽>2,则杂色鸢尾)。
  由上述可知,这边采用搭建神经网络的办法对其进行分类,即将鸢尾花花萼长、花萼宽、花瓣长、花瓣宽四个输入属性喂入搭建好的神经网络,网络优化参数得到模型,输出分类结果。
2.2 网络搭建与训练
  搭建包含输入层与输出层的神经网络模型,通过对输入值乘权值,并于偏置值求和的方式得到输出值,图示如下。
在这里插入图片描述

                    *图 2.2 鸢尾花神经网络简要模型* 

   由图 2.2 可知输出 y = x ∗w+ b ,即所有的输入 x 乘以各自线上的权重 w 求和加上偏置项b得到输出y 。由 2.1部分对数据集的介绍可知,输入特征 x 形状应为(1,4)即 1 行 4 列,输出 y 形状应为(1,3)即 1 行 3 列,w 形状应为(4,3)即 4 行 3 列,b 形状应为(3, )即有 3 个偏置项。
   搭建好基本网络后,需要输入特征数据,并对线上权重 w 与偏置b 进行初始化。搭建的神经网络如图 2.3 所示, w,b 初始化矩阵如图 2.4 所示。在这里,我们输入标签为 0 的狗尾草鸢尾。
在这里插入图片描述

                                     *图 2.3 鸢尾花神经网络展开模型* 

在这里插入图片描述

                        *图 2.4 权重与偏置初始化矩阵* 

  有了输入数据与线上权重等数据,即可按照 y = x ∗ w + b 方式进行前向传播, 计算过程如图 2.5 所示。

在这里插入图片描述

                          *图 2.5 前向传播计算过程* 

   图 2.5 中输出 y 中,1.01 代表 0 类鸢尾得分,2.01 代表 1 类鸢尾得分,0.66 代表2 类鸢尾得分。通过输出 y 可以看出数值最大(可能性最高)的是 1 类鸢尾,而不是标签0类鸢尾。这是由于最初的参数 w 和b 是随机产生的,现在输出的结果是蒙的。 为了修正这一结果,我们用损失函数,定义预测值 y 和标准答案(标签) _ y 的 差距,损失函数可以定量的判断当前这组参数 w 和b 的优劣,当损失函数最小 时,即可得到最优w的值和b的值。
   损失函数的定义有多种方法,均方误差就是一种常用的损失函数,它计算每个前向传播输出 y 和标准答案 _ y的差求平方再求和再除以 n 求平均值,表征了
网络前向传播推理结果和标准答案之间的差距。
   通过上述对损失函数的介绍,其目的是寻找一组参数 w 和b 使得损失函数最小。为达成这一目的,我们采用梯度下降的方法。损失函数的梯度表示损失函数 对各参数求偏导后的向量,损失函数梯度下降的方向,就是是损失函数减小的方向。梯度下降法即沿着损失函数梯度下降的方向,寻找损失函数的最小值,从而得到最优的参数。梯度下降法涉及的公式如下
           wt+1 = wt −lr∂loss/∂wt
           bt+1 = bt −lr
∂loss/∂bt
           wt+1x+bt+1 → y
  上式中,lr 表示学习率,是一个超参数,表征梯度下降的速度。如学习率设置 过小,参数更新会很慢,如果学习率设置过大,参数更新可能会跳过最小值。
  上述梯度下降更新的过程为反向传播,下面通过例子感受反向传播。利用如 下公式对参数 w 进行更新。
              wt+1 = wt −lr
∂loss/∂wt
  设损失函数为(w+1)2,则其对w的偏导数为2w+2。设w在初始化时被随机初始化为 5,学习率设置为 0.2。则我们可按上述公式对w进行更新:第一次参数为 5,按上式计算即5−0.2×(2×5+ 2) =2.6。同理第二次计算得到参数为 1.16,第三次计算得到参数为 0.296…… 画出损失函数(w+1)2的图像,可知w =-1时损失函数最小,我们反向传播优化参数的目的即为找到这个使损失函数最小的w =-1值。
3.添加独热码标签
  可用 tf.one_hot(待转换数据,depth=几分类)函数实现用独热码表示标签,在分类问题中很常见。标记类别为为 1 和 0,其中 1 表示是,0 表示非。如在鸢尾花分类任务中,如果标签是 1,表示分类结果是 1 杂色鸢尾,其用把它用独热码表示就是 0,1,0,这样可以表示出每个分类的概率:也就是百分之 0 的可能是 0 狗尾草鸢尾,百分百的可能是 1 杂色鸢尾,百分之 0 的可能是弗吉尼亚鸢尾。举例如下:

classes = 3 labels = tf.constant([1,0,2])   output = tf.one_hot( labels, depth=classes ) print(output)

  输出结果:tf.Tensor([[0. 1. 0.] [1. 0. 0.] [0. 0. 1.]], shape=(3, 3), dtype=float32)

  索引从 0 开始,待转换数据中各元素值应小于 depth,若带转换元素值大于等于depth,则该元素输出编码为 [0, 0 … 0, 0]。即 depth 确定列数,待转换元素的个数确定行数。举例如下:

classes = 3 
labels = tf.constant([1,4,2])       # 输入的元素值 4 超出 depth-1 
output = tf.one_hot(labels,depth=classes) print(output) 

输出结果:
  tf.Tensor([[0. 1. 0.] [0. 0. 0.] [0. 0. 1.]], shape=(3, 3), dtype=float32) 即元素 4 对应的输出编码为[0. 0. 0.]。

3.2  可利用 tf.nn.softmax( )函数使前向传播的输出值符合概率分布,进而与独热码形式的标签作比较,其计算公式为 :
在这里插入图片描述

其中yi 是前向传播的输出。在前一部分,我们得到了前向传播的输出值,分别为 1.01、2.01、-0.66,通过上述计算公式,可计算对应的概率值:
在这里插入图片描述

上式中,0.256表示为0类鸢尾的概率是 25.6%,0.695 表示为1类鸢尾的概率是
69.5%,0.048 表示为2类鸢尾的概率是4.8%程序实现如下:

y=tf.constant([1.01, 2.01, -0.66])
y_pro=tf.nn.softmax(y) print("After softmax, y_pro is:", y_pro) 

输出结果:After softmax, y_pro is:
    tf.Tensor([0.25598174 0.69583046 0.0481878], shape=(3,), dtype=float32)
与上述计算结果相同。

4总结

  1. 准备数据:采集大量“特征标签”数据
  2. 搭建网络:搭建神经网络结构
  3. 优化参数:训练网络获取最佳参数(反传)
  4. 应用网络:将网络保存为模型,输入新数据输出分类或预测结果(前传)

源码1:(源码二,是20行解决这个问题)

# 利用鸢尾花数据集,实现前向传播、反向传播,可视化loss曲线

# 导入所需模块
import tensorflow as tf
from sklearn import datasets  #导入数据集
from matplotlib import pyplot as plt
import numpy as np    #数组
import  time
# 导入数据,分别为输入特征和标签
x_data = datasets.load_iris().data
y_data = datasets.load_iris().target

# 随机打乱数据(因为原始数据是顺序的,顺序不打乱会影响准确率)
# seed: 随机数种子,是一个整数,当设置之后,每次生成的随机数都一样
np.random.seed(116)  # 使用相同的seed,保证输入特征和标签一一对应
np.random.shuffle(x_data)
np.random.seed(116)
np.random.shuffle(y_data)
tf.random.set_seed(116)

# 将打乱后的数据集分割为训练集和测试集,训练集为前120行,测试集为后30行
x_train = x_data[:-30]
y_train = y_data[:-30]
x_test = x_data[-30:]
y_test = y_data[-30:]

# 转换x的数据类型,否则后面矩阵相乘时会因数据类型不一致报错
x_train = tf.cast(x_train, tf.float32)
x_test = tf.cast(x_test, tf.float32)

# from_tensor_slices函数使输入特征和标签值一一对应。(把数据集分批次,每个批次batch组数据)
train_db = tf.data.Dataset.from_tensor_slices((x_train, y_train)).batch(32)  #分批次喂入
test_db = tf.data.Dataset.from_tensor_slices((x_test, y_test)).batch(32)

# 生成神经网络的参数,4个输入特征故,输入层为4个输入节点;因为3分类,故输出层为3个神经元
# 用tf.Variable()标记参数可训练
w1 = tf.Variable(tf.random.truncated_normal([4, 3], stddev=0.1, seed=1))
b1 = tf.Variable(tf.random.truncated_normal([3], stddev=0.1, seed=1))#(标准差,随机参数)

lr = 0.1 # 学习率
train_loss_results = []  # 将每轮的loss记录在此列表中,为后续画loss曲线提供数据
test_acc = []  # 将每轮的acc记录在此列表中,为后续画acc曲线提供数据
epoch = 500  # 循环500轮
loss_all = 0  # 每轮分4个step,loss_all记录四个step生成的4个loss的和

# 训练部分
now_time = time.time()  ##2##

for epoch in range(epoch):  #数据集级别的循环,每个epoch循环一次数据集
    for step, (x_train, y_train) in enumerate(train_db):  #batch级别的循环 ,每个step循环一个batch
        with tf.GradientTape() as tape:  # with结构记录梯度信息
            y = tf.matmul(x_train, w1) + b1  # 神经网络乘加运算
            y = tf.nn.softmax(y)  # 使输出y符合概率分布(此操作后与独热码同量级,可相减求loss)
            y_ = tf.one_hot(y_train, depth=3)  # 将标签值转换为独热码格式,方便计算loss和accuracy
            loss = tf.reduce_mean(tf.square(y_ - y))  # 采用均方误差损失函数mse = mean(sum(y-out)^2)
            loss_all += loss.numpy()  # 将每个step计算出的loss累加,为后续求loss平均值提供数据,这样计算的loss更准确
        # 计算loss对各个参数的梯度
        grads = tape.gradient(loss, [w1, b1])

        # 实现梯度更新 w1 = w1 - lr * w1_grad    b = b - lr * b_grad
        w1.assign_sub(lr * grads[0])  # 参数w1自更新
        b1.assign_sub(lr * grads[1])  # 参数b自更新

    # 每个epoch,打印loss信息
    print("Epoch {}, loss: {}".format(epoch, loss_all/4))
    train_loss_results.append(loss_all / 4)  # 将4个step的loss求平均记录在此变量中
    loss_all = 0  # loss_all归零,为记录下一个epoch的loss做准备

    # 测试部分
    # total_correct为预测对的样本个数, total_number为测试的总样本数,将这两个变量都初始化为0
    total_correct, total_number = 0, 0
    for x_test, y_test in test_db:
        # 使用更新后的参数进行预测
        y = tf.matmul(x_test, w1) + b1
        y = tf.nn.softmax(y)
        pred = tf.argmax(y, axis=1)  # 返回y中最大值的索引,即预测的分类
        # 将pred转换为y_test的数据类型
        pred = tf.cast(pred, dtype=y_test.dtype)
        # 若分类正确,则correct=1,否则为0,将bool型的结果转换为int型
        correct = tf.cast(tf.equal(pred, y_test), dtype=tf.int32)
        # 将每个batch的correct数加起来
        correct = tf.reduce_sum(correct)
        # 将所有batch中的correct数加起来
        total_correct += int(correct)
        # total_number为测试的总样本数,也就是x_test的行数,shape[0]返回变量的行数
        total_number += x_test.shape[0]
    # 总的准确率等于total_correct/total_number
    acc = total_correct / total_number
    test_acc.append(acc)
    print("Test_acc:", acc)
    print("--------------------------")
total_time = time.time() - now_time  ##3##
print("total_time", total_time)  ##4##

# 绘制 loss 曲线
plt.title('Loss Function Curve')  # 图片标题
plt.xlabel('Epoch')  # x轴变量名称
plt.ylabel('Loss')  # y轴变量名称
plt.plot(train_loss_results, label="$Loss$")  # 逐点画出trian_loss_results值并连线,连线图标是Loss
plt.legend()  # 画出曲线图标
plt.show()  # 画出图像

# 绘制 Accuracy 曲线
plt.title('Acc Curve')  # 图片标题
plt.xlabel('Epoch')  # x轴变量名称
plt.ylabel('Acc')  # y轴变量名称
plt.plot(test_acc, label="$Accuracy$")  # 逐点画出test_acc值并连线,连线图标是Accuracy
plt.legend()
plt.show()

源码2:(实现效果同上)

import tensorflow as tf
from tensorflow.keras.layers import Dense
from tensorflow.keras import Model
from sklearn import datasets
import numpy as np

x_train = datasets.load_iris().data
y_train = datasets.load_iris().target

np.random.seed(116)
np.random.shuffle(x_train)
np.random.seed(116)
np.random.shuffle(y_train)
tf.random.set_seed(116)

class IrisModel(Model):
    def __init__(self):
        super(IrisModel, self).__init__()
        self.d1 = Dense(3, activation='softmax', kernel_regularizer=tf.keras.regularizers.l2())

    def call(self, x):
        y = self.d1(x)
        return y

model = IrisModel()

model.compile(optimizer=tf.keras.optimizers.SGD(lr=0.1),
              loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=False),
              metrics=['sparse_categorical_accuracy'])

model.fit(x_train, y_train, batch_size=32, epochs=500, validation_split=0.2, validation_freq=20)
model.summary()


  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

锦鲤AI幸运

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

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

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

打赏作者

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

抵扣说明:

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

余额充值