Official Implementation for HyperStyle: StyleGAN Inversion with HyperNetworks for Real Image Editing

Overview

HyperStyle: StyleGAN Inversion with HyperNetworks for Real Image Editing

Yuval Alaluf*, Omer Tov*, Ron Mokady, Rinon Gal, Amit H. Bermano
*Denotes equal contribution

The inversion of real images into StyleGAN's latent space is a well-studied problem. Nevertheless, applying existing approaches to real-world scenarios remains an open challenge, due to an inherent trade-off between reconstruction and editability: latent space regions which can accurately represent real images typically suffer from degraded semantic control. Recent work proposes to mitigate this trade-off by fine-tuning the generator to add the target image to well-behaved, editable regions of the latent space. While promising, this fine-tuning scheme is impractical for prevalent use as it requires a lengthy training phase for each new image. In this work, we introduce this approach into the realm of encoder-based inversion. We propose HyperStyle, a hypernetwork that learns to modulate StyleGAN's weights to faithfully express a given image in editable regions of the latent space. A naive modulation approach would require training a hypernetwork with over three billion parameters. Through careful network design, we reduce this to be in line with existing encoders. HyperStyle yields reconstructions comparable to those of optimization techniques with the near real-time inference capabilities of encoders. Lastly, we demonstrate HyperStyle's effectiveness on several applications beyond the inversion task, including the editing of out-of-domain images which were never seen during training.

Inference Notebook:
Animation Notebook:


Given a desired input image, our hypernetworks learn to modulate a pre-trained StyleGAN network to achieve accurate image reconstructions in editable regions of the latent space. Doing so enables one to effectively apply techniques such as StyleCLIP and InterFaceGAN for editing real images.

Description

Official Implementation of our HyperStyle paper for both training and evaluation. HyperStyle introduces a new approach for learning to efficiently modify a pretrained StyleGAN generator based on a given target image through the use of hypernetworks.

Getting Started

Prerequisites

  • Linux or macOS
  • NVIDIA GPU + CUDA CuDNN (CPU may be possible with some modifications, but is not inherently supported)
  • Python 3

Installation

  • Dependencies: We recommend running this repository using Anaconda.
    All dependencies for defining the environment are provided in environment/hyperstyle_env.yaml.

Pretrained HyperStyle Models

In this repository, we provide pretrained HyperStyle models for various domains.
All models make use of a modified, pretrained e4e encoder for obtaining an initial inversion into the W latent space.

Please download the pretrained models from the following links.

Path Description
Human Faces HyperStyle trained on the FFHQ dataset.
Cars HyperStyle trained on the Stanford Cars dataset.
Wild HyperStyle trained on the AFHQ Wild dataset.

Auxiliary Models

In addition, we provide various auxiliary models needed for training your own HyperStyle models from scratch.
These include the pretrained e4e encoders into W, pretrained StyleGAN2 generators, and models used for loss computation.


Pretrained W-Encoders

Path Description
Faces W-Encoder Pretrained e4e encoder trained on FFHQ into the W latent space.
Cars W-Encoder Pretrained e4e encoder trained on Stanford Cars into the W latent space.
Wild W-Encoder Pretrained e4e encoder trained on AFHQ Wild into the W latent space.

StyleGAN2 Generators

Path Description
FFHQ StyleGAN StyleGAN2 model trained on FFHQ with 1024x1024 output resolution.
LSUN Car StyleGAN StyleGAN2 model trained on LSUN Car with 512x384 output resolution.
AFHQ Wild StyleGAN StyleGAN-ADA model trained on AFHQ Wild with 512x512 output resolution.
Toonify Toonify generator from Doron Adler and Justin Pinkney converted to Pytorch using rosinality's conversion script, used in domain adaptation.
Pixar Pixar generator from StyleGAN-NADA used in domain adaptation.

Note: all StyleGAN models are converted from the official TensorFlow models to PyTorch using the conversion script from rosinality.


Other Utility Models

Path Description
IR-SE50 Model Pretrained IR-SE50 model taken from TreB1eN for use in our ID loss and encoder backbone on human facial domain.
ResNet-34 Model ResNet-34 model trained on ImageNet taken from torchvision for initializing our encoder backbone.
MoCov2 Model Pretrained ResNet-50 model trained using MOCOv2 for computing MoCo-based loss on non-facial domains. The model is taken from the official implementation.
CurricularFace Backbone Pretrained CurricularFace model taken from HuangYG123 for use in ID similarity metric computation.
MTCNN Weights for MTCNN model taken from TreB1eN for use in ID similarity metric computation. (Unpack the tar.gz to extract the 3 model weights.)

By default, we assume that all auxiliary models are downloaded and saved to the directory pretrained_models. However, you may use your own paths by changing the necessary values in configs/path_configs.py.



Training

Preparing your Data

In order to train HyperStyle on your own data, you should perform the following steps:

  1. Update configs/paths_config.py with the necessary data paths and model paths for training and inference.
dataset_paths = {
    'train_data': '/path/to/train/data'
    'test_data': '/path/to/test/data',
}
  1. Configure a new dataset under the DATASETS variable defined in configs/data_configs.py. There, you should define the source/target data paths for the train and test sets as well as the transforms to be used for training and inference.
DATASETS = {
	'my_hypernet': {
		'transforms': transforms_config.EncodeTransforms,   # can define a custom transform, if desired
		'train_source_root': dataset_paths['train_data'],
		'train_target_root': dataset_paths['train_data'],
		'test_source_root': dataset_paths['test_data'],
		'test_target_root': dataset_paths['test_data'],
	}
}
  1. To train with your newly defined dataset, simply use the flag --dataset_type my_hypernet.

Preparing your Generator

In this work, we use rosinality's StyleGAN2 implementation. If you wish to use your own generator trained using NVIDIA's implementation there are a few options we recommend:

  1. Using NVIDIA's StyleGAN2 / StyleGAN-ADA TensorFlow implementation.
    You can then convert the TensorFlow .pkl checkpoints to the supported format using the conversion script found in rosinality's implementation.
  2. Using NVIDIA's StyleGAN-ADA PyTorch implementation.
    You can then convert the PyTorch .pkl checkpoints to the supported format using the conversion script created by Justin Pinkney found in dvschultz's fork.

Once you have the converted .pt files, you should be ready to use them in this repository.


Training HyperStyle

The main training script can be found in scripts/train.py.
Intermediate training results are saved to opts.exp_dir. This includes checkpoints, train outputs, and test outputs.
Additionally, if you have tensorboard installed, you can visualize tensorboard logs in opts.exp_dir/logs.

Training HyperStyle with the settings used in the paper can be done by running the following command. Here, we provide an example for training on the human faces domain:

python scripts/train.py \
--dataset_type=ffhq_hypernet \
--encoder_type=SharedWeightsHyperNetResNet \
--exp_dir=experiments/hyperstyle \
--workers=8 \
--batch_size=8 \
--test_batch_size=8 \
--test_workers=8 \
--val_interval=5000 \
--save_interval=10000 \
--lpips_lambda=0.8 \
--l2_lambda=1 \
--id_lambda=0.1 \
--n_iters_per_batch=5 \
--max_val_batches=150 \
--output_size=1024 \
--load_w_encoder \
--w_encoder_checkpoint_path pretrained_models/faces_w_encoder \ 
--layers_to_tune=0,2,3,5,6,8,9,11,12,14,15,17,18,20,21,23,24

Additional Notes:

  • To select which generator layers to tune with the hypernetwork, you can use the --layers_to_tune flag.
    • By default, we will alter all non-toRGB convolutional layers.
  • ID/similarity losses:
    • For the human facial domain we use a specialized ID loss based on a pretrained ArcFace network. This is set using the flag --id_lambda=0.1.
    • For all other domains, please set --id_lambda=0 and --moco_lambda=0.5 to use the MoCo-based similarity loss from Tov et al.
      • Note, you cannot set both id_lambda and moco_lambda to be active simultaneously.
  • You should also adjust the --output_size and --stylegan_weights flags according to your StyleGAN generator.
  • To use the HyperStyle with Refinement Blocks based on separable convolutions (see the ablation study), you can set the encoder_type to SharedWeightsHyperNetResNetSeparable.
  • See options/train_options.py for all training-specific flags.

Pre-Extracting Initial Inversions:

To provide a small speed-up and slightly reduce memory consumption, we could pre-extract all the latents and inversions from our W-encoder rather than inverting on the fly during training.
We provide an example for how to do this in configs/data_configs.py under the ffhq_hypernet_pre_extract dataset.
Here, we must define:

  • train_source_root: the directory holding all the initial inversions
  • train_target_root: the directory holding all target images (i.e., original images)
  • train_latents_path: the .npy file holding the latents for the inversions of the form
    latents = { "0.jpg": latent, "1.jpg": latent, ... }.

And similarly for the test dataset.

Performing the above and pre-extracting the latents and inversions could also allow you to train HyperStyle using latents from various encoders such as pSp, e4e, and ReStyle into W+ rather than using our pretrained encoder into W.

During training, we will use the LatentsImagesDataset for loading the inversion, latent code, and target image.


Inference

Inference Notebooks

To help visualize the results of ReStyle we provide a Jupyter notebook found in notebooks/inference_playground.ipynb.
The notebook will download the pretrained models and run inference on the images found in notebooks/images or on images of your choosing. It is recommended to run this in Google Colab.

We have also provided a notebook for generating interpolation videos such as those found in the project page. This notebook can be run using Google Colab here.


Inference Script

You can use scripts/inference.py to apply a trained HyperStyle model on a set of images:

python scripts/inference.py \
--exp_dir=/path/to/experiment \
--checkpoint_path=experiment/checkpoints/best_model.pt \
--data_path=/path/to/test_data \
--test_batch_size=4 \
--test_workers=4 \
--n_iters_per_batch=5 \
--load_w_encoder \
--w_encoder_checkpoint_path /path/to/w_encoder.pt

This script will save each step's outputs in a separate sub-directory (e.g., the outputs of step i will be saved in /path/to/experiment/inference_results/i). In addition, side-by-side reconstruction results will be saved to /path/to/experiment/inference_coupled.

Notes:

  • By default, the images will be saved at their original output resolutions (e.g., 1024x1024 for faces, 512x384 for cars).
    • If you wish to save outputs resized to resolutions of 256x256 (or 256x192 for cars), you can do so by adding the flag --resize_outputs.
  • This script will also save all the latents as an .npy file in a dictionary format as follows:
    • latents = { "0.jpg": latent, "1.jpg": latent, ... }
  • In addition, by setting the flag --save_weight_deltas, we will save the final predicted weight deltas for each image.
    • These will be saved as .npy files in the sub-directory weight_deltas.
    • Setting this flag is important if you would like to apply them for some down-stream task. For example, if you would like apply them for editing using StyleCLIP (see below).

Computing Metrics

Given a trained model and generated outputs, we can compute the loss metrics on a given dataset.
These scripts receive the inference output directory and ground truth directory.

python scripts/calc_losses_on_images.py \
--metrics lpips,l2,msssim \
--output_path=/path/to/experiment/inference_results \
--gt_path=/path/to/test_images

Here, we can compute multiple metrics using a comma-separated list with the flag --metrics.

Similarly, to compute the ID similarity:

python scripts/calc_losses_on_images.py \
--output_path=/path/to/experiment/inference_results \
--gt_path=/path/to/test_images

These scripts will traverse through each sub-directory of output_path to compute the metrics on each step's output images.


Editing


Editing results obtained via HyperStyle using StyleCLIP, InterFaceGAN, and GanSpace, respectively.

For performing inference and editing using InterFaceGAN (for faces) and GANSpace (for cars), you can run editing/inference_face_editing.py and editing/inference_cars_editing.py.


Editing Faces with InterFaceGAN:

python editing/inference_face_editing.py \
--exp_dir=/path/to/experiment \
--checkpoint_path=experiment/checkpoints/best_model.pt \
--data_path=/path/to/test_data \
--test_batch_size=4 \
--test_workers=4 \
--n_iters_per_batch=3 \
--edit_directions=age,pose,smile \
--factor_ranges=5

For InterFaceGAN we currently support edits of age, pose, and smile.


Editing Cars with GanSpace:

python editing/inference_cars_editing.py \
--exp_dir=/path/to/experiment \
--checkpoint_path=experiment/checkpoints/best_model.pt \
--data_path=/path/to/test_data \
--test_batch_size=4 \
--test_workers=4 \
--n_iters_per_batch=3

For GANSpace we currently support edits of pose, cube, color, and grass.

These scripts will perform the inversion immediately followed by the latent space edit.
For each image, we save the original image followed by the inversion and the resulting edits.


Editing Faces with StyleCLIP:

In addition, we support editing with StyleCLIP's global directions approach on the human faces domain. Editing can be performed by running editing/styleclip/edit.py. For example,

python editing/styleclip/edit.py \
--exp_dir /path/to/experiment \   
--weight_deltas_path /path/to/experiment/weight_deltas \
--neutral_text "a face" \
--target_tex "a face with a beard" \

Note: before running the above script, you need to install the official CLIP package:

pip install git+https://github.com/openai/CLIP.git

Note: we assume that latents.npy and the directory weight_deltas, obtained by running inference.py are both saved in the the given exp_dir.
For each input image we save a grid of results with different values of alpha and beta as defined in StyleCLIP.


Domain Adaptation


Domain adaptation results obtained via HyperStyle by applying the learned weight offsets to various fine-tuned generators.

In scripts/run_domain_adaptation.py, we provide a script for performing domain adaptation from the FFHQ domain to another (e.g., toons or sketches). Specifically, using a HyperStyle network trained on FFHQ, we can predict the weight offsets for a given input image. We can then apply the predicted weight offsets to a fine-tuned generator to obtain a translated image that better preserves the input image.

A example command is provided below:

python scripts/run_domain_adaptation.py \
--exp_dir /path/to/experiment \   
--checkpoint_path=experiment/checkpoints/best_model.pt \
--data_path=/path/to/test_data \
--test_batch_size=4 \
--test_workers=4 \
--load_w_encoder \
--w_encoder_checkpoint_path=pretrained_models/faces_w_encoder.pt \
--restyle_checkpoint_path=pretrained_models/restyle_e4e_ffhq_encode.pt \
--finetuned_generator_checkpoint_path=pretrained_models/pixar.pt \
--n_iters_per_batch=2 \
--restyle_n_iterations=2

Here, since we are performing a translation to a new domain, we recommend setting the number of iterations to a small number (e.g., 2-3).

Below we provide links the pre-trained ReStyle-e4e network and various fine-tuned generators.

Path Description
FFHQ ReStyle e4e ReStyle e4e trained on FFHQ with 1024x1024 output resolution.
Toonify Toonify generator from Doron Adler and Justin Pinkney converted to Pytorch using rosinality's conversion script, used in domain adaptation.
Pixar Pixar generator from StyleGAN-NADA used in domain adaptation.
Sketch Sketch generator from StyleGAN-NADA used in domain adaptation.
Disney Princess Disney princess generator from StyleGAN-NADA used in domain adaptation.

Repository structure

Path Description
hyperstyle Repository root folder
├  configs Folder containing configs defining model/data paths and data transforms
├  criteria Folder containing various loss criterias for training
├  datasets Folder with various dataset objects
├  docs Folder containing images displayed in the README
├  environment Folder containing Anaconda environment used in our experiments
├  editing Folder containing scripts for applying various editing techniques
├  licenses Folder containing licenses of the open source projects used in this repository
├ models Folder containing all the models and training objects
│  ├  encoders Folder containing various encoder architecture implementations such as the W-encoder, pSp, and e4e
│  ├  hypernetworks Implementations of our hypernetworks and Refinement Blocks
│  ├  mtcnn MTCNN implementation from TreB1eN
│  ├  stylegan2 StyleGAN2 model from rosinality
│  ├  hyperstyle.py Main class for our HyperStyle network
├  notebooks Folder with jupyter notebooks containing HyperStyle inference playgrounds
├  options Folder with training and test command-line options
├  scripts Folder with running scripts for training, inference, and metric computations
├  training Folder with main training logic and Ranger implementation from lessw2020
├  utils Folder with various utility functions

Related Works

Many GAN inversion techniques focus on finding a latent code that most accurately reconstructs a given image using a fixed, pre-trained generator. These works include encoder-based approaches such as pSp, e4e and ReStyle, and optimization techniques such as those from Abdal et al. and Zhu et al., among many others.

In contrast, HyperStyle learns to modulate the weights of a pre-trained StyleGAN using a hypernetwork to achieve more accurate reconstructions. Previous generator tuning approaches performed a per-image optimization for fine-tuning the generator weights (Roich et. al) or feature activations (Bau et al.).

Given our inversions we can apply off-the-shelf editing techniques such as StyleCLIP, InterFaceGAN, and GANSpace, even on the modified generator.

Finally, we can apply weight offsets learned on HyperStyle trained on FFHQ to fine-tuned generators such as those obtained from StyleGAN-NADA, resulting in more faithful translations.

Credits

StyleGAN2 model and implementation:
https://github.com/rosinality/stylegan2-pytorch
Copyright (c) 2019 Kim Seonghyeon
License (MIT) https://github.com/rosinality/stylegan2-pytorch/blob/master/LICENSE

IR-SE50 model and implementations:
https://github.com/TreB1eN/InsightFace_Pytorch
Copyright (c) 2018 TreB1eN
License (MIT) https://github.com/TreB1eN/InsightFace_Pytorch/blob/master/LICENSE

Ranger optimizer implementation:
https://github.com/lessw2020/Ranger-Deep-Learning-Optimizer
License (Apache License 2.0) https://github.com/lessw2020/Ranger-Deep-Learning-Optimizer/blob/master/LICENSE

LPIPS model and implementation:
https://github.com/S-aiueo32/lpips-pytorch
Copyright (c) 2020, Sou Uchida
License (BSD 2-Clause) https://github.com/S-aiueo32/lpips-pytorch/blob/master/LICENSE

pSp model and implementation:
https://github.com/eladrich/pixel2style2pixel
Copyright (c) 2020 Elad Richardson, Yuval Alaluf
License (MIT) https://github.com/eladrich/pixel2style2pixel/blob/master/LICENSE

e4e model and implementation:
https://github.com/omertov/encoder4editing
Copyright (c) 2021 omertov
License (MIT) https://github.com/omertov/encoder4editing/blob/main/LICENSE

ReStyle model and implementation:
https://github.com/yuval-alaluf/restyle-encoder
Copyright (c) 2021 Yuval Alaluf
License (MIT) https://github.com/yuval-alaluf/restyle-encoder/blob/main/LICENSE

StyleCLIP implementation:
https://github.com/orpatashnik/StyleCLIP
Copyright (c) 2021 Or Patashnik, Zongze Wu
https://github.com/orpatashnik/StyleCLIP/blob/main/LICENSE

StyleGAN-NADA models:
https://github.com/rinongal/StyleGAN-nada
Copyright (c) 2021 rinongal
https://github.com/rinongal/StyleGAN-nada/blob/main/LICENSE

Please Note: The CUDA files under the StyleGAN2 ops directory are made available under the Nvidia Source Code License-NC

Acknowledgments

This code borrows from pixel2style2pixel, encoder4editing, and ReStyle.

Citation

If you use this code for your research, please cite the following work:

@misc{alaluf2021hyperstyle,
      title={HyperStyle: StyleGAN Inversion with HyperNetworks for Real Image Editing}, 
      author={Yuval Alaluf and Omer Tov and Ron Mokady and Rinon Gal and Amit H. Bermano},
      year={2021},
      eprint={2111.15666},
      archivePrefix={arXiv},
      primaryClass={cs.CV}
}
Owner
Computer vision research scientist and enthusiast
Official implementation of "Learning to Discover Cross-Domain Relations with Generative Adversarial Networks"

DiscoGAN Official PyTorch implementation of Learning to Discover Cross-Domain Relations with Generative Adversarial Networks. Prerequisites Python 2.7

SK T-Brain 754 Dec 29, 2022
Hypersim: A Photorealistic Synthetic Dataset for Holistic Indoor Scene Understanding

The Hypersim Dataset For many fundamental scene understanding tasks, it is difficult or impossible to obtain per-pixel ground truth labels from real i

Apple 1.3k Jan 04, 2023
This is a repository of our model for weakly-supervised video dense anticipation.

Introduction This is a repository of our model for weakly-supervised video dense anticipation. More results on GTEA, Epic-Kitchens etc. will come soon

2 Apr 09, 2022
An open-source, low-cost, image-based weed detection device for fallow scenarios.

Welcome to the OpenWeedLocator (OWL) project, an opensource hardware and software green-on-brown weed detector that uses entirely off-the-shelf compon

Guy Coleman 145 Jan 05, 2023
Streamlit app demonstrating an image browser for the Udacity self-driving-car dataset with realtime object detection using YOLO.

Streamlit Demo: The Udacity Self-driving Car Image Browser This project demonstrates the Udacity self-driving-car dataset and YOLO object detection in

Streamlit 992 Jan 04, 2023
Deep Learning and Reinforcement Learning Library for Scientists and Engineers 🔥

TensorLayer is a novel TensorFlow-based deep learning and reinforcement learning library designed for researchers and engineers. It provides an extens

TensorLayer Community 7.1k Dec 29, 2022
Repo for paper "Dynamic Placement of Rapidly Deployable Mobile Sensor Robots Using Machine Learning and Expected Value of Information"

Repo for paper "Dynamic Placement of Rapidly Deployable Mobile Sensor Robots Using Machine Learning and Expected Value of Information" Notes I probabl

Berkeley Expert System Technologies Lab 0 Jul 01, 2021
Improving Deep Network Debuggability via Sparse Decision Layers

Improving Deep Network Debuggability via Sparse Decision Layers This repository contains the code for our paper: Leveraging Sparse Linear Layers for D

Madry Lab 35 Nov 14, 2022
Implementation of DocFormer: End-to-End Transformer for Document Understanding, a multi-modal transformer based architecture for the task of Visual Document Understanding (VDU)

DocFormer - PyTorch Implementation of DocFormer: End-to-End Transformer for Document Understanding, a multi-modal transformer based architecture for t

171 Jan 06, 2023
Multi Agent Path Finding Algorithms

MATP-solver Simulator collision check path step random initial states or given states Traditional method Seperate A* algorithem Confict-based Search S

30 Dec 12, 2022
Distributed DataLoader For Pytorch Based On Ray

Dpex——用户无感知分布式数据预处理组件 一、前言 随着GPU与CPU的算力差距越来越大以及模型训练时的预处理Pipeline变得越来越复杂,CPU部分的数据预处理已经逐渐成为了模型训练的瓶颈所在,这导致单机的GPU配置的提升并不能带来期望的线性加速。预处理性能瓶颈的本质在于每个GPU能够使用的C

Dalong 23 Nov 02, 2022
A repository with exploration into using transformers to predict DNA ↔ transcription factor binding

Transcription Factor binding predictions with Attention and Transformers A repository with exploration into using transformers to predict DNA ↔ transc

Phil Wang 62 Dec 20, 2022
MatryODShka: Real-time 6DoF Video View Synthesis using Multi-Sphere Images

Main repo for ECCV 2020 paper MatryODShka: Real-time 6DoF Video View Synthesis using Multi-Sphere Images. visual.cs.brown.edu/matryodshka

Brown University Visual Computing Group 75 Dec 13, 2022
SimDeblur is a simple framework for image and video deblurring, implemented by PyTorch

SimDeblur (Simple Deblurring) is an open source framework for image and video deblurring toolbox based on PyTorch, which contains most deep-learning based state-of-the-art deblurring algorithms. It i

220 Jan 07, 2023
A Pytorch Implementation for Compact Bilinear Pooling.

CompactBilinearPooling-Pytorch A Pytorch Implementation for Compact Bilinear Pooling. Adapted from tensorflow_compact_bilinear_pooling Prerequisites I

169 Dec 23, 2022
Real-time pose estimation accelerated with NVIDIA TensorRT

trt_pose Want to detect hand poses? Check out the new trt_pose_hand project for real-time hand pose and gesture recognition! trt_pose is aimed at enab

NVIDIA AI IOT 803 Jan 06, 2023
LabelImg is a graphical image annotation tool.

LabelImgPlus LabelImg is a graphical image annotation tool. This project is not updated with new functions now. More functions are supported with Labe

lzx1413 200 Dec 20, 2022
disentanglement_lib is an open-source library for research on learning disentangled representations.

disentanglement_lib disentanglement_lib is an open-source library for research on learning disentangled representation. It supports a variety of diffe

Google Research 1.3k Dec 28, 2022
RealFormer-Pytorch Implementation of RealFormer using pytorch

RealFormer-Pytorch Implementation of RealFormer using pytorch. Includes comparison with classical Transformer on image classification task (ViT) wrt C

Simo Ryu 90 Dec 08, 2022
RefineMask (CVPR 2021)

RefineMask: Towards High-Quality Instance Segmentation with Fine-Grained Features (CVPR 2021) This repo is the official implementation of RefineMask:

Gang Zhang 191 Jan 07, 2023