[[433966]] 図 1 に示すように、さまざまな種類の機械学習技術は、さまざまなカテゴリに分類できます。方法の選択は、問題の種類 (分類、回帰、クラスタリング)、データの種類 (画像、グラフ、時系列、オーディオなど)、および方法自体の構成 (チューニング) によって異なります。 この記事では、Python で最も有名な 3 つのモジュールを使用して、単純な線形回帰モデルを実装します。 Python を使用する理由は、学習と適用が簡単だからです。 使用する 3 つのモジュールは次のとおりです。 1- Numpy: 配列、行列、多次元行列、およびそれらに関連するすべての操作に使用できます。 2- Keras: TensorFlow への高レベル インターフェース。 また、深層学習モデルと浅い学習モデルの両方をサポートおよび実装するためにも使用されます。 これは Google のエンジニアによって開発されました。 3- PyTorch: Torch をベースにしたディープラーニング フレームワーク。 これはFacebookによって開発されました。 これらのモジュールはすべてオープンソースです。 Keras と PyTorch はどちらも、実行を高速化するために GPU の使用をサポートしています。 次のセクションでは、線形回帰の理論と概念について説明します。 すでに理論に精通していて、実践的な部分を知りたい場合は、次の部分に進んでください。 線形回帰これは、基礎となるデータに線を当てはめる数学的手法です。 出力と入力の間には線形関係があると想定します。 入力は特徴または説明変数と呼ばれ、出力はターゲットまたは従属変数と呼ばれます。 出力変数は連続している必要があります。 たとえば、価格、速度、距離、温度などです。 次の式は線形回帰モデルを数学的に表します。 Y = W*X + B この方程式を行列形式で記述すると、 Y は出力行列、X は入力行列、W は重み行列、B はバイアス ベクトルです。 重みとバイアスは線形回帰パラメータです。 重みとバイアスは、それぞれ傾きと切片と呼ばれることもあります。 モデルをトレーニングする最初のステップは、これらのパラメータをランダムに初期化することです。 次に、入力データを使用して出力を計算します。 計算された出力は、誤差を測定することによって実際の出力と比較され、それに応じてパラメータが更新されます。上記の手順を繰り返します。この誤差は L2 ノルム (二乗誤差の合計) と呼ばれ、次のように表されます。 誤差を計算する関数は損失関数とも呼ばれ、さまざまな式を持つことができます。 i はデータ サンプルの数、y は予測出力、t は実際のターゲットです。 パラメータは、次の式で示される勾配降下法則に従って更新されます。 ここで、(ギリシャ文字のイータ)は学習率であり、パラメータの更新ステップ(更新速度)を指定します。 (ギリシャ文字のデルタ) は、予測された出力と実際の出力の差です。 i は反復(いわゆるラウンド)を表します。 L(W)は、重みに対する損失関数の勾配(微分)です。 学習率の値については言及する価値のあることが 1 つあります。 値が小さいほどトレーニングが遅くなり、値が大きいほど局所的最小値付近での振動や発散(損失関数の局所的最小値に到達できない)が発生します。 図 2 は上記のすべてをまとめたものです。 それでは、各モジュールを詳しく見て、上記のメソッドを実装してみましょう。 Numpy実装Google Colab は強力で、必要なモジュールがすべて提供されており、インストールが不要で(一部のモジュールを除く)、無料で使用できるため、IDE(統合開発環境)として使用します。 実装を簡素化するために、単一の特徴とバイアス (y = w1*x1 + b) を持つ線形関係を検討します。 まず、線形回帰モデルを実装するための Numpy モジュールと視覚化のための Matplotlib をインポートします。 - #モデルを構築するにはNumpyが必要です
- numpyをnpとしてインポートする
- #データを視覚化するためのモジュールmatplotlibをインポートします
- matplotlib.pyplot をpltとしてインポートします。
作業にはいくつかのデータが必要です。 データは特徴と出力で構成されます。 特徴生成のために、ランダムな均一分布から 1000 個のサンプルを生成します。 - # この行は、コードを再現可能にするために使用します(実行時に同じ結果が得られるようにするため)
- np.ランダムシード(42)
- #まず、サイズを格納する変数を宣言します 生成したいトレーニングセットの
- 観測数 = 1000
- # 次の関係があると仮定します
- # y = 13x + 2
- # yは出力です xは入力または特徴である
- #一様分布からランダムに特徴を生成します。このメソッドには3 つの引数(low、high、 size ) があります。
- #サイズ xは1による観測です。この場合: 1000 x 1。
- x = np.random.uniform(low=-10, high=10, size =(観測値,1))
- #特徴ベクトルの形状を出力してみましょう
- 印刷 (x.shape)
出力 (ターゲット) を生成するには、次の関係を使用します。 - Y = 13 * X + 2 + ノイズ
これを線形回帰モデルを使用して推定してみます。 重み値は 13、バイアスは 2 です。ノイズ変数はランダム性を追加するために使用されます。 - np.ランダムシード(42)
- #関数に小さなノイズを追加します よりランダムに
- ノイズ = np.random.uniform(-1, 1, (観測値,1))
- # f(x) = 13x + 2 + ノイズの定義に従ってターゲットを生成します。
- # これは、重みとバイアスが 1 つある単純な線形関係です。
- # この方法では、基本的に重みは13 、バイアスは 2であることを示しています。
- ターゲット = 13*x + 2 + ノイズ
- #ターゲットの形状をすぐに確認する ケースでは、n x mでなければなりません。ここで、 nはサンプル数です。
- # mは 出力変数は 1000 x 1 です。
- 印刷 (targets.shape)
生成されたデータをプロットしてみましょう。 - # xとターゲットをプロットする
- plt.plot(x,ターゲット)
- # x軸とy軸にラベルを追加する
- plt.ylabel( 'ターゲット' )
- plt.xlabel( '入力' )
- #グラフにタイトルを追加する
- plt.title( 'データ' )
- # プロットを表示
- plt.show()
図 3 はこの線形関係を示しています。 モデルのトレーニングでは、パラメータの初期値から始めます。 それらは、指定された範囲内のランダムな均一分布から生成されます。 これらの値は実際の値から大きく離れていることがわかります。 - np.ランダムシード(42)
- # 重みとバイアスを小さな初期範囲内でランダムに初期化します。
- # init_range はそれを測定する変数です。
- 初期範囲 = 0.1
- # 重量は サイズはk x mで、 kは入力変数の数、 mは 出力変数
- #この場合、重み行列は1 x 1です。 入力(x)と出力(y)は1つだけ
- 重み = np.random.uniform(low=-init_range, high=init_range, size =(1, 1))
- # 偏見は サイズ1なので 出力は1 つだけです。バイアスはスカラーです。
- バイアス = np.random.uniform(low=-init_range, high=init_range, size =1)
- # 重みがどのように初期化されたかを確認するために重みを出力します。
- #実際の値とはかけ離れていることがわかります。
- 印刷(重み)
- 印刷(バイアス)
- [[-0.02509198]]
- [0.09014286]
トレーニングの学習率も設定します。 0.02 という値を選択しました。 ここでさまざまな値を試してパフォーマンスを調べることができます。 データを取得し、パラメータを初期化し、学習率を設定したので、トレーニング プロセスを開始する準備が整いました。 エポックを 100 に設定してデータを反復処理します。各エポックでは、初期パラメータを使用して新しい出力を計算し、実際の出力と比較します。 損失関数は、前述の勾配降下法のルールに従ってパラメータを更新するために使用されます。 新しく更新されたパラメータは次の反復に使用されます。 このプロセスはエポック番号に達するまで繰り返されます。 トレーニングを中止する基準は他にもあるかもしれませんが、今日はそれについては説明しません。 - #セット 若干の学習率
- # 0.02は この例では非常にうまく機能します。もう一度、いろいろ試してみてください。
- # ぜひ試してみることを強くお勧めします。
- 学習率 = 0.02
- # トレーニング データセットを 100 回反復します。学習率0.02でうまく機能します。
- # これらを反復エポックと呼びます。
- # 各エポックの損失を格納する変数を定義しましょう。
- 損失 = []
- iが範囲(100)内にある場合:
-
- # これは線形モデルです: y = xw + b 方程式
- 出力 = np.dot(x,重み) + バイアス
- # デルタは出力とターゲットの差です
- # ここでのデルタはベクトル 1000 x 1であることに注意してください
- デルタ = 出力 - ターゲット
-
- #損失関数(回帰問題)としてL2 ノルム損失を検討していますが、2で割っています。
- # さらに、これを観測数で割って、 L2 ノルムの平均を算出します。
- 損失 = np.sum (デルタ**2)/2/観測値
-
- # 各ステップで損失関数の値を出力し、期待どおりに減少しているかどうかを確認します。
- 印刷(損失)
- #損失をリストに追加する
- 損失.append(損失)
-
- # もう一つの小さなトリックは 損失関数と同じ方法でデルタをスケーリングする
- # このように、学習率はサンプル数(観測値)に依存しません。
- # 繰り返しますが、これは原理的には何も変更しません。単に単一の学習率を選択するのが簡単になります。
- #トレーニング サンプル (観測値)の数を変更しても同じままになります。
- deltas_scaled = デルタ / 観測値
-
- # 最後に、勾配降下法の更新ルールを適用する必要があります。
- # 重みは 1 x 1、学習率は1 x 1 (スカラー)、入力は 1000 x 1、 deltas_scaledは 1000 x 1 です
- # 許可された操作が得られるように入力を転置する必要があります。
- 重み = 重み - 学習率 * np.dot(xT,deltas_scaled)
- バイアス = バイアス - 学習率 * np.sum (deltas_scaled)
-
- # 重みは線形代数的に更新されます(行列から別の行列を引く)
- # ただし、バイアスはここでは単なる 1 つの数値なので、デルタをスカラーに変換する必要があります。
- # 2 本の線はどちらも勾配降下法と一致しています。
各エポックでのトレーニング損失を観察できます。 - # プロットの時代と損失
- plt.plot(範囲(100),損失)
- # x軸とy軸にラベルを追加する
- plt.ylabel( '損失' )
- plt.xlabel( 'エポック' )
- #グラフにタイトルを追加する
- plt.title( 'トレーニング' )
- # プロットを表示
- # 曲線は各エポックで減少しており、これが必要なことです
- # 数エポック後、曲線が平坦になっていることがわかります。
- # これはアルゴリズムが収束したため、大きな更新がないことを意味します
- #または重みやバイアスの変化。
- plt.show()
図 4 からわかるように、損失は各エポックで減少しています。 これは、モデルがパラメータの実際の値にどんどん近づいていることを意味します。 数エポック経過後も、損失に大きな変化はありませんでした。 これは、モデルが収束し、パラメータが更新されなくなった(または更新が非常に小さい)ことを意味します。 さらに、実際の出力と予測出力をプロットすることで、モデルが真の関係をどれだけうまく見つけているかを検証できます。 - #本物を印刷します および予測されるターゲット 注文 線形関係があるかどうかを確認します。
- #実際のターゲットと予測されたターゲットはほぼ完全に一致しています。
- # これは私たちの機械学習モデルの成功を示す良い兆候です。
- plt.plot(出力、ターゲット、 'bo' )
- plt.xlabel( '予測' )
- plt.ylabel( '実数' )
- plt.show()
- # 重みとバイアスを出力して、それらが目的どおりに収束したかどうかを確認します。
- #実際の重みは13でバイアスは2であることが分かっています
- 印刷(重み、バイアス)
これにより、図 5 に示すグラフが生成されます。最後のエポック後のパラメータ値を印刷することもできます。 明らかに、更新されたパラメータは実際のパラメータに非常に近いです。 - [[13.09844702]] [1.73587336]
これは、Numpy が線形回帰モデルを実装する方法です。 Keras 実装まず必要なモジュールをインポートします。この実装の中核となるのは TensorFlow です。 モデルを構築するために必要です。 Keras は、使いやすさを考慮して TensorFlow を抽象化したものです。 - #データを生成するにはNumpyが必要です
- numpyをnpとしてインポートする
- #視覚化にはMatplotlib が必要です
- matplotlib.pyplot をpltとしてインポートします。
- #モデル構築にはTensorFlowが必要です
- テンソルフローをtfとしてインポートする
データ(特徴とターゲット)を生成するために、Numpy でデータを生成するコードを使用しました。 他のモデルで使用したい場合に備えて、Numpy 配列をファイルに保存する行を追加しました (おそらく必要ありませんが、追加しても問題ありません)。 - np.savez( 'TF_intro' 、入力=x、ターゲット=targets)
Keras には Sequential クラスがあります。 モデルを作成するレイヤーを積み重ねるために使用されます。 機能と出力は 1 つしかないため、密なレイヤーと呼ばれるレイヤーが 1 つだけあります。 このレイヤーは線形変換 (W*X +B) を担当し、これがモデル化の対象となります。 この層は回帰モデルなので、出力計算用のニューロンと呼ばれる計算単位を持っています。 カーネル (重み) とバイアスの初期化には、指定された範囲内で均一なランダム分布を適用しました (Numpy と同じですが、レイヤー内で指定されます)。 - #入力サイズを格納する変数を宣言します 私たちのモデルの
- #変数の数と同じである必要があります
- 入力サイズ = 1
- #出力を宣言する サイズ モデルの
- #出力の数と同じである必要があります(回帰の場合、通常は 1 です)
- 出力サイズ = 1
- # モデルの概要
- #モデルをレイアウトします '一連'
- # 計算は行われていないことに注意してください。ネットワークを説明しているだけです。
- モデル = tf.keras.Sequential([
- # 各「レイヤー」 ここに記載されています
- # 'Dense'メソッドは、数学的演算が(xw + b)であることを示します。
- tf.keras.layers.Input(形状=(入力サイズ,))、
- tf.keras.layers.Dense(出力サイズ、
- #モデルをカスタマイズするために追加できる引数があります
- #私たちの場合、私たちはただ 解決策を創造する
- #として 近い NumPyモデルに可能な限り適合
- # ここでのカーネルは単なる別名です 重みパラメータ
- kernel_initializer = tf.random_uniform_initializer(最小値 = -0.1、最大値 = 0.1)、
- バイアス初期化子 = tf.random_uniform_initializer(最小値 = -0.1、最大値 = 0.1)
- )
- ])
- #モデルの構造を印刷する
- モデル.要約()
モデルをトレーニングするために、Keras はこれを実行するための fit メソッドを提供します。 したがって、最初にデータを読み込み、特徴とラベルを指定し、エポックを設定します。 モデルをトレーニングする前に、適切なオプティマイザーと損失関数を選択してモデルを構成します。 これがコンパイルが行うことです。 学習率 0.02 (前と同じ) の確率的勾配降下法を使用し、損失は平均二乗誤差でした。 - # NPZからトレーニングデータをロードする
- トレーニングデータ = np.load ( 'TF_intro.npz' )
- #学習率を指定できるカスタムオプティマイザーを定義することもできます
- カスタムオプティマイザー = tf.keras.optimizers.SGD(学習率=0.02)
- # 'コンパイル' あなたが選ぶ場所です 最適化と損失を示す
- # ここでの損失は平均二乗誤差です
- model.compile(オプティマイザー=custom_optimizer、損失= 'mse' )
- # 最後にモデルを適合させ、入力とターゲットを指定します
- # 特に指定がない場合は、エポック数は1 (トレーニングの1 エポック) になります。
- #エポック数は 'ある意味'必須でもある
- # verboseでいろいろ試せますが、verbose=2 が推奨されます
- model.fit(training_data[ '入力' ], training_data[ 'ターゲット' ], エポック=100, 詳細=2)
トレーニング中に各エポックでの損失を監視して、すべてが順調に進んでいるかどうかを確認できます。 トレーニングが完了したら、モデルのパラメータを印刷できます。 明らかに、モデルは実際の値に非常に近いパラメータ値に収束しています。 - # 重みとバイアスの抽出は非常に簡単に行えます
- モデル.レイヤー[0].get_weights()
- # 重みとバイアスを別々の変数に保存して、簡単に調べられるようにすることができます
- # 数百または数千個存在する可能性があることに注意してください。
- 重み = model.layers[0].get_weights()[0]
- バイアス = model.layers[0].get_weights()[1]
- バイアス、重み
- (配列([1.9999999], dtype=float32), 配列([[13.1]], dtype=float32))
何千ものパラメータとさまざまなレイヤーを持つ複雑なモデルを構築する場合、TensorFlow を使用すると、多くの労力とコード行を節約できます。 モデルが単純すぎるため、Keras の利点はここでは示されません。 PyTorch 実装トーチを輸入しております。これはモデルの作成に使用されるため必須です。 - #データ生成にはNumpyが必要です
- numpyをnpとしてインポートする
- #モデル構築にはPytorch が必要です
- 輸入トーチ
データ生成部分は、以前使用したコードと同じなので表示されません。 しかし、Torch はテンソル (torch.Tensor) のみを扱います。したがって、特徴配列とターゲット配列の両方をテンソルに変換する必要があります。 最後に、これら 2 つのテンソルからテンソル データセットが作成されます。 - # TensorDatasetは、 テンソルの形式でトレーニングデータを準備する
- torch.utils.dataからTensorDataset をインポートします
- # CPUまたはGPU (利用可能な場合) のいずれかでモデルを実行するには
- デバイス = 'cuda' 、torch.cuda.is_available() の場合、そうでない場合 'CPU'
- # torchはテンソルを扱うので、 numpy配列をtorchテンソルに変換します
- x_tensor = torch.from_numpy(x) .float () です。
- y_tensor = torch.from_numpy(ターゲット) .float ()
- # 特徴テンソルとターゲットテンソルをトーチデータセットに結合する
- train_data = TensorDataset(x_tensor、y_tensor) です。
モデルの作成は簡単です。 keras と同様に、Sequential クラスはレイヤーのスタックを作成するために使用されます。 線形レイヤー (keras では密なレイヤーと呼ばれます)、入力 1 つ、出力 1 つだけがあります。 モデルのパラメータは定義された関数を使用してランダムに初期化されます。 モデルを構成するには、学習率、損失関数、およびオプティマイザーを設定します。 設定する必要がある他のパラメータもありますが、ここでは紹介しません。 - #コードを再現可能にするためにシードを初期化する
- トーチ.マニュアル_シード(42)
- # この関数 は モデルのパラメータ初期化用
- def init_weights(m):
- isinstance(m, torch.nn.Linear): の場合
- torch.nn.init.uniform_(m.weight、a = -0.1、b = 0.1) です。
- torch.nn.init.uniform_(m.bias、a = -0.1、b = 0.1) です。
- # Sequentialクラスを使用してモデルを定義する
- #含まれるもの 1つの入力と1つの出力を持つ単一の線形層のみ
- モデル = torch.nn.Sequential(torch.nn.Linear(1, 1))。 to (デバイス)
- # 定義された関数を使用してモデルのパラメータを初期化します 上から
- モデルに適用(init_weights)
- # モデルのパラメータを印刷する
- 印刷(model.state_dict())
- # 学習率を指定する
- 0.02 ...
- # 損失関数 平均二乗誤差
- loss_fn = torch.nn.MSELoss(削減 = 'mean' )
- # 最適化は、一定の学習率を持つ確率的勾配降下法である
- オプティマイザー = torch.optim.SGD(model.parameters(), lr = lr)
ミニバッチ勾配降下法を使用してモデルをトレーニングします。 DataLoader は、トレーニング データセットからバッチを作成する役割を担います。 トレーニングは keras 実装に似ていますが、異なる構文を使用します。 Torch トレーニングに関する追加のポイントがいくつかあります。 1- モデルとバッチは同じデバイス (CPU または GPU) 上にある必要があります。 2- モデルをトレーニング モードに設定する必要があります。 3- 間違った値につながる可能性がある累積 (エポック間の勾配の合計) を防ぐために、各エポックの後に勾配を必ずゼロにすることを忘れないでください。 - #データのバッチ処理にはDataLoader が必要です
- torch.utils.dataからDataLoader をインポートします
- # トレーニングデータセットはバッチに変換されます サイズはそれぞれ16サンプルです。
- #データをランダム化するためにシャッフルが有効になっています
- train_loader = DataLoader(train_data、batch_size = 16、shuffle = True )
- #関数 モデルのトレーニング用
- # それは関数です 関数の(なんて素敵なの)
- def make_train_step(モデル、オプティマイザ、loss_fn):
- 定義train_step(x, y):
- #モデルをトレーニングモードに設定する
- モデル.train()
- # モデルにデータ(特徴)をフィードフォワードして予測値を取得する
- yhat = モデル(x)
- #予測目標と実際の目標に基づいて損失を計算する
- 損失 = loss_fn(y, yhat)
- # 逆伝播法を実行して勾配を求める
- 損失.後方()
- #計算された勾配でパラメータを更新する
- オプティマイザ.ステップ()
- #蓄積を防ぐために勾配をゼロに設定する
- オプティマイザ.zero_grad()
- リターン損失.item()
- train_stepを返す
- # トレーニング関数を呼び出す
- train_step = make_train_step(モデル、オプティマイザ、loss_fn)
- #各エポックの損失を保存する
- 損失 = []
- #エポックを100に設定する
- エポック = 100
- # トレーニング機能を実行する 各エポックのデータのバッチ
- # これが2つのforループがある理由です
- #エポックの外側のループ
- #トレーニングデータバッチを反復処理するための内部ループ
- 範囲(エポック)内のエポックの場合:
- #損失を蓄積する 単一エポック内のすべてのバッチ
- バッチロス = 0
- train_loaderのx_batch 、 y_batchの場合:
- x_batch = x_batch.to (デバイス)
- y_batch = y_batch.to (デバイス)
- 損失 = train_step(x_batch, y_batch)
- バッチ損失 = バッチ損失 + 損失
- # 63は 魔法の数字ではありません。トレーニングセット内のバッチの数です
- # サンプルは1000個あり、バッチサイズは 16 ( DataLoaderで定義)
- # 1000/16 = 63
- エポックロス = バッチロス / 63
- 損失.append(epoch_loss)
- #トレーニングが完了したらパラメータを出力します
- 印刷(model.state_dict())
- OrderedDict([( '0.weight' 、 テンソル([[13.0287]]、 デバイス= 'cuda:0' ))、 ( '0.bias' 、 テンソル([2.0096]、 デバイス= 'cuda:0' ))])
最後のステップとして、エポックごとのトレーニング損失をプロットして、モデルのパフォーマンスを観察できます。 図6に示すように。 仕上げる。 これまで学んだことをまとめてみましょう。 要約する線形回帰は、実装と解釈が最も簡単な機械学習モデルの 1 つと考えられています。 この記事では、Python の 3 つの異なる一般的なモジュールを使用して線形回帰を実装しました。 作成可能な他のモジュールもあります。 たとえば、Scikitlearn。 |