在 TensorFlow 之中,我們可以使用內(nèi)置的四則運(yùn)算函數(shù)進(jìn)行操作:tf.add:進(jìn)行張量的加法;tf.subtract:進(jìn)行張量的減法;tf.multiply:進(jìn)行張量的乘法;tf.divid:進(jìn)行張量的除法。以乘法為例,我們可以看一下使用方法:x1 = tf.constant([1, 3, 5])x2 = tf.constant([1, 3, 5])y = tf.multiply(x1, x2)print(y)我們可以得到如下結(jié)果:tf.Tensor([ 1 9 25], shape=(3,), dtype=int32)由此我們可以得到兩個(gè)張量相乘的結(jié)果。但是 TensorFlow 已經(jīng)對四則運(yùn)算進(jìn)行了重載,因此我們可以直接使用 + - * / 符號進(jìn)行運(yùn)算,比如:y = x1 * x2也可以得到相同的結(jié)果。
重點(diǎn)是如何進(jìn)行調(diào)用,先來看一下語法:/* 清除瀏覽器默認(rèn)邊距 */* { padding: 0; margin: 0; }body { /* 這段代碼是為了居中顯示,不是重點(diǎn),看不懂的話可以無視 */ height: 100vh; display: flex; align-items: center; justify-content: center; /* 添加背景圖 */ background: url(../img/bg.jpg) center / cover;}.animate { width: 130px; height: 130px; background: url(../img/rect.png); /* 動畫: 動畫名(loading) 時(shí)長(0.6秒) 運(yùn)行方式(step-end) 動畫次數(shù)(3次) 填充模式(雙向) */ animation: loading .6s step-end 3 both, /* 動畫可以定義多個(gè),每個(gè)動畫用逗號分隔。*/ /* 第二個(gè)動畫的動畫名(animate) 時(shí)長(0.8秒) 運(yùn)行方式(step-end) 延時(shí)(1.8秒) 動畫次數(shù)(無限) */ animate .8s steps(12) 1.8s infinite;}/* 定義動畫:動畫名(loading) */@keyframes loading { from { background-position: 0 0 } /* 第一個(gè)數(shù)字代表x軸坐標(biāo),第二個(gè)數(shù)字代表y軸坐標(biāo) */ 10% { background-position: -130px 0 } /* x坐標(biāo):-130 y坐標(biāo):0 */ 20% { background-position: -260px 0 } /* x坐標(biāo):-260 y坐標(biāo):0 */ 30% { background-position: -390px 0 } /* x坐標(biāo):-390 y坐標(biāo):0 */ 40% { background-position: -520px 0 } /* x坐標(biāo):-520 y坐標(biāo):0 */ 50% { background-position: 0 -130px } /* x坐標(biāo):0 y坐標(biāo):-130 */ 60% { background-position: -130px -130px } /* x坐標(biāo):-130 y坐標(biāo):-130 */ 70% { background-position: -260px -130px } /* x坐標(biāo):-260 y坐標(biāo):-130 */ 80% { background-position: -390px -130px } /* x坐標(biāo):-390 y坐標(biāo):-130 */ 90% { background-position: -520px -130px } /* x坐標(biāo):-520 y坐標(biāo):-130 */ /* 修改最后一幀,以便動畫結(jié)束后盒子就應(yīng)用最后一幀的樣式 */ to { /* 下一個(gè)動畫的寬高 */ width: 216px; height: 300px; /* 下一個(gè)動畫的雪碧圖 */ background-image: url(../img/animate.png); }}/* 定義動畫:動畫名(animate) */@keyframes animate { from { background-position: 0 } to { background-position: -2600px }}運(yùn)行結(jié)果:這是怎么個(gè)原理呢?原來調(diào)用動畫的時(shí)候可以一次性調(diào)用多個(gè)動畫,動畫與動畫直接用逗號進(jìn)行分隔。第一個(gè)加載動畫我們讓他重復(fù)運(yùn)行 3 次,由于下一個(gè)動畫的背景圖和寬高都和加載動畫不同,所以調(diào)用第一個(gè)動畫時(shí)用填充模式將最后一幀定義的樣式應(yīng)用到下個(gè)動畫上。
Markdown 中的數(shù)學(xué)公式也分為「行中公式」和「獨(dú)立公式」兩種。2.1.1 行中公式行中公式使用兩個(gè)單獨(dú)的「美元符 $」表示。實(shí)例 1:$1 + 1 = 2$其渲染效果如下:2.1.1 獨(dú)立公式獨(dú)立公式的寫法是將公式兩邊用兩個(gè)連續(xù)的「美元符 $$」包裹,換行通過在行尾添加 \\ 實(shí)現(xiàn)。實(shí)例 2:$$x + y = 10 \\x - y = 6 \\2x = 16 \\x = 8 \\y = 2$$其渲染效果如下:
arcTo 方法作用是繪制一個(gè)切線為 PA 和 PB、半徑為 r 的圓弧,圓弧由切線控制。變量說明:變量名類型是否必須說明x1Number是切線交點(diǎn)P的X坐標(biāo)。y1Number是切線交點(diǎn)P的Y坐標(biāo)。x2Number是指PB切線的任意一點(diǎn)的X坐標(biāo)。y2Number是指PB切線的任意一點(diǎn)的Y坐標(biāo)。rNumber是圓的半徑。
我們再來看一下 2.3 的例子:BinaryOperator<Long> add = (x,y) -> x+y ;在這個(gè)例子中,參數(shù) x,y 和返回值 x+y 我們都沒有指定具體的類型,但是編譯器卻知道它是什么類型。原因就在于編譯器可以從程序的上下文推斷出來,這里的上下文包含下面 3 種情況:賦值上下文;方法調(diào)用上下文;類型轉(zhuǎn)換上下文。通過這 3 種上下文就可以推斷出 Lambda 表達(dá)式的目標(biāo)類型。目標(biāo)類型并不是一個(gè)全新的概念,通常我們在 Java 數(shù)據(jù)初始化的時(shí)候就是根據(jù)上下文推斷出來的。比如:String[] array = {"hello","world"};等號右邊的代碼我們并沒有聲明它是什么類型,系統(tǒng)會根據(jù)上下文推斷出類型的信息。
在 Python 的 math 模塊中包含如下常用的三角函數(shù),在詞條 “Python 中常用的標(biāo)準(zhǔn)庫系列之 math 模塊” 獲取詳細(xì)用法。函數(shù)功能描述 abs(x) 返回?cái)?shù)值的絕對值 ceil(x) 返回?cái)?shù)值的上入整數(shù) exp(x) 返回 e 的 x 次冪 fabs(x) 返回浮點(diǎn)數(shù)的絕對值 floor(x) 返回浮點(diǎn)數(shù)的下舍整數(shù) log(x) 返回 x 的自然對數(shù) log10(x) 返回以 10 為基數(shù)的 x 的對數(shù) max(x, y) 返回給定參數(shù)的最大值 min(x, y) 返回給定參數(shù)的最小值 pow(x, y) 返回以 x 為底數(shù)、y 為指數(shù)的運(yùn)算結(jié)果 round(x) 返回浮點(diǎn)數(shù) x 的四舍五入值 sqrt(x) 返回?cái)?shù)值 x 的平方根
首先編寫布局文件,我們需要 4 個(gè) TextView,分別用來顯示觸摸起點(diǎn)的 X 軸、Y 軸坐標(biāo),以及滑動時(shí)的 X 軸、Y 軸偏移量,最后創(chuàng)建一個(gè) View 用作觸摸事件的接收源。內(nèi)容非常簡單,代碼如下:<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="20dp" android:transitionGroup="true" tools:context=".MainActivity"> <TextView android:id="@+id/title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_centerHorizontal="true" android:text="Android 事件處理" android:textSize="35dp" /> <TextView android:id="@+id/down_x" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@+id/title" android:layout_alignStart="@+id/title" android:layout_marginTop="30dp" android:hint="點(diǎn)擊的X軸坐標(biāo)" android:textColor="@color/colorPrimary" /> <TextView android:id="@+id/down_y" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@+id/down_x" android:layout_alignStart="@+id/down_x" android:layout_marginTop="10dp" android:hint="點(diǎn)擊的Y軸坐標(biāo)" android:textColor="@color/colorPrimary" /> <TextView android:id="@+id/move_x" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@+id/down_y" android:layout_alignStart="@+id/down_y" android:layout_marginTop="60dp" android:hint="移動位置的X軸坐標(biāo)" android:textColor="@color/colorPrimaryDark" /> <TextView android:id="@+id/move_y" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@+id/move_x" android:layout_alignStart="@+id/move_x" android:hint="移動位置的Y軸坐標(biāo)" android:textColor="@color/colorPrimaryDark" /> <TextView android:id="@+id/touch" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:text="點(diǎn)我開始滑動" android:textColor="#ff5480ff" android:textSize="35sp" /></RelativeLayout>
既然了解了如何自定義網(wǎng)絡(luò)層,那么便要知道如何自定義網(wǎng)絡(luò)模型,其實(shí)網(wǎng)絡(luò)模型是由網(wǎng)絡(luò)層構(gòu)成的,因此只要將網(wǎng)絡(luò)層定義清楚,那么網(wǎng)絡(luò)模型便可以很輕松得到了。網(wǎng)絡(luò)模型的構(gòu)建大致也分為以下幾步:自定義模型類,并繼承自 tf.keras.Model 類;在初始化函數(shù)之中定義要用到的網(wǎng)絡(luò)層;在 call 函數(shù)之中定義具體的處理方式。于是,借用上面的網(wǎng)絡(luò)層,我們可以定義我們的網(wǎng)絡(luò)模型:class MyModel(tf.keras.Model): def __init__(self): super(MyModel, self).__init__() self.l1 = MyLayer(10, 5) self.l2 = MyLayer2(5, 10) def call(self, inputs, training=True): x = self.l1(inputs) y = self.l2(x) return y我們的網(wǎng)絡(luò)模型使用了 MyLayer 和 MyLayer2 兩個(gè)網(wǎng)絡(luò)層,并且在 call 函數(shù)之中進(jìn)行了順序處理,從而得到最后的結(jié)果。我們可以通過測試:x = tf.ones((5, 5))model = MyModel()y = model(x)print(y)得到輸出:tf.Tensor([[ 0.07020754 -0.14177878 -0.00841531 -0.0398875 0.14821295] [ 0.07020754 -0.14177878 -0.00841531 -0.0398875 0.14821295] [ 0.07020754 -0.14177878 -0.00841531 -0.0398875 0.14821295] [ 0.07020754 -0.14177878 -0.00841531 -0.0398875 0.14821295] [ 0.07020754 -0.14177878 -0.00841531 -0.0398875 0.14821295]], shape=(5, 5), dtype=float32)我們發(fā)現(xiàn)我們的網(wǎng)絡(luò)模型也是很正確的進(jìn)行了輸出。
Python 提供函數(shù) int 用于將字符串轉(zhuǎn)換為整數(shù)。使用 int 函數(shù)重寫以上程序如下:>> a = input()'1'>> b = input()'1'>> x = int(a)>> y = int(b)>> x + y2在第 5 行,將字符串 a 轉(zhuǎn)換為整數(shù) x 在第 6 行,將字符串 b 轉(zhuǎn)換為整數(shù) y 在第 7 行,將整數(shù) x 和整數(shù) y 相加,得到結(jié)果 2將 input 返回的結(jié)果從將字符串轉(zhuǎn)換為整數(shù)后,我們得到了預(yù)期的結(jié)果。
createLinearGradient() 方法創(chuàng)建一個(gè)沿參數(shù)坐標(biāo)指定的直線的漸變,該方法返回一個(gè)線性 CanvasGradient 對象。語法:ctx.createLinearGradient(startX, startY, endX, endY);變量說明:變量名類型是否必須說明startXNumber是起點(diǎn)的 x 軸坐標(biāo)。startYNumber是起點(diǎn)的 y 軸坐標(biāo)。endXNumber是終點(diǎn)的 x 軸坐標(biāo)。endYNumber是終點(diǎn)的 y 軸坐標(biāo)。返回值:CanvasGradient一個(gè)根據(jù)指定線路初始化的線性漸變對象。
定義:雙引號內(nèi)存放文字的字符串對象。使用場景:推薦用來定義復(fù)雜的字符串(包括轉(zhuǎn)義符或者表達(dá)式插值操作)。實(shí)例:# 輸出一段文字puts "Hello Ruby!"# ---- 輸出結(jié)果 ----Hello Ruby!當(dāng)使用雙引號創(chuàng)建字符串對象時(shí),首先他會查找以反斜杠\開頭的字符,進(jìn)行轉(zhuǎn)義操作,其中最常見轉(zhuǎn)義符為\n,它叫做換行符,當(dāng)輸出包含換行符的字符串的時(shí)候,\n會被強(qiáng)制轉(zhuǎn)換為換行。實(shí)例:# 輸出帶有換行符的字符串puts "Goodnight,\nAlice"# ---- 輸出結(jié)果 ----Goodnight,Alice其次,雙引號字符串做的第二件事是表達(dá)式插值,在字符串中,#{表達(dá)式}會被表達(dá)式的結(jié)果替換。實(shí)例:# 表達(dá)式插值name = 'Alice' #定義一個(gè)局部變量name,這里的字符串單引號雙引號均可puts "Goodnight, #{name}"# ---- 輸出結(jié)果 ----Goodnight, Alice表達(dá)式也可以是數(shù)學(xué)運(yùn)算。實(shí)例:x, y, z = 12, 36, 72puts "x 的值為 #{ x }"puts "x + y 的值為 #{ x + y }"puts "x + y + z 的平均值為 #{ (x + y + z)/3 }"# ---- 輸出結(jié)果 ----x 的值為 12x + y 的值為 48x + y + z 的平均值為 40如果表達(dá)式只是全局變量$,類變量@@或?qū)嵗兞緻,則可以省略花括號。變量類型將在之后章節(jié)給大家普及。實(shí)例:puts "This is line #$."# ---- 輸出結(jié)果 ----This is line 1經(jīng)驗(yàn):除了#{}這種表達(dá)式插值的形式,使用+也可以進(jìn)行字符串拼接操作,但是要求進(jìn)行拼接的兩個(gè)變量的類型一定是字符串,否則會拋出異常,Ruby 會將#{}表達(dá)式中的結(jié)果強(qiáng)制轉(zhuǎn)化為字符串,我們不需要關(guān)心變量的類型,只需要關(guān)心拼接的操作。所以,最好不使用+來拼接字符串。對比下面兩種情況:x = 12puts "x 的值為 #{x}"# ---- 輸出結(jié)果 ----x 的值為 12x = 12puts "x 的值為 " + x# ---- 輸出結(jié)果 ----Traceback (most recent call last): 1: from ruby.rb:2:in `<main>'ruby.rb:2:in `+': no implicit conversion of Integer into String (TypeError)而這樣就不會拋出異常:x = 12puts "x 的值為 " + x.to_s # 將12從數(shù)字轉(zhuǎn)化成字符串# ---- 輸出結(jié)果 ----x 的值為 12
用法:RUN <命令>示例:RUN echo 'text' > test.txt為了保持 Dockerfile 文件的可讀性,以及可維護(hù)性,建議將長的或復(fù)雜的RUN指令用反斜杠\分割成多行。例如:RUN apt update && apt install -y \ vim \ emacs這里需要注意一個(gè)關(guān)于軟件源更新安裝軟件的問題。如果我們需要更新軟件源并安裝軟件源中的軟件vim,在Linux環(huán)境中我們一般會執(zhí)行這個(gè)的命令:apt updateapt install -y vim如果需要在鏡像中安裝軟件,我們會想當(dāng)然地在 Dockerfile 寫成這樣RUN apt updateRUN apt install -y vimDockerfile 構(gòu)建一次之后,apt update 構(gòu)建的鏡像層就會緩存到本地,無論后面這個(gè) Dockerfile 如何更新 apt install 的內(nèi)容,apt update 鏡像緩存也不會更新,這會導(dǎo)致安裝的始終是第一次 Dockerfile構(gòu)建時(shí)獲取的軟件源版本,除非你手動刪除這些緩存鏡像層。解決的方法很簡單,用 RUN apt-get update && apt-get install -y 可以確保 Dockerfiles 每次安裝的都是包的最新的版本。
上面介紹了核心編程方法,我們給出一個(gè)非常簡潔明了的官方例子,切實(shí)體會一下 StampedLock 的用法。import java.util.concurrent.locks.StampedLock;public class StampedLockTest { // 成員變量 private double x, y; // 鎖實(shí)例 private final StampedLock sl = new StampedLock(); // 排它鎖-寫鎖(writeLock) void move(double deltaX, double deltaY) { long stamp = sl.writeLock(); try { x += deltaX; y += deltaY; } finally { sl.unlockWrite(stamp); } } // 一個(gè)只讀方法 // 其中存在樂觀讀鎖到悲觀讀鎖的轉(zhuǎn)換 double distanceFromOrigin() { // 嘗試獲取樂觀讀鎖 long stamp = sl.tryOptimisticRead(); // 將全部變量拷貝到方法體棧內(nèi) double currentX = x, currentY = y; // 檢查在獲取到讀鎖stamp后,鎖有沒被其他寫線程搶占 if (!sl.validate(stamp)) { // 如果被搶占則獲取一個(gè)共享讀鎖(悲觀獲取) stamp = sl.readLock(); try { // 將全部變量拷貝到方法體棧內(nèi) currentX = x; currentY = y; } finally { // 釋放共享讀鎖 sl.unlockRead(stamp); } } // 返回計(jì)算結(jié)果 return Math.sqrt(currentX * currentX + currentY * currentY); } // 獲取讀鎖,并嘗試轉(zhuǎn)換為寫鎖 void moveIfAtOrigin(double newX, double newY) { long stamp = sl.tryOptimisticRead(); try { // 如果當(dāng)前點(diǎn)在原點(diǎn)則移動 while (x == 0.0 && y == 0.0) { // 嘗試將獲取的讀鎖升級為寫鎖 long ws = sl.tryConvertToWriteLock(stamp); // 升級成功,則更新stamp,并設(shè)置坐標(biāo)值,然后退出循環(huán) if (ws != 0L) { stamp = ws; x = newX; y = newY; break; } else { // 讀鎖升級寫鎖失敗則釋放讀鎖,顯示獲取獨(dú)占寫鎖,然后循環(huán)重試 sl.unlockRead(stamp); stamp = sl.writeLock(); } } } finally { sl.unlock(stamp); } }}注意在使用時(shí),獲取鎖的操作應(yīng)該放在 try 之前,而釋放鎖的操作需要放在 finally 中,可確保鎖釋放。另外需要注意 StampedLock 具有不可重入性。
在網(wǎng)絡(luò)層的使用之中,我們可能會遇到網(wǎng)絡(luò)層嵌套使用的情況。而且 TensorFlow 也可以支持網(wǎng)絡(luò)層的嵌套使用。比如以下代碼:class MyLayer(tf.keras.layers.Layer): def __init__(self, hidden_units, input_units): super(MyLayer, self).__init__() self.w = self.add_weight(shape=(input_units, hidden_units), initializer="random_normal") self.b = self.add_weight(shape=(hidden_units,), initializer="random_normal") def call(self, inputs): return tf.matmul(tf.matmul(inputs, inputs), self.w) + self.bclass MyLayer2(tf.keras.layers.Layer): def __init__(self, hidden_units, input_units): super(MyLayer2, self).__init__() self.w = self.add_weight(shape=(input_units, hidden_units), initializer="random_normal") self.b = self.add_weight(shape=(hidden_units,), initializer="random_normal", trainable=False) def call(self, inputs, training=True): return tf.matmul(inputs, self.w) + self.bclass MyLayer3(tf.keras.layers.Layer): def __init__(self): super(MyLayer3, self).__init__() self.l1 = MyLayer(10, 5) self.l2 = MyLayer2(5, 10) def call(self, inputs, training=True): x = self.l1(inputs) y = self.l2(x) return y在這個(gè)網(wǎng)絡(luò)層之中,我們在前面重新定義了兩個(gè)網(wǎng)絡(luò)層類,并在后面我們嵌套了我們之前的兩個(gè)網(wǎng)絡(luò)層,我們通過順序調(diào)用來實(shí)現(xiàn)了一個(gè)新的網(wǎng)絡(luò)層的操作。我們可以通過具體的數(shù)據(jù)進(jìn)行測試:x = tf.ones((5, 5))my_layer = MyLayer3(10, 5)y = my_layer(x)print(y)我們可以得到輸出:tf.Tensor([[ 0.00422265 0.02767846 0.04585129 0.10204907 -0.08051172] [ 0.00422265 0.02767846 0.04585129 0.10204907 -0.08051172] [ 0.00422265 0.02767846 0.04585129 0.10204907 -0.08051172] [ 0.00422265 0.02767846 0.04585129 0.10204907 -0.08051172] [ 0.00422265 0.02767846 0.04585129 0.10204907 -0.08051172]], shape=(5, 5), dtype=float32)可以發(fā)現(xiàn),我們的程序成功地運(yùn)行了相應(yīng)的數(shù)據(jù),并產(chǎn)生了結(jié)果。
在講解變量之前,我們先來看一段代碼:int x;int y=0;char z='A';x=6;在上面這段代碼中出現(xiàn)的 x、y、z 都是一個(gè) C 變量。變量是編程語言中不可或缺的組成部分。它承載這存貯數(shù)據(jù)以及計(jì)算結(jié)果等等功能,顧名思義變量就是可以再計(jì)算執(zhí)行過程中變化的量。這節(jié)課我們來學(xué)習(xí)下到底什么是變量。
arc 方法作用是繪制一個(gè)起點(diǎn)在 (x, y)、半徑為 r 的圓弧,圓弧由起始角和結(jié)束角控制。變量說明:變量名類型是否必須說明xNumber是指定圓心位置的X坐標(biāo)。yNumber是指定圓心位置的Y坐標(biāo)。rNumber是圓的半徑。sAngleNumber是起始角,以弧度計(jì),(弧的圓形的三點(diǎn)鐘位置是 0 度)。eAngleNumber是結(jié)束角,以弧度計(jì)。counterclockwiseBoolean否規(guī)定應(yīng)該逆時(shí)針還是順時(shí)針繪圖,false = 順時(shí)針,true = 逆時(shí)針。
strokeText 方法作用是繪制一行空心文字。語法:void ctx.strokeText(text, x, y [, maxWidth]);變量說明:變量名類型是否必須說明textString是要繪制的文本。xNumber是文本起始點(diǎn)的 x 軸坐標(biāo)。yNumber是文本起始點(diǎn)的 y 軸坐標(biāo)。maxWidthNumber是可選,需要繪制的最大寬度。如果指定了值,并且經(jīng)過計(jì)算字符串的寬度比最大寬度還要寬,字體為了適應(yīng)會使用一個(gè)水平縮小的字體或者小號的字體。
先來回顧下之前章節(jié)介紹的函數(shù)類型:const add: (x: number, y: number) => string = function(x: number, y: number): string { return (x + y).toString()}等號左側(cè)的 (x: number, y: number) => string 為函數(shù)類型。再看下泛型類型:function identity<T>(arg: T): T { return arg}let myIdentity: <T>(arg: T) => T = identity同樣的等號左側(cè)的 <T>(arg: T) => T 即為泛型類型,它還有另一種帶有調(diào)用簽名的對象字面量書寫方式:{ <T>(arg: T): T }:function identity<T>(arg: T): T { return arg}let myIdentity: { <T>(arg: T): T } = identity這就引導(dǎo)我們?nèi)懙谝粋€(gè)泛型接口了。把上面例子里的對象字面量拿出來作為一個(gè)接口:interface GenericIdentityFn { <T>(arg: T): T}function identity<T>(arg: T): T { return arg}let myIdentity: GenericIdentityFn = identity進(jìn)一步,把泛型參數(shù)當(dāng)作整個(gè)接口的一個(gè)參數(shù),我們可以把泛型參數(shù)提前到接口名上。這樣我們就能清楚的知道使用的具體是哪個(gè)泛型類型:interface GenericIdentityFn<T> { (arg: T): T}function identity<T>(arg: T): T { return arg}let myIdentity: GenericIdentityFn<number> = identity注意,在使用泛型接口時(shí),需要傳入一個(gè)類型參數(shù)來指定泛型類型。示例中傳入了 number 類型,這就鎖定了之后代碼里使用的類型。
微分是所有目前幾乎所有機(jī)器學(xué)習(xí)的基礎(chǔ),也是 TensorFlow 與 Pytorch 等框架的基礎(chǔ)。我們對模型進(jìn)行優(yōu)化的過程大致可以分為以下三個(gè)步驟:數(shù)據(jù)通過模型得到輸出;我們通過計(jì)算得到模型中每個(gè)參數(shù)的梯度;確定學(xué)習(xí)的步長(學(xué)習(xí)率);按照梯度的方向和學(xué)習(xí)率對每個(gè)參數(shù)進(jìn)行優(yōu)化。我們可以很清楚的看到,最后的兩步是關(guān)鍵的優(yōu)化部分,而第二步 —— 求得梯度的一步就是這兩個(gè)關(guān)鍵步驟的前提和基礎(chǔ)。因此我們要首先了解什么是 “梯度”。梯度的本意是一個(gè)向量(矢量),表示某一函數(shù)在該點(diǎn)處的方向?qū)?shù)沿著該方向取得最大值 —— 百度百科。簡單來說,就是梯度是一個(gè)方向,它會指明某一個(gè)參數(shù)在哪個(gè)方向上面變化地更快。或者不恰當(dāng)?shù)卣f(但是卻非常容易理解),梯度可以理解為一個(gè)參數(shù)的導(dǎo)數(shù)。因此我們可以通過梯度就可以得到模型的參數(shù)在哪個(gè)方向上面變化,會使得最終的結(jié)果的 Loss 變?。贿M(jìn)而我們就可以進(jìn)行模型的優(yōu)化工作。舉個(gè)例子:y = x**2 + 4這是一個(gè)很簡單的賦值公式:我們將 x 的平方加上 4 ,然后將其賦給 y 。那么 y 對于 x 求導(dǎo)數(shù),便得到:dy_dx = 2*x因此我們在 x 取任意一個(gè)值的時(shí)候便可以得到 y 對于 x 的梯度。比如當(dāng) x 為 5 的時(shí)候,那么 y 對于 x 的梯度便為 2 * 5 = 10 。
按照第 2 小節(jié)的方式 show 出來的 Toast 默認(rèn)會在屏幕的底部中間位置展示,如果想要不走尋常路,可以通過接口setGravity(int gravity, int x, int y)改變 Toast 展示的位置,參數(shù)如下:int gravity:第一個(gè)參數(shù)表示重心,和 Layout 里面的 gravity 類似,我們可以直接使用 Gravity.java 類里面的常量來設(shè)置。有以下四種可選項(xiàng):Gravity.BOTTOMGravity.RIGHTGravity.LEFTGravity.TOP當(dāng)然我們也可以同時(shí)設(shè)置兩個(gè)值,中間用“|”隔開,如Gravity.TOP|Gravity.LEFT表示左上方向。int x:設(shè)置水平方向上的距離,這個(gè)距離的參照是左邊還是右邊依賴第一個(gè)參數(shù)gravityint y:設(shè)置垂直方向上的距離,這個(gè)距離的參照是頂部還是底部依賴于第一個(gè)參數(shù)gravity的設(shè)置如果設(shè)置 gravity 為 Gravity.CENTER,x 為 100,y 為 200。那么最后 show 出來的示意圖如下:
整數(shù)相減 >>> 2 - 11浮點(diǎn)數(shù)相減 >>> 2.3 - 1.21.09999999999999輸出結(jié)果為 1.09999999999999,而不是 1.1。在計(jì)算機(jī)內(nèi)部,有的浮點(diǎn)數(shù)無法被精確的表示,在這個(gè)例子中,只能使用近似值來表示 1.1。復(fù)數(shù)相減 >>> x = 1 + 2j>>> y = 2 + 3j>>> y - x(1 + 1j)
CentOS 8 系統(tǒng)中自帶 zip、unzip 壓縮與解壓工具,可以使用 zip -v、unzip -v 命令查看當(dāng)前是否安裝 zip、unzip 工具,若是沒有安裝,則可以使用如下命令安裝:yum -y updateyum -y install zip unzip安裝過程如下圖:如上圖所示,先要更新 yum 源的軟件包數(shù)據(jù),如下圖所示為安裝 zip、unzip 的過程執(zhí)行圖:Tips:yum 是 Linux 中的一個(gè)軟件管理倉庫,關(guān)于 yum 如何安裝軟件后續(xù)小節(jié)會詳細(xì)介紹。
我們使用 strftime 來格式化時(shí)間。實(shí)例:time = Time.newtime.strftime("%d/%m/%Y") # "10/04/2020"time.strftime("%k:%M") # "0:00"time.strftime("%I:%M %p") # "12:00 AM"time.strftime("Today is %A") # "Today is Friday"time.strftime("%d of %B, %Y") # "10 of April, 2020"time.strftime("Unix time is %s") # "Unix time is 1586448049"如您所見,此方法非常靈活。您可以獲取不帶日期的時(shí)間,也可以獲取格式正確的日期以及當(dāng)前月份的年,日和名稱。方法時(shí)機(jī)簡介(調(diào)用的時(shí)機(jī))%d每月的某天(01…31)%m一年中的月份(01…12)將%-m用于(1…12)%k小時(shí)(0…23)%M分鐘%S秒(00…60)%I小時(shí) (1…12)%pAM/PM%Y年%A星期幾(名稱)%B月(名稱)
寫入圖片常用方法,見下表。方法參數(shù)描述 insert_bitmap(filename, row, col, x = 0, y = 0, scale_x = 1, scale_y = 1) 其中 filename 為文件名,row 為行索引,col 為列索引,x 為水平方向偏移位置,y 為垂直方向偏移位置,scale_x 與 scale_y 為縮放比例,默認(rèn) 1,即按 1:1 行展示在指定位置插入圖片對應(yīng)代碼中訪問,如下所示:ws = wb.add_sheet("sheet1")ws.insert_bitmap("user1.bmp", 0, 0)通過上述代碼,可以得知在創(chuàng)建的 sheet1 下,第 1 行第 1 列的位置插入了 user1.bmp 圖片。
對輸入的時(shí)間字符串按照指定格式輸出。示例如下:{{ value|date:"D d M Y" }}這里參數(shù)含義較多,請參考官方文檔。
我們通過之前的學(xué)習(xí)了解了,如何去定義一個(gè)類。class C puts "Hello"end# ---- 輸出結(jié)果 ----HelloRuby 中類定義的語句和其他語句本質(zhì)是一樣的,我們現(xiàn)在使用 3.times 來迭代定義類 C。3.times do class C puts "Hello" endend# ---- 輸出結(jié)果 ----HelloHelloHello這并不意味著我們可以定義三個(gè)同樣名字為 C 的類,類只有第一次被創(chuàng)建,之后我們只是打開了這個(gè)類,并追加了一些內(nèi)容給這個(gè)類。class D def x 'x' endendclass D def y 'y' endendobj = D.newputs obj.xputs obj.y# ---- 輸出結(jié)果 ----xy解釋:當(dāng)?shù)谝淮翁峒癱lass D的時(shí)候,我們還沒有類 D,所以我們定義了類 D,并增加了一個(gè)x方法。當(dāng)?shù)诙翁峒癱lass D的時(shí)候,我們已經(jīng)創(chuàng)建了類 D,就不會再次定義了,只是重新打開這個(gè)類 D,并給它定義了y方法。Tips:您甚至可以修改 Array 和 String 這些類,為這些類增加補(bǔ)丁。
在 JavaScript 構(gòu)造函數(shù)也被成為 對象構(gòu)造器,用于產(chǎn)生對象。構(gòu)造函數(shù)的聲明和普通函數(shù)幾乎沒有區(qū)別:function Point(x, y) { this.x = x; this.y = y;}var point = new Point(1, 2);console.log(point.x); // 輸出:1console.log(point.y); // 輸出:2構(gòu)造函數(shù)使用 new 關(guān)鍵字來構(gòu)造對象。所以當(dāng)一個(gè)函數(shù)被使用 new 關(guān)鍵字調(diào)用時(shí),這個(gè)函數(shù)就會作為一個(gè)構(gòu)造函數(shù)。在一個(gè)構(gòu)造函數(shù)被調(diào)用后,其內(nèi)部的 this 會指向一個(gè)對象,具體的內(nèi)容可以參考 構(gòu)造函數(shù) 章節(jié)。
TypeScript 類型兼容性是基于結(jié)構(gòu)類型的;結(jié)構(gòu)類型只使用其成員來描述類型。TypeScript 結(jié)構(gòu)化類型系統(tǒng)的基本規(guī)則是,如果 x 要兼容 y,那么 y 至少具有與 x 相同的屬性。比如:interface User { name: string, year: number}let protagonist = { name: 'Sherlock·Holmes', year: 1854, address: 'Baker Street 221B'}let user: User = protagonist // OK代碼解釋: 接口 User 中的每一個(gè)屬性在 protagonist 對象中都能找到對應(yīng)的屬性,且類型匹配。另外,可以看到 protagonist 具有一個(gè)額外的屬性 address,但是賦值同樣會成功。
流程圖常用于項(xiàng)目的需求分析和設(shè)計(jì)階段,也較常出現(xiàn)于程序使用手冊中。實(shí)例 9:冒泡排序流程圖。?```mermaidgraph LR 執(zhí)行1[i = 1] 執(zhí)行2[j = 0] 執(zhí)行3[i ++] 執(zhí)行4["a = arr[j], b = arr[j + 1]"] 執(zhí)行5[交換 a, b] 執(zhí)行6[j ++] 判斷1["i < n"] 判斷2["j < n - i"] 判斷3["a > b"] 開始 --> 執(zhí)行1 執(zhí)行1 --> 判斷1 判斷1 --Y--> 執(zhí)行2 執(zhí)行2 --> 判斷2 判斷2 --Y--> 執(zhí)行4 判斷2 --N--> 執(zhí)行3 執(zhí)行3 --> 判斷1 執(zhí)行4 --> 判斷3 判斷3 --N--> 判斷2 判斷3 --Y--> 執(zhí)行5 執(zhí)行5 --> 執(zhí)行6 執(zhí)行6 --> 判斷2 判斷1 --N--> 結(jié)束?```渲染效果如下:
需要使用 gcc 編譯器對源碼進(jìn)行編譯,安裝 gcc 命令如下:yum -y install gcc執(zhí)行結(jié)果如下圖: