{
  "source_file": "0930",
  "source_platform": "Hashnode",
  "author": "Wesley Kambale",
  "title_listed": "Implementing Advanced Model Architecture with TensorFlow - Part II",
  "keywords": "",
  "domain": "机器学习",
  "content_type": "深度技术解析",
  "is_paid_flag": "否",
  "url": "https://kambale.dev/advanced-model-architecture-part-ii",
  "publish_date": "2024-07-30",
  "corpus_stage": "",
  "notes": "",
  "id": "281596ef6397",
  "collected_at": "2026-10-02T14:11:24",
  "title": "Advanced Model Architecture with TensorFlow - Part II",
  "body_markdown": "Implementing Advanced Model Architecture with TensorFlow - Part II\nA deep dive into advanced model architecture with TensorFlow\nPublished\nJuly 30, 2024\n•\n11\nmin read\n•\nView as Markdown\nW\nWesley Kambale\nI'm a Machine Learning Engineer passionate about building production-ready ML systems for the African market.\nWith experience in TensorFlow, Keras, and Python-based workflows, I help teams bridge the gap between machine learning research and real-world deployment—especially on resource-constrained devices.\nI'm also a Google Developer Expert in AI. I regularly speak at tech conferences including PyCon Africa, DevFest Kampala, DevFest Nairobi and more and also write technical articles on AI/ML here.\nPart of series\nMachine Learning\nif you are finding this for the first time, it means you've missed\nPart I\n, it's recommended that you start from the beginning, okay? Let's do that real quick\nhere\n.\nDone? Okay. Let's go...\nImplementing Attention Mechanisms\nAttention mechanisms have revolutionized the field of deep learning, particularly in natural language processing (NLP) and computer vision. They allow models to focus on specific parts of the input sequence or data, effectively improving the model's ability to capture dependencies and relationships.\nUnderstanding Attention\nAttention mechanisms work by assigning different weights to different parts of the input, allowing the model to focus on the most relevant parts. This is particularly useful in sequence-to-sequence tasks such as machine translation, where certain words in the input sequence may be more important than others for generating the output sequence.\nTypes of Attention\nSelf-Attention\n: Computes attention weights within the same sequence, allowing each element to focus on other elements in the sequence.\nCross-Attention\n: Computes attention weights between two different sequences, such as in encoder-decoder models.\nScaled Dot-Product Attention\nThe scaled dot-product attention mechanism is a common type of attention used in many models, including the Transformer. It involves three main components: queries (Q), keys (K), and values (V).\n$$\\text{Attention}(Q, K, V) = \\text{softmax}\\left(\\frac{QK^T}{\\sqrt{d_k}}\\right)V$$\nMulti-Head Attention\nMulti-head attention extends the concept of single attention by applying multiple attention mechanisms in parallel, allowing the model to focus on different parts of the input sequence simultaneously.\n$$\\text{MultiHead}(Q, K, V) = \\text{Concat}(\\text{head}_1, \\text{head}_2, ..., \\text{head}_h)W^O$$\nwhere each head is an independent attention mechanism.\nImplementing Attention in TensorFlow\nHere's an example of implementing scaled dot-product attention and multi-head attention in TensorFlow.\nScaled Dot-Product Attention\nimport\ntensorflow\nas\ntf\ndef\nscaled_dot_product_attention\n(\nq, k, v, mask=None\n):\nmatmul_qk = tf.matmul(q, k, transpose_b=\nTrue\n)\n    dk = tf.cast(tf.shape(k)[\n-1\n], tf.float32)\n    scaled_attention_logits = matmul_qk / tf.math.sqrt(dk)\nif\nmask\nis\nnot\nNone\n:\n        scaled_attention_logits += (mask *\n-1e9\n)\n\n    attention_weights = tf.nn.softmax(scaled_attention_logits, axis=\n-1\n)\n    output = tf.matmul(attention_weights, v)\nreturn\noutput, attention_weights\nMulti-Head Attention\nclass\nMultiHeadAttention\n(\ntf.keras.layers.Layer\n):\ndef\n__init__\n(\nself, d_model, num_heads\n):\nsuper(MultiHeadAttention, self).__init__()\n        self.num_heads = num_heads\n        self.d_model = d_model\nassert\nd_model % self.num_heads ==\n0\nself.depth = d_model // self.num_heads\n\n        self.wq = tf.keras.layers.Dense(d_model)\n        self.wk = tf.keras.layers.Dense(d_model)\n        self.wv = tf.keras.layers.Dense(d_model)\n\n        self.dense = tf.keras.layers.Dense(d_model)\ndef\nsplit_heads\n(\nself, x, batch_size\n):\nx = tf.reshape(x, (batch_size,\n-1\n, self.num_heads, self.depth))\nreturn\ntf.transpose(x, perm=[\n0\n,\n2\n,\n1\n,\n3\n])\ndef\ncall\n(\nself, v, k, q, mask\n):\nbatch_size = tf.shape(q)[\n0\n]\n\n        q = self.wq(q)\n        k = self.wk(k)\n        v = self.wv(v)\n\n        q = self.split_heads(q, batch_size)\n        k = self.split_heads(k, batch_size)\n        v = self.split_heads(v, batch_size)\n\n        scaled_attention, attention_weights = scaled_dot_product_attention(q, k, v, mask)\n\n        scaled_attention = tf.transpose(scaled_attention, perm=[\n0\n,\n2\n,\n1\n,\n3\n])\n        concat_attention = tf.reshape(scaled_attention, (batch_size,\n-1\n, self.d_model))\n\n        output = self.dense(concat_attention)\nreturn\noutput, attention_weights\nUsing Attention in a Transformer Model\nThe Transformer model relies heavily on attention mechanisms. Here's a brief overview of how attention is used in the Transformer architecture.\nTransformer Encoder\nThe encoder consists of multiple layers, each containing a multi-head self-attention mechanism and a feed-forward neural network.\nclass\nEncoderLayer\n(\ntf.keras.layers.Layer\n):\ndef\n__init__\n(\nself, d_model, num_heads, dff, rate=\n0.1\n):\nsuper(EncoderLayer, self).__init__()\n        self.mha = MultiHeadAttention(d_model, num_heads)\n        self.ffn = tf.keras.Sequential([\n            tf.keras.layers.Dense(dff, activation=\n'relu'\n),\n            tf.keras.layers.Dense(d_model)\n        ])\n\n        self.layernorm1 = tf.keras.layers.LayerNormalization(epsilon=\n1e-6\n)\n        self.layernorm2 = tf.keras.layers.LayerNormalization(epsilon=\n1e-6\n)\n\n        self.dropout1 = tf.keras.layers.Dropout(rate)\n        self.dropout2 = tf.keras.layers.Dropout(rate)\ndef\ncall\n(\nself, x, training, mask\n):\nattn_output, _ = self.mha(x, x, x, mask)\n        attn_output = self.dropout1(attn_output, training=training)\n        out1 = self.layernorm1(x + attn_output)\n\n        ffn_output = self.ffn(out1)\n        ffn_output = self.dropout2(ffn_output, training=training)\n        out2 = self.layernorm2(out1 + ffn_output)\nreturn\nout2\nBuilding Generative Models\nGenerative models are a class of machine learning models that learn to generate new data samples that resemble the training data. Two popular types of generative models are Variational Autoencoders (VAEs) and Generative Adversarial Networks (GANs).\nVariational Autoencoders (VAEs)\nVariational Autoencoders (VAEs) are probabilistic graphical models that aim to learn a latent representation of the data, which can then be used to generate new samples. VAEs consist of two main components: the encoder and the decoder.\nKey Components of VAEs\nEncoder\n: Maps the input data to a latent space, producing a mean and a variance for each dimension of the latent space.\nDecoder\n: Maps the latent representation back to the data space, generating new samples that resemble the original data.\nImplementing a VAE in TensorFlow\nHere's an example of implementing a simple VAE for generating images.\nimport\ntensorflow\nas\ntf\nfrom\ntensorflow.keras\nimport\nlayers, models\nclass\nSampling\n(\nlayers.Layer\n):\ndef\ncall\n(\nself, inputs\n):\nz_mean, z_log_var = inputs\n        batch = tf.shape(z_mean)[\n0\n]\n        dim = tf.shape(z_mean)[\n1\n]\n        epsilon = tf.keras.backend.random_normal(shape=(batch, dim))\nreturn\nz_mean + tf.exp(\n0.5\n* z_log_var) * epsilon\n\nlatent_dim =\n2\nencoder_inputs = tf.keras.Input(shape=(\n28\n,\n28\n,\n1\n))\nx = layers.Flatten()(encoder_inputs)\nx = layers.Dense(\n512\n, activation=\n'relu'\n)(x)\nz_mean = layers.Dense(latent_dim)(x)\nz_log_var = layers.Dense(latent_dim)(x)\nz = Sampling()([z_mean, z_log_var])\nencoder = tf.keras.Model(encoder_inputs, [z_mean, z_log_var, z], name=\n\"encoder\"\n)\n\ndecoder_inputs = tf.keras.Input(shape=(latent_dim,))\nx = layers.Dense(\n512\n, activation=\n'relu'\n)(decoder_inputs)\nx = layers.Dense(\n28\n*\n28\n*\n1\n, activation=\n'sigmoid'\n)(x)\ndecoder_outputs = layers.Reshape((\n28\n,\n28\n,\n1\n))(x)\ndecoder = tf.keras.Model(decoder_inputs, decoder_outputs, name=\n\"decoder\"\n)\nclass\nVAE\n(\ntf.keras.Model\n):\ndef\n__init__\n(\nself, encoder, decoder, **kwargs\n):\nsuper(VAE, self).__init__(**kwargs)\n        self.encoder = encoder\n        self.decoder = decoder\ndef\ncall\n(\nself, inputs\n):\nz_mean, z_log_var, z = self.encoder(inputs)\n        reconstructed = self.decoder(z)\n        kl_loss =\n-0.5\n* tf.reduce_mean(z_log_var - tf.square(z_mean) - tf.exp(z_log_var) +\n1\n)\n        self.add_loss(kl_loss)\nreturn\nreconstructed\n\nvae = VAE(encoder, decoder)\nvae.compile(optimizer=\n'adam'\n, loss=\n'binary_crossentropy'\n)\n\n(x_train, _), (x_test, _) = tf.keras.datasets.mnist.load_data()\nx_train = x_train.astype(\n\"float32\"\n) /\n255.0\nx_train = x_train.reshape(\n-1\n,\n28\n,\n28\n,\n1\n)\nx_test = x_test.astype(\n\"float32\"\n) /\n255.0\nx_test = x_test.reshape(\n-1\n,\n28\n,\n28\n,\n1\n)\n\nvae.fit(x_train, x_train, epochs=\n30\n, batch_size=\n128\n, validation_data=(x_test, x_test))\nEncoder\n: The encoder consists of a dense layer followed by two output layers: one for the mean and one for the log variance of the latent space.\nDecoder\n: The decoder maps the latent space back to the original data space.\nSampling Layer\n: The sampling layer implements the reparameterization trick, which allows backpropagation through the stochastic latent space.\nVAE Model\n: The VAE model combines the encoder and decoder, adding the KL divergence loss to encourage the latent space to follow a standard normal distribution.\nGenerative Adversarial Networks (GANs)\nGenerative Adversarial Networks (GANs) consist of two neural networks: the generator and the discriminator. The generator learns to produce realistic data samples, while the discriminator learns to distinguish between real and generated samples. The two networks are trained in a competitive process.\nKey Components of GANs\nGenerator\n: Takes random noise as input and generates data samples.\nDiscriminator\n: Takes data samples as input and classifies them as real or fake.\nImplementing a GAN in TensorFlow\nHere's an example of implementing a simple GAN for generating images.\nimport\ntensorflow\nas\ntf\nfrom\ntensorflow.keras\nimport\nlayers, models\ndef\nbuild_generator\n():\nmodel = models.Sequential()\n    model.add(layers.Dense(\n256\n, activation=\n'relu'\n, input_dim=\n100\n))\n    model.add(layers.BatchNormalization())\n    model.add(layers.Dense(\n512\n, activation=\n'relu'\n))\n    model.add(layers.BatchNormalization())\n    model.add(layers.Dense(\n1024\n, activation=\n'relu'\n))\n    model.add(layers.BatchNormalization())\n    model.add(layers.Dense(\n28\n*\n28\n*\n1\n, activation=\n'tanh'\n))\n    model.add(layers.Reshape((\n28\n,\n28\n,\n1\n)))\nreturn\nmodel\ndef\nbuild_discriminator\n():\nmodel = models.Sequential()\n    model.add(layers.Flatten(input_shape=(\n28\n,\n28\n,\n1\n)))\n    model.add(layers.Dense(\n512\n, activation=\n'relu'\n))\n    model.add(layers.Dense(\n256\n, activation=\n'relu'\n))\n    model.add(layers.Dense(\n1\n, activation=\n'sigmoid'\n))\nreturn\nmodel\n\ngenerator = build_generator()\ndiscriminator = build_discriminator()\ndiscriminator.compile(optimizer=\n'adam'\n, loss=\n'binary_crossentropy'\n, metrics=[\n'accuracy'\n])\n\ngan_input = tf.keras.Input(shape=(\n100\n,))\ngenerated_image = generator(gan_input)\ndiscriminator.trainable =\nFalse\ngan_output = discriminator(generated_image)\ngan = tf.keras.Model(gan_input, gan_output)\ngan.compile(optimizer=\n'adam'\n, loss=\n'binary_crossentropy'\n)\n\n(x_train, _), (_, _) = tf.keras.datasets.mnist.load_data()\nx_train = x_train.astype(\n\"float32\"\n) /\n255.0\nx_train = x_train.reshape(\n-1\n,\n28\n,\n28\n,\n1\n)\nimport\nnumpy\nas\nnp\n\nbatch_size =\n128\nepochs =\n10000\nhalf_batch = batch_size //\n2\nfor\nepoch\nin\nrange(epochs):\n    idx = np.random.randint(\n0\n, x_train.shape[\n0\n], half_batch)\n    real_images = x_train[idx]\n    noise = np.random.normal(\n0\n,\n1\n, (half_batch,\n100\n))\n    fake_images = generator.predict(noise)\n\n    d_loss_real = discriminator.train_on_batch(real_images, np.ones((half_batch,\n1\n)))\n    d_loss_fake = discriminator.train_on_batch(fake_images, np.zeros((half_batch,\n1\n)))\n    d_loss =\n0.5\n* np.add(d_loss_real, d_loss_fake)\n\n    noise = np.random.normal(\n0\n,\n1\n, (batch_size,\n100\n))\n    valid_y = np.array([\n1\n] * batch_size)\n    g_loss = gan.train_on_batch(noise, valid_y)\nif\nepoch %\n100\n==\n0\n:\n        print(\nf\"\n{epoch}\n[D loss:\n{d_loss[\n0\n]}\n| D accuracy:\n{\n100\n*d_loss[\n1\n]}\n] [G loss:\n{g_loss}\n]\"\n)\nGenerator\n: The generator network consists of dense layers followed by batch normalization and activation functions. It maps random noise to a data sample.\nDiscriminator\n: The discriminator network consists of dense layers and activation functions. It classifies data samples as real or fake.\nTraining Loop\n: The GAN is trained in a loop where the discriminator is trained on real and fake samples, followed by training the generator to produce samples that can fool the discriminator.\nHyperparameter Tuning and Model Evaluation\nHyperparameter tuning and model evaluation are crucial steps in the development of machine learning models. Proper tuning ensures optimal performance, while thorough evaluation helps understand the model's strengths and weaknesses.\nHyperparameter Tuning\nHyperparameters are settings that define the model structure and how it is trained, such as learning rate, batch size, number of layers, and units per layer. Unlike parameters learned during training, hyperparameters need to be set before the training process begins.\nImportance of Hyperparameter Tuning\nEffective hyperparameter tuning can significantly improve model performance. Poorly chosen hyperparameters can lead to underfitting or overfitting, resulting in a model that performs poorly on unseen data.\nTechniques for Hyperparameter Tuning\nGrid Search\n: Exhaustively searches over a specified hyperparameter grid.\nRandom Search\n: Samples hyperparameters randomly from a defined range.\nBayesian Optimization\n: Uses probabilistic models to find the optimal hyperparameters.\nHyperband\n: Combines random search and early stopping to efficiently find optimal hyperparameters.\nGrid Search\nGrid search is a brute-force technique that searches over a predefined grid of hyperparameters.\nfrom\nsklearn.model_selection\nimport\nGridSearchCV\nfrom\nsklearn.ensemble\nimport\nRandomForestClassifier\n\nparam_grid = {\n'n_estimators'\n: [\n100\n,\n200\n,\n300\n],\n'max_depth'\n: [\n10\n,\n20\n,\n30\n],\n'min_samples_split'\n: [\n2\n,\n5\n,\n10\n]\n}\n\ngrid_search = GridSearchCV(estimator=RandomForestClassifier(), param_grid=param_grid, cv=\n3\n, n_jobs=\n-1\n, verbose=\n2\n)\ngrid_search.fit(X_train, y_train)\n\nprint(\n\"Best Hyperparameters:\"\n, grid_search.best_params_)\nRandom Search\nRandom search samples hyperparameters from a specified distribution, which can be more efficient than grid search.\nfrom\nsklearn.model_selection\nimport\nRandomizedSearchCV\nfrom\nsklearn.ensemble\nimport\nRandomForestClassifier\nfrom\nscipy.stats\nimport\nrandint\n\nparam_dist = {\n'n_estimators'\n: randint(\n100\n,\n500\n),\n'max_depth'\n: randint(\n10\n,\n50\n),\n'min_samples_split'\n: randint(\n2\n,\n11\n)\n}\n\nrandom_search = RandomizedSearchCV(estimator=RandomForestClassifier(), param_distributions=param_dist, n_iter=\n100\n, cv=\n3\n, n_jobs=\n-1\n, verbose=\n2\n)\nrandom_search.fit(X_train, y_train)\n\nprint(\n\"Best Hyperparameters:\"\n, random_search.best_params_)\nBayesian Optimization\nBayesian optimization uses a surrogate model to estimate the performance of hyperparameters and efficiently searches the space.\nfrom\nskopt\nimport\nBayesSearchCV\nfrom\nsklearn.ensemble\nimport\nRandomForestClassifier\n\nparam_space = {\n'n_estimators'\n: (\n100\n,\n500\n),\n'max_depth'\n: (\n10\n,\n50\n),\n'min_samples_split'\n: (\n2\n,\n11\n)\n}\n\nbayes_search = BayesSearchCV(estimator=RandomForestClassifier(), search_spaces=param_space, n_iter=\n32\n, cv=\n3\n, n_jobs=\n-1\n, verbose=\n2\n)\nbayes_search.fit(X_train, y_train)\n\nprint(\n\"Best Hyperparameters:\"\n, bayes_search.best_params_)\nHyperband\nHyperband combines random search with early stopping to find the best hyperparameters more efficiently.\nfrom\nkeras_tuner.tuners\nimport\nHyperband\nfrom\ntensorflow.keras.models\nimport\nSequential\nfrom\ntensorflow.keras.layers\nimport\nDense\ndef\nbuild_model\n(\nhp\n):\nmodel = Sequential()\n    model.add(Dense(units=hp.Int(\n'units'\n, min_value=\n32\n, max_value=\n512\n, step=\n32\n), activation=\n'relu'\n, input_shape=(input_dim,)))\n    model.add(Dense(\n1\n, activation=\n'sigmoid'\n))\n    model.compile(optimizer=\n'adam'\n, loss=\n'binary_crossentropy'\n, metrics=[\n'accuracy'\n])\nreturn\nmodel\n\ntuner = Hyperband(build_model, objective=\n'val_accuracy'\n, max_epochs=\n10\n, factor=\n3\n, directory=\n'my_dir'\n, project_name=\n'helloworld'\n)\ntuner.search(X_train, y_train, epochs=\n50\n, validation_split=\n0.2\n)\n\nprint(\n\"Best Hyperparameters:\"\n, tuner.get_best_hyperparameters()[\n0\n].values)\nModel Evaluation\nModel evaluation involves assessing the performance of a trained model using various metrics. This helps determine how well the model generalizes to new, unseen data.\nEvaluation Metrics\nAccuracy\n: Proportion of correctly predicted instances.\nPrecision\n: Proportion of true positives among the predicted positives.\nRecall\n: Proportion of true positives among the actual positives.\nF1 Score\n: Harmonic mean of precision and recall.\nROC-AUC\n: Area under the Receiver Operating Characteristic curve, measuring the trade-off between true positive rate and false positive rate.\nMean Squared Error (MSE)\n: Average of the squared differences between predicted and actual values (for regression).\nMean Absolute Error (MAE)\n: Average of the absolute differences between predicted and actual values (for regression).\nCross-Validation\nCross-validation is a technique for assessing model performance by splitting the data into multiple folds and training/testing the model on these folds. Common methods include k-fold cross-validation and stratified k-fold cross-validation.\nfrom\nsklearn.model_selection\nimport\ncross_val_score\nfrom\nsklearn.ensemble\nimport\nRandomForestClassifier\n\nmodel = RandomForestClassifier(n_estimators=\n100\n)\nscores = cross_val_score(model, X, y, cv=\n5\n, scoring=\n'accuracy'\n)\n\nprint(\n\"Cross-Validation Scores:\"\n, scores)\nprint(\n\"Mean Accuracy:\"\n, scores.mean())\nConfusion Matrix\nA confusion matrix provides a detailed breakdown of model predictions, showing the counts of true positives, true negatives, false positives, and false negatives.\nfrom\nsklearn.metrics\nimport\nconfusion_matrix, ConfusionMatrixDisplay\n\ny_pred = model.predict(X_test)\ncm = confusion_matrix(y_test, y_pred)\ndisp = ConfusionMatrixDisplay(confusion_matrix=cm)\ndisp.plot()\nplt.show()\nROC Curve and AUC\nThe ROC curve plots the true positive rate against the false positive rate at various threshold settings. The AUC represents the area under this curve.\nfrom\nsklearn.metrics\nimport\nroc_curve, roc_auc_score\nimport\nmatplotlib.pyplot\nas\nplt\n\ny_pred_proba = model.predict_proba(X_test)[:,\n1\n]\nfpr, tpr, _ = roc_curve(y_test, y_pred_proba)\nauc = roc_auc_score(y_test, y_pred_proba)\n\nplt.plot(fpr, tpr, label=\nf'ROC Curve (AUC =\n{auc:\n.2\nf}\n)'\n)\nplt.xlabel(\n'False Positive Rate'\n)\nplt.ylabel(\n'True Positive Rate'\n)\nplt.title(\n'Receiver Operating Characteristic'\n)\nplt.legend(loc=\n'lower right'\n)\nplt.show()\nConclusion - Part II\nImplementing advanced model architectures with TensorFlow encompasses a broad range of techniques and methodologies, each crucial for developing robust, efficient, and high-performing machine learning models. From setting up the development environment to fine-tuning hyperparameters and evaluating models, every step plays a vital role in the model development lifecycle.\nKey Takeaways\nImplementing Attention Mechanisms\n: Attention mechanisms, especially in the context of the Transformer architecture, have revolutionized the way models handle sequential data. By enabling models to focus on relevant parts of the input, attention mechanisms significantly enhance the capability of models to understand complex dependencies.\nBuilding Generative Models\n: Generative models like Variational Autoencoders (VAEs) and Generative Adversarial Networks (GANs) open up new possibilities in data generation and augmentation. These models are particularly powerful in applications such as image synthesis, data augmentation, and creative AI tasks.\nHyperparameter Tuning and Model Evaluation\n: Hyperparameter tuning is a critical step in optimizing model performance. Techniques like grid search, random search, Bayesian optimization, and Hyperband provide systematic approaches to finding the best hyperparameters. Model evaluation metrics and methods ensure that the models are not only accurate but also generalize well to unseen data.\nFinal Thoughts\nBuilding and deploying advanced model architectures with TensorFlow requires a blend of theoretical knowledge and practical skills. By understanding and applying the concepts covered in this tutorial, developers can build sophisticated models capable of solving a wide range of real-world problems. The journey from setting up the environment to fine-tuning hyperparameters and evaluating model performance is iterative and requires continuous learning and experimentation. With TensorFlow’s powerful capabilities and a systematic approach, the possibilities for innovation in machine learning are vast and exciting.\nEmbarking on this journey will not only enhance your technical skills but also enable you to contribute to the rapidly advancing field of artificial intelligence, pushing the boundaries of what is possible with machine learning.\n#\ntensorflow\n#\nmodels\n#\narchitecture",
  "metadata": {
    "title": "Advanced Model Architecture with TensorFlow - Part II",
    "description": "A deep dive into advanced model architecture with TensorFlow",
    "keywords": null,
    "author": null,
    "og:title": "Advanced Model Architecture with TensorFlow - Part II",
    "og:description": "A deep dive into advanced model architecture with TensorFlow",
    "og:url": "https://kambale.dev/advanced-model-architecture-part-ii",
    "og:site_name": "Wesley Kambale",
    "og:image": "https://cdn.hashnode.com/res/hashnode/image/upload/v1722298824598/8b7a18c7-d2a0-4ebf-89e3-abc08037f0ef.png",
    "og:image:width": "1200",
    "og:image:height": "630",
    "og:type": "article",
    "twitter:card": "summary_large_image",
    "twitter:creator": "https://twitter.com/WesKambale",
    "twitter:title": "Advanced Model Architecture with TensorFlow - Part II",
    "twitter:description": "A deep dive into advanced model architecture with TensorFlow",
    "twitter:image": "https://cdn.hashnode.com/res/hashnode/image/upload/v1722298824598/8b7a18c7-d2a0-4ebf-89e3-abc08037f0ef.png",
    "article:published_time": "2024-07-30T00:20:53.273Z",
    "article:author": "https://kambale.dev/@kambale"
  },
  "paywall": {
    "listed_paid": false,
    "detected": false,
    "marker": "",
    "public_only": false,
    "policy": "付费/会员内容只保留页面公开可见部分，不绕过付费墙"
  },
  "crawl": {
    "success": true,
    "status_code": 200,
    "error": ""
  },
  "code_blocks": [
    {
      "file": "attachments/281596ef6397/code/body-000.txt",
      "chars": 465,
      "language": "text"
    },
    {
      "file": "attachments/281596ef6397/code/body-001.txt",
      "chars": 1291,
      "language": "text"
    },
    {
      "file": "attachments/281596ef6397/code/body-002.txt",
      "chars": 998,
      "language": "text"
    },
    {
      "file": "attachments/281596ef6397/code/body-003.txt",
      "chars": 1858,
      "language": "text"
    },
    {
      "file": "attachments/281596ef6397/code/body-004.txt",
      "chars": 2190,
      "language": "text"
    },
    {
      "file": "attachments/281596ef6397/code/body-005.txt",
      "chars": 430,
      "language": "text"
    },
    {
      "file": "attachments/281596ef6397/code/body-006.txt",
      "chars": 510,
      "language": "text"
    },
    {
      "file": "attachments/281596ef6397/code/body-007.txt",
      "chars": 421,
      "language": "text"
    },
    {
      "file": "attachments/281596ef6397/code/body-008.txt",
      "chars": 723,
      "language": "text"
    },
    {
      "file": "attachments/281596ef6397/code/body-009.txt",
      "chars": 300,
      "language": "text"
    },
    {
      "file": "attachments/281596ef6397/code/body-010.txt",
      "chars": 213,
      "language": "text"
    },
    {
      "file": "attachments/281596ef6397/code/body-011.txt",
      "chars": 436,
      "language": "text"
    }
  ],
  "images": [
    {
      "status": "ok",
      "url": "https://cdn.hashnode.com/res/hashnode/image/upload/v1722044079231/65d18b11-4320-4d72-9d9d-2eae1d93f3e6.png",
      "bytes": 89288,
      "reused": true,
      "local_path": "attachments/281596ef6397/images/000.png",
      "src": "https://cdn.hashnode.com/res/hashnode/image/upload/v1722044079231/65d18b11-4320-4d72-9d9d-2eae1d93f3e6.png",
      "alt": "Implementing Advanced Model Architecture with TensorFlow - Part II",
      "downloaded": true
    }
  ],
  "audio": [],
  "videos": [],
  "links": [
    {
      "href": "https://kambale.dev/advanced-model-architecture-part-ii.md",
      "label": "View as Markdown",
      "type": "a"
    },
    {
      "href": "https://hashnode.com/@kambale",
      "label": "W",
      "type": "a"
    },
    {
      "href": "https://twitter.com/WesKambale",
      "label": "",
      "type": "a"
    },
    {
      "href": "https://linkedin.com/in/WesKambale",
      "label": "",
      "type": "a"
    },
    {
      "href": "https://kambale.dev/series/ml-series",
      "label": "Part of series Machine Learning",
      "type": "a"
    },
    {
      "href": "https://kambale.dev/advanced-model-architecture-part-i",
      "label": "Part I",
      "type": "a"
    },
    {
      "href": "https://kambale.dev/tag/tensorflow",
      "label": "# tensorflow",
      "type": "a"
    },
    {
      "href": "https://kambale.dev/tag/models",
      "label": "# models",
      "type": "a"
    },
    {
      "href": "https://kambale.dev/tag/architecture",
      "label": "# architecture",
      "type": "a"
    }
  ],
  "repair_version": 2,
  "repaired_at": "2026-10-14T10:50:49Z",
  "source_url": "https://kambale.dev/advanced-model-architecture-part-ii",
  "papers": [],
  "actual_video_files": [],
  "body_chars": 21027,
  "expected_body_images": 1,
  "discovery_status": "ok",
  "delivery_status": "ok",
  "missing_reason": "",
  "raw_html": "attachments/281596ef6397/pages/source.html",
  "local_html": "attachments/281596ef6397/pages/article.html",
  "body_base_path": "attachments/281596ef6397/pages/",
  "body_markdown_path": "attachments/281596ef6397/pages/article.md"
}