吴恩达深度学习编程作业(1-1):Logistic Regression with a Neural Network mindset

  本次编程作业对应的完整代码实现(Python版本) → Github链接

1. 作业简介

  本次作业的内容是使用Logistic回归通过训练来判断一副图像是否为猫。
  主要内容:如何利用Python的来实现Logistic函数。包括:初始化、计算代价函数和梯度、使用梯度下降算法进行优化等并把他们整合成为一个函数。

2. 工具包

  在这个过程中,我们将会用到如下库:

  • numpy:Python科学计算中最重要的库;
  • h5py:Python与H5文件交互的库;
  • mathplotlib:Python画图的库;
  • PIL:Python图像相关的库;
  • scipy:Python科学计算相关的库。

3. 数据集

3.1 数据说明

  对于训练集的标签而言,如果是猫,标记为1,否则标记为0。每一个图像的维度都是(num_px, num_px, 3),其中,长宽相同,3表示是RGB图像。train_set_x_orig和test_set_x_orig中,包含_orig是由于我们稍候需要对图像进行预处理,预处理后的变量将会命名为train_set_x和train_set_y,train_set_x_orig中的每一个元素对于这一副图像。

3.2 数据预处理

  接下来为了方便会对输入数据集的维度进行调整,由原来的(209,64,64,3)调整到 (12288,209),经过这样的调整之后 ,数据集中的每一列都代表了一张图片,所以这里应该有m_train列 。
  为了代表彩色图像,需要RGB3个通道,每个通道的像素值都是0-255。在机器学习中预处理的常见步骤就是数据中心化和标准化,常用的处理方法是对于每个样本都减去均值,然后再除以整个矩阵的标准差。但是在图像中有一种简单的额归一化方法,效果也不错,就是每个样本都除以255(每个通道像素的最大值)。
  具体步骤:1)弄清楚要处理的数据集的大小和形状;
       2)重塑一些数据集的形状;
       3)“标准化”数据。

4. Logistics介绍

在这里插入图片描述
  对于每个训练样本x,其误差函数的计算方式如下:
z ( i ) = w T x ( i ) + b z^{(i)}=w^{T}x^{(i)}+b z(i)=wTx(i)+b y ^ ( i ) = a ( i ) = s i g m o i d ( z ( i ) ) \hat{y}^{(i)}=a^{(i)}=sigmoid(z^{(i)}) y^(i)=a(i)=sigmoid(z(i)) L ( a ( i ) , y ( i ) ) = − y ( i ) l o g ( a ( i ) ) − ( 1 − y ( i ) ) l o g ( 1 − a ( i ) ) L(a^{(i)},y^{(i)})=-y^{(i)}log(a^{(i)})-(1-y^{(i)})log(1-a^{(i)}) L(a(i),y(i))=y(i)log(a(i))(1y(i))log(1a(i))  而整体的代价函数计算如下: J = 1 m ∑ i = 1 m L ( a ( i ) , y ( i ) ) J=\frac{1}{m}\sum ^{m}_{i=1}L(a^{(i)},y^{(i)}) J=m1i=1mL(a(i),y(i))

5. 创建算法

5.1 算法的创建基本流程

  1. 定义模型的架构(比如输入特征的数量)
  2. 初始化模型参数
  3. 循环
    1)计算当前损失(正向传播)
    2)计算当前梯度(反向传播)
    3)更新参数(梯度下降)
  4. 通常我们会分别实现1-3三个步骤,并且最终放在一个函数model ()中。

5.2 程序实现步骤

  • step1:实现sigmod函数
  • step2:初始化参数
  • step3:前向传播与反向传播
         计算公式如下: 得 到 X                                                                                                                                                                   计 算 A = σ ( w T X + b ) = ( a ( 0 ) , a ( 1 ) , . . . , a ( m − 1 ) , a ( m ) )                                         计 算 代 价 函 数 J = − 1 m ∑ i = 1 m y ( i ) l o g ( a ( i ) ) + ( 1 − y ( i ) ) l o g ( 1 − a ( i ) ) \begin{matrix} 得到X\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\\ 计算A=\sigma (w^{T}X+b)=(a^{(0)},a^{(1)},...,a^{(m-1)},a^{(m)})\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\\ 计算代价函数J=-\frac{1}{m}\sum ^{m}_{i=1}y^{(i)}log(a^{(i)})+(1-y^{(i)})log(1-a^{(i)}) \end{matrix} X                                                                                 A=σ(wTX+b)=(a(0),a(1),...,a(m1),a(m))                    J=m1i=1my(i)log(a(i))+(1y(i))log(1a(i)) ∂ J ∂ w = 1 m X ( A − Y ) T \frac{\partial J}{\partial w}=\frac{1}{m}X(A-Y)^{T} wJ=m1X(AY)T ∂ J ∂ b = 1 m ∑ i = 1 m ( a ( i ) − y ( i ) ) \frac{\partial J}{\partial b}=\frac{1}{m}\sum ^{m}_{i=1}(a^{(i)}-y^{(i)}) bJ=m1i=1m(a(i)y(i))
  • step4:更新参数(参数优化)
    更新参数的公式如下:
    θ = θ − α d θ , w h e r e   α   i s   t h e   l e a r n i n g   r a t e . \theta=\theta - \alpha d\theta,where\ _{}\alpha\ _{}is\ _{}the\ _{}learning\ _{}rate. θ=θαdθ,where α is the learning rate.
  • step5:利用训练好的模型对测试集进行预测
    计算公式如下: Y ^ = A = σ ( w T X + b ) \hat{Y}=A=\sigma (w^{T}X+b) Y^=A=σ(wTX+b)当输出大于0.5时,我们认为其预测认为结果是猫,否则不是猫。
  • step6:将以上功能整合到一个模型中

    在这里插入图片描述
      训练的准确性接近100%,测试的准确性为70%,说明出现了过拟合的情况。

6. 学习率优化

  学习率的选取决定了学习的快慢,实际情况我们需要尝试许多种学习率,最终选取效果最好的。
  为了让梯度下降起作用,我们必须明智地选择学习速率。学习率α决定了我们更新参数的速度。如果学习率过高,我们可能会“超过”最优值。同样,如果它太小,我们将需要太多迭代才能收敛到最佳值。这就是为什么使用良好调整的学习率至关重要的原因。

在这里插入图片描述
  不同的学习率能够产生不同的代价从而导致不同的预测结果。学习率如果过大就会导致代价上下震荡(尽管在上面的例子中得到了很好的结果)。学习率越小并不意味着学习到的模型更好,你需要检查是否出现了过拟合,也就是训练的准确性远远高于测试的准确性。

7. 实现代码

  • ex1.py
# import library we need
import numpy as np
import matplotlib.pyplot as plt
import imageio
from skimage.transform import resize
from lr_utils import load_dataset


'### 加载数据集'
# Loading the data (cat/non-cat)
train_set_x_orig, train_set_y, test_set_x_orig, test_set_y, classes = load_dataset()


'### 数据预处理(一般步骤):'
# 1、识别数据集的大小和形状
# 2、重塑一些数据的形状
# 3、“标准化”数据

# Figure out the dimensions and shapes of the problem (m_train, m_test, num_px, ...)
m_train = train_set_x_orig.shape[0]  # m_train = 209
m_test = test_set_x_orig.shape[0]  # m_test = 50
num_px = train_set_x_orig[0].shape[0]  # Height/Width of each image: num_px = 64
# Each image is of size: (64, 64, 3)
# train_set_x shape: (209, 64, 64, 3) = (209, 12288)
# train_set_y shape: (1, 209)
# test_set_x shape: (50, 64, 64, 3) = (50, 12288)
# test_set_y shape: (1, 50)

# Reshape the training and test examples
# X_flatten = X.reshape(X.shape[0], -1).T      # X.T is the transpose of X
train_set_x_flatten = train_set_x_orig.reshape(m_train,-1).T  # train_set_x_flatten shape:(12288, 209)
test_set_x_flatten = test_set_x_orig.reshape(m_test, -1).T  # test_set_x_flatten shape: (12288, 50)

# standardize our dataset(Image normalization)
train_set_x = train_set_x_flatten / 255.
test_set_x = test_set_x_flatten / 255.


'### 算法的创建基本流程是:'
#  1、定义模型的架构(比如输入特征的数量)
#  2、初始化模型参数
#  3、循环
#     1)前向传播计算当前的代价函数
#     2)反向传播计算当前的梯度
#     3)使用梯度下降的方法更新参数
#   4、分别实现1-3三个步骤,并且最终放在一个函数model ()中

# GRADED FUNCTION: sigmoid
# Step1:实现sigmod函数
def sigmoid(z):
    """
    参数:
        z  - 任何大小的标量或numpy数组。
    
    返回:
        s  -  sigmoid(z)
    """
    s = 1 / (1 + np.exp(-z))
    return s


# GRADED FUNCTION: initialize_with_zeros
# Step2:初始化参数w、b
def initialize_with_zeros(dim):
    """
        此函数为w创建一个维度为(dim,1)的0向量,并将b初始化为0。
        
        参数:
            dim  - 我们想要的w矢量的大小(或者这种情况下的参数数量)
        
        返回:
            w  - 维度为(dim,1)的初始化向量。
            b  - 初始化的标量(对应于偏差)
    """
    w = np.zeros((dim, 1))  # w的维度是(dim,1),dim = (num_px *num_px *3, 1)
    b = 0
    assert (w.shape == (dim, 1))   # assert()断言函数是为了检测一下是否正常,来确保我要的数据是正确的
    assert (isinstance(b, float) or isinstance(b, int))  # b的类型是float或者是int
    return w, b


# GRADED FUNCTION: propagate
# Step3:前向传播与反向传播
def propagate(w, b, X, Y):
    """
    实现前向和后向传播的成本函数及其梯度。
    参数:
        w  - 权重,大小不等的数组(num_px * num_px * 3,1)
        b  - 偏差,一个标量
        X  - 矩阵类型为(num_px * num_px * 3,训练数量)
        Y  - 真正的“标签”矢量(如果非猫则为0,如果是猫则为1),矩阵维度为(1,训练数据数量)

    返回:
        cost- 逻辑回归的负对数似然成本
        dw  - 相对于w的损失梯度,因此与w相同的形状
        db  - 相对于b的损失梯度,因此与b的形状相同
    """
    m = X.shape[1]
    # 正向传播
    A = sigmoid(np.dot(w.T, X) + b)
    cost = -1 / m * np.sum(np.multiply(Y, np.log(A)) + np.multiply(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)
    cost = np.squeeze(cost)  # 从数组的形状中删除单维条目,即把shape中为1的维度去掉
    assert (cost.shape == ())
    # 创建一个字典,把dw和db保存起来
    grads = {"dw": dw, "db": db}
    return grads, cost


# GRADED FUNCTION: optimize
# Step4:参数更新(优化)
def optimize(w, b, X, Y, num_iterations, learning_rate, print_cost=False):
     """
    此函数通过运行梯度下降算法来优化w和b
    
    参数:
        w  - 权重,大小不等的数组(num_px * num_px * 3,1)
        b  - 偏差,一个标量
        X  - 维度为(num_px * num_px * 3,训练数据的数量)的数组。
        Y  - 真正的“标签”矢量(如果非猫则为0,如果是猫则为1),矩阵维度为(1,训练数据的数量)
        num_iterations  - 优化循环的迭代次数
        learning_rate  - 梯度下降更新规则的学习率
        print_cost  - 每100步打印一次损失值
    
    返回:
        params  - 包含权重w和偏差b的字典
        grads  - 包含权重和偏差相对于成本函数的梯度的字典
        成本 - 优化期间计算的所有成本列表,将用于绘制学习曲线。
    
    提示:
    我们需要写下两个步骤并遍历它们:
        1)计算当前参数的成本和梯度,使用propagate()。
        2)使用w和b的梯度下降法则更新参数。
    """
     costs = []
     for i in range(num_iterations):
         grades, cost = propagate(w, b, X, Y)
         dw = grades["dw"]
         db = grades["db"]
         w = w - learning_rate * dw
         b = b - learning_rate * db

         if i % 100 == 0:  # 每迭代100次更新一次参数
             costs.append(cost)
         if print_cost and i % 100 == 0:
             print("Cost after iteration %i: %f" % (i, cost))

     params = {"w": w, "b": b}

     grads = {"dw": dw, "db": db}

     return params, grads, costs


# GRADED FUNCTION: predict
# Step5:利用训练好的模型对测试集进行预测
def predict(w, b, X):
     """
    使用学习逻辑回归参数logistic (w,b)预测标签是0还是1
    
    参数:
        w  - 权重,大小不等的数组(num_px * num_px * 3,1)
        b  - 偏差,一个标量
        X  - 维度为(num_px * num_px * 3,训练数据的数量)的数据
    
    返回:
        Y_prediction  - 包含X中所有图片的所有预测【0 | 1】的一个numpy数组(向量)
    
    """
     m = X.shape[1]
     Y_prediction = np.zeros((1, m))
     w = w.reshape(X.shape[0], 1)
     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] = 1
         else:
             Y_prediction[0, i] = 0

     assert (Y_prediction.shape == (1, m))
     return Y_prediction


# GRADED FUNCTION: model
# Step6:将以上功能整合到一个模型中
def model(X_train, Y_train, X_test, Y_test, num_iterations=2000, learning_rate=0.5, print_cost=False):
    """
    通过调用之前实现的函数来构建逻辑回归模型
    
    参数:
        X_train  - numpy的数组,维度为(num_px * num_px * 3,m_train)的训练集
        Y_train  - numpy的数组,维度为(1,m_train)(矢量)的训练标签集
        X_test   - numpy的数组,维度为(num_px * num_px * 3,m_test)的测试集
        Y_test   - numpy的数组,维度为(1,m_test)的(向量)的测试标签集
        num_iterations  - 表示用于优化参数的迭代次数的超参数
        learning_rate  - 表示optimize()更新规则中使用的学习速率的超参数
        print_cost  - 设置为true以每100次迭代打印成本
    
    返回:
        d  - 包含有关模型信息的字典。
    """
    w, b = np.zeros((X_train.shape[0], 1)), 0  # 初始化参数w、b
    parameters, grads, costs = optimize(w, b, X_train, Y_train, num_iterations, learning_rate, print_cost)  # 优化参数
    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


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

'### 把训练好的模型参数储存起来'
# 先创建并打开一个文本文件
file = open('模型参数.txt', 'w')
# 遍历字典的元素,将每项元素的key和value分拆组成字符串,注意添加分隔符和换行符
for k, v in d.items():
    file.write(str(k) + ':' + str(v) + '\n')
# 注意关闭文件
file.close()

'### 测试集中具体的图片预测情况'
index = 40
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.")
plt.show()

# Plot learning curve (with costs)
costs = np.squeeze(d['costs'])
plt.plot(costs)
plt.ylabel('cost')
plt.xlabel('iterations (per hundreds)')
plt.title("Learning rate =" + str(d["learning_rate"]))
plt.show()

# # 学习率优化 learning_rates = [0.01, 0.001, 0.0001] models = {} for i in learning_rates: print("learning rate is: " +
# str(i)) models[str(i)] = model(train_set_x, train_set_y, test_set_x, test_set_y, num_iterations=1500,
# learning_rate=i, print_cost=False)
# print('\n' + "-------------------------------------------------------" + '\n')
#
# for i in learning_rates:
#     plt.plot(np.squeeze(models[str(i)]["costs"]), label=str(models[str(i)]["learning_rate"]))  # 设置图例(legend)的标
#
# plt.ylabel('cost')
# plt.xlabel('iterations')
#
# legend = plt.legend(loc='upper center', shadow=True)  # legend显示图例 # shadow设置背景为灰色
# frame = legend.get_frame()  # get_frame() 返回legend所在的方形对象 # 获得背景
# frame.set_facecolor('0.90')  # 设置图例legend背景透明度
# plt.show()


# 测试自己的图片
my_image = "16.jpg"  # change this to the name of your image file

# We preprocess the image to fit your algorithm.
fname = "C:/Users/123/Pictures/" + my_image
image = np.array(imageio.imread(fname))

my_image = resize(image, output_shape=(num_px,num_px)).reshape((1, num_px*num_px*3)).T
# my_image = my_image / 255.
my_predicted_image = predict(d["w"], d["b"], my_image)

plt.imshow(image)
print("y = " + str(np.squeeze(my_predicted_image)) + ", your algorithm predicts a \""
      + classes[int(np.squeeze(my_predicted_image)),].decode("utf-8") + "\" picture.")
plt.show()
  • test_program.py
import numpy as np
import h5py
    
def load_dataset():
    train_dataset = h5py.File('datasets/train_catvnoncat.h5', "r")
    train_set_x_orig = np.array(train_dataset["train_set_x"][:]) # your train set features
    train_set_y_orig = np.array(train_dataset["train_set_y"][:]) # your train set labels

    test_dataset = h5py.File('datasets/test_catvnoncat.h5', "r")
    test_set_x_orig = np.array(test_dataset["test_set_x"][:]) # your test set features
    test_set_y_orig = np.array(test_dataset["test_set_y"][:]) # your test set labels

    classes = np.array(test_dataset["list_classes"][:]) # the list of classes
    
    train_set_y_orig = train_set_y_orig.reshape((1, train_set_y_orig.shape[0]))
    test_set_y_orig = test_set_y_orig.reshape((1, test_set_y_orig.shape[0]))
    
    return train_set_x_orig, train_set_y_orig, test_set_x_orig, test_set_y_orig, classes
  • Ir_utils.py
import numpy as np
import matplotlib.pyplot as plt
import imageio
from skimage.transform import resize


# 声明一个空字典,来保存文本文件数据
dict_temp = {}
# 打开文本文件
file = open('模型参数.txt','r')
# 遍历文本文件的每一行,strip可以移除字符串头尾指定的字符(默认为空格或换行符)或字符序列
for line in file.readlines():
    line = line.strip()
    k = line.split(' ')[0]
    v = line.split(' ')[1]
    dict_temp[k] = v
# 依旧是关闭文件
f.close()
print(dict_temp)


'# 测试自己的图片'
## START CODE HERE ## (PUT YOUR IMAGE NAME)
my_image = "16.jpg"  # change this to the name of your image file

# We preprocess the image to fit your algorithm.
fname = "C:/Users/123/Pictures/" + my_image
image = np.array(imageio.imread(fname))

my_image = resize(image, output_shape=(num_px,num_px)).reshape((1, num_px*num_px*3)).T
# my_image = my_image / 255.
my_predicted_image = predict(d["w"], d["b"], my_image)

plt.imshow(image)
print("y = " + str(np.squeeze(my_predicted_image)) + ", your algorithm predicts a \""
      + classes[int(np.squeeze(my_predicted_image)),].decode("utf-8") + "\" picture.")
plt.show()
  • 5
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值