專案開發環境為Visual Studio 2019 + .Net 5
建立新專案後首先通過Nuget引入相關包:
SciSharp.TensorFlow.Redist是Google提供的TensorFlow開發庫,是採用C語言開發的動態連結庫(DLL);
TensorFlow.NET採用C#語言對C語言的庫進行封裝,提供.NET呼叫介面;
TensorFlow.Keras是一個高階工具類,對建模和訓練過程進行封裝,提供簡便介面。
通過下列語句對庫進行引用:
using Tensorflow;
using Tensorflow.NumPy;
using static Tensorflow.Binding;
using static Tensorflow.KerasApi;
下面展示一些TensorFlow.NET的基本型別操作:
/// <summary> /// 構建張量 /// </summary> private void Base_Constant() { //通過基本型別構建張量 var c1 = tf.constant(3); // int var c2 = tf.constant(1.0f); // float var c3 = tf.constant(2.0); // double var c4 = tf.constant("Hello Tensorflow.Net!"); // string Console.WriteLine(c1); Console.WriteLine(c2); Console.WriteLine(c3); Console.WriteLine(c4); //通過多維數值構建張量 int[,] arr = new int[,] { { 1, 2, 3 }, { 4, 5, 6 } }; var nd = np.array(arr); var tensor = tf.constant(nd); Console.WriteLine(tensor); //構建全0或全1張量 var tensor0 = tf.constant(np.zeros(new Shape(2, 3))); var tensor1 = tf.constant(np.ones(new Shape(2, 3))); Console.WriteLine(tensor0); Console.WriteLine(tensor1); var tensor_0 = tf.zeros(new Shape(2, 3)); var tensor_1 = tf.ones(new Shape(2, 3)); Console.WriteLine(tensor_0); Console.WriteLine(tensor_1); } /// <summary> /// 張量運算 /// </summary> private void Base_Operator() { var a = tf.constant(2.0f); var b = tf.constant(3.0f); var c = tf.constant(5.0f); // 基本運算,可以採+ - * / 等運算子 var add = tf.add(a, b); var sub = tf.subtract(a, b); var mul = tf.multiply(a, b); var div = tf.divide(a, b); print($"{(float)a} + {(float)b} = {(float)add}"); print($"{(float)a} - {(float)b} = {(float)sub}"); print($"{(float)a} * {(float)b} = {(float)mul}"); print($"{(float)a} / {(float)b} = {(float)div}"); // 求平均、求和 var mean = tf.reduce_mean(tf.constant(new[] { a, b, c })); var sum = tf.reduce_sum(tf.constant(new[] { a, b, c })); print("mean =", mean.numpy()); print("sum =", sum.numpy()); // 矩陣相乘 var matrix1 = tf.constant(new float[,] { { 1, 2, 3 }, { 3, 4, 5 } }); var matrix2 = tf.constant(new float[,] { { 3, 4 }, { 5, 6 }, { 7, 8 } }); var product1 = tf.matmul(matrix1, matrix2); print("product1 =", product1.numpy()); } /// <summary> /// 生成隨機數張量 /// </summary> private void Base_Random() { var t1 = tf.random.normal(new Shape(10)); var t2 = tf.random.uniform(new Shape(2, 5)); var t3 = tf.random.uniform(new Shape(2, 5), 1, 100); Console.WriteLine($"t1={t1.numpy()}"); Console.WriteLine($"t2={t2.numpy()}"); Console.WriteLine($"t3={t3.numpy()}"); t1 = tf.random.normal(new Shape(100), mean: 0.5f, stddev: 2); var mean = tf.reduce_mean(t1); var max = tf.reduce_max(t1); var min = tf.reduce_min(t1); Console.WriteLine($"mean={mean.numpy()},max={max.numpy()},min={min.numpy()}"); }
上述程式碼基本都比較簡單,基本一看就能懂,有幾處需要解釋一下:
1、平常我們在生成隨機數時,一般都是平均分佈,但機器學習的資料更多趨向正態分佈,所以採用normal生成隨機數,mean表示中心點,stddev表示分佈範圍;
2、從表面看tf的框架似乎提供了一套可以進行矩陣運算的Math庫,但實際並非如此,tf框架的核心是可以計算運算的梯度,這個問題我們後面再講;
3、tf有兩個版本,V1版和V2版本,如果要使用V1版本語法,需要在程式碼之前加一句:tf.compat.v1.disable_eager_execution();
相對的,V2版本為:tf.enable_eager_execution();由於預設為V2版本,所以這行程式碼可以省略不寫。
本系列的所有程式碼均採用V2版本。官方提供的樣例裡有大量V1版本程式碼,有一些V2版沒有提供的功能,可能不得不採用V1版程式碼實現。
【參考資料】
【專案原始碼】
Git: https://gitee.com/seabluescn/tf_not.git
專案名稱:SayHello