【深度學習】深度學習md筆記總結第1篇:深度學習課程,要求【附程式碼文件】

程序员一诺yinuo發表於2024-03-19

深度學習筆記完整教程(附程式碼資料)主要內容講述:深度學習課程,深度學習介紹要求,目標,學習目標,1.1.1 區別。TensorFlow介紹,2.2 圖與TensorBoard學習目標,2.2.1 什麼是圖結構,2.2.2 圖相關操作,2.2.3 TensorBoard:視覺化學習。TensorFlow介紹,2.4 張量學習目標,2.4.1 張量(Tensor),2.4.2 建立張量的指令,2.4.3 張量的變換。TensorFlow介紹,2.7 案例:實現線性迴歸學習目標,2.7.1 線性迴歸原理複習,2.7.2 案例:實現線性迴歸的訓練,2.7.3 增加其他功能。TensorFlow介紹,1.2 神經網路基礎學習目標。TensorFlow介紹,總結學習目標,1.3.1 神經網路,1.3.2 playground使用。神經網路與tf.keras,1.4 神經網路原理學習目標,1.4.1 softmax迴歸,1.4.2 交叉熵損失,1.4.3 梯度下降演算法。神經網路與tf.keras,1.3 Tensorflow實現神經網路學習目標,1.3.1 TensorFlow keras介紹,1.3.2 案例:實現多層神經網路進行時裝分類。神經網路與tf.keras,1.4 深層神經網路學習目標。神經網路與tf.keras,總結。卷積神經網路,3.1 卷積神經網路(CNN)原理學習目標。卷積神經網路,3.1 卷積神經網路(CNN)原理學習目標。卷積神經網路,2.2案例:CIFAR100類別分類學習目標,2.2.1 CIFAR100資料集介紹,2.2.2 API 使用,2.2.3 步驟分析以及程式碼實現(縮減版LeNet5)。卷積神經網路,2.2 梯度下降演算法改進學習目標。卷積神經網路,2.4 BN與神經網路調優學習目標。卷積神經網路,2.4 經典分類網路結構學習目標,2.4.6 案例:使用pre_trained模型進行VGG預測,2.4.7 總結。卷積神經網路,2.5 CNN網路實戰技巧學習目標。卷積神經網路,3.1 遷移學習案例3.1.1 案例:基於VGG對五種圖片類別識別的遷移學習,3.1.2 資料增強的作用。卷積神經網路,總結學習目標,1.1.1 專案演示,1.1.2 專案結構,1.1.3 專案知識點。商品物體檢測專案介紹,3.3 R-CNN。商品物體檢測專案介紹,3.4 Fast R-CNN。YOLO與SSD,3.6 YOLO(You only look once)。YOLO與SSD,4.3 案例:SSD進行物體檢測4.3.1 案例效果,4.3.2 案例需求,4.3.3 步驟分析以及程式碼,2.1.1 常用目標檢測資料集。商品檢測資料集訓練,5.2 標註資料讀取與儲存5.2.1 案例:xml讀取本地檔案儲存到pkl,5.3.1 案例訓練結果,5.3.2 案例思路,5.3.3 多GPU訓練程式碼修改。

全套筆記資料程式碼移步: 前往gitee倉庫檢視

感興趣的小夥伴可以自取哦,歡迎大家點贊轉發~


全套教程部分目錄:


部分檔案圖片:

深度學習課程

要求

  • 熟練掌握機器學習基礎,如分類、迴歸
  • 熟練掌握numpy,pandas,sklearn等框架使用

目標

  • 演算法

    • 掌握神經網路的數學原理

    • 手動實現簡單的神經網路結構

  • 應用

    • 熟練掌握TensorFlow框架使用
    • 掌握神經網路影像相關案例

深度學習介紹

1.1 深度學習與機器學習的區別

學習目標

  • 目標

    • 知道深度學習與機器學習的區別
  • 應用

1.1.1 區別

區別

1.1.1.1 特徵提取方面

  • 機器學習的特徵工程步驟是要靠手動完成的,而且需要大量領域專業知識
  • 深度學習通常由多個層組成,它們通常將更簡單的模型組合在一起,透過將資料從一層傳遞到另一層來構建更復雜的模型。透過大量資料的訓練自動得到模型,不需要人工設計特徵提取環節

深度學習演算法試圖從資料中學習高階功能,這是深度學習的一個非常獨特的部分。因此,減少了為每個問題開發新特徵提取器的任務。適合用在難提取特徵的影像、語音、自然語言領域

1.1.1.2 資料量

機器學習需要的執行時間遠少於深度學習,深度學習引數往往很龐大,需要透過大量資料的多次最佳化來訓練引數。

資料量

第一、它們需要大量的訓練資料集

第二、是訓練深度神經網路需要大量的算力

可能要花費數天、甚至數週的時間,才能使用數百萬張影像的資料集訓練出一個深度網路。所以以後

  • 需要強大對的GPU伺服器來進行計算
  • 全面管理的分散式訓練與預測服務——比如[谷歌 TensorFlow 雲機器學習平臺]( CPU 和 GPU

1.1.2 演算法代表

  • 機器學習

    • 樸素貝葉斯、決策樹等
  • 深度學習

    • 神經網路

深度學習的應用場景

學習目標

  • 目標

    • 知道深度學習的主要應用場景
  • 應用

  • 影像識別

    • 物體識別
    • 場景識別
    • 車型識別
    • 人臉檢測跟蹤
    • 人臉關鍵點定位
    • 人臉身份認證
  • 自然語言處理技術

    • 機器翻譯
    • 文字識別
    • 聊天對話
  • 語音技術

    • 語音識別

1.2 深度學習框架介紹

學習目標

  • 目標

    • 瞭解常見的深度學習框架
    • 瞭解TensorFlow框架
  • 應用

1.2.1 常見深度學習框架對比

框架關注

tensorflow的github:

1.2.2 TensorFlow的特點

tensorflow

官網:[

  • 語言多樣(Language Options)

    • TensorFlow使用C++實現的,然後用Python封裝。谷歌號召社群透過SWIG開發更多的語言介面來支援TensorFlow
  • 使用分發策略進行分發訓練

    • 對於大型 ML 訓練任務,分發策略 API使在不更改模型定義的情況下,可以輕鬆地在不同的硬體配置上分發和訓練模型。由於 TensorFlow 支援一系列硬體加速器,如 CPU、GPU 和 TPU
  • Tensorboard視覺化

    • TensorBoard是TensorFlow的一組Web應用,用來監控TensorFlow執行過程
  • 在任何平臺上的生產中進行強大的模型部署

一旦您訓練並儲存了模型,就可以直接在應用程式中執行它,或者使用部署庫為其提供服務:

  • [TensorFlow 服務]( HTTP/REST 或 GRPC/協議緩衝區提供服務的 TensorFlow 庫構建。
  • [TensorFlow Lite]( 針對移動和嵌入式裝置的輕量級解決方案提供了在 Android、iOS 和嵌入式系統上部署模型的能力。
  • [tensorflow.js]( JavaScript 環境中部署模型,例如在 Web 瀏覽器或伺服器端透過 Node.js 部署模型。TensorFlow.js 還支援在 JavaScript 中定義模型,並使用類似於 Kera 的 API 直接在 Web 瀏覽器中進行訓練。

1.2.3 TensorFlow的安裝

安裝 TensorFlow在64 位系統上測試這些系統支援 TensorFlow:

  • Ubuntu 16.04 或更高版本
  • Windows 7 或更高版本
  • macOS 10.12.6 (Sierra) 或更高版本(不支援 GPU)

進入虛擬環境當中再安裝。剛開始的環境比較簡單,只要下載tensorflow即可

  • 環境包:

安裝較慢,指定映象源,請在帶有numpy等庫的虛擬環境中安裝

  • ubuntu安裝
pip install tensorflow==1.12 -i 
  • MacOS安裝
pip install tensorflow==1.12 -i 

注:如果需要下載GPU版本的(TensorFlow只提供windows和linux版本的,沒有Macos版本的)參考官網[

1、虛擬機器下linux也是用不了GPU版本TensorFlow

2、本機單獨的windows和本機單獨的unbuntu可以使用GPU版本TensorFlow,需要安裝相關驅動

1.2.4 Tenssorlfow使用技巧

  • 使用**[tf.keras](
  • tensorflow提供模型訓練模型部署

TensorFlow介紹

說明TensorFlow的資料流圖結構
應用TensorFlow操作圖
說明會話在TensorFlow程式中的作用
應用TensorFlow實現張量的建立、形狀型別修改操作
應用Variable實現變數op的建立
應用Tensorboard實現圖結構以及張量值的顯示
應用tf.train.saver實現TensorFlow的模型儲存以及載入
應用tf.app.flags實現命令列引數新增和使用
應用TensorFlow實現線性迴歸

2.1 TF資料流圖

學習目標

  • 目標

    • 說明TensorFlow的資料流圖結構
  • 應用

  • 內容預覽

    • 2.1.1 案例:TensorFlow實現一個加法運算

      • 1 程式碼
      • 2 TensorFlow結構分析
    • 2.1.2 資料流圖介紹

2.1.1 案例:TensorFlow實現一個加法運算

2.1.1.1 程式碼

def tensorflow_demo():
    """
    透過簡單案例來了解tensorflow的基礎結構
    :return: None
    """
    # 一、原生python實現加法運算
    a = 10
    b = 20
    c = a + b
    print("原生Python實現加法運算方法1:\n", c)
    def add(a, b):
        return a + b
    sum = add(a, b)
    print("原生python實現加法運算方法2:\n", sum)

    # 二、tensorflow實現加法運算
    a_t = tf.constant(10)
    b_t = tf.constant(20)
    # 不提倡直接運用這種符號運算子進行計算
    # 更常用tensorflow提供的函式進行計算
    # c_t = a_t + b_t
    c_t = tf.add(a_t, b_t)
    print("tensorflow實現加法運算:\n", c_t)
    # 如何讓計算結果出現?
    # 開啟會話
    with tf.Session() as sess:
        sum_t = sess.run(c_t)
        print("在sess當中的sum_t:\n", sum_t)

    return None

注意問題:警告指出你的CPU支援AVX運算加速了線性代數計算,即點積,矩陣乘法,卷積等。可以從原始碼安裝TensorFlow來編譯,當然也可以選擇關閉

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

2.1.1.2 TensorFlow結構分析

TensorFlow 程式通常被組織成一個構建圖階段和一個執行圖階段。

在構建階段,資料與操作的執行步驟被描述成一個圖。

在執行階段,使用會話執行構建好的圖中的操作。

  • 圖和會話 :

    • 圖:這是 TensorFlow 將計算表示為指令之間的依賴關係的一種表示法
    • 會話:TensorFlow 跨一個或多個本地或遠端裝置執行資料流圖的機制
  • 張量:TensorFlow 中的基本資料物件

  • 節點:提供圖當中執行的操作

2.1.2 資料流圖介紹

![](https://img2024.cnblogs.com/other/3367718/202403/3367718-20240319195652050-1316767910.png) ![](https://img2024.cnblogs.com/other/3367718/202403/3367718-20240319195652401-1868723764.png)
TensorFlow是一個採用資料流圖(data flow graphs),用於數值計算的開源框架。

節點(Operation)在圖中表示數學操作,線(edges)則表示在節點間相互聯絡的多維資料陣列,即張量(tensor)。

TensorFlow介紹

說明TensorFlow的資料流圖結構
應用TensorFlow操作圖
說明會話在TensorFlow程式中的作用
應用TensorFlow實現張量的建立、形狀型別修改操作
應用Variable實現變數op的建立
應用Tensorboard實現圖結構以及張量值的顯示
應用tf.train.saver實現TensorFlow的模型儲存以及載入
應用tf.app.flags實現命令列引數新增和使用
應用TensorFlow實現線性迴歸

2.2 圖與TensorBoard

學習目標

  • 目標

    • 說明圖的基本使用
    • 應用tf.Graph建立圖、tf.get_default_graph獲取預設圖
    • 知道開啟TensorBoard過程
    • 知道圖當中op的名字以及名稱空間
  • 應用

  • 內容預覽

    • 2.2.1 什麼是圖結構

    • 2.2.2 圖相關操作

      • 1 預設圖
      • 2 建立圖
    • 2.2.3 TensorBoard:視覺化學習

      • 1 資料序列化-events檔案
      • 2 啟動TensorBoard
    • 2.2.4 OP

      • 1 常見OP
      • 2 指令名稱

2.2.1 什麼是圖結構

圖包含了一組tf.Operation代表的計算單元物件和tf.Tensor代表的計算單元之間流動的資料。

2.2.2 圖相關操作

1 預設圖

通常TensorFlow會預設幫我們建立一張圖。

檢視預設圖的兩種方法:

  • 透過呼叫tf.get_default_graph()訪問 ,要將操作新增到預設圖形中,直接建立OP即可。
  • op、sess都含有graph屬性 ,預設都在一張圖中
def graph_demo():
    # 圖的演示
    a_t = tf.constant(10)
    b_t = tf.constant(20)
    # 不提倡直接運用這種符號運算子進行計算
    # 更常用tensorflow提供的函式進行計算
    # c_t = a_t + b_t
    c_t = tf.add(a_t, b_t)
    print("tensorflow實現加法運算:\n", c_t)

    # 獲取預設圖
    default_g = tf.get_default_graph()
    print("獲取預設圖:\n", default_g)

    # 資料的圖屬性
    print("a_t的graph:\n", a_t.graph)
    print("b_t的graph:\n", b_t.graph)
    # 操作的圖屬性
    print("c_t的graph:\n", c_t.graph)

    # 開啟會話
    with tf.Session() as sess:
        sum_t = sess.run(c_t)
        print("在sess當中的sum_t:\n", sum_t)
        # 會話的圖屬性
        print("會話的圖屬性:\n", sess.graph)

    return None

2 建立圖

  • 可以透過tf.Graph()自定義建立圖

  • 如果要在這張圖中建立OP,典型用法是使用tf.Graph.as_default()上下文管理器

def graph_demo():
    # 圖的演示
    a_t = tf.constant(10)
    b_t = tf.constant(20)
    # 不提倡直接運用這種符號運算子進行計算
    # 更常用tensorflow提供的函式進行計算
    # c_t = a_t + b_t
    c_t = tf.add(a_t, b_t)
    print("tensorflow實現加法運算:\n", c_t)

    # 獲取預設圖
    default_g = tf.get_default_graph()
    print("獲取預設圖:\n", default_g)

    # 資料的圖屬性
    print("a_t的graph:\n", a_t.graph)
    print("b_t的graph:\n", b_t.graph)
    # 操作的圖屬性
    print("c_t的graph:\n", c_t.graph)

    # 自定義圖
    new_g = tf.Graph()
    print("自定義圖:\n", new_g)
    # 在自定義圖中去定義資料和操作
    with new_g.as_default():
        new_a = tf.constant(30)
        new_b = tf.constant(40)
        new_c = tf.add(new_a, new_b)

    # 資料的圖屬性
    print("new_a的graph:\n", new_a.graph)
    print("new_b的graph:\n", new_b.graph)
    # 操作的圖屬性
    print("new_c的graph:\n", new_c.graph)

    # 開啟會話
    with tf.Session() as sess:
        sum_t = sess.run(c_t)
        print("在sess當中的sum_t:\n", sum_t)
        # 會話的圖屬性
        print("會話的圖屬性:\n", sess.graph)
        # 不同的圖之間不能互相訪問
        # sum_new = sess.run(new_c)
        # print("在sess當中的sum_new:\n", sum_new)

    with tf.Session(graph=new_g) as sess2:
        sum_new = sess2.run(new_c)
        print("在sess2當中的sum_new:\n", sum_new)
        print("會話的圖屬性:\n", sess2.graph)

    # 很少會同時開啟不同的圖,一般用預設的圖就夠了
    return None

TensorFlow有一個亮點就是,我們能看到自己寫的程式的視覺化效果,這個功能就是Tensorboard。在這裡我們先簡單介紹一下其基本功能。

2.2.3 TensorBoard:視覺化學習

TensorFlow 可用於訓練大規模深度神經網路所需的計算,使用該工具涉及的計算往往復雜而深奧。為了更方便 TensorFlow 程式的理解、除錯與最佳化,TensorFlow提供了TensorBoard 視覺化工具。

Tensorboard

實現程式視覺化過程:

1 資料序列化-events檔案

TensorBoard 透過讀取 TensorFlow 的事件檔案來執行,需要將資料生成一個序列化的 Summary protobuf 物件。

  
  
# 返回filewriter,寫入事件檔案到指定目錄(最好用絕對路徑),以提供給tensorboard使用
  
  
tf.summary.FileWriter('./tmp/summary/test/', graph=sess.graph)

這將在指定目錄中生成一個 event 檔案,其名稱格式如下:

events.out.tfevents.{timestamp}.{hostname}

2 啟動TensorBoard

tensorboard  --logdir="./tmp/tensorflow/summary/test/"

在瀏覽器中開啟 TensorBoard 的圖頁面 [127.0.0.1:6006](

![](https://img2024.cnblogs.com/other/3367718/202403/3367718-20240319195652856-289568147.png)

2.2.4 OP

2.2.4.1 常見OP

哪些是OP?

型別 例項
標量運算 add, sub, mul, div, exp, log, greater, less, equal
向量運算 concat, slice, splot, constant, rank, shape, shuffle
矩陣運算 matmul, matrixinverse, matrixdateminant
帶狀態的運算 Variable, assgin, assginadd
神經網路元件 softmax, sigmoid, relu,convolution,max_pool
儲存, 恢復 Save, Restroe
佇列及同步運算 Enqueue, Dequeue, MutexAcquire, MutexRelease
控制流 Merge, Switch, Enter, Leave, NextIteration

一個操作物件(Operation)是TensorFlow圖中的一個節點, 可以接收0個或者多個輸入Tensor, 並且可以輸出0個或者多個Tensor,Operation物件是透過op建構函式(如tf.matmul())建立的。

例如: c = tf.matmul(a, b) 建立了一個Operation物件,型別為 MatMul型別, 它將張量a, b作為輸入,c作為輸出,,並且輸出資料,列印的時候也是列印的資料。其中tf.matmul()是函式,在執行matmul函式的過程中會透過MatMul類建立一個與之對應的物件

  
  
# 實現一個加法運算
  
  
con_a = tf.constant(3.0)
con_b = tf.constant(4.0)

sum_c = tf.add(con_a, con_b)

print("列印con_a:\n", con_a)
print("列印con_b:\n", con_b)
print("列印sum_c:\n", sum_c)

列印語句會生成:

列印con_a:
 Tensor("Const:0", shape=(), dtype=float32)
列印con_b:
 Tensor("Const_1:0", shape=(), dtype=float32)
列印sum_c:
 Tensor("Add:0", shape=(), dtype=float32)

注意,列印出來的是張量值,可以理解成OP當中包含了這個值。並且每一個OP指令都對應一個唯一的名稱,如上面的Const:0,這個在TensorBoard上面也可以顯示

請注意,tf.Tensor 物件以輸出該張量的 tf.Operation 明確命名。張量名稱的形式為 "<OP_NAME>:",其中:

  • "<OP_NAME>" 是生成該張量的指令的名稱
  • "" 是一個整數,它表示該張量在指令的輸出中的索引

2.2.4.2 指令名稱

tf.Graph物件為其包含的 tf.Operation物件定義的一個名稱空間。TensorFlow 會自動為圖中的每個指令選擇一個唯一名稱,使用者也可以指定描述性名稱,使程式閱讀起來更輕鬆。我們可以以以下方式改寫指令名稱

  • 每個建立新的 tf.Operation 或返回新的 tf.Tensor 的 API 函式可以接受可選的 name 引數。

例如,tf.constant(42.0, name="answer") 建立了一個名為 "answer" 的新 tf.Operation 並返回一個名為 "answer:0" 的 tf.Tensor。如果預設圖已包含名為 "answer" 的指令,則 TensorFlow 會在名稱上附加 "1"、"2" 等字元,以便讓名稱具有唯一性。

  • 當修改好之後,我們在Tensorboard顯示的名字也會被修改
a = tf.constant(3.0, name="a")
b = tf.constant(4.0, name="b" )

OP名字修改

2.3 會話

學習目標

  • 目標

    • 應用sess.run或者eval執行圖程式並獲取張量值
    • 應用feed_dict機制實現執行時填充資料
    • 應用placeholder實現建立佔位符
  • 應用

  • 內容預覽

    • 2.3.1 會話

      • 1 init(target='', graph=None, config=None)
      • 2 會話的run()
      • 3 feed操作

2.3.1 會話

一個執行TensorFlow operation的類。會話包含以下兩種開啟方式

  • tf.Session:用於完整的程式當中
  • tf.InteractiveSession:用於互動式上下文中的TensorFlow ,例如shell

1 TensorFlow 使用 tf.Session 類來表示客戶端程式(通常為 Python 程式,但也提供了使用其他語言的類似介面)與 C++ 執行時之間的連線

2 tf.Session 物件使用分散式 TensorFlow 執行時提供對本地計算機中的裝置和遠端裝置的訪問許可權。

2.3.1.1 init(target='', graph=None, config=None)

會話可能擁有的資源,如 tf.Variable,tf.QueueBase和tf.ReaderBase。當這些資源不再需要時,釋放這些資源非常重要。因此,需要呼叫tf.Session.close會話中的方法,或將會話用作上下文管理器。以下兩個例子作用是一樣的:

def session_demo():
    """
    會話演示
    :return:
    """

    a_t = tf.constant(10)
    b_t = tf.constant(20)
    # 不提倡直接運用這種符號運算子進行計算
    # 更常用tensorflow提供的函式進行計算
    # c_t = a_t + b_t
    c_t = tf.add(a_t, b_t)
    print("tensorflow實現加法運算:\n", c_t)

    # 開啟會話
    # 傳統的會話定義
    # sess = tf.Session()
    # sum_t = sess.run(c_t)
    # print("sum_t:\n", sum_t)
    # sess.close()

    # 開啟會話
    with tf.Session() as sess:
        # sum_t = sess.run(c_t)
        # 想同時執行多個tensor
        print(sess.run([a_t, b_t, c_t]))
        # 方便獲取張量值的方法
        # print("在sess當中的sum_t:\n", c_t.eval())
        # 會話的圖屬性
        print("會話的圖屬性:\n", sess.graph)

    return None
  • target:如果將此引數留空(預設設定),會話將僅使用本地計算機中的裝置。可以指定 grpc:// 網址,以便指定 TensorFlow 伺服器的地址,這使得會話可以訪問該伺服器控制的計算機上的所有裝置。
  • graph:預設情況下,新的 tf.Session 將繫結到當前的預設圖。
  • config:此引數允許您指定一個 tf.ConfigProto 以便控制會話的行為。例如,ConfigProto協議用於列印裝置使用資訊
  
  
# 執行會話並列印裝置資訊
  
  
sess = tf.Session(config=tf.ConfigProto(allow_soft_placement=True,
                                        log_device_placement=True))

會話可以分配不同的資源在不同的裝置上執行。

/job:worker/replica:0/task:0/device:CPU:0

device_type:型別裝置(例如CPU,GPU,TPU)

2.3.1.2 會話的run()

  • run(fetches,feed_dict=None, options=None, run_metadata=None)
    • 透過使用sess.run()來執行operation

    • fetches:單一的operation,或者列表、元組(其它不屬於tensorflow的型別不行)

    • feed_dict:引數允許呼叫者覆蓋圖中張量的值,執行時賦值

      • 與tf.placeholder搭配使用,則會檢查值的形狀是否與佔位符相容。

使用tf.operation.eval()也可執行operation,但需要在會話中執行

  
  
# 建立圖
  
  
a = tf.constant(5.0)
b = tf.constant(6.0)
c = a * b

  
  
# 建立會話
  
  
sess = tf.Session()

  
  
# 計算C的值
  
  
print(sess.run(c))
print(c.eval(session=sess))

2.3.1.3 feed操作

  • placeholder提供佔位符,run時候透過feed_dict指定引數
def session_run_demo():
    """
    會話的run方法
    :return:
    """
    # 定義佔位符
    a = tf.placeholder(tf.float32)
    b = tf.placeholder(tf.float32)
    sum_ab = tf.add(a, b)
    print("sum_ab:\n", sum_ab)
    # 開啟會話
    with tf.Session() as sess:
        print("佔位符的結果:\n", sess.run(sum_ab, feed_dict={a: 3.0, b: 4.0}))
    return None

請注意執行時候報的錯誤error:

RuntimeError:如果這Session是無效狀態(例如已關閉)。
TypeError:如果fetches或者feed_dict鍵的型別不合適。
ValueError:如果fetches或feed_dict鍵無效或引用 Tensor不存在的鍵。

未完待續, 同學們請等待下一期

全套筆記資料程式碼移步: 前往gitee倉庫檢視

感興趣的小夥伴可以自取哦,歡迎大家點贊轉發~

相關文章