সাহায্য Kaggle উপর TensorFlow সঙ্গে গ্রেট বেরিয়ার রিফ রক্ষা চ্যালেঞ্জ যোগদান

মৌলিক শ্রেণিবিন্যাস: পোশাকের চিত্রগুলিকে শ্রেণিবদ্ধ করুন

TensorFlow.org এ দেখুন Google Colab-এ চালান GitHub-এ উৎস দেখুন নোটবুক ডাউনলোড করুন

এই নির্দেশিকাটি স্নিকার এবং শার্টের মতো পোশাকের চিত্রগুলিকে শ্রেণিবদ্ধ করতে একটি নিউরাল নেটওয়ার্ক মডেলকে প্রশিক্ষণ দেয়৷ আপনি যদি সমস্ত বিবরণ বুঝতে না পারেন তবে ঠিক আছে; এটি একটি সম্পূর্ণ টেনসরফ্লো প্রোগ্রামের একটি দ্রুতগতির ওভারভিউ যা আপনি যাওয়ার সাথে সাথে ব্যাখ্যা করা হয়েছে।

এই নির্দেশিকাটি ব্যবহার tf.keras , TensorFlow মধ্যে তৈরি করুন এবং ট্রেন মডেলের একটি উচ্চ পর্যায়ের API- টি।

# TensorFlow and tf.keras
import tensorflow as tf

# Helper libraries
import numpy as np
import matplotlib.pyplot as plt

print(tf.__version__)
2.5.0

ফ্যাশন MNIST ডেটাসেট আমদানি করুন

এই নির্দেশিকাটি ব্যবহার ফ্যাশন MNIST ডেটা সেটটি যা 10 শ্রেণিবিভাগ 70,000 গ্রেস্কেল চিত্র ধারণ করে। চিত্রগুলি কম রেজোলিউশনে পোশাকের পৃথক প্রবন্ধ দেখায় (28 বাই 28 পিক্সেল), যেমনটি এখানে দেখা হয়েছে:

ফ্যাশন MNIST পরী
চিত্র 1. ফ্যাশান-MNIST নমুনা (Zalando এমআইটি লাইসেন্স দ্বারা)।

ফ্যাশন MNIST সর্বোত্তম জন্য একটি ড্রপ ইন পরিবর্তে দেয়ার উদ্দেশ্যে করা হচ্ছে MNIST ডেটা সেটটি-প্রায়ই কম্পিউটার ভিশন জন্য মেশিন লার্নিং প্রোগ্রামের "হ্যালো, ওয়ার্ল্ড" হিসেবে ব্যবহার করা হয়েছে। MNIST ডেটাসেটে হস্তলিখিত সংখ্যার ছবি রয়েছে (0, 1, 2, ইত্যাদি) এমন একটি বিন্যাসে যা আপনি এখানে ব্যবহার করবেন পোশাকের নিবন্ধগুলির অনুরূপ।

এই নির্দেশিকাটি বিভিন্নতার জন্য ফ্যাশন MNIST ব্যবহার করে, এবং কারণ এটি নিয়মিত MNIST-এর তুলনায় একটু বেশি চ্যালেঞ্জিং সমস্যা। উভয় ডেটাসেট তুলনামূলকভাবে ছোট এবং একটি অ্যালগরিদম প্রত্যাশিত হিসাবে কাজ করে তা যাচাই করতে ব্যবহৃত হয়। কোড পরীক্ষা এবং ডিবাগ করার জন্য তারা ভাল শুরুর পয়েন্ট।

এখানে, নেটওয়ার্ককে প্রশিক্ষিত করতে 60,000টি ছবি এবং 10,000টি ছবিকে মূল্যায়ন করার জন্য ব্যবহার করা হয় যে নেটওয়ার্ক কতটা নির্ভুলভাবে ছবিকে শ্রেণীবদ্ধ করতে শিখেছে। আপনি TensorFlow থেকে সরাসরি ফ্যাশন MNIST অ্যাক্সেস করতে পারেন। আমদানি ও ফ্যাশন MNIST ডেটা লোড TensorFlow থেকে সরাসরি:

fashion_mnist = tf.keras.datasets.fashion_mnist

(train_images, train_labels), (test_images, test_labels) = fashion_mnist.load_data()
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/train-labels-idx1-ubyte.gz
32768/29515 [=================================] - 0s 0us/step
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/train-images-idx3-ubyte.gz
26427392/26421880 [==============================] - 0s 0us/step
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/t10k-labels-idx1-ubyte.gz
8192/5148 [===============================================] - 0s 0us/step
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/t10k-images-idx3-ubyte.gz
4423680/4422102 [==============================] - 0s 0us/step

ডেটাসেট লোড করা চারটি NumPy অ্যারে প্রদান করে:

  • train_images এবং train_labels অ্যারে প্রশিক্ষণ যে সময়টাতে তথ্য মডেল ব্যবহার শিখতে সেট করা আছে।
  • মডেল টেস্ট সেট বিরুদ্ধে পরীক্ষা করা হয় test_images এবং test_labels অ্যারে।

চিত্র 28x28 NumPy অ্যারে, হয় পূর্ণসংখ্যার একটি অ্যারের, 0 থেকে 9 পোশাক বর্গ ইমেজ প্রতিনিধিত্ব করে এইসব মিলা পর্যন্ত হয় পিক্সেল 0 থেকে 255 লেবেল ছোটো মান:

লেবেল ক্লাস
0 টি-শার্ট/টপ
1 ট্রাউজার
2 পুলওভার
3 পোষাক
4 কোট
5 চন্দন
6 শার্ট
7 স্নিকার
8 থলে
9 গোড়ালি বুট

প্রতিটি ছবি একটি একক লেবেলে ম্যাপ করা হয়। যেহেতু বর্গ নাম ডেটা সেটটি সঙ্গে অন্তর্ভুক্ত করা হয় না, তাদের এখানে যখন ইমেজ ষড়যন্ত্র পরে ব্যবহার করার জন্য দোকান:

class_names = ['T-shirt/top', 'Trouser', 'Pullover', 'Dress', 'Coat',
               'Sandal', 'Shirt', 'Sneaker', 'Bag', 'Ankle boot']

তথ্য অন্বেষণ

মডেলকে প্রশিক্ষণ দেওয়ার আগে আসুন ডেটাসেটের বিন্যাসটি অন্বেষণ করি। নিম্নলিখিত দেখায় প্রশিক্ষণ সেটে 60,000টি চিত্র রয়েছে, প্রতিটি চিত্রকে 28 x 28 পিক্সেল হিসাবে উপস্থাপন করা হয়েছে:

train_images.shape
(60000, 28, 28)

একইভাবে, প্রশিক্ষণ সেটে 60,000টি লেবেল রয়েছে:

len(train_labels)
60000

প্রতিটি লেবেল 0 এবং 9 এর মধ্যে একটি পূর্ণসংখ্যা:

train_labels
array([9, 0, 0, ..., 3, 0, 5], dtype=uint8)

পরীক্ষার সেটে 10,000টি ছবি রয়েছে। আবার, প্রতিটি চিত্রকে 28 x 28 পিক্সেল হিসাবে উপস্থাপন করা হয়েছে:

test_images.shape
(10000, 28, 28)

এবং পরীক্ষার সেটটিতে 10,000টি চিত্র লেবেল রয়েছে:

len(test_labels)
10000

ডেটা প্রিপ্রসেস করুন

নেটওয়ার্ক প্রশিক্ষণের আগে ডেটা অবশ্যই প্রিপ্রসেস করা উচিত। আপনি যদি প্রশিক্ষণ সেটের প্রথম চিত্রটি পরিদর্শন করেন, আপনি দেখতে পাবেন যে পিক্সেল মান 0 থেকে 255 এর মধ্যে পড়ে:

plt.figure()
plt.imshow(train_images[0])
plt.colorbar()
plt.grid(False)
plt.show()

png

এই মানগুলিকে নিউরাল নেটওয়ার্ক মডেলে খাওয়ানোর আগে 0 থেকে 1 এর পরিসরে স্কেল করুন৷ এটা করার জন্য, 255 দ্বারা মান ভাগ করে এটি গুরুত্বপূর্ণ যে ট্রেনিং সেট এবং পরীক্ষার সেট একই ভাবে preprocessed করা আছে:

train_images = train_images / 255.0

test_images = test_images / 255.0

যে ডেটা সঠিক বিন্যাসে এবং আপনার বিল্ড করার জন্য প্রস্তুত হন এবং নেটওয়ার্ক প্রশিক্ষণ যে যাচাই করতে, প্রশিক্ষণ সেট থেকে প্রথম 25 চিত্রগুলি প্রদর্শনের দিন এবং প্রতিটি ইমেজ নীচের বর্গ নাম প্রদর্শন করে।

plt.figure(figsize=(10,10))
for i in range(25):
    plt.subplot(5,5,i+1)
    plt.xticks([])
    plt.yticks([])
    plt.grid(False)
    plt.imshow(train_images[i], cmap=plt.cm.binary)
    plt.xlabel(class_names[train_labels[i]])
plt.show()

png

মডেল তৈরি করুন

নিউরাল নেটওয়ার্ক তৈরি করার জন্য মডেলের স্তরগুলি কনফিগার করা প্রয়োজন, তারপর মডেলটি কম্পাইল করা।

স্তরগুলি সেট আপ করুন

একটি স্নায়ুর নেটওয়ার্ক মৌলিক বিল্ডিং ব্লক হয় স্তর । স্তরগুলি তাদের মধ্যে দেওয়া ডেটা থেকে উপস্থাপনা বের করে। আশা করি, এই উপস্থাপনাগুলি হাতের সমস্যার জন্য অর্থবহ।

গভীর শিক্ষার বেশিরভাগ অংশই সহজ স্তরে একত্রে চেইন করে। যেমন সর্বাধিক স্তর tf.keras.layers.Dense , প্যারামিটার প্রশিক্ষণের সময় শিখেছি আছে।

model = tf.keras.Sequential([
    tf.keras.layers.Flatten(input_shape=(28, 28)),
    tf.keras.layers.Dense(128, activation='relu'),
    tf.keras.layers.Dense(10)
])

এই নেটওয়ার্ক, প্রথম স্তর tf.keras.layers.Flatten , (28 * 28 = 784 পিক্সেল) একটি এক-মাত্রিক বিন্যাসের থেকে (28 দ্বারা 28 পিক্সেল) একটি দ্বি-মাত্রিক অ্যারে থেকে ইমেজ ফরম্যাট রূপান্তরিত করে। এই স্তরটিকে চিত্রে পিক্সেলের সারিগুলি আনস্ট্যাক করা এবং সেগুলিকে সারিবদ্ধ করা হিসাবে ভাবুন। এই স্তরে শেখার কোন পরামিতি নেই; এটা শুধুমাত্র তথ্য পুনর্বিন্যাস.

পরে পিক্সেল চ্যাপ্টা হয়, নেটওয়ার্ক দুই একটা ক্রম নিয়ে গঠিত tf.keras.layers.Dense স্তর। এগুলি ঘনভাবে সংযুক্ত, বা সম্পূর্ণভাবে সংযুক্ত, নিউরাল স্তর। প্রথম Dense স্তর 128 নোড (অথবা নিউরোন) আছে। দ্বিতীয় (এবং শেষ) স্তরটি 10 ​​এর দৈর্ঘ্য সহ একটি লগিট অ্যারে প্রদান করে। প্রতিটি নোডে একটি স্কোর থাকে যা নির্দেশ করে যে বর্তমান চিত্রটি 10টি শ্রেণীর একটির অন্তর্গত।

মডেল কম্পাইল করুন

মডেলটি প্রশিক্ষণের জন্য প্রস্তুত হওয়ার আগে, এটির আরও কয়েকটি সেটিংস প্রয়োজন। এই মডেলের সময় যোগ করা হয় কম্পাইল পদক্ষেপ:

  • কমানোর ফাংশন পরিমাপ করে কিভাবে সঠিক মডেল প্রশিক্ষণের সময় হয় -এই। মডেলটিকে সঠিক দিকে নিয়ে যাওয়ার জন্য আপনি এই ফাংশনটিকে ছোট করতে চান৷
  • অপ্টিমাইজার -এই কিভাবে মডেল ডেটা দেখে এবং তার ক্ষতি ফাংশন উপর ভিত্তি করে আপডেট করা হয়।
  • মেট্রিক্স প্রশিক্ষণ ও পরীক্ষার পদক্ষেপ নিরীক্ষণ করতে -Used। নিম্নলিখিত উদাহরণে সঠিকতা, চিত্র যে সঠিকভাবে শ্রেণীবদ্ধ করা হয় ভগ্নাংশ ব্যবহার করে।
model.compile(optimizer='adam',
              loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
              metrics=['accuracy'])

মডেলকে প্রশিক্ষণ দিন

নিউরাল নেটওয়ার্ক মডেল প্রশিক্ষণের জন্য নিম্নলিখিত পদক্ষেপগুলি প্রয়োজন:

  1. মডেলে প্রশিক্ষণের ডেটা ফিড করুন। এই উদাহরণে, প্রশিক্ষণ ডেটা রয়েছে train_images এবং train_labels অ্যারে।
  2. মডেলটি ছবি এবং লেবেল সংযুক্ত করতে শেখে।
  3. আপনি একটি টেস্ট সেট-ইন এই উদাহরণে, সম্পর্কে ভবিষ্যৎবাণী করার মডেল জিজ্ঞাসা test_images অ্যারে।
  4. যাচাই করুন যে ভবিষ্যৎবাণী থেকে লেবেলগুলি মেলে test_labels অ্যারে।

মডেলকে খাওয়ান

প্রশিক্ষণ শুরু করার জন্য, কল model.fit পদ্ধতি-তথাকথিত কারণ এটি "তড়কা" ট্রেনিং ডেটাতে মডেল:

model.fit(train_images, train_labels, epochs=10)
Epoch 1/10
1875/1875 [==============================] - 3s 1ms/step - loss: 0.4982 - accuracy: 0.8256
Epoch 2/10
1875/1875 [==============================] - 3s 1ms/step - loss: 0.3747 - accuracy: 0.8658
Epoch 3/10
1875/1875 [==============================] - 3s 1ms/step - loss: 0.3356 - accuracy: 0.8770
Epoch 4/10
1875/1875 [==============================] - 3s 1ms/step - loss: 0.3112 - accuracy: 0.8856
Epoch 5/10
1875/1875 [==============================] - 3s 1ms/step - loss: 0.2941 - accuracy: 0.8915
Epoch 6/10
1875/1875 [==============================] - 3s 1ms/step - loss: 0.2776 - accuracy: 0.8972
Epoch 7/10
1875/1875 [==============================] - 3s 1ms/step - loss: 0.2678 - accuracy: 0.9000
Epoch 8/10
1875/1875 [==============================] - 3s 1ms/step - loss: 0.2564 - accuracy: 0.9049
Epoch 9/10
1875/1875 [==============================] - 3s 1ms/step - loss: 0.2467 - accuracy: 0.9083
Epoch 10/10
1875/1875 [==============================] - 3s 1ms/step - loss: 0.2399 - accuracy: 0.9103
<tensorflow.python.keras.callbacks.History at 0x7fe108a0c150>

মডেল ট্রেন হিসাবে, ক্ষতি এবং নির্ভুলতা মেট্রিক্স প্রদর্শিত হয়. এই মডেলটি প্রশিক্ষণের ডেটাতে প্রায় 0.91 (বা 91%) এর নির্ভুলতায় পৌঁছেছে।

নির্ভুলতা মূল্যায়ন

এরপরে, পরীক্ষার ডেটাসেটে মডেলটি কীভাবে কাজ করে তা তুলনা করুন:

test_loss, test_acc = model.evaluate(test_images,  test_labels, verbose=2)

print('\nTest accuracy:', test_acc)
313/313 - 0s - loss: 0.3413 - accuracy: 0.8814

Test accuracy: 0.8813999891281128

দেখা যাচ্ছে যে পরীক্ষার ডেটাসেটের নির্ভুলতা প্রশিক্ষণ ডেটাসেটের নির্ভুলতার চেয়ে একটু কম। প্রশিক্ষণ সঠিকতা এবং পরীক্ষা সঠিকতা মধ্যে এই ফাঁক overfitting প্রতিনিধিত্ব করে। ওভারফিটিং ঘটে যখন একটি মেশিন লার্নিং মডেল নতুন, পূর্বে অদেখা ইনপুটগুলিতে প্রশিক্ষণ ডেটার চেয়ে খারাপ কাজ করে। একটি ওভারফিটেড মডেল প্রশিক্ষণ ডেটাসেটের গোলমাল এবং বিশদ বিবরণকে "মুখস্থ" করে এমন একটি বিন্দুতে যেখানে এটি নতুন ডেটাতে মডেলের কর্মক্ষমতাকে নেতিবাচকভাবে প্রভাবিত করে। আরও তথ্যের জন্য, নিম্নলিখিত দেখুন:

ভবিষৎবাণী কর

প্রশিক্ষিত মডেলের সাথে, আপনি কিছু চিত্র সম্পর্কে ভবিষ্যদ্বাণী করতে এটি ব্যবহার করতে পারেন। মডেলের রৈখিক আউটপুট, logits । লগিটগুলিকে সম্ভাব্যতায় রূপান্তর করতে একটি সফটম্যাক্স স্তর সংযুক্ত করুন, যা ব্যাখ্যা করা সহজ।

probability_model = tf.keras.Sequential([model, 
                                         tf.keras.layers.Softmax()])
predictions = probability_model.predict(test_images)

এখানে, মডেলটি পরীক্ষার সেটে প্রতিটি ছবির জন্য লেবেলের পূর্বাভাস দিয়েছে। আসুন প্রথম ভবিষ্যদ্বাণীটি দেখে নেওয়া যাক:

predictions[0]
array([2.9212106e-07, 1.6208847e-10, 1.3363140e-08, 2.7341349e-09,
       5.5379962e-10, 4.5457238e-04, 4.2226111e-06, 4.4925120e-03,
       5.8868943e-07, 9.9504781e-01], dtype=float32)

একটি ভবিষ্যদ্বাণী হল 10টি সংখ্যার একটি অ্যারে। তারা মডেলের "আত্মবিশ্বাস" প্রতিনিধিত্ব করে যে চিত্রটি পোশাকের 10টি ভিন্ন নিবন্ধের প্রতিটির সাথে মিলে যায়। আপনি দেখতে পারেন কোন লেবেলে সর্বোচ্চ আস্থার মান রয়েছে:

np.argmax(predictions[0])
9

সুতরাং, মডেল যে এই ছবিটি একটি গোড়ালি বুট, অথবা সবচেয়ে আত্মবিশ্বাসী class_names[9] । পরীক্ষার লেবেল পরীক্ষা করে দেখায় যে এই শ্রেণীবিভাগ সঠিক:

test_labels[0]
9

10টি শ্রেণীর ভবিষ্যদ্বাণীর সম্পূর্ণ সেট দেখতে এটি গ্রাফ করুন।

def plot_image(i, predictions_array, true_label, img):
  true_label, img = true_label[i], img[i]
  plt.grid(False)
  plt.xticks([])
  plt.yticks([])

  plt.imshow(img, cmap=plt.cm.binary)

  predicted_label = np.argmax(predictions_array)
  if predicted_label == true_label:
    color = 'blue'
  else:
    color = 'red'

  plt.xlabel("{} {:2.0f}% ({})".format(class_names[predicted_label],
                                100*np.max(predictions_array),
                                class_names[true_label]),
                                color=color)

def plot_value_array(i, predictions_array, true_label):
  true_label = true_label[i]
  plt.grid(False)
  plt.xticks(range(10))
  plt.yticks([])
  thisplot = plt.bar(range(10), predictions_array, color="#777777")
  plt.ylim([0, 1])
  predicted_label = np.argmax(predictions_array)

  thisplot[predicted_label].set_color('red')
  thisplot[true_label].set_color('blue')

ভবিষ্যদ্বাণী যাচাই করুন

প্রশিক্ষিত মডেলের সাথে, আপনি কিছু চিত্র সম্পর্কে ভবিষ্যদ্বাণী করতে এটি ব্যবহার করতে পারেন।

আসুন 0ম চিত্র, ভবিষ্যদ্বাণী এবং ভবিষ্যদ্বাণী অ্যারে দেখি। সঠিক ভবিষ্যদ্বাণী লেবেল নীল এবং ভুল ভবিষ্যদ্বাণী লেবেল লাল। সংখ্যাটি পূর্বাভাসিত লেবেলের জন্য শতাংশ (100টির মধ্যে) দেয়।

i = 0
plt.figure(figsize=(6,3))
plt.subplot(1,2,1)
plot_image(i, predictions[i], test_labels, test_images)
plt.subplot(1,2,2)
plot_value_array(i, predictions[i],  test_labels)
plt.show()

png

i = 12
plt.figure(figsize=(6,3))
plt.subplot(1,2,1)
plot_image(i, predictions[i], test_labels, test_images)
plt.subplot(1,2,2)
plot_value_array(i, predictions[i],  test_labels)
plt.show()

png

আসুন তাদের ভবিষ্যদ্বাণী সহ বেশ কয়েকটি চিত্র প্লট করি। মনে রাখবেন যে মডেলটি খুব আত্মবিশ্বাসী হলেও ভুল হতে পারে।

# Plot the first X test images, their predicted labels, and the true labels.
# Color correct predictions in blue and incorrect predictions in red.
num_rows = 5
num_cols = 3
num_images = num_rows*num_cols
plt.figure(figsize=(2*2*num_cols, 2*num_rows))
for i in range(num_images):
  plt.subplot(num_rows, 2*num_cols, 2*i+1)
  plot_image(i, predictions[i], test_labels, test_images)
  plt.subplot(num_rows, 2*num_cols, 2*i+2)
  plot_value_array(i, predictions[i], test_labels)
plt.tight_layout()
plt.show()

png

প্রশিক্ষিত মডেল ব্যবহার করুন

অবশেষে, একটি একক চিত্র সম্পর্কে একটি ভবিষ্যদ্বাণী করতে প্রশিক্ষিত মডেল ব্যবহার করুন।

# Grab an image from the test dataset.
img = test_images[1]

print(img.shape)
(28, 28)

tf.keras মডেলের একবারে একটি ব্যাচ উপর পূর্বাভাস, বা সংগ্রহ, উদাহরণ তৈরি করতে অপ্টিমাইজ করা হয়। তদনুসারে, যদিও আপনি একটি একক চিত্র ব্যবহার করছেন, আপনাকে এটি একটি তালিকায় যুক্ত করতে হবে:

# Add the image to a batch where it's the only member.
img = (np.expand_dims(img,0))

print(img.shape)
(1, 28, 28)

এখন এই ছবির জন্য সঠিক লেবেল ভবিষ্যদ্বাণী করুন:

predictions_single = probability_model.predict(img)

print(predictions_single)
[[8.8914348e-05 1.3264636e-13 9.9108773e-01 1.2658383e-10 8.1463791e-03
  1.6905785e-08 6.7695131e-04 2.7492119e-17 5.1699739e-10 7.1339325e-17]]
plot_value_array(1, predictions_single[0], test_labels)
_ = plt.xticks(range(10), class_names, rotation=45)
plt.show()

png

tf.keras.Model.predict ডেটার ব্যাচ প্রতিটি ইমেজ জন্য তালিকা সহ এক তালিকা একটি তালিকা প্রদান করে। ব্যাচে আমাদের (শুধুমাত্র) চিত্রের জন্য ভবিষ্যদ্বাণীগুলি ধরুন:

np.argmax(predictions_single[0])
2

এবং মডেলটি প্রত্যাশিত হিসাবে একটি লেবেল ভবিষ্যদ্বাণী করে।

# 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.