如何用Python实现神经网络softmax多分类模型

这几天在review一些代码,手撸了一个softmax捋一捋思路,谈谈如何从无到有构建一个完整的神经网络模型,完整代码请查阅我的Github: https://github.com/LittletreeZou/Python-Projects
新的一年开始了,题主的新年愿望之一就是好好用心经营简书,多学习多写文章多分享ヾ(◍°∇°◍)ノ゙


一、 什么是softmax?

在数学,尤其是概率论和相关领域中,softmax函数,是逻辑函数的一种推广。它能将一个含任意实数的K维向量“压缩”到另一个K维实向量中,使得每一个元素的范围都在0-1之间,并且使所有元素的和为1。这样,每个元素就代表了属于某个分类的概率。值越大,概率就越大,属于某一类的可能性就越大。

二、softmax有什么用?

softmax广泛应用于机器学习和深度学习中的多分类问题。在深度学习中,softmax常用于多分类问题最后一层的激活函数,用于输出某样本属于某个分类的概率值。

三、 如何实现softmax呢?

本文fashion_minist为例(为什么要用这个数据集而不用那个经典的手写数字识别数据集呢,当然是因为题主的电脑渣呀o(╥﹏╥)o),用Python从头到尾构建一个两层的神经网络多分类模型,预测图片的label。

数据集介绍:fashion_minist是tensorflow里面一个自带数据集,有60000张28x28的带label的训练图片和10000张28x28的测试图片,它的label有10个分类,鞋子裙子啥的,下图显示的是部分训练样本数据,是不是很高清无码!!!

fashion_minist

Softmax模型构建流程:
第一步:明确模型框架:input layer — hidden layer — output layer( activation = softmax)
第二步:参数初始化
第三步:循环:前向传播 - 计算损失 - 后向传播 - 更新参数(梯度下降)

四、先搭框架,再建模块,最后整合

1、搭建框架

模型框架:input layer — hidden layer (128 units, relu) — output layer(10 units, softmax)

2、定义辅助函数

辅助函数较多,不一一展开,具体代码请查阅我的Github。

# 激活函数
relu(Z)    # relu激活函数
softmax(Z)  # softmax激活函数,注意exp(z)容易造成数值上溢

# 参数初始化
initialize_parameters(n_x, n_h, n_y)  

# 前向传播模块
linear_forward(A, W, b) 
linear_activation_forward(A_prev, W, b, activation)

# 计算损失
compute_cost(AL, Y)

# 后向传播模块
linear_backward(dZ, cache)
relu_backward(dA, cache)
softmax_backward(Y, cache)
linear_activation_backward(dA, cache, activation)

# 参数更新
update_parameters(parameters, grads, learning_rate)

3、整合模型

def two_layer_model(X, Y, layers_dims, learning_rate = 0.1, num_iterations = 3000, print_cost=False):
    """
    two-layer neural network: LINEAR->RELU->LINEAR->SOFTMAX.
    
    Arguments:
    X -- input data, of shape (n_x, number of examples)
    Y -- true "label", of shape (classes, number of examples)
    layers_dims -- dimensions of the layers (n_x, n_h, n_y)
    num_iterations -- number of iterations of the optimization loop
    learning_rate -- learning rate of the gradient descent update rule
    print_cost -- If set to True, this will print the cost every 100 iterations 
    
    Returns:
    parameters -- a dictionary containing W1, W2, b1, and b2
    """
    #np.random.seed(1)
    grads = {}
    costs = []                              # to keep track of the cost
    m = X.shape[1]                    # number of examples
    (n_x, n_h, n_y) = layers_dims
    
    # Initialize parameters dictionary
    parameters = initialize_parameters(n_x, n_h, n_y)
    
    # Get W1, b1, W2 and b2 from the dictionary parameters.
    W1 = parameters["W1"]
    b1 = parameters["b1"]
    W2 = parameters["W2"]
    b2 = parameters["b2"]
    
    # Loop (gradient descent)

    for i in range(0, num_iterations):

        # Forward propagation: LINEAR -> RELU -> LINEAR -> SOFTMAX. 
        A1, cache1 = linear_activation_forward(X, W1, b1, activation='relu')
        A2, cache2 = linear_activation_forward(A1, W2, b2, activation='softmax')

        # Compute cost
        cost = compute_cost(A2, Y)
        
        # Backward propagation
        dA1, dW2, db2 = linear_activation_backward(Y, cache2, activation='softmax')
        dA0, dW1, db1 = linear_activation_backward(dA1, cache1, activation='relu')
        
        # Set grads['dWl'] to dW1, grads['db1'] to db1, grads['dW2'] to dW2, grads['db2'] to db2
        grads['dW1'] = dW1
        grads['db1'] = db1
        grads['dW2'] = dW2
        grads['db2'] = db2
        
        # Update parameters.
        parameters = update_parameters(parameters, grads, learning_rate)

        # Retrieve W1, b1, W2, b2 from parameters
        W1 = parameters["W1"]
        b1 = parameters["b1"]
        W2 = parameters["W2"]
        b2 = parameters["b2"]
        
        # Print the cost every 100 training example
        if print_cost and i % 100 == 0:
            print("Cost after iteration {}: {}".format(i, np.squeeze(cost)))
        if print_cost and i % 100 == 0:
            costs.append(cost)
       
    # plot the cost

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

4、模型测试

# 拿了10000个训练样本来训练模型
train_x = train_set_x[:,0:10000]
train_y = train_labels_onehot[:,0:10000]
parameters = two_layer_model(train_x, train_y, layers_dims = (784, 128, 10), num_iterations = 1000, print_cost=True)
训练样本的performance

从上图可以看出,cost一直在下降,说明模型是work的。

我们再来看看测试集的表现。

def predict_labels(X, y, parameters):
    """
    Arguments:
    X -- data set of examples you would like to label
    parameters -- parameters of the trained model
    
    Returns:
    predict_label -- predictions for the given dataset X
    """
    m = X.shape[1]
    
    W1 = parameters["W1"]
    b1 = parameters["b1"]
    W2 = parameters["W2"]
    b2 = parameters["b2"]
    
    # Forward propagation
    A1, _ = linear_activation_forward(X, W1, b1, activation='relu')
    probs, _ = linear_activation_forward(A1, W2, b2, activation='softmax')
    
    # convert probas to 0-9 predictions
    predict_label = np.argmax(probs, axis=0)
    
    print("Accuracy: "  + str(np.sum((predict_label == y)/float(m))))
        
    return predict_label

prediction = predict_labels(test_set_x, test_labels, parameters)
# output: Accuracy: 0.8132000000000001

测试集上的预测准确率为81.3%,说明这个模型的效果还是可以的,至少是有效的。

五、优化方向

上面我们已经构建了一个完整的神经网络模型用以实现有监督的多分类任务。不过,这只是最基本的框架结构,有很多可以优化的地方,主要的三个优化方向是:

  1. 参数初始化的方式:这里采用的是随机初始化,可尝试Xavier 初始化或者He初始化。
  2. 优化算法:这里采用的是梯度下降算法,可采用SGD、RMSprop、Adam等。
  3. 模型参数调优:学习率,隐藏结点个数,神经网络的层数等。

六、Reference

[1] Deep Learning and Neural Network on Coursera 吴恩达

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,457评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,837评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,696评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,183评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,057评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,105评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,520评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,211评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,482评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,574评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,353评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,897评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,489评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,683评论 2 335