视频知识点:

一、基本命名方法

m_{train}:训练集样本数目:{(x1,y1),(x2,y2),……}

m_{test}:测试集样本数目

x:nx维的特征向量 y∈{0,1}

输入X :m列,nx行 : X.shape=(nx,m)

输出Y:m列 ,1行 :  Y.shape=(1,m)

二、激活函数

常见的激活函数有四种:
sigmoi函数:通常只适用于二分类问题的输出层

其公式为:\sigma (z) = \frac{1}{1+e^{-z}}

tanh函数:在很多情况下比sigmoid函数更加优越

相对于sigmoid函数,tanh函数中心点在原点处

ReLU函数:适用于大部分情况

ReLU函数适用性很强,且速度快

leaky ReLU函数:

leaky ReLU函数相对于ReLU函数,在z<0时,是一条过原点且有倾斜度的直线

注:在这个模型中我们使用sigmoid函数,因为输出层是一个二分类问题,即为“cat” or "no cat"

三、损失函数、成本函数

损失函数是“一个样本”的误差,成本函数是“整个数据集”的平均误差

我们的目标就是:找到更好的w和b使这个成本函数得到的值更小

损失函数:

成本函数:

注意:这里的log相当于是ln

四、梯度下降法

通过沿着函数梯度(下降最快)的方向逐步调整参数,以最小化损失函数的优化算法

这里,先放在二维坐标系里面计算w:

同理,b也是一样:

五、反向传播

如图,前面通过正向传播(黑色线),我们得到损失函数L的值,然后我们可以反向(红色线)求得dw,db,从而更新w和b的值,使损失函数的值更小

这里,各处的求导即在图中

下图是具体更新w,b的方法:J+上单个训练样本的损失值;在for循环之后,对求得的j和m求平均值;最后,对w和b的值进行更新

这里,我在看视频的时候会产生疑惑:为什么z上面要加一个i?

因为z是针对单个训练样本,所以要加上i,以便得知是针对哪个样本所求得的z

六、向量化

在向量化之前,我们需要弄懂np的几个函数:

np.sum(axis=0):每一列在竖直方向上求和

np.sum(axis=1):每一行在水平方向上求和

np.zeros:用于创建一个指定形状的数组,数组中的所有元素都被初始化为 0

np.log:求数组里面每个数的对数

np.abs:求数组里面每个数的绝对值

np.maximu(v,0): 把数组(或标量)v 里的每一个元素都和 0 比较,返回两者中的较大者,就是把 v 里所有负数截成 0,其余保留

np.array: 创建一个目标数组,例如arr = np.array([0, 2]),那么得到arr:[0,2]

np.dot:

输入 a 输入 b 函数行为
一维 `(N,)`一维 `(N,)` 向量内积 `sum(a*b)`
二维 `(M,N)`二维 `(N,K)矩阵乘法 `a @ b` 或 `a.matmul(b)`
多维 `(…,M,N)`多维 `(…,N,K)`批量矩阵乘法(最后两维做乘,前面广播)
多维/混合任意把 ≥1-D 的输入当成向量/矩阵,按广播规则做内积 

七、广播

NumPy让不同形状的数组进行数学运算时自动扩展维度以匹配的机制。

举例子,如图中的列向量[1,2,3,4]需要加上100,那么广播会自动将100拓展成为[100,100,100,100],这样每个数都能加上100,其他例子也是一样

最后,具体传播过程:

正向传播,一次迭代完成:

反向传播:

L1W2作业:

一、建立学习算法的一般架构

1、初始化模型参数

2、通过最小化损失来学习模型的参数

3、使用学习到的参数进行预测(在测试集上)

4、分析结果并得出结论

二、引入头函数:

import numpy as np
import matplotlib.pyplot as plt
import h5py
import scipy
from PIL import Image
from scipy import ndimage
from Lr_utilss import load_dataset
%matplotlib inline

注意:这里的%matplotlib inline:让 matplotlib 生成的图表直接嵌入在 Notebook 页面中显示

三、加载数据集

train_set_x_orig,train_set_y,test_set_x_orig,test_set_y,classes = load_dataset()#获取数据集

这里,train_set_x_orig和test_set_x_orig的每一行都是代表图像的数组,且在图像数据集(训练和测试)的末尾添加了"_orig",以便对其进行预处理。预处理后,我们将得到train_set_x和test_set_x(标签train_set_y和test_set_y不需要任何预处理)

这里还可以通过以下代码可视化示例。 还可以随意更改index值并重新运行以查看其他图像。

index = 5
plt.imshow(train_set_x_orig[index])
print("y= "+str(train_set_y[:,index]) + ", it's a "+ classes[np.squeeze(train_set_y[:,index])].decode("utf-8")+"'picture.")

注意:plt.imshow(train_set_x_orig[index]):显示第index个图片

np.squeeze(train_set_y[:,index]):移除多余的维度(长度为1的维度),得到标量值:

举个例子:

                arr = np.array([[[1], [2], [3]]])

                print("原来的形状:", arr.shape)  # 输出:(1, 3, 1) 三维了

                squeezed = np.squeeze(arr)

                print("挤掉后的形状:", squeezed.shape)  # 输出:(3,)

                print("数组内容:", squeezed)  # 输出:[1 2 3]

                decode("utf-8"):将字节字符串解码为普通字符串

四、预处理数据集

步骤如下:

1、找出数据的尺寸和维度(m_train,m_test,num_px等)

2、重塑数据集,以使每个示例都是大小为(num_px \ num_px \ 3,1)的向量

3、“标准化”数据

1、找出数据的尺寸和维度
m_train = train_set_x_orig.shape[0]#找到训练集样本数量
m_test = test_set_x_orig.shape[0]#找到测试集样本数量
num_px = train_set_x_orig.shape[1]#每个图像的宽/高
print ("Number of training examples: m_train = " + str(m_train))
print ("Number of testing examples: m_test = " + str(m_test))
print ("Height/Width of each image: num_px = " + str(num_px))
print ("Each image is of size: (" + str(num_px) + ", " + str(num_px) + ", 3)")
print ("train_set_x shape: " + str(train_set_x_orig.shape))
print ("train_set_y shape: " + str(train_set_y.shape))
print ("test_set_x shape: " + str(test_set_x_orig.shape))
print ("test_set_y shape: " + str(test_set_y.shape))
2、重塑数据集

为了便于后续矩阵乘法运算,这里需要以维度(num_px ∗ num_px ∗ 3, 1)的numpy数组重塑维度(num_px,num_px,3)的图像

当你想将维度为(a,b,c,d)的矩阵X展平为形状为(b∗c∗d, a)的矩阵X_flatten时的一个技巧是:

X_flatten = X.reshape(X.shape [0],-1).T     # 其中X.T是X的转置矩阵

train_set_x_flatten = train_set_x_orig.reshape(train_set_x_orig.shape[0],-1).T
test_set_x_flatten = test_set_x_orig.reshape(test_set_x_orig.shape[0],-1).T
print ("train_set_x_flatten shape: " + str(train_set_x_flatten.shape))
print ("train_set_y shape: " + str(train_set_y.shape))
print ("test_set_x_flatten: " + str(test_set_x_flatten.shape))
print ("test_set_y shape: " + str(test_set_y.shape))
print("sanity check after reshaping: "+str(train_set_x_flatten[0:5,0]))

注意:当我们将 (length, height, 3) 的图像转换为 (length*height*3, 1) 的向量时,每一行代表图像中的一个单独的通道值。第1行: 第一个像素的R通道值,第2行: 第一个像素的G通道值,第3行: 第一个像素的B通道值

3、标准化数据

图片数据集的标准化处理很简单,只需要将数据集的每一行除以255(像素通道的最大值)

train_set_x = train_set_x_flatten/255.0
test_set_x = test_set_x_flatten/255.0

五、构建神经网络

建立神经网络的主要步骤是:

1.定义模型结构(例如输入特征的数量)

2.初始化模型的参数

3.循环:

                计算当前损失(正向传播)

                计算当前梯度(向后传播)

                更新参数(梯度下降)

一、初始化模型参数

这里需要对w,b进行初始化,将w初始化成一个二维数组,b初始化成float/int型常量

def initialize_with_zeros(dim):
    w = np.zeros((dim,1))#Np.zeros:用于创建一个指定形状的数组,数组中的所有元素都被初始化为 0
    b = 0
    assert(w.shape==(dim,1))#assert:声明这个数组就是这样的形状
    assert(isinstance(b,float) or isinstance(b,int))
    return w, b
dim = 2
w, b = initialize_with_zeros(dim)
print("w = "+str(w))
print("b = "+str(b))
二、循环
1、计算当前损失(正向传播)

首先需要构建一个sigmoid函数:

def sigmoid(z):
    s = 1/(1+np.exp(-z))
    return s
print("sigmoid([0,2]):",str(sigmoid(np.array([0,2]))))

 

正向传播的步骤:

2、计算梯度(反向传播)

通过求出dw,db从而不断更新w,b的值

def propagate(w,b,X,Y):
    m = X.shape[1]#求出样本数量
    A = sigmoid(np.dot(w.T,X) + b)#求出损失
    cost = -1 /m *np.sum(Y * np.log(A) + (1 - Y) * np.log(1 - A))#求出成本
    dw = 1/ m * np.dot(X,(A-Y).T)
    db = 1 / m * np.sum(A-Y)
    assert (dw.shape==w.shape)#确保二者的形状相同
    assert (db.dtype == float)#确保db的类型是float
    cost = np.squeeze(cost)#确保cost是一维
    assert(cost.shape==())

    grads = {"dw": dw, "db": db}#创建一个梯度字典,用于存储逻辑回归的梯度值
    return grads,cost
def optimize(w,b,X,Y,num_iterations,learning_rate,print_cost):
    costs = []#创建一个空的成本列表
    for i in range(num_iterations):
        grads,cost = propagate(w,b,X,Y)
        dw = grads["dw"]
        db = grads["db"]
        w = w - learning_rate * dw
        b = b - learning_rate * db

        if i % 100 == 0:
            costs.append(cost)#每迭代100次,把cost添加进列表

        if print_cost and i %100 ==0:
            print("Cost after iteration %i:%f"%(i,cost))
    params = {"w":w,"b":b}#创建一个字典,用于存储w,b
    grads = {"dw": dw, "db": db}#创建一个梯度字典,用于存储逻辑回归的梯度值
    return params,grads,costs

params,grads,costs = optimize(w,b,X,Y,num_iterations=100,learning_rate=0.009,print_cost=True)
print("w "+ str(params["w"]))
print("b "+ str(params["b"]))
print("dw " + str(grads["dw"]))
print("db " + str(grads["db"]))
print(costs)

六、预测函数

1.计算

2.将a的项转换为0(如果激活<= 0.5)或1(如果激活> 0.5),并将预测结果存储在向量“ Y_prediction”中

def predict(w,b,X):
    m = X.shape[1]
    Y_prediction = np.zeros((1,m))
    w = w.reshape(X.shape[0],1)#确保权重向量 w 的形状与输入特征矩阵 X 的维度匹配,这样才能进行后面的相乘

    A = sigmoid(np.dot(w.T,X)+b)
    for i in range(A.shape[1]):
        if A[0, i] <=0.5:
            Y_prediction[0,i] = 0
        else:
            Y_prediction[0,i] = 1
    assert (Y_prediction.shape == (1,m))
    return Y_prediction

七、合并所有的功能

将所有实现的功能以正确的顺序放在一起,从而得到整体的模型结构

def model(X_train,Y_train,X_test,Y_test,num_iterations=20000,learning_rate=0.005
,print_cost=True):
    w,b = initialize_with_zeros(X_train.shape[0])#初始化w,b
    parameters,grads,costs = optimize(w,b,X_train,Y_train,num_iterations,learning_rate,print_cost)#正向反向传播得到w,b,aw,ab
    w = parameters["w"]
    b = parameters["b"]

    Y_prediction_test = predict(w,b,X_test)
    Y_prediction_train = predict(w,b,X_train)

    print("train accuracy: {} %".format(100-np.mean(np.abs(Y_prediction_train - Y_train)) * 100))
    print("test accuracy: {} %".format(100-np.mean(np.abs(Y_prediction_test - Y_test)) * 100))

    d = {"costs":costs,"Y_prediction_test":Y_prediction_test,"Y_prediction_train":
Y_prediction_train,"w":w,"b":b,"learning_rate":learning_rate,"num_iterations":
num_iterations}
    return d

其中:

  • np.abs():取绝对值(确保差异都是正数)

  • np.mean():计算平均误差

  • * 100:将误差转换为百分比形式

  • 100 - ...:用100%减去误差率得到准确率

最后运行以下单元格训练模型:

d = model(train_set_x,train_set_y,test_set_x,test_set_y,num_iterations=20000,
learning_rate=0.005,print_cost=True)

八、对测试集预测

index = 1
plt.imshow(test_set_x[:,index].reshape((num_px,num_px,3)))
print("y = " + str(test_set_y[0,index]) + ", you predicted that it is a \"" + classes[int(d["Y_prediction_test"][0,index])].decode("utf-8")+ "\"picture.")

九、绘制损失函数和梯度

costs = np.squeeze(d['costs'])#从d中取出对应cost键的值,并确保是一维
plt.plot(costs)#绘制成本随迭代次数变化的曲线,costs是包含每次迭代成本的数组
plt.ylabel('cost')
plt.xlabel('iteration(per hundreds)')
plt.title("Learning rate = " + str(d["learning_rate"]))
plt.show
Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐