.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
@d2l.add_to_class(d2l.Classifier) #@save
def loss(self, Y_hat, Y, averaged=True):
Y_hat = d2l.reshape(Y_hat, (-1, Y_hat.shape[-1]))
Y = d2l.reshape(Y, (-1,))
if tab.selected('mxnet'):
fn = gluon.loss.SoftmaxCrossEntropyLoss()
l = fn(Y_hat, Y)
return l.mean() if averaged else l
if tab.selected('pytorch'):
return F.cross_entropy(
Y_hat, Y, reduction='mean' if averaged else 'none')
if tab.selected('tensorflow'):
fn = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)
return fn(Y, Y_hat)
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
@d2l.add_to_class(d2l.Classifier) #@save
def loss(self, Y_hat, Y, averaged=True):
Y_hat = d2l.reshape(Y_hat, (-1, Y_hat.shape[-1]))
Y = d2l.reshape(Y, (-1,))
if tab.selected('mxnet'):
fn = gluon.loss.SoftmaxCrossEntropyLoss()
l = fn(Y_hat, Y)
return l.mean() if averaged else l
if tab.selected('pytorch'):
return F.cross_entropy(
Y_hat, Y, reduction='mean' if averaged else 'none')
if tab.selected('tensorflow'):
fn = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)
return fn(Y, Y_hat)
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
@d2l.add_to_class(d2l.Classifier) #@save
@partial(jax.jit, static_argnums=(0, 5))
def loss(self, params, X, Y, state, averaged=True):
# To be used later (e.g., for batch norm)
Y_hat = state.apply_fn({'params': params}, *X,
mutable=False, rngs=None)
Y_hat = d2l.reshape(Y_hat, (-1, Y_hat.shape[-1]))
Y = d2l.reshape(Y, (-1,))
fn = optax.softmax_cross_entropy_with_integer_labels
# The returned empty dictionary is a placeholder for auxiliary data,
# which will be used later (e.g., for batch norm)
return (fn(Y_hat, Y).mean(), {}) if averaged else (fn(Y_hat, Y), {})
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
@d2l.add_to_class(d2l.Classifier) #@save
def loss(self, Y_hat, Y, averaged=True):
Y_hat = d2l.reshape(Y_hat, (-1, Y_hat.shape[-1]))
Y = d2l.reshape(Y, (-1,))
if tab.selected('mxnet'):
fn = gluon.loss.SoftmaxCrossEntropyLoss()
l = fn(Y_hat, Y)
return l.mean() if averaged else l
if tab.selected('pytorch'):
return F.cross_entropy(
Y_hat, Y, reduction='mean' if averaged else 'none')
if tab.selected('tensorflow'):
fn = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)
return fn(Y, Y_hat)
.. raw:: html
.. raw:: html
学習
----
次にモデルを学習する。Fashion-MNIST画像を、784次元の特徴ベクトルに平坦化して用いる。
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
data = d2l.FashionMNIST(batch_size=256)
model = SoftmaxRegression(num_outputs=10, lr=0.1)
trainer = d2l.Trainer(max_epochs=10)
trainer.fit(model, data)
.. figure:: output_softmax-regression-concise_95a25b_46_0.svg
これまでと同様に、このアルゴリズムは かなり正確な解に収束する。
今回は以前よりも少ないコード行数でそれが実現できる。
まとめ
------
高水準APIは、数値安定性のような潜在的に危険な側面を
利用者からうまく隠してくれるので非常に便利である。さらに、
ごく少ないコード行数で簡潔にモデルを設計できるようにしてくれる。これは
祝福であると同時に呪いでもある。明らかな利点は、
統計の授業を一度も受けたことのないエンジニアでさえも
非常に利用しやすくなることです(実際、彼らはこの本の想定読者の一部です)。
しかし、鋭い部分を隠すことには代償もある。自分で新しく異なる構成要素を追加しようという
意欲が削がれやすいのである。というのも、それを行うための身体的な記憶が
ほとんど身につかないからである。さらに、フレームワークの保護用の
緩衝材がすべての例外ケースを完全には覆いきれないときに、
それを\ *修正*\ することも難しくなる。これもやはり、
慣れの不足によるものである。
そのため、以下に続く多くの実装については、
素朴な版と洗練された版の両方を確認することを強く勧める。理解しやすさを重視しているが、
それでも実装は通常かなり高性能です(畳み込みはここでの大きな例外です)。
私たちの意図は、あなたがフレームワークでは得られない新しいものを発明したときに、
それを土台として発展させられるようにすることである。
演習
----
1. 深層学習では、FP64倍精度(非常にまれに使われる)、
FP32単精度、BFLOAT16(圧縮表現に適している)、FP16(非常に不安定)、
TF32(NVIDIAの新しい形式)、INT8など、多くの異なる数値形式が使われる。
数値アンダーフローやオーバーフローを起こさない指数関数の引数の最小値と最大値を求めなさい。
2. INT8は、\ :math:`1` から :math:`255`
までの非ゼロ数からなる非常に制約の厳しい形式である。より多くのビットを使わずに、その動的範囲をどのように拡張できるか?通常の乗算と加算はそのまま使えますか?
3. 学習のエポック数を増やしなさい。しばらくすると検証精度が下がるのはなぜだろうか?それをどう修正できるか?
4. 学習率を増やすと何が起こりますか?いくつかの学習率について損失曲線を比較しなさい。どれがよりうまく機能するか?それはいつですか?