人工智能的主流:连接主义。
人工智能的三个学派:
1、行为主义:基于控制论,由感知到控制。
2、符号主义:基于表达式,先描述表达式,再求解表达式,是一种用公式描述的人工智能。
3、连接主义:仿生学,神经网络的感性控制。
搭建一个完整的神经网络,往往需要以下几个步骤:
1、准备数据:特征和标签对(数据集)
2、搭建网络:确定神经网络的结构
3、优化参数:(利用反向传播)获取最佳参数
4、应用网络:保存训练模型,应用(前向传播)
神经网络的表达式:y=w*x+b y表示期望,w表示权重,b表示偏置,在最初的设计中,w和b都是随机设置的。
损失函数:预测期望值与实际值的差距,根据损失函数去判断参数w、b优化的好坏,是否还需要继续优化。常见的是均方误差(MSE),目的就是找到使损失函数最小的w和b。
梯度:损失函数对各参数求偏导后的向量,梯度下降的方向即损失函数变小的方向,沿着梯度的下降方向寻找损失函数的最小值。
迭代函数:wt=wt-lr*(loss对w的偏导) wt表示参数,lr表示迭代速率
Tensor:张量,多维数组
拥有的数据类型:int、float(32,64)、bool、string
创建张量tensor:tf.constant(张量内容,形状,dtype=数据类型)
张量内容如果是一个数值,那么在张量内部都会填充为该数值。
tf.constant([1 5], shape=(2,), dtype=int64) 表示是一个两行,第一行为1第二行为5的整型张量。
对于numpy格式的数据,要用tf.convert_to_tensor(a,dtype=)转变为tensor。
创建全为0的张量:tf.zeros(维度)
创建全为1的张量:tf.ones(维度)
创建全为指定值的张量:tf.fill(维度,指定值)
生成正态分布的随机数,默认均值为0,标准差为1 tf.random.normal(维度,mean=均值,stddev=标准差)
生成截断式正态分布的随机数 tf.random.truncated_normal(维度,mean=均值,stddev=标准差)
生成均匀分布随机数 tf.random.uniform(维度,minval=最小值,maxval=最大值) 最小最大为前闭后开区间
常见函数:
强制转换类型函数:tf.cast(A张量名,dtype=数据类型) 表明要将张量A转变为dtype后的数据类型
计算张量维度元素上的最小值:tf.reduce_min(张量A)
计算张量维度元素上的最大值:tf.reduce_max(张量A)
axis:指定axis等于0或1,来控制被执行的行与列。
axis=0,表示沿着行垂直往下(列);axis=1,表示沿着列水平向右(行),如果不指定axis,则所有元素都参与计算。
tf.varuable(初始值):
将变量标记为“可训练”,被标记的变量会在反向传播中记录梯度信息。神经网络训练汇总,常用该函数标记带训练参数。
四则运算:
tf.add/subtract/multiply/divide(张量1,张量2),分别表示+-*/,只有相同维度的张量才可以进行四则运算。
平方:tf.square(张量)
次方:tf.pow(张量)
开方:tf.sqrt(张量)
矩阵乘:tf.matmul(a,b) a,b必须符合矩阵的运算要求
# -*- coding: UTF-8 -*-
# UTF-8编码解码器,使计算机能正确识别中文
# 利用鸢尾花数据集,实现前向传播、反向传播,可视化loss曲线
# 导入所需模块
import tensorflow as tf #引入tensorflow包,并重命名为tf,后续的tf即表示tensorflow(用于神经网络搭建)
from sklearn import datasets #从sklearn包下载datasets数据集
from matplotlib import pyplot as plt #从matplotlib包引入pyplot函数,并重命名为plt(用于记录数据绘图输出图形)
import numpy as np #引入numpy包重命名为np(用于数值计算和数据扩展)
#一、准备数据
# ①数据集读入
# 导入数据,分别为输入特征和标签
x_data = datasets.load_iris().data #表示从datasets加载iris的特征数据
y_data = datasets.load_iris().target #表示从datasets加载iris的标签
#②数据集乱序
# 随机打乱数据(因为原始数据是顺序的,顺序不打乱会影响准确率)
# seed: 随机数种子,是一个整数,当设置之后,每次生成的随机数都一样
# shuffle用来吧一个列表中的元素顺序随机打乱
np.random.seed(116) # 使用相同的seed,保证输入特征和标签一一对应,先设置随机数,再执行乱序的shuffle操作
np.random.shuffle(x_data)
np.random.seed(116) #设置操作级别的种子数
np.random.shuffle(y_data)
# 此时x与y被打乱,但二者的特征和标签仍旧一一对应
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)
# 将训练组的x与y对应起来,后边加.batch表示将该数据组按照每32个一组组成一个batch
test_db = tf.data.Dataset.from_tensor_slices((x_test, y_test)).batch(32)
# 将测试组的x与y对应起来
# 二搭建神经网络
# 生成神经网络的参数,4个输入特征(鸢尾花有四个特征测量数据),输入层为4个输入节点;因为3分类,故输出层为3个神经元
# 用tf.Variable()标记参数可训练
# 使用seed使每次生成的随机数相同(方便教学,使大家结果都一致,在现实使用时不写seed)
w1 = tf.Variable(tf.random.truncated_normal([4, 3], stddev=0.1, seed=1))
#标记w1是可训练参数,然后随机生成一个截取正态范围内的一部分作为随机数生成的区间(表示生成了一个四行三列,标准差为0.1,随机种子为1的矩阵)
b1 = tf.Variable(tf.random.truncated_normal([3], stddev=0.1, seed=1))
# b1作为偏置项,衡量的是一个神经元激活的难易程度,越大越难以被激活,通过对b的优化,使各个神经元达到最合适的激活状态
lr = 0.1 # 学习率为0.1,即沿着梯度下降方向的步长
train_loss_results = [] # 定义了一个列表(()为元组不可变,[]为列表可变,{}为字典),将每轮的loss记录在此列表中,为后续画loss曲线提供数据
test_acc = [] # 定义了一个列表,将每轮的acc记录在此列表中,为后续画acc曲线提供数据
epoch = 500 # 循环500轮
loss_all = 0 # 每轮分4个step,loss_all记录四个step生成的4个loss的和
# 训练部分
# 120个数据分为每32个数据一组,进行训练。训练500epoch(轮)
for epoch in range(epoch): #for循环进行迭代训练(for往往针对的是次数已知的循环,while针对的是次数未知的),数据集级别的循环,每个epoch循环一次数据集
for step, (x_train, y_train) in enumerate(train_db): #batch级别的循环 ,每个step循环一个batch
# enumerate函数用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标,一般用在 for 循环当中
with tf.GradientTape() as tape: # with,上下文管理器,该结构记录梯度信息
y = tf.matmul(x_train, w1) + b1 # 神经网络矩阵乘法与加法运算,完成y=w*x+b的运算
y = tf.nn.softmax(y) # 使输出y(预测值)符合概率分布(此操作后与独热码同量级,可相减求loss)
# softmax层的输入是全连接,输出是0-1之间的一个概率值,取最大的为输出结果
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])
# gradient函数,求梯度
# 实现梯度更新 w1 = w1 - lr * w1_grad b = b - lr * b_grad
w1.assign_sub(lr * grads[0]) # 参数w1自更新,assign_sub 自减
b1.assign_sub(lr * grads[1]) # 参数b自更新
# 对每个epoch,打印loss信息
print("Epoch {}, loss: {}".format(epoch, loss_all/4))
train_loss_results.append(loss_all / 4) # 给train_loss_results追加内容,将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) # argmax 返回y中最大值的索引,即预测的分类
# 将pred转换为y_test的数据类型
pred = tf.cast(pred, dtype=y_test.dtype) #cast 强制转换数据类型,后边跟某个变量,指的是转变成该变量的格式
# 若分类正确,则correct=1,否则为0,将bool型的结果转换为int型
correct = tf.cast(tf.equal(pred, y_test), dtype=tf.int32) #比较pred和y_test的数据类型,二者的形式要一致,否则不能进行比较
# 相同输出true,不同输出false
# 将每个batch的correct数加起来
correct = tf.reduce_sum(correct)
# 将所有batch中的correct数加起来
total_correct += int(correct)
# total_number为测试的总样本数,也就是x_test的行数,shape[0]返回变量的行数,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("--------------------------")
# 绘制 loss 曲线,plt绘图函数
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()