X、前言
X.1环境配置
x.1.1安装Anaconda
直接官网下载Anaconda,安装完成后,conda -V查看是否安装成功
activate-->进入base环境
conda create -n py37 python=3.7 创建一个叫py37的python3.7的虚拟环境
conda activate py37 进入py37虚拟环境
conda deactivate 退出一层虚拟环境
x.1.2安装Pycharm
直接官网下载社区版,安装Pycharm
安装成功后,打开创建一个新的Project,存储路径自己选
点击File-->settings-->project:PythonProject(可能就是项目名称)

点击小齿轮就可以Add解释器啦,找到Anaconda的安装文件,在envs中找到py37这个虚拟环境,将其中的python.exe文件添加到解释器中,这里就有解释器用啦
执行一个程序,运行成功,表示解释器在工作了。
x.1.3 安装CUDA与cudnn
英伟达为了使其GPU在深度学习上进行张量运算,推出了CUDA,确保系统中没有CUDA相关应用后,到CUDA官网下载适配显卡的CUDA版本,进行下载
安装CUDA,不要修改安装路径,并且对于三个要设置路径的安装部分来说,自己创建CUDA11.1文件夹,并在其中新建CUDA1与CUDA2文件夹,将前两个部分的安装路径设置到CUDA1下,将第三个部分的安装路径和设置到CUDA2下,安装即可
cudnn是一个基于CUDA的神经网络加速器,直接在官网找到对应版本,解压后将文件夹复制到CUDA1下即可
安装完成后用ncvv -V检查是否成功
x.1.4安装Pytorch
在刚刚的py37虚拟环境中安装Pytorch,激活到该虚拟环境中即可,找到有效的镜像源,直接pip install安装即可
x.1.5安装tensorflow
新建一个虚拟环境tf2,在该环境中安装tensorflow,直接用有效的镜像源安装即可,注意版本适配性
这样,就拥有了Pytorch与tensorflow两个不同虚拟环境了,在Pycharm中选择不同的虚拟环境下的解释器,就可以使用不同框架玩转深度学习啦
X.2注意事项
一、基础语法
#类
class Man:
def __init__(self,name):
self.name = name
print("Initialized!")
def hello(self):
print("Hello" + self.name + "!")
def goodbye(self):
print("Good-bye" + self.name + "!")
m = Man("David")
m.hello()
m.goodbye()
# 基础绘图
import numpy as np
import matplotlib.pyplot as plt
# 生成数据
x = np.arange(0,6,0.1)
y1 = np.sin(x)
y2 = np.cos(x)
# 绘制图形
plt.plot(x,y1,label = "sin")
plt.plot(x,y2,linestyle = "--",label = "cos")# 用虚线绘制
plt.xlabel("x")# x轴标签
plt.ylabel("y")# y轴标签
plt.title('sin & cos')# 添加图标题
plt.legend(loc = 1)# 添加图例
plt.show()
plt.show
# 读取与打印图片
import matplotlib.pyplot as plt
from matplotlib.image import imread
# 读入图像的函数imread,显示图像的函数imshow
img = imread('lena.jpg')# 读入图像(要有路径)
plt.imshow(img)
plt.show()
print(img)# 图像就是一个矩阵
二、感知机
2.1与门感知机
2.1.1线性可分感知机
感知机有多个输入信号与一个输出信号,某一个输入信号会用权重衡量其重要性,然后进行加权求和,并与阈值比较,大于阈值就激活神经元,返回1,小于等于阈值就返回0;
同样地,可以将阈值调整为偏置,这样就直接与0比较大小就行了。
# 与门感知机
def AND(x1,x2):
w1,w2,theta = 0.5,0.5,0.7
tmp = x1 * w1 + x2 * w2
if tmp <= theta:
return 0
elif tmp > theta:
return 1
# 利用加偏置的方式写与门感知机
import numpy as np
def AND(x1,x2):
x = np.array([x1,x2])# 输入
w = np.array([0.5,0.5])# 权重
b = -0.7# 偏置
tmp = np.sum(w * x) + b# 计算信号加权求和加偏置
if tmp <= 0:
return 0
else:
return 1
# 与非门感知机
def NAND(x1,x2):
x = np.array([x1,x2])# 输入
w = np.array([-0.5,-0.5])# 权重
b = 0.7# 偏置
tmp = np.sum(w * x) + b# 计算信号加权求和加偏置
if tmp <= 0:
return 0
else:
return 1
# 或门感知机
def OR(x1,x2):
x = np.array =([x1,x2])
w = np.array = ([0.5,0.5])
b = 0.3
tmp = np.sum(w * x) + b
if tmp <= 0:
return 0
else:
return 1
OR(1,1)
2.1.2线性不可分感知机
就是无法用直线分割的空间,需要用曲线甚至是更复杂的方式才能分割,对于 线性不可分 可以采用叠加层感知机进行分割,如异或门,所谓叠加层,也就是先进行或门,与非门,得到对应的输出,再将这两个输出作为输入,进行与门,就实现了异或门:
# 异或门感知机,叠加层感知机
def XOR(x1,x2):
s1 = OR(x1,x2)
s2 = NAND(x1,x2)
return AND(s1,s2)
XOR(0,1)
三、神经网络
3.1激活函数
所谓激活函数,就是在神经元处,将输入信号加权求和并加上偏置得到的值,通过某函数处理一下得到输出值,这个函数就是激活函数,激活函数都是非线性的,因为线性激活函数的处理总能被单层网络以某种方式实现,丧失了叠加层神经网络的优势。
# 激活函数1:阶跃函数
def step_fun(x):
'''这里的x只能接受实数'''
if x > 0:
return 1
else:
return 0
# 设置成数组的输入的阶跃函数
import numpy as np
def step_fun2(x):
'''可以接受数组哦'''
y = x > 0# 非常巧妙地利用了np.array数组的特性,[1.0,-1.0] > 0,返回[True,False]
return y.astype(np.int)# astype是以将序列中的元素转换为指定的数据类型,如[True,False]转换成[1,0]
import matplotlib.pylab as plt
def step_function(x1):
return np.array(x1 > 0,dtype = np.int)# 返回一个np.array()数组,并确定元素类型为dtype = np.int
x1 = np.arange(-5.0,5.0,0.1)# 生成范围为-5.0到5.0的步长为0.1的数组
y1 = step_function(x1)
plt.plot(x1,y1)
plt.ylim(-0.1,1.1)# 指定y轴的范围
plt.show()
# 激活函数2:sigmoid函数的实现
def sigmoid(x2):
return 1 / (1 + np.exp(-x2))# np.exp()对一个数组进行取以e为底的指数数组
x2 = np.arange(-5.0,5.0,0.1)
y2 = sigmoid(x2)
plt.plot(x2,y2)
plt.ylim(-0.1,1.1)
plt.show()
figure = plt.figure()
ax = figure.subplots(1,1)
ax.plot(x1,y1,'r--')
ax.plot(x2,y2)
# 激活函数3:ReLU函数
def relu(x3):
return np.array(list(map(lambda x: x if x > 0 else 0,x3)))
x3 = np.arange(-5.0,5.0,0.1)
y3 = relu(x3)
plt.plot(x3,y3)
# ReLU函数的实现2
def relu(x3):
return np.maximum(0,x3)
y3 = relu(x3)
plt.plot(x3,y3)
3.2多维数组的运算
import numpy as np
A = np.array([1,2,3,4])
print(A)
np.ndim(A)# 获取数组的维数,如这个A的维数就是1
A.shape# 获取数组的形状,如这个就是(4,),指的是4*1,如果是二维数组,比如(4,3)指的是4*3的二维数组
A.shape[0]# 返回4
B = np.array([[1,2],[3,4],[5,6]])
print(B)
np.ndim(B)# 2维,行和列
B.shape
X = np.array([[1,2],[3,4]])# 2*2矩阵
Y = np.array([[5,6],[7,8]])# 2*2矩阵
np.dot(X,Y)# 进行矩阵乘法,也称点积,结果还是2*2的矩阵
A = np.array([[1,2],[3,4],[5,6]])# 3*2矩阵
B = np.array([7,8])# 它既可以看成行向量,也可以看作列向量,根据实际情况自动调整的,也就是既可以看为2*1,也可以看出1*2
np.dot(A,B)# 显然这里的B被看作2*1的列向量
# 神经网络的内积
'''X是输入数组,就是(x1,x2),W是权重矩阵,其第m行,就是xm指向后一层n个神经元y1,..,yn的权重顺序数组[w11,w21,w31],如w21指的就是x1->y2的权重,Y是输出数组[y1,y2,y3]'''
X = np.array([1,2])# 1*2
X.shape
W = np.array([[1,3,5],[2,4,6]])# 2*3矩阵
print(W)
W.shape
Y = np.dot(X,W)# 1*3
print(Y)
3.3三层神经网络的实现
3.3.1分层实现
# 神经网络的的第一层信号传递计算
'''X是输入层输入的数组,W1是输入层输入的权重矩阵,A1是在第二层节点处求和得到数组,B1是输入层的偏置数组,Z1是激活函数激活后的数组'''
X = np.array([1.0,0.5])# 1*2
W1 = np.array([[0.1,0.3,0.5],[0.2,0.4,0.6]])# 2*3
B1 = np.array([0.1,0.2,0.3])# 1*3
print(W1.shape)# (2,3)
print(X.shape)# (2,)
print(B1.shape)# (3,)
A1 = np.dot(X,W1) + B1# 1*3
print(A1)
Z1 = sigmoid(A1)# 1*3
print(Z1)
# 神经网络的的第二层信号传递计算
'''Z1是激活函数激活后的数组,即从第二层输出的数组,W2就是第二层输出数组的权重,A2是在第三层节点处求和得到数组,B2是第二层输入的偏置数组,Z2是A2通过激活函数激活得到的数组'''
W2 = np.array([[0.1,0.4],[0.2,0.5],[0.3,0.6]])
B2 = np.array([0.1,0.2])
print(Z1.shape)
print(W2.shape)
print(B2.shape)
A2 = np.dot(Z1,W2) + B2
Z2 = sigmoid(A2)
# 神经网络输出层的信号传递
'''W3,B3,A3,Y分别是第三层输入的权重,第三层输入的偏置,第四层也就是输出层处的求和,以及输出层的最终输出'''
def identity_fun(x):# 这是恒等函数,作为sigma激活函数,专用于输出层激活,也可以不用定义该函数,只是为了与前面保持一致才定义的
return x
W3 = np.array([[0.1,0.3],[0.2,0.4]])# 2*2
B3 = np.array([0.1,0.2])# 2*1
A3 = np.dot(Z2,W3) + B3
Y = identity_fun(A3)
print(Y)
3.3.2直接实现
# 三层神经网络的定义
def sigmoid(x2):#定义激活函数sigmoid函数,作为隐层的激活
return 1 / (1 + np.exp(-x2))# np.exp()对一个数组进行取以e为底的指数数组
def identity_fun(x):# 这是恒等函数,作为sigma激活函数,专用于回归的输出层激活,也可以不用定义该函数,只是为了与前面保持一致才定义的
return x
def init_network():
network = {}#创建字典,用来储存三层的权重矩阵和偏置数组
network['W1'] = np.array([[0.1,0.3,0.5],[0.2,0.4,0.6]])# 2*3
network['b1'] = np.array([0.1,0.2,0.3])# 3*1
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_fun(a3)#直到输出层,用恒等函数激活,获取输出数组
return y#返回输出数组
network = init_network()#调用init_network函数获得该字典
x = np.array([1.0,0.5])#生成输入数组
y = forward(network,x)#传入实参,获取返回值输出数组
print(y)
3.4输出层的设计
3.4.1softmax激活函数
softmax函数是针对分类设计的,其各类输出值之和是1,各输出值可以看作出现该种类别的概率,其中概率最大的结果,就认为是输出的类别,又因为softmax函数其实是基于指数函数的,所以不添加这个激活函数,也可以进行分类,因为指数函数是单调递增的,所以输入softmax的值越大,输出的值肯定也越大,直接比输入的值的大小就行了,另外输出层的神经元数量就应该设置成类别的数量。
#softmax函数
a = np.array([0.3,2.9,4.0])
exp_a = np.exp(a)
print(exp_a)
sum_exp_a = np.sum(exp_a)
print(sum_exp_a)
y = exp_a / sum_exp_a
print(y)
#考虑溢出问题的softmax激活函数
a = np.array([1010,1000,990])
np.exp(a) /np.sum(np.exp(a))#因为exp(n),当n很大的时候,会返回一个超出8字节的数字,对象无法保存它,会返回nan
c = np.max(a)
np.exp(a - c) /np.sum(np.exp(a - c))#让a中每个值都减去最大值c,相当于对分子分母同乘以c',不影响结果,但是解决了溢出问题
#定义softmax激活函数
def softmax(a):
c = np.max(a)
exp_a = np.exp(a - c)#解决溢出
exp_sum_a = np.sum(np.exp(a - c))
return exp_a / exp_sum_a
a = np.array([0.3,2.9,4.0])
y = softmax(a)
np.sum(y)#显然softmax函数输出的值的和是1,所以各结果的输出值可以称为概率
3.5手写数字识别
采用前向传播神经网络,所谓前向传播,就是将学习到的参数,用来实现神经网络的推理。