Logistic Regression with a Neural Network mindset

文章内容为吴恩达深度学习第二周的编程作业

**ipynbg格式代码及数据集-->陈能豆 **
密码: o1bn

#!/usr/bin/env python
# coding: utf-8

# # 吴恩达深度学习第二周编程作业

# ## 题目部分

# 先来看一下 英文的题目部分

# Logistic Regression with a Neural Network mindset
# Welcome to your first (required) programming assignment! You will build a logistic regression classifier to recognize cats. This assignment will step you through how to do this with a Neural Network mindset, and so will also hone your intuitions about deep learning.
# 
# Instructions:
# 
# Do not use loops (for/while) in your code, unless the instructions explicitly ask you to do so.
# You will learn to:
# 
# Build the general architecture of a learning algorithm, including:
# Initializing parameters
# Calculating the cost function and its gradient
# Using an optimization algorithm (gradient descent)
# Gather all three functions above into a main model function, in the right order.

# ### 简单解释一下要求  
# 要求我们建议一个逻辑回归分类器来识别猫的图片  
# 
# #### 要求如下:  
# * 不要在代码中使用循环(for/while),除非指令明确要求您这样做。  
# 
# * 算法的架构如下:  
# 1. 参数初始化  
# 2. 成本函数及梯度的计算  
# 3. 优化算法  
# 
# 你需要编写上面提到的方法,并进行组合,成为一个模型
# 
# #### 数据集概述
# 这里会提供给我们一个数据集,名字为”data.h5“(和下面代码用的是同一个数据集,不过名字改成了”train_catvnoncat.h5“)  
# 里面包含了相关数据集,更具体的可以看代码的数据导入方法。 
# 主要包括:  
# 1. 标签设置好的训练集,标记是否为cat(0/1)  
# 2. 标签设置好的测试集  
# 3. 图片的形状为(64, 64, 3)  
# 
# 
# 数据集及代码附上链接--> [陈能豆](https://pan.baidu.com/s/1VMCuVU8IKWLycKM6B20O_g)  
# 提取密码:q73d
# 
# #### ok  下面看代码
# 

# In[98]:


# pip --version   # 这里看一下python的版本  ,3.6 以及别的版本应该也是可行的   


# ### 代码部分

# #### 代码段后面附上相关重点提示 
# #### 相关函数用法 不会的百度

# In[197]:


import numpy as np
import matplotlib.pyplot as plt
import h5py
import random
# 下面两个用于测试模型 
from PIL import Image
import imageio


# 导入相关包

# In[198]:


# 导入数据函数
def load_datasets():
    
    train_datasets = h5py.File('datasets/train_catvnoncat.h5',"r")
    train_set_x_origi = np.array(train_datasets["train_set_x"][:])
    train_set_y_origi = np.array(train_datasets["train_set_y"][:])
    # 读取训练集
    
    
    test_datasets = h5py.File('datasets/test_catvnoncat.h5',"r")
    test_set_x_origi = np.array(test_datasets["test_set_x"][:])
    test_set_y_origi = np.array(test_datasets["test_set_y"][:])
    # 测试集
    
    
    classes = np.array(test_datasets["list_classes"][:])
    # 存储可能的结果   0 non-cat  1  cat
    
    # 初始化矩阵格式
    train_set_y_origi = train_set_y_origi.reshape( (1,train_set_y_origi.shape[0]) )
    test_set_y_origi = test_set_y_origi.reshape( (1,test_set_y_origi.shape[0]) )
    
    return train_set_x_origi,train_set_y_origi,test_set_x_origi,test_set_y_origi,classes
    
    


# 从数据集中导入数据  其中classes 用于存储可能的结果  
# classes: array([b'non-cat', b'cat'], dtype='|S7')

# In[199]:


# 读入数据
train_set_x_origi,train_set_y,test_set_x_origi,test_set_y,classes = load_datasets()


# In[200]:


# 显示一下训练集的数据
index = random.randint(1,train_set_y.shape[1])

plt.imshow(train_set_x_origi[index])
# 打印图片

# 打印结果
print( "The picture number is " +str(index) + "  The ans is " +classes[ np.squeeze(train_set_y[:,index])].decode("utf-8") )

print("使用np.squeeze:" + str(np.squeeze(train_set_y[:,index])) )
print("不使用np.squeeze: " + str(train_set_y[:,index])  )


# 显示的是数据集中随机的一张图片及结果
# 可改为指定编号  
# squeeze 函数的作用为压缩维度  
# 是否使用squeeze的区别见代码
# 

# In[201]:


# 查看矩阵维数
im_number_train = train_set_y.shape[1]
im_number_test = test_set_y.shape[1]
im_size = train_set_x_origi.shape[1]

# 打印
print("训练集图片数量: "+str(im_number_train))
print("测数集图片数量: "+str(im_number_test))
print("图片宽度高度为: "+str(im_size))
print("每张图片大小为" +str(im_size)+","+str(im_size)+",3")
print("训练集x维数为 "+str(train_set_x_origi.shape))
print("训练集y维数为 "+str(train_set_y.shape))
print("测试集x维数为 "+str(test_set_x_origi.shape))
print("测试集y维数为 "+str(test_set_y.shape))


# shaape 函数 返回矩阵维数  
# 返回数据类型为n元组   可通过下标引用

# In[202]:


# 降维  数据预处理
train_set_x_flatten = train_set_x_origi.reshape(train_set_x_origi.shape[0],-1).T
test_set_x_flatten = test_set_x_origi.reshape(test_set_x_origi.shape[0],-1).T

# 打印降维后的维数

print("训练集降维后的维数为 "+str(train_set_x_flatten.shape))
print("测试集降维后的维数为 "+str(test_set_x_flatten.shape))


# reshape 函数用于改变矩阵维数  
# -1 表示 自动计算下一维度   

# In[203]:


# 核对维数
print("训练集x的位数为 "+str(train_set_x_flatten.shape))
print("训练集y维数为 "+str(train_set_y.shape))
print("测试集x的维数为 "+str(test_set_x_flatten.shape))
print("测试集y维数为 "+str(test_set_y.shape))


# In[204]:


# 数据标准化
# 图片存储的值为像素值    0-255
# 例如数据集中
print(np.amax(train_set_x_flatten))
print(np.amin(train_set_x_flatten))

train_set_x = train_set_x_flatten/255
test_set_x = test_set_x_flatten/255


# In[205]:


def sigmoid(z):
    # 参数为z数组
    
    # 返回s = sigmoid(z)
    
    s = 1/(1+np.exp(-z))
    
    return s


# 激活函数有很多种    
# ![image.png](attachment:image.png "激活函数")

# In[206]:


# 测试siggmod 函数 是否符合预期
print( "sigmoid(0) = "+str(sigmoid(0)))
print( "sigmoid(1) = "+str(sigmoid(1)))
print( "sigmoid(10) = "+str(sigmoid(10)))
print( "sigmoid(-1) = "+str(sigmoid(-1)))
print( "sigmoid(-10) = "+str(sigmoid(-10)))


# In[207]:


def initialize_zeros_vector(size): 
    # 函数作用 生成 并返回一个(size,1) 的0向量  同时初始化 b=0
    
    
    w = np.zeros( (size,1) )
    b = 0
    
    # 断言确保维数
    assert( w.shape== (size,1) )
    assert( isinstance(b,float) or isinstance(b,int) )
    
    return (w , b)

    


# In[208]:


def  two_way_propogate(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)
    cost = np.squeeze(cost)
    
    # 存储dw db
    grads = {
        "dw":dw,
        "db":db
    }
    
    return grads, cost

    
    


# ### 这里附上课程中求导计算过程中的部分截图,便于理解  
# 向量化之前:   
# ![image.png](attachment:image.png)
# 向量化后:  
# ![image.png](attachment:image.png)

# In[209]:


# 测试 two_way_propogate 
# 随便初始化一些参数
W ,b ,X, Y = np.array([ [2],[2] ]),2,np.array([ [1,0],[0,0] ]),np.array([0,0])
grabs, cost = two_way_propogate(W,b,X,Y)
print("dw = " + str(grabs["dw"]))
print("db = " + str(grabs["db"]))
print("cost = " + str(cost))
# 迭代一次 看效果如何
learning_rate = 0.1
W = W -learning_rate*grabs["dw"]
b= b- learning_rate * grabs["db"]
grads, cost = two_way_propogate(W,b,X,Y)
print("迭代一次后")
print("dw = " + str(grabs["dw"]))
print("db = " + str(grabs["db"]))
print("cost = " + str(cost))


# In[210]:


def optimize( W , b , X , Y , num_iteration , learning_rate , print_cost=False , print_frequency = 100):
    # 该函数作用 运用梯度下降优化W 和b
    # 参数描述放在下面 
    """
    此函数通过运行梯度下降算法来优化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_iteration):
        grads , cost = two_way_propogate( W , b, X , Y )
        
        dw = grads["dw"]
        db = grads["db"]
        W = W- dw * learning_rate
        b = b- db * learning_rate
        
        if(i%print_frequency==0):
            costs.append(cost)
        
        
        if(print_cost and i%print_frequency==0):
            print("迭代次数为:%i , 误差值为:  %f" % (i,cost))
    
    
    params = {
        "W": W,
        "b": b
    }
    
    grads = {
        "dw": dw,
        "db": db
    }
    
    return (params , grabs , costs)



#         w  - 权重矩阵
#         b  - 偏差值  一个数
#         X  - 维度为 训练集
#         Y  - 训练标签集 真正的“标签”矢量(如果非猫则为0,如果是猫则为1),矩阵维度为(1,训练数据的数量)
#         num_iterations  - 优化循环的迭代次数
#         learning_rate  - 梯度下降更新规则的学习率
#         print_cost  - 是否打印cost
#         print_frequency - 打印频率,迭代多少次打印一次cost

# In[211]:


# 测试 optimize
W, b, X, Y = np.array([[2], [3]]), 3, np.array([[0,1], [2,2]]), np.array([[0, 2]])
params , grads , costs = optimize(W , b , X , Y , num_iteration=100 , learning_rate = 0.009)
print ("w = " + str(params["W"]))
print ("b = " + str(params["b"]))
print ("dw = " + str(grads["dw"]))
print ("db = " + str(grads["db"]))


# In[212]:


def predict(W , b , X):
    
    # 根据参数 预测结果
    
    m = X.shape[1]
    
    # 这里参数的维度假设是符合的  不需要判断
    
    A = sigmoid( np.dot(W.T,X )+b)
    
    assert(A.shape==(1,m))
    for i in range(A.shape[1]):
        
        A[0,i] = 1 if A[0,i] >0.5  else 0
    # 默认0.5为临界值 
    
    assert(A.shape==(1,m) )
    
    return A
    


# 这里的0.5 可以修改为一个指定的临界值    或设置为参数

# In[213]:


# 测试predict
w, b, X, Y = np.array([[1], [2]]), 2, np.array([[1,2], [3,4]]), np.array([[1, 0]])
print("predictions = " + str(predict(w, b, X)))


# In[214]:


def model ( X_train , Y_train , X_test , Y_test , num_iterations = 2000 , learning_rate = 0.5, print_cost = False , print_frequency = 100):
    
    
    W , b = initialize_zeros_vector(X_train.shape[0])
    parameters , grabs , costs = optimize(W , b , X_train , Y_train , num_iterations , learning_rate , print_cost, print_frequency)
    
                                          
    W , b = parameters["W"] , parameters["b"]
    # 预测测试集
    Y_prediction_tset = predict(W , b , X_test)
    Y_prediction_train = predict(W , b , X_train)
    
    # 打印准确性
    print("训练集准确性: " , format(100 - np.mean(np.abs(Y_prediction_train - Y_train)) * 100 ) , "%")
    print("测试集准确性: " , format(100 - np.mean(np.abs(Y_prediction_tset - Y_test)) * 100 ) , "%")
    
    
    
    d = {
        "costs" : costs,
        "Y_prediction_test" : Y_prediction_tset,
        "Y_prediction_train" : Y_prediction_train,
        "W" : W,
        "b" : b,
        "learning_rate" : learning_rate,
        "num_iterations" : num_iterations
    }
    
    return d
     


# In[215]:


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


# In[216]:


costs = np.squeeze( d["costs"] )
plt.plot(costs)
plt.ylabel("cost")
plt.xlabel("iterations(per 100)")
plt.title("Learning rate= "+ str(d["learning_rate"]))
plt.show


# In[217]:


# 测试不同的学习率

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=2000,learning_rate=i,print_cost=False)
    print("\n")
    

for i in learning_rates:
    plt.plot(np.squeeze(models[str(i)]["costs"]  ), label= str(models[str(i)]["learning_rate"]))


plt.ylabel('cost')
plt.xlabel('iterations')
legend = plt.legend(loc='upper center' , shadow=True )
frame = legend.get_frame()
frame.set_facecolor('0.90')
plt.show


# In[218]:


def test_my_image( my_image):
    image_name = my_image
    fname = "images/" + my_image  # 在当前目录下有一个images文件夹  用于存放我们的图片 
    image = np.array(imageio.imread(fname))

    my_image = Image.fromarray(image).resize(( im_size , im_size ))
    my_image = np.array(my_image).reshape((1, im_size * im_size * 3)).T

    my_predicted_image = predict(d["W"], d["b"], my_image)

    plt.imshow(image)
    print("image name is: "+image_name)
    print( "y = " + str(np.squeeze(my_predicted_image)) + ", your algorithm predicts a \"" + classes[int(np.squeeze(my_predicted_image)),].decode("utf-8") +  "\" picture.")

    


# 下面我们自己整一张图片试一试

# In[220]:


my_image1 = "my_image1.jpg" 
# my_image2 = "my_image1.jpg"
# my_image3 = "my_image2.jpg"
# my_image4 = "my_image3.jpg"
# my_image5 = "my_image4.jpg"
test_my_image(my_image1)
# test_my_image(my_image2)
# test_my_image(my_image3)
# test_my_image(my_image4)
# test_my_image(my_image5)


# ####  声明: 本人参考了[Kulbear](https://github.com/Kulbear/deep-learning-coursera) 的github上的文章 ,加以自己理解,编写了本篇内容。尽力让人轻松理解课程内容及作业
 
posted @ 2021-06-15 22:44  Mr小明同学  阅读(97)  评论(0编辑  收藏  举报