Giter VIP home page Giter VIP logo

920232796 / bert_seq2seq Goto Github PK

View Code? Open in Web Editor NEW
1.3K 13.0 206.0 3.53 MB

pytorch实现 Bert 做seq2seq任务,使用unilm方案,现在也可以做自动摘要,文本分类,情感分析,NER,词性标注等任务,支持t5模型,支持GPT2进行文章续写。

License: Apache License 2.0

Python 100.00%
bert seq2seq ner crf text-classification unilm pytorch roberta autotitle gpt2

bert_seq2seq's Introduction

Hi there 👋

  • 🔭 Graduate student
  • 😄 Like code
  • 📫 Welcome to QQ communication group:975907202

bert_seq2seq's People

Contributors

920232796 avatar zhiyuan-fan avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

bert_seq2seq's Issues

关于预测的问题

我感觉预测那里有点小问题。将输入和输出的句子拼接,搞成bert的输入形式进行输入,然后预测的时候,你这里是不是直接预测的就是这个拼接的句子,也就是说,你把输入的一部分也进行了预测??我不知道我理解的对不对。。。。望回答  谢谢了。

beam search issue

您好,大佬,首先非常感谢您的项目,我有个问题,请教下:
在beam search中,如果是batch输入的话,
logit_score = torch.log_softmax(scores, dim=-1)[:, -1] --> 不理解为什么会取最后一个的分数,按我的理解每个batch_size的文本长度应该是不一样的吧

这个时候该如何迭代生成最终结果呢?

1. 关于多卡训练支持建议。2. 关于tokenizer的pre_train建议。3. 关于外露模型配置API的建议。

  1. 参考 https://github.com/920232796/bert_seq2seq/blob/master/examples/nezha_auto_title_train.py ,使用torch.nn.DataParallel类写了一个多卡运行的版本。修改了一些源代码。因此给出example代码和对源代码做的修改以资参考。如果作者看到后能改改源代码就更好了,下次我升级后就快乐直接运行源代码不用自己手动改了!

nezha_auto_title_train.py做修改的核心代码在4个地方:一是增加 self.bert_model=torch.nn.DataParallel(self.bert_model,device_ids=[0,1])(建议在加载完预训练模型等在训练前需要对原self.bert_model做的处理都完成之后,如原代码167行 self.bert_model.load_pretrain_params(model_path) 之后)。二是在此后调用self.bert_model时改为调用self.bert_model.module,如原代码 self.bert_model.save_all_params(save_path) 需要改成self.bert_model.module.save_all_params(save_path),因为torch.nn.DataParallel会使原模型的方法不可见。三是这样直接得到的loss就不是一个元素而是多个元素,所以原代码第153行 report_loss += loss.item() 不可用。
参考#15 ,我把代码改成了这样:

loss=loss.mean()
report_loss += loss.item()

事实上我并不确定这样直接求平均是否正确……看起来应该是合理的……反正能跑起来了。
第四点是在forward()函数运行之前就手动把输入数据放置到模型初始卡上(原代码148-149行之间的位置):

token_ids=token_ids.to(self.device)
token_type_ids=token_type_ids.to(self.device)
target_ids=target_ids.to(self.device)

对源代码的修改:
bert_seq2seq/seq2seq_model.py
源代码69-75行手动将输入数据放置到模型初始卡上的代码删除:

input_tensor = input_tensor.to(self.device)
token_type_id = token_type_id.to(self.device)
if position_enc is not None:
    position_enc = position_enc.to(self.device)
if labels is not None :
    labels = labels.to(self.device)

原80行 ones = torch.ones((1, 1, seq_len, seq_len), dtype=torch.float32, device=self.device) 删除,83-84行之间添加 ones = torch.ones((1, 1, seq_len, seq_len), dtype=torch.float32, device=s_ex13.device)

另外还有一个不必要的优化工作:参考 https://blog.csdn.net/weixin_43301333/article/details/111386343 这篇博文的建议,把源代码第97行 return predictions, loss 改成了 return loss,然后nezha_auto_title_train.py原第149行 predictions, loss = self.bert_model(token_ids, 改成 loss = self.bert_model(token_ids,,因为反正predictions不需要,只输出loss能有效降低模型初始卡上的消耗,每个卡上每个batch能多放一条数据了。

  1. 苏神bert4keras项目的 https://github.com/bojone/bert4keras/blob/master/bert4keras/tokenizers.py 的TokenizerBase有个pre_tokenize参数,我看到您项目的 https://github.com/920232796/bert_seq2seq/blob/master/bert_seq2seq/tokenizer.py 中只有T5PegasusTokenizer加了这个参数,想请问您后续还更新BasicTokenizer类的pre_tokenize参数吗?
    我觉得这个参数看起来组合jieba.cut会很好用。
  2. 一是如前文第一条所述,有时想仅输出模型的loss,有时想输出模型的隐藏层向量,所以想问问您这边有没有什么策略能设置在调用时直接选择输出什么呢?
    二是希望能在调用时手动改模型的参数,如 https://github.com/920232796/bert_seq2seq/blob/master/bert_seq2seq/model/nezha_model.py 的BertConfig,之前2.3.2版本时 max_position_embeddings=2048 因为太大所以我手动改成了1024。希望能改成我可以在调用时就直接修改的方式。

如何使用问题?

up主 你好 非常感谢开源这么好的软件,对于非技术人员 在使用上有些吃力 可否出个适合小白用户的版本 见谅见谅

预训练权重问题

utils.py下的load_model_params函数只加载了Bert的权重(3个embedding层以及12个transformer块),但是没有加载decoder层(比如seq2seq任务的BertLMPredictionHead)参数,这是为什么?
(推测加载后效果会更好。)

def load_model_params(model, pretrain_model_path):
checkpoint = torch.load(pretrain_model_path)
# 模型刚开始训练的时候, 需要载入预训练的BERT
checkpoint = {k[5:]: v for k, v in checkpoint.items()
if k[:4] == "bert" and "pooler" not in k}
model.load_state_dict(checkpoint, strict=False)
torch.cuda.empty_cache()
print("{} loaded!".format(pretrain_model_path))

关于摘要自动生成

你好
我刚刚接触到这个领域,请问在做文章摘要生成时使用对联的例子是可以的吗?
在对联的seq2seq模型中只有一个bert作为encoder,这样子可以很好的完成seq2seq模型吗

代码问题 multi-head attention 中的 extended_attention_mask

在 bert_model.py 的 445行, 下面的代码好像有点问题:
extended_attention_mask = extended_attention_mask.unsqueeze(1).unsqueeze(2)
if attention_mask is not None :
## 如果传进来的注意力mask不是null,那就直接用传进来的注意力mask 乘 原始mask
# 注意 原始mask是extended_attention_mask,这个是用来把pad部分置为0,去掉pad部分影响
extended_attention_mask = attention_mask * extended_attention_mask

在原始的Bert代码中, 是这样的:
if attention_mask is None:
attention_mask = torch.ones_like(input_ids)
if token_type_ids is None:
token_type_ids = torch.zeros_like(input_ids)

    # We create a 3D attention mask from a 2D tensor mask.
    # Sizes are [batch_size, 1, 1, to_seq_length]
    # So we can broadcast to [batch_size, num_heads, from_seq_length, to_seq_length]
    # this attention mask is more simple than the triangular masking of causal attention
    # used in OpenAI GPT, we just need to prepare the broadcast dimension here.
    extended_attention_mask = attention_mask.unsqueeze(1).unsqueeze(2)

上面两种操作, 产生的 extended_attention_mask 是有差异的. 不过因为在本代码的训练过程中, attention_mask 一直为None, 所以训练过程没有问题, 但实际上代码可能存在问题

关于target_ids

在seq2seq模型中,我不明白为什么token_ids 去掉首字符 即CLS后,就是target_ids。例如在古诗词任务中,token_ids是 cls+标题+sep + 诗词 + sep,我理解targe_ids应该是 诗词,为什么代码中是 标题+sep+诗词+sep

预训练

您好,想问一个热别简单的问题。bert提供的预训练好的模型都训练好哪些参数呀? 难道和代码中初始化的参数不一样么?如果一样的话,随机初始化的话不相当于白训练了?谢谢!

`class BertPreTrainedModel(nn.Module):
""" An abstract class to handle weights initialization and
a simple interface for downloading and loading pretrained models.
"""

def __init__(self, config, *inputs, **kwargs):
    super(BertPreTrainedModel, self).__init__()
    if not isinstance(config, BertConfig):
        raise ValueError(
            "Parameter config in `{}(config)` should be an instance of class `BertConfig`. "
            "To create a model from a Google pretrained model use "
            "`model = {}.from_pretrained(PRETRAINED_MODEL_NAME)`".format(
                self.__class__.__name__, self.__class__.__name__
            ))
    self.config = config

def init_bert_weights(self, module):
    """ Initialize the weights.
    """
    if isinstance(module, (nn.Linear)):
        # 初始线性映射层的参数为正态分布
        module.weight.data.normal_(mean=0.0, std=self.config.initializer_range)
    elif isinstance(module, BertLayerNorm):
        # 初始化LayerNorm中的alpha为全1, beta为全0
        module.beta.data.zero_()
        module.gamma.data.fill_(1.0)
    if isinstance(module, nn.Linear) and module.bias is not None:
        # 初始化偏置为0
        module.bias.data.zero_()

`

关于标题分类的问题

我想对特定领域不同的句子进行一个分类,我参考了一下新闻标题分类的代码,但是我看到它的训练集的加载,那测试集和验证集应该怎么接入呢? 他们的格式是什么样的,大佬能发一份分类的数据 我想参考一下。我的邮箱:[email protected]

数据集下载

弱弱的问一句,数据集哪里可以下载到呀?

文本摘要的博客和数据集

大神,看了一下你的博客,并没有看到你有关文本摘要的文章。另外,我在网上找了一下,只找到两个数据集:LCSTS、教育培训行业抽象式自动摘要中文语料库。有一个NLPCC的数据链接应该是失效了。请问还有其他什么中文的数据集吗?

关于example中生成类模型token_type_ids 的padding问题和mask问题

您好,非常感谢您贡献了这么好的repo给我们试用和学习,有两个问题想请教一下,还请帮忙指点指点:

1.关于example中给出的训练代码,像写诗这样的需要生成序列的任务中,我观察到collate_fn这个函数中的token_ids_padded和token_type_ids_padded调用的padding方法中,padding试用的id是0,但是对于输入中有2个序列的情况,如果padding id是0,不就是说补的padding token是属于第一个sequence了吗?但其实位置是在第二个sequence的,这个会不会对模型训练造成影响呢?
代码如下:
def collate_fn(batch):
"""
动态padding, batch为一部分sample
"""

def padding(indice, max_length, pad_idx=0):
    """
    pad 函数
    """
    pad_indice = [item + [pad_idx] * max(0, max_length - len(item)) for item in indice]
    return torch.tensor(pad_indice)

token_ids = [data["token_ids"] for data in batch]
max_length = max([len(t) for t in token_ids])
token_type_ids = [data["token_type_ids"] for data in batch]

token_ids_padded = padding(token_ids, max_length)
token_type_ids_padded = padding(token_type_ids, max_length)
target_ids_padded = token_ids_padded[:, 1:].contiguous()

return token_ids_padded, token_type_ids_padded, target_ids_padded

我个人认为 token_type_ids_padded = padding(token_type_ids, max_length)需要传一个pad_idx=1参数,请问下这样是否才正确,不对也请帮忙指正

2.Seq2SeqModel中forward函数中,构建特殊的mask这里,s_ex12 和s_ex13这两个mask和a_mask = (1.0 - s_ex12) * (1.0 - s_ex13) + s_ex13 * a_mask的计算方法不是很理解,可否帮忙指点或者提供一点参考链接?

感激不尽

NEZHA 模型 长度超过512 报错!

image
您好,请问我在使用nezha这个预训练模型做文本摘要时,为什么长度超过512,会报错呢?还是您的内部没有相应的相对位置编码实现呢?

unilm问题

您好,我对unilm的理解是:它是在bert的基础上进行fineturn,只不过微调过程中对mask方式进行了更改。不知道我这样的理解对不对。

关于输入mask的问题

原本的bert的输入是需要75%的mask的,但是我看您的输入好像没有这一部分,请问是不是因为attenion mask存在的缘故??

找不到_token_unk_id

执行对联_train.py时,报下面的错误了。全局找了一下_token_unk_id,好像忘了定义吧。
File "/home/workspace/pycharm/bert_seq2seq/bert_seq2seq/tokenizer.py", line 191, in token_to_id
return self._token_dict.get(token, self._token_unk_id)
AttributeError: 'Tokenizer' object has no attribute '_token_unk_id'

关于多卡训练

现在的代码只支持单卡训练,为了改成多GPU并行训练,加了DistributedDataParallel。报错
RuntimeError: grad can be implicitly created only for scalar outputs
好像是loss.backward()的错误
请问有尝试修改代码做多GPU训练吗?

模型加载输出问题

首先,非常感谢大佬能开源这么优秀的工具。
我是个小白,在训练完模型以后,使用test目录下的auto_title_test.py,test_data没有变,为什么输出是17,8,10三个数字?大佬能教下怎么用吗?

你好运行的时候报错

Error(s) in loading state_dict for BertSeqLabelingCRF:
Missing key(s) in state_dict: "transform.dense.weight", "transform.dense.bias", "transform.LayerNorm.weight", "transform.LayerNorm.bias", "final_dense.weight", "final_dense.bias", "crf_layer.trans".
Unexpected key(s) in state_dict: "cls.predictions.bias", "cls.predictions.transform.dense.weight", "cls.predictions.transform.dense.bias", "cls.predictions.transform.LayerNorm.weight", "cls.predictions.transform.LayerNorm.bias", "cls.predictions.decoder.weight", "cls.seq_relationship.weight", "cls.seq_relationship.bias".

UNILM的Attention Mask设置问题。

楼主你好,我对于这个attention的mask还有一点小问题。
目前我在处于测试阶段,生成任务就是简单的复制,给5个数字,然后生成相同的5个数字。这个任务应该很简答, 所以我就用了bert和一个全连接softmax就结束了。

在训练过程中我对这个attention的mask设置有了点问题,如下:
举个例子,batch_size=1,我的5个数字是12345。
我在训练的过程中设置了最大长度是15,我给的输入是:
[[CLS],1,2,3,4,5,[SEP],1,2,3,4,5, [PAD],[PAD]]
7个字符的segment_0,6个segment_1,还有2个pad。
这里我不知道第二个句子要不要加SEP,因为我们是生成任务,如果给了[SEP],那到最后一个SEP的时候我生成出来的应该是啥。。

第二个就是attention mask, 如上文,我的输入是size:[1,15]
所以这个attention mask我就设置的是size[1,15,15]
和楼主图里的设置一样,segment_0的mask全部为1,这样mask矩阵的前7行就是7个1加上8个0
之后segment_1,第一个数字的生成,attention不到自己,也是7个1加上8个0,么?
之后第二个数字,就是8个1加上7个0,以此类推。
最后两行的PAD就全部0.
具体的矩阵就是下面这样的,有点大,辛苦楼主了。

  ([[1., 1., 1., 1., 1., 1., 1., 0., 0., 0., 0., 0., 0., 0., 0.],
    [1., 1., 1., 1., 1., 1., 1., 0., 0., 0., 0., 0., 0., 0., 0.],
    [1., 1., 1., 1., 1., 1., 1., 0., 0., 0., 0., 0., 0., 0., 0.],
    [1., 1., 1., 1., 1., 1., 1., 0., 0., 0., 0., 0., 0., 0., 0.],
    [1., 1., 1., 1., 1., 1., 1., 0., 0., 0., 0., 0., 0., 0., 0.],
    [1., 1., 1., 1., 1., 1., 1., 0., 0., 0., 0., 0., 0., 0., 0.],
    [1., 1., 1., 1., 1., 1., 1., 0., 0., 0., 0., 0., 0., 0., 0.],
    [1., 1., 1., 1., 1., 1., 1., 0., 0., 0., 0., 0., 0., 0., 0.],
    [1., 1., 1., 1., 1., 1., 1., 1., 0., 0., 0., 0., 0., 0., 0.],
    [1., 1., 1., 1., 1., 1., 1., 1., 1., 0., 0., 0., 0., 0., 0.],
    [1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 0., 0., 0., 0., 0.],
    [1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 0., 0., 0., 0.],
    [1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 0., 0., 0.],
    [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
    [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]])

不知道这样的attentionmask对不对,因为我最后生成出来的效果不好,经常是全5,全7,全PAD,不会完整的复制。

数据集问题

请问一下,./state_dict/里的数据有资源可以下载吗?

关于beam search预测输出,请教一个问题

大概看了一下seq2seq_model.py文件里的beam search方法的代码,有几个疑惑点请作者解答下哈:

  1. 对于预测,假设我有一个句子“你好啊”,对于模型的token_id应该是[[CLS], 你, 好, 啊, [SEP], [PAD]],那对应的segment_id是这样的吗:[0, 0, 0, 0, 0, 0](看了生成token那段代码,发现输入似乎只能这样),那么预测的第一个字是基于输入文本的[SEP]这个符号来的吗?其实,就是我没有理解预测阶段是从哪个字符开始的哈以及输入形式是怎样的。。。
  2. 看到代码这一段,seq2seq_model.py的221行:
# 用来保存累计得分        
        output_scores = torch.zeros(token_ids.shape[0], device=device)
        for step in range(self.out_max_length):
            scores = self.forward(token_ids, token_type_ids, device=device) --> 这边输出的应该是[batch_size, sen_len, vocab_size]吧
            if step == 0:
                # 重复beam-size次 输入ids
                token_ids = token_ids.view(1, -1).repeat(beam_size, 1)
                token_type_ids = token_type_ids.view(1, -1).repeat(beam_size, 1)
            ## 计算log 分值 (beam_size, vocab_size)
            logit_score = torch.log_softmax(scores, dim=-1)[:, -1] --> 不理解为什么会取最后一个的分数,按我的理解每个batch_size的文本长度应该是不一样的吧
            logit_score = output_scores.view(-1, 1) + logit_score # 累计得分
            ## 取topk的时候我们是展平了然后再去调用topk函数

上面两个箭头是我的疑问哈,希望作者解答下哈,不胜感激~

roberta_auto_title_train.py

请问这个代码所需的文件是不全的吗?如./state_dict/文件下的roberta_wwm_vocab.txt等?

关于医学代码的问题

大佬你好我是一个刚接触实体识别的萌新,看了你的代码有几个问题请教:
1.这个医学的medical_ner_update.txt在哪里下载呀?
2.这个医学的代码可以用bert模型跑吗?直接运行吗?
还希望大佬告知一下。刚接触懂得太少了,谢谢。

关于生成摘要的使用

您好
我想请问下关于生成摘要的模型使用,我想利用这个模型做一些新闻摘要,请问我应该怎么使用,我是需要每次把需要生成的文本放入testdata中进行二十轮的结训练得到结果,还是需要利用生成的bin文件来做,如果是后者,该怎么利用这个bin文件即bert_auto_title_model.bin

疑似bug

hello, 感谢您的分享。 在bert_seq2seq/model/bert_model.py 的 409行, 这里在给BertLayerNorm初始化的时候初始化的alpha, gamma好像没有诶, 这里是不是应该是weight和bias呢。

情感分析问题

大佬 我想用您的bert+crf做个情感分析的模型 比如分析一个评论是好评还是差评 该怎么做呢

粗粒度NER-tokenizer问题

在NER中, 一个比较容易出错的地方是由于tokenizer以后, 导致 句子和原始输入的句子长度、token的位置不一致.
在 tokenier.py的代码中, 好像并没有解决 tokenizer输入和输出长度不一致的问题.
例如, 在读入 粗粒度NER的语料后,
sents_src, sents_tgt = read_corpus(data_path)
其中的 sents_src[3], sents_tgt[3], 经过 tokenizer以后, 长度并一致, 这样会报错.

您好,作者请问您有在一些官方的数据集上面测试过准确性吗?

最近在看一个天池大数据的中医药文本生成比赛,我用了微软开源的Unlim代码加载roberta wwm ext的权重后5轮迭代(2-3小时),基本已经收敛,并且提交后的结果有54+。用您开源的代码运行了一晚上,但是loss在2.XX后就不再收敛,最终效果也不是很好,提交后只有27.XX。
作者有在一些官方的数据集上和微软的代码对比过准确率吗,在同样的数据集上准确率是否可以达到微软开源代码的效果。

如果要使用英文数据集需要更改什么

感谢作者带来如此优秀的项目!
我现在想用您的项目中的三元组关系抽取来处理一些英文的数据集。
在自己看来,除了要使用Bert的英文预训练模型之外,请问是否还需要在tokenizer.py 上做修改呢?

咨询下文本生成的几个细节

非常感谢您开源这个项目,让我学习了bert做文本生成的**方法,还有几个问题想请教一下。

1.训练的数据的生成,一种是文本对[cls] source [sep] target [eos] [sep],另一种是拼在一起[cls] source target [eos] [sep],您认为这两种那种更合理呢?我倾向前者

2.预测下一个字符,是采用[cls]的分类吗。比如输入1234,我要预测 5678,[cls] 1 2 3 4 [sep] 5 6 [sep],是[cls]预测 7 吗?还是6这个位置的tensor预测7?

3.我看了前面的issue,如果只做文本生成,重点应该是target,训练的时候没必要计算source 的loss吧,应该是只需要对target位置进行attention mask然后计算target部分的loss就可以了吧。

4.Seq2SeqModel中的forward函数我看到了tril下三角函数,还有修改了BertModel中的extended_attention_mask。训练过程中,source =1234,target = 5678。传进去12345678,是可以一次自动mask5678后面位置字符,一起预测概率计算损失;还是要手动处理做四次不同的mask,1234mmmm->5、12345mmm->6、123456mm->7、1234567m->8

感谢您的解答!

seq2seq的loss计算问题

seq2seq_model.py 108行
需要构建特殊的输出mask,屏蔽掉句子a的影响
预测的值不用取最后sep符号的结果 因此是到-1
predictions = predictions[:, :-1].contiguous()
target_mask = token_type_id[:, 1:].contiguous()

为什么target_mask是丢掉了[CLS]位,而predictions是丢掉[SEP]位,这在计算Loss的时候不是错位了么?

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.