|
13 | 13 | "source": [
|
14 | 14 | "# One Device Strategy \n",
|
15 | 15 | "\n",
|
16 |
| - "In this ungraded lab you'll learn to set up a One Device Strategy" |
| 16 | + "In this ungraded lab, you'll learn how to set up a [One Device Strategy](https://www.tensorflow.org/api_docs/python/tf/distribute/OneDeviceStrategy). This is typically used to deliberately test your code on a single device. This can be used before switching to a different strategy that distributes across multiple devices. Please click on the **Open in Colab** badge above so you can download the datasets and use a GPU-enabled lab environment." |
17 | 17 | ]
|
18 | 18 | },
|
19 | 19 | {
|
|
42 | 42 | "import tensorflow as tf\n",
|
43 | 43 | "import tensorflow_hub as hub\n",
|
44 | 44 | "import tensorflow_datasets as tfds\n",
|
45 |
| - "tfds.disable_progress_bar()\n", |
46 |
| - "devices = tf.config.list_physical_devices('CPU')\n", |
47 |
| - "cpu_name = devices[0].name\n", |
48 | 45 | "\n",
|
49 |
| - "devices = tf.config.list_physical_devices('CPU')\n", |
| 46 | + "tfds.disable_progress_bar()" |
| 47 | + ] |
| 48 | + }, |
| 49 | + { |
| 50 | + "cell_type": "markdown", |
| 51 | + "metadata": {}, |
| 52 | + "source": [ |
| 53 | + "## Define the Distribution Strategy\n", |
| 54 | + "\n", |
| 55 | + "You can list available devices in your machine and specify a device type. This allows you to verify the device name to pass in `tf.distribute.OneDeviceStrategy()`." |
| 56 | + ] |
| 57 | + }, |
| 58 | + { |
| 59 | + "cell_type": "code", |
| 60 | + "execution_count": null, |
| 61 | + "metadata": {}, |
| 62 | + "outputs": [], |
| 63 | + "source": [ |
| 64 | + "# choose a device type such as CPU or GPU\n", |
| 65 | + "devices = tf.config.list_physical_devices('GPU')\n", |
50 | 66 | "print(devices[0])\n",
|
51 |
| - "# You'll see that the name will look something like \"/physical_device:CPU:0\"\n", |
52 |
| - "# Just take the CPU:0 part and use that as the name\n", |
53 |
| - "cpu_name = \"CPU:0\"" |
| 67 | + "\n", |
| 68 | + "# You'll see that the name will look something like \"/physical_device:GPU:0\"\n", |
| 69 | + "# Just take the GPU:0 part and use that as the name\n", |
| 70 | + "gpu_name = \"GPU:0\"\n", |
| 71 | + "\n", |
| 72 | + "# define the strategy and pass in the device name\n", |
| 73 | + "one_strategy = tf.distribute.OneDeviceStrategy(device=gpu_name)" |
| 74 | + ] |
| 75 | + }, |
| 76 | + { |
| 77 | + "cell_type": "markdown", |
| 78 | + "metadata": {}, |
| 79 | + "source": [ |
| 80 | + "## Parameters\n", |
| 81 | + "\n", |
| 82 | + "We'll define a few global variables for setting up the model and dataset." |
54 | 83 | ]
|
55 | 84 | },
|
56 | 85 | {
|
|
66 | 95 | "pixels = 224\n",
|
67 | 96 | "MODULE_HANDLE = 'https://tfhub.dev/tensorflow/resnet_50/feature_vector/1'\n",
|
68 | 97 | "IMAGE_SIZE = (pixels, pixels)\n",
|
| 98 | + "BATCH_SIZE = 32\n", |
| 99 | + "\n", |
69 | 100 | "print(\"Using {} with input size {}\".format(MODULE_HANDLE, IMAGE_SIZE))"
|
70 | 101 | ]
|
71 | 102 | },
|
| 103 | + { |
| 104 | + "cell_type": "markdown", |
| 105 | + "metadata": {}, |
| 106 | + "source": [ |
| 107 | + "## Download and Prepare the Dataset\n", |
| 108 | + "\n", |
| 109 | + "We will use the [Cats vs Dogs](https://www.tensorflow.org/datasets/catalog/cats_vs_dogs) dataset and we will fetch it via TFDS." |
| 110 | + ] |
| 111 | + }, |
72 | 112 | {
|
73 | 113 | "cell_type": "code",
|
74 | 114 | "execution_count": null,
|
|
80 | 120 | "outputs": [],
|
81 | 121 | "source": [
|
82 | 122 | "splits = ['train[:80%]', 'train[80%:90%]', 'train[90%:]']\n",
|
83 |
| - "#data, info = tfds.load('cats_vs_dogs', with_info=True, as_supervised=True, split=splits)\n", |
84 | 123 | "\n",
|
85 | 124 | "(train_examples, validation_examples, test_examples), info = tfds.load('cats_vs_dogs', with_info=True, as_supervised=True, split=splits)\n",
|
86 | 125 | "\n",
|
87 | 126 | "num_examples = info.splits['train'].num_examples\n",
|
88 |
| - "num_classes = info.features['label'].num_classes\n" |
| 127 | + "num_classes = info.features['label'].num_classes" |
89 | 128 | ]
|
90 | 129 | },
|
91 | 130 | {
|
|
98 | 137 | },
|
99 | 138 | "outputs": [],
|
100 | 139 | "source": [
|
| 140 | + "# resize the image and normalize pixel values\n", |
101 | 141 | "def format_image(image, label):\n",
|
102 |
| - " image = tf.image.resize(image, IMAGE_SIZE) / 255.0\n", |
103 |
| - " return image, label" |
| 142 | + " image = tf.image.resize(image, IMAGE_SIZE) / 255.0\n", |
| 143 | + " return image, label" |
104 | 144 | ]
|
105 | 145 | },
|
106 | 146 | {
|
|
113 | 153 | },
|
114 | 154 | "outputs": [],
|
115 | 155 | "source": [
|
116 |
| - "BATCH_SIZE = 32\n", |
| 156 | + "# prepare batches\n", |
117 | 157 | "train_batches = train_examples.shuffle(num_examples // 4).map(format_image).batch(BATCH_SIZE).prefetch(1)\n",
|
118 | 158 | "validation_batches = validation_examples.map(format_image).batch(BATCH_SIZE).prefetch(1)\n",
|
119 | 159 | "test_batches = test_examples.map(format_image).batch(1)"
|
|
129 | 169 | },
|
130 | 170 | "outputs": [],
|
131 | 171 | "source": [
|
| 172 | + "# check if the batches have the correct size and the images have the correct shape\n", |
132 | 173 | "for image_batch, label_batch in train_batches.take(1):\n",
|
133 |
| - " pass\n", |
| 174 | + " pass\n", |
134 | 175 | "\n",
|
135 |
| - "image_batch.shape" |
| 176 | + "print(image_batch.shape)" |
| 177 | + ] |
| 178 | + }, |
| 179 | + { |
| 180 | + "cell_type": "markdown", |
| 181 | + "metadata": {}, |
| 182 | + "source": [ |
| 183 | + "## Define and Configure the Model\n", |
| 184 | + "\n", |
| 185 | + "As with other strategies, setting up the model requires minimal code changes. Let's first define a utility function to build and compile the model." |
136 | 186 | ]
|
137 | 187 | },
|
138 | 188 | {
|
|
145 | 195 | },
|
146 | 196 | "outputs": [],
|
147 | 197 | "source": [
|
148 |
| - "do_fine_tuning = False #@param {type:\"boolean\"}" |
| 198 | + "# tells if we want to freeze the layer weights of our feature extractor during training\n", |
| 199 | + "do_fine_tuning = False" |
149 | 200 | ]
|
150 | 201 | },
|
151 | 202 | {
|
|
159 | 210 | "outputs": [],
|
160 | 211 | "source": [
|
161 | 212 | "def build_and_compile_model():\n",
|
162 |
| - " print(\"Building model with\", MODULE_HANDLE)\n", |
163 |
| - " feature_extractor = hub.KerasLayer(MODULE_HANDLE,\n", |
| 213 | + " print(\"Building model with\", MODULE_HANDLE)\n", |
| 214 | + "\n", |
| 215 | + " # configures the feature extractor fetched from TF Hub\n", |
| 216 | + " feature_extractor = hub.KerasLayer(MODULE_HANDLE,\n", |
164 | 217 | " input_shape=IMAGE_SIZE + (3,), \n",
|
165 | 218 | " trainable=do_fine_tuning)\n",
|
166 |
| - " model = tf.keras.Sequential([\n", |
| 219 | + "\n", |
| 220 | + " # define the model\n", |
| 221 | + " model = tf.keras.Sequential([\n", |
167 | 222 | " feature_extractor,\n",
|
| 223 | + " # append a dense with softmax for the number of classes\n", |
168 | 224 | " tf.keras.layers.Dense(num_classes, activation='softmax')\n",
|
169 |
| - " ])\n", |
170 |
| - " model.summary()\n", |
| 225 | + " ])\n", |
171 | 226 | "\n",
|
172 |
| - " optimizer = tf.keras.optimizers.SGD(lr=0.002, momentum=0.9) if do_fine_tuning else 'adam'\n", |
173 |
| - " model.compile(optimizer=optimizer,\n", |
| 227 | + " # display summary\n", |
| 228 | + " model.summary()\n", |
| 229 | + "\n", |
| 230 | + " # configure the optimizer, loss and metrics\n", |
| 231 | + " optimizer = tf.keras.optimizers.SGD(lr=0.002, momentum=0.9) if do_fine_tuning else 'adam'\n", |
| 232 | + " model.compile(optimizer=optimizer,\n", |
174 | 233 | " loss='sparse_categorical_crossentropy',\n",
|
175 | 234 | " metrics=['accuracy'])\n",
|
176 |
| - " \n", |
177 |
| - " return model" |
| 235 | + "\n", |
| 236 | + " return model" |
| 237 | + ] |
| 238 | + }, |
| 239 | + { |
| 240 | + "cell_type": "markdown", |
| 241 | + "metadata": {}, |
| 242 | + "source": [ |
| 243 | + "You can now call the function under the strategy scope. This places variables and computations on the device you specified earlier." |
178 | 244 | ]
|
179 | 245 | },
|
180 | 246 | {
|
|
187 | 253 | },
|
188 | 254 | "outputs": [],
|
189 | 255 | "source": [
|
190 |
| - "one_strategy = tf.distribute.OneDeviceStrategy(device=cpu_name)\n", |
| 256 | + "# build and compile under the strategy scope\n", |
191 | 257 | "with one_strategy.scope():\n",
|
192 |
| - " model = build_and_compile_model()" |
| 258 | + " model = build_and_compile_model()" |
| 259 | + ] |
| 260 | + }, |
| 261 | + { |
| 262 | + "cell_type": "markdown", |
| 263 | + "metadata": {}, |
| 264 | + "source": [ |
| 265 | + "`model.fit()` can be run as usual." |
193 | 266 | ]
|
194 | 267 | },
|
195 | 268 | {
|
|
209 | 282 | ]
|
210 | 283 | },
|
211 | 284 | {
|
212 |
| - "cell_type": "code", |
213 |
| - "execution_count": null, |
214 |
| - "metadata": { |
215 |
| - "colab": {}, |
216 |
| - "colab_type": "code", |
217 |
| - "id": "P6zyUR7-4fm3" |
218 |
| - }, |
219 |
| - "outputs": [], |
220 |
| - "source": [] |
| 285 | + "cell_type": "markdown", |
| 286 | + "metadata": {}, |
| 287 | + "source": [ |
| 288 | + "Once everything is working correctly, you can switch to a different device or a different strategy that distributes to multiple devices." |
| 289 | + ] |
221 | 290 | }
|
222 | 291 | ],
|
223 | 292 | "metadata": {
|
224 | 293 | "accelerator": "GPU",
|
225 | 294 | "colab": {
|
226 | 295 | "collapsed_sections": [],
|
227 |
| - "name": "OneDeviceStrategyExerciseAnswer.ipynb", |
| 296 | + "name": "C2W4_Lab_4_one-device-strategy.ipynb", |
228 | 297 | "provenance": []
|
229 | 298 | },
|
230 | 299 | "kernelspec": {
|
|
0 commit comments