吴恩达机器学习第三周作业

3.0代码(使用Ligistic Regression进行多分类)

题目:在本次练习中,你将使用逻辑回归和神经网络来识别手写数字(从0到9)。今天,自动手写数字识别被广泛使用,从识别信封上的邮政编码到识别银行支票上的金额。这个练习将向您展示如何将您所学的方法用于此分类任务。在第一部分中,将扩展以前的逻辑回归,并将其应用于one-vs-all分类。
关于数据:本次的数据是以.mat格式储存的,mat格式是matlab的数据存储格式,按照矩阵保存,与numpy数据格式兼容,适合于各种数学运算,因此这次主要使用numpy进行运算。ex3data1中有5000个训练样例,其中每个训练样例是一个20像素×20像素灰度图像的数字,每个像素由一个浮点数表示,该浮点数表示该位置的灰度强度。每个20×20像素的网格被展开成一个400维的向量。这些每个训练样例都变成数据矩阵X中的一行。这就得到了一个5000×400矩阵X,其中每一行都是手写数字图像的训练样例。训练集的第二部分是一个包含训练集标签的5000维向量y,“0”的数字标记为“10”,而“1”到“9”的数字按自然顺序标记为“1”到“9”。

数据集链接:https://pan.baidu.com/s/1cEgQIvehUcLxZ0WVhxcPuQ
提取码: xejn

import numpy as np
import scipy.io as scio
import matplotlib.pyplot as plt


# 根据输入的数据和参数,计算神经网络的输出
def predict_nn(X, theta1, theta2):
    m = X.shape[0]
    X = np.c_[np.ones(m), X]
    # 隐藏层的输入
    z1 = theta1.dot(X.T)
    # 增加一行维度
    z1 = np.row_stack((np.ones(z1.shape[1]), z1))
    # 隐藏层的输出
    A1 = sigmoid(z1)

    # 输出层的输入
    z2 = theta2.dot(A1)
    # 输出层的输出
    A2 = sigmoid(z2.T)

    # 进行预测
    P = np.zeros(m)
    for num in range(m):
        # 找到第num行中,与该行最大值相等的列的下标,此时下标的范围是[0,9]
        # label的范围是[1,10],需要把下标的值+1
        # np.where()返回的是一个长度为2的元祖,保存的是满足条件的下标
        # 元组中第一个元素保存的是行下标,第二元素保存的是列下标
        index = np.where(A2[num, :] == np.max(A2[num, :]))
        P[num] = index[0][0].astype(int) + 1

    return P


# 向量化logistic的预测函数
def predict_one_vs_all(X, all_theta):
    m = X.shape[0]
    X = np.c_[np.ones(m), X]
    # 标签数10
    num_labels = all_theta.shape[0]

    # preds[m][k]是第m个样本属于k的概率
    preds = sigmoid(X.dot(all_theta.T))
    P = np.zeros(m)

    for num in range(m):
        # 找到第num行中,与该行最大值相等的列的下标,此时下标的范围是[0,9]
        # label的范围是[1,10],需要把下标的值+1
        # np.where()返回的是一个长度为2的元祖,保存的是满足条件的下标
        # 元组中第一个元素保存的是行下标,第二元素保存的是列下标
        index = np.where(preds[num, :] == np.max(preds[num, :]))
        P[num] = index[0][0].astype(int) + 1

    return P


def one_vs_all(X, Y, num_labels, lmd):
    # 给数据添加偏置维度
    X = np.c_[np.ones(X.shape[0]), X]
    n = X.shape[1]
    # 保存所有theta的集合
    all_theta = np.zeros((num_labels, n))
    # Y中的值是1~10
    for i in range(1, num_labels + 1):
        init_theta = np.zeros((n, 1));
        y = (Y == i).astype(int)

        def cost_func(t):
            return lr_cost_function(X, y, t, lmd)[0]

        def grad_func(t):
            return lr_cost_function(X, y, t, lmd)[1]

        theta, cost, *unused = opt.fmin_bfgs(f=cost_func, fprime=grad_func, x0=init_theta, maxiter=100,
                                             full_output=True, disp=False)
        all_theta[i - 1, :] = theta.T

    return all_theta


# 这个函数是用来求代价和梯度,和前面ex2的costfunction相同
def lr_cost_function(X, Y, theta, lmd):
    m = X.shape[0]
    g = sigmoid(X.dot(theta))
    # g.shape = [m,]
    # Y.shape = [m,1]
    # 两者相减得到的是[m,m]
    Y = Y.reshape(Y.size)

    cost = (-Y.T).dot(np.log(g)) - ((1 - Y).T).dot(np.log(1 - g))
    cost = cost / (m) + lmd * (theta.T).dot(theta) / (2 * m)

    grad = (X.T).dot(g - Y) / m
    grad[0] = grad[0]
    grad[1:] = grad[1:] + (lmd * theta[1:]) / m

    return cost, grad


def display_data(x):
    (m, n) = x.shape

    # 设置每个小图例的宽度和高度
    width = np.round(np.sqrt(n)).astype(int)
    height = (n / width).astype(int)

    # 设置图片的行数和列数
    rows = np.floor(np.sqrt(m)).astype(int)
    cols = np.ceil(m / rows).astype(int)

    # 设置图例之间的间隔
    pad = 1

    # 初始化图像数据
    display_array = -np.ones((pad + rows * (height + pad),
                              pad + cols * (width + pad)))

    # 把数据按行和列复制进图像中
    current_image = 0
    for j in range(rows):
        for i in range(cols):
            if current_image > m:
                break
            # [:,np.newaxis]可以让指定的那一列数据以列的形式返回和指定
            # 否则返回的是行的形式
            max_val = np.max(np.abs(x[current_image, :]))
            display_array[pad + j * (height + pad) + np.arange(height),
                          pad + i * (width + pad) + np.arange(width)[:, np.newaxis]] = \
                x[current_image, :].reshape((height, width)) / max_val
            current_image += 1
        if current_image > m:
            break

    # 显示图像
    plt.figure()
    # 设置图像色彩为灰度值,指定图像坐标范围
    plt.imshow(display_array, cmap='gray', extent=[-1, 1, -1, 1])
    plt.axis('off')
    plt.title('Random Seleted Digits')


# 使用Ligistic Regression进行多分类

# ============================== 1.读取数据和初始化 ============================
# 使用scipy.io中的函数读取mat文件,data的格式是字典
data = scio.loadmat('ex3data1.mat')
# 根据关键字,分别获得输入数据和输出的真值
# print(type(Y),type(X)) # X和Y都是numpy.narray格式,也就是数组格式
X = data['X']
Y = data['y']
print(X.shape)
print(Y.shape)

# 随机取出其中的100个样本,显示结果
m = X.shape[0]
# 从[0,m-1]之间,随机生成一个序列
rand_indices = np.random.permutation(range(m))
selected = X[rand_indices[1:100], :]
# 显示手写数字样例
display_data(selected)

# ========================= 2.向量化Logistic Rgression =========================
# 测试函数lr_cost_function的功能
"""
theta_t = np.array([-2, -1, 1, 2])
X_t = np.c_[np.ones(5), np.arange(1, 16).reshape((3, 5)).T/10]
y_t = np.array([1, 0, 1, 0, 1])
lmda_t = 3
cost,grad = lr_cost_function(X_t,y_t,theta_t,lmda_t)
np.set_printoptions(formatter={'float': '{: 0.6f}'.format})
print('Cost: {:0.7f}'.format(cost))
print('Expected cost: 3.734819')
print('Gradients:\n{}'.format(grad))
print('Expected gradients:\n[ 0.146561 -0.548558 0.724722 1.398003]')
"""
# 训练模型

lmd = 0.01
num_labels = 10
all_theta = one_vs_all(X, Y, num_labels, lmd)

# =============================== 3.预测 =======================================
pred = predict_one_vs_all(X, all_theta)
# 这里一定要把Y.shape变成(m,),否则Y.shape = (m,1),带入是无效的
Y = Y.reshape(Y.size)
print('Training set accurayc:{}'.format(np.mean(pred == Y) * 100))

使用简单的神经网络对“手写数字”进行训练和识别

import numpy as np
import scipy.io as scio
import matplotlib.pyplot as plt


# 根据输入的数据和参数,计算神经网络的输出
def predict_nn(X, theta1, theta2):
    m = X.shape[0]
    X = np.c_[np.ones(m), X]
    # 隐藏层的输入
    z1 = theta1.dot(X.T)
    # 增加一行维度
    z1 = np.row_stack((np.ones(z1.shape[1]), z1))
    # 隐藏层的输出
    A1 = sigmoid(z1)

    # 输出层的输入
    z2 = theta2.dot(A1)
    # 输出层的输出
    A2 = sigmoid(z2.T)

    # 进行预测
    P = np.zeros(m)
    for num in range(m):
        # 找到第num行中,与该行最大值相等的列的下标,此时下标的范围是[0,9]
        # label的范围是[1,10],需要把下标的值+1
        # np.where()返回的是一个长度为2的元祖,保存的是满足条件的下标
        # 元组中第一个元素保存的是行下标,第二元素保存的是列下标
        index = np.where(A2[num, :] == np.max(A2[num, :]))
        P[num] = index[0][0].astype(int) + 1

    return P


# 计算sigmoid函数值
def sigmoid(z):
    g = 1 / (1 + np.exp(-z))

    return g


# 向量化logistic的预测函数
def predict_one_vs_all(X, all_theta):
    m = X.shape[0]
    X = np.c_[np.ones(m), X]
    # 标签数10
    num_labels = all_theta.shape[0]

    # preds[m][k]是第m个样本属于k的概率
    preds = sigmoid(X.dot(all_theta.T))
    P = np.zeros(m)

    for num in range(m):
        # 找到第num行中,与该行最大值相等的列的下标,此时下标的范围是[0,9]
        # label的范围是[1,10],需要把下标的值+1
        # np.where()返回的是一个长度为2的元祖,保存的是满足条件的下标
        # 元组中第一个元素保存的是行下标,第二元素保存的是列下标
        index = np.where(preds[num, :] == np.max(preds[num, :]))
        P[num] = index[0][0].astype(int) + 1

    return P


def one_vs_all(X, Y, num_labels, lmd):
    # 给数据添加偏置维度
    X = np.c_[np.ones(X.shape[0]), X]
    n = X.shape[1]
    # 保存所有theta的集合
    all_theta = np.zeros((num_labels, n))
    # Y中的值是1~10
    for i in range(1, num_labels + 1):
        init_theta = np.zeros((n, 1));
        y = (Y == i).astype(int)

        def cost_func(t):
            return lr_cost_function(X, y, t, lmd)[0]

        def grad_func(t):
            return lr_cost_function(X, y, t, lmd)[1]

        theta, cost, *unused = opt.fmin_bfgs(f=cost_func, fprime=grad_func, x0=init_theta, maxiter=100,
                                             full_output=True, disp=False)
        all_theta[i - 1, :] = theta.T

    return all_theta


# 这个函数是用来求代价和梯度,和前面ex2的costfunction相同
def lr_cost_function(X, Y, theta, lmd):
    m = X.shape[0]
    g = sigmoid(X.dot(theta))
    # g.shape = [m,]
    # Y.shape = [m,1]
    # 两者相减得到的是[m,m]
    Y = Y.reshape(Y.size)

    cost = (-Y.T).dot(np.log(g)) - ((1 - Y).T).dot(np.log(1 - g))
    cost = cost / (m) + lmd * (theta.T).dot(theta) / (2 * m)

    grad = (X.T).dot(g - Y) / m
    grad[0] = grad[0]
    grad[1:] = grad[1:] + (lmd * theta[1:]) / m

    return cost, grad


def display_data(x):
    (m, n) = x.shape

    # 设置每个小图例的宽度和高度
    width = np.round(np.sqrt(n)).astype(int)
    height = (n / width).astype(int)

    # 设置图片的行数和列数
    rows = np.floor(np.sqrt(m)).astype(int)
    cols = np.ceil(m / rows).astype(int)

    # 设置图例之间的间隔
    pad = 1

    # 初始化图像数据
    display_array = -np.ones((pad + rows * (height + pad),
                              pad + cols * (width + pad)))

    # 把数据按行和列复制进图像中
    current_image = 0
    for j in range(rows):
        for i in range(cols):
            if current_image > m:
                break
            # [:,np.newaxis]可以让指定的那一列数据以列的形式返回和指定
            # 否则返回的是行的形式
            max_val = np.max(np.abs(x[current_image, :]))
            display_array[pad + j * (height + pad) + np.arange(height),
                          pad + i * (width + pad) + np.arange(width)[:, np.newaxis]] = \
                x[current_image, :].reshape((height, width)) / max_val
            current_image += 1
        if current_image > m:
            break

    # 显示图像
    plt.figure()
    # 设置图像色彩为灰度值,指定图像坐标范围
    plt.imshow(display_array, cmap='gray', extent=[-1, 1, -1, 1])
    plt.axis('off')
    plt.title('Random Seleted Digits')


# 使用简单的神经网络对“手写数字”进行训练和识别
# ========================= 1.读取数据,显示随机样例 ===========================
data = scio.loadmat('ex3data1.mat')
X = data['X']
Y = data['y'].flatten()
# 随机取出其中的100个样本,显示结果
m = X.shape[0]
# 从[0,m-1]之间,随机生成一个序列
rand_indices = np.random.permutation(range(m))
selected = X[rand_indices[1:100], :]
# 显示手写数字样例
display_data(selected)
# plt.show()

# ======================= 2.读取神经网络的参数 =================================
weight = scio.loadmat('ex3weights.mat')
# theta1.shape=(25,401),隐藏层有25个节点,输入数据为401维(添加了1个维度的偏置)
# Theta2.shape=(10,26),10输出层有10个节点,隐藏层添加一个维度后,有25个输出
theta1 = weight['Theta1']
theta2 = weight['Theta2']

P = predict_nn(X, theta1, theta2)
print('Training set accuracy: {}'.format(np.mean(P == Y) * 100))

# ======================= 3.随机选取样本,并显示预测结果 =========================
rp = np.random.permutation(range(m))
for i in range(m):
    print('Displaying Example image')
    example = X[rp[i]]
    example = example.reshape((1, example.size))
    display_data(example)

    pred = predict_nn(example, theta1, theta2, )
    print('Neural network prediction: {} (digit {})'.format(pred, np.mod(pred, 10)))

    plt.show()

    s = input('Paused - press ENTER to continue, q + ENTER to exit: ')
    if s == 'q':
        break

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值