吴恩达神经网络学习-L2W3作业1

# TensorFlow,PaddlePaddle,Torch,Caffe,Keras等机器学习框架可以极大地加快你的机器学习开发速度。
# 所有这些框架也都有很多文档,你应该随时阅读学习。在此笔记本中,你将学习在TensorFlow中执行以下操作:
# 初始化变量
# 创建自己的会话(session)
# 训练算法
# 实现神经网络

import math
import numpy as np
import h5py
import matplotlib.pyplot as plt
import tensorflow as tf
from tensorflow.python.framework import ops
from tf_utils import load_dataset, random_mini_batches, convert_to_one_hot, predict

np.random.seed(1)

tf.compat.v1.disable_eager_execution() #保证sess.run()能够正常运行(因为版本不同,所以得加上这句话)

#计算一个训练数据的损失
y_hat=tf.constant(36,name='y_hat') # 创建常量的函数,Define y_hat constant. Set to 36.
y=tf.constant(39,name='y') # Define y. Set to 39

loss=tf.Variable((y-y_hat)**2,name='loss') #tf.Variable()函数用于创建变量,在tensorflow的世界里变量的定义和初始化是被分开的

# init = tf.global_variables_initializer() 新版本的tensorflow已经移除了这个属性,需改为下面的代码
init=tf.compat.v1.global_variables_initializer()# When init is run later (session.run(init)),the loss variable will be initialized and ready to be computed

# with tf.Session() as session: 这里也许要改,都在原属性前加上.compat.v1
with tf.compat.v1.Session() as session: # Create a session and print the output
    session.run(init) # Initializes the variables
    print(session.run(loss)) # Prints the loss

# 在TensorFlow中编写和运行程序包含以下步骤:
# 1.创建尚未执行的张量(变量)。
# 2.在这些张量之间编写操作。
# 3.初始化张量。
# 4.创建一个会话。
# 5.运行会话,这将运行你上面编写的操作。
# 因此,当我们为损失创建变量时,我们仅将损失定义为其他数量的函数,但没有验证其值。为了验证它,
# 我们必须运行init = tf.compat.v1.global_variables_initializer()初始化损失变量,在最后一行中,我们终于能够验证loss的值并打印它

a=tf.constant(2)
b=tf.constant(10)
c=tf.multiply(a,b)
print(c)
# 不出所料,看不到结果20!而是得到一个张量,是一个不具有shape属性且类型为“int32”的张量。
# 你所做的所有操作都已放入“计算图”中,但你尚未运行此计算。为了实际将两个数字相乘,必须创建一个会话并运行它。
session=tf.compat.v1.Session()
print(session.run(c))

# !!! 记住要初始化变量,创建一个会话并在该会话中运行操作 !!!


# 接下来,你还必须了解 placeholders(占位符)。占位符是一个对象,你只能稍后指定其值。
# 要为占位符指定值,你可以使用"feed dictionary"(feed_dict变量)传入值。在下面,我们为x创建了一个占位符,以允许我们稍后在运行会话时传递数字。
x=tf.compat.v1.placeholder(tf.int64,name='x')
print(session.run(2*x,feed_dict={x:3})) #feed_dict则是将对应的数据传入计算图中占位符,它是字典数据结构只在调用方法内有效,output is 2*3=6
session.close() # 关闭会话连接
# 当你首次定义x时,不必为其指定值。占位符只是一个变量,你在运行会话时才将数据分配给该变量。也就是说你在运行会话时向这些占位符“提供数据”。
# 当你指定计算所需的操作时,你在告诉TensorFlow如何构造计算图。计算图可以具有一些占位符,你将在稍后指定它们的值。最后,在运行会话时,你要告诉TensorFlow执行计算图。


#1.1 线性函数
#Y=W*X+b,W的维度为(4,3),X的维度为(3,1),b的维度为(4,1)。例如,下面是定义维度为(3,1)的常量X的方法:
# X = tf.constant(np.random.randn(3,1), name = "X")
# 你可能会发现以下函数很有用:
# tf.matmul(..., ...)进行矩阵乘法
# tf.add(..., ...)进行加法
# np.random.randn(...)随机初始化

def linear_function():
    """
        Implements a linear function:
                Initializes W to be a random tensor of shape (4,3)
                Initializes X to be a random tensor of shape (3,1)
                Initializes b to be a random tensor of shape (4,1)
        Returns:
        result -- runs the session for Y = WX + b
        """
    np.random.seed(1)

    X=tf.constant(np.random.randn(3,1),name='X')
    W=tf.constant(np.random.randn(4,3),name='W')
    b=tf.constant(np.random.randn(4,1),name='b')
    Y=tf.add(tf.matmul(W,X),b) #为什么这里可以直接计算,而不用先tf.compat.v1.Variable()一个变量?

    session=tf.compat.v1.Session()
    result=session.run(Y)
    session.close()

    return result

print( "result = " + str(linear_function()))

#1.2 计算Sigmoid
# 你将使用占位符变量x进行此练习。在运行会话时,应该使用feed字典传入输入z。在本练习中,你必须:
# (i)创建一个占位符x;
# (ii)使用tf.sigmoid定义计算Sigmoid所需的操作;
# (iii)然后运行该会话

# 练习:实现下面的Sigmoid函数。你应该使用以下内容:
# tf.placeholder(tf.float32, name = "...")
# tf.sigmoid(...)
# sess.run(..., feed_dict = {x: z})

# 注意,在tensorflow中创建和使用会话有两种典型的方法:
# Method 1:
# sess = tf.Session()
# # Run the variables initialization (if needed), run the operations
# result = sess.run(..., feed_dict = {...})
# sess.close() # Close the session

# Method 2:
# with tf.Session() as sess:
#     # run the variables initialization (if needed), run the operations
#     result = sess.run(..., feed_dict = {...})
#     # This takes care of closing the session for you :)

def sigmoid(z):
    """
        Computes the sigmoid of z
        Arguments:
        z -- input value, scalar or vector
        Returns:
        results -- the sigmoid of z
        """
    x=tf.compat.v1.placeholder(tf.float32,name='x')

    session=tf.compat.v1.Session()
    result=session.run(tf.sigmoid(x),feed_dict={x:z})
    session.close()

    return result

print ("sigmoid(0) = " + str(sigmoid(0)))
print ("sigmoid(12) = " + str(sigmoid(12)))
# 总而言之,你知道如何:
# 1.创建占位符
# 2.指定运算相对应的计算图
# 3.创建会话
# 4.如果需要指定占位符变量的值,使用feed字典运行会话。


#1.3 计算损失
# 练习:实现交叉熵损失。你将使用的函数是:
# tf.nn.sigmoid_cross_entropy_with_logits(logits = ..., labels = ...)

def cost(logits,labels):
    """
        Computes the cost using the sigmoid cross entropy

        Arguments:
        logits -- vector containing z, output of the last linear unit (before the final sigmoid activation)
        labels -- vector of labels y (1 or 0)

        Note: What we've been calling "z" and "y" in this class are respectively called "logits" and "labels"
        in the TensorFlow documentation. So logits will feed into z, and labels into y.

        Returns:
        cost -- runs the session of the cost (formula (2))
    """
    z=tf.compat.v1.placeholder(tf.float32,name='z')
    y=tf.compat.v1.placeholder(tf.float32,name='y')
    cost=tf.nn.sigmoid_cross_entropy_with_logits(logits=z,labels=y)

    session=tf.compat.v1.Session()
    cost=session.run(cost,{z:logits,y:labels})
    session.close()

    return cost

logits = sigmoid(np.array([0.2,0.4,0.7,0.9]))
cost = cost(logits, np.array([0,0,1,1]))
print ("cost = " + str(cost))


#1.4 使用独热(One Hot)编码
# 独热编码,因为在转换后的表示形式中,每一列中的一个元素正好是“hot”(设为1)。要以numpy格式进行此转换,你可能需要编写几行代码。在tensorflow中,你可以只使用一行代码:
# tf.one_hot(labels, depth, axis)
# 练习:实现以下函数,以获取一个标签向量和C类的总数,并返回一个独热编码。使用tf.one_hot()来做到这一点。
def one_hot_matrix(labels,C):
    """
        Creates a matrix where the i-th row corresponds to the ith class number and the jth column
                         corresponds to the jth training example. So if example j had a label i. Then entry (i,j)
                         will be 1.

        Arguments:
        labels -- vector containing the labels
        C -- number of classes, the depth of the one hot dimension

        Returns:
        one_hot -- one hot matrix
    """
    one_hot_matrix=tf.one_hot(labels,C,axis=0) # axis=1,以行为主赋0赋1;axis=0,以列为主赋0赋1

    session=tf.compat.v1.Session()
    one_hot=session.run(one_hot_matrix)
    session.close()

    return one_hot

labels = np.array([1,2,3,0,2,1])
one_hot = one_hot_matrix(labels, C = 4)
print ("one_hot = " + str(one_hot))


#1.5 使用0和1初始化
# 现在,你将学习如何初始化0和1的向量。 你将要调用的函数是tf.ones()。要使用零初始化,可以改用tf.zeros()。这些函数采用一个维度,并分别返回一个包含0和1的维度数组。
# 练习:实现以下函数以获取维度并返回维度数组。
# tf.ones(shape)
def ones(shape):
    """
        Creates an array of ones of dimension shape

        Arguments:
        shape -- shape of the array you want to create

        Returns:
        ones -- array containing only ones
        """
    ones=tf.ones(shape)

    session=tf.compat.v1.Session()
    ones=session.run(ones)
    session.close()

    return ones

print ("ones = " + str(ones([3])))



#使用Tensorflow构建你的第一个神经网络
# 实现tensorflow模型包含两个部分:
# 创建计算图
# 运行计算图

# 2.0 问题陈述:SIGNS 数据集
# 一个下午,我们决定和一些朋友一起用计算机来解密手语。
# 训练集:1080张图片(64 x 64像素)的手势表示从0到5的数字(每个数字180张图片)。
# 测试集:120张图片(64 x 64像素)的手势表示从0到5的数字(每个数字20张图片)

X_train_orig, Y_train_orig, X_test_orig, Y_test_orig, classes=load_dataset()
# Example of a picture
index = 0
plt.imshow(X_train_orig[index])
plt.show()
print ("y = " + str(np.squeeze(Y_train_orig[:, index])))

#通常先将图像数据集展平,然后除以255以对其进行归一化。最重要的是将每个标签转换为一个独热向量
X_train_flatten=X_train_orig.reshape(X_train_orig.shape[0],-1).T
X_test_flatten=X_test_orig.reshape(X_test_orig.shape[0],-1).T
X_train=X_train_flatten/255
X_test=X_test_flatten/255

Y_train=convert_to_one_hot(Y_train_orig,6)
Y_test=convert_to_one_hot(Y_test_orig,6)

# print ("number of training examples = " + str(X_train.shape[1]))
# print ("number of test examples = " + str(X_test.shape[1]))
# print ("X_train shape: " + str(X_train.shape))
# print ("Y_train shape: " + str(Y_train.shape))
# print ("X_test shape: " + str(X_test.shape))
# print ("Y_test shape: " + str(Y_test.shape))

# 你的目标是建立一种能够高精度识别符号的算法。为此,你将构建一个tensorflow模型,
# 该模型与你先前在numpy中为猫识别构建的tensorflow模型几乎相同(但现在使用softmax输出)。
# 模型为LINEAR-> RELU-> LINEAR-> RELU-> LINEAR-> SOFTMAX 。 SIGMOID输出层已转换为SOFTMAX。SOFTMAX层将SIGMOID应用到两个以上的类。

#2.1 创建占位符
def create_placeholders(n_x,n_y):
    """
        Creates the placeholders for the tensorflow session.

        Arguments:
        n_x -- scalar, size of an image vector (num_px * num_px = 64 * 64 * 3 = 12288)
        n_y -- scalar, number of classes (from 0 to 5, so -> 6)

        Returns:
        X -- placeholder for the data input, of shape [n_x, None] and dtype "float"
        Y -- placeholder for the input labels, of shape [n_y, None] and dtype "float"

        Tips:
        - You will use None because it let's us be flexible on the number of examples you will for the placeholders.
          In fact, the number of examples during test/train is different.
    """
    X=tf.compat.v1.placeholder(shape=[n_x,None],dtype=tf.float32)
    Y = tf.compat.v1.placeholder(shape=[n_y, None], dtype=tf.float32)

    return X,Y

X, Y = create_placeholders(12288, 6)
# print ("X = " + str(X))
# print ("Y = " + str(Y))

#2.2 初始化参数
# 练习:实现以下函数以初始化tensorflow中的参数。使用权重的Xavier初始化和偏差的零初始化。维度如下,对于W1和b1,你可以使用:
# W1 = tf.get_variable("W1", [25,12288], initializer = tf.contrib.layers.xavier_initializer(seed = 1))
# b1 = tf.get_variable("b1", [25,1], initializer = tf.zeros_initializer())
# 请使用seed = 1来确保你的结果与我们的结果相符。
def initialize_parameters():
    """
        Initializes parameters to build a neural network with tensorflow. The shapes are:
                            W1 : [25, 12288]
                            b1 : [25, 1]
                            W2 : [12, 25]
                            b2 : [12, 1]
                            W3 : [6, 12]
                            b3 : [6, 1]

        Returns:
        parameters -- a dictionary of tensors containing W1, b1, W2, b2, W3, b3
    """

    # tf.compat.v1.set_random_seed(1)

    #tf.contrib.layers.xavier_initializer因为版本不同需进行替换
    W1=tf.compat.v1.get_variable("W1",[25, 12288],initializer=tf.keras.initializers.glorot_normal(seed = 1))
    b1=tf.compat.v1.get_variable("b1",[25, 1],initializer=tf.zeros_initializer())
    W2 = tf.compat.v1.get_variable("W2", [12, 25], initializer=tf.keras.initializers.glorot_normal(seed=1))
    b2 = tf.compat.v1.get_variable("b2", [12, 1], initializer=tf.zeros_initializer())
    W3 = tf.compat.v1.get_variable("W3", [6, 12], initializer=tf.keras.initializers.glorot_normal(seed=1))
    b3 = tf.compat.v1.get_variable("b4", [6, 1], initializer=tf.zeros_initializer())

    parameters={
        "W1":W1,
        "b1": b1,
        "W2": W2,
        "b2": b2,
        "W3": W3,
        "b3": b3
    }

    return parameters

tf.compat.v1.reset_default_graph() #tf.reset_default_graph函数用于清除默认图形堆栈并重置全局默认图形。
with tf.compat.v1.Session() as sess:
    parameters = initialize_parameters()
    print("W1 = " + str(parameters["W1"]))
    print("b1 = " + str(parameters["b1"]))
    print("W2 = " + str(parameters["W2"]))
    print("b2 = " + str(parameters["b2"]))

#2.3 Tensorflow中的正向传播
# 你现在将在tensorflow中实现正向传播模块。该函数将接收参数字典,并将完成正向传递。你将使用的函数是:
# tf.add(...,...)进行加法
# tf.matmul(...,...)进行矩阵乘法
# tf.nn.relu(...)以应用ReLU激活
# 问题:实现神经网络的正向传递。我们为你注释了numpy等式,以便你可以将tensorflow实现与numpy实现进行比较。
# 重要的是要注意,前向传播在z3处停止。原因是在tensorflow中,最后的线性层输出作为计算损失函数的输入。因此,你不需要a3!

def forward_propagation(X,parameters):
    """
        Implements the forward propagation for the model: LINEAR -> RELU -> LINEAR -> RELU -> LINEAR -> SOFTMAX

        Arguments:
        X -- input dataset placeholder, of shape (input size, number of examples)
        parameters -- python dictionary containing your parameters "W1", "b1", "W2", "b2", "W3", "b3"
                      the shapes are given in initialize_parameters

        Returns:
        Z3 -- the output of the last LINEAR unit
    """
    W1=parameters["W1"]
    b1=parameters["b1"]
    W2 = parameters["W2"]
    b2= parameters["b2"]
    W3 = parameters["W3"]
    b3 = parameters["b3"]

    Z1=tf.add(tf.matmul(W1,X),b1)
    A1=tf.nn.relu(Z1)
    Z2=tf.add(tf.matmul(W2,A1),b2)
    A2=tf.nn.relu(Z2)
    Z3=tf.add(tf.matmul(W3,A2),b3)

    return Z3

tf.compat.v1.reset_default_graph()

with tf.compat.v1.Session() as sess:
    X, Y = create_placeholders(12288, 6)
    parameters = initialize_parameters()
    Z3 = forward_propagation(X, parameters)
    print("Z3 = " + str(Z3))

#2.4 计算损失
# 如前所述,使用以下方法很容易计算损失:
# tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits = ..., labels = ...))
# 问题:实现以下损失函数。
# 重要的是要知道tf.nn.softmax_cross_entropy_with_logits的"logits"和"labels"输入应具有一样的维度(数据数,类别数)。 因此,我们为你转换了Z3和Y。
# 此外,tf.reduce_mean是对所以数据进行求和。
def compute_cost(Z3,Y):
    """
        Computes the cost

        Arguments:
        Z3 -- output of forward propagation (output of the last LINEAR unit), of shape (6, number of examples)
        Y -- "true" labels vector placeholder, same shape as Z3

        Returns:
        cost - Tensor of the cost function
        """
    # to fit the tensorflow requirement for tf.nn.softmax_cross_entropy_with_logits(...,...)
    logits=tf.transpose(Z3) #这个函数主要适用于交换输入张量的不同维度用的
    labels=tf.transpose(Y)

    cost=tf.nn.softmax_cross_entropy_with_logits(logits=logits,labels=labels)

    cost=tf.reduce_mean(cost)

    return cost

tf.compat.v1.reset_default_graph()

with tf.compat.v1.Session() as sess:
    X, Y = create_placeholders(12288, 6)
    parameters = initialize_parameters()
    Z3 = forward_propagation(X, parameters)
    cost = compute_cost(Z3, Y)
    print("cost = " + str(cost))

#2.5 反向传播和参数更新
# 所有反向传播和参数更新均可使用1行代码完成,将这部分合并到模型中非常容易。
# 计算损失函数之后,你将创建一个"optimizer"对象。运行tf.session时,必须与损失一起调用此对象。调用时,它将使用所选方法和学习率对给定的损失执行优化。
# 例如,对于梯度下降,优化器将是:
# optimizer = tf.train.GradientDescentOptimizer(learning_rate = learning_rate).minimize(cost)
# 要进行优化,你可以执行以下操作:
# _ , c = sess.run([optimizer, cost], feed_dict={X: minibatch_X, Y: minibatch_Y})
# 通过相反顺序的tensorflow图来计算反向传播。从损失到输入。
# 注意编码时,我们经常使用_作为“throwaway”变量来存储以后不再需要使用的值。这里_代表了我们不需要的optimizer的评估值(而 c 代表了 cost变量的值)。

#2.6 建立模型
def model(X_train,Y_train,X_test,Y_test,learning_rate=0.0001,
          num_epochs=1500,minibatch_size=32,print_cost=True):
    """
        Implements a three-layer tensorflow neural network: LINEAR->RELU->LINEAR->RELU->LINEAR->SOFTMAX.

        Arguments:
        X_train -- training set, of shape (input size = 12288, number of training examples = 1080)
        Y_train -- test set, of shape (output size = 6, number of training examples = 1080)
        X_test -- training set, of shape (input size = 12288, number of training examples = 120)
        Y_test -- test set, of shape (output size = 6, number of test examples = 120)
        learning_rate -- learning rate of the optimization
        num_epochs -- number of epochs of the optimization loop
        minibatch_size -- size of a minibatch
        print_cost -- True to print the cost every 100 epochs

        Returns:
        parameters -- parameters learnt by the model. They can then be used to predict.
        """
    ops.reset_default_graph()  # to be able to rerun the model without overwriting tf variables
    tf.compat.v1.set_random_seed(1)  # to keep consistent results
    seed=3
    n_x,m=X_train.shape
    n_y=Y_train.shape[0]
    costs=[]

    X,Y=create_placeholders(n_x,n_y)
    parameters=initialize_parameters()
    Z3=forward_propagation(X,parameters)
    cost=compute_cost(Z3,Y)

    optimizer=tf.compat.v1.train.AdamOptimizer(learning_rate=learning_rate).minimize(cost)

    init=tf.compat.v1.global_variables_initializer()

    with tf.compat.v1.Session() as sess:
        sess.run(init)
        for epoch in range(num_epochs):
            epoch_cost = 0 # Defines a cost related to an epoch
            seed+=1
            num_minibatches = int(m / minibatch_size)  # number of minibatches of size minibatch_size in the train set
            mini_batches=random_mini_batches(X_train,Y_train,minibatch_size,seed)

            for mini_batch in mini_batches:
                mini_batch_X,mini_batch_Y=mini_batch
                _,mini_batch_cost=sess.run([optimizer,cost],feed_dict={X: mini_batch_X, Y: mini_batch_Y})# Run the session to execute the "optimizer" and the "cost", the feedict should contain a minibatch for (X,Y).
                                                           #fetches主要指从计算图中取回计算结果进行放回的那些placeholder和变量
                epoch_cost+=mini_batch_cost/num_minibatches

            if print_cost == True and epoch % 100 == 0:
                print("Cost after epoch %i: %f" % (epoch, epoch_cost))
            if print_cost == True and epoch % 5 == 0:
                costs.append(epoch_cost)

        plt.plot(np.squeeze(costs))
        plt.ylabel('cost')
        plt.xlabel('iterations (per tens)')
        plt.title("Learning rate =" + str(learning_rate))
        plt.show()

        # lets save the parameters in a variable
        parameters = sess.run(parameters)
        print("Parameters have been trained!")

        # Calculate the correct predictions
        correct_prediction = tf.equal(tf.argmax(Z3), tf.argmax(Y))

        # Calculate accuracy on the test set
        accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))

        print("Train Accuracy:", accuracy.eval({X: X_train, Y: Y_train}))
        print("Test Accuracy:", accuracy.eval({X: X_test, Y: Y_test}))

        return parameters

parameters = model(X_train, Y_train, X_test, Y_test)

# Tensorflow是深度学习中经常使用的编程框架
# Tensorflow中的两个主要对象类别是张量和运算符。
# 在Tensorflow中进行编码时,你必须执行以下步骤:
#      - 创建一个包含张量(变量,占位符...)和操作(tf.matmul,tf.add,...)的计算图
#      - 创建会话
#      - 初始化会话
#      - 运行会话以执行计算图
# 你可以像在model()中看到的那样多次执行计算图
# 在“优化器”对象上运行会话时,将自动完成反向传播和优化。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值