[Глубокое обучение] Созданная вручную модель глубокой нейронной сети DNN

глубокое обучение

На прошлой неделе код для построения DNN писался два-три дня, в процессе я столкнулся с массой проблем, из-за чего не решился резюмировать его в блоге. Не паникуйте, если вы обнаружите, что созданная вами нейронная сеть на самом деле не распознает загруженные нами изображения. наш реальный тестовый набор Точность вышеизложенного (изображение, загруженное пользователем) совершенно недостижима! На таком небольшом наборе данных написание модели DNN больше связано с знакомством с внутренней структурой глубокой нейронной сети и применением теоретических знаний о глубоком обучении на практике. Это то же предложение: изучение теоретических знаний является ядром.Изучив принципы реализации нейронных сетей, вы сможете лучше понять, как оптимизировать нейронные сети.

1. Наборы данных и инструменты

ссылка для скачиванияФактически, это набор данных распознавания изображений кошек, используемый в модели логистической регрессии. Код извлечения: xx1w

2. Уменьшение размерности изображения и нормализация

import numpy as np #numpy科学计算库
import h5py #与H5文件中存储的数据集进行交互的常用软件包
from lr_utils import load_dataset #加载本数据集的资料包
import matplotlib.pyplot as plt #绘制图表
from dnn_utils import sigmoid, sigmoid_backward, relu, relu_backward
train_x, train_y, test_x, test_y ,classes = load_dataset() 

index = 2
plt.imshow(train_x[index])
print("y="+ str(train_y[: ,index])+",it is a "+ classes[np.squeeze(train_y[:,index])].decode("utf-8"))

在这里插入图片描述

# 输出索引为1的图像
index = 1
plt.imshow(train_x[index])
print("y="+ str(train_y[:,index])+",it is a "+ classes[np.squeeze(train_y[:,index])].decode("utf-8"))

在这里插入图片描述

# 查看数据集具体情况
m_train = train_y.shape[1] #训练集样本数
m_test = test_y.shape[1] #测试集样本数
num_px = train_x.shape[1] #图片的宽/长
print("训练集样本数量:"+str(m_train))
print("测试集样本数量:"+str(m_test))
print("每张图片的宽/高:"+str(num_px))
print("每张图片的大小:("+str(num_px)+", "+str(num_px)+", 3)")
print("训练集图片维度:"+str(train_x.shape))
print("训练集标签维度:"+str(train_y.shape))
print("测试集图片维度:"+str(test_x.shape))
print("测试集标签维度:"+str(test_y.shape))
# 为什么图片维度多了一个3?因为每个像素点有三原色(R,G,B)构成
训练集样本数量:209
测试集样本数量:50
每张图片的宽/高:64
每张图片的大小:(64, 64, 3)
训练集图片维度:(209, 64, 64, 3)
训练集标签维度:(1, 209)
测试集图片维度:(50, 64, 64, 3)
测试集标签维度:(1, 50)
#由于需要处理二维矩阵,所以需要降维
#即是把3个二维图像依次拉伸为(num_px)^2,再把m_train个样本列堆积
train_x_flatten = train_x.reshape(train_x.shape[0], -1).T
test_x_flatten = test_x.reshape(test_x.shape[0], -1).T
print("训练集降维后的维度:"+str(train_x_flatten.shape))
print("测试集降维后的维度:"+str(test_x_flatten.shape))
训练集降维后的维度:(12288, 209)
测试集降维后的维度:(12288, 50)
对像素值0-255归一化处理,对图像简单除以255即可
train_x1 = train_x_flatten / 255
test_x1 = test_x_flatten / 255

2. Произвольная инициализация сетевых параметров

# 浅层神经网络的参数的随机初始化
def initialization(n_x, n_h, n_y):
    W1 = np.random.randn(n_h, n_x) * 0.1 #乘0.1是为了初始化的参数尽可能小
    b1 = np.random.randn(n_h, 1)
    W2 = np.random.randn(n_y, n_h) * 0.1
    b2 = np.random.randn(n_y, 1)
    
    parameters = {
        "W1": W1,
        "b1": b1,
        "W2": W2,
        "b2": b2   
    }
    return parameters
# L层神经网络的随机初始化
def initialization_deep(layer_dims):
    L = len(layer_dims)
    parameters = {}
    for l in range(1, L):
        parameters["W" + str(l)] = np.random.randn(layer_dims[l], layer_dims[l-1]) / np.sqrt(layer_dims[l-1]) # 除以平方根防止梯度爆炸/消失
        parameters["b" + str(l)] = np.zeros((layer_dims[l], 1))
    return parameters

3. Прямое распространение

# 前向传播的线性处理
def linear_forward(A, W, b):
    Z = np.dot(W, A) + b
    cache = (A, W, b)
    return Z, cache
# 前向传播的线性和激活处理
def linear_activation_forward(A_previous, W, b, activation):
    Z, linear_cache = linear_forward(A_previous, W, b)
    if activation == "sigmoid":
        A, activation_cache = sigmoid(Z)
    elif activation == "relu":
        A, activation_cache = relu(Z)
    cache = (linear_cache, activation_cache) 
    return A, cache
# L层神经网络的前向传播
def L_model_forward(X, parameters):
    A = X    
    L = len(parameters) // 2 # 参数有w和b两种,除以2得到层数L
    caches = []
    for l in range(1, L):
        A_previous = A 
        A, cache = linear_activation_forward(A_previous, parameters['W' + str(l)], parameters['b' + str(l)], activation = "relu")
        caches.append(cache)
    AL, cache = linear_activation_forward(A, parameters['W' + str(L)], parameters['b' + str(L)], activation = "sigmoid")
    caches.append(cache)
    return AL, caches

В-четвертых, вычислите функцию стоимости

# 计算成本值
def compute_cost(AL, Y):
    m = Y.shape[1]
    cost = -np.sum(np.multiply(np.log(AL),Y) + np.multiply(np.log(1 - AL), 1 - Y)) / m # 交叉熵损失函数
    cost = np.squeeze(cost) # 表示向量的数组转换为秩为1的数组 方便plot连续图像
    return cost

5. Обратное распространение

# 反向传播的线性过程
def linear_backward(dZ, cache):
    A_prev, W, b = cache
    m = A_prev.shape[1]
    dW = np.dot(dZ, A_prev.T) / m
    db = np.sum(dZ, axis=1, keepdims=True) / m
    dA_previous = np.dot(W.T, dZ)
    return dA_previous, dW, db
# 反向传播的线性和激活过程
def linear_activation_backward(dA, cache, activation):
    linear_cache, activation_cache = cache
    if activation == "relu":
        dZ = relu_backward(dA, activation_cache)
        dA_previous, dW, db = linear_backward(dZ, linear_cache)
    elif activation == "sigmoid":
        dZ = sigmoid_backward(dA, activation_cache)
        dA_previous, dW, db = linear_backward(dZ, linear_cache)
    return dA_previous, dW, db
# L层神经网络的反向传播
def L_model_backward(AL, Y, caches):
    grads = {}
    L = len(caches)
    m = AL.shape[1]
    dAL = - (np.divide(Y, AL) - np.divide(1 - Y, 1 - AL))
    
    current_cache = caches[L-1]
    grads["dA"+str(L)], grads["dW"+str(L)], grads["db"+str(L)] = linear_activation_backward(dAL, current_cache, "sigmoid") 
    for l in reversed(range(L-1)):
        current_cache = caches[l]
        dA_prev_temp, dW_temp, db_temp = linear_activation_backward(grads["dA" + str(l + 2)], current_cache, "relu")
        grads["dA" + str(l + 1)] = dA_prev_temp
        grads["dW" + str(l + 1)] = dW_temp
        grads["db" + str(l + 1)] = db_temp
    
    return grads

6. Обновление параметров

# 参数更新
def update_parameters(parameters, grads, learning_rate):
    L = len(parameters) // 2
    for l in range(1, L+1):
        parameters['W' + str(l)] = parameters['W' + str(l)] - learning_rate * grads["dW" + str(l)]
        parameters['b' + str(l)] = parameters['b' + str(l)] - learning_rate * grads["db" + str(l)]
    return parameters

Семь, постройте двухслойную нейронную сеть

# 两层神经网络
def two_layer_model(X, Y, layers_dims, learning_rate=0.0075, num_iterations=3000, print_cost=False, isPlot=True):
    grads = {}
    costs = [] 
    (n_x,n_h,n_y) = layers_dims
    parameters = initialization(n_x, n_h, n_y)
    
    W1 = parameters["W1"]
    b1 = parameters["b1"]
    W2 = parameters["W2"]
    b2 = parameters["b2"]

    for i in range(0, num_iterations):
        #前向传播
        A1, cache1 = linear_activation_forward(X, W1, b1, "relu")
        A2, cache2 = linear_activation_forward(A1, W2, b2, "sigmoid")
        
        #计算成本
        cost = compute_cost(A2,Y)
        
        #反向传播
        dA2 = - (np.divide(Y, A2) - np.divide(1 - Y, 1 - A2))
        
        #反向传播,输入:“dA2,cache2,cache1”。 输出:“dA1,dW2,db2;还有dA0(未使用),dW1,db1”。
        dA1, dW2, db2 = linear_activation_backward(dA2, cache2, "sigmoid")
        dA0, dW1, db1 = linear_activation_backward(dA1, cache1, "relu")
        
        #反向传播完成后的数据保存到grads
        grads["dW1"] = dW1
        grads["db1"] = db1
        grads["dW2"] = dW2
        grads["db2"] = db2
        
        #更新参数
        parameters = update_parameters(parameters,grads,learning_rate)
        W1 = parameters["W1"]
        b1 = parameters["b1"]
        W2 = parameters["W2"]
        b2 = parameters["b2"]
        
        #打印成本值
        if i % 100 == 0:
            #记录成本
            costs.append(cost)
            #是否打印成本值
            if print_cost:
                print("第", i ,"次迭代,成本值为:" ,np.squeeze(cost))
    #迭代完成,根据条件绘制图
    if isPlot:
        plt.plot(np.squeeze(costs))
        plt.ylabel('cost')
        plt.xlabel('iterations (per tens)')
        plt.title("Learning rate =" + str(learning_rate))
        plt.show()
    
    #返回parameters
    return parameters

Восемь, постройте нейронную сеть L-слоя.

# L层神经网络模型
def L_layer_model(X, Y, layers_dims, learning_rate=0.0075, num_iterations=3000, print_cost=False,isPlot=True):
    np.random.seed(1)
    costs = []
    parameters = initialization_deep(layers_dims)
    
    for i in range(0, num_iterations):
        AL , caches = L_model_forward(X,parameters)
        cost = compute_cost(AL,Y)
        grads = L_model_backward(AL,Y,caches)
        parameters = update_parameters(parameters,grads,learning_rate)
        #打印成本值,如果print_cost=False则忽略
        if i % 100 == 0:
            #记录成本
            costs.append(cost)
            #是否打印成本值
            if print_cost:
                print("第", i ,"次迭代,成本值为:" ,np.squeeze(cost))
    #迭代完成,根据条件绘制图
    if isPlot:
        plt.plot(np.squeeze(costs))
        plt.ylabel('cost')
        plt.xlabel('iterations (per tens)')
        plt.title("Learning rate =" + str(learning_rate))
        plt.show()
    return parameters

9. Функция прогнозирования

# 预测
def predict(X, y, parameters):
    m = X.shape[1]
    n = len(parameters) // 2 
    p = np.zeros((1,m))
    #根据参数前向传播
    probas, caches = L_model_forward(X, parameters)
    
    for i in range(0, probas.shape[1]):
        # 概率的四舍五入判断是否为猫
        if probas[0,i] > 0.5:
            p[0,i] = 1
        else:
            p[0,i] = 0
    
    print("准确度为: "  + str(float(np.sum((p == y))/m)))
    return p

Десять, двухслойный тест нейронной сети

# 两层神经网络测试
n_x = 12288
n_h = 7
n_y = 1
layers_dims = (n_x,n_h,n_y)

parameters = two_layer_model(train_x1, train_y, layers_dims = (n_x, n_h, n_y), learning_rate = 0.0075, num_iterations = 2500, print_cost=True, isPlot=True)
第 0 次迭代,成本值为: 0.7063761340884793
第 100 次迭代,成本值为: 0.6419469811594473
第 200 次迭代,成本值为: 0.6208666114090164
第 300 次迭代,成本值为: 0.5933708778671708
第 400 次迭代,成本值为: 0.5603947807293141
第 500 次迭代,成本值为: 0.52507577356433
第 600 次迭代,成本值为: 0.48483872973856995
第 700 次迭代,成本值为: 0.43879411822651754
第 800 次迭代,成本值为: 0.38704167645831195
第 900 次迭代,成本值为: 0.333046068471014
第 1000 次迭代,成本值为: 0.2806951051341951
第 1100 次迭代,成本值为: 0.23217499051903273
第 1200 次迭代,成本值为: 0.19121167548582782
第 1300 次迭代,成本值为: 0.16152294268990633
第 1400 次迭代,成本值为: 0.1269867481897763
第 1500 次迭代,成本值为: 0.10258796371356442
第 1600 次迭代,成本值为: 0.08479208245264541
第 1700 次迭代,成本值为: 0.07013694938988196
第 1800 次迭代,成本值为: 0.05924202127477445
第 1900 次迭代,成本值为: 0.05064065400193104
第 2000 次迭代,成本值为: 0.04377464932374992
第 2100 次迭代,成本值为: 0.038263203798063965
第 2200 次迭代,成本值为: 0.03378462039921001
第 2300 次迭代,成本值为: 0.03007443521321217
第 2400 次迭代,成本值为: 0.02698793871455636

在这里插入图片描述

predictions_train = predict(train_x1, train_y, parameters) #训练集
predictions_test = predict(test_x1, test_y, parameters) #测试集
准确度为: 1.0
准确度为: 0.68
  • При анализе ошибок глубокого обучения точность ниже на наборе разработки/тестирования, на самом деле этовысокая дисперсия.

Одиннадцать, L-слойный тест нейронной сети

layers_dims = [12288, 20, 7, 5, 1] #  5-layer model
parameters = L_layer_model(train_x1, train_y, layers_dims, learning_rate = 0.0075, num_iterations = 3000, print_cost = True, isPlot=True)
第 0 次迭代,成本值为: 0.7717493284237686
第 100 次迭代,成本值为: 0.6720534400822913
第 200 次迭代,成本值为: 0.6482632048575212
第 300 次迭代,成本值为: 0.6115068816101354
第 400 次迭代,成本值为: 0.567047326836611
第 500 次迭代,成本值为: 0.5401376634547801
第 600 次迭代,成本值为: 0.5279299569455267
第 700 次迭代,成本值为: 0.4654773771766852
第 800 次迭代,成本值为: 0.369125852495928
第 900 次迭代,成本值为: 0.3917469743480534
第 1000 次迭代,成本值为: 0.31518698886006163
第 1100 次迭代,成本值为: 0.2726998441789384
第 1200 次迭代,成本值为: 0.23741853400268131
第 1300 次迭代,成本值为: 0.19960120532208644
第 1400 次迭代,成本值为: 0.18926300388463305
第 1500 次迭代,成本值为: 0.1611885466582775
第 1600 次迭代,成本值为: 0.14821389662363316
第 1700 次迭代,成本值为: 0.13777487812972938
第 1800 次迭代,成本值为: 0.1297401754919012
第 1900 次迭代,成本值为: 0.12122535068005211
第 2000 次迭代,成本值为: 0.1138206066863371
第 2100 次迭代,成本值为: 0.10783928526254133
第 2200 次迭代,成本值为: 0.10285466069352682
第 2300 次迭代,成本值为: 0.10089745445261784
第 2400 次迭代,成本值为: 0.09287821526472397
第 2500 次迭代,成本值为: 0.0884125117761504
第 2600 次迭代,成本值为: 0.08595130416146428
第 2700 次迭代,成本值为: 0.08168126914926334
第 2800 次迭代,成本值为: 0.07824661275815534
第 2900 次迭代,成本值为: 0.07544408693855481

在这里插入图片描述

predictions_train = predict(train_x1, train_y, parameters) #训练集
predictions_test = predict(test_x1, test_y, parameters) #测试集
准确度为: 0.9904306220095693
准确度为: 0.82

12. Отображение неправильно классифицированных изображений для анализа

def print_mislabeled_images(classes, X, y, p):
    a = p + y
    mislabeled_indices = np.asarray(np.where(a == 1))
    plt.rcParams['figure.figsize'] = (40.0, 40.0) # set default size of plots
    num_images = len(mislabeled_indices[0])
    for i in range(num_images):
        index = mislabeled_indices[1][i]
        
        plt.subplot(2, num_images, i + 1)
        plt.imshow(X[:,index].reshape(64,64,3), interpolation='nearest')
        plt.axis('off')
        plt.title("Prediction: " + classes[int(p[0,index])].decode("utf-8") + " \n Class: " + classes[y[0,index]].decode("utf-8"))
print_mislabeled_images(classes, test_x1, test_y, predictions_test)

在这里插入图片描述

  • Можно видеть, что такие факторы, как размытие изображения, смещение положения объекта и большое количество света и тени, могут привести к ошибкам в оценке системы, поэтому вы можете выбрать большую часть из них для оптимизации.

13. Предскажите свою собственную картину

my_image = "cat.jpg"
my_label = [1]
fname = "./" + my_image
image = np.array(plt.imread(fname))
my_image = np.array(Image.fromarray(image).resize(size=(num_px,num_px))).reshape((1, num_px*num_px*3)).T
my_predicted_image = predict(my_image, my_label, parameters)

plt.imshow(image)
print ("y = " + str(np.squeeze(my_predicted_image)) + ", your L-layer model predicts a \"" + classes[int(np.squeeze(my_predicted_image)),].decode("utf-8") +  "\" picture.")
准确度为: 1.0
y = 1.0, your L-layer model predicts a "cat" picture.

在这里插入图片描述Не паникуйте, если вы выбрасываете изображение, отличное от кошки, и идентифицируете его как изображение кошки.Для этого набора данных, даже если он хорошо влияет на обучающий набор и набор для разработки/тестирования, на самом деле, на наш реальный тестовый набор ( Пользовательские картинки) Точность совершенно недостижимая! На таком небольшом наборе данных написание модели DNN больше связано с знакомством с внутренней структурой глубокой нейронной сети и применением теоретических знаний о глубоком обучении на практике. Это то же предложение: изучение теоретических знаний является ядром.Изучив принципы реализации нейронных сетей, вы сможете лучше понять, как оптимизировать нейронные сети.在这里插入图片描述 在这里插入图片描述