Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >一学就会!快来查收这份 MMPose 学习指南

一学就会!快来查收这份 MMPose 学习指南

作者头像
OpenMMLab 官方账号
发布于 2022-04-09 08:50:14
发布于 2022-04-09 08:50:14
2.3K00
代码可运行
举报
文章被收录于专栏:OpenMMLabOpenMMLab
运行总次数:0
代码可运行

前言

对于 MMPose 我是慕名已久,一直以来跟不少做 Pose 的大佬交流时也常常提起,说同样的模型用 MMPose 跑出来点数会高不少,然而 MM 系列的封装逻辑和学习门槛让我一再搁置,终于最近才下定决心要把它啃下来。

本系列将记录我第一次接触 MMPose 系列的学习轨迹,学习思路,以及过程中的一些心得体会。

由于我目前主要研究领域是轻量级的手部姿态估计,据我初步观察,MMPose 复现的工作主要集中在 Heatmap-based 方法,因此我也希望之后有机会给 MMPose 做一些 PR,将我复现的近期的一些 Regression-based 方法加入其中,这算是我为本次学习立的一个小目标。

初步计划

由于是第一次接触,我给自己粗略列出了一个学习计划,依次进行完成,以对 MMPose 的基本功能有一个直观的感受:

· 基于预训练模型,在自己的图片上进行推理测试

· 编写一个脚本,在本地摄像头上进行实时推理

· 导出 ONNX 格式文件,测试转 MNN 流程,校验转换后的模型精度损失

我希望通过以上内容让我搞清楚:

· MMPose 代码运行的参数含义和逻辑

· 数据处理流程和封装逻辑

· 模型导出和部署验证

· MMPose 推理阶段的数据处理流程

在后续的笔记中我会继续以这样一种学习计划的形式层层递进,这些计划是我在学习之前列出的,因此可能有一些计划是在学习之后发现不必自己实现的,但我依然这样列出来,记录自己的整个思维过程。

预训模型推理

在 fork+clone 到本地后,我打开了 MMPose 的文档,进行最简单的预训练模型推理实验。

文档地址如下:

https://mmpose.readthedocs.io/zh_CN/latest/demo.html

通过目录可以看到,MMPose 对于市面上大部分的关键点人物数据集都有支持,并编写了对应的 demo 示例,我在简单浏览后选择测试在 onehand10k 数据集上预训练的,基于 deeppose 方法的 res50 模型。

所谓 deeppose 方法其实就是最原始的 Regression-based 方法,即直接用全连接层回归得到关键点坐标值。

我注意到 MMPose 对于 3D Hand 数据集并没有 Regression-based 方法支持,这将是我之后会尝试添加的内容(挖坑待填)。

来到 Model Zoo 页面,下载我所需要的 deeppose_resnet_50 模型的 ckpt 文件,我在 MMPose 本地目录中创建了一个 models 目录用于存放预训练模型。

随后找到示例页面 2D Hand Image Demo,发现推理 demo 给了两个版本,分别是直接推理和带检测器的推理,出于简便考虑,我尝试了带检测器的版本,因此额外安装了 MMDetection 库,目前 MMPose 和 MMDetection 都对 Windows 进行了支持,可以很容易地通过 pip 进行安装:

pip install mmdet

带检测器的 demo 说明上也给出了 det model 的参数下载界面:

将检测器所需要的 cascade_rcnn_x101_64x4d_fpn_20e_onehand10k-dac19597_20201030.pth 文件也放到 models 目录下后,终于可以正式进行推理了。

可以看到运行代码样例给得非常完整,并且 demo 支持本地文件和远程下载两种方式获取模型权重,由于我已经下载到本地了,因此只需要对参数进行稍微的修改:

python demo/top_down_img_demo_with_mmdet.py \

demo/mmdetection_cfg/cascade_rcnn_x101_64x4d_fpn_1class.py \

models/cascade_rcnn_x101_64x4d_fpn_20e_onehand10k-dac19597_20201030.pth \

configs/hand/2d_kpt_sview_rgb_img/deeppose/onehand10k/res50_onehand10k_256x256.py \

models/deeppose_res50_onehand10k_256x256-cbddf43a_20210330.pth \

--img-root tests/data/onehand10k/ \

--img 9.jpg \

--out-img-root vis_results

运行结果保存到了自动新建的 vis_results 目录下:

看来结果还是不错的,但这毕竟是 onehand10k 数据集有的图片,而且作为 demo 样例效果好是很正常的,于是我又自己找了一张图片进行测试:

果然对于真实场景下的图片表现就不那么让人满意了,可以看到大拇指指尖的位置明显错了,不过这是在意料之中的,只使用 onehand10k 一个数据集训练得到的模型在这种业务数据上表现不佳很正常。

此时我突然灵光一闪,Regression-based 方法表现不佳,那么 Heatmap-based 方法训练出来的模型是否泛化性能会更好呢?毕竟直接监督高斯热图的方式,按理来说对于局部特征的捕捉泛化能力是会强于回归方法的,所以我又实验了 Topdown Heatmap + Resnet50 模型。

从 Model Zoo 的结果上显示,Heatmap 训练的 Resnet50 模型 AUC 达到了 0.555,而回归方法训练的 AUC 只有 0.486,高斯热图果然名不虚传,那么实际表现怎么样呢:

python demo/top_down_img_demo_with_mmdet.py \

demo/mmdetection_cfg/cascade_rcnn_x101_64x4d_fpn_1class.py \

models/cascade_rcnn_x101_64x4d_fpn_20e_onehand10k-dac19597_20201030.pth \

configs/hand/2d_kpt_sview_rgb_img/topdown_heatmap/onehand10k/res50_onehand10k_256x256.py \ https://download.openmmlab.com/mmpose/top_down/resnet/res50_onehand10k_256x256-e67998f6_20200813.pth \

--img-root tests/data/cchand/ \

--img test.jpg \

--out-img-root vis_results

很容易看出,出来的结果更烂(狗头),我真不是故意要黑它的,图片我都是随机选的(摊手)。

但分析一下这结果其实也不意外,这张图片中手指根部受到了遮挡,对于 Heatmap-based 方法而言,如果训练时没有加入 AID 之类的随机擦除数据增强,对于遮挡的鲁棒性其实是不如 Regression-based 方法的,毕竟回归方法连超出 bbox 以外的关键点都能直接回归出来。

本地摄像头实时推理

使用本地摄像头进行模型推理来感受模型性能是非常直观的,在进一步查看了说明文档后,我了解到 MMPose 已经提供了这样的脚本,并且还提供了两个版本:一旧一新。

旧版本的脚本是:/demo/webcam_demo.py

这个脚本提供了包括身体、面部、手部,甚至动物姿态在内的全部内容,通过命令行参数的形式进行各个模块的开关,缺乏使用文档说明,在后续被 MMPose Webcam API 所替代。

新版本的脚本在 /tools/webcam 下,有专门的文档进行使用说明。

按照说明把

/tools/webcam/configs/examples/pose_estimation.py 中,DetectorNode 和 PoseEstimatorNode的model_config和model_checkpoint 改为了我所使用的手部检测的模型,再把 clas_names 改为 ['hand'] 后,就可以运行了:

python tools/webcam/run_webcam.py --config

tools/webcam/configs/examples/pose_estimation.py

说巧不巧的是,不知道是不是因为 Webcam API 是新推出的脚本,代码还不够完善,第一次尝试我就发现了一个 MMPose 的代码 bug:

File"E:\project\mmpose\tools\webcam\webcam_apis\nodes\mmdet_node.py", line 52

, in process

det_result = self._post_process(preds)

File"E:\project\mmpose\tools\webcam\webcam_apis\nodes\mmdet_node.py", line 65

, in _post_process

assert len(dets) == len(self.model.CLASSES)

AssertionError

一番检查之后发现错误是因为 MMDeteciton 预训练参数中保存的 CLASSES 字段是一个 string,

'hand'

而这里脚本中需要的是一个 tuple。

('hand', )

但毕竟刚接触 MMPose,我不确定是不是自己哪里弄错了,先提了一个 issue 询问,很快就得到了回复,并与维护者交流了一下修改方案,在他的帮助下对代码逻辑有了更清晰的了解,在我的方案得到认可后提交了我的 PR。

想不到这么快就实现了给 MMPose 提 PR 的小目标,有点意外,但也让我有了更多成为 contributor 的信心,MM 系列虽然名声在外,但其中仍然存在很多我们可以贡献一份力量的地方。

假如各位小伙伴在看到这篇笔记时,运行的这个 demo 脚本,其中就已经有我 PR 的代码了。

相比于旧版的 demo/webcam_demo.py 而言,新版的摄像头推理 demo 还是要强大和方便不少的。MMPose 提供的 Webcam API 中集成了检测、姿态估计,通过底层代码的阅读我发现还做了多线程优化来提升推理效率,感觉基于这套工具开发一些简单的摄像头应用应该会很方便。

在文档里还给出了几个应用开发的示例,有兴趣的小伙伴也可以去玩一下:

mmpose/example_cn.md at d66c4445c979e24685153c1cf73f2f3bb905279f · open-mmlab/mmpose (github.com)github.com/open-mmlab/mmpose/blob/d66c4445c979e24685153c1cf73f2f3bb905279f/tools/webcam/docs/exa

导出 ONNX 转 MNN

目前的部署框架大都需要把 pytorch 训练的模型先转成 ONNX,这个过程中常常因为各种代码或算子的实现存在问题而无法部署,因此在开始学习之初,验证 MMPose->ONNX->MNN 这一流程的通畅是很有必要的。

我跟随官方教程导出 onnx 模型:

python tools/deployment/pytorch2onnx.py \

configs/hand/2d_kpt_sview_rgb_img/deeppose/onehand10k/res50_onehand10k_256x256.py \

https://download.openmmlab.com/mmpose/hand/deeppose/deeppose_res50_onehand10k_256x256-cbddf43a_20210330.pth \

--shape 1 3 256 256

得到 tmp.onnx 模型后习惯性地用 onnxsimpler 进行了简化:

python -m onnxsim tmp.onnx tmp-sim.onnx

对比之后可以发现,对于 MMPose 转换出来的模型,onnxsimpler 还是可以起到优化作用的。

之后转 MNN 也没有遇到任何问题:

python -m MNN.tools.mnnconvert -f ONNX --modelFile tmp-sim.onnx --MNNModel model.mnn --fp16 --bizCode mnn

随后我写了一个简单的 python 端的 MNN 推理代码来验证模型结果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Hand():
    def __init__(self, model_path, joint_num=21, mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]):
        self.model_path = model_path
        self.joint_num = joint_num
        self.mean = np.array(mean).reshape(1, -1, 1, 1)
        self.std = np.array(std).reshape(1, -1, 1, 1)
        self.interpreter = MNN.Interpreter(model_path)
        self.model_sess = self.interpreter.createSession({
            'numThread': 1
        })
    def preprocess(self, img):
        input_shape = img.shape
        assert len(input_shape) == 4, 'expect shape like (1, C, H, W)'
        img = (np.transpose(img, (0, 3, 1, 2)) / 255. - self.mean) / self.std
        return img.astype(np.float32)
    def inference(self, img):
        input_shape = img.shape
        assert len(input_shape) == 4, 'expect shape like (1, C, H, W)'
        input_tensor = self.interpreter.getSessionInput(self.model_sess)
        tmp_input = MNN.Tensor(input_shape,
                               MNN.Halide_Type_Float,
                               img.astype(np.float32),
                               MNN.Tensor_DimensionType_Caffe)
        input_tensor.copyFrom(tmp_input)
        self.interpreter.runSession(self.model_sess)
        output_tensor = self.interpreter.getSessionOutputAll(self.model_sess)
        joint_coord = np.array(output_tensor['518'].getData())
        return joint_coord
    def predict(self, img):
        img = self.preprocess(img)
        joint_coord = self.inference(img)
        return joint_coord

实验后发现,导出的 MNN 模型推理的结果跟 MMPose 提供的 inference_top_down_pose_model() 方法出来的结果完全对不上,MNN 得到的结果全是小数,于是我很快意识到模型输出的结果应该是归一化过的,MMPose 提供的推理方法中应该还包含了预处理和后处理代码。

顺着 inference_top_down_pose_model() 一路走下去,可以发现 MMPose 会先基于 bbox 和 image_size 对坐标进行归一化,计算出 scale 和 center 参数用于后处理时计算原图坐标:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# mmpose/apis/inference.py
    batch_data = []
    for bbox in bboxes:
        center, scale = _box2cs(cfg, bbox)
        # prepare data
        data = {
            'center':
            center,
            'scale':
            scale,
            'bbox_score':
            bbox[4] if len(bbox) == 5 else 1,
            'bbox_id':
            0,  # need to be assigned if batch_size > 1
            'dataset':
            dataset_name,
            'joints_3d':
            np.zeros((cfg.data_cfg.num_joints, 3), dtype=np.float32),
            'joints_3d_visible':
            np.zeros((cfg.data_cfg.num_joints, 3), dtype=np.float32),
            'rotation':
            0,
            'ann_info': {
                'image_size': np.array(cfg.data_cfg['image_size']),
                'num_joints': cfg.data_cfg['num_joints'],
                'flip_pairs': flip_pairs
            }
        }
        if isinstance(img_or_path, np.ndarray):
            data['img'] = img_or_path
        else:
            data['image_file'] = img_or_path
        data = test_pipeline(data)
        batch_data.append(data)
    batch_data = collate(batch_data, samples_per_gpu=len(batch_data))
    batch_data = scatter(batch_data, [device])[0]
    # forward the model
    with torch.no_grad():
        result = model(
            img=batch_data['img'],
            img_metas=batch_data['img_metas'],
            return_loss=False,
            return_heatmap=return_heatmap)
    return result['preds'], result['output_heatmap']

可以注意到的是,模型推理时除了图片以外,还传入了数据信息以及是否计算 loss 和返回 heatmap 的参数,这些都是在自己进行模型推理时需要注意的。

接下来进入模型的推理代码:

找到 /mmpose/models/detectors/ 下的 top_down.py

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# /mmpose/models/detectors/top_down.py
@auto_fp16(apply_to=('img', ))
def forward(self,
            img,
            target=None,
            target_weight=None,
            img_metas=None,
            return_loss=True,
            return_heatmap=False,
            **kwargs):
    if return_loss:
        return self.forward_train(img, target, target_weight, img_metas,
                                      **kwargs)
    return self.forward_test(
        img, img_metas, return_heatmap=return_heatmap, **kwargs)

可以看到是否打开 return_loss 开关是会影响推理流程的,并且默认的参数是 True,因此在手动进行 torch 推理时需要关掉它。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# /mmpose/models/detectors/top_down.py
def forward_test(self, img, img_metas, return_heatmap=False, **kwargs):
    """Defines the computation performed at every call when testing."""
    assert img.size(0) == len(img_metas)
    batch_size, _, img_height, img_width = img.shape
    if batch_size > 1:
        assert 'bbox_id' in img_metas[0]

    result = {}

    features = self.backbone(img)
    if self.with_neck:
        features = self.neck(features)
    if self.with_keypoint:
        output_heatmap = self.keypoint_head.inference_model(
            features, flip_pairs=None)

    if self.test_cfg.get('flip_test', True):
        img_flipped = img.flip(3)
        features_flipped = self.backbone(img_flipped)
        if self.with_neck:
            features_flipped = self.neck(features_flipped)
        if self.with_keypoint:
            output_flipped_heatmap = self.keypoint_head.inference_model(
                features_flipped, img_metas[0]['flip_pairs'])
            output_heatmap = (output_heatmap +
                              output_flipped_heatmap) * 0.5

    if self.with_keypoint:
        keypoint_result = self.keypoint_head.decode(
            img_metas, output_heatmap, img_size=[img_width, img_height])
        result.update(keypoint_result)

        if not return_heatmap:
            output_heatmap = None

        result['output_heatmap'] = output_heatmap

    return result

从 forward_test() 中就可以清晰看出,模型的输出会在 keypoint_head 定义的 decode() 进行后处理,将模型输出的结果还原为原图坐标,而这部分想必是不会写进模型里的,毕竟我们知道 heatmap-based 方法中常用的后处理都是不可导的。

找到 decode() 验证一下我们的想法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# /mmpose/models/heads/deeppose_regression_head.py
def decode(self, img_metas, output, **kwargs):
    batch_size = len(img_metas)
    if 'bbox_id' in img_metas[0]:
        bbox_ids = []
    else:
        bbox_ids = None
    c = np.zeros((batch_size, 2), dtype=np.float32)
    s = np.zeros((batch_size, 2), dtype=np.float32)
    image_paths = []
    score = np.ones(batch_size)
    for i in range(batch_size):
        c[i, :] = img_metas[i]['center']
        s[i, :] = img_metas[i]['scale']
        image_paths.append(img_metas[i]['image_file'])
        if 'bbox_score' in img_metas[i]:
            score[i] = np.array(img_metas[i]['bbox_score']).reshape(-1)
        if bbox_ids is not None:
            bbox_ids.append(img_metas[i]['bbox_id'])
    preds, maxvals = keypoints_from_regression(output, c, s,
                                                kwargs['img_size'])
    all_preds = np.zeros((batch_size, preds.shape[1], 3), dtype=np.float32)
    all_boxes = np.zeros((batch_size, 6), dtype=np.float32)
    all_preds[:, :, 0:2] = preds[:, :, 0:2]
    all_preds[:, :, 2:3] = maxvals
    all_boxes[:, 0:2] = c[:, 0:2]
    all_boxes[:, 2:4] = s[:, 0:2]
    all_boxes[:, 4] = np.prod(s * 200.0, axis=1)
    all_boxes[:, 5] = score
    result = {}
    result['preds'] = all_preds
    result['boxes'] = all_boxes
    result['image_paths'] = image_paths
    result['bbox_ids'] = bbox_ids
    return result

这里发现里面原来还封装了一层,模型输出的结果 output 还通过了一个 keypoints_from_regression() 来取得返回值,而这个返回值的命名 preds, maxvals 就非常眼熟了,常见的开源代码中无论是 DARK 还是别的 heatmap-based 工作,都会有这么一个函数来获取 heatmap 对应的坐标点。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# /mmpose/core/evaluation/top_down_eval.py
def keypoints_from_regression(regression_preds, center, scale, img_size):
    N, K, _ = regression_preds.shape
    preds, maxvals = regression_preds, np.ones((N, K, 1), dtype=np.float32)
    preds = preds * img_size
    # Transform back to the image
    for i in range(N):
        preds[i] = transform_preds(preds[i], center[i], scale[i], img_size)
    return preds, maxvals
# /mmpose/core/post_processing/post_transforms.py
def transform_preds(coords, center, scale, output_size, use_udp=False):
    assert coords.shape[1] in (2, 4, 5)
    assert len(center) == 2
    assert len(scale) == 2
    assert len(output_size) == 2
    # Recover the scale which is normalized by a factor of 200.
    scale = scale * 200.0
    if use_udp:
        scale_x = scale[0] / (output_size[0] - 1.0)
        scale_y = scale[1] / (output_size[1] - 1.0)
    else:
        scale_x = scale[0] / output_size[0]
        scale_y = scale[1] / output_size[1]
    target_coords = np.ones_like(coords)
    target_coords[:, 0] = coords[:, 0] * scale_x + center[0] - scale[0] * 0.5
    target_coords[:, 1] = coords[:, 1] * scale_y + center[1] - scale[1] * 0.5
    return target_coords

再又经过了两层封装后我才终于见到了最底层的后处理逻辑,即利用预处理时计算得到的 bbox 的 center 和 scale 将模型的结果还原为原图坐标。

弄清楚所有处理流程后,我给 MNN 推理代码增加了一段后处理:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# 加到Hand()里
def post_process(self, coords, bbox):
    w = bbox[2] - bbox[0]
    h = bbox[3] - bbox[1]
    target_coords = coords * np.array([w, h])
    target_coords += np.array([bbox[0], bbox[1]])
    return target_coords

最终推理结果对比,精度损失还是有的,不过还能接受,平均每个点的偏移误差在 4 个像素左右。

结语

作为第一次接触和学习 MMPose 的记录,这个过程比我想象中要长,也遇到了不少曲折,好在最终一一进行了解决。接下来我会学习 MMPose 的训练、自定义数据、加入新模块,也会对 MMPose 的封装逻辑进行总结。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-03-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 OpenMMLab 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
漫谈数据仓库之维度建模
数据仓库包含的内容很多,它可以包括架构、建模和方法论。对应到具体工作中的话,它可以包含下面的这些内容:
架构师修炼
2021/01/05
7740
漫谈数据仓库之维度建模
维度模型数据仓库(二) —— 维度模型基础
        既然维度模型是数据仓库建设中的一种数据建模方法,那不妨先看一下几种主流的数据仓库架构。
用户1148526
2022/12/02
1K0
维度模型数据仓库(二) —— 维度模型基础
数据仓库常见建模方法与建模实例演示[通俗易懂]
为什么要进行数据仓库建模?大数据的数仓建模是通过建模的方法更好的组织、存储数据,以便在 性能、成本、效率和数据质量之间找到最佳平衡点。一般主要从下面四点考虑
全栈程序员站长
2022/11/09
3.5K0
数据仓库常见建模方法与建模实例演示[通俗易懂]
深入讲解四种数仓建模理论方法
数据仓库的建设的最重要的核心核心之一就是数仓模型的设计和构建,这个决定了数仓的复用和性能,本文将介绍四种建模的理论:维度建模、关系建模、Data Vault建模、Anchor模型建模,文后也介绍几种常见的数仓建模工具。
Spark学习技巧
2024/01/26
2.9K0
深入讲解四种数仓建模理论方法
数据仓库常见建模方法与大数据领域建模实例综述
随着从IT时代到DT时代的跨越,数据开始出现爆发式的增长,这当中产生的价值也是不言而喻。如何将这些数据进行有序、有结构地分类组织存储,是我们所有数据从业者都要面临的一个挑战。
全栈程序员站长
2022/08/22
1.9K0
数据仓库常见建模方法与大数据领域建模实例综述
数仓建模——维度表详细讲解
来源:菜鸟数据之旅 本文约2100字,建议阅读5分钟 维度表是一种数据建模技术,用于存储与数据中心的各个业务领域相关的维度信息。 一、 维度表是什么 维度表是一种数据建模技术,用于存储与数据中心的各个业务领域相关的维度信息。它通常用于构建数据仓库、数据集市等决策支持系统,以便进行多维数据分析和报告。 在数据仓库中,维度表是与事实表相对应的表。维度表是维度建模的基础和灵魂。事实表紧紧围绕业务过程进行设计,事实表存储度量数据,如销售额、数量、收入等,而维度表则围绕业务过程所处的环境进行设计,维度表存储描述度
数据派THU
2023/05/11
1.3K0
数仓建模——维度表详细讲解
通俗易懂数仓建模—Inmon范式建模与Kimball维度建模
本文开始先简单理解两种建模的核心思想,然后根据一个具体的例子,分别使用这两种建模方式进行建模,大家便会一目了然!
五分钟学大数据
2021/04/15
2.1K0
通俗易懂数仓建模—Inmon范式建模与Kimball维度建模
基于Hadoop生态圈的数据仓库实践 —— 概述(一)
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wzy0623/article/details/51757011
用户1148526
2019/05/25
7580
数据仓库建模方法详解视频_三维建模流程步骤
范式建模法其实是我们在构建数据模型常用的一个方法,该方法的主要由Inmon所提倡,主要解决关系型数据库得数据存储,利用的一种技术层面上的方法,主要用于业务系统,所以范式建模主要是利用关系型数据库进行数仓建设
全栈程序员站长
2022/11/09
7940
数据仓库建模方法详解视频_三维建模流程步骤
数仓建模 - 维度 vs 关系
数据管理一直在演进,从早期的电子表格、蛛网系统到架构式数据仓库。发展至今以维度建模和关系建模为主,而随着互联网的发展,数据从GB到PB的裱花,企业业务迭代更新亦是瞬息万变,对维度模型的偏爱渐渐有统一互联网数仓建模标准的趋势。
大数据老哥
2022/02/17
8870
数仓建模 - 维度 vs 关系
数据仓库系列之维度建模
上一篇文章我已经简单介绍了数据分析中为啥要建立数据仓库,从本周开始我们开始一起学习数据仓库。学习数据仓库,你一定会了解到两个人:数据仓库之父比尔·恩门(Bill Inmon)和数据仓库权威专家Ralph Kimball。Inmon和Kimball两种DW架构支撑了数据仓库以及商业智能近二十年的发展,其中Inmon主张自上而下的架构,不同的OLTP数据集中到面向主题、集成的、不易失的和时间变化的结构中,用于以后的分析;且数据可以通过下钻到最细层,或者上卷到汇总层;数据集市应该是数据仓库的子集;每个数据集市是针对独立部门特殊设计的。而Kimball正好与Inmon相反,Kimball架构是一种自下而上的架构,它认为数据仓库是一系列数据集市的集合。企业可以通过一系列维数相同的数据集市递增地构建数据仓库,通过使用一致的维度,能够共同看到不同数据集市中的信息,这表示它们拥有公共定义的元素。
黄昏前黎明后
2019/08/26
1.4K0
Greenplum 实时数据仓库实践(2)——数据仓库设计基础
本篇首先介绍关系数据模型、多维数据模型和Data Vault模型这三种常见的数据仓库模型和与之相关的设计方法,然后讨论数据集市的设计问题,最后说明一个数据仓库项目的实施步骤。规划实施过程是整个数据仓库设计的重要组成部分。
用户1148526
2021/12/07
1.9K0
Greenplum 实时数据仓库实践(2)——数据仓库设计基础
浅谈数仓建模及其方法论
1.简单报表阶段:这个阶段,系统的主要目标是解决一些日常的工作中业务人员需要的报表,以及生成一些简单的能够帮助领导进行决策所需要的汇总数据。这个阶段的大部分表现形式为数据库和前端报表工具。
大数据真好玩
2021/03/15
1.9K0
数据仓库(03)数仓建模之星型模型与维度建模
维度建模是一种将数据结构化的逻辑设计方法,也是一种广泛应用的数仓建模方式,它将客观世界划分为度量和上下文。度量是常常是以数值形式出现,事实周围有上下文包围着,这种上下文被直观地分成独立的逻辑块,称之为维度。它与实体-关系建模有很大的区别,实体-关系建模是面向应用,遵循第三范式,以消除数据冗余为目标的设计技术。维度建模是面向分析,为了提高查询性能可以增加数据冗余,反规范化的设计技术。
张飞的猪
2022/09/03
8120
系列 | 漫谈数仓第二篇NO.2 数据模型(维度建模)
model对于数仓是最核心的东西,数据模型是数据组织和存储方法,模型的好坏,决定了数仓能支撑企业业务多久。
Spark学习技巧
2019/09/26
2.9K0
系列 | 漫谈数仓第二篇NO.2 数据模型(维度建模)
8000字,详解数据建模的方法、模型、规范和工具!
由于在变化快速的商业世界里,业务形态多种多样,为了能够更有针对性的进行数据建模,经过长时间的摸索,业界逐步形成了数据建模的四部曲:业务建模->领域建模->逻辑建模->物理建模。
肉眼品世界
2022/01/20
4.6K0
8000字,详解数据建模的方法、模型、规范和工具!
万字漫游数据仓库模型从入门到放弃
数据模型就是数据组织和存储方法,它强调从业务、数据存取和使用角度合理存储数据。只有将数据有序的组织和存储起来之后,数据才能得到高性能、低成本、高效率、高质量的使用。
Spark学习技巧
2023/09/07
6480
万字漫游数据仓库模型从入门到放弃
数据仓库建模
如果把数据看作图书馆里的书,我们希望看到它们在书架上分门别类地放置;如果把数据看作城市的建筑,我们希望城市规划布局合理;如果把数据看作电脑文件和文件夹,我们希望按照自己的习惯有很好的文件夹组织方式,而不是糟糕混乱的桌面,经常为找一个文件而不知所措。
用户1217611
2020/06/19
1.4K0
数仓建模与分析建模_数据仓库建模与数据挖掘建模
数据仓库: 数据仓库是一个面向主题的、集成的、非易失的、随时间变化的数据集合。重要用于组织积累的历史数据,并且使用分析方法(OLAP、数据分析)进行分析整理,进而辅助决策,为管理者、企业系统提供数据支持,构建商业智能。
全栈程序员站长
2022/11/09
1.4K0
数仓建模与分析建模_数据仓库建模与数据挖掘建模
【读书笔记】《 Hadoop构建数据仓库实践》第2章
一个列或者列集,唯一标识表中的一条记录。超键可能包含用于唯一标识记录所不必要的额外的列,我们通常只对仅包含能够唯一标识记录的最小数量的列感兴趣。
辉哥
2022/05/13
1K0
【读书笔记】《 Hadoop构建数据仓库实践》第2章
推荐阅读
相关推荐
漫谈数据仓库之维度建模
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验