ओवरफिट और अंडरफिट

TensorFlow.org पर देखें Google Colab में चलाएं GitHub पर स्रोत देखें नोटबुक डाउनलोड करें

हमेशा की तरह, इस उदाहरण में कोड का उपयोग करेगा tf.keras एपीआई, जो आप TensorFlow में के बारे में अधिक सीख सकते हैं Keras गाइड

पिछले उदाहरण- के दोनों में वर्गीकृत करने पाठ और ईंधन दक्षता की भविष्यवाणी - हमने देखा कि सत्यापन के आंकड़ों पर हमारे मॉडल की सटीकता अवधियों के एक नंबर के लिए प्रशिक्षण के बाद चोटी, और फिर बहना या कम हो रही शुरू होगा।

दूसरे शब्दों में, हमारे मॉडल प्रशिक्षण आंकड़ों के overfit होगा। ओवरफिटिंग से निपटने का तरीका सीखना महत्वपूर्ण है। हालांकि यह अक्सर प्रशिक्षण सेट पर उच्च सटीकता प्राप्त करने के लिए संभव है, क्या हम वास्तव में चाहते हैं मॉडल है कि एक परीक्षण सेट (या डेटा वे पहले नहीं देखा है) करने के लिए अच्छी तरह से सामान्य विकसित करना है।

Overfitting के विपरीत underfitting है। अंडरफिटिंग तब होती है जब ट्रेन डेटा में सुधार की गुंजाइश होती है। यह कई कारणों से हो सकता है: यदि मॉडल पर्याप्त शक्तिशाली नहीं है, अति-नियमित है, या बस पर्याप्त रूप से प्रशिक्षित नहीं किया गया है। इसका मतलब है कि नेटवर्क ने प्रशिक्षण डेटा में प्रासंगिक पैटर्न नहीं सीखा है।

यदि आप बहुत लंबे समय तक प्रशिक्षण लेते हैं, तो मॉडल ओवरफिट होना शुरू कर देगा और प्रशिक्षण डेटा से पैटर्न सीखना शुरू कर देगा जो परीक्षण डेटा को सामान्यीकृत नहीं करता है। हमें संतुलन बनाने की जरूरत है। यह समझना कि उचित संख्या में युगों के लिए कैसे प्रशिक्षित किया जाए, जैसा कि हम नीचे देखेंगे, एक उपयोगी कौशल है।

ओवरफिटिंग को रोकने के लिए, सबसे अच्छा समाधान अधिक संपूर्ण प्रशिक्षण डेटा का उपयोग करना है। डेटासेट को इनपुट की पूरी श्रृंखला को कवर करना चाहिए जिसे मॉडल से संभालने की उम्मीद है। अतिरिक्त डेटा केवल तभी उपयोगी हो सकता है जब इसमें नए और दिलचस्प मामले शामिल हों।

अधिक संपूर्ण डेटा पर प्रशिक्षित एक मॉडल स्वाभाविक रूप से बेहतर सामान्यीकरण करेगा। जब यह अब संभव नहीं है, तो अगला सबसे अच्छा समाधान नियमितीकरण जैसी तकनीकों का उपयोग करना है। ये स्थान आपके मॉडल द्वारा संग्रहीत की जा सकने वाली जानकारी की मात्रा और प्रकार पर प्रतिबंध लगाते हैं। यदि कोई नेटवर्क केवल कुछ पैटर्नों को याद रखने का जोखिम उठा सकता है, तो अनुकूलन प्रक्रिया उसे सबसे प्रमुख पैटर्न पर ध्यान केंद्रित करने के लिए मजबूर करेगी, जिसमें अच्छी तरह से सामान्यीकरण की बेहतर संभावना है।

इस नोटबुक में, हम कई सामान्य नियमितीकरण तकनीकों का पता लगाएंगे, और उनका उपयोग वर्गीकरण मॉडल में सुधार के लिए करेंगे।

सेट अप

आरंभ करने से पहले, आवश्यक पैकेज आयात करें:

import tensorflow as tf

from tensorflow.keras import layers
from tensorflow.keras import regularizers

print(tf.__version__)
2.5.0
!pip install git+https://github.com/tensorflow/docs

import tensorflow_docs as tfdocs
import tensorflow_docs.modeling
import tensorflow_docs.plots
from  IPython import display
from matplotlib import pyplot as plt

import numpy as np

import pathlib
import shutil
import tempfile
logdir = pathlib.Path(tempfile.mkdtemp())/"tensorboard_logs"
shutil.rmtree(logdir, ignore_errors=True)

हिग्स डेटासेट

इस ट्यूटोरियल का लक्ष्य कण भौतिकी करना नहीं है, इसलिए डेटासेट के विवरण पर ध्यान न दें। इसमें ११,०००,००० उदाहरण हैं, प्रत्येक में २८ विशेषताएं हैं, और एक बाइनरी क्लास लेबल है।

gz = tf.keras.utils.get_file('HIGGS.csv.gz', 'http://mlphysics.ics.uci.edu/data/higgs/HIGGS.csv.gz')
Downloading data from http://mlphysics.ics.uci.edu/data/higgs/HIGGS.csv.gz
2816409600/2816407858 [==============================] - 148s 0us/step
FEATURES = 28

tf.data.experimental.CsvDataset वर्ग कोई मध्यवर्ती विसंपीड़न कदम के साथ एक gzip फ़ाइल से सीधे सीएसवी रिकॉर्ड को पढ़ने के लिए इस्तेमाल किया जा सकता।

ds = tf.data.experimental.CsvDataset(gz,[float(),]*(FEATURES+1), compression_type="GZIP")

वह सीएसवी पाठक वर्ग प्रत्येक रिकॉर्ड के लिए स्केलर की एक सूची देता है। निम्न फ़ंक्शन स्केलर्स की उस सूची को एक (फीचर_वेक्टर, लेबल) जोड़ी में दोबारा पैक करता है।

def pack_row(*row):
  label = row[0]
  features = tf.stack(row[1:],1)
  return features, label

डेटा के बड़े बैचों पर काम करते समय TensorFlow सबसे कुशल है।

तो repacking प्रत्येक पंक्ति को व्यक्तिगत रूप से एक नया बनाने के बजाय Dataset कि 10000-उदाहरण के बैच लेता है, पर लागू होता है pack_row प्रत्येक बैच के लिए समारोह, और फिर विभाजन बैचों व्यक्तिगत रिकॉर्ड में बैक अप:

packed_ds = ds.batch(10000).map(pack_row).unbatch()

इस नए से कुछ रिकॉर्ड पर एक नज़र डालें packed_ds

सुविधाएँ पूरी तरह से सामान्यीकृत नहीं हैं, लेकिन यह इस ट्यूटोरियल के लिए पर्याप्त है।

for features,label in packed_ds.batch(1000).take(1):
  print(features[0])
  plt.hist(features.numpy().flatten(), bins = 101)
tf.Tensor(
[ 0.8692932  -0.6350818   0.22569026  0.32747006 -0.6899932   0.75420225
 -0.24857314 -1.0920639   0.          1.3749921  -0.6536742   0.9303491
  1.1074361   1.1389043  -1.5781983  -1.0469854   0.          0.65792954
 -0.01045457 -0.04576717  3.1019614   1.35376     0.9795631   0.97807616
  0.92000484  0.72165745  0.98875093  0.87667835], shape=(28,), dtype=float32)

पीएनजी

इस ट्यूटोरियल को अपेक्षाकृत कम रखने के लिए सत्यापन के लिए पहले १००० नमूनों का उपयोग करें, और प्रशिक्षण के लिए अगले १०,००० का उपयोग करें:

N_VALIDATION = int(1e3)
N_TRAIN = int(1e4)
BUFFER_SIZE = int(1e4)
BATCH_SIZE = 500
STEPS_PER_EPOCH = N_TRAIN//BATCH_SIZE

Dataset.skip और Dataset.take तरीकों इस आसान बनाते हैं।

इसी समय, का उपयोग Dataset.cache सुनिश्चित करना है कि लोडर के लिए प्रत्येक युग पर फ़ाइल से डेटा को फिर से पढ़ा की जरूरत नहीं है विधि:

validate_ds = packed_ds.take(N_VALIDATION).cache()
train_ds = packed_ds.skip(N_VALIDATION).take(N_TRAIN).cache()
train_ds
<CacheDataset shapes: ((28,), ()), types: (tf.float32, tf.float32)>

ये डेटासेट अलग-अलग उदाहरण लौटाते हैं। का प्रयोग करें .batch प्रशिक्षण के लिए एक उचित आकार के बैच बनाने के लिए विधि। भी batching से पहले याद .shuffle और .repeat प्रशिक्षण सेट।

validate_ds = validate_ds.batch(BATCH_SIZE)
train_ds = train_ds.shuffle(BUFFER_SIZE).repeat().batch(BATCH_SIZE)

ओवरफिटिंग का प्रदर्शन करें

ओवरफिटिंग को रोकने का सबसे सरल तरीका एक छोटे मॉडल से शुरू करना है: एक मॉडल जिसमें सीखने योग्य मापदंडों की एक छोटी संख्या होती है (जो परतों की संख्या और प्रति परत इकाइयों की संख्या से निर्धारित होती है)। गहन शिक्षण में, मॉडल में सीखने योग्य मापदंडों की संख्या को अक्सर मॉडल की "क्षमता" के रूप में संदर्भित किया जाता है।

सहज रूप से, अधिक मापदंडों वाले मॉडल में अधिक "याद रखने की क्षमता" होगी और इसलिए प्रशिक्षण नमूनों और उनके लक्ष्यों के बीच एक आदर्श शब्दकोश जैसी मैपिंग को आसानी से सीखने में सक्षम होगा, बिना किसी सामान्यीकरण शक्ति के मानचित्रण, लेकिन भविष्यवाणियां करते समय यह बेकार होगा पहले के अनदेखे डेटा पर।

इसे हमेशा ध्यान में रखें: गहन शिक्षण मॉडल प्रशिक्षण डेटा को फिट करने में अच्छे होते हैं, लेकिन वास्तविक चुनौती सामान्यीकरण है, फिटिंग नहीं।

दूसरी ओर, यदि नेटवर्क के पास सीमित स्मृति संसाधन हैं, तो वह मानचित्रण को उतनी आसानी से नहीं सीख पाएगा। इसके नुकसान को कम करने के लिए, इसे संकुचित अभ्यावेदन सीखना होगा जिसमें अधिक भविष्य कहनेवाला शक्ति हो। उसी समय, यदि आप अपने मॉडल को बहुत छोटा बनाते हैं, तो प्रशिक्षण डेटा को फिट करने में कठिनाई होगी। "बहुत अधिक क्षमता" और "पर्याप्त क्षमता नहीं" के बीच एक संतुलन है।

दुर्भाग्य से, आपके मॉडल के सही आकार या वास्तुकला को निर्धारित करने के लिए कोई जादुई सूत्र नहीं है (परतों की संख्या, या प्रत्येक परत के लिए सही आकार के संदर्भ में)। आपको विभिन्न आर्किटेक्चर की एक श्रृंखला का प्रयोग करके प्रयोग करना होगा।

एक उपयुक्त मॉडल आकार खोजने के लिए, अपेक्षाकृत कुछ परतों और मापदंडों के साथ शुरू करना सबसे अच्छा है, फिर परतों के आकार को बढ़ाना या नई परतों को जोड़ना शुरू करें जब तक कि आप सत्यापन हानि पर कम रिटर्न नहीं देखते।

केवल का उपयोग कर एक साधारण मॉडल के साथ शुरू करो layers.Dense एक आधार रेखा के रूप में है, तो बड़ा संस्करण बनाने, और उनकी तुलना।

प्रशिक्षण प्रक्रिया

यदि आप प्रशिक्षण के दौरान सीखने की दर को धीरे-धीरे कम करते हैं तो कई मॉडल बेहतर तरीके से प्रशिक्षित होते हैं। का प्रयोग करें optimizers.schedules समय के साथ सीखने की दर को कम करने:

lr_schedule = tf.keras.optimizers.schedules.InverseTimeDecay(
  0.001,
  decay_steps=STEPS_PER_EPOCH*1000,
  decay_rate=1,
  staircase=False)

def get_optimizer():
  return tf.keras.optimizers.Adam(lr_schedule)

कोड सेट एक ऊपर schedules.InverseTimeDecay अतिश्योक्ति 1000 अवधियों को, 2000 अवधियों को और इतने पर पर 1/3 पर आधार दर का 1/2 के लिए सीखने की दर कम करने के लिए।

step = np.linspace(0,100000)
lr = lr_schedule(step)
plt.figure(figsize = (8,6))
plt.plot(step/STEPS_PER_EPOCH, lr)
plt.ylim([0,max(plt.ylim())])
plt.xlabel('Epoch')
_ = plt.ylabel('Learning Rate')

पीएनजी

इस ट्यूटोरियल में प्रत्येक मॉडल समान प्रशिक्षण कॉन्फ़िगरेशन का उपयोग करेगा। तो कॉलबैक की सूची से शुरू करके इन्हें पुन: प्रयोज्य तरीके से सेट करें।

इस ट्यूटोरियल के लिए प्रशिक्षण कई छोटे युगों तक चलता है। लॉगिंग कम करने के लिए शोर का उपयोग tfdocs.EpochDots जो केवल एक प्रिंट . प्रत्येक युग के लिए, और प्रत्येक 100 युगों में मेट्रिक्स का एक पूरा सेट।

अगला शामिल callbacks.EarlyStopping लंबी और अनावश्यक प्रशिक्षण बार से बचने के लिए। ध्यान दें कि यह कॉलबैक नजर रखने के लिए सेट कर दिया जाता है कि val_binary_crossentropy , नहीं val_loss । यह अंतर बाद में महत्वपूर्ण होगा।

उपयोग callbacks.TensorBoard प्रशिक्षण के लिए TensorBoard लॉग उत्पन्न करने के लिए।

def get_callbacks(name):
  return [
    tfdocs.modeling.EpochDots(),
    tf.keras.callbacks.EarlyStopping(monitor='val_binary_crossentropy', patience=200),
    tf.keras.callbacks.TensorBoard(logdir/name),
  ]

इसी तरह प्रत्येक मॉडल एक ही उपयोग करेगा Model.compile और Model.fit सेटिंग्स:

def compile_and_fit(model, name, optimizer=None, max_epochs=10000):
  if optimizer is None:
    optimizer = get_optimizer()
  model.compile(optimizer=optimizer,
                loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),
                metrics=[
                  tf.keras.losses.BinaryCrossentropy(
                      from_logits=True, name='binary_crossentropy'),
                  'accuracy'])

  model.summary()

  history = model.fit(
    train_ds,
    steps_per_epoch = STEPS_PER_EPOCH,
    epochs=max_epochs,
    validation_data=validate_ds,
    callbacks=get_callbacks(name),
    verbose=0)
  return history

छोटा मॉडल

एक मॉडल को प्रशिक्षित करके शुरू करें:

tiny_model = tf.keras.Sequential([
    layers.Dense(16, activation='elu', input_shape=(FEATURES,)),
    layers.Dense(1)
])
size_histories = {}
size_histories['Tiny'] = compile_and_fit(tiny_model, 'sizes/Tiny')
Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense (Dense)                (None, 16)                464       
_________________________________________________________________
dense_1 (Dense)              (None, 1)                 17        
=================================================================
Total params: 481
Trainable params: 481
Non-trainable params: 0
_________________________________________________________________
WARNING:tensorflow:Callback method `on_train_batch_begin` is slow compared to the batch time (batch time: 0.0031s vs `on_train_batch_begin` time: 0.0346s). Check your callbacks.
WARNING:tensorflow:Callback method `on_train_batch_end` is slow compared to the batch time (batch time: 0.0031s vs `on_train_batch_end` time: 0.0125s). Check your callbacks.

Epoch: 0, accuracy:0.5093,  binary_crossentropy:0.7681,  loss:0.7681,  val_accuracy:0.5000,  val_binary_crossentropy:0.7207,  val_loss:0.7207,  
....................................................................................................
Epoch: 100, accuracy:0.6058,  binary_crossentropy:0.6244,  loss:0.6244,  val_accuracy:0.5700,  val_binary_crossentropy:0.6322,  val_loss:0.6322,  
....................................................................................................
Epoch: 200, accuracy:0.6220,  binary_crossentropy:0.6124,  loss:0.6124,  val_accuracy:0.5990,  val_binary_crossentropy:0.6202,  val_loss:0.6202,  
....................................................................................................
Epoch: 300, accuracy:0.6388,  binary_crossentropy:0.6045,  loss:0.6045,  val_accuracy:0.6150,  val_binary_crossentropy:0.6114,  val_loss:0.6114,  
....................................................................................................
Epoch: 400, accuracy:0.6475,  binary_crossentropy:0.5976,  loss:0.5976,  val_accuracy:0.6270,  val_binary_crossentropy:0.6012,  val_loss:0.6012,  
....................................................................................................
Epoch: 500, accuracy:0.6579,  binary_crossentropy:0.5917,  loss:0.5917,  val_accuracy:0.6390,  val_binary_crossentropy:0.5929,  val_loss:0.5929,  
....................................................................................................
Epoch: 600, accuracy:0.6662,  binary_crossentropy:0.5878,  loss:0.5878,  val_accuracy:0.6410,  val_binary_crossentropy:0.5890,  val_loss:0.5890,  
....................................................................................................
Epoch: 700, accuracy:0.6664,  binary_crossentropy:0.5847,  loss:0.5847,  val_accuracy:0.6670,  val_binary_crossentropy:0.5865,  val_loss:0.5865,  
....................................................................................................
Epoch: 800, accuracy:0.6709,  binary_crossentropy:0.5822,  loss:0.5822,  val_accuracy:0.6460,  val_binary_crossentropy:0.5896,  val_loss:0.5896,  
....................................................................................................
Epoch: 900, accuracy:0.6772,  binary_crossentropy:0.5793,  loss:0.5793,  val_accuracy:0.6540,  val_binary_crossentropy:0.5880,  val_loss:0.5880,  
...................

अब जांचें कि मॉडल ने कैसे किया:

plotter = tfdocs.plots.HistoryPlotter(metric = 'binary_crossentropy', smoothing_std=10)
plotter.plot(size_histories)
plt.ylim([0.5, 0.7])
(0.5, 0.7)

पीएनजी

छोटा मॉडल

यह देखने के लिए कि क्या आप छोटे मॉडल के प्रदर्शन को मात दे सकते हैं, कुछ बड़े मॉडलों को उत्तरोत्तर प्रशिक्षित करें।

प्रत्येक 16 इकाइयों के साथ दो छिपी हुई परतों का प्रयास करें:

small_model = tf.keras.Sequential([
    # `input_shape` is only required here so that `.summary` works.
    layers.Dense(16, activation='elu', input_shape=(FEATURES,)),
    layers.Dense(16, activation='elu'),
    layers.Dense(1)
])
size_histories['Small'] = compile_and_fit(small_model, 'sizes/Small')
Model: "sequential_1"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense_2 (Dense)              (None, 16)                464       
_________________________________________________________________
dense_3 (Dense)              (None, 16)                272       
_________________________________________________________________
dense_4 (Dense)              (None, 1)                 17        
=================================================================
Total params: 753
Trainable params: 753
Non-trainable params: 0
_________________________________________________________________
WARNING:tensorflow:Callback method `on_train_batch_begin` is slow compared to the batch time (batch time: 0.0030s vs `on_train_batch_begin` time: 0.0258s). Check your callbacks.
WARNING:tensorflow:Callback method `on_train_batch_end` is slow compared to the batch time (batch time: 0.0030s vs `on_train_batch_end` time: 0.0176s). Check your callbacks.

Epoch: 0, accuracy:0.4757,  binary_crossentropy:0.7130,  loss:0.7130,  val_accuracy:0.4630,  val_binary_crossentropy:0.7012,  val_loss:0.7012,  
....................................................................................................
Epoch: 100, accuracy:0.6295,  binary_crossentropy:0.6092,  loss:0.6092,  val_accuracy:0.6120,  val_binary_crossentropy:0.6145,  val_loss:0.6145,  
....................................................................................................
Epoch: 200, accuracy:0.6575,  binary_crossentropy:0.5879,  loss:0.5879,  val_accuracy:0.6520,  val_binary_crossentropy:0.5976,  val_loss:0.5976,  
....................................................................................................
Epoch: 300, accuracy:0.6758,  binary_crossentropy:0.5774,  loss:0.5774,  val_accuracy:0.6610,  val_binary_crossentropy:0.5958,  val_loss:0.5958,  
....................................................................................................
Epoch: 400, accuracy:0.6830,  binary_crossentropy:0.5698,  loss:0.5698,  val_accuracy:0.6690,  val_binary_crossentropy:0.5949,  val_loss:0.5949,  
....................................................................................................
Epoch: 500, accuracy:0.6873,  binary_crossentropy:0.5650,  loss:0.5650,  val_accuracy:0.6720,  val_binary_crossentropy:0.5930,  val_loss:0.5930,  
....................................................................................................
Epoch: 600, accuracy:0.6923,  binary_crossentropy:0.5600,  loss:0.5600,  val_accuracy:0.6570,  val_binary_crossentropy:0.5946,  val_loss:0.5946,  
......................................................

मध्यम मॉडल

अब 64 इकाइयों के साथ 3 छिपी हुई परतों का प्रयास करें:

medium_model = tf.keras.Sequential([
    layers.Dense(64, activation='elu', input_shape=(FEATURES,)),
    layers.Dense(64, activation='elu'),
    layers.Dense(64, activation='elu'),
    layers.Dense(1)
])

और उसी डेटा का उपयोग करके मॉडल को प्रशिक्षित करें:

size_histories['Medium']  = compile_and_fit(medium_model, "sizes/Medium")
Model: "sequential_2"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense_5 (Dense)              (None, 64)                1856      
_________________________________________________________________
dense_6 (Dense)              (None, 64)                4160      
_________________________________________________________________
dense_7 (Dense)              (None, 64)                4160      
_________________________________________________________________
dense_8 (Dense)              (None, 1)                 65        
=================================================================
Total params: 10,241
Trainable params: 10,241
Non-trainable params: 0
_________________________________________________________________
WARNING:tensorflow:Callback method `on_train_batch_begin` is slow compared to the batch time (batch time: 0.0033s vs `on_train_batch_begin` time: 0.0251s). Check your callbacks.
WARNING:tensorflow:Callback method `on_train_batch_end` is slow compared to the batch time (batch time: 0.0033s vs `on_train_batch_end` time: 0.0189s). Check your callbacks.

Epoch: 0, accuracy:0.5026,  binary_crossentropy:0.6944,  loss:0.6944,  val_accuracy:0.4740,  val_binary_crossentropy:0.6830,  val_loss:0.6830,  
....................................................................................................
Epoch: 100, accuracy:0.7164,  binary_crossentropy:0.5242,  loss:0.5242,  val_accuracy:0.6490,  val_binary_crossentropy:0.6316,  val_loss:0.6316,  
....................................................................................................
Epoch: 200, accuracy:0.7919,  binary_crossentropy:0.4224,  loss:0.4224,  val_accuracy:0.6480,  val_binary_crossentropy:0.7022,  val_loss:0.7022,  
.......................................

बड़ा मॉडल

एक अभ्यास के रूप में, आप एक और भी बड़ा मॉडल बना सकते हैं, और देख सकते हैं कि यह कितनी जल्दी ओवरफिट होने लगता है। इसके बाद, आइए इस बेंचमार्क में एक ऐसा नेटवर्क जोड़ें जिसमें बहुत अधिक क्षमता हो, समस्या से कहीं अधिक वारंट होगा:

large_model = tf.keras.Sequential([
    layers.Dense(512, activation='elu', input_shape=(FEATURES,)),
    layers.Dense(512, activation='elu'),
    layers.Dense(512, activation='elu'),
    layers.Dense(512, activation='elu'),
    layers.Dense(1)
])

और, फिर से, उसी डेटा का उपयोग करके मॉडल को प्रशिक्षित करें:

size_histories['large'] = compile_and_fit(large_model, "sizes/large")
Model: "sequential_3"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense_9 (Dense)              (None, 512)               14848     
_________________________________________________________________
dense_10 (Dense)             (None, 512)               262656    
_________________________________________________________________
dense_11 (Dense)             (None, 512)               262656    
_________________________________________________________________
dense_12 (Dense)             (None, 512)               262656    
_________________________________________________________________
dense_13 (Dense)             (None, 1)                 513       
=================================================================
Total params: 803,329
Trainable params: 803,329
Non-trainable params: 0
_________________________________________________________________
WARNING:tensorflow:Callback method `on_train_batch_begin` is slow compared to the batch time (batch time: 0.0033s vs `on_train_batch_begin` time: 0.0237s). Check your callbacks.
WARNING:tensorflow:Callback method `on_train_batch_end` is slow compared to the batch time (batch time: 0.0033s vs `on_train_batch_end` time: 0.0182s). Check your callbacks.

Epoch: 0, accuracy:0.5116,  binary_crossentropy:0.7680,  loss:0.7680,  val_accuracy:0.5440,  val_binary_crossentropy:0.6753,  val_loss:0.6753,  
....................................................................................................
Epoch: 100, accuracy:1.0000,  binary_crossentropy:0.0021,  loss:0.0021,  val_accuracy:0.6610,  val_binary_crossentropy:1.8058,  val_loss:1.8058,  
....................................................................................................
Epoch: 200, accuracy:1.0000,  binary_crossentropy:0.0001,  loss:0.0001,  val_accuracy:0.6500,  val_binary_crossentropy:2.4712,  val_loss:2.4712,  
.........................

प्रशिक्षण और सत्यापन हानियों को प्लॉट करें

ठोस रेखाएँ प्रशिक्षण हानि दिखाती हैं, और धराशायी रेखाएँ सत्यापन हानि दिखाती हैं (याद रखें: कम सत्यापन हानि एक बेहतर मॉडल को इंगित करती है)।

एक बड़े मॉडल का निर्माण करते समय यह अधिक शक्ति देता है, अगर इस शक्ति को किसी भी तरह से बाधित नहीं किया जाता है तो यह आसानी से प्रशिक्षण सेट से अधिक हो सकता है।

इस उदाहरण में, आम तौर पर, केवल "Tiny" मॉडल पूरी तरह overfitting से बचने के लिए प्रबंधन करता है, और बड़े मॉडलों में से प्रत्येक के डेटा और अधिक तेजी से overfit। इस के लिए इतनी गंभीर हो जाता है "large" मॉडल है कि तुम सच देख क्या हो रहा है एक लॉग पैमाने पर करने के लिए साजिश स्विच करना होगा।

यह तब स्पष्ट होता है जब आप सत्यापन मेट्रिक्स को प्रशिक्षण मेट्रिक्स से प्लॉट और तुलना करते हैं।

  • एक छोटा सा अंतर होना सामान्य है।
  • यदि दोनों मेट्रिक्स एक ही दिशा में आगे बढ़ रहे हैं, तो सब कुछ ठीक है।
  • यदि प्रशिक्षण मीट्रिक में सुधार जारी रहने पर सत्यापन मीट्रिक स्थिर होना शुरू हो जाता है, तो आप संभवतः ओवरफिटिंग के करीब हैं।
  • यदि सत्यापन मीट्रिक गलत दिशा में जा रहा है, तो मॉडल स्पष्ट रूप से ओवरफिटिंग है।
plotter.plot(size_histories)
a = plt.xscale('log')
plt.xlim([5, max(plt.xlim())])
plt.ylim([0.5, 0.7])
plt.xlabel("Epochs [Log Scale]")
Text(0.5, 0, 'Epochs [Log Scale]')

पीएनजी

टेंसरबोर्ड में देखें

इन सभी मॉडलों ने प्रशिक्षण के दौरान TensorBoard लॉग लिखे।

एक नोटबुक के अंदर एक एम्बेडेड TensorBoard व्यूअर खोलें:


# Load the TensorBoard notebook extension
%load_ext tensorboard

# Open an embedded TensorBoard viewer
%tensorboard --logdir {logdir}/sizes

आप देख सकते हैं पिछले एक रन के परिणामों पर इस नोटबुक की TensorBoard.dev

TensorBoard.dev सभी के साथ ML प्रयोगों को होस्ट करने, ट्रैक करने और साझा करने का एक प्रबंधित अनुभव है।

यह भी में शामिल है एक <iframe> सुविधा के लिए:

display.IFrame(
    src="https://tensorboard.dev/experiment/vW7jmmF9TmKmy3rbheMQpw/#scalars&_smoothingWeight=0.97",
    width="100%", height="800px")

आप साझा करना चाहते हैं TensorBoard आप के लिए लॉग अपलोड कर सकते हैं परिणाम TensorBoard.dev एक कोड-सेल में निम्नलिखित को कॉपी करके।

tensorboard dev upload --logdir  {logdir}/sizes

ओवरफिटिंग को रोकने के लिए रणनीतियाँ

इस धारा के सामग्री में से पहले से प्रशिक्षण लॉग कॉपी "Tiny" ऊपर मॉडल, तुलना के लिए एक आधार रेखा के रूप में उपयोग करने के लिए।

shutil.rmtree(logdir/'regularizers/Tiny', ignore_errors=True)
shutil.copytree(logdir/'sizes/Tiny', logdir/'regularizers/Tiny')
PosixPath('/tmp/tmp_tm13yei/tensorboard_logs/regularizers/Tiny')
regularizer_histories = {}
regularizer_histories['Tiny'] = size_histories['Tiny']

वजन नियमितीकरण जोड़ें

आप ओकम के रेजर सिद्धांत से परिचित हो सकते हैं: किसी चीज़ के लिए दो स्पष्टीकरण दिए गए हैं, स्पष्टीकरण के सही होने की सबसे अधिक संभावना "सरल" है, जो कम से कम अनुमान लगाता है। यह तंत्रिका नेटवर्क द्वारा सीखे गए मॉडल पर भी लागू होता है: कुछ प्रशिक्षण डेटा और एक नेटवर्क आर्किटेक्चर को देखते हुए, वज़न मान (एकाधिक मॉडल) के कई सेट होते हैं जो डेटा की व्याख्या कर सकते हैं, और सरल मॉडल जटिल लोगों की तुलना में अधिक होने की संभावना कम होती है।

इस संदर्भ में एक "सरल मॉडल" एक ऐसा मॉडल है जहां पैरामीटर मानों के वितरण में कम एन्ट्रॉपी होती है (या कम पैरामीटर वाला एक मॉडल, जैसा कि हमने ऊपर अनुभाग में देखा था)। इस प्रकार ओवरफिटिंग को कम करने का एक सामान्य तरीका है कि नेटवर्क के वजन को केवल छोटे मान लेने के लिए मजबूर करके नेटवर्क की जटिलता पर प्रतिबंध लगाया जाए, जिससे वजन मूल्यों का वितरण अधिक "नियमित" हो जाता है। इसे "वेट रेगुलराइजेशन" कहा जाता है, और यह नेटवर्क के लॉस फंक्शन में बड़े वजन से जुड़ी लागत को जोड़कर किया जाता है। यह लागत दो स्वादों में आती है:

  • एल 1 नियमितीकरण , (यानी क्या वजन के "एल 1 के आदर्श" कहा जाता है करने के लिए) जहां लागत जोड़ा वजन गुणांकों के निरपेक्ष मूल्य के लिए आनुपातिक है।

  • एल 2 नियमितीकरण , (यानी क्या वर्ग वजन के "एल 2 आदर्श" कहा जाता है करने के लिए) जहां लागत जोड़ा वजन गुणांक के मूल्य के वर्ग के समानुपाती होता है। L2 नियमितीकरण को तंत्रिका नेटवर्क के संदर्भ में वजन क्षय भी कहा जाता है। अलग-अलग नाम को भ्रमित न होने दें: वजन में गिरावट गणितीय रूप से L2 नियमितीकरण के समान ही है।

L1 नियमितीकरण एक विरल मॉडल को प्रोत्साहित करने के लिए वजन को बिल्कुल शून्य की ओर धकेलता है। L2 नियमितीकरण वजन मापदंडों को विरल किए बिना दंडित करेगा क्योंकि छोटे वजन के लिए जुर्माना शून्य हो जाता है-एक कारण है कि L2 अधिक सामान्य है।

में tf.keras , वजन नियमितीकरण कीवर्ड तर्कों के रूप परतों को वजन regularizer उदाहरणों पास करके जोड़ा जाता है। आइए अब L2 वजन नियमितीकरण जोड़ें।

l2_model = tf.keras.Sequential([
    layers.Dense(512, activation='elu',
                 kernel_regularizer=regularizers.l2(0.001),
                 input_shape=(FEATURES,)),
    layers.Dense(512, activation='elu',
                 kernel_regularizer=regularizers.l2(0.001)),
    layers.Dense(512, activation='elu',
                 kernel_regularizer=regularizers.l2(0.001)),
    layers.Dense(512, activation='elu',
                 kernel_regularizer=regularizers.l2(0.001)),
    layers.Dense(1)
])

regularizer_histories['l2'] = compile_and_fit(l2_model, "regularizers/l2")
Model: "sequential_4"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense_14 (Dense)             (None, 512)               14848     
_________________________________________________________________
dense_15 (Dense)             (None, 512)               262656    
_________________________________________________________________
dense_16 (Dense)             (None, 512)               262656    
_________________________________________________________________
dense_17 (Dense)             (None, 512)               262656    
_________________________________________________________________
dense_18 (Dense)             (None, 1)                 513       
=================================================================
Total params: 803,329
Trainable params: 803,329
Non-trainable params: 0
_________________________________________________________________
WARNING:tensorflow:Callback method `on_train_batch_begin` is slow compared to the batch time (batch time: 0.0038s vs `on_train_batch_begin` time: 0.0242s). Check your callbacks.
WARNING:tensorflow:Callback method `on_train_batch_end` is slow compared to the batch time (batch time: 0.0038s vs `on_train_batch_end` time: 0.0199s). Check your callbacks.

Epoch: 0, accuracy:0.5059,  binary_crossentropy:0.7720,  loss:2.2831,  val_accuracy:0.4620,  val_binary_crossentropy:0.7035,  val_loss:2.1321,  
....................................................................................................
Epoch: 100, accuracy:0.6490,  binary_crossentropy:0.5996,  loss:0.6228,  val_accuracy:0.6270,  val_binary_crossentropy:0.5898,  val_loss:0.6131,  
....................................................................................................
Epoch: 200, accuracy:0.6737,  binary_crossentropy:0.5826,  loss:0.6061,  val_accuracy:0.6680,  val_binary_crossentropy:0.5857,  val_loss:0.6096,  
....................................................................................................
Epoch: 300, accuracy:0.6842,  binary_crossentropy:0.5748,  loss:0.5993,  val_accuracy:0.6840,  val_binary_crossentropy:0.5754,  val_loss:0.5998,  
....................................................................................................
Epoch: 400, accuracy:0.6934,  binary_crossentropy:0.5620,  loss:0.5862,  val_accuracy:0.6690,  val_binary_crossentropy:0.5825,  val_loss:0.6066,  
.....................................................................................

l2(0.001) का मतलब है कि परत के वजन मैट्रिक्स में हर गुणांक जोड़ देगा 0.001 * weight_coefficient_value**2 नेटवर्क का कुल नुकसान के लिए।

यही कारण है कि हम निगरानी कर रहे है binary_crossentropy सीधे। क्योंकि इसमें यह नियमितीकरण घटक मिश्रित नहीं है।

तो, कि एक ही "Large" एक साथ मॉडल L2 नियमितीकरण की सजा प्रदर्शन काफी बेहतर:

plotter.plot(regularizer_histories)
plt.ylim([0.5, 0.7])
(0.5, 0.7)

पीएनजी

आप देख सकते हैं, "L2" को नियमित मॉडल अब और अधिक के साथ प्रतिस्पर्धी है "Tiny" मॉडल। यह "L2" मॉडल भी ज्यादा से ज्यादा overfitting के लिए प्रतिरोधी है "Large" मॉडल मापदंडों के एक ही नंबर होने के बावजूद उस पर आधारित था।

और जानकारी

इस तरह के नियमितीकरण के बारे में दो महत्वपूर्ण बातें ध्यान देने योग्य हैं।

पहली: अगर आप अपने स्वयं के प्रशिक्षण पाश लिख रहे हैं, तो आप अपने नियमितीकरण नुकसान के लिए मॉडल पूछ लें की जरूरत है।

result = l2_model(features)
regularization_loss=tf.add_n(l2_model.losses)

दूसरा: इस कार्यान्वयन मॉडल की हानि करने के लिए वजन दंड जोड़ने, और फिर उस के बाद एक मानक अनुकूलन प्रक्रिया लागू किया जाता है।

एक दूसरा दृष्टिकोण है कि इसके बजाय केवल कच्चे नुकसान पर ऑप्टिमाइज़र चलाता है, और फिर गणना किए गए चरण को लागू करते समय ऑप्टिमाइज़र कुछ वजन क्षय भी लागू करता है। यह "decoupled भार क्षय" की तरह optimizers में देखा जाता है optimizers.FTRL और optimizers.AdamW

ड्रॉपआउट जोड़ें

ड्रॉपआउट तंत्रिका नेटवर्क के लिए सबसे प्रभावी और सबसे अधिक इस्तेमाल की जाने वाली नियमितीकरण तकनीकों में से एक है, जिसे टोरंटो विश्वविद्यालय में हिंटन और उनके छात्रों द्वारा विकसित किया गया है।

ड्रॉपआउट के लिए सहज व्याख्या यह है कि क्योंकि नेटवर्क में अलग-अलग नोड्स दूसरों के आउटपुट पर भरोसा नहीं कर सकते हैं, इसलिए प्रत्येक नोड को उन विशेषताओं को आउटपुट करना चाहिए जो अपने आप में उपयोगी हैं।

ड्रॉपआउट, एक परत पर लागू होता है, जिसमें प्रशिक्षण के दौरान बेतरतीब ढंग से "ड्रॉपिंग आउट" (यानी शून्य पर सेट) परत की कई आउटपुट विशेषताएं होती हैं। मान लें कि दी गई परत सामान्य रूप से प्रशिक्षण के दौरान दिए गए इनपुट नमूने के लिए एक वेक्टर [0.2, 0.5, 1.3, 0.8, 1.1] लौटाती है; ड्रॉपआउट लागू करने के बाद, इस वेक्टर में यादृच्छिक रूप से वितरित कुछ शून्य प्रविष्टियां होंगी, उदाहरण के लिए [0, 0.5, 1.3, 0, 1.1]।

"छोड़ने की दर" उन सुविधाओं का अंश है जिन्हें शून्य किया जा रहा है; यह आमतौर पर 0.2 और 0.5 के बीच सेट होता है। परीक्षण के समय, किसी भी इकाई को बाहर नहीं किया जाता है, और इसके बजाय परत के आउटपुट मूल्यों को ड्रॉपआउट दर के बराबर एक कारक द्वारा घटाया जाता है, ताकि इस तथ्य के लिए संतुलन बनाया जा सके कि प्रशिक्षण के समय की तुलना में अधिक इकाइयाँ सक्रिय हैं।

में tf.keras आप छोड़ने वालों की परत है, जो सही से पहले परत के उत्पादन के लिए लागू किया जाता है के माध्यम से नेटवर्क में छोड़ने वालों लागू कर सकते हैं।

आइए अपने नेटवर्क में दो ड्रॉपआउट परतें जोड़ें, यह देखने के लिए कि वे ओवरफिटिंग को कम करने में कितना अच्छा करते हैं:

dropout_model = tf.keras.Sequential([
    layers.Dense(512, activation='elu', input_shape=(FEATURES,)),
    layers.Dropout(0.5),
    layers.Dense(512, activation='elu'),
    layers.Dropout(0.5),
    layers.Dense(512, activation='elu'),
    layers.Dropout(0.5),
    layers.Dense(512, activation='elu'),
    layers.Dropout(0.5),
    layers.Dense(1)
])

regularizer_histories['dropout'] = compile_and_fit(dropout_model, "regularizers/dropout")
Model: "sequential_5"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense_19 (Dense)             (None, 512)               14848     
_________________________________________________________________
dropout (Dropout)            (None, 512)               0         
_________________________________________________________________
dense_20 (Dense)             (None, 512)               262656    
_________________________________________________________________
dropout_1 (Dropout)          (None, 512)               0         
_________________________________________________________________
dense_21 (Dense)             (None, 512)               262656    
_________________________________________________________________
dropout_2 (Dropout)          (None, 512)               0         
_________________________________________________________________
dense_22 (Dense)             (None, 512)               262656    
_________________________________________________________________
dropout_3 (Dropout)          (None, 512)               0         
_________________________________________________________________
dense_23 (Dense)             (None, 1)                 513       
=================================================================
Total params: 803,329
Trainable params: 803,329
Non-trainable params: 0
_________________________________________________________________
WARNING:tensorflow:Callback method `on_train_batch_begin` is slow compared to the batch time (batch time: 0.0040s vs `on_train_batch_begin` time: 0.0241s). Check your callbacks.
WARNING:tensorflow:Callback method `on_train_batch_end` is slow compared to the batch time (batch time: 0.0040s vs `on_train_batch_end` time: 0.0208s). Check your callbacks.

Epoch: 0, accuracy:0.5060,  binary_crossentropy:0.7949,  loss:0.7949,  val_accuracy:0.5140,  val_binary_crossentropy:0.6710,  val_loss:0.6710,  
....................................................................................................
Epoch: 100, accuracy:0.6623,  binary_crossentropy:0.5950,  loss:0.5950,  val_accuracy:0.6840,  val_binary_crossentropy:0.5723,  val_loss:0.5723,  
....................................................................................................
Epoch: 200, accuracy:0.6897,  binary_crossentropy:0.5559,  loss:0.5559,  val_accuracy:0.6800,  val_binary_crossentropy:0.5971,  val_loss:0.5971,  
....................................................................................................
Epoch: 300, accuracy:0.7202,  binary_crossentropy:0.5114,  loss:0.5114,  val_accuracy:0.6800,  val_binary_crossentropy:0.5984,  val_loss:0.5984,  
...............................................
plotter.plot(regularizer_histories)
plt.ylim([0.5, 0.7])
(0.5, 0.7)

पीएनजी

यह इन नियमितीकरण के दोनों के व्यवहार में सुधार दृष्टिकोण है कि इस साजिश से स्पष्ट है "Large" मॉडल। लेकिन यह अभी भी भी हरा नहीं करता है "Tiny" आधारभूत।

अगला उन दोनों को एक साथ आज़माएं, और देखें कि क्या इससे बेहतर होता है।

संयुक्त L2 + ड्रॉपआउट

combined_model = tf.keras.Sequential([
    layers.Dense(512, kernel_regularizer=regularizers.l2(0.0001),
                 activation='elu', input_shape=(FEATURES,)),
    layers.Dropout(0.5),
    layers.Dense(512, kernel_regularizer=regularizers.l2(0.0001),
                 activation='elu'),
    layers.Dropout(0.5),
    layers.Dense(512, kernel_regularizer=regularizers.l2(0.0001),
                 activation='elu'),
    layers.Dropout(0.5),
    layers.Dense(512, kernel_regularizer=regularizers.l2(0.0001),
                 activation='elu'),
    layers.Dropout(0.5),
    layers.Dense(1)
])

regularizer_histories['combined'] = compile_and_fit(combined_model, "regularizers/combined")
Model: "sequential_6"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense_24 (Dense)             (None, 512)               14848     
_________________________________________________________________
dropout_4 (Dropout)          (None, 512)               0         
_________________________________________________________________
dense_25 (Dense)             (None, 512)               262656    
_________________________________________________________________
dropout_5 (Dropout)          (None, 512)               0         
_________________________________________________________________
dense_26 (Dense)             (None, 512)               262656    
_________________________________________________________________
dropout_6 (Dropout)          (None, 512)               0         
_________________________________________________________________
dense_27 (Dense)             (None, 512)               262656    
_________________________________________________________________
dropout_7 (Dropout)          (None, 512)               0         
_________________________________________________________________
dense_28 (Dense)             (None, 1)                 513       
=================================================================
Total params: 803,329
Trainable params: 803,329
Non-trainable params: 0
_________________________________________________________________
WARNING:tensorflow:Callback method `on_train_batch_begin` is slow compared to the batch time (batch time: 0.0040s vs `on_train_batch_begin` time: 0.0245s). Check your callbacks.
WARNING:tensorflow:Callback method `on_train_batch_end` is slow compared to the batch time (batch time: 0.0040s vs `on_train_batch_end` time: 0.0214s). Check your callbacks.

Epoch: 0, accuracy:0.5056,  binary_crossentropy:0.8201,  loss:0.9784,  val_accuracy:0.5130,  val_binary_crossentropy:0.6691,  val_loss:0.8269,  
....................................................................................................
Epoch: 100, accuracy:0.6409,  binary_crossentropy:0.6052,  loss:0.6362,  val_accuracy:0.6670,  val_binary_crossentropy:0.5831,  val_loss:0.6139,  
....................................................................................................
Epoch: 200, accuracy:0.6673,  binary_crossentropy:0.5893,  loss:0.6147,  val_accuracy:0.6880,  val_binary_crossentropy:0.5666,  val_loss:0.5920,  
....................................................................................................
Epoch: 300, accuracy:0.6724,  binary_crossentropy:0.5814,  loss:0.6092,  val_accuracy:0.6850,  val_binary_crossentropy:0.5638,  val_loss:0.5916,  
....................................................................................................
Epoch: 400, accuracy:0.6791,  binary_crossentropy:0.5764,  loss:0.6061,  val_accuracy:0.6960,  val_binary_crossentropy:0.5536,  val_loss:0.5832,  
....................................................................................................
Epoch: 500, accuracy:0.6750,  binary_crossentropy:0.5722,  loss:0.6037,  val_accuracy:0.6760,  val_binary_crossentropy:0.5583,  val_loss:0.5899,  
....................................................................................................
Epoch: 600, accuracy:0.6818,  binary_crossentropy:0.5651,  loss:0.5989,  val_accuracy:0.6940,  val_binary_crossentropy:0.5422,  val_loss:0.5761,  
....................................................................................................
Epoch: 700, accuracy:0.6882,  binary_crossentropy:0.5594,  loss:0.5943,  val_accuracy:0.6880,  val_binary_crossentropy:0.5436,  val_loss:0.5786,  
....................................................................................................
Epoch: 800, accuracy:0.6886,  binary_crossentropy:0.5567,  loss:0.5927,  val_accuracy:0.6960,  val_binary_crossentropy:0.5446,  val_loss:0.5807,  
....................................................................................................
Epoch: 900, accuracy:0.6994,  binary_crossentropy:0.5535,  loss:0.5907,  val_accuracy:0.6900,  val_binary_crossentropy:0.5463,  val_loss:0.5835,  
................................................
plotter.plot(regularizer_histories)
plt.ylim([0.5, 0.7])
(0.5, 0.7)

पीएनजी

साथ यह मॉडल "Combined" नियमितीकरण स्पष्ट रूप से सबसे अच्छा एक अब तक है।

टेंसरबोर्ड में देखें

इन मॉडलों ने TensorBoard लॉग भी रिकॉर्ड किए।

एक नोटबुक के अंदर एक एम्बेडेड टेंसरबोर्ड व्यूअर खोलने के लिए, निम्नलिखित को एक कोड-सेल में कॉपी करें:

%tensorboard --logdir {logdir}/regularizers

आप देख सकते हैं पिछले एक रन के परिणामों पर इस नोटबुक की TensorDoard.dev

यह भी में शामिल है एक <iframe> सुविधा के लिए:

display.IFrame(
    src="https://tensorboard.dev/experiment/fGInKDo8TXes1z7HQku9mw/#scalars&_smoothingWeight=0.97",
    width = "100%",
    height="800px")

इसके साथ अपलोड किया गया था:

tensorboard dev upload --logdir  {logdir}/regularizers

निष्कर्ष

संक्षेप में: तंत्रिका नेटवर्क में ओवरफिटिंग को रोकने के सबसे सामान्य तरीके यहां दिए गए हैं:

  • अधिक प्रशिक्षण डेटा प्राप्त करें।
  • नेटवर्क की क्षमता को कम करें।
  • वजन नियमितीकरण जोड़ें।
  • ड्रॉपआउट जोड़ें।

इस गाइड में शामिल नहीं किए गए दो महत्वपूर्ण दृष्टिकोण हैं:

  • डेटा-वृद्धि
  • बैच सामान्यीकरण

याद रखें कि प्रत्येक विधि अपने आप में मदद कर सकती है, लेकिन अक्सर उनका संयोजन और भी अधिक प्रभावी हो सकता है।

# MIT License
#
# Copyright (c) 2017 François Chollet
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.