ML - SVM(支持向量機)

背景:

1.1 最早是由 Vladimir N. Vapnik 和 Alexey Ya. Chervonenkis 在1963年提出

1.2 目前的版本(soft margin)是由Corinna Cortes 和 Vapnik在1993年提出凯力,并在1995年發(fā)表

1.3 深度學習(2012)出現(xiàn)之前拗秘,SVM被認為機器學習中近十幾年來最成功雕旨,表現(xiàn)最好的算法

機器學習的一般框架:

訓練集 => 提取特征向量 => 結(jié)合一定的算法(分類器:比如決策樹凡涩,KNN)=>得到結(jié)果

介紹:

3.1 例子:

兩類活箕?哪條線最好育韩?

SVM尋找區(qū)分兩類的超平面(hyper plane), 使邊際(margin)最大

總共可以有多少個可能的超平面陨舱?無數(shù)條

如何選取使邊際(margin)最大的超平面 (Max Margin Hyperplane)?

超平面到一側(cè)最近點的距離等于到另一側(cè)最近點的距離蛮粮,兩側(cè)的兩個超平面平行

線性可區(qū)分(linear separable) 和 線性不可區(qū)分 (linear inseparable)
定義與公式建立

超平面可以定義為

W: weight vectot

n 是特征值的個數(shù)

X: 訓練實例

b: bias

假設(shè)2維特征向量:X = (x1, X2)

把 b 想象為額外的 wight

超平面方程變?yōu)椋?div id="xfitlcu" class="image-package">

所有超平面右上方的點滿足:

所有超平面左下方的點滿足:

調(diào)整weight,使超平面定義邊際的兩邊:

綜合以上兩式妨蛹,得到: yi(w0 + w1x1 + w2x2) >=1蛙卤,任意i. (1)

所有坐落在邊際的兩邊的超平面上的點被稱作“支持向量(support vectors)”

分界的超平面到H1或H2上任意一點的距離為:

(i.e:其中

是向量的范數(shù)(norm))

所以,最大邊際距離為:
求解

SVM如何找出最大邊際的超平面呢(MMH)行嗤?

利用一些數(shù)學推倒,以上公式(1)可變?yōu)橛邢拗频耐箖?yōu)化問題(convex quadratic optimization)

利用Karush-Kuhn-Tucker(KKT)條件和拉格朗日公式既琴,可以推出MMH可以被表示為以下“決定邊界”(decision boundary)

其中甫恩,yi是支持向量點Xi(support vector)的類別標記(class lable)

是要測試的實例

和 b0 都是單一數(shù)值型參數(shù)磺箕,由以上提到的最優(yōu)算法得出

l 是支持向量點的個數(shù)

對于任何測試(要歸類的)實例简僧,帶入以上公式岛马,得出的符號是正還是負決定

例子:

說明:(2,3)減去(1,1)可以把weight表示為 (a,2a)

應(yīng)用
  • sklearn簡單例子(上圖三個點計算svm)
 from sklearn import svm

X = [[2, 0], [1, 1], [2, 3]]

# 假設(shè)前兩個為一類,第三個點為另外一類
y = [0, 0, 1]
clf = svm.SVC(kernel='linear')
clf.fit(X, y)

print(clf)

# get support vectors
print(clf.support_vectors_)

# get indices of support vectors(找到支持向量在list x中的下標)
print(clf.support_)

# get number of support vectors for each class(在兩個分類中各找到了幾個支持向量)
print(clf.n_support_)

# 輸出結(jié)果:
# SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0,
#   decision_function_shape='ovr', degree=3, gamma='auto', kernel='linear',
#   max_iter=-1, probability=False, random_state=None, shrinking=True,
#   tol=0.001, verbose=False)
# [[1. 1.]
#  [2. 3.]]
# [1 2]
# [1 1]
  • sklearn畫出決定界限
import numpy as np
import pylab as pl
from sklearn import svm

# we create 40 separable points,多次運行程序隨機生成的點不變
np.random.seed(0)
# 隨機生成20個點的列表np.random.randn(20, 2)
X = np.r_[np.random.randn(20, 2) - [2, 2], np.random.randn(20, 2) + [2, 2]]
# 前20個點分為一類夏志,后20個點分為一類
Y = [0] * 20 + [1] * 20

# fit the model
clf = svm.SVC(kernel='linear')
clf.fit(X, Y)

# 得到分離超平面
w = clf.coef_[0]
a = -w[0] / w[1]
# 產(chǎn)生-5到5的連續(xù)點
xx = np.linspace(-5, 5)
yy = a * xx - (clf.intercept_[0]) / w[1]

# 繪制與通過的分離超平面的平行線
b = clf.support_vectors_[0]
yy_down = a * xx + (b[1] - a * b[0])
b = clf.support_vectors_[-1]
yy_up = a * xx + (b[1] - a * b[0])

print("w: ", w)
print("a: ", a)
# print " xx: ", xx
# print " yy: ", yy
print("support_vectors_: ", clf.support_vectors_)
print("clf.coef_: ", clf.coef_)

#在scikit - learn中沟蔑,coef_屬性保存線性模型的分離超平面的向量。
#在二進制分類示例中浦旱,n_features == 2宣蠕,因此w = coef_[0]是與超平面正交的向量

#在2D情況下繪制此超平面(2D平面的任何超平面都是1D線)抢蚀,
#我們想找到一個f皿曲,如y = f(x)= a.x + b屋休。 在這種情況下劫樟,a是線的斜率奶陈,可以通過a = -w[0] / w[1]來計算吃粒。


# 繪制線徐勃,點和平面的最近向量
pl.plot(xx, yy, 'k-')
pl.plot(xx, yy_down, 'k--')
pl.plot(xx, yy_up, 'k--')

pl.scatter(clf.support_vectors_[:, 0], clf.support_vectors_[:, 1],
           s=80, facecolors='none')
pl.scatter(X[:, 0], X[:, 1], c=Y, cmap=pl.cm.Paired)

pl.axis('tight')
pl.show()

運行結(jié)果:

w:  [0.90230696 0.64821811]
a:  -1.391980476255765
support_vectors_:  [[-1.02126202  0.2408932 ]
 [-0.46722079 -0.53064123]
 [ 0.95144703  0.57998206]]
clf.coef_:  [[0.90230696 0.64821811]]
  • SVM算法特性
  • 訓練好的模型的算法復雜度是由支持向量的個數(shù)決定的,而不是由數(shù)據(jù)的維度決定的扎酷。所以SVM不太容易產(chǎn)生overfitting

  • SVM訓練出來的模型完全依賴于支持向量(Support Vectors), 即使訓練集里面所有非支持向量的點都被去除,重復訓練過程幅聘,結(jié)果仍然會得到完全一樣的模型荐糜。

  • 一個SVM如果訓練得出的支持向量個數(shù)比較小暴氏,SVM訓練出的模型比較容易被泛化必怜。

2 .線性不可分的情況 (linearly inseparable case)
線性不可分
  • 數(shù)據(jù)集在空間中對應(yīng)的向量不可被一個超平面區(qū)分開

  • 兩個步驟來解決:

  1. 利用一個非線性的映射把原數(shù)據(jù)集中的向量點轉(zhuǎn)化到一個更高維度的空間中

  2. 在這個高維度的空間中找一個線性的超平面來根據(jù)線性可分的情況處理

轉(zhuǎn)換到高維空間進行線性區(qū)分
線性不可分
建立映射進行區(qū)分

視覺化演示

2.1 如何利用非線性映射把原始數(shù)據(jù)轉(zhuǎn)化到高維中?

3維輸入向量:



轉(zhuǎn)化到6維空間 Z 中去:



新的決策超平面:



其中W和Z是向量嗦明,這個超平面是線性的解出W和b之后,并且?guī)牖卦匠蹋?/p>

思考問題:

1: 如何選擇合理的非線性轉(zhuǎn)化把數(shù)據(jù)轉(zhuǎn)到高緯度中邻薯?

2: 如何解決計算內(nèi)積時算法復雜度非常高的問題厕诡?

  1. 核方法(kernel trick)
    動機: 在線性SVM中轉(zhuǎn)化為最優(yōu)化問題時求解的公式計算都是以內(nèi)積(dot product)的形式出現(xiàn)的



    ,其中
    是把訓練集中的向量點轉(zhuǎn)化到高維的非線性映射函數(shù)寿羞,因為內(nèi)積的算法復雜度非常大绪穆,所以我們利用核函數(shù)來取代計算非線性映射函數(shù)的內(nèi)積

3.1 以下核函數(shù)和非線性映射函數(shù)的內(nèi)積等同


3.2 常用的核函數(shù)(kernel functions)

  • h度多項式核函數(shù)(polynomial kernel of degree h):
  • 高斯徑向基核函數(shù)(Gaussian radial basis function kernel):


  • S型核函數(shù)(Sigmoid function kernel):

如何選擇使用哪個kernel第岖?根據(jù)先驗知識蔑滓,比如圖像分類键袱,通常使用RBF杠纵,文字不使用RBF,嘗試不同的kernel铝量,根據(jù)結(jié)果準確度而定慢叨。

3.3 核函數(shù)舉例:

假設(shè)定義兩個向量: x = (x1, x2, x3); y = (y1, y2, y3)
定義方程:f(x) = (x1x1, x1x2, x1x3, x2x1, x2x2, x2x3, x3x1, x3x2, x3x3)

K(x, y ) = (<x, y>)^2

假設(shè)x = (1, 2, 3); y = (4, 5, 6).

f(x) = (1, 2, 3, 2, 4, 6, 3, 6, 9)
f(y) = (16, 20, 24, 20, 25, 36, 24, 30, 36)
<f(x), f(y)> = 16 + 40 + 72 + 40 + 100+ 180 + 72 + 180 + 324 = 1024

K(x, y) = (4 + 10 + 18 ) ^2 = 32^2 = 1024
同樣的結(jié)果,使用kernel方法計算容易很多。

  1. SVM擴展可解決多個類別分類問題
    對于每個類践瓷,有一個當前類和其他類的二類分類器(one-vs-rest)
利用SVM進行人臉識別實例:
from __future__ import print_function
# 從time模塊導入time晕翠,因為有些步驟需要計時
from time import time
# 打印出一些程序進展信息
import logging
# 繪圖的包淋肾,即最后將我們預測出來的人臉打印出來
import matplotlib.pyplot as plt

from sklearn.cross_validation import train_test_split
from sklearn.datasets import fetch_lfw_people
from sklearn.grid_search import GridSearchCV
from sklearn.metrics import classification_report
from sklearn.metrics import confusion_matrix
from sklearn.decomposition import PCA
from sklearn import svm

# 打印輸出日志信息
logging.basicConfig(level=logging.INFO, format='%(asctime)s%(message)s')
# 下載數(shù)據(jù)集--戶外臉部數(shù)據(jù)集lfw(Labeled Faces in the Wild)
# minfaces_per_person:int,可選默認無樊卓,提取的數(shù)據(jù)集僅保留包含min_faces_per_person不同圖片的人的照片
# resize調(diào)整每張人臉圖片的比例碌尔,默認是0.5
lfw_people = fetch_lfw_people(min_faces_per_person=70, resize=0.4)
# 返回數(shù)據(jù)集有多少個實例,h是多少陪白,w是多少
n_samples, h, w = lfw_people.images.shape
# X矩陣用來裝特征向量咱士,得到數(shù)據(jù)集的所有實例
# 每一行是一個實例序厉,每一列是個特征值
X = lfw_people.data
# X矩陣調(diào)用shape返回矩陣的行數(shù)和列數(shù)弛房,
# X.shape[1]返回矩陣的列數(shù)文捶,對應(yīng)的特征向量的維度或者特征點多少
n_features = X.shape[1]
# 獲取特征結(jié)果集粹排,提取每個實例對應(yīng)的每個人臉
# y為classlabel目標分類標記顽耳,即不同人的身份
y = lfw_people.target
# 數(shù)據(jù)集中有多少個人膝迎,以人名組成列表返回
target_names = lfw_people.target_names
# shape[0]就是多少行限次,多少個人掂恕,多少類
n_classes = target_names.shape[0]

print("Total dataset size:")  # 數(shù)據(jù)集中信息
print("n_samples:%d" % n_samples)  # 數(shù)據(jù)個數(shù)1288
print("n_features:%d" % n_features)  # 特征個數(shù)懊亡,維度1850
print("n_classes:%d" % n_classes)  # 結(jié)果集類別個數(shù)店枣,即多少個人

# 結(jié)果
# Total dataset size:
# n_samples:1288
# n_features:1850
# n_classes:7

# 利用train_test_split拆分訓練集合測試集
# test_size=0.25表示隨機抽取25%的測試集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25)

# 采用PCA降維鸯两,原始數(shù)據(jù)的特征向量維度非常高钧唐,意味著訓練模型的復雜度非常高
# 保存的組件數(shù)目钝侠,也即保留下來的特征個數(shù)n
n_components = 150

print("Exreacting the top %d eigenfaces from %faces" % (n_components, X_train.shape[0]))
# 初始時間
t0 = time()
# 降維
pca = PCA(n_components=n_components, whiten=True).fit(X_train)
print("pca done in %0.3fs" % (time() - t0))
# 從人臉中提取特征點帅韧,對于人臉的一張照片提取的特征值名為eigenfaces
eigenfaces = pca.components_.reshape((n_components, h, w))

print("projecting the input data on the eigenfaces orthonormal basis")
t0 = time()
# 把訓練集特征向量轉(zhuǎn)化為更低維的矩陣
X_train_pca = pca.transform(X_train)
# 把測試集的特征向量轉(zhuǎn)化為更低維的矩陣
X_test_pca = pca.transform(X_test)
print("done in %0.3fs" % (time() - t0))

# 訓練一個支持向量機的分類model——構(gòu)造分類器
print("Fitting the classifier to the training set")
t0 = time()

# c是一個對錯誤德部分的懲罰
# gamma的參數(shù)對不同核函數(shù)有不同的表現(xiàn)忽舟,gamma表示使用多少比例的特征點
# 使用不同的c和不同值的gamma叮阅,進行多個量的嘗試帘饶,然后進行搜索及刻,選出準確率最高模型
param_grid = {
    'C': [1e3, 5e3, 1e4, 5e4, 1e5],
    'gamma': [0.0001, 0.0005, 0.001, 0.005, 0.01, 0.1]
}
# 調(diào)用SVM進行分類搜索哪對組合產(chǎn)生最好的歸類精確度
# ernel:rbf高斯徑向基核函數(shù)   class_weight權(quán)重
# 把所有我們所列參數(shù)的組合都放在SVC里面進行計算缴饭,最后看出哪一組函數(shù)的表現(xiàn)度最好
clf = GridSearchCV(svm.SVC(kernel='rbf', class_weight='balanced'), param_grid=param_grid)
clf = clf.fit(X_train_pca, y_train)
print("fit done in %0.3fs" % (time() - t0))
print("Best estimator found by grid search:")
print(clf.best_estimator_)

##################進行評估準確率計算######################
print("Predicting people's names on the test set")
t0 = time()
# 預測新的分類
y_pred = clf.predict(X_test_pca)
print("done in %0.3fs" % (time() - t0))
# 通過classification_report方法進行查看担猛,可以得到預測結(jié)果中哪些是正確
print(classification_report(y_test, y_pred, target_names=target_names))
# confusion_matrix是建一個n*n的方格傅联,橫行和縱行分別表示真實的每一組測試的標記和測試集標記的差別
# 對角線表示的是正確的值蒸走,對角線數(shù)字越多表示準確率越高
print(confusion_matrix(y_test, y_pred, labels=range(n_classes)))


# 將測試標記過進行展示比驻,即先弄一個通用的圖片可視化函數(shù):
def plot_gallery(images, titles, h, w, n_row=3, n_col=4):
    """Helper function to plot a gallery of portraits"""
    # 建立圖作為背景
    # 自定義畫布大小
    plt.figure(figsize=(1.8 * n_col, 2.4 * n_row))
    # 位置調(diào)整
    plt.subplots_adjust(bottom=0, left=.01, right=.99, top=.90, hspace=.35)
    for i in range(n_row * n_col):
        # 設(shè)置畫布劃分以及圖像在畫布上輸出的位置
        plt.subplot(n_row, n_col, i + 1)
        # 在軸上顯示圖片
        plt.imshow(images[i].reshape((h, w)), cmap=plt.cm.gray)
        # 整個畫板的標題
        plt.title(titles[i], size=12)
        # 獲取或設(shè)置x别惦、y軸的當前刻度位置和標簽
        plt.xticks(())
        plt.yticks(())


# 預測函數(shù)歸類標簽和實際歸類標簽打印
# 返回預測人臉姓和測試人臉姓的對比title
def title(y_pred, y_test, target_names, i):
    # rsplit(' ',1)從右邊開始以右邊第一個空格為界掸掸,分成兩個字符
    # 組成一個list
    # 此處代表把'姓'和'名'分開猾漫,然后把后面的姓提出來
    # 末尾加[-1]代表引用分割后的列表最后一個元素
    pred_name = target_names[y_pred[i]].rsplit(' ', 1)[-1]
    true_name = target_names[y_test[i]].rsplit(' ', 1)[-1]
    return 'predicted:%s\ntrue:  %s' % (pred_name, true_name)


# 預測出的人名
prediction_titles = [title(y_pred, y_test, target_names, i)
                     for i in range(y_pred.shape[0])]
# 測試集的特征向量矩陣和要預測的人名打印
plot_gallery(X_test, prediction_titles, h, w)
# 打印原圖和預測的信息
eigenface_titles = ["eigenface %d" % i for i in range(eigenfaces.shape[0])]
# 調(diào)用plot_gallery函數(shù)打印出實際是誰,預測的誰粒督,以及提取過特征的臉
# plot_gallery(eigenfaces, eigenface_titles, h, w)

plt.show()

# 結(jié)果
# Predicting people's names on the test set
# done in 0.053s
#                    precision    recall  f1-score   support
#      Ariel Sharon       0.89      0.47      0.62        17
#      Colin Powell       0.77      0.93      0.84        60
#   Donald Rumsfeld       0.94      0.64      0.76        25
#     George W Bush       0.83      0.96      0.89       137
# Gerhard Schroeder       0.88      0.79      0.83        28
#       Hugo Chavez       1.00      0.47      0.64        15
#        Tony Blair       0.91      0.78      0.84        40
#       avg / total       0.85      0.84      0.83       322
# [[  8   5   0   4   0   0   0]
#  [  0  56   0   4   0   0   0]
#  [  0   2  16   7   0   0   0]
#  [  0   6   0 131   0   0   0]
#  [  1   1   0   2  22   0   2]
#  [  0   1   0   5   1   7   1]
#  [  0   2   1   4   2   0  31]]

結(jié)果:


預測結(jié)果
特征點
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市礁哄,隨后出現(xiàn)的幾起案子溪北,更是在濱河造成了極大的恐慌,老刑警劉巖茉继,帶你破解...
    沈念sama閱讀 212,718評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件烁竭,死亡現(xiàn)場離奇詭異派撕,居然都是意外死亡终吼,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,683評論 3 385
  • 文/潘曉璐 我一進店門佩脊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來威彰,“玉大人歇盼,你說我怎么就攤上這事豹缀⌒象希” “怎么了氮惯?”我有些...
    開封第一講書人閱讀 158,207評論 0 348
  • 文/不壞的土叔 我叫張陵妇汗,是天一觀的道長杨箭。 經(jīng)常有香客問我储狭,道長,這世上最難降的妖魔是什么擒悬? 我笑而不...
    開封第一講書人閱讀 56,755評論 1 284
  • 正文 為了忘掉前任侈净,我火速辦了婚禮畜侦,結(jié)果婚禮上躯保,老公的妹妹穿的比我還像新娘途事。我一直安慰自己,他們只是感情好义图,可當我...
    茶點故事閱讀 65,862評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著奏夫,像睡著了一般。 火紅的嫁衣襯著肌膚如雪廊谓。 梳的紋絲不亂的頭發(fā)上蹂析,一...
    開封第一講書人閱讀 50,050評論 1 291
  • 那天,我揣著相機與錄音竖共,去河邊找鬼公给。 笑死,一個胖子當著我的面吹牛淌铐,可吹牛的內(nèi)容都是我干的际起。 我是一名探鬼主播吐葱,決...
    沈念sama閱讀 39,136評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼灾前,長吁一口氣:“原來是場噩夢啊……” “哼哎甲!你這毒婦竟也來了炭玫?” 一聲冷哼從身側(cè)響起础嫡,我...
    開封第一講書人閱讀 37,882評論 0 268
  • 序言:老撾萬榮一對情侶失蹤榴鼎,失蹤者是張志新(化名)和其女友劉穎巫财,沒想到半個月后平项,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體闽瓢,經(jīng)...
    沈念sama閱讀 44,330評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡扣讼,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,651評論 2 327
  • 正文 我和宋清朗相戀三年椭符,在試婚紗的時候發(fā)現(xiàn)自己被綠了销钝。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,789評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡纵装,死狀恐怖诗箍,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情瓶籽,我是刑警寧澤,帶...
    沈念sama閱讀 34,477評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站扬绪,受9級特大地震影響种蘸,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜航瞭,卻給世界環(huán)境...
    茶點故事閱讀 40,135評論 3 317
  • 文/蒙蒙 一诫硕、第九天 我趴在偏房一處隱蔽的房頂上張望刊侯。 院中可真熱鬧,春花似錦纲菌、人聲如沸疮绷。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,864評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽只冻。三九已至喜德,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間舍悯,已是汗流浹背朴艰。 一陣腳步聲響...
    開封第一講書人閱讀 32,099評論 1 267
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留金矛,地道東北人饼酿。 一個月前我還...
    沈念sama閱讀 46,598評論 2 362
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親碌廓。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,697評論 2 351

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

  • SVM SVM有很多種實現(xiàn),本文只關(guān)注其中最流行的一種實現(xiàn),即序列最小優(yōu)化(SMO)算法。 支持向量機是一種分類器...
    洛克黃瓜閱讀 1,225評論 0 0
  • 【概述】 SVM訓練分類器的方法是尋找到超平面,使正負樣本在超平面的兩側(cè)(分類正確性即“分得開”),且樣本到超平面...
    sealaes閱讀 11,046評論 0 7
  • 1. 背景: 最早是由 Vladimir N. Vapnik 和 Alexey Ya. Chervonenkis ...
    foochane閱讀 1,138評論 0 0
  • 支持向量機:是一種監(jiān)督式學習的方法,可廣泛地應(yīng)用于統(tǒng)計分類以及回歸分析酬诀。支持向量機屬于一般化線性分類器肴裙,這族分類器...
    Vince_zzhang閱讀 1,259評論 0 0
  • 姓名:劉小瓊 公司:寧波大發(fā)化纖有限公司 期數(shù):第235期六項精進 日精進打卡第265天 [知~學習] 六項精進 ...
    劉小瓊282閱讀 86評論 0 0