4.1 认识神经网络
- 必要性
- 当特征值只有两个时,我们仍可以用之前学过的算法去解决
- 但当特征值很多,且含有很多个多次多项式时,用之前的算法就很难解决了
例子 :图像感知 Recogonition image
计算机识别汽车是靠像素点的亮度值
神经网络做法:
4.2 如何在神经网络上推理
4.2.1 神经网络定义
定义一个神经网络如下:
计算第l层第j个激活值的公式:
注意符号的含义 w2_1 上标2代表layer 2 下标 1代表第一个神经元
4.2.2 构建:前向传播 forward propagation(使用TensorFlow实现)
前向传播是从输入层开始,通过各层计算直至输出层,从而得出预测结果。
- eg1:手写识别0、1
- 每次层计算, 从左往右计算,要传播神经元的激活值
- eg2:烤咖啡的好坏
- python实现前向传播
自定义dense密集函数:输入前一层的激活,给定当前层的参数,它会输出下一层激活值 自定义sequential函数
其中:W大写在线性代数中代表矩阵
- 拓展: AGI 通用人工智能
4.3 课后作业
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
from scipy.io import loadmat
from scipy.optimize import minimize
# 加载数据集,这里的数据为matlab格式,所有要用SciPy.io的loadmat函数
def load_data(path):
data = loadmat(path)
X = data['X']
y = data['y']
return X, y
X, y = load_data('ex3data1.mat')
print(np.unique(y)) # 找到数组 y 中的所有唯一元素,并返回一个已排序的数组
# [ 1 2 3 4 5 6 7 8 9 10]
X.shape, y.shape
# ((5000, 400), (5000, 1))
# 其中有5000个训练样本,每个样本是20 * 20
# 像素的数字的灰度图像。每个像素代表一个浮点数,表示该位置的灰度强度。20×20的像素网格被展开成一个400维的向量。
# 在我们的数据矩阵X中,每一个样本都变成了一行,这给了我们一个5000×400矩阵X,每一行都是一个手写数字图像的训练样本。
# 第一个任务是将我们的逻辑回归实现修改为完全向量化(即没有“for”循环)。
# 这是因为向量化代码除了简洁外,还能够利用线性代数优化,并且通常比迭代代码快得多。
# Visualizing the data
def plot_an_image(X):
"""
随机打印一个数字
"""
pick_one = np.random.randint(0, 5000) # 从0到5000中随机选取一个整数
image = X[pick_one, :] # 从数据集中选取这个随机索引对应的图像数据
fig, ax = plt.subplots(figsize=(1, 1))
# 将选取的图像数据重新塑形为20x20的矩阵,并使用灰度反转的颜色显示
ax.matshow(image.reshape((20, 20)), cmap='gray_r') # matshow用于以矩阵形式显示二维数组
plt.xticks([])
plt.yticks([]) # 去除x轴和y轴的刻度,使图像显示更美观。
plt.show()
print('this should be {}'.format(y[pick_one]))
def plot_100_image(X):
"""
随机画100个数字
"""
sample_idx = np.random.choice(np.arange(X.shape[0]), 100)
sample_images = X[sample_idx, :] # (100, 400)
# 创建一个10x10的子图网格,共享x轴和y轴的刻度和标签,图像大小为8x8英寸
fig, ax_array = plt.subplots(nrows=10, ncols=10, sharey=True, sharex=True, figsize=(8, 8))
for row in range(10):
for column in range(10):
ax_array[row, column].matshow(sample_images[10 * row + column].reshape((20, 20)), cmap='gray_r')
plt.xticks([])
plt.yticks([])
plt.show()
# Vectorizing Logistic Regression
# 我们将使用多个one-vs-all(一对多)logistic回归模型来构建一个多类分类器。由于有10个类,需要训练10个独立的分类器。
# 为了提高训练效率,重要的是向量化。
# Vectorizing the cost function
def sigmoid(z):
return 1 / (1 + np.exp(-z))
def regularized_cost(theta, X, y, l):
"""
don't penalize theta_0
args:
X: feature matrix, (m, n+1) # 插入了x0=1
y: target vector, (m, )
l(正则化常数λ): lambda constant for regularization
"""
thetaReg = theta[1:]
first = (-y*np.log(sigmoid(X@theta))) + (y-1)*np.log(1-sigmoid(X@theta))
reg = (thetaReg@thetaReg)*l / (2*len(X))
return np.mean(first) + reg
# Vectorizing the gradient
def regularized_gradient(theta, X, y, l):
"""
don't penalize theta_0
args:
l: lambda constant
return:
a vector of gradient
"""
thetaReg = theta[1:]
first = (1 / len(X)) * X.T @ (sigmoid(X @ theta) - y)
# 这里人为插入一维0,使得对theta_0不惩罚,方便计算
reg = np.concatenate([np.array([0]), (l / len(X)) * thetaReg]) # 使用np.concatenate将上面两个数组连接在一起。
return first + reg
# One-vs-all Classification
# 这部分我们将实现一对多分类通过训练多个正则化logistic回归分类器,每个对应数据集中K类中的一个。
# 对于这个任务,我们有10个可能的类,并且由于logistic回归只能一次在2个类之间进行分类,每个分类器在“类别i”和“不是i”之间决定。
# 我们将把分类器训练包含在一个函数中,该函数计算10个分类器中的每个分类器的最终权重,并将权重返回shape为(k,(n + 1))数组,其中n是参数数量。
def one_vs_all(X, y, l, K):
"""generalized logistic regression
args:
X: feature matrix, (m, n+1) # with incercept x0=1
y: target vector, (m, )
l: lambda constant for regularization λ控制正则化强度
K: numbel of labels
return: trained parameters
"""
all_theta = np.zeros((K, X.shape[1])) # (10, 401)
for i in range(1, K+1):
theta = np.zeros(X.shape[1])
y_i = np.array([1 if label == i else 0 for label in y])
ret = minimize(fun=regularized_cost, x0=theta, args=(X, y_i, l), method='TNC',
jac=regularized_gradient, options={'disp': True}) # 设置disp为True以显示优化过程。
all_theta[i - 1, :] = ret.x
return all_theta
# 这里需要注意的几点:首先,我们为X添加了一列常数项1 ,以计算截距项(常数项)。
# 其次,我们将y从类标签转换为每个分类器的二进制值(要么是类i,要么不是类i)。 最后,我们使用SciPy的较新优化API来最小化每个分类器的代价函数。
# 如果指定的话,API将采用目标函数,初始参数集,优化方法和jacobian(渐变)函数。 然后将优化程序找到的参数分配给参数数组。
# 实现向量化代码的一个更具挑战性的部分是正确地写入所有的矩阵,保证维度正确。
def predict_all(X, all_theta):
# 计算每个样本在每个类别上的概率
h = sigmoid(X @ all_theta.T) # 注意的这里的all_theta需要转置
# 创建一个数组,包含每个样本概率最大的类别的索引
# axis=1,返回沿着每行或水平方向最大值的索引
h_argmax = np.argmax(h, axis=1)
# 将索引值从0开始的数组转换为从1开始的数组。
h_argmax = h_argmax + 1
return h_argmax
# 这里的h共5000行,10列,每行代表一个样本,每列是预测对应数字的概率。我们取概率最大对应的index加1就是我们分类器最终预测出来的类别。
# 返回的h_argmax是一个array,包含5000个样本对应的预测值。
raw_X, raw_y = load_data('ex3data1.mat')
X = np.insert(raw_X, 0, 1, axis=1) # (5000, 401)
y = raw_y.flatten() # 这里消除了一个维度,将其转换为一维数组,方便后面的计算 or .reshape(-1) (5000,)
all_theta = one_vs_all(X, y, 1, 10)
all_theta # 每一行是一个分类器的一组参数
y_pred = predict_all(X, all_theta)
accuracy = np.mean(y_pred == y)
print('accuracy = {0}%'.format(accuracy * 100))
# Neural Networks
# 上面使用了多类logistic回归,然而logistic回归不能形成更复杂的假设,因为它只是一个线性分类器。
# 接下来我们用神经网络来尝试下,神经网络可以实现非常复杂的非线性的模型。我们将利用已经训练好了的权重进行预测。
def load_weight(path):
data = loadmat(path)
return data['Theta1'], data['Theta2']
theta1, theta2 = load_weight('ex3weights.mat')
# theta1.shape, theta2.shape
# 因此在数据加载函数中,原始数据做了转置,然而,转置的数据与给定的参数不兼容,因为这些参数是由原始数据训练的。
# 所以为了应用给定的参数,需要使用原始数据(不转置)
X, y = load_data('ex3data1.mat')
y = y.flatten()
# 向特征矩阵 X 的每一行开头插入一个值为1的列
X = np.insert(X, 0, values=np.ones(X.shape[0]), axis=1)
X.shape, y.shape
a1 = X
z2 = a1 @ theta1.T
# z2.shape
z2 = np.insert(z2, 0, 1, axis=1)
a2 = sigmoid(z2)
# a2.shape
z3 = a2 @ theta2.T
# z3.shape
a3 = sigmoid(z3)
# a3.shape
y_pred = np.argmax(a3, axis=1) + 1
accuracy = np.mean(y_pred == y)
print ('accuracy = {0}%'.format(accuracy * 100)) # accuracy = 97.52%
标签:分类器,10,算法,shape,神经网络,深度,np,theta,data From: https://www.cnblogs.com/pgl6/p/18346406