版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
第2章TesnorFlow2.X基礎(chǔ)計算機(jī)視覺開發(fā)01數(shù)據(jù)類型變量創(chuàng)建張量目錄CONTENTS索引和切片0203040607050809維度變換張量數(shù)學(xué)運(yùn)算自動求導(dǎo)機(jī)制TensorBoard可視化組件tf.keras數(shù)據(jù)集數(shù)據(jù)類型01第2章TesnorFlow2.X基礎(chǔ)2.1.1數(shù)值類型
數(shù)值類型的張量是TensorFlow的主要數(shù)據(jù)載體,在TensorFlow中,為了表達(dá)方便,一般把標(biāo)量、向量、矩陣等數(shù)據(jù)統(tǒng)稱為張量,當(dāng)需要判斷它們的具體類型時,可根據(jù)張量的維度數(shù)或形狀來判斷。在TensorFlow中每個張量都是一個對象,包含很多重要的屬性,常見的有維度(dimension)和形狀(shape)屬性。根據(jù)張量的維度數(shù)來劃分,數(shù)據(jù)可細(xì)分為:01020304標(biāo)量向量矩陣普通張量2.1.1數(shù)值類型
標(biāo)量(Scalar):單個的實(shí)數(shù),如0,1,3.14,等,維度(Dimension)數(shù)為0,形狀(shape)為[]。val=3.14#python語言方式創(chuàng)建標(biāo)量val_tf=tf.constant(3.14)#TF方式創(chuàng)建標(biāo)量#輸出各標(biāo)量的類型type(val),type(val_tf),tf.is_tensor(val_tf)(float,tensorflow.python.framework.ops.EagerTensor,True)val_tf.shape,val_tf.numpy()(TensorShape([]),3.14)2.1.1數(shù)值類型
向量(Vector):??個實(shí)數(shù)的有序集合,通過中括號包裹,它的維度數(shù)(dimension)為1,形狀(shape)為[n],其中n為向量中數(shù)據(jù)個數(shù)。如[3.14],維度數(shù)為1,形狀shape為[1]。向量[1,2,3,4,5]的維度數(shù)為1,形狀shape為[5]。x=tf.constant([1,2,3,4,5])#輸出張量x的相關(guān)信息x<tf.Tensor:shape=(5,),dtype=int32,numpy=array([1,2,3,4,5])>x.shapeTensorShape([5])2.1.1數(shù)值類型
矩陣(Matrix):??行??列實(shí)數(shù)的有序集合,它的維度(dimension)數(shù)為2,形狀(shape)為[??,??]。如[[1,2,3],[4,5,6]],也可以寫成:它的維度數(shù)為2,形狀(shape)為[2,3]。#創(chuàng)建2行2列的矩陣a=tf.constant([[1,2],[3,4]])a,a.shape(<tf.Tensor:shape=(2,2),dtype=int32,numpy=array([[1,2],[3,4]])>,TensorShape([2,2]))2.1.1數(shù)值類型
普通張量(Tensor):維度數(shù)大于2的普通張量,一般簡稱為張量。張量的每個維度也稱作軸(Axis)。一般維度代表了具體的物理含義。譬如shape為[16,28,3]的張量共有3維,如果表示圖片數(shù)據(jù)的話,每個維度/軸代表的含義分別是圖片高度、圖片寬度、圖片通道數(shù),其中16代表了高,28代表了寬,3代表了RGB共3個通道。#創(chuàng)建3維張量tf.constant([[[1,2],[3,4]],[[5,6],[7,8]]])<tf.Tensor:shape=(2,2,2),dtype=int32,numpy=array([[[1,2],[3,4]],[[5,6],[7,8]]])>2.1.2字符串類型
TensorFlow還支持字符串(String)類型的數(shù)據(jù),例如在表示圖片數(shù)據(jù)時,可以先記錄圖片的路徑字符串,再通過預(yù)處理函數(shù)根據(jù)路徑讀取圖片張量。
雖然Python已經(jīng)有了字符串類型,TensorFlow還是加入了字符串類型,其中一個重要的作用是可以使它成為TensorFlow的內(nèi)置類型直接加入到模型的輸入中,這對自然語言處理領(lǐng)域是很有用的。TensorFlow中的字符串功能由模塊strings提供。
UTF-8(8位元,UniversalCharacterSet/UnicodeTransformationFormat)是針對Unicode的一種可變長度字符編碼。它可以用來表示Unicode標(biāo)準(zhǔn)中的任何字符,而且其編碼中的第一個字節(jié)仍與ASCII相容,使得原來處理ASCII字符的軟件無須或只進(jìn)行少部分修改后,便可繼續(xù)使用。因此,它逐漸成為電子郵件、網(wǎng)頁及其他存儲或傳送文字的應(yīng)用中,優(yōu)先采用的編碼。2.1.2字符串類型
通過傳入字符串對象即可創(chuàng)建字符串類型的張量。#創(chuàng)建英文字符串t=tf.constant("Hello,AI")print(t)print(tf.strings.length(t))print(tf.strings.length(t,unit="UTF8_CHAR"))#將字符串t的編碼方式從unicode轉(zhuǎn)換為"UTF8print(tf.strings.unicode_decode(t,"UTF8"))tf.Tensor(b'Hello,AI',shape=(),dtype=string)tf.Tensor(9,shape=(),dtype=int32)tf.Tensor(9,shape=(),dtype=int32)tf.Tensor([7210110810811144326573],shape=(9,),dtype=int32)2.1.2字符串類型
字符串中的字符編碼可以轉(zhuǎn)換,但中英文的字符數(shù)被相同對待。#stringarrayt=tf.constant(["cafe","coffee","咖啡"])print(tf.strings.length(t,"UTF8_CHAR"))r=tf.strings.unicode_decode(t,"UTF8")print(t)print(r)tf.Tensor([462],shape=(3,),dtype=int32)tf.Tensor([b'cafe'b'coffee'b'\xe5\x92\x96\xe5\x95\xa1'],shape=(3,),dtype=string)<tf.RaggedTensor[[99,97,102,101],[99,111,102,102,101,101],[21654,21857]]>2.1.2字符串類型
通過傳入字符串對象即可創(chuàng)建字符串類型的張量。#
創(chuàng)建中文字符串wordes_ch
=
tf.constant(u'歡迎閱讀《計算機(jī)視覺開發(fā)》')
wordes_ch,wordes_ch.numpy().decode()(<tf.Tensor:shape=(),dtype=string,numpy=b'\xe6\xac\xa2\xe8\xbf\x8e\xe9\x98\x85\xe8\xaf\xbb\xe3\x80\x8a\xe8\xae\xa1\xe7\xae\x97\xe6\x9c\xba\xe8\xa7\x86\xe8\xa7\x89\xe5\xbc\x80\xe5\x8f\x91\xe3\x80\x8b'>,'歡迎閱讀《計算機(jī)視覺開發(fā)》')由此可見,對包含中文的字符串張量,直接輸出numpy()將得到內(nèi)容的數(shù)字編碼,對它調(diào)用解碼函數(shù)decode,就會得到原本的字符串內(nèi)容。2.1.2字符串類型
在tf.strings模塊中,提供了常見的字符串類型的工具函數(shù),如小寫化lower()、拼接join()、長度length()、切分split()等。#小寫化字符串words_en=tf.constant('Hello,AI')tf.strings.lower(words_en)<tf.Tensor:shape=(),dtype=string,numpy=b'hello,ai'>#分割字符串成數(shù)組tf.strings.split(words_en)<tf.Tensor:shape=(2,),dtype=string,numpy=array([b'Hello,',b'AI'],dtype=object)>2.1.3布爾類型
為了方便表達(dá)比較運(yùn)算操作的結(jié)果,TensorFlow還支持布爾類型(Boolean,簡稱bool)的張量。布爾類型的張量只需要傳入Python語言的布爾類型數(shù)據(jù),轉(zhuǎn)換成TensorFlow內(nèi)部布爾型即可。#創(chuàng)建布爾類型標(biāo)量tf.constant(True)<tf.Tensor:shape=(),dtype=bool,numpy=True>2.1.3布爾類型
創(chuàng)建其它維度的布爾型張量,方法和創(chuàng)建其他數(shù)據(jù)類型的張量相同,例如:#創(chuàng)建布爾類型向量a=tf.constant([True,False])<tf.Tensor:id=10,shape=(2,),dtype=bool,numpy=array([True,False])>2.1.3布爾類型
需要注意的是,TensorFlow的布爾類型和Python語言的布爾類型并不等價,不能通用,例如:#tensorflow的布爾張量不是python的布爾型值tf.constant(True)isTrueFalse2.1.3布爾類型
雖然TensorFlow的布爾類型和Python語言的布爾類型并不等價,但它們可以進(jìn)行比較運(yùn)算,結(jié)果是布爾型tensorflow張量:#tensorflow的布爾張量可以和python的布爾型值進(jìn)行比較運(yùn)算tf.constant(True)==True<tf.Tensor:shape=(),dtype=bool,numpy=True>2.1.4數(shù)值精度
對于數(shù)值類型的張量,可以保存為不同字節(jié)長度的精度,如浮點(diǎn)數(shù)3.14既可以保存為16位(Bit)長度,也可以保存為32位甚至64位的精度。位越長,精度越高,同時占用的內(nèi)存空間也就越大。常用的精度類型有16、32、64、tf.float16、tf.float32、tf.float64等,其中tf.float64即為tf.double。#創(chuàng)建指定精度的張量tf.constant(123456789,dtype=32)<tf.Tensor:shape=(),dtype=int32,numpy=123456789>2.1.4數(shù)值精度
當(dāng)保存精度過低時,可能會發(fā)生數(shù)據(jù)溢出,得到錯誤結(jié)果,例如:tf.constant(123456789,dtype=16)<tf.Tensor:shape=(),dtype=int16,numpy=-13035>可以看到,由于保存精度過低,數(shù)據(jù)123456789發(fā)生了溢出,得到了錯誤結(jié)果-13035。2.1.4數(shù)值精度
對于浮點(diǎn)數(shù),高精度的張量可以表示更精準(zhǔn)的數(shù)據(jù),例如采用tf.float32精度保存π時,實(shí)際保存的數(shù)據(jù)為3.1415927。importnumpyasnp#從numpy中導(dǎo)入pi常量np.pi#保存為32位浮點(diǎn)數(shù)tf.constant(np.pi,dtype=tf.float32)<tf.Tensor:shape=(),dtype=float32,numpy=3.1415927>#采用tf.float64精度保存π,則能獲得更高的精度tf.constant(np.pi,dtype=tf.float64)<tf.Tensor:shape=(),dtype=float64,numpy=3.141592653589793>2.1.4數(shù)值精度
通過訪問張量的dtype成員屬性可以判斷張量的保存精度。a=tf.constant(np.pi,dtype=tf.float16)#讀取原有張量的數(shù)值精度a.dtypetf.float162.1.5類型轉(zhuǎn)換
系統(tǒng)的每個模塊使用的數(shù)據(jù)類型、數(shù)值精度可能各不相同,對于不符合要求的張量類型及精度,需要通過tf.cast()函數(shù)進(jìn)行轉(zhuǎn)換,例如:#創(chuàng)建tf.float16低精度張量a=tf.constant(np.pi,dtype=tf.float16)#轉(zhuǎn)換為高精度張量tf.cast(a,tf.double)<tf.Tensor:shape=(),dtype=float64,numpy=3.140625>2.1.5類型轉(zhuǎn)換
進(jìn)行類型轉(zhuǎn)換時,需要保證轉(zhuǎn)換操作的合法性,譬如將高精度的張量轉(zhuǎn)換為低精度的張量時,可能發(fā)生數(shù)據(jù)溢出隱患,例如:a=tf.constant(123456789,dtype=32)#轉(zhuǎn)換為低精度整型tf.cast(a,16)<tf.Tensor:shape=(),dtype=int16,numpy=-13035>可以看到,由于保存精度過低,發(fā)生了數(shù)據(jù)溢出,得到了錯誤結(jié)果-13035。2.1.5類型轉(zhuǎn)換
布爾類型與整型之間相互轉(zhuǎn)換也是合法的,是比較常見的操作,例如:a=tf.constant([False,True,False])#布爾類型轉(zhuǎn)整型tf.cast(a,32)<tf.Tensor:shape=(3,),dtype=int32,numpy=array([0,1,0])>2.1.5類型轉(zhuǎn)換
數(shù)值與布爾型相互轉(zhuǎn)換時,一般默認(rèn)0表示False,1表示True,在TensorFlow中,將非0數(shù)字都視為True。a=tf.constant([-10,0,3,0])#整型轉(zhuǎn)布爾類型tf.cast(a,tf.bool)<tf.Tensor:shape=(4,),dtype=bool,numpy=array([True,False,True,False])>
變量對象02第2章TesnorFlow2.X基礎(chǔ)2.2變量對象(待優(yōu)化張量)
通過tf.constant創(chuàng)建的張量對象里除了張量數(shù)據(jù)外不保存其他額外信息,而張量在各種人工智能算法的訓(xùn)練程序中,需要頻繁地計算梯度,為了區(qū)分需要計算梯度信息的張量與不需要計算梯度信息的張量,TensorFlow增加了一種專門的數(shù)據(jù)類型來支持梯度信息的記錄:變量對象(tf.Variable),也稱待優(yōu)化張量。
對于模型中需要被訓(xùn)練的參數(shù)一般設(shè)置為tf.Variable類型,這些參數(shù)會在反向傳播中記錄自己的梯度信息,并且它們可以用.assign(),.assign_add(),.assign_sub()等方法重新賦值。2.2變量對象(待優(yōu)化張量)
通過tf.Variable()函數(shù)可以將普通張量轉(zhuǎn)換為待優(yōu)化張量,例如:#
創(chuàng)建
tf.constant類型
張量con
=
tf.constant([0,
1,
2])
#
轉(zhuǎn)換為
Variable
類型val
=
tf.Variable(con)
#
Variable
類型張量的屬性,
val.trainable
,val('Variable:0',True,<tf.Variable'Variable:0'shape=(3,)dtype=int32,numpy=array([0,1,2])>)2.2變量對象(待優(yōu)化張量)
張量的name和trainable屬性是Variable特有的屬性,name屬性用于內(nèi)部維護(hù),一般不需要用戶關(guān)注。trainable屬性指定當(dāng)前張量是否需要被優(yōu)化,創(chuàng)建Variable對象時默認(rèn)為True,可以設(shè)置trainable=False來設(shè)置張量不需要優(yōu)化。
#設(shè)置變量對象的trainable屬性val=tf.Variable(con,trainable=False)print(val,val.trainable)<tf.Variable'Variable:0'shape=(3,)dtype=int32,numpy=array([0,1,2])>FalseTensorflow中定義的時,可以通過trainable屬性控制這個變量是否可以被優(yōu)化器更新。但是在以后的使用中,trainable屬性是只讀的,我們無法動態(tài)更改這個只讀屬性。2.2變量對象(待優(yōu)化張量)
除了通過轉(zhuǎn)換普通張量的方式創(chuàng)建Variable,也可以直接創(chuàng)建它,例如:#直接創(chuàng)建Variable張量tf.Variable([[1,2,3],[4,5,6]])<tf.Variable'Variable:0'shape=(2,3)dtype=int32,numpy=array([[1,2,3],[4,5,6]])>
創(chuàng)建張量03第2章TesnorFlow2.X基礎(chǔ)2.3.1
從數(shù)組、列表對象創(chuàng)建張量
在TensorFlow中,可以通過多種方式創(chuàng)建張量,如從Python列表對象創(chuàng)建,從Numpy數(shù)組創(chuàng)建,或者創(chuàng)建采樣自某種已知分布的張量等。
NumpyArray數(shù)組和PythonList列表是Python程序中間非常重要的數(shù)據(jù)載體容器,很多數(shù)據(jù)都是通過Python語言將數(shù)據(jù)加載至Array或者List容器,再轉(zhuǎn)換到Tensor類型,通過TensorFlow運(yùn)算處理后導(dǎo)出到Array或者List容器,方便其他模塊調(diào)用。2.3.1
從數(shù)組、列表對象創(chuàng)建張量
我們也可以通過numpy的數(shù)組對象來創(chuàng)建張量:例如:#從數(shù)組中創(chuàng)建張量tf.convert_to_tensor(np.array([[1,2],[3,4]]))<tf.Tensor:shape=(2,2),dtype=int32,numpy=array([[1,2],[3,4]])>2.3.1
從數(shù)組、列表對象創(chuàng)建張量
需要注意的是,Numpy浮點(diǎn)數(shù)數(shù)組默認(rèn)使用64位精度保存數(shù)據(jù),轉(zhuǎn)換到Tensor類型時精度為tf.float64,可以在需要的時候?qū)⑵滢D(zhuǎn)換為tf.float32類型,或者在創(chuàng)建時指定精度。tf.convert_to_tensor(np.array([[1.1,2.2],[3.3,4.4]]))<tf.Tensor:shape=(2,2),dtype=float64,numpy=array([[1.1,2.2],[3.3,4.4]])>tf.convert_to_tensor(np.array([[1.1,2.2],[3.3,4.4]]),dtype=tf.float32)<tf.Tensor:shape=(2,2),dtype=float32,numpy=array([[1.1,2.2],[3.3,4.4]],dtype=float32)>2.3.2
創(chuàng)建全0或全1張量
將張量創(chuàng)建為全0或者全1數(shù)據(jù)是非常常見的張量初始化形式。tf.zeros()創(chuàng)建全零張量,tf.ones()創(chuàng)建全1張量,它們的參數(shù)都是張量的形狀(shape)。#創(chuàng)建全0,全1的向量tf.zeros([3]),tf.ones([4])(<tf.Tensor:shape=(3,),dtype=float32,numpy=array([0.,0.,0.],dtype=float32)>,<tf.Tensor:shape=(4,),dtype=float32,numpy=array([1.,1.,1.,1.],dtype=float32)>)2.3.2
創(chuàng)建全0或全1張量
創(chuàng)建shape為[2,3]的全0、全1矩陣:#創(chuàng)建全0、全1矩陣,指定shape為2行3列tf.zeros([2,3]),tf.ones([2,3])(<tf.Tensor:shape=(2,3),dtype=float32,numpy=array([[0.,0.,0.],[0.,0.,0.]],dtype=float32)>,<tf.Tensor:shape=(2,3),dtype=float32,numpy=array([[1.,1.,1.],[1.,1.,1.]],dtype=float32)>)2.3.2
創(chuàng)建全0或全1張量
tf.zeros_like和tf.ones_like用來新建與某個張量形狀(shape)一致且數(shù)值全為0或1的張量,例如,創(chuàng)建一個與val形狀相同,但是全為1的新張量:#創(chuàng)建一個矩陣張量val=tf.zeros([2,3])#創(chuàng)建一個與val形狀相同,但是全為1的新矩陣張量tf.ones_like(val)<tf.Tensor:shape=(2,3),dtype=float32,numpy=array([[1.,1.,1.],[1.,1.,1.]],dtype=float32)>2.3.2
創(chuàng)建全0或全1張量
創(chuàng)建一個與val形狀相同,但是全為0的新張量:#創(chuàng)建一個矩陣張量val=tf.ones([2,3])#創(chuàng)建一個與val形狀相同,但是全為0的新矩陣張量tf.zeros_like(val)<tf.Tensor:shape=(2,3),dtype=float32,numpy=array([[0.,0.,0.],[0.,0.,0.]],dtype=float32)>2.3.3創(chuàng)建已知分布的隨機(jī)值張量
正態(tài)分布(NormalDistribution,也稱GaussianDistribution)和均勻分布(UniformDistribution)是最常見的隨機(jī)分布之一,在人工神經(jīng)網(wǎng)絡(luò)的算法中經(jīng)常需要創(chuàng)建這兩種分布的隨機(jī)值張量。通過tf.random.normal(shape,mean=0.0,stddev=1.0)可以創(chuàng)建形狀為shape,均值為mean,標(biāo)準(zhǔn)差為stddev的正態(tài)分布隨機(jī)值張量。通過tf.random.uniform(shape,minval=0,maxval=None,dtype=tf.float32)可以創(chuàng)建采樣自[minval,maxval)區(qū)間的均勻分布的隨機(jī)值張量。通過tf.range(limit,delta=1)函數(shù)創(chuàng)建連續(xù)的序列張量。2.3.3創(chuàng)建已知分布的張量
創(chuàng)建形狀為[2,3],均值為默認(rèn)值0,標(biāo)準(zhǔn)差為默認(rèn)值1的正態(tài)分布隨機(jī)值張量:#創(chuàng)建標(biāo)準(zhǔn)正態(tài)分布的張量tf.random.normal([2,3])<tf.Tensor:shape=(2,3),dtype=float32,numpy=array([[0.3751436,-0.2862245,0.06686653],[0.0467275,0.48540983,0.90134674]],dtype=float32)>2.3.3創(chuàng)建已知分布的張量
創(chuàng)建采樣自區(qū)間[0,1),shape為[2,3]的隨機(jī)值張量:#創(chuàng)建采樣自[0,1)均勻分布的矩陣tf.random.uniform([2,3])<tf.Tensor:shape=(2,3),dtype=float32,numpy=array([[0.27674258,0.46022487,0.95487845],[0.19414663,0.43507028,0.6008235]],dtype=float32)>2.3.3創(chuàng)建已知分布的張量
在代碼中進(jìn)行循環(huán)計算時,經(jīng)常需要創(chuàng)建一段連續(xù)的整型序列,我們可以通過tf.range()函數(shù)來實(shí)現(xiàn)它。tf.range(limit,delta=1)可以創(chuàng)建在[0,limit)之間,步長為delta的整型序列,序列不包含limit本身。
例如,創(chuàng)建0~10,步長為2的整型序列:#創(chuàng)建0~10,步長為2的整形序列tf.range(10,delta=2)<tf.Tensor:shape=(5,),dtype=int32,numpy=array([0,2,4,6,8])>索引與切片04第2章TesnorFlow2.X基礎(chǔ)2.4.1索引
通過索引與切片操作可以提取張量的部分?jǐn)?shù)據(jù),它們的使用頻率非常高。
TensorFlow支持基本的[i][j]?標(biāo)準(zhǔn)索引方式,也支持通過逗號分隔索引號的索引方式,例如我們創(chuàng)建一個shape為(4,32,32,3)的張量表示4張32×32大小的彩色圖片(為了方便演示,使用隨機(jī)分布模擬產(chǎn)生),實(shí)現(xiàn)如下:#創(chuàng)建4維張量x=tf.random.uniform([4,32,32,3],minval=0,maxval=256,dtype=32)x.shapeTensorShape([4,32,32,3])2.4.1索引
我們可以使用索引方式讀取圖片的部分?jǐn)?shù)據(jù)。
取第1張圖片的數(shù)據(jù):#取第1張圖片的數(shù)據(jù)x[0]<tf.Tensor:shape=(32,32,3),dtype=float32,numpy=array([[[-1.2999741,-0.08147629,1.2331405],[-0.46759546,0.872048,0.9821139],[-0.50117636,-0.53197354,-0.8914879],...,[1.0370245,-0.97947764,0.8455341],[0.72594947,-0.6259352,-0.12225632],[0.09181922,0.3200802,-1.1037049]]],dtype=float32)>2.4.1索引
取第1張圖片的第2行:#取第1張圖片的第2行x[0][1]<tf.Tensor:shape=(32,3),dtype=float32,numpy=array([[-0.02236159,0.2303121,-0.16067502],[0.2799066,-0.06766614,-1.0063653],…[0.14589657,-0.83992064,0.2661913],[-0.36365488,0.4383212,0.51949],[0.7012511,-0.24197082,-0.1288976]],dtype=float32)>2.4.1索引
取第1張圖片的第2行,第3列的數(shù)據(jù):#取第1張圖片,第2行,第3列的數(shù)據(jù)x[0][1][2]<tf.Tensor:shape=(3,),dtype=float32,numpy=array([0.44945362,-0.21581197,1.1323806],dtype=float32)>#取第3張圖片,第2行,第1列的像素,B通道(第2個通道)顏色強(qiáng)度值x[2][1][0][1]<tf.Tensor:shape=(),dtype=float32,numpy=0.9684435>
取第3張圖片的第2行,第1列的像素,B通道(第2個通道)顏色強(qiáng)度值:2.4.2切片
切片就是按一定的方式提取數(shù)據(jù)集中的一部分?jǐn)?shù)據(jù),其基本語法為:[start:end:step],其中start為開始讀取位置的索引,end為結(jié)束讀取位置的索引(不包含end位),step為采樣步長。2.4.2切片
以shape為[4,32,32,3]的圖片張量為例,我們可以通過切片獲得不同位置的數(shù)據(jù)。例如讀取第2,3張圖片:#讀取第2,3張圖片x[1:3]<tf.Tensor:shape=(2,32,32,3),dtype=float32,numpy=array([[[[0.8699068,0.4639625,0.8125596],[-0.7148029,0.28057125,-1.7965403],[-0.63620824,-0.33896002,-0.7434767],...,[-1.8229674,2.7207685,-0.40766257],[0.5166683,-0.14965399,-0.04573024],[-1.6019406,-0.11176273,0.30408612]]]],dtype=float32)>2.4.2切片
start:end:step切片方式有很多簡寫方式,其中start、end、step這3個參數(shù)可以根據(jù)需要選擇性地省略,全部省略時即為::,表示從最開始讀取到最末尾,步長為1,即不跳過任何元素。如x[0,::]表示讀取第1張圖片的所有行,其中::表示在行維度上讀取所有行,它等價于x[0]的寫法:#讀取第一張圖片x[0,::]<tf.Tensor:shape=(32,32,3),dtype=float32,numpy=array([[[-1.2999741,-0.08147629,1.2331405],[-0.46759546,0.872048,0.9821139],[-0.50117636,-0.53197354,-0.8914879],...,[1.0370245,-0.97947764,0.8455341],[0.72594947,-0.6259352,-0.12225632],[0.09181922,0.3200802,-1.1037049]]],dtype=float32)>2.4.2切片[start:end:step]中步長step取負(fù)數(shù)的話,表示逆向讀取數(shù)值。#考慮一個0~9的簡單序列向量,逆序取到第1號元素,不包含第1號#創(chuàng)建0~9向量x=tf.range(9)#從8取到0,逆序,不包含0x[8:0:-1]<tf.Tensor:shape=(8,),dtype=int32,numpy=array([8,7,6,5,4,3,2,1])>#逆序選取全部元素x[::-1]<tf.Tensor:shape=(9,),dtype=int32,numpy=array([8,7,6,5,4,3,2,1,0])>2.4.2切片
[start:end:step]切片的簡寫方式,其中從第一個元素讀取時start可以省略,即start=0時可以省略,讀取到最后一個元素時end可以省略,步長為1時step可以省略。切片方式意義start:end:step從start開始讀取到end(不包含end),步長為stepstart:end從start開始讀取到end(不包含end),步長為1start:從start開始讀取完后續(xù)所有元素,步長為1start::step從start開始讀取完后續(xù)所有元素,步長為step:end:step從0開始讀取到end(不包含end),步長為step:end從0開始讀取到end(不包含end),步長為1::step步長為step采樣::或:讀取所有元素維度變換05第2章TesnorFlow2.X基礎(chǔ)2.5.1改變視圖
在神經(jīng)網(wǎng)絡(luò)運(yùn)算過程中,維度變換是常見的張量操作,通過維度變換可以將數(shù)據(jù)任意地切換形式,滿足不同場合的運(yùn)算需求。常見的維度變換用于增刪維度和改變視圖兩種情況下。張量在內(nèi)存上保存為一段連續(xù)的內(nèi)存區(qū)域,對于同樣的存儲,我們可以通過reshape函數(shù)來改變形狀。2.5.1改變視圖
張量的視圖就是我們理解張量的方式,譬如shape為(2,4,4,3)的張量??,我們從邏輯上可以理解為:(??,?*w,??)張量理解為??張圖片,?*w個像素點(diǎn),??個通道(??,?,w*??)張量理解為??張圖片,?行,每行的特征長度為w*??(??,?*w*??)張量理解為??張圖片,每張圖片的特征長度為?*w*??2.5.1改變視圖
視圖變換只需要滿足新視圖的元素總量與原來大小相等即可,即新視圖的元素數(shù)量等于??*?*w*??。下面先創(chuàng)建一個模擬圖像集:#按(b,h,w,c)的形狀生成模擬圖像集D
=
tf.random.normal(shape
=
(4,28,28,3),mean=0.5)D.shapeTensorShape([4,28,28,3])#改變張量形狀,按(b,h*w,c)輸出D1
=
tf.reshape(D,shape=(4,28*28,3))D1.shapeTensorShape([4,784,3])2.5.1改變視圖
當(dāng)將形狀參數(shù)的某一維設(shè)置為-1時,代表由系統(tǒng)根據(jù)總量不變的原則,自動判斷這一維的長度。例如將數(shù)據(jù)集D的形狀改變?yōu)椋?,28*28,-1),則系統(tǒng)根據(jù)總的數(shù)據(jù)量,自動判斷出最后一維(-1指代的這一維度)長度為3。#按(b,h,w,c)的形狀生成模擬圖像集D
=
tf.random.normal(shape
=
(4,28,28,3),mean=0.5)D2=tf.reshape(D,shape=(4,28*28,-1))D2.shapeTensorShape([4,784,3])2.5.2改變維度
增加一個長度為1的維度就是給原有的數(shù)據(jù)添加一個新維度,并且新增維度長度為1,故數(shù)據(jù)總量并沒改變,僅僅是改變了數(shù)據(jù)的理解方式,因此它可以理解為改變視圖的一種特殊方式。通過tf.expand_dims()方法可在指定的axis軸前插入一個新的維度。tf.expand_dims(input,axis,name=None)以shape為(b,c,h,w)的張量為例,不同axis參數(shù)的實(shí)際插入位置:2.5.2改變維度
一張28×28大小的灰度圖片的數(shù)據(jù)保存為shape為(28,28)的張量,在末尾給張量增加一新維度,定義為通道數(shù)維度,此時張量的shape變?yōu)?28,28,1),實(shí)現(xiàn)如下:產(chǎn)生矩陣x=tf.random.uniform([28,28],maxval=10,dtype=32)x<tf.Tensor:shape=(28,28),dtype=int32,numpy=array([[6,8,5,0,5,2,7,8,8,3,0,5,6,8,8,9,1,8,2,1,9,7,7,6,8,7,5,6],…[9,9,0,8,5,2,4,6,9,9,6,5,1,2,2,0,3,5,4,6,3,0,0,4,2,8,7,1]])>2.5.2改變維度
一張28×28大小的灰度圖片的數(shù)據(jù)保存為shape為(28,28)的張量,在末尾給張量增加一新維度,定義為通道數(shù)維度,此時張量的shape變?yōu)?28,28,1),實(shí)現(xiàn)如下:#axis=2表示在最后面插入一個維度x=tf.expand_dims(x,axis=2)x<tf.Tensor:shape=(28,28,1),dtype=int32,numpy=array([[[6],[8],[5],[0],[5],[2],[7…[1]]])>2.5.2改變維度
插入一個新維度后,數(shù)據(jù)的存儲順序并沒有改變,依然按著原先的順序保存,僅僅是在插入一個新的維度后,改變了數(shù)據(jù)的視圖。同樣的方法,可以在最前面插入一個新的維度,并命名為圖片數(shù)量維度,長度為1,此時張量的shape變?yōu)?1,28,28,1):x=tf.expand_dims(x,axis=0)#高維度之前插入新維度x<tf.Tensor:shape=(1,28,28,1),dtype=int32,numpy=array([[[[6],[8],[5],[0],[5],[2],[7],…[1]]]])>2.5.2改變維度
刪除維度是增加維度的逆操作,與增加維度相同,刪除維度只能刪除長度為1的維度??梢酝ㄟ^tf.squeeze()方法來實(shí)現(xiàn)。該操作不會改變張量的存儲順序。對shape為(1,28,28,1)的圖片張量,我們刪除圖片數(shù)量維度(axis=0),實(shí)現(xiàn)如下:x=tf.squeeze(x,axis=0)#刪除圖片數(shù)量維度x<tf.Tensor:shape=(28,28,1),dtype=int32,numpy=array([[[6],[8],[5],[0],[5],[2],[7],…[1]]]])>2.5.2改變維度
此時圖片張量的shape為(28,28,1),繼續(xù)刪除通道數(shù)維度(axis=2),實(shí)現(xiàn)如下:x=tf.squeeze(x,axis=2)#刪除通道數(shù)維度x<tf.Tensor:shape=(28,28),dtype=int32,numpy=array([[6,8,5,0,5,2,7,8,8,3,0,5,6,8,8,9,1,8,2,1,9,7,7,6,8,7,5,6],…[9,9,0,8,5,2,4,6,9,9,6,5,1,2,2,0,3,5,4,6,3,0,0,4,2,8,7,1]])>2.5.2改變維度
改變視圖、增刪維度都不會影響張量的存儲。交換維度(Transpose)在改變張量存儲順序的同時也改變了張量的視圖。交換維度在圖像處理中是非常常見的操作。譬如,在TensorFlow中,圖片張量的默認(rèn)存儲格式是通道后行格式(??,?,w,??),但是部分圖庫的圖片格式是通道先行格式(??,??,?,w),因此需要完成(??,??,?,w)到(??,?,w,??)維度交換運(yùn)算,此時一般使用tf.transpose()方法來交換維度。x=tf.random.normal([2,32,32,3])y=tf.transpose(x,[0,3,1,2])print(x.shape,y.shape)(2,32,32,3)(2,3,32,32)數(shù)學(xué)運(yùn)算06第2章TesnorFlow2.X基礎(chǔ)2.6.1四則常規(guī)運(yùn)算
加、減、乘、除是最基本的數(shù)學(xué)運(yùn)算,分別通過tf.add,tf.subtract,tf.multiply,tf.divide函數(shù)實(shí)現(xiàn),TensorFlow已經(jīng)重載了+、?、?、/運(yùn)算符,一般推薦直接使用運(yùn)算符來完成加、減、乘、除運(yùn)算。
整除和余除也是常見的運(yùn)算之一,分別通過//和%運(yùn)算符實(shí)現(xiàn)。2.6.1四則常規(guī)運(yùn)算
使用運(yùn)算符來完成加、減、乘、除等四則運(yùn)算:#定義兩個float64類型張量a,b進(jìn)行四則運(yùn)算a=tf.constant(-4.5,dtype=tf.float64)b=tf.constant(3,dtype=tf.float64)print('a+b=',a+b,'\na*b=',a*b)a+b=tf.Tensor(-1.5,shape=(),dtype=float64)a*b=tf.Tensor(-13.5,shape=(),dtype=float64)2.6.1四則常規(guī)運(yùn)算
張量與常數(shù)的四則運(yùn)算:tf.range(5)+3<tf.Tensor:shape=(5,),dtype=int32,numpy=array([3,4,5,6,7])>tf.range(5)*3<tf.Tensor:shape=(5,),dtype=int32,numpy=array([0,3,6,9,12])>2.6.1四則常規(guī)運(yùn)算
張量與列表的四則運(yùn)算:tf.constant([1,4,5])+[3,5,6]<tf.Tensor:shape=(3,),dtype=int32,numpy=array([4,9,11])>a=tf.range(5)b=tf.constant(2)#整除運(yùn)算a//b<tf.Tensor:shape=(5,),dtype=int32,numpy=array([0,0,1,1,2])>
張量的整除運(yùn)算:2.6.2指數(shù)和對數(shù)運(yùn)算
通過函數(shù)tf.pow(x,a)可以方便地實(shí)現(xiàn)的乘方運(yùn)算,也可以通過運(yùn)算符**實(shí)現(xiàn)指數(shù)運(yùn)算。x=tf.range(4)#乘方運(yùn)算tf.pow(x,3)<tf.Tensor:shape=(4,),dtype=int32,numpy=array([0,1,8,27])>x=tf.constant([1.,4.,9.])#平方根x**(0.5)<tf.Tensor:shape=(3,),dtype=float32,numpy=array([1.,2.,3.],dtype=float32)>2.6.2指數(shù)和對數(shù)運(yùn)算
特別地,對于自然指數(shù),可以通過tf.exp(x)函數(shù)實(shí)現(xiàn)。#自然指數(shù)運(yùn)算tf.exp(1.)<tf.Tensor:shape=(),dtype=float32,numpy=2.7182817>#自然指數(shù)運(yùn)算,e的平方tf.exp(2.)<tf.Tensor:shape=(),dtype=float32,numpy=7.389056>2.6.2指數(shù)和對數(shù)運(yùn)算
自然對數(shù)可以通過函數(shù)tf.math.log(x)實(shí)現(xiàn)。x=tf.exp(3.)#對數(shù)運(yùn)算tf.math.log(x)<tf.Tensor:shape=(),dtype=float32,numpy=3.0>x=tf.constant([1.,2.])x=10**x#換底公式tf.math.log(x)/tf.math.log(10.)<tf.Tensor:shape=(2,),dtype=float32,numpy=array([1.,2.],dtype=float32)>
以10為底的對數(shù)運(yùn)算,可以通過換底公式來實(shí)現(xiàn)。2.6.3矩陣相乘運(yùn)算
神經(jīng)網(wǎng)絡(luò)中間包含了大量的矩陣相乘運(yùn)算,我們可以通過@運(yùn)算符方便地實(shí)現(xiàn)矩陣相乘,也可以通過tf.matmul(a,b)函數(shù)來實(shí)現(xiàn)。
TensorFlow中的矩陣相乘可以使用批量方式,也就是參與計算的張量??和??的維度數(shù)可以大于2。當(dāng)張量??和??維度數(shù)大于2時,TensorFlow會選擇??和??的最后兩個維度進(jìn)行矩陣相乘,前面所有的維度都視作批量(Batch)維度。2.6.2指數(shù)和對數(shù)運(yùn)算
使用運(yùn)算符‘*’進(jìn)行矩陣操作,實(shí)現(xiàn)的是矩陣點(diǎn)乘。#點(diǎn)乘tf.constant([1,2,3])*tf.constant([2,3,4])<tf.Tensor:shape=(3,),dtype=int32,numpy=array([2,6,12])>2.6.2指數(shù)和對數(shù)運(yùn)算
使用運(yùn)算符‘*’進(jìn)行矩陣操作,實(shí)現(xiàn)的是矩陣點(diǎn)乘。x=tf.constant([1,2,3])x=tf.expand_dims(x,axis=0)y=tf.reshape(tf.constant([2,3,4]),[3,1])x,y(<tf.Tensor:shape=(1,3),dtype=int32,numpy=array([[1,2,3]])>,<tf.Tensor:shape=(3,1),dtype=int32,numpy=array([[2],[3],[4]])>)#矩陣相乘tf.matmul(x,y)<tf.Tensor:shape=(1,1),dtype=int32,numpy=array([[20]])>2.6.2指數(shù)和對數(shù)運(yùn)算
使用運(yùn)算符‘@’進(jìn)行矩陣操作,實(shí)現(xiàn)的是矩陣叉乘。a=tf.reshape(tf.range(72),[2,3,3,4])b=tf.reshape(tf.range(72),[2,3,4,3])#批量形式的矩陣相乘a@bOutputexceedsthesizelimit.Openthefulloutputdatainatexteditor<tf.Tensor:shape=(2,3,3,3),dtype=int32,numpy=array([[[[42,48,54],[114,136,158],[186,224,262]],...[12090,12320,12550]],[[15882,16128,16374],[16914,17176,17438],[17946,18224,18502]]]])>自動求導(dǎo)機(jī)制07第2章TesnorFlow2.X基礎(chǔ)2.7自動求導(dǎo)機(jī)制
在深度學(xué)習(xí)中,我們經(jīng)常需要計算函數(shù)的導(dǎo)數(shù)。TensorFlow提供了強(qiáng)大的自動求導(dǎo)機(jī)制來計算導(dǎo)數(shù)。在即時執(zhí)行模式下,TensorFlow引入了tf.GradientTape()這個“梯度記錄器”來實(shí)現(xiàn)自動求導(dǎo)。定義自變量withtf.GradientTape()astape:
定義運(yùn)算表達(dá)式導(dǎo)數(shù)
=tape.gradient(表達(dá)式值,自變量)
必須要注意的是,參與求導(dǎo)計算的待優(yōu)化張量Variable,必須是浮點(diǎn)數(shù)類型,如果傳入整型,計算過程會報錯。2.7自動求導(dǎo)機(jī)制
x=tf.Variable(3.)#聲明自變量,注意傳入的必須是浮點(diǎn)數(shù)withtf.GradientTape()astape:y=x**2+x+1dy_dx=tape.gradient(y,x)print('y=',y)print('dy_dx=',dy_dx)y=tf.Tensor(13.0,shape=(),dtype=float32)dy_dx=tf.Tensor(7.0,shape=(),dtype=float32)2.7自動求導(dǎo)機(jī)制x=tf.Variable(1.)#聲明自變量,注意傳入的必須是浮點(diǎn)數(shù)y=tf.Variable(2.)#聲明自變量,注意傳入的必須是浮點(diǎn)數(shù)withtf.GradientTape()astape:f=2*x**2+3*y**2+1df_dx,df_dy=tape.gradient(f,[x,y])print('f=',f)print('df_dx=',df_dx)print('df_dy=',df_dy)f=tf.Tensor(15.0,shape=(),dtype=float32)df_dx=tf.Tensor(4.0,shape=(),dtype=float32)df_dy=tf.Tensor(12.0,shape=(),dtype=float32)2.7自動求導(dǎo)機(jī)制x=tf.Variable([1.,2.,3.])#將向量傳入自變量y=tf.Variable([4.,5.,6.])#將向量傳入自變量withtf.GradientTape()astape:f=2*x**2+3*y**2+1df_dx,df_dy=tape.gradient(f,[x,y])print('f=',f)print('df_dx=',df_dx)print('df_dy=',df_dy)f=tf.Tensor([51.83.99999127.],shape=(3,),dtype=float32)df_dx=tf.Tensor([4.8.12.],shape=(3,),dtype=float32)df_dy=tf.Tensor([24.30.36.],shape=(3,),dtype=float32)TensorBoard使用08第2章TesnorFlow2.X基礎(chǔ)2.8.1TensorBoard簡介
TensorBoard是TensorFlow的內(nèi)置原生可視化工具,無需獨(dú)立安裝,在安裝TensorFlow時會自動安裝對應(yīng)版本的TensorBoard,可直接使用。
TensorBoard對訓(xùn)練過程數(shù)據(jù)的展示有曲線圖、直方圖、圖像、模型結(jié)構(gòu)圖和數(shù)據(jù)分布圖等幾種形式,針對不同數(shù)據(jù)使用不同的展示形式。2.8.1TensorBoard簡介(1)Scalars:展示訓(xùn)練過程中的準(zhǔn)確率、損失值、權(quán)重/偏置的變化情況。(2)Images:展示訓(xùn)練過程中記錄的圖像。(3)Audio:展示訓(xùn)練過程中記錄的音頻。(4)Graphs:展示模型的數(shù)據(jù)流圖,以及訓(xùn)練在各個設(shè)備上消耗的內(nèi)存和時間。(5)Distributions:展示訓(xùn)練過程中記錄的數(shù)據(jù)的分部圖。(6)Histograms:展示訓(xùn)練過程中記錄的數(shù)據(jù)的柱狀圖。(7)Embeddings:展示詞向量后的投影分部。TensorBoard目前支持7種可視化,主要功能包括:2.8.1TensorBoard簡介
TensorBoard以瀏覽器為顯示工具,在瀏覽器中將TensorFlow的訓(xùn)練結(jié)果可視化。TensorBoard通過運(yùn)行一個本地服務(wù)器,來監(jiān)聽6006端口。在瀏覽器發(fā)出請求時,分析訓(xùn)練時記錄的數(shù)據(jù),繪制訓(xùn)練過程中的圖像。2.8.1TensorBoard簡介2.8.2TensorBoard基本用法
TensorBoard主要用來可視化與TensorFlow自動圖相關(guān)的數(shù)據(jù),要將普通的Python代碼轉(zhuǎn)換為TensorFlow的自動圖結(jié)構(gòu),只要使用裝飾器@tf.function就可以非常方便地實(shí)現(xiàn)。@tf.functiondefmat_op(m1,m2):
"""矩陣運(yùn)算
參數(shù):
m1:參與運(yùn)算張量
m2:參與運(yùn)算張量
返回:
res:張量運(yùn)算的結(jié)果"""res=tf.matmul(m1,m2)returnres2.8.2TensorBoard基本用法
定義參與運(yùn)算的張量和日志路徑:#定義兩個相乘的張量c1=tf.constant([[1,2,3],[4,5,6]],name='m1')c2=tf.constant([[1,2],[3,4],[5,6]],name='m2')#日志文件路徑log_path="./logs/matrix_op"
接著設(shè)置日志文件并追蹤張量運(yùn)算:#保存日志文件summary_writer=tf.summary.create_file_writer(log_path)#追蹤圖結(jié)構(gòu)tf.summary.trace_on(graph=True,profiler=True)#執(zhí)行運(yùn)算res=mat_op(c1,c2)2.8.2TensorBoard基本用法
保存了圖結(jié)構(gòu)之后,TensorBoard才可以去訪問,并可視化它。tf.summary.trace_export(name='mat',step=0,profiler_outdir=log_path)
當(dāng)準(zhǔn)備好了日志文件之后,我們就可以使用TensorBoard來打開它了。在命令行界面(注意:非jupyternotebook單元格)中,進(jìn)入當(dāng)前路徑,輸入如下命令:Tensorboard–logdir=./logs
打開瀏覽器之后,在地址欄輸入http://localhost:6006,就可以看到TensorBoard的界面了。keras數(shù)據(jù)集09第2章TesnorFlow2.X基礎(chǔ)2.9.1數(shù)據(jù)集加載
在TensorFlow中,keras.datasets模塊提供了常用經(jīng)典數(shù)據(jù)集的自動下載、管理、加載與轉(zhuǎn)換功能,并且提供了tf.data.Dataset數(shù)據(jù)集對象,方便實(shí)現(xiàn)多線程(Multi-threading)、預(yù)處理(Preprocessing)、隨機(jī)打
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 未來五年猴頭菌企業(yè)ESG實(shí)踐與創(chuàng)新戰(zhàn)略分析研究報告
- 未來五年慶紅寶種子企業(yè)數(shù)字化轉(zhuǎn)型與智慧升級戰(zhàn)略分析研究報告
- 未來五年花椰菜企業(yè)ESG實(shí)踐與創(chuàng)新戰(zhàn)略分析研究報告
- 未來五年家電市場管理服務(wù)企業(yè)縣域市場拓展與下沉戰(zhàn)略分析研究報告
- 未來五年杏企業(yè)數(shù)字化轉(zhuǎn)型與智慧升級戰(zhàn)略分析研究報告
- 2026年縣鄉(xiāng)教師選調(diào)進(jìn)城考試《教育心理學(xué)》題庫含答案【輕巧奪冠】
- 未來五年養(yǎng)殖淡水鰱魚企業(yè)數(shù)字化轉(zhuǎn)型與智慧升級戰(zhàn)略分析研究報告
- 模板施工健康監(jiān)測方案
- 電氣線路隱蔽工程檢查方案
- 2026年大學(xué)環(huán)境生態(tài)學(xué)期末試題及答案(真題匯編)
- 老年人高血壓的護(hù)理
- 糧油產(chǎn)品授權(quán)書
- 責(zé)任督學(xué)培訓(xùn)課件
- 關(guān)于安吉物流市場的調(diào)查報告
- 抑郁病診斷證明書
- 心電監(jiān)測技術(shù)操作考核評分標(biāo)準(zhǔn)
- 歷史時空觀念的教學(xué)與評價
- 維克多高中英語3500詞匯
- 《LED顯示屏基礎(chǔ)知識培訓(xùn)》
- 第五屆全國輔導(dǎo)員職業(yè)能力大賽案例分析與談心談話試題(附答案)
- LY/T 2501-2015野生動物及其產(chǎn)品的物種鑒定規(guī)范
評論
0/150
提交評論