(四)Tensorflow 搭建自己的神經(jīng)網(wǎng)絡(luò) (莫煩 Python 教程)

本教程資料來(lái)自于:Tensorflow 搭建自己的神經(jīng)網(wǎng)絡(luò) (莫煩 Python 教程)

本小節(jié)主要簡(jiǎn)介卷積神經(jīng)網(wǎng)絡(luò),卷積神經(jīng)網(wǎng)絡(luò)继阻,在處理圖片信息的時(shí)候很有優(yōu)勢(shì),它和以往的多層神經(jīng)網(wǎng)絡(luò)不同的是废酷,它和好保留了圖片的列信息瘟檩。

18 、卷積神經(jīng)網(wǎng)絡(luò) CNN (深度學(xué)習(xí))

應(yīng)用范圍:圖形圖像識(shí)別澈蟆、視頻分析墨辛、藥物發(fā)現(xiàn)、自然語(yǔ)言處理趴俘、ALPHAGO

卷積神經(jīng)網(wǎng)絡(luò)是如何運(yùn)作的睹簇,識(shí)別圖片的例子:


升級(jí)網(wǎng)絡(luò)由神經(jīng)層組成,每一層神經(jīng)層有很多神經(jīng)元寥闪,神經(jīng)元是神經(jīng)網(wǎng)絡(luò)識(shí)別的關(guān)鍵太惠,每一種神經(jīng)網(wǎng)絡(luò)都有自己的輸入和輸出,當(dāng)輸入是圖片的時(shí)候疲憋,是一對(duì)數(shù)字凿渊。


卷積神經(jīng)網(wǎng)絡(luò)(卷積 + 神經(jīng)網(wǎng)絡(luò))

卷積:神經(jīng)網(wǎng)絡(luò)不再是對(duì)每一個(gè)像素輸入的信息做處理,而是對(duì)圖片上每一小塊像素區(qū)域的處理。這種做法加快了圖片信息的連續(xù)性,使得神經(jīng)網(wǎng)絡(luò)能看到圖形而非一個(gè)點(diǎn)埃脏,這種做法同時(shí)也加深了搪锣,神經(jīng)網(wǎng)絡(luò)對(duì)圖片的理解。



卷積神經(jīng)網(wǎng)絡(luò)有一個(gè)批量過(guò)濾器彩掐,持續(xù)不斷在圖片上滾動(dòng)和收集圖像的信息构舟,每一次收集來(lái)的信息只是一小塊像素信息,然后把收集來(lái)的信息進(jìn)行整理堵幽,整理出來(lái)的信息有了實(shí)際上的一些呈現(xiàn)狗超,這使得神經(jīng)網(wǎng)絡(luò)可以看到一些邊緣的圖片信息,然后以同樣的不走谐檀,使用批量過(guò)濾器抡谐,掃過(guò)產(chǎn)生的邊緣信息,神經(jīng)網(wǎng)絡(luò)利用這些邊緣信息總結(jié)產(chǎn)生出更高級(jí)的信息結(jié)構(gòu)桐猬。比如總結(jié)的邊緣信息可以畫(huà)出眼睛麦撵、鼻子等等。在經(jīng)過(guò)幾次批量過(guò)濾器溃肪,眼睛和鼻子這些信息就被提取出來(lái)免胃,構(gòu)成了人臉,然后在套用到全連接層softmax分類(lèi)識(shí)別就好了惫撰。
神經(jīng)網(wǎng)絡(luò)


通過(guò)不斷的掃描羔沙,來(lái)收集信息。把圖片的厚度不斷增加厨钻,長(zhǎng)寬減少扼雏。



再次進(jìn)行卷積,長(zhǎng)寬不斷壓縮夯膀,高度不斷增加诗充。將壓縮的圖片信息,嵌入到普通分類(lèi)神經(jīng)層上诱建,我們就能對(duì)這種圖片進(jìn)行分類(lèi)了蝴蜓。

實(shí)際中卷積會(huì)丟失掉一部分信息,這時(shí)候池化pooling可以很好的解決這個(gè)問(wèn)題俺猿。也就是說(shuō)在卷積的時(shí)候我們不壓縮長(zhǎng)寬茎匠,盡量保留更多的信息,壓縮的工作交給池化押袍。這樣附加的工作可以有效提高數(shù)據(jù)的準(zhǔn)確性诵冒。


在卷積的時(shí)候不壓縮長(zhǎng)寬,盡量保留更多的信息谊惭。壓縮的工作就交給了池化造烁。這樣附加的工作可以有效提高數(shù)據(jù)的準(zhǔn)確性否过。

常用的搭建結(jié)構(gòu):


從下到上的搭建順序:

  • 1.圖片(輸入)
  • 2.卷積層
  • 3.池化 處理卷積信息
  • 4.卷積層
  • 5.池化 處理卷積信息(max pooling)
  • 6.全連接層
  • 7.全連接層 fully connected
  • 8.分類(lèi)器 classifier

CNN 卷積神經(jīng)網(wǎng)絡(luò) 1

https://morvanzhou.github.io/tutorials/machine-learning/tensorflow/5-03-CNN1/


2562563 RGB 三原色
每個(gè)卷積核對(duì)應(yīng)一個(gè)深度
不斷壓縮長(zhǎng)和寬,增加厚度惭蟋,利用厚度的信息把他變成一個(gè)分類(lèi)器

卷積核 kernel patch 每一個(gè)小部分都會(huì)變成一個(gè)長(zhǎng)度一個(gè)寬度簿盅,k厚度的數(shù)列谤专。


Stride 抽離的跨度是多少倒戏。


跨兩步進(jìn)行收集信息拉庶。stride = 2


padding的兩種方式

  • same padding 抽離后的長(zhǎng)寬與之前一樣

  • valid padding 抽離后的長(zhǎng)寬縮小了

polling

該圖片上面卷積的效果和下面卷積的效果看似一樣實(shí)際上不一樣,
上面直接將stride 設(shè)置成2進(jìn)行抽取木缝,
下面stride=1便锨,然后在進(jìn)行池化。

  • max polling
  • vaild polling

CNN 卷積神經(jīng)網(wǎng)絡(luò) 2

https://morvanzhou.github.io/tutorials/machine-learning/tensorflow/5-04-CNN2/

import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
import os

os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'

# number 1 to 10 data
mnist = input_data.read_data_sets('MNIST_data', one_hot=True)


def compute_accuracy(v_xs, v_ys):
    # 輸出準(zhǔn)確度
    global prediction
    y_pre = sess.run(prediction, feed_dict={xs: v_xs, keep_prob: 1})
    correct_prediction = tf.equal(tf.argmax(y_pre, 1), tf.argmax(v_ys, 1))
    accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
    result = sess.run(accuracy, feed_dict={xs: v_xs, ys: v_ys, keep_prob: 1})
    return result


def weight_variable(shape):
    # 根據(jù)參數(shù)形狀隨機(jī)產(chǎn)生參數(shù)
    initial = tf.truncated_normal(shape, stddev=0.1)
    return tf.Variable(initial)


def bais_vaiable(shape):
    # 偏移量我碟,b使用放案,常量0.1 一般使用正值
    initial = tf.constant(0.1, shape=shape)
    return tf.Variable(initial)


def conv2d(x, W):
    # 功能:卷積
    # 定義卷積神經(jīng)網(wǎng)絡(luò)層
    # x為輸入的層,W為該層的連接權(quán)重
    # 卷積窗口移動(dòng)步長(zhǎng):stride[1, x_movement, y_movement, 1]
    # Must have strides[0] = strides[3] = 1
    # conn2d 實(shí)現(xiàn)卷積神經(jīng)
    # strides 步長(zhǎng) 在Tesnorflow中它是4個(gè)長(zhǎng)度的列表[1,,,1]第一個(gè)和最后一個(gè)元素必須等于1
    # 第二個(gè)參數(shù) 在x方向(水平方向)跨度為  第三個(gè)參數(shù) 在y方向(豎直方向)跨度
    # 卷積的方式:padding 有兩種形式 SAME 和 VALID
    # SAME padding 中多余出來(lái)的用0來(lái)填充矫俺,因?yàn)閜adding的大小不一定等于1
    return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME')


def max_pool_2x2(x):
    # 功能:池化
    # 為了防止跨度太大吱殉,丟失信息過(guò)多,padding后要進(jìn)行pooling處理厘托,盡量保留更多的圖片信息
    # 移動(dòng)的步長(zhǎng):stride[1, x_movement, y_movement, 1] 第一個(gè)和最后一個(gè)元素必須等于1
    # kisze池化窗口的大小[1, height, weight, 1]
    # pool和卷積很相似友雳,但是他不用傳入?yún)?shù)W
    # 池化的方式: SAME 和 VALID
    return tf.nn.max_pool(x, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')


# define placeholder for inputs to network
xs = tf.placeholder(tf.float32, [None, 784])  # 28*28
ys = tf.placeholder(tf.float32, [None, 10])
keep_prob = tf.placeholder(tf.float32)
# 圖片的信息
# -1的含義是,我們自己不用去管這個(gè)維度的大小铅匹,在這里是指的是圖片樣例的個(gè)數(shù)
# 第四個(gè)參數(shù):黑白圖片是 1  彩色圖片是3 RGB
x_image = tf.reshape(xs, [-1, 28, 28, 1])
# print(x_image.shape)  # [n_sample, 28, 28, 1]
# 圖片是個(gè)三維數(shù)據(jù) 28*28*1 黑白圖片

# ********************* conv1 layer ********************* #
# 卷積1 + 池化1
W_conv1 = weight_variable([5, 5, 1, 32])  # patch 5*5, in size 1, out size 32
# feature_map = 32 卷積從圖片中提取的特征個(gè)數(shù)
# 5*5 就是卷積核的大小押赊、濾波器 filter
# insize=1 圖片的厚度是1
b_conv1 = bais_vaiable([32])
# 卷積核的個(gè)數(shù)是32 產(chǎn)生的輸出就是32  疊加起來(lái)的厚度就是32
h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1)+b_conv1)  # output size 28*28*32
# VALID padding 就不是32,而是24
# 激活函數(shù):relu  (非線性處理)
h_pool1 = max_pool_2x2(h_conv1)                         # output size 14*14*32
# tf.nn.max_pool(x, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
# strides 池化移動(dòng)的步長(zhǎng)為2包斑,2 則長(zhǎng)寬成為了原先的一半 pooling
# 卷積 和 池化 參數(shù)設(shè)置是兩會(huì)事流礁,卷積設(shè)為2 就從32變?yōu)?4,池化就從24變?yōu)?4
# 該層的輸出值

# ********************* conv2 layer ********************* #
# 卷積2 + 池化2
W_conv2 = weight_variable([5, 5, 32, 64])  # patch 5*5, in size 32, out size 64
b_conv2 = bais_vaiable([64])
# h_pool1 conv1 layer輸出的東西
h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2)+b_conv2)  # output size 14*14*64
h_pool2 = max_pool_2x2(h_conv2)                         # output size 7*7*64

# 以上卷積和池化的工作只是為了壓縮舉證特征值罗丰,不設(shè)計(jì)神經(jīng)網(wǎng)絡(luò)分類(lèi)

# ********************* func1 layer ********************* #
W_fc1 = weight_variable([7*7*64, 1024])  # 把7*7*64(乘法) 變成 1024
b_fc1 = bais_vaiable([1024])
# [n_samples, 7, 7, 64] ->> [n_samples, 7*7*64]
h_pool2_flat = tf.reshape(h_pool2, [-1, 7*7*64])   # 把pooling后三維的數(shù)據(jù)變成一個(gè)一維的數(shù)據(jù)
# [n_samples, 7, 7, 64] 變到[n_samples, 7*7*64]
h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1)
h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)  # 考慮到過(guò)擬合overfictting
# ********************* func2 layer ********************* #
# 傳入1024神帅,傳出10(判斷0,1丸卷,2枕稀,3询刹,4...9谜嫉,十個(gè)數(shù)字)
W_fc2 = weight_variable([1024, 10])
b_fc2 = bais_vaiable([10])
# 預(yù)測(cè)值
# softmax算法概率
prediction = tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2) + b_fc2)


# the error between prediction and real data
cross_entropy = tf.reduce_mean(-tf.reduce_sum(ys*tf.log(prediction), reduction_indices=[1]))

# 1e-4 = 0.0001
# 優(yōu)化沒(méi)有使用梯度下降 , 對(duì)于龐大系統(tǒng)的參數(shù)優(yōu)化就用AdamOptimizer
train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)

sess = tf.Session()

# important step
sess.run(tf.global_variables_initializer())

for i in range(1000):
    batch_xs, batch_ys = mnist.train.next_batch(100)
    sess.run(train_step, feed_dict={xs: batch_xs, ys: batch_ys, keep_prob: 1})
    if i % 50 == 0:
        print(compute_accuracy(mnist.test.images, mnist.test.labels))
lijuncheng@lijunchengdeMacBook-Pro ~/WORK/Code/TensorFlow $ cd /Users/lijuncheng/WORK/Code/TensorFlow ; env "PYTHONIOENCODING=UTF-8" "PYTHONUNBUFFERED=1"/Users/lijuncheng/anaconda3/bin/python3 /Users/lijuncheng/.vscode/extensions/ms-python.python-2018.6.0/pythonFiles/PythonTools/visualstudio_py_launcher_nodebug.py /Users/lijuncheng/WORK/Code/TensorFlow 58723 34806ad9-833a-4524-8cd6-18ca4aa74f14 RedirectOutput,RedirectOutput /Users/lijuncheng/WORK/Code/TensorFlow/python11.py
/Users/lijuncheng/anaconda3/lib/python3.6/site-packages/h5py/__init__.py:34:FutureWarning: Conversion of the second argument of issubdtype from `float` to `np.floating` is deprecated. In future, it will be treated as `np.float64 == np.dtype(float).type`.
  from ._conv import register_converters as _register_converters
Extracting MNIST_data/train-images-idx3-ubyte.gz
Extracting MNIST_data/train-labels-idx1-ubyte.gz
Extracting MNIST_data/t10k-images-idx3-ubyte.gz
Extracting MNIST_data/t10k-labels-idx1-ubyte.gz
0.0996
0.7874
0.8648
0.9067
0.9262
0.9223
0.9323
0.9437
0.9478
0.9451
0.958
0.9609
0.9532
0.9638
0.9613
0.963
0.9634
0.9666
0.9668
0.967
[1]    44912 terminated  env "PYTHONIOENCODING=UTF-8" "PYTHONUNBUFFERED=1" 58723
我想你

一直很琢磨不透這個(gè)代碼風(fēng)格提示器凹联。醉了

Saver 保存讀取

import tensorflow as tf

import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'

# Save to file
# remember to define the same dtype and shape when restore
# 在保存的時(shí)候最好定義一下數(shù)據(jù)類(lèi)型
W = tf.Variable([[1, 2, 3], [3, 4, 5]], dtype=tf.float32, name='weights')
# 保存已經(jīng)得到權(quán)重?cái)?shù)據(jù) [[1, 2, 3], [3, 4, 5]]
b = tf.Variable([[1, 2, 4]], dtype=tf.float32, name='biases')

init = tf.global_variables_initializer()
# 全局變量初始化

saver = tf.train.Saver()

with tf.Session() as sess:
    sess.run(init)
    # .ckpt后綴
    # 之前要先定義文件夾
    save_path = saver.save(sess, "my_net/save_net.ckpt")
    print("Save to path:", save_path)

lijuncheng@lijunchengdeMacBook-Pro ~/WORK/Code/TensorFlow $ cd /Users/lijuncheng/WORK/Code/TensorFlow ; env "PYTHONIOENCODING=UTF-8" "PYTHONUNBUFFERED=1" /Users/lijuncheng/anaconda3/bin/python /Users/lijuncheng/.vscode/extensions/ms-python.python-2018.6.0/pythonFiles/PythonTools/visualstudio_py_launcher_nodebug.py /Users/lijuncheng/WORK/Code/TensorFlow 60330 34806ad9-833a-4524-8cd6-18ca4aa74f14 RedirectOutput,RedirectOutput /Users/lijuncheng/WORK/Code/TensorFlow/python14.py
Save to path: my_net/save_net.ckpt
[1]    49379 terminated  env "PYTHONIOENCODING=UTF-8" "PYTHONUNBUFFERED=1"    60330

提取保存的ckpt

import tensorflow as tf
import numpy as np

import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'

# restore variables
# redefine the same shape and same type for your varibale
# 記住保存數(shù)據(jù)的形狀 和 類(lèi)型
# 定義空的框架   使用用nupmy方便
W = tf.Variable(np.arange(6).reshape((2, 3)), dtype=tf.float32, name='weights')
b = tf.Variable(np.arange(3).reshape((1, 3)), dtype=tf.float32, name='biases')
# 整個(gè)神經(jīng)網(wǎng)絡(luò)的框架也要重新定義沐兰,不能保存

# not need init step 不用定義  init = tf.global_variables_initializer()  全局初始化

saver = tf.train.Saver()
with tf.Session() as sess:
    saver.restore(sess, "my_net/save_net.ckpt")
    print("weight:", sess.run(W))
    print("biases:", sess.run(b))

lijuncheng@lijunchengdeMacBook-Pro ~/WORK/Code/TensorFlow $ cd /Users/lijuncheng/WORK/Code/TensorFlow ; env "PYTHONIOENCODING=UTF-8" "PYTHONUNBUFFERED=1" /Users/lijuncheng/anaconda3/bin/python /Users/lijuncheng/.vscode/extensions/ms-python.python-2018.6.0/pythonFiles/PythonTools/visualstudio_py_launcher_nodebug.py /Users/lijuncheng/WORK/Code/TensorFlow 60536 34806ad9-833a-4524-8cd6-18ca4aa74f14 RedirectOutput,RedirectOutput /Users/lijuncheng/WORK/Code/TensorFlow/python12.py
weight: [[1. 2. 3.]
 [3. 4. 5.]]
biases: [[1. 2. 4.]]
[1]    51475 terminated  env "PYTHONIOENCODING=UTF-8" "PYTHONUNBUFFERED=1"    60536
lijuncheng@lijunchengdeMacBook-Pro ~/WORK/Code/TensorFlow $

向莫煩老師致敬

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市蔽挠,隨后出現(xiàn)的幾起案子住闯,更是在濱河造成了極大的恐慌瓜浸,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,651評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件比原,死亡現(xiàn)場(chǎng)離奇詭異插佛,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)量窘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)雇寇,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人蚌铜,你說(shuō)我怎么就攤上這事锨侯。” “怎么了冬殃?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,931評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵囚痴,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我审葬,道長(zhǎng)深滚,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,218評(píng)論 1 292
  • 正文 為了忘掉前任耳璧,我火速辦了婚禮成箫,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘旨枯。我一直安慰自己蹬昌,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,234評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布攀隔。 她就那樣靜靜地躺著皂贩,像睡著了一般。 火紅的嫁衣襯著肌膚如雪昆汹。 梳的紋絲不亂的頭發(fā)上明刷,一...
    開(kāi)封第一講書(shū)人閱讀 51,198評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音满粗,去河邊找鬼辈末。 笑死,一個(gè)胖子當(dāng)著我的面吹牛映皆,可吹牛的內(nèi)容都是我干的挤聘。 我是一名探鬼主播,決...
    沈念sama閱讀 40,084評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼捅彻,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼组去!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起步淹,我...
    開(kāi)封第一講書(shū)人閱讀 38,926評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤从隆,失蹤者是張志新(化名)和其女友劉穎诚撵,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體键闺,經(jīng)...
    沈念sama閱讀 45,341評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡寿烟,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,563評(píng)論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了辛燥。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片韧衣。...
    茶點(diǎn)故事閱讀 39,731評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖购桑,靈堂內(nèi)的尸體忽然破棺而出畅铭,到底是詐尸還是另有隱情,我是刑警寧澤勃蜘,帶...
    沈念sama閱讀 35,430評(píng)論 5 343
  • 正文 年R本政府宣布硕噩,位于F島的核電站,受9級(jí)特大地震影響缭贡,放射性物質(zhì)發(fā)生泄漏炉擅。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,036評(píng)論 3 326
  • 文/蒙蒙 一阳惹、第九天 我趴在偏房一處隱蔽的房頂上張望谍失。 院中可真熱鬧,春花似錦莹汤、人聲如沸快鱼。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,676評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)抹竹。三九已至,卻和暖如春止潮,著一層夾襖步出監(jiān)牢的瞬間窃判,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,829評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工喇闸, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留袄琳,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,743評(píng)論 2 368
  • 正文 我出身青樓燃乍,卻偏偏與公主長(zhǎng)得像唆樊,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子橘沥,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,629評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容