Giter Club home page Giter Club logo

dfmgan's Issues

关于KID指标的问题

你好,在生成的图片质量不差的情况下,为何我得到的kid指标为0.03几,想知道关于代码中计算kid的值是有什么讲究吗?
--我的超参数均设置为默认,图片为256*256,pretrain的kimg=3000,transfer的kimg=300

训练第二阶段显存不够

如题,本人使用单显卡12G训练,第一阶段的模型训练时刚好撑满,但是训练第二阶段就一直提示显存不够。

于是我尝试了许多办法,包括减小批次大小、channel数、设置nhwc,但是都失败了。

而且很奇怪的是,我做这些修改后所提示需要分配的显存都是一样的,这点很奇怪,应该是所需分配的显存会越来越少吧?不知道我哪里没理解对。

还是说只有resume第一个阶段生成的模型后就占了非常大的显存,很难再优化只能再从头训练一次?小白虚心请教。
Snipaste_2024-07-18_19-36-28

关于对比实验的方法

您好,Defect-GAN好像没有开源,您是自己复现的吗,能否提供一下这个方法的代码?

使用图片label作为生成条件的疑惑

注意到这行代码 c_dim=0 if self.transfer in ['res_block', 'res_block_match_dis', 'res_block_uni_dis']
想问一下,指定缺陷位置训练阶段,为什么不可以使用label同时作为生成条件?
根据您的代码,如果我要使用 --cond,正确方式应该是?

Runtime error when training: Torch grad

Describe the bug
When I run train.py (stage I), I get the following error: RuntimeError: derivative for aten::grid_sampler_2d_backward is not implemented

This happens in accumulate_gradients.

Thought it was related to nvidia (cuda) but now suspect internal torch issue.

  • Torch version: 2.0.1
  • cuda version: cuda_11.8.r11.8
  • Ubuntu OS
  • Running 1 GPU A10 on LambdaLabs.
  • python version: 3.8.10

Thoughts??? Time-sensitive issue 🙏🏼

bias_act和upfirdn2d插件问题

训练时一直显示ImportError: No module named bias_act_plugin和upfirdn2d_plugin的警告,发现在使用torch.utils.cpp_extension.load的时候没有生成bias_act.o、bias_act.cuda.o、bias_act_plugin.pyd这些文件,请问这该怎么解决?

Optimal Batch Size

For the sake of time, I am wondering if the default setting for batch size, which I believe is 16, is the optimal for this model. I am wondering if a batch size of 16 is too large and will potentially have the learning rate set too high.

配置问题

您好,
我原本使用torch 1.7.1+cu110的环境能跑您的训练和测试,然后今天突然不行了。upfirdn2d这步卡死,撤销后报错
报错信息:Failed to build CUDA kernels for upfirdn2d. UserWarning: Failed to build CUDA kernels for upfirdn2d.
image
image
随后去stylegan-ada Issue里面找,跟着下方图一的回答走更换成了 1.8.0+cu111,还是不行,试了不少方法没成功,您能给点建议么~
image

image

单张图片多种类型缺陷的生成

感谢您的工作!模型针对单个类型缺陷生成的效果不错,但是在我的数据集中,一张图片存在多种类型的缺陷,那么如果我需要生成包含多种缺陷的单个图像,那么我需要分别为每一类缺陷创建数据集,然后同时训练多个模型,每个模型生成一类缺陷然后再图片上叠加吗?这样操作过于复杂,而且生成的缺陷在下一步缺陷生成时会互相干扰吗?
我的GPU内存只有6G,我可以调整哪些参数减小模型的尺寸呢?

生成图像效果问题

这是grid_bent类
image
这是carpet_hole类
image

以上都是模型的默认配置,请问作者是如何克服这几种生成图片过差的问题的呢?使用了什么筛选方法吗?

环境问题

您好,我的cuda环境是11.3,readme里面python及pytorch版本最高只支持到cuda11.1。请问有其他的环境可以使用吗?

運行環境

請問這可以在windows上運行嗎?
你這邊寫Stylegan2不支持windows,但stylegan2裡寫了支持windows

謝謝

Training MVTec Wood datasets & Different inference results

Hi, I am graduate student in korea.
I want to generate various defective industrial data images by utilizing your model,
so before handling our datas, I use MVTec Wood datasets (Defect : Scratch) to confirm and check the model's performances.

But, when I train model and inference with wood datasets, Its result is quite different with your paper's result.
Both Good and Mask images have not good quality than I expected. (Furthermore, It occurs Overfitting after 400 kimg in good images / Generated Defect images are not similar with MVTec dataset's original scratch things)

I want to know how to optimize the parameters ( that you used ) to develop image qualities.

  1. What parameters did you handle? (It may be a little rude, but I'm most curious about it.)

  2. Did you take other Augmentation tech except for ADA of StyleGAN2 - ADA ?

  3. This is different from the point, when I generate a defective image in my dataset, in that model, both normal and defect images are generated and combined from Latent vector, but can I modify the model by inputting it into the normal image I have without generating the generated image and combining it with the generated defective image? (just generating defect images from latent vectors, but not for normal images. because, I think generated normal images of my industrial dataset will have poor quaility.)

Thanks for reading!
I appreciate for your model services.

Seek error in Stage 2

Describe the bug
A clear and concise description of what the bug is.
Traceback (most recent call last):
File "train.py", line 651, in
main() # pylint: disable=no-value-for-parameter
File "/home/vision-ai/.local/lib/python3.6/site-packages/click/core.py", line 1128, in call
return self.main(*args, **kwargs)
File "/home/vision-ai/.local/lib/python3.6/site-packages/click/core.py", line 1053, in main
rv = self.invoke(ctx)
File "/home/vision-ai/.local/lib/python3.6/site-packages/click/core.py", line 1395, in invoke
return ctx.invoke(self.callback, **ctx.params)
File "/home/vision-ai/.local/lib/python3.6/site-packages/click/core.py", line 754, in invoke
return __callback(*args, **kwargs)
File "/home/vision-ai/.local/lib/python3.6/site-packages/click/decorators.py", line 26, in new_func
return f(get_current_context(), *args, **kwargs)
File "train.py", line 644, in main
subprocess_fn(rank=0, args=args, temp_dir=temp_dir)
File "train.py", line 478, in subprocess_fn
training_loop.training_loop(rank=rank, **args)
File "/home/vision-ai/nas_data/hmjung/2023/02.multi_channel/DFMGAN/training/training_loop.py", line 146, in training_loop
training_set = dnnlib.util.construct_class_by_name(**training_set_kwargs) # subclass of training.dataset.Dataset
File "/home/vision-ai/nas_data/hmjung/2023/02.multi_channel/DFMGAN/dnnlib/util.py", line 296, in construct_class_by_name
return call_func_by_name(*args, func_name=class_name, **kwargs)
File "/home/vision-ai/nas_data/hmjung/2023/02.multi_channel/DFMGAN/dnnlib/util.py", line 291, in call_func_by_name
return func_obj(*args, **kwargs)
File "/home/vision-ai/nas_data/hmjung/2023/02.multi_channel/DFMGAN/training/dataset.py", line 178, in init
raw_shape = [len(self._image_fnames)] + list(self._load_raw_image(0).shape)
File "/home/vision-ai/nas_data/hmjung/2023/02.multi_channel/DFMGAN/training/dataset.py", line 217, in _load_raw_image
image = np.load(f)
File "/opt/conda/lib/python3.6/site-packages/numpy/lib/npyio.py", line 426, in load
fid.seek(-min(N, len(magic)), 1) # back-up
io.UnsupportedOperation: seek

To Reproduce
Steps to reproduce the behavior:

  1. In Stage 2: Transfer Learning
    python train.py --data ./data/hazelnut_hole_mask.zip
    --outdir runs/hazelnut_hole --resume pkls/hazelnut_good.pkl
    --gpus 2 --kimg 400 --snap 10 --transfer res_block_match_dis
  2. Hello, Thanks for providing the code. The train in stage 1 went well, but in stage 2, during transfer learning using the mask file, a seek error occurs in the load part. how can i fix it?

Desktop (please complete the following information):

  • OS: Linux Ubuntu
  • PyTorch version : pytorch 1.7.1

Unable to train the defect mask

I trained self-built dataset with your code. However, during the defect transfer phase, I found that it is unable to generate defects and the corresponding masks when using the original settings. I tried to adjust the values of lambda-ms and lambda-match many times, defects finally generated when I reduce the value of lambda-match to 0.2 even more smaller. That is to say, mask matching operation hinders defect generation in my dataset. I am so confused, can you give me some suggestions? The following is the failure case of the mask generation.
image
image

some suggestion about the code

Thank you for sharing your code, the results of the experiment look great! However, I do have a few suggestions:
// 1. Regarding the issue of generating temporary files, it would be better to change it to "with tempfile.TemporaryDirectory(None, None, args.run_dir) as temp_dir:" to avoid any potential problems caused by default generation in /tmp.
// 2. Have you considered changing the code to a class-based approach? The current implementation of the training_loop function looks quite cumbersome.
// 3. When running the code, some .so files are generated in /raid/ubuntu/.cache/torch_extensions. If different versions of PyTorch are used, these files may become locked and cause the program to hang indefinitely.

In this case, simply deleting the temporary files should resolve the issue.

I Can't execute Pretrain.

Describe the bug
I get the attached error and can't run pretrain.
I was able to execute up to pre-processing.

To Reproduce
Steps to reproduce the behavior:

  1. In '...' directory, run command '...'
cd DFMGAN
python train.py --data ./data/hazelnut_good.zip --outdir runs/hazelnut_good --gpus 1 --kimg 3000
  1. See error (copy&paste full log, including exceptions and stacktraces).
/home/oshita-n/.pyenv/versions/anaconda3-2022.05/envs/dfmgan/lib/python3.8/site-packages/torch/nn/modules/module.py:1051: UserWarning: Named tensors and all their associated APIs are an experimental feature and subject to change. Please do not use them for anything important until they are released as stable. (Triggered internally at  /opt/conda/conda-bld/pytorch_1623448234945/work/c10/core/TensorImpl.h:1156.)
  return forward_call(*input, **kwargs)
Traceback (most recent call last):
  File "train.py", line 644, in <module>
    main() # pylint: disable=no-value-for-parameter
  File "/home/oshita-n/.pyenv/versions/anaconda3-2022.05/envs/dfmgan/lib/python3.8/site-packages/click/core.py", line 1130, in __call__
    return self.main(*args, **kwargs)
  File "/home/oshita-n/.pyenv/versions/anaconda3-2022.05/envs/dfmgan/lib/python3.8/site-packages/click/core.py", line 1055, in main
    rv = self.invoke(ctx)
  File "/home/oshita-n/.pyenv/versions/anaconda3-2022.05/envs/dfmgan/lib/python3.8/site-packages/click/core.py", line 1404, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/home/oshita-n/.pyenv/versions/anaconda3-2022.05/envs/dfmgan/lib/python3.8/site-packages/click/core.py", line 760, in invoke
    return __callback(*args, **kwargs)
  File "/home/oshita-n/.pyenv/versions/anaconda3-2022.05/envs/dfmgan/lib/python3.8/site-packages/click/decorators.py", line 26, in new_func
    return f(get_current_context(), *args, **kwargs)
  File "train.py", line 637, in main
    subprocess_fn(rank=0, args=args, temp_dir=temp_dir)
  File "train.py", line 472, in subprocess_fn
    training_loop.training_loop(rank=rank, **args)
  File "/home/oshita-n/github/DFMGAN/training/training_loop.py", line 532, in training_loop
    result_dict = metric_main.calc_metric(metric=metric, G=snapshot_data['G_ema'],
  File "/home/oshita-n/github/DFMGAN/metrics/metric_main.py", line 46, in calc_metric
    results = _metric_dict[metric](opts)
  File "/home/oshita-n/github/DFMGAN/metrics/metric_main.py", line 86, in fid50k_full
    fid = frechet_inception_distance.compute_fid(opts, max_real=None, num_gen=50000)
  File "/home/oshita-n/github/DFMGAN/metrics/frechet_inception_distance.py", line 29, in compute_fid
    mu_gen, sigma_gen = metric_utils.compute_feature_stats_for_generator(
  File "/home/oshita-n/github/DFMGAN/metrics/metric_utils.py", line 280, in compute_feature_stats_for_generator
    features = detector(images, **detector_kwargs)
  File "/home/oshita-n/.pyenv/versions/anaconda3-2022.05/envs/dfmgan/lib/python3.8/site-packages/torch/nn/modules/module.py", line 1051, in _call_impl
    return forward_call(*input, **kwargs)
RuntimeError: MALFORMED INPUT: lanes dont match

Expected behavior
A clear and concise description of what you expected to happen.

  • can execute

Desktop (please complete the following information):

  • OS: Ubuntu 20.04 on WSL
  • PyTorch version: 1.9.0, 1.9.1
  • CUDA toolkit version: 11.6
  • NVIDIA driver version: 526.98
  • GPU 2090ti
  • use Docker: No
    Additional context

I would like to know what libraries and OS versions you can reliably run.

About Stage2 resume the pretraining

您好,LdhIwh!!!首先感谢您将代码开源,我认为这对缺陷生成领域有着巨大贡献。同时,我有下面的一个问题,还望您指教。
在第一阶段训练好后,我尝试训练第二阶段。但是当训练到kimg=80.0时,程序意外停止(报错信息如下)。

numpy.core._exceptions.MemoryError: Unable to allocate 64.0 MiB for an array with shape (2048, 2048) and data type complex128

为了节约时间,当我再次尝试运行时,我更改了加载的预训练模型为network-snapshot-000080.pkl,执行命令为:

python train.py --data ./data/hazelnut_hole_mask.zip -outdir runs/hazelnut_hole \
--resume runs/hazelnut_hole/00000-hazelnut_hole_mask-auto1-kimg400-resumecustom/network-snapshot-000080.pkl \
--gpus 1 --kimg 400 --snap 10 --transfer res_block_match_dis

我想知道这是否会影响我的训练结果

Pytorch version Compatibility

I use PyTorch 2.3.1+cu118, 'conv2d_gradfix' and 'grid_sample_gradfix' operations are not supported, instead using basic 'torch.nn.functional.conv2d' and 'torch.nn.functional.grid_sample' operations. Also, RuntimeError has occurred that no function has been implemented to calculate the gradient for aten:grid_sampler_2d_backward.

Which PyTorch, Cuda version should I use to avoid errors and use that model well?

mismatch shape in stage2

Hi,
I got error when in the stage2

RuntimeError: output with shape [1, 512, 1, 1] doesn't match the broadcast shape [3, 512, 1, 1]

RuntimeError: DataLoader worker (pid(s) 68788) exited unexpectedly

Describe the bug
I have pre-trained a dataset with defect masks and normal images.

The pre-training process was completed successfully, but during the transfer process, the "pkls" folder and pkl files corresponding to "--resume" were not generated. I manually created the folder and copied the last pkl file from the "runs" folder to that location.

Afterwards, during the transfer process, an error occurs after tick 10. It seems that the error is happening in the Dataloader, but I'm not exactly sure of the cause.

My PC has a GeForce RTX 4080 GPU and an i5-10400F CPU.

To Reproduce
Steps to reproduce the behavior:

  1. python dataset_tool.py --source F:\DATASET\QFP_S\OK --dest ./data/qfp_ok.zip --width 256 --height 256
  2. python dataset_tool.py --source F:\DATASET\QFP_S\NG --source-mask F:\DATASET\QFP_S\NG_defect_mask --dest ./data/qfp_ng.zip --width 256 --height 256
  3. python train.py --data ./data/qfp_ok.zip --outdir runs/qfp_ok --gpus 1 --kimg 3000
  4. python train.py --data ./data/qfp_ng.zip --outdir runs/qfp_ng --resume pkls/qfp_ok.pkl --gpus 1 --kimg 400 --snap 10 --transfer res_block_match_dis

Expected behavior
A clear and concise description of what you expected to happen.

I hope the transfer learning process proceeds smoothly after resolving the error.

Screenshots
If applicable, add screenshots to help explain your problem.
image

Desktop (please complete the following information):

  • OS: Windows10
  • PyTorch version (e.g., pytorch 1.7.1) : 1.8.0+cu111
  • CUDA toolkit version (e.g., CUDA 11.0) : Cuda compilation tools, release 11.2, V11.2.152 Build cuda_11.2.r11.2/compiler.29618528_0
  • NVIDIA driver version : 545.84
  • GPU [e.g., Titan V, RTX 3090] : RTX 4080
  • Docker: did you use Docker? If yes, specify docker image URL (e.g., nvcr.io/nvidia/pytorch:20.12-py3) : NO

Additional context
Add any other context about the problem here.

a bug when read gray image

in file dataset_tool.py line 73

img = np.array(PIL.Image.open(fname))

need to be convert to

Load image and convert to RGB if needed.

img = np.array(PIL.Image.open(fname).convert('RGB'))

dataset_tool.py /gray scale image

When dealing with grayscale images in the grid class, how should the command in dataset_tool.py be configured?

The issue seems to be with this line:

img = np.concatenate((img, np.expand_dims(mask, axis=-1)), axis=2)
It appears to be causing the problem.

hazelnut hole defect train

Did you use any other augmentations while training for hazelnut hole defects?

Did you follow the method provided in the official GitHub exactly as it is for training hazelnut holes?

I resumed training for hole defects using the hazelnut good model you provided, but the performance seems different.

------------------------------ code
python train.py --data ./data/hazelnut_hole_mask.zip
--outdir runs/hazelnut_hole --resume pkls/hazelnut_good.pkl
--gpus 2 --kimg 400 --snap 10 --transfer res_block_match_dis

预训练时报错

预训练时报错,网上找不到相关的问题,可否给点提示

Traceback (most recent call last):
File "/home/zxy/exp/DFMGAN-main/train.py", line 645, in
main() # pylint: disable=no-value-for-parameter
File "/home/zxy/anaconda3/envs/dftgan/lib/python3.9/site-packages/click/core.py", line 1157, in call
return self.main(*args, **kwargs)
File "/home/zxy/anaconda3/envs/dftgan/lib/python3.9/site-packages/click/core.py", line 1078, in main
rv = self.invoke(ctx)
File "/home/zxy/anaconda3/envs/dftgan/lib/python3.9/site-packages/click/core.py", line 1434, in invoke
return ctx.invoke(self.callback, **ctx.params)
File "/home/zxy/anaconda3/envs/dftgan/lib/python3.9/site-packages/click/core.py", line 783, in invoke
return __callback(*args, **kwargs)
File "/home/zxy/anaconda3/envs/dftgan/lib/python3.9/site-packages/click/decorators.py", line 33, in new_func
return f(get_current_context(), *args, **kwargs)
File "/home/zxy/exp/DFMGAN-main/train.py", line 638, in main
subprocess_fn(rank=0, args=args, temp_dir=temp_dir)
File "/home/zxy/exp/DFMGAN-main/train.py", line 473, in subprocess_fn
training_loop.training_loop(rank=rank, **args)
File "/home/zxy/exp/DFMGAN-main/training/training_loop.py", line 532, in training_loop
result_dict = metric_main.calc_metric(metric=metric, G=snapshot_data['G_ema'],
File "/home/zxy/exp/DFMGAN-main/metrics/metric_main.py", line 46, in calc_metric
results = _metric_dictmetric
File "/home/zxy/exp/DFMGAN-main/metrics/metric_main.py", line 86, in fid50k_full
fid = frechet_inception_distance.compute_fid(opts, max_real=None, num_gen=50000)
File "/home/zxy/exp/DFMGAN-main/metrics/frechet_inception_distance.py", line 29, in compute_fid
mu_gen, sigma_gen = metric_utils.compute_feature_stats_for_generator(
File "/home/zxy/exp/DFMGAN-main/metrics/metric_utils.py", line 280, in compute_feature_stats_for_generator
features = detector(images, **detector_kwargs)
File "/home/zxy/anaconda3/envs/dftgan/lib/python3.9/site-packages/torch/nn/modules/module.py", line 1051, in _call_impl
return forward_call(*input, **kwargs)
RuntimeError: MALFORMED INPUT: lanes dont match

res_block_match_dis error

training/training_loop.py", line 368, in training_loop
assert phase_real_img.ndim == 4 and phase_real_img.shape[1] == 4
AssertionError

/opt/conda/lib/python3.8/multiprocessing/resource_tracker.py:216: UserWarning: resource_tracker: There appear to be 17 leaked semaphore objects to clean up at shutdown
warnings.warn('resource_tracker: There appear to be %d '

assert phase_real_img.ndim == 4 and phase_real_img.shape[1] == 4

When res_block_match_dis is enabled, the above error occurs.

One question on result of train

Hello, im a researcher on data augmentation for defect images

I trained your model(DFMGAN) twice for two kind of custom data

First was showing very good result.

But First stage(normal image training) of second data shows some curious results.

The trained model generate rotated image from normal dataset images.

image

Then, i found the augmentation options on training_options.json

There is "rotate90 : 1" on the file.

Can you explain why DFMGAN generates rotated images?

论文结果的复现

您好,
我这边想要复现论文的测试结果,但是使用Repo的代码测试的结果与论文的结果差别很大。您这边方便把你训练好的PreTrained Model上传供测试吗?

can you explain about DFMGAN args briefly?

Hello. Thank you for sharing such a great piece of work.
I'm curious about the following training options # DFMGAN args:
ft = None,
transfer = None,
res_st = None,
uni_st = None,
mask_threshold = None,
lambda_match = None,
mode_seek = None,
lambda_ms = None,
no_round = None,
tanh_k = None,
tanh_mask = None,
dmatch_scale = None
Could you explain them briefly?
And would you recommend changing these options for better results?

Single Image Generation?

Describe the Question
I am currently generating images based on my own dataset, and I want to generate individual snippets of the images. In other words, currently the model outputs an image of size 4x7. The description in the paper provides an option for a triplet like Figure 4 in the paper as well, but I want a single piece image. How can I do that?

SDGAN, Defect-GAN

Hello,

I have been studying the DFMGAN paper and found it to be immensely beneficial for my research on surface defect recognition. The concepts of SDGAN and Defect-GAN presented in the paper have particularly piqued my interest.

I am curious about how the SDGAN and Defect-GAN models have been implemented. If possible, could you provide links to any official or unofficial code repositories for these models? Access to such resources would be invaluable for understanding and possibly extending your work.

Thank you for your contributions to the field,

Best regards!

RuntimeError: Ninja is required to load C++ extensions

image
I had the run time error during running the code of train.py on defect-free images.

I installed the Ninja package inside my python environment, but the issue still persists.

will the version be an issue of causing this? (the pytorch version I used to be 2.2.1 and the cuda version is 11.8.

预训练时间

请问我用一张A40在无缺陷图像上训练StyleGAN2,大概需要多长时间呢?一直卡在这里正常吗?
image

it doesn't make any pkls/ng.pkl

  1. The readme instructs to use the pkl file generated in the pkls folder, but both the folder and the file cannot be found. Is it okay to use the network-snapshot-000400.pkl file from the runs folder instead?

  2. Is it correct to train NG with the OK pkl file generated during the first training, and then generate defects using the pkl file obtained after training NG? However, the generated images during the generation process do not show any markings on the mask file.
    image
    image
    image

显存不够,能否给点建议?

您好,
我电脑只有12G显存,请问可以跑stylegan2-ada么,能够给点建议(尝试调整batchsize,但会带来一些bug),谢谢~

Training Issue with Transistor Class

image

image

None of the defect classes for the transistor are being generated properly. Although the training images for the "good" class are created successfully, the images for all defect classes of the transistor are getting corrupted during Stage 2: Transfer learning when using the official GitHub command.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.