目录
激活函数
激活函数是连接感知机和神经网络的桥梁
阶跃函数
阶跃函数是在感知机中使用的激活函数。
\[h(x)=\begin{cases} 0 \quad x<0\\ 1 \quad x>=0\\ \end{cases} \]图像:
实现
import numpy as np
def step_function(x):
y = x > 0
return y.astype(np.int)
print(step_function(np.array([1, -1, 1, 3, -3, -4])))
sigmoid函数
\[h(x)=\frac{1}{1+e^{-x}} \]其中\(e=2.7182...\)是纳皮尔常数。
图像:
实现
import numpy as np
import matplotlib.pyplot as plt
# numpy array具有广播功能
def sigmoid(x):
return 1 / (1 + np.exp(-x))
# x = np.arange(-5, 5, 0.1)
# y = sigmoid(x)
# plt.plot(x, y)
# plt.ylim(-0.1, 1.1)
# plt.show()
在感知机中使用的是阶跃函数,在神经网络中我们引入了sigmoid函数。
可以先比较两种函数
从两方面去比较
不同点:
- 平滑性:阶跃函数是不平滑的,sigmoid函数是平滑的
- 返回值:阶跃函数只能返回两种值0|1,sigmoid可以返回的值是[0,1]之间的实数
相同点: - 从宏观上去看,两者的趋势比较一致或者说形状吧
- 两者均属于非线性函数
神经网络中的激活函数必须使用非线性函数。
为什么呢?
可以考虑使用线性函数,我们知道神经网络是一层一层这样叠加下去,使用线性函数的话,无论叠加多少层,到最后我们的函数都可以等价为只使用一个等价的线性函数
ReLU函数
\[h(x)=\begin{cases} 0 \quad x<0\\ x \quad x>=0\\ \end{cases} \]图像
实现
import numpy as np
from matplotlib import pyplot as plt
def relu(x):
return np.maximum(0, x)
# x = np.arange(-5, 5, 0.3)
# y = relu(x)
# plt.plot(x, y)
# plt.ylim(-5, 10)
# plt.show()
三层神经网络的实现
第0层到第1层
X = np.array([1.0, 0.5])
W1 = np.array([[0.1, 0.3, 0.5],
[0.2, 0.4, 0.6]])
B1 = np.array([0.1, 0.2, 0.3])
# print(W1.shape)
# print(X.shape)
# print(B1.shape)
# 通过矩阵运算,使得信息向前传递
A1 = np.dot(X, W1) + B1
# 激活函数
Z1 = sigmoid(A1)
# print(A1)
# print(Z1)
第1层到第2层
W2 = np.array([[0.1, 0.4],
[0.2, 0.5],
[0.3, 0.6]])
B2 = np.array([0.1, 0.2])
A2 = np.dot(Z1, W2) + B2
Z2 = sigmoid(A2)
# print(A2)
# print(Z2)
第2层到输出层
# 第2层到输出层
W3 = np.array([[0.1, 0.3],
[0.2, 0.4]])
B3 = np.array([0.1, 0.2])
A3 = np.dot(Z2, W3) + B2
# 恒等函数,将第2层结果传递到输出层
Y = identity_function(A3)
将上面代码整合一下就可以得到下面代码
def init_network():
network = {}
network['W1'] = np.array([[0.1, 0.3, 0.5],
[0.2, 0.4, 0.6]])
network['B1'] = np.array([0.1, 0.2, 0.3])
network['W2'] = np.array([[0.1, 0.4],
[0.2, 0.5],
[0.3, 0.6]])
network['B2'] = np.array([0.1, 0.2])
network['W3'] = np.array([[0.1, 0.3],
[0.2, 0.4]])
network['B3'] = np.array([0.1, 0.2])
return network
def forward(network, x):
W1, W2, W3 = network['W1'], network['W2'], network['W3']
b1, b2, b3 = network['B1'], network['B2'], network['B3']
a1 = np.dot(x, W1) + b1
z1 = sigmoid(a1)
a2 = np.dot(z1, W2) + b2
z2 = sigmoid(a2)
a3 = np.dot(z2, W3) + b3
y = identity_function(a3)
return y
network = init_network()
x = np.array([1.0, 0.5])
y = forward(network, x)
print(y)
init_network()中做的工作是,初始化权重和偏置,并用一个字典存储作为返回值
forward,是将输入信号进行计算得出输出信号,[forward的含义是表示从输入到输出方向传递]
输出层设计
我们知道神经网络的运用一般是分类和回归,根据不同的任务,我们可以设计不同的输出,不同的输出可以通过不同的输出层激活函数来实现。
具体而言,回归问题使用恒等函数\((identity_function)\),分类问题使用\(softmax\)函数
恒等函数和softmax函数
恒等函数顾名思义就是恒等函数
import numpy as np
def identity_function(x):
return x
softmax
函数
import numpy as np
def softmax(x):
exp_x = np.exp(x)
sum_exp_x = np.sum(exp_x)
y = exp_x / sum_exp_x
return y
# a = np.array([0.3, 2.9, 4.0])
# print(softmax(a))
softmax函数的一些小优化防止溢出
import numpy as np
def softmax(x):
c = np.max(x)
exp_x = np.exp(x - c)
sum_exp_x = np.sum(exp_x)
y = exp_x / sum_exp_x
return y
softmax函数的性质,观察softmax函数的式子可以发现,softmax函数值在[0,1]内,同时所有的函数值加起来为1,这个性质和概率的的定义比较像,所以我们可以把它解释为概率
输出层的神经元数量
在分类问题中输出层神经元的数量由分类的类别确定
手写数字识别
机器学习解决问题一般分为两个步骤,一是学习,而是推理。
学习的过程就是最优化我们权重的过程,推理的过程是通过学习到的权重对问题进行处理。
推理的过程也被称之为前向传播\((forward propagation)\)
MINIST数据集
MINIST数据集通常是指手写数字识别数据集,其中包含大量的手写数字图像和相应的标签。这个数据集通常用于机器学习和深度学习领域的算法测试和验证。MINIST数据集包含了来自高中学生和美国人口普查局员工的手写数字样本,涵盖了数字0到9。
MINIST数据集通常包含以下几个部分:
训练集:用于训练机器学习模型的数据集,包含许多手写数字图像及其对应的标签。
测试集:用于评估模型性能的数据集,也包含手写数字图像及其标签,但是这些数据不用于模型的训练,只用于测试。
每个图像通常都是28x28像素的灰度图像,标签是0到9之间的数字,表示相应图像中的手写数字。MINIST数据集是一个相对较小的数据集,适合用于快速验证和测试机器学习模型的原型。
MINIST数据集是很多深度学习入门书上的例子,很经典。
有很大的学习价值。
神经网络的推理处理
# coding: utf-8
import pickle
import sys, os
from sigmoid import *
from softmax import *
sys.path.append(os.pardir) # 親ディレクトリのファイルをインポートするための設定
import numpy as np
from dataset.mnist import load_mnist
def get_data():
(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, flatten=True, one_hot_label=False)
return x_test, t_test
def init_network():
with open("sample_weight.pkl", 'rb') as f:
network = pickle.load(f)
return network
def predict(network, x):
W1, W2, W3 = network['W1'], network['W2'], network['W3']
b1, b2, b3 = network['b1'], network['b2'], network['b3']
a1 = np.dot(x, W1)
z1 = sigmoid(a1)
a2 = np.dot(z1, W2)
z2 = sigmoid(a2)
a3 = np.dot(z2, W3)
y = softmax(a3)
return y
# 输入数据
x, t = get_data()
# 创建网络
network = init_network()
# 精度(准确度的计算)
accuracy_cnt = 0
for i in range(len(x)):
y = predict(network, x[i])
# 获取概率最高的索引
p = np.argmax(y)
if p == t[i]:
accuracy_cnt = accuracy_cnt + 1
print("Accuracy:" + str(float(accuracy_cnt / len(x))))
批处理
-
向量化运算
: 在现代的深度学习框架中,通常会利用高度优化的线性代数库(如NumPy、TensorFlow、PyTorch等)来执行批处理操作。这些库能够利用硬件加速器(如GPU)进行并行化操作,从而高效地进行向量化运算。相比逐个样本处理,批处理可以充分发挥这些库的优势,使得计算速度大大提高。 -
减少数据传输开销
: 在训练过程中,数据的传输开销可能成为瓶颈之一,尤其是当数据量较大时。通过批处理,可以减少数据传输的次数,因为一次传输可以处理多个样本。这样可以显著减少由数据传输引起的延迟。 -
优化内存访问
: 当处理一批数据时,可以利用现代计算机架构的缓存机制,从而更有效地利用内存。在批处理中,连续的数据通常会被放置在内存中相邻的位置,这有助于减少内存访问的随机性,提高数据访问效率。 -
并行计算
: 许多深度学习框架支持在GPU上并行计算,批处理可以更充分地利用GPU的并行计算能力。通过一次处理多个样本,可以同时执行多个神经网络计算步骤,从而加快整体训练速度。
x, t = get_data()
network = init_network()
batch_size = 100 # 批数量
accuracy_cnt = 0
# range(start, end, step),start表示起始下标,end表示结束下标的下一个,step为步长[start, end)
for i in range(0, len(x), batch_size):
# numpy中的切片操作
x_batch = x[i:i + batch_size]
y_batch = predict(network, x_batch)
# axis=1表示确定第0维求,第二维最大值的下标
p = np.argmax(y_batch, axis=1)
accuracy_cnt += np.sum(p == t[i:i + batch_size])
print("Accuracy:" + str(float(accuracy_cnt) / len(x)))
标签:0.1,入门,sigmoid,python,network,神经网络,np,array,函数
From: https://www.cnblogs.com/cxy8/p/18075543