精华内容
下载资源
问答
  • 有没有简单有效的方法快速提升团队的编码水平,人人都能写高质量优秀代码?本篇文章用实战案例告诉你。

    文/罗恩良


    优秀编码很难。即使在有很多编码书籍、编程规范的情况下,绝大部分项目输出的代码依旧质量不高。


    为什么会出现这种情况?我觉得主要是因为不分轻重面面俱到,“面面俱到”必然导致“面面不到”。数十本编码必读的书籍、好几千页、22 种坏味道、72 种重构方法,让绝大多部程序员不堪重负,根本记不住,更不说有效地应用了。




    那有没有简单有效的方法快速提升团队的编码水平,人人都能写高质量优秀代码?


    本篇文章总结提取出优秀编码最重要的四个原则,不用面面俱到,只是简单地应用了此四原则,我所在部门团队的编码水平就提高了一个层次。团队有部分成员也反馈现在的编码水平和二个月前的编码已不在同一个层次。


    优秀编码四大原则



    优秀编码原则 1单一抽象层次




    我个人认为,函数单一抽象层次是优秀编码中最重要的原则,没有之一!单一抽象层次指一个函数或者方法中所有的操作处于相同层次。







    如上图所示,一个函数或方法中所有的操作处于相同逻辑层次。


    优秀编码原则 2最小化缩进


    过分深层的缩进,或者“嵌套”已经困扰了计算机界达几十年之久,而且至今仍然是产生混乱代码的罪魁祸首之一。


    Noam Chomsky 和 Gerald Weinberg 做过一份研究表明,很少有人能够理解超过 3 层的嵌套 (Yourdon 1986a),很多研究人员建议避免使用超过 3 层的嵌套。




    如上图所示,以卫语句取代嵌套条件表达式是最少化缩进的精髓之一。卫语句可以把我们的视线从异常处理中解放出来,集中精力到正常处理的代码中。



    上面这段代码可以改编成下面的样式:







    总结: 如下图所示,简化复杂的 if else 语句,基本就是三个手段:


    • 针对头重脚轻的 if else,尽早使用 return 返回,从而减少嵌套层次;

    • 合并分支。有些分支持执行的内容相同,可以合并成为一个分支;

    • 扁平化。这个例子就是扁平化最好的示例。





    优秀编码原则 3清晰表达式


    优秀代码不是越少越好,而是理解它所花的时间越少越好。


    代码应当使别人理解它所需的时间最小化---这就是非常重要的“可读性基本定理”。


    清晰表达式原则是这个基本定理的一个重要原则之一。


    什么是清晰表达原则?以下是一些例子,请各位参考。





    优秀编码原则 4善用辅助类拆分




    前面讲的三个原则都是在讨论如何编写良好的函数,编写良好易读的代码行和代码块,现在我们来把注意力放在代码组织的更高层面,这一部分将涉及到软件设计中最重要的能力——类的职责分配问题


    如果你编写的类有几十个甚至上百个方法,或上千行代码,一般都说明这个类设计上有问题了。


    类和人一样,职责多的类就像职责多的领导,领导需要秘书和助理,因为秘书和助理能帮助领导从琐事中解放出来。巨型类也一样,也需要辅助类把与主业务逻辑无关的事移除出去。


    哪些琐事应该交给助理来处理?不产生数据的函数,不修改数据的函数,或有输入就有明确输出的函数,不和外部对象交互的函数等。


    下面是两个例子:








    结束语一些编码理念


    • 理解函数所花的时间,应该越短越好。



    • 笔者认为人人都能写优秀代码,优秀代码都是一遍一遍地改出来的。允许先写肮脏的代码,但必须重构它。

    (更多华为资讯请关注华为开发者社区,华为自己的对外开放门户:http://developer.huawei.com/cn/ict/ ,不要问我叫啥,别人都叫我雷锋


    展开全文
  • 叉树编码实现

    万次阅读 2013-09-16 11:48:18
    本次就自己实现一地图叉树索引,但是还有一些问题也希望各位路过的大神能指点一下。   首先,结合一下应用场景(我们需要用叉树来索引地图数据),考虑一下使用叉树索引地图数据存在的一些问题。 1.什么...

    关于四叉树的原理我想应该不需要多说啦,大家都懂得,实在不晓得的话,百度吧~

    由于四叉树索引效率还可以并且非常简单,因此在Gis中广泛的应用也是毋庸置疑的。

     

    本次就自己实现一个地图四叉树索引,但是还有一些问题也希望各位路过的大神能指点一下。

     

    首先,结合一下应用场景(我们需要用四叉树来索引地图数据),考虑一下使用四叉树索引地图数据存在的一些问题。

    1.什么时候建立四叉树索引,四叉树索引如何存储(序列化还是自己写算法来存储四叉树)?第一次加载数据的时候建立四叉树,当对地图数据操作的时候动态的维护四叉树,关闭地图的时候,保存内存中的四叉树实例,以避免每次建立四叉树耗时。目前我直接使用四叉树序列化。

    2.什么东西可能会影响到四叉树索引地图数据的效率?树的深度,空节点每次还要被搜索,使用不平衡四叉树来避免无意义的搜索;每个节点上所关联的地图数据个数。子节点已经包含了地图数据的实例,则父节点不包含,减少数据的冗余。

     

    为了可以在四叉树节点上关联地图数据,设计如下结构来表示地图数据。

        /// <summary>
        /// 包含有包络线的对象接口定义
        /// </summary>
        public interface IHasBoundingBox
        {
            /// <summary>
            /// 几何对象的包络线
            /// </summary>
            BoundingBox Box
            {
                get;
                set;
            }
        }


     

        /// <summary>
        /// 几何对象的的ID和包络线构成索引对象
        /// </summary>
        public class GeoBox:IHasBoundingBox
        {
            BoundingBox _box;
    
            /// <summary>
            /// 几何对象的Id
            /// </summary>
            public uint ID;
    
            #region IHasBoundingBox 成员
    
            public BoundingBox Box
            {
                get
                {
                    return _box;
                }
                set
                {
                    _box = value;
                }
            }
    
            #endregion
        }


    用一个矩形范围和几何对象的Id来表示地图上需要索引的几何对象,当请求地图数据的时候,首先根据地图范围来遍历四叉树,找到对应四叉树的节点后,遍历该自树获取所有数据,即Id,根据Id去读取物理文件的数据。

     

    四叉树节点的定义:

        /// <summary>
        /// 四叉树节点
        /// </summary>
        /// <typeparam name="T">节点中所包含的数据类型</typeparam>
        public class QuadNode<T>
        {
            private int _depth;
            private List<T> _datas;
            private BoundingBox _rect;
            private QuadNode<T> _lt;
            private QuadNode<T> _rt;
            private QuadNode<T> _lb;
            private QuadNode<T> _rb;
            private bool _isLeaf;
            private QuadNodeLimit _limit;
    
            public QuadNodeLimit Limit
            {
                get { return _limit; }
            }
    
            public bool IsLeaf
            {
                get { return _isLeaf; }
                set { _isLeaf = value; }
            }
    
            public int Depth
            {
                get { return _depth; }
                set { _depth = value; }
            }
    
            public List<T> Datas
            {
                get { return _datas; }
                set { _datas = value; }
            }
    
            public BoundingBox Rect
            {
                get { return _rect; }
                set { _rect = value; }
            }
    
            public QuadNode<T> LT
            {
                get { return _lt; }
                set { _lt = value; }
            }
    
            public QuadNode<T> RT
            {
                get { return _rt; }
                set { _rt = value; }
            }
    
            public QuadNode<T> LB
            {
                get { return _lb; }
                set { _lb = value; }
            }
    
            public QuadNode<T> RB
            {
                get { return _rb; }
                set { _rb = value; }
            }
    
            public QuadNode(BoundingBox box,QuadNodeLimit limit, int depth)
            {
                _datas = new List<T>();
                _rect = box;
                _lt = null;
                _rt = null;
                _lb = null;
                _rb = null;
                _isLeaf = true;
                _depth = depth;
                _limit = limit;
            }
    
            public bool Insert(T data)
            {
                QuadNode<T> ret = QueryNode((data as IHasBoundingBox).Box);
                if (ret != null)
                {
                    //此处开始分裂子节点,不是平衡四叉树
                    if ( ret.Datas.Count >= _limit.MaxObjNum && ret.Depth < _limit.MaxDepth)
                    {
                        BoundingBox childBox;
                        double xmin = 0;
                        double ymin = 0;
                        double xmax = 0;
                        double ymax = 0;
    
                        // 开始分裂子节点
                        if (ret.LT == null)
                        {
                            xmin = _rect.Min.X;
                            ymin = _rect.Min.Y;
                            xmax = _rect.Min.X + _rect.Width / 2;
                            ymax = _rect.Min.Y + _rect.Height/2;
    
                            childBox = new BoundingBox(xmin, ymin, xmax, ymax);
                            if (childBox.Contains((data as IHasBoundingBox).Box))
                            {
                                ret.LT = new QuadNode<T>(childBox, ret.Limit, ret.Depth + 1);
                                ret.IsLeaf = false;
                                SplitDatas(ret.LT, ret.Datas);
                                ret = ret.LT;
                            }
                        }
                        if (ret.RT == null)
                        {
                            xmin = _rect.Min.X + _rect.Width / 2;
                            ymin = _rect.Min.Y;
                            xmax = _rect.Max.X;
                            ymax = _rect.Min.Y + _rect.Height / 2;
    
                            childBox = new BoundingBox(xmin, ymin, xmax, ymax);
                            if (childBox.Contains((data as IHasBoundingBox).Box))
                            {
                                ret.RT = new QuadNode<T>(childBox, ret.Limit, ret.Depth + 1);
                                ret.IsLeaf = false;
                                SplitDatas(ret.RT, ret.Datas);
                                ret = ret.RT;
                            }
                        }
                        if (ret.LB == null)
                        {
                            xmin = _rect.Min.X;
                            ymin =  _rect.Min.Y + _rect.Height / 2;
                            xmax = _rect.Min.X + _rect.Width / 2;
                            ymax = _rect.Max.Y;
    
                            childBox = new BoundingBox(xmin, ymin, xmax, ymax);
                            if (childBox.Contains((data as IHasBoundingBox).Box))
                            {
                                ret.LB = new QuadNode<T>(childBox, ret.Limit, ret.Depth + 1);
                                ret.IsLeaf = false;
                                SplitDatas(ret.LB, ret.Datas);
                                ret = ret.LB;
                            }
                        }
                        if (ret.RB == null)
                        {
                            xmin = _rect.Min.X + _rect.Width / 2;
                            ymin = _rect.Min.Y + _rect.Height / 2;
                            xmax = _rect.Max.X;
                            ymax = _rect.Max.Y;
    
                            childBox = new BoundingBox(xmin, ymin, xmax, ymax);
                            if (childBox.Contains((data as IHasBoundingBox).Box))
                            {
                                ret.RB = new QuadNode<T>(childBox, ret.Limit, ret.Depth + 1);
                                ret.IsLeaf = false;
                                SplitDatas(ret.RB, ret.Datas);
                                ret = ret.RB;
                            }
                        }
                    }
                    ret.Datas.Add(data);
                    return true;
                }
                else
                    return false;
            }
    
            public void Remove(T data)
            {
                QuadNode<T> ret = QueryNode((data as IHasBoundingBox).Box);
                if (ret != null)
                    ret.Datas.Remove(data);
            }
    
            public QuadNode<T> QueryNode(BoundingBox env)
            {
                QuadNode<T> ret = null;
                if (Rect.Contains(env) || Rect.Equals(env))
                {
                    ret = this;
                }
                else if (env.Contains(Rect))
                {
                    return this;
                }
                else
                {
                    return null;
                }
                if (LT != null && LT.Rect.Contains(env))
                {
                    ret = LT.QueryNode(env);
                }
                else if (RT != null && RT.Rect.Contains(env))
                {
                    ret = RT.QueryNode(env);
                }
                else if (LB != null && LB.Rect.Contains(env))
                {
                    ret = LB.QueryNode(env);
                }
                else if (RB != null && RB.Rect.Contains(env))
                {
                    ret = RB.QueryNode(env);
                }
                return ret;
            }
    
            public void QueryData(QuadNode<T> node, ref List<T> datas)
            {
                QuadNode<T> tempNode = node;
    
                datas.AddRange(tempNode.Datas);
                if (tempNode.LT != null)
                {
                    QueryData(tempNode.LT, ref datas);
                }
                if (tempNode.LB != null)
                {
                    QueryData(tempNode.LB, ref datas);
                }
                if (tempNode.RT != null)
                {
                    QueryData(tempNode.RT, ref datas);
                }
                if (tempNode.RB != null)
                {
                    QueryData(tempNode.RB, ref datas);
                }
            }
    
            private void SplitDatas(QuadNode<T> node, List<T> datas)
            {
                for (int i = 0; i < datas.Count; i++) 
                {
                    if (node.Rect.Contains((datas[i] as IHasBoundingBox).Box))
                    {
                        node.Datas.Add(datas[i]);
                    }
                }
                //是否去掉父节点重复的节点,若是去掉获取数据消耗时间会变长,若是没有去掉则树中会有大量的冗余数据
                for (int i = 0; i < node.Datas.Count; i++)
                {
                    datas.Remove(node.Datas[i]);
                }
            }
        }

     

    四叉树的定义:

        /// <summary>
        /// 四叉树地图索引
        /// 四叉树必须要保证层数不能太深,同时也要保证节点保存对象数目不能大于规定的最大对象数目
        /// 上述两个条件冲突时以深度为优先判断要素
        /// 节点保存对象数目小于规定的最小保存数目时该节点则该节点不再分裂子节点
        /// 注意:删除数据时该树不会自动萎缩,用户可以调用重新构造树的方法进行维护树
        /// devCopper 2013.9.12
        /// </summary>
        /// <typeparam name="T">保存对象的数据类型</typeparam>
        public class QuadTree<T> where T : IHasBoundingBox
        {
            QuadNode<T> _root;
    
            List<T> _datas;
    
            /// <summary>
            /// 四叉树的根节点
            /// </summary>
            public QuadNode<T> Root
            {
                get { return _root; }
                set { _root = value; }
            }
    
            /// <summary>
            /// 所有被索引的对象
            /// </summary>
            public List<T> Datas
            {
                get { return _datas; }
                set { _datas = value; }
            }
    
            public QuadTree()
            { }
    
            /// <summary>
            /// 构造函数
            /// </summary>
            /// <param name="env">根节点的包围盒</param>
            public QuadTree(BoundingBox env, QuadNodeLimit limit)
            {
                _root = new QuadNode<T>(env, limit, 0);
                _datas = new List<T>();
            }
    
            /// <summary>
            /// 插入一个对象
            /// </summary>
            /// <param name="data">插入的数据</param>
            public void Insert(T data)
            {
                _root.Insert(data);
                _datas.Add(data);
            }
    
            /// <summary>
            /// 移除一个对象
            /// </summary>
            /// <param name="data">移除的对象,该对象的BoundingBox属性值不需要关心</param>
            public void Remove(T data) 
            {
                _root.Remove(data);
                _datas.Remove(data);
            }
    
            /// <summary>
            /// 遍历四叉树查询矩形框所包含的对象
            /// </summary>
            /// <param name="env">查询条件</param>
            /// <returns>包含对象的节点</returns>
            public List<T> Query(BoundingBox env)
            {
                List<T> data = new List<T>();
    
                QuadNode<T> ret = _root.QueryNode(env);
                if (ret != null)
                    ret.QueryData(ret, ref data);
    
                return data;
            }
    
            /// <summary>
            /// 初始化四叉树
            /// </summary>
            /// <param name="objs">初始化对象</param>
            public void Initialize(List<T> datas)
            {
                for (int i = 0; i < datas.Count; i++)
                {
                    if(_root.Insert(datas[i]))
                        _datas.Add(datas[i]);
                }
            }
    
            /// <summary>
            /// 重新构造索引
            /// </summary>
            public void Rebuild()
            {
                for (int i = 0; i < _datas.Count; i++)
                {
                    _root.Insert(_datas[i]);
                }
            }
    
            /// <summary>
            /// 从文件中读取四叉树索引
            /// </summary>
            /// <param name="file">文件</param>
            /// <returns>一颗四叉树</returns>
            public static QuadTree<GeoBox>  FromFile(string file)
            {
                System.IO.FileStream fs = new System.IO.FileStream(file, System.IO.FileMode.Open);
                BinaryFormatter bf = new BinaryFormatter();
    
                QuadTree<GeoBox> tree = (QuadTree<GeoBox>)bf.Deserialize(fs);
                
                fs.Close();
                return tree;
            }
    
            /// <summary>
            /// 保存四叉树索引
            /// </summary>
            /// <param name="tree">四叉树对象</param>
            /// <param name="file">保存的文件</param>
            public static void SaveIndex(QuadTree<GeoBox> tree, string file)
            {
                System.IO.FileStream fs = new System.IO.FileStream(file, System.IO.FileMode.CreateNew);
                BinaryFormatter bf = new BinaryFormatter();
                bf.Serialize(fs, tree);
                fs.Close();
            }
    
        }
    



     

    展开全文
  • 编码器及其变形很多,本篇博客目前主要基于普通自编码器、欠完备自编码器、稀疏自编码器和去噪自编码器,会提供理论+实践(有的理论本人没有完全理解,就先没有写上,后更)。另外,关于收缩自编码器、变分自编码...

    写在前面

    因为时间原因本文有些图片自己没有画,来自网络的图片我尽量注出原链接,但是有的链接已经记不得了,如果有使用到您的图片,请联系我,必注释。

    自编码器及其变形很多,本篇博客目前主要基于普通自编码器、栈式自编码器、欠完备自编码器、稀疏自编码器和去噪自编码器,会提供理论+实践(有的理论本人没有完全理解,就先没有写上,后更)。另外,关于收缩自编码器、变分自编码器、CNN自编码器、RNN自编码器及其自编码器的应用,后更。

    本文展示的所有完整代码详见:完整代码
    (目前只有Keras版本,有时间会写Tensorflow版本)

    文章较长,PDF版点击链接:PDF版

    一、自编码器(Autoencoder, AE)

    1、自编码器的结构和思想

    自编码器是一种无监督的数据维度压缩和数据特征表达方法。
    自编码器是神经网络的一种,经过训练后能尝试将输入复制到输出。自编码器由编码器和解码器组成,如下图所示(图片来源:深度学习浅层理解(三)— 常用模型之自编码器):

    h=f(x)h=f(x)表示编码器,r=g(h)=g(f(x))r=g(h)=g(f(x))表示解码器,自编码的目标便是优化损失函数L(x,g(f(x))L(x,g(f(x)),也就是减小图中的Error。

    2、自编码器和前馈神经网络的比较

    二者的区别和联系如下:

    (1)自编码器是前馈神经网络的一种,最开始主要用于数据的降维以及特征的抽取,随着技术的不断发展,现在也被用于生成模型中,可用来生成图片等。
    (2)前馈神经网络是有监督学习,其需要大量的标注数据。自编码器是无监督学习,数据不需要标注因此较容易收集。
    (3)前馈神经网络在训练时主要关注的是输出层的数据以及错误率,而自编码的应用可能更多的关注中间隐层的结果。

    3、自编码器和受限玻尔兹曼机的比较

    关于受限玻尔兹曼机的博客请参见:[受限玻尔兹曼机] 原理、求解、深度信念网络
    二者的区别和联系如下:

    (1)自编码器和受限自编码器的相同点如下:①都起到了降维的作用;②都可以用来对神经网络进行预训练;③训练都是无监督的。
    (2)自编码器和受限自编码器的不同点如下:①自编码器希望通过非线性变换找到输入数据的特征表示,其重构的是输入分布与reconstruct分布的KL距离,它是某种确定论性的模型;而RBM则是围绕概率分布进行的,它通过输入数据的概率分布来提取中间层表示,它是某种概率论性的模型。②AE使用的是BP算法进行优化,而RBM是基于概率模型,使用CD算法进行优化。

    4、普通自编码器存在的问题

    在普通的自编码器中,输入和输出是完全相同的,因此输出对我们来说没有什么应用价值,所以我们希望利用中间隐层的结果,比如,可以将其作为特征提取的结果、利用中间隐层获取最有用的特性等。
    但是如果只使用普通的自编码器会面临什么问题呢?比如,输入层和输出层的维度都是5,中间隐层的维度也是5,那么我们使用相同的输入和输出来不断优化隐层参数,最终得到的参数可能是这样:x1&gt;a1x2&gt;a2x1-&gt;a1,x2-&gt;a2,…的参数为1,其余参数为0,也就是说,中间隐层的参数只是完全将输入记忆下来,并在输出时将其记忆的内容完全输出即可,神经网络在做恒等映射,产生数据过拟合。如下图所示(图片来源:Introduction to autoencoders.):

    上图是隐层单元数等于输入维度的情况,当然,如果是隐层单元数大于输入维度,也会发生类似的情况,即当隐层单元数大于等于输入维度时,网络可以采用完全记忆的方式,虽然这种方式在训练时精度很高,但是复制的输出对我们来说毫无意义
    因此,我们会给隐层加一些约束,如限制隐藏单元数、添加正则化等,后面后介绍。

    5、自编码器实现与结果分析

    (1)实现框架: Keras
    (2)数据集: Mnist手写数字识别
    (3)关键代码:

    def train(x_train):
        """
        build autoencoder.
        :param x_train:  the train data
        :return: encoder and decoder
        """
        # input placeholder
        input_image = Input(shape=(ENCODING_DIM_INPUT, ))
    
        # encoding layer
        hidden_layer = Dense(ENCODING_DIM_OUTPUT, activation='relu')(input_image)
        # decoding layer
        decode_output = Dense(ENCODING_DIM_INPUT, activation='relu')(hidden_layer)
    
        # build autoencoder, encoder, decoder
        autoencoder = Model(inputs=input_image, outputs=decode_output)
        encoder = Model(inputs=input_image, outputs=hidden_layer)
    
        # compile autoencoder
        autoencoder.compile(optimizer='adam', loss='mse')
    
        # training
        autoencoder.fit(x_train, x_train, epochs=EPOCHS, batch_size=BATCH_SIZE, shuffle=True)
    
        return encoder, autoencoder
    

    (4)代码分析:
    Keras封装的比较厉害,所以傻瓜式编程,这里是最简单的自编码器,其输入维度是28*28=784,中间单隐层的维度是2,使用的激活函数是Relu,返回encoder和autoencoder。encoder部分可以用于降维后的可视化,或者降维之后接分类等,autoencoder可以用来生成图片等(这部分代码git上都有)。结构见图如下:

    (5)结果展示:

    (i)Eencoder结果的可视化如图:

    上图中不同表示表示不同的数字,由图可知,自编码器降维之后的结果并不能很好地表示10个数字。

    (ii)autoencoder还原之后的图片和原图片对比如下:

    上图说明,autoencoder的生成结果不是很清晰。

    二、栈式自编码器(Stack Autoencoder)

    1、栈式自编码器思想

    栈式自编码器又称为深度自编码器,其训练过程和深度神经网络有所区别,下面是基于栈式自编码器的分类问题的训练过程(图片来自台大李宏毅老师的PPT):
    栈式自编码器训练过程
    即过程如下:
    首先,训练784->1000->784的自编码器,而后已经固定已经训练好的参数和1000维的结果,训练第二个自编码器:1000->1000->1000,而后固定已经训练好的参数和训练的中间层结果,训练第三个自编码器:1000->500->1000,固定参数和中间隐层的结果。此时,前3层的参数已经训练完毕,此时,最后一层接一个分类器,将整体网络使用反向传播进行训练,对参数进行微调。这便是使用栈式自编码器进行分类的整体过程。
    注:encoder和decoder的参数可以是对称的,也可以是非对称的。

    2、栈式自编码器的特点

    ①增加隐层可以学到更复杂的编码,每一层可以学习到不同的信息维度。
    ②若层数太深,encoder过于强大,可以将学习将输入映射为任意数(然后decoder学习其逆映射)。这一编码器可以很好的重建数据,但它并没有在这一过程中学到有用的数据表示。

    3、栈式自编码器和深度信念网络的异同点

    ①自编码器栈式自编码器;受限玻尔兹曼机深度信念网络
    ②栈式自编码器和深度信念网络都是逐层训练。
    ③栈式自编码器和深度信念网络的训练方法不同,栈式自编码器使用BP算法训练参数,深度信念网络使用的是对比散度算法。

    4、栈式自编码器实现与结果分析

    (1)实现框架: Keras
    (2)数据集: Mnist手写数字识别
    (3)关键代码:

    def train(x_train):
    
        # input placeholder
        input_image = Input(shape=(ENCODING_DIM_INPUT, ))
    
        # encoding layer
        encode_layer1 = Dense(ENCODING_DIM_LAYER1, activation='relu')(input_image)
        encode_layer2 = Dense(ENCODING_DIM_LAYER2, activation='relu')(encode_layer1)
        encode_layer3 = Dense(ENCODING_DIM_LAYER3, activation='relu')(encode_layer2)
        encode_output = Dense(ENCODING_DIM_OUTPUT)(encode_layer3)
    
        # decoding layer
        decode_layer1 = Dense(ENCODING_DIM_LAYER3, activation='relu')(encode_output)
        decode_layer2 = Dense(ENCODING_DIM_LAYER2, activation='relu')(decode_layer1)
        decode_layer3 = Dense(ENCODING_DIM_LAYER1, activation='relu')(decode_layer2)
        decode_output = Dense(ENCODING_DIM_INPUT, activation='tanh')(decode_layer3)
    
        # build autoencoder, encoder
        autoencoder = Model(inputs=input_image, outputs=decode_output)
        encoder = Model(inputs=input_image, outputs=encode_output)
    
        # compile autoencoder
        autoencoder.compile(optimizer='adam', loss='mse')
    
        # training
        autoencoder.fit(x_train, x_train, epochs=EPOCHS, batch_size=BATCH_SIZE, shuffle=True)
    
        return encoder, autoencoder
    

    栈式自编码器相当于深度网络的过程,主要注意维度对应即可,另外,这里设置的encoder和decoder的维度是对称的。其架构图如下:

    (4)结果展示:

    (i)Eencoder结果的可视化如图:

    上图中不同表示表示不同的数字,由图可知,栈式自编码器的效果相比较普通自编码器好很多,这里基本能将10个分类全部分开。

    (ii)autoencoder还原之后的图片和原图片对比如下:

    三、欠完备自编码器(Undercomplete Autoencoder)

    1、欠完备自编码器的思想

    由上述自编码器的原理可知,当隐层单元数大于等于输入维度时,网络会发生完全记忆的情况,为了避免这种情况,我们限制隐层的维度一定要比输入维度小,这就是欠完备自编码器,如下图所示(图片来源:Introduction to autoencoders.)。 学习欠完备的表示将强制自编码器捕捉训练数据中最显著的特征。

    2、欠完备自编码器和主成分分析(PCA)的比较

    实际上,若同时满足下列条件,欠完备自编码器的网络等同于PCA,其会学习出于PCA相同的生成子空间:

    • 每两层之间的变换均为线性变换。
    • 目标函数L(x,g(f(x))L(x,g(f(x))为均方误差。

    因此,拥有非线性编码器函数ff和非线性解码器函数gg的自编码器能够学习出比PCA更强大的知识,其是PCA的非线性推广。下图是在二维空间中PCA算法和自编码器同时作用在二维点上做映射的结果(图片来源:Introduction to autoencoders.) ,从图中可以看出,自编码器具有更好的表达能力,其可以映射到非线性函数。

    3、欠完备自编码器特点

    • 防止过拟合,并且因为隐层编码维数小于输入维数,可以学习数据分布中最显著的特征。
    • 若中间隐层单元数特别少,则其表达信息有限,会导致重构过程比较困难。

    四、稀疏自编码器(Sparse Autoencoder)

    1、稀疏自编码器思想

    稀疏自编码器是加入正则化的自编码器,其未限制网络接收数据的能力,即不限制隐藏层的单元数。
    所谓稀疏性限制是指:

    若激活函数是sigmoid,则当神经元的输出接近于1的时候认为神经元被激活,输出接近于0的时候认为神经元被抑制。使得大部分神经元别抑制的限制叫做稀疏性限制。若激活函数是tanh,则当神经元的输出接近于-1的时候认为神经元是被抑制的。

    如上图所示(图片来源:Introduction to autoencoders. ),浅色的神经元表示被抑制的神经元,深色的神经元表示被激活的神经元。通过稀疏自编码器,我们没有限制隐藏层的单元数,但是防止了网络过度记忆的情况。
    稀疏自编码器损失函数的基本表示形式如下:
    Lsparse(x,g(f(x)))=L(x,g(f(x)))+Ω(h) L_{sparse}(x, g(f(x)))=L(x, g(f(x))) + \Omega (h)
    其中g(h)g(h)是解码器的输出,通常hh是编码器的输出,即h=f(x)h=f(x)

    2、损失函数和BP函数推导

    损失函数可以加入L1正则化,也可以加入KL散度,下面是对加入KL散度的损失函数的分析。
    损失函数的分析如下:
    假设aj(2)(x)a_j^{(2)}(x)表示在给定输入xx的情况下,自编码网络隐层神经元jj的激活度,则神经元在所有训练样本上的平均激活度为:
    ρj^=1mi=1m[aj(2)(xi)] \hat{\rho_j}=\frac{1}{m}\sum_{i=1}^{m}[a_j^{(2)}(x^{i})]
    其中,aj(2)=f(wj(1)x(i)+bj(1))a_j^{(2)}=f(w_j^{(1)}x^{(i)}+b_j^{(1)}),我们的目的使得网络激活神经元稀疏,所以可以引入一个稀疏性参数ρ\rho,通常ρ\rho是一个接近于0的值(即表示隐藏神经元中激活神经元的占比)。则若可以使得ρj^=ρ\hat{\rho_j}=\rho,则神经元在所有训练样本上的平均激活度ρj^\hat{\rho_j}便是稀疏的,这就是我们的目标。为了使得ρj^=ρ\hat{\rho_j}=\rho,我们使用KL散度衡量二者的距离,两者相差越大,KL散度的值越大,KL散度的公式如下:
    j=1s2KL(ρρj^)=j=1s2[ρlogρρj^+(1ρ)log1ρ1ρj^] \sum_{j=1}^{s_2}KL(\rho||\hat{\rho_j})=\sum_{j=1}^{s_2} [\rho \log \frac{\rho}{\hat{\rho_j}} + (1-\rho) \log \frac{1-\rho}{1-\hat{\rho_j}}]
    ρ\rho表示平均激活度的目标值。因此损失函数如下:
    Jsparse(W,b)=J(W,b)+βj=1s2KL(ρρj^) J_{sparse}(W,b)=J(W,b)+\beta \sum_{j=1}^{s_2}KL(\rho||\hat{\rho_j})
    其中J(W,b)J(W, b)便是NN网络中的普通的代价函数,可以使用均方误差等。

    反向传播的分析如下:
    上式代价函数,左部分就是之前BP的结果,结果如下:
    J(W,b)zi(2)=j=1s2Wji(2)J(W,b)zi(3)f(zi(2)) \frac{\partial J(W,b)}{ \partial z_i^{(2)}} = \sum_{j=1}^{s_2}W_{ji}^{(2)}\frac{\partial J(W,b)}{ \partial z_i^{(3)}}{f}&#x27;(z_i^{(2)})
    可参考反向传导算法

    右部分的求导如下:

    j=1s2KL(ρρj^)zi(2)=KL(ρρi^)zi(2)=KL(ρρi^)ρi^ρi^zi(2)=(ρlogρρi^+(1ρ)log1ρ1ρi^)ρi^ρi^zi(2)=(ρρi^+1ρ1ρi^)f(zi(2)) \begin{aligned} \frac{\partial \sum_{j=1}^{s_2}KL(\rho||\hat{\rho_j})}{\partial z_i^{(2)}} &amp;= \frac{\partial KL(\rho||\hat{\rho_i})}{\partial z_i^{(2)}} \newline \\ &amp;= \frac{\partial KL(\rho||\hat{\rho_i})}{\partial \hat{\rho_i}}\cdot \frac{\partial \hat{\rho_i}}{\partial z_i^{(2)}} \\ &amp;= \frac{\partial(\rho \log \frac{\rho}{\hat{\rho_i}}+(1-\rho) \log \frac{1-\rho}{1-\hat{\rho_i}})}{\partial\hat{\rho_i}}\cdot \frac{\partial \hat{\rho_i}}{\partial z_i^{(2)}} \\ &amp;= (-\frac{\rho}{\hat{\rho_i}} + \frac{1-\rho}{1-\hat{\rho_i}}) \cdot {f}&#x27;(z_i^{(2)}) \end{aligned}
    因此Jsparse(W,b)J_{sparse}(W,b)的求导结果如下:
    Jsparse(W,b)zi(2)=((j=1s2Wji(2)J(W,b)zi(3))+β(ρρi^+1ρ1ρi^))f(zi(2)) \frac{\partial J_{sparse}(W,b)}{ \partial z_i^{(2)}}= ((\sum_{j=1}^{s_2}W_{ji}^{(2)}\frac{\partial J(W,b)}{ \partial z_i^{(3)}})+ \beta(-\frac{\rho}{\hat{\rho_i}} + \frac{1-\rho}{1-\hat{\rho_i}})){f}&#x27;(z_i^{(2)})
    此即反向传播的方程,根据此方程可以参数WWbb进行更新。

    3、Mini-Batch的情况

    平均激活度是根据所有样本计算出来的,所以在计算任何单元的平均激活度之前,需要对所有样本计算一下正向传播,从而获得平均激活度,所以使用小批量时计算效率很低。要解决这个问题,可采取的方法是只计算Mini-Batch中包含的训练样本的平均激活度,然后在Mini-Batch之间计算加权值
    ρ^jt=λρ^jt1+(1λ)ρ^jt \hat{\rho}_j^t=\lambda\hat{\rho}_j^{t-1}+(1-\lambda)\hat{\rho}_j^t
    其中,ρ^jt\hat{\rho}_j^t是时刻tt的Mini-Batch的平均激活度,ρ^jt1\hat{\rho}_j^{t-1}是时刻t-1的Mini-Batch的平均激活度。若\lambda大,则时刻t1t-1的Mini-Batch的平均激活度所占比重大,否则,时刻t的Mini-Batch的平均激活度所占比重大。

    4、稀疏限制和L1/L2正则化的关系

    ①稀疏限制是对激活函数的结果增加限制,使得尽量多的激活函数的结果为0(如果激活函数是tanh,则为-1)
    ②L2/L1是对参数增加限制,使得尽可能多的参数为0。
    若自编码器编码函数f(wx+b)f(wx+b),若ff是一个线性函数,则编码器便可以写成wx+bwx+b,限制激活函数的结果尽量为0,即是限制ww尽量为0,此时稀疏限制和正则化限制相同。

    5、稀疏自编码器在分类中的应用

    稀疏自编码器一般用来学习特征,以便用于像分类这样的任务。如下图(图片来源:为什么稀疏自编码器很少见到多层的?):

    上述过程不是一次训练的,可以看到上面只有编码器没有解码器,因此其训练过程是自编码器先使用数据训练参数,然后保留编码器,将解码器删除并在后面接一个分类器,并使用损失函数来训练参数已达到最后效果。

    5、稀疏编码器实现与结果分析

    (1)框架: Keras
    (2)数据集: Mnist手写数字识别
    (3)关键代码:

    def train(x_train):
    
        # input placeholder
        input_image = Input(shape=(ENCODING_DIM_INPUT, ))
    
        # encoding layer
        # *****!!! this code is changed compared with Autoencoder, adding the activity_regularizer to make the input sparse.
        encode_layer1 = Dense(ENCODING_DIM_LAYER1, activation='relu', activity_regularizer=regularizers.l1(10e-6))(input_image)
        # *******************************************************
        encode_layer2 = Dense(ENCODING_DIM_LAYER2, activation='relu')(encode_layer1)
        encode_layer3 = Dense(ENCODING_DIM_LAYER3, activation='relu')(encode_layer2)
        encode_output = Dense(ENCODING_DIM_OUTPUT)(encode_layer3)
    
        # decoding layer
        decode_layer1 = Dense(ENCODING_DIM_LAYER3, activation='relu')(encode_output)
        decode_layer2 = Dense(ENCODING_DIM_LAYER2, activation='relu')(decode_layer1)
        decode_layer3 = Dense(ENCODING_DIM_LAYER1, activation='relu')(decode_layer2)
        decode_output = Dense(ENCODING_DIM_INPUT, activation='tanh')(decode_layer3)
    
        # build autoencoder, encoder
        autoencoder = Model(inputs=input_image, outputs=decode_output)
        encoder = Model(inputs=input_image, outputs=encode_output)
    
        # compile autoencoder
        autoencoder.compile(optimizer='adam', loss='mse')
    
        # training
        autoencoder.fit(x_train, x_train, epochs=EPOCHS, batch_size=BATCH_SIZE, shuffle=True)
    
        return encoder, autoencoder
    

    这里是以多层的自编码器举例,单隐层的同样适用,主要是在第一层加一个正则化项,activity_regularizer=regularizers.l1(10e-6)说明加入的是L1正则化项,10e-6是正则化项系数,完整代码可参见最开始的git。其架构如下:

    (4)结果展示:
    (i)Encoder结果的可视化如图:

    上图中不同颜色表示不同的数字,由图可知,这个编码器的分类效果还可以,比自编码器好很多,但是看起来还是作用不大,因为大部分作用需要归功于栈式自编码器。

    (ii)autoencoder还原之后的图片和原图片对比如下:

    五、去噪自编码器(Denoising Autoencoder)

    1、去噪自编码器思想

    去噪自编码器是一类接受损失数据作为输入,并训练来预测原始未被损坏的数据作为输出的自编码器。 如下图所示(图片来自花书):

    其训练过程如下:
    引入一个损坏过程C(x~x)C(\tilde{x}|x),这个条件分布代表给定数据样本xx产生损坏样本x~\tilde{x}的概率。自编码器学习重构分布preconstruct(xx~)p_{reconstruct}(x|\tilde{x}):

    • 从训练数据中采一个训练样本xx
    • C(x~X=x)C(\tilde{x}|X=x)采一个损坏样本x~\tilde{x}
    • (x~,x)(\tilde{x}, x)作为训练样本来估计自编码器的重构分布preconstruct(xx~)=pdecoder(xh)p_{reconstruct}(x|\tilde{x})=p_{decoder}(x|h),其中hh是编码器f(x~)f(\tilde{x})的输出,pdecoderp_{decoder}根据解码函数g(h)g(h)定义。

    去噪自编码器中作者给出的直观解释是:和人体感官系统类似,比如人的眼睛看物体时,如果物体的某一小部分被遮住了,人依然能够将其识别出来,所以去噪自编码器就是破坏输入后,使得算法学习到的参数仍然可以还原图片。
    注: 噪声可以是添加到输入的纯高斯噪声,也可以是随机丢弃输入层的某个特性。

    2、去噪自编码器和Dropout

    噪声可以是添加到输入的纯高斯噪声,也可以是随机丢弃输入层的某个特性,即如果C(x~X=x)C(\tilde{x}|X=x)是一个二项分布,则其表现为下图所示内容,即经过处理的xx的结果是保留或者舍掉,也就是说,C(x~X=x)C(\tilde{x}|X=x)会舍去一部分内容,保留一部分内容:

    这个思想类似于Dropout,但是二者还有一些区别:

    (1) 去噪自编码器操作的是输入数据,相当于对输入数据去掉一部分内容;而Dropout操作的是网络隐藏层,相当于去掉隐藏层的一部分单元。
    (2) Dropout在分层预训练权值的过程中是不参与的,只是后面的微调部分会加入;而去噪自编码器是在每层预训练的过程中作为输入层被引入,在进行微调时不参与

    3、去噪自编码器和PCA

    去噪自编码器来源于论文[Vincent P, Larochelle H, Bengio Y, et al. Extracting and composing robust features with denoising autoencoders[C]//Proceedings of the 25th international conference on Machine learning. ACM, 2008: 1096-1103.]

    上图是去噪自编码器从流形角度的原理,图中黑色的曲线表示原始的局部流型,我们通过C(x~X=x)C(\tilde{x}|X=x)将其映射到一个圆的某一点,x~\tilde{x}表示添加噪声之后数据点。我们的目标是使得添加噪声之后的点能够映射到原始点,这样损失值为最小,即:图中红色箭头是噪声添加的向量场,而紫色部分是重构过程中需要不断查找的向量场。
    因此,可以理解为,去噪自编码器的局部就是简化的PCA原理,其是对PCA的非线性扩展。
    除此之外,文章还从信息论文、随机算子等角度理论上证明了去噪自编码器的可行性,有兴趣的读者可以参考上面提到的论文。

    4、去噪自编码器效果

    论文中的实验基于Minst数据集,其实验结果如下:

    其中,第一个和第二个baseline是使用高斯核和多项式核的SVM,DBN-1是1层隐层单元的深度信念网络,DBN-3是3层隐层单元的深度信念网络,SAA-3是使用栈式自编码器初始化之后的3层深度网络,最后的Sda-3是3层的栈式去噪自编码器。从表中可以看出,使用去噪自编码器的结果优于其他网络。
    除此之外,网站Denoising Autoencoders (dA)有去噪自编码器的代码和实验,其去噪前和去噪后过滤器的对比结果如下:

    左图是去噪之前的过滤器数据,右图是去噪之后的过滤器数据,从图中可以看出,去噪自编码器学习到的特征更具代表性。。

    5、去噪自编码器特点

    • 普通的自编码器的本质是学一个相等函数,即输入和输出是同一个内容,这种相等函数的缺点便是当测试样本和训练样本不符合同一个分布时,在测试集上效果不好,而去噪自编码器可以很好地解决这个问题。
    • 欠完备自编码器限制学习容量,而去噪自编码器允许学习容量很高,同时防止在编码器和解码器学习一个无用的恒等函数。
    • 经过了加入噪声并进行降噪的训练过程,能够强迫网络学习到更加鲁棒的不变性特征,获得输入的更有效的表达。

    6、去噪编码器实现与结果分析

    (1)框架: Keras
    (2)数据集: Mnist手写数字识别
    (3)关键代码:

    def addNoise(x_train, x_test):
        """
        add noise.
        :return:
        """
        x_train_noisy = x_train + NOISE_FACTOR * np.random.normal(loc=0.0, scale=1.0, size=x_train.shape)
        x_test_noisy = x_test + NOISE_FACTOR * np.random.normal(loc=0.0, scale=1.0, size=x_test.shape)
    
        x_train_noisy = np.clip(x_train_noisy, 0., 1.)     # limit into [0, 1]
        x_test_noisy = np.clip(x_test_noisy, 0., 1.)   # limit into [0, 1]
    
        return x_train_noisy, x_test_noisy
    

    去噪自编码器主要是对输入添加噪声,所以训练过程是不需要改变的,只需要改变输入和输出。上述便是对输入添加噪声的过程,NOISE_FACTOR * np.random.normal(loc=0.0, scale=1.0, size=x_train.shape)便是添加的噪声。 np.clip()是截取函数,将数值限制在0~1之间。其架构如下:

    (4)结果展示:
    (i)Eencoder结果的可视化如图:

    上图中不同表示表示不同的数字,这里不是很直观,看下面的图片对比

    (ii)autoencoder还原之后的图片和原图片对比如下:

    上图是添加噪声的效果对比,第一行表示原数据,第二行表示噪声处理过后的数据。

    上图根据噪声数据还原图片的对比,第一行表示噪声处理过后的数据,第二行表示去噪自编码器decoder还原之后的结果,上图可以看出,去噪自编码器的效果还是可以的。

    六、卷积自编码器(convolutional Autoencoder)

    1、卷积自编码器思想

    卷积自编码器和普通自编码器的区别在于其encoder和decoder都是卷积神经网络,相应的,encoder使用的是卷积操作和池化操作,而decoder中使用的反卷积操作和反卷积操作,关于卷积、反卷积、池化和反池化的内容详见:[CNN] 卷积、反卷积、池化、反池化

    2、去噪编码器实现与结果分析

    (1)框架: Keras
    (2)数据集: Mnist手写数字识别
    (3)关键代码:

    def train(x_train):
        """
        build autoencoder.
        :param x_train:  the train data
        :return: encoder and decoder
        """
        # input placeholder
        input_image = Input(shape=(28, 28, 1))
    
        # encoding layer
        x = Conv2D(CHANNEL_1, (3, 3), activation='relu', padding="same")(input_image)
        x = MaxPool2D((2, 2), padding='same')(x)
        x = Conv2D(CHANNEL_2, (3, 3), activation='relu', padding='same')(x)
        encoded = MaxPool2D((2, 2), padding='same')(x)
    
        # decoding layer
        x = Conv2D(CHANNEL_2, (3, 3), activation='relu', padding='same')(encoded)
        x = UpSampling2D((2, 2))(x)
        x = Conv2D(CHANNEL_1, (3, 3),activation='relu', padding='same')(x)
        x = UpSampling2D((2, 2))(x)
        decoded = Conv2D(CHANNEL_OUTPUT, (3, 3), activation='sigmoid', padding='same')(x)
    
        # build autoencoder, encoder, decoder
        autoencoder = Model(inputs=input_image, outputs=decoded)
        encoder = Model(inputs=input_image, outputs=encoded)
    
        # compile autoencoder
        autoencoder.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
    
        # training
        # need return history, otherwise can not use history["acc"]
        history_record = autoencoder.fit(x_train, x_train, epochs=EPOCHS, batch_size=BATCH_SIZE, shuffle=True, )
    
        return encoder, autoencoder, history_record
    

    注意:

    i)在Keras编码中,反卷积的实现代码便是卷积操作,具体解释详见上述博客。
    ii) UpSampling2D()实现的是反平均卷积的操作。

    autoencoder.summary()如下:

    代码架构图如下:

    (4)结果展示:
    (i)autoencoder还原之后的图片和原图片对比如下:

    上图根据原图片和生成图片的对比,第一行表示原图片,第二行表示卷积自编码器decoder还原之后的结果,上图可以看出,效果还是不错的。

    (ii)loss变化图:

    由上图可以看出,虽然loss在不断降低,但是accuracy还不是非常高,一方面是和参数相关,因为性能原因,在此文章版本上对epochs设置为20,另外,网络的深度也不够,也没有加入一些其他的提高性能的小技巧。



    其他参考文章:
    [1] Kandeng. 自编码算法与稀疏性[EB/OL]. (2018/11/24)[ 2018/11/24] http://ufldl.stanford.edu/wiki/index.php/自编码算法与稀疏性
    [2] Goodfellow I, Bengio Y, Courville A, et al. Deep learning[M]. Cambridge: MIT press, 2016.
    [3] 山下隆义. 图解深度学习[M]. 人民邮电出版社,2018:68-78
    [4] Francois Chollet. Building Autoencoders in Keras[EB/OL]. (2018/11/24)[ 2018/11/25] https://blog.keras.io/building-autoencoders-in-keras.html

    展开全文
  • 信源编码与信道编码

    万次阅读 多人点赞 2017-03-26 17:02:44
    但现代通信应用中常见的信源编码方式有:Huffman编码、算术编码、L-Z编码,这三种都是无损编码,另外还有一些有损的编码方式。信源编码的目标就是使信源减少冗余,更加有效、经济地传输,最常见的应用形式就是压缩。...

    一.信源编码和信道编码的发展历程

    信源编码:

        最原始的信院编码就是莫尔斯电码,另外还有ASCII码和电报码都是信源编码。但现代通信应用中常见的信源编码方式有:Huffman编码、算术编码、L-Z编码,这三种都是无损编码,另外还有一些有损的编码方式。信源编码的目标就是使信源减少冗余,更加有效、经济地传输,最常见的应用形式就是压缩。

    相对地,信道编码是为了对抗信道中的噪音和衰减,通过增加冗余,如校验码等,来提高抗干扰能力以及纠错能力。

    信道编码:

    1948年Shannon极限理论

    →1950年Hamming码

    →1955年Elias卷积码

    →1960年 BCH码、RS码、PGZ译码算法

    →1962年Gallager LDPC(Low Density Parity Check,低密度奇偶校验)码

    →1965年B-M译码算法

    →1967年RRNS码、Viterbi算法

    →1972年Chase氏译码算法

    →1974年Bahl MAP算法

    →1977年IMaiBCM分组编码调制

    →1978年Wolf 格状分组码

    →1986年Padovani恒包络相位/频率编码调制

    →1987年Ungerboeck TCM格状编码调制、SiMonMTCM多重格状编码调制、WeiL.F.多维星座TCM

    →1989年Hagenauer SOVA算法

    →1990年Koch Max-Lg-MAP算法

    →1993年Berrou Turbo码

    →1994年Pyndiah 乘积码准最佳译码

    →1995年 Robertson Log-MAP算法

    →1996年 Hagenauer TurboBCH码

    →1996MACKay-Neal重新发掘出LDPC码

    →1997年 Nick Turbo Hamming码

    →1998年Tarokh 空-时卷格状码、AlaMouti空-时分组码

    →1999年删除型Turbo码

         虽然经过这些创新努力,已很接近Shannon极限,例如1997年Nickle的TurboHamming码对高斯信道传输时已与Shannon极限仅有0.27dB相差,但人们依然不会满意,因为时延、装备复杂性与可行性都是实际应用的严峻要求,而如果不考虑时延因素及复杂性本来就没有意义,因为50多年前的Shannon理论本身就已预示以接近无限的时延总容易找到一些方法逼近Shannon极限。因此,信道编码和/或编码调制理论与技术在向Shannon极限逼近的创新过程中,其难点是要同时兼顾考虑好编码及交织等处理时延、比特误码率门限要求、系统带宽、码率、编码增益、有效吞吐量、信道特征、抗衰落色散及不同类别干扰能力以及装备复杂性等要求。从而,尽管人们普遍公认Turbo码确是快速逼近Shannon极限的一种有跃变性改进的码类,但其时延、复杂性依然为其最严峻的挑战因素,看来,沿AlaMouti的STB方式是一种看好的折衷方向。同样,实际性能可比Turbo码性能更优良的LDPC码,从1962年Gallager提出, 当时并未为人们充分理解与重视,至1996年为MACKay—Neal重新发现后掀起的另一股推进其研究、应用热潮, 此又为另一明显示例。LDPC码是一类可由非常稀疏的奇偶校验矩阵或二分图(Bi-PartiteGrapg)定义的线性分组前向纠错码,它具有更简单的结构描述与硬件复杂度,可实现完全并行操作,有利高速、大吞吐能力译码,且译码复杂度亦比Turbo码低,并具更优良的基底(Floor)残余误码性能,研究表明,最好的非正则(Irregular)LDPC码,其长度为106时可获得BER=10-6时与Shannon极限仅相差0.13dB;当码长为107、码率为1/2,与Shannon极限仅差0.04dB;与Turbo码结构不同,这是由另一种途径向“Shannon极限条件”的更有效与更逼真的模拟,从而取得比Turbo码更好的性能。因此,“学习、思考、创新、发展”这一永恒主题中持续“创新”最为关键,MIMO-STC及Turbo/LDPC码的发展历程亦充分证实了这一发展哲理。

    二.信源编码和信道编码远离的简要介绍

    信源编码:

    一种以提高通信有效性为目的而对信源符号进行的变换;为了减少或消除信源剩余度而进行的信源符号变换。为了减少信源输出符号序列中的剩余度、提高符号的平均信息量,对信源输出的符号序列所施行的变换。具体说,就是针对信源输出符号序列的统计特性来寻找某种方法,把信源输出符号序列变换为最短的码字序列,使后者的各码元所载荷的平均信息量最大,同时又能保证无失真地恢复原来的符号序列。

      数字信号在传输中往往由于各种原因,使得在传送的数据流中产生误码,从而使接收端产生图象跳跃、不连续、出现马赛克等现象。所以通过信道编码这一环节,对数码流进行相应的处理,使系统具有一定的纠错能力和抗干扰能力,可极大地避免码流传送中误码的发生。误码的处理技术有纠错、交织、线性内插等。

      提高数据传输效率,降低误码率是信道编码的任务。信道编码的本质是增加通信的可靠性。但信道编码会使有用的信息数据传输减少,信道编码的过程是在源数据码流中加插一些码元,从而达到在接收端进行判错和纠错的目的,这就是我们常常说的开销。这就好象我们运送一批玻璃杯一样,为了保证运送途中不出现打烂玻璃杯的情况,我们通常都用一些泡沫或海棉等物将玻璃杯包装起来,这种包装使玻璃杯所占的容积变大,原来一部车能装5000各玻璃杯的,包装后就只能装4000个了,显然包装的代价使运送玻璃杯的有效个数减少了。同样,在带宽固定的信道中,总的传送码率也是固定的,由于信道编码增加了数据量,其结果只能是以降低传送有用信息码率为代价了。将有用比特数除以总比特数就等于编码效率了,不同的编码方式,其编码效率有所不同。

        基于层次树的集分割(SPIHT)信源编码方法是基于EZW而改进的算法,它是有效利用了图像小波分解后的多分辨率特性,根据重要性生成比特流的一个渐进式编码。这种编码方法,编码器能够在任意位置终止编码,因此能够精确实现一定目标速率或目标失真度。同样,对于给定的比特流,解码器可以在任意位置停止解码,而仍然能够恢复由截断的比特流编码的图像。而实现这一优越性能并不需要事先的训练和预存表或码本,也不需要任何关于图像源的先验知识。

      数字电视中常用的纠错编码,通常采用两次附加纠错码的前向纠错(FEC)编码。RS编码属于第一个FEC,188字节后附加16字节RS码,构成(204,188)RS码,这也可以称为外编码。第二个附加纠错码的FEC一般采用卷积编码,又称为内编码。外编码和内编码结合一起,称之为级联编码。级联编码后得到的数据流再按规定的调制方式对载频进行调制。  

      前向纠错码(FEC)的码字是具有一定纠错能力的码型,它在接收端解码后,不仅可以发现错误,而且能够判断错误码元所在的位置,并自动纠错。这种纠错码信息不需要储存,不需要反馈,实时性好。所以在广播系统(单向传输系统)都采用这种信道编码方式。以下是纠错码的各种类型:

        既然信源编码的基本目的是提高码字序列中码元的平均信息量,那么,一切旨在减少剩余度而对信源输出符号序列所施行的变换或处理,都可以在这种意义下归入信源编码的范畴,例如过滤、预测、域变换和数据压缩等。当然,这些都是广义的信源编码。  

    一般来说,减少信源输出符号序列中的剩余度、提高符号平均信息量的基本途径有两个:①使序列中的各个符号尽可能地互相独立;②使序列中各个符号的出现概率尽可能地相等。前者称为解除相关性,后者称为概率均匀化。

    第三代移动通信中的信源编码包括语音压缩编码、各类图像压缩编码及多媒体数据压缩编码。

    信道编码:

        数字信号在传输中往往由于各种原因,使得在传送的数据流中产生误码,从而使接收端产生图象跳跃、不连续、出现马赛克等现象。所以通过信道编码这一环节,对数码流进行相应的处理,使系统具有一定的纠错能力和抗干扰能力,可极大地避免码流传送中误码的发生。误码的处理技术有纠错、交织、线性内插等。

    提高数据传输效率,降低误码率是信道编码的任务。信道编码的本质是增加通信的可靠性。但信道编码会使有用的信息数据传输减少,信道编码的过程是在源数据码流中加插一些码元,从而达到在接收端进行判错和纠错的目的,这就是我们常常说的开销。

    码率兼容截短卷积(RCPC)信道编码,就是一类采用周期性删除比特的方法来获得高码率的卷积码,它具有以下几个特点:

    (1)截短卷积码也可以用生成矩阵表示,它是一种特殊的卷积码;

    (2)截短卷积码的限制长度与原码相同,具有与原码同等级别的纠错能力;                                            (3)截短卷积码具有原码的隐含结构,译码复杂度降低;

       (4)改变比特删除模式,可以实现变码率的编码和译码。

    三.信源编码和信道编码的区别

        信源编码信源编码的作用之一是设法减少码元数目和降低码元速率,即通常所说的数据压缩。码元速率将直接影响传输所占的带宽,而传输带宽又直接反映了通信的有效性。作用之二是,当信息源给出的是模拟语音信号时,信源编码器将其转换成数字信号,以实现模拟信号的数字化传输。模拟信号数字化传输的两种方式:脉冲编码调制(PCM)和增量调制(ΔM)。信源译码是信源编码的逆过程。1.脉冲编码调制(PCM)简称脉码调制:一种用一组二进制数字代码来代替连续信号的抽样值,从而实现通信的方式。由于这种通信方式抗干扰能力强,它在光纤通信、数字微波通信、卫星通信中均获得了极为广泛的应用。增量调制(ΔM):将差值编码传输,同样可传输模拟信号所含的信息。此差值又称“增量”,其值可正可负。这种用差值编码进行通信的方式,就称为“增量调制”,缩写为DM或ΔM,主要用于军方通信中。信源编码为了减少信源输出符号序列中的剩余度、提高符号的平均信息量,对信源输出的符号序列所施行的变换。具体说,就是针对信源输出符号序列的统计特性来寻找某种方法,把信源输出符号序列变换为最短的码字序列,使后者的各码元所载荷的平均信息量最大,同时又能保证无失真地恢复原来的符号序列.信道编码的目的:信道编码是为了保证信息传输的可靠性、提高传输质量而设计的一种编码。它是在信息码中增加一定数量的多余码元,使码字具有一定的抗干扰能力。信道编码的实质:信道编码的实质就是在信息码中增加一定数量的多余码元(称为监督码元),使它们满足一定的约束关系,这样由信息码元和监督码元共同组成一个由信道传输的码字。信源编码很好理解,比如你要发送一个图形,必须把这个图像转成0101的编码,这就是信源编码。

        信道编码数字信号在信道传输时,由于噪声、衰落以及人为干扰等,将会引起差错。为了减少差错,信道编码器对传输的信息码元按一定的规则加入保护成分(监督元),组成所谓“抗干扰编码”。接收端的信道译码器按一定规则进行解码,从解码过程中发现错误或纠正错误,从而提高通信系统抗干扰能力,实现可靠通信。信道编码是针对无线信道的干扰太多,把你要传送的数据加上些信息,来纠正信道的干扰。信道编码数字信号在信道传输时,由于噪声、衰落以及人为干扰等,将会引起差错。为了减少差错,信道编码器对传输的信息码元按一定的规则加入保护成分(监督元),组成所谓“抗干扰编码”。接收端的信道译码器按一定规则进行解码,从解码过程中发现错误或纠正错误,从而提高通信系统抗干扰能力,实现可靠通信。

    信源编码信号:例如语音信号(频率范围300-3400Hz)、图象信号(频率范围0-6MHz)……基带信号(基带:信号的频率从零频附近开始)。在发送端把连续消息变换成原始电信号,这种变换由信源来完成。

    信道编码信号:例如二进制信号、2PSK信号……已调信号(也叫带通信号、频带信号)。这种信号有两个基本特征:一是携带信息;二是适应在信道中传输,把基带信号变换成适合在信道中传输的信号完成这样的变换是调制器。

    信源编码是对输入信息进行编码,优化信息和压缩信息并且打成符合标准的数据包。信道编码是在数据中加入验证码,并且把加入验证码的数据进行调制。两者的作用完全不一样的。信源编码是指信号来源的编码,主要是指从那个接口进来的。信道编码是说的信号通道的编码,一般是指机内的电路。总的来说吧:信源编码是对视频, 音频, 数据进行的编码,即对信息进行编码以便处理,而信道编码是指在信息传输的过程中对信息进行的处理。

    四.信源编码和信道编码在现代社会的应用

    1.在现代无线通信中的应用:

        通信的任务是由一整套技术设备和传输媒介所构成的总体——通信系统来完成的。电子通信根据信道上传输信号的种类可分为模拟通信和数字通信。最简单的数字通信系统模型由信源、信道和信宿三个基本部分组成。实际的数字通信系统模型要比简单的数字通信系统模型复杂得多。数字通信系统设备多种多样,综合各种数字通信系统,其构成如图所示:

        信源编码是以提高通信有效性为目的的编码。通常通过压缩信源的冗余度来实现。采用的一般方法是压缩每个信源符号的平均比特数或信源的码率。

    信道,通俗地说是指以传输媒质为基础的信号通路。具体地说,信道是指由有线或无线电线路提供的信号通路。信道的作用是传输信号,它提供一段频带让信号通过,同时又给信号加以限制和损害。

    信道编码是以提高信息传输的可靠性为目的的编码。通常通过增加信源的冗余度来实现。采用的一般方法是增大码率或带宽。与信源编码正好相反。在计算机科学领域,信道编码(channel code)被广泛用作表示编码错误监测和纠正的术语,有时候也可以在通信和存储领域用作表示数字调制方式。信道编码用来在数据传输的时候保护数据,还可以在出现错误的时候来恢复数据。

    2.在超宽带信道中的应用

    超宽带(Ultra Wideband,以下简称UWB) [1][2]系统具有高传输速率、低功耗、低成本等独特优点,是下一代短距离无线通信系统的有力竞争者。它是指具有很高带宽比射频(带宽与中心频率之比)的无线电技术。近年来,超宽带无线通信在图像和视频传输中获得了越来越广泛的应用,它具有极高的传输速率以及很宽的传输频带,可以提供高达1Gbit/s的数据传输速率,可用在数字家庭网络或办公网络中,实现近距离、高速率数据传输。例如,利用UWB技术可以在家用电器设备之间提供高速的音频、视频业务传输,在数字办公环境中,应用UWB技术可以减少线缆布放的麻烦,提供无线高速互联。  

        联合信源信道编码(Joint Source Channel Coding,以下简称JSCC)[3][4]近几年来日益受到通信界的广泛重视,主要原因是多媒体无线通信变得更加重要。根据Shannon信息论原理,通信系统中信源编码和信道编码是分离的[5],然而,该定理假设信源编码是最优的,可以去掉所有冗余,并且假设当比特率低于信道容量时可纠正所有误码。在不限制码长的复杂性和时延的前提下,可以得到这样的系统。而在实际系统中又必须限制码长的复杂性和时延,这必然会导致性能下降,这和香农编码定理的假设是相矛盾的。因此,在许多情况下,采用独立编码技术并不能获得满意的效果,例如有严重噪声的衰落信道和(移动通信信道),采用独立编码技术不能满足要求。因此需要将信源编码和信道编码联合考虑,在实际的信道条件中获得比信源和信道单独进行编码更好的效果。其中不等差错保护是联合信源信道编码的一种, 是相对于同等差错保护而言的。在网络资源有限的情况下,同等差错保护方案使得重要信息得不到足够的保护而使解码质量严重下降。而不等差错保护根据码流的不同部分对图像重建质量的重要性不同, 而采用不同的信道保护机制, 是信源信道联合编码的一个重要应用。

    不等差错保护(Unequal Error Protection,以下简称UEP)的信源编码主要采用嵌入式信源编码,如SPIHT(Set Partitioning In Hierarchical Trees) [6],EZW,JPEG2000等,信源输出码流具有渐进特性,信道编码采用RCPC[7],RCPT等码率可变的信道编码。文章[8]中研究了在AWGN信道下的不等差错保护的性能; 文章[9]中研究了有反馈的移动信道下的多分辨率联合信源信道编码;文章[10]研究了无线信道下的图像传输,信源编码采用SPIHT,信道编码采用多码率Turbo coder的不等差错保护方案;文章[11]中研究了DS-CDMA多径衰落信道下信源编码为分层视频图像编码,信道编码采用RCPC,解决了在信源编码,信道编码以及各个层之间的码率最优分配; 文章[12]研究了3G网络下MPEG-4视频流的传输,信道编码采用 Turbo编码,提出了用TCP传输非常重要的MPEG-4流,而用UDP传输MPEG-4 audio/video ES (Elementary Streams),并且对UDP传输的码流进行UEP的方案;文章[13]研究在无线频率选择性衰落信道中将MIMO-OFDM和adaptive wavelet pretreatment(自适应小波预处理)结合在一起的联合信源信道编码图像传输。据我们的了解, 现在并无文章研究超宽带无线信道下不等差错保护方案,本文将不等差错保护联合信源信道编码应用于超宽带无线通信中, 信源部分采用基于小波SPIHT 的编码方法,而信道部分采用RCPC编码( Rate Compatible Punctured Convolutional codes) 对SPIHT输出码流按重要程度进行不等错误保护,并基于DS-UWB[14]方案提出双重不等差错保护方案, 研究了不等差错保护给图像在超宽带无线通信中的图像传输所带来性能增益。  

    采用标准LENA256×256图像进行仿真实验, 信源编码采用SPIHT算法,SPIHT 编码速率为0.5bpp, 信道编码采用码率自适应截短卷积码RCPC, 对实验图像进行同等差错保护信道编码( EEP) 和不等差错保护信道编码(UEP), 对于EEP编码采用1/ 2 码率;对于UEP 编码,其重要信息(包括头部语法及图像重要数据) 采用1/ 3码率,对图像次重要数据采用1/ 2码率进行编码,对图像非重要数据不进行编码。信道编码输出码流经过一个(Ns,1)重复编码器,对重要信息Ns取30,次重要数据Ns取20,非重要数据Ns取为10,再用一个周期为Np=Ns的伪随机DS码序列对重复编码器输出序列进行编码,最后对编码输出进行PAM调制和脉冲成形从而形成DS-UWB发送信号波形,其中脉冲参数设置为平均发射功率为-30,抽样频率为50e9,平均脉冲重复时间为2e-9,冲激响应持续时间为0.5e-9,脉冲波形形成因子为0.25e-9。DS-UWB信号经过IEEE802.15.3a CM1信道模型,接收端采用Rake接收机对接收信号进行解调,解调后的码流经过RCPC信道译码和SPIHT信源译码恢复出原始图像。

               CMI信道模型下Double-UEP与UEP,EEP的性能比较

    图中给出了IEEE802.15.3a CM1信道模型下双重不等差错保护(Double-UEP)与传统不等差错保护(UEP)与同等差错保护(EEP)的性能比较,其中横轴为超宽带信道中的信噪比Eb/N0,纵轴为重建图像的峰值信噪比PSNR(Peek Signal Noise Ratio)。

      由图可见,在UWB信道中,不等差错保护的性能普遍好于同等差错保护的性能,尤其是在低信噪比的时候,采用不等差错保护能够获得更大的性能增益。在高信噪比时,由于此时信道质量较好,误码率较低,图像中的重要码流基本不会产生误码,此时不等差错保护和同等差错保护性能趋于一致;而在低信噪比时,由于不等差错保护方案对图像的重要信息加入了更多的冗余,从而在不增加传输速率的情况下使图像得以更可靠的传输,提升重建图像的质量。

    五.信源编码与信道编码的发展前景

    信息论理论的建立,提出了信息、信息熵的概念,接着人们提出了编码定理。编码方法有较大发展,各种界限也不断有人提出,使多用户信息论的理论日趋完整,前向纠错码(FEC)的码字也在不断完善。但现有信息理论中信息对象的层次区分对产生和构成信息存在的基本要素、对象及关系区分不清,适用于复杂信息系统的理论比较少,缺乏核心的“实有信息”概念,不能很好地解释信息的创生和语义歧义问题。只有无记忆单用户信道和多用户信道中的特殊情况的编码定理已有严格的证明,其他信道也有一些结果,但尚不完善。但近几年来,第三代移动通信系统(3G)的热衷探索,促进了各种数字信号处理技术发展,而且Turbo码与其他技术的结合也不断完善信道编码方案。

    移动通信的发展日新月异,从1978年第一代模拟蜂窝通信系统诞生至今,不过20多年的时间,就已经过三代的演变,成为拥有10亿多用户的全球电信业最活跃、最具发展潜力的业务。尤其是近几年来,随着第三代移动通信系统(3G)的渐行渐近,以及各国政府、运营商和制造商等各方面为之而投入的大量人力物力,移动通信又一次地在电信业乃至全社会掀起了滚滚热潮。虽然目前由于全球电信业的低迷以及3G系统自身存在的一些问题尚未完全解决等因素,3G业务的全面推行并不象计划中的顺利,但新一代移动通信网的到来必是大势所趋。因此,人们对新的移动通信技术的研究的热情始终未减。

    移动通信的强大魅力之所在就是它能为人们提供了固话所不及的灵活、机动、高效的通信方式,非常适合信息社会发展的需要。但同时,这也使移动通信系统的研究、开发和实现比有线通信系统更复杂、更困难。实际上,移动无线信道是通信中最恶劣、最难预测的通信信道之一。由于无线电波传输不仅会随着传播距离的增加而造成能量损耗,并且会因为多径效应、多普勒频移和阴影效应等的影响而使信号快速衰落,码间干扰和信号失真严重,从而极大地影响了通信质量。为了解决这些问题,人们不断地研究和寻找多种先进的通信技术以提高移动通信的性能。特别是数字移动通信系统出现后,促进了各种数字信号处理技术如多址技术、调制技术、纠错编码、分集技术、智能天线、软件无线电等的发展。

    结论:

    从文中我们可以清楚的认识到信源编码和信道编码的发展布满艰辛,今天的成就来之不易。随着今天移动通信技术的不断发展和创新,信源编码与信道编码的应用也越来越广泛,其逐步的应用于各个领域,在通信系统中扮演着非常重要的角色,起到了至关重要的作用。但是,现有信息理论也存在一定的缺陷,具体表现在以下几个方面:

    1.现有信息理论体系中缺乏核心的 “实有信息”概念。

    2.适用于复杂信息系统的理论比较少。目前的狭义与广义信息论大多是起源和立足于简单系统的信息理论,即用简单通讯信息系统的方法来类比复杂系统的信息现象,将复杂性当成了简单性来处理。而涉及生命现象和人的认识论层次的信息是很复杂的对象,其中信宿主体内信息的语义歧义和信息创生问题是难点,用现有信息理论难以解释。

    3.对产生和构成信息存在的基本要素、对象及关系区分不清。如将对象的直接存在(对象的物质、能量、相互作用、功能等存在)当成信息存在;将信息的载体存在当成信息存在;将信息与载体的统一体当成信息存在;把信宿获得的“实得信息”当成唯一的信息存在,这是主观信息论。或者把信源和信道信息当成唯一的信息存在,称之为客观信息论。这二种极端的信息理论正是忽略了信息在关系中产生、在关系中存在的复杂本质。忽略了信息存在至少涉及三个以上对象及复杂关系。

    4.现有信息理论不能很好地解释信息的创生和语义歧义问题。

    5.现有信息理论对信宿实得信息的理解过于简单,没有将直接实得信息与间接实得信息区别开来。

    6.信息对象的层次区分没有得到重视。不少研究者将本体论层次的信息与认识论层次的信息混为一谈,将普适性信息范畴与具体科学,特别是技术层次(如通信、控制、计算等)的信息概念混为一谈。抓住信息的某一层次或某一方面当成信息对象的总体。

        因此,在科学技术飞速发展的今天,我们应该加强对信源编码与信道编码的了解和认识,这能让在以后的生活和学习过程中不断完善和改进现有信息论存在的缺陷,更好的应用和了解我们的专业知识,更好更快的做好自己的工作,让自己能从各方面得到满意的结果。

    展开全文
  • 信源编码和信道编码

    千次阅读 2018-12-06 15:14:59
    但现代通信应用中常见的信源编码方式有:Huffman编码、算术编码、L-Z编码,这三种都是无损编码,另外还有一些有损的编码方式。信源编码的目标就是使信源减少冗余,更加有效、经济地传输,最常见的应用形式就是压缩。...
  • 哈夫曼编码

    千次阅读 2016-12-07 23:36:35
    不多说上代码: # include ...# define N 601 //如果想录入x字节那么就把N的数值改成x+1 x>3 # define M 13 //哈夫曼树编码的长度 typedef struct ptree //定义二叉树结点类型 { struct ptree *lchild;
  • J2EE-6 编码

    万次阅读 2018-09-19 10:04:56
    一个字符占用四个字符,第一个比特位是0 utf-8: 定义了字节序 汉字的编码长度是3个字节 unicode: 没有规定字节序 需要加两个字节用来指定字节序 两个字节 java程序的编码方式是unicode ...
  • 编码结构之编码时的分层处理架构  本博文主要介绍HEVC编码结构中的“编码时的分层处理架构”。HEVC编码结构的主要目的就是为了各种应用下操作的灵活性以及数据损失的鲁棒性(所谓“鲁棒性”,是指控制系统在...
  • 自从1980年提出矢量量化器码书设计的LBG算法以来,矢量量化技术已经成功地应用到图像压缩和语音编码中。 LBG算法中的最佳矢量量化器设计的关键是最佳划分和最佳码书的设计。 一是给定码书条件下寻找信源空间的最佳...
  • CABAC编码

    千次阅读 2012-04-28 15:00:11
    H.264/AVC标准采用了很多新技术和新方法,大大提高了视频编码效率,其中CABAC便... (1)上下文建模提供编码符号条件概率分布的估计。利用适当的上下文模型,在编码当前符号时,根据已编码的临近符号的概率统计,在不
  • 在视频压缩前后,对视频图像质量增强的操作视频编解码系统输出的图像主观质量不仅与压缩算法的性能有关,还受视频处理的影响压缩之前对视频的处理称作预处理(Pre-processing)压缩之后对视频的处理称作后处理(Post...
  • 稀疏编码

    千次阅读 2016-10-16 10:13:41
    稀疏编码学习笔记整理(一) 最近新入手稀疏编码,在这里记录我对稀疏编码的理解(根据学习进度不断更新中) 一,稀疏编码的概述  稀疏编码的概念来自于神经生物学。生物学家提出,哺乳类动物在长期的进化中,...
  • HM编码器代码阅读(12)——CU编码

    万次阅读 2016-04-14 16:28:03
    入口函数:TEncCu::compressCU(或者xCompressCU)。xCompressCU是一个递归函数,对于每一个CU,该函数都会被调用,主要是计算当前CU编码之后代价,然后再计算...(2)计算当前CU四个角的坐标 (3)调用xComputeQP计
  • 哈夫曼编码简介

    千次阅读 2013-09-21 19:58:17
     哈弗曼编码几乎是所有压缩算法的基础,其实这算法并不复杂,简单的理解就是,如何用更短的bit来编码数据。 我们知道普通的编码都是定长的,比如常用的ASCII编码,每字符都是8bit: 字符 编码...
  • DNA编码

    千次阅读 2017-12-27 14:42:19
    虽然一万不想学这东西,但还是要先了解一些。书名《DNA编码序列的设计与优化》 第一章 DNA的计算 主要讲了DNA计算相关的内容。 首先说了DNA为什么出现,分子水平的研究成熟,数学上很多NP-hard问题传统计算机...
  • 图像编码的原因: 数据时信息传递的手段,相同的信息可以通过不同的数据量去表示,尝试用不同的表达方式以减少表示图像的数据量,对图像的压缩可以通过对图像的编码实现。 数据压缩 减少表示给定信息所需要的数据量...
  • Android 音视频采集与软编码总结

    万次阅读 2017-07-22 21:06:24
    前言 本文总结了笔者在 Android 音视频采集与软编码中的一些经验与技巧,包括移植 FFmpeg、YUV 视频帧处理... 文章最后将展示一实现了音视频采集功能与本地视频压缩功能的完整项目。 采用软编码利弊 众所周知
  • 哈夫曼树和哈夫曼编码
  • 霍夫曼编码(Huffman Coding)

    万次阅读 多人点赞 2016-09-22 21:44:16
    霍夫曼编码使用变长编码表对源符号(如文件中的一字母)进行编码,其中变长编码表是通过一种评估来源符号出现机率的方法得到的,出现机率高的字母使用较短的编码,反之出现机率低的则使用较长的编码,这便使编码...
  • 信号与编码

    千次阅读 2013-08-19 16:47:28
    翻出来一篇自己学习信号与编码时做的笔记。简单的介绍下信号、采样、脉冲、时钟,与编码
  • 哈夫曼树与哈夫曼编码(前缀编码)理解

    万次阅读 多人点赞 2017-11-21 14:30:11
    哈夫曼树又称最优二叉树,是带权路径长度(WPL)最短的树,可以构造最优编码,用于数据传输,数据压缩等方向 下面是二叉树和哈夫曼树二、概念 路径:树中一结点到另一结点之间的分支序列构成两结点间的路径 ...
  • 对抗自编码器指南之一:自编码

    千次阅读 2017-12-09 19:21:41
    编码器是一种特殊的神经网络(`neural network`),它的输出目标(`target`)就是输入(所以它基本上就是试图将输出重构为输入),由于它不需要任何人工标注,所以可以...自编码器包括两组成部分:编码器和解码器。
  • 《H.264/AVC视频编解码技术详解》视频教程已经在“CSDN学院”上线,视频中详述了H.264的背景、标准协议和实现,并通过一实战工程的形式对H.264的标准进行解析和实现,欢迎观看!“纸上得来终觉浅,绝知此事要躬行...
  • MPEG2视频编码简介

    千次阅读 2019-04-20 17:42:17
    MPEG-2视频编码简介 MPEG-2是一组用于视音频压缩编码及其数据流封装的国际标准。它定义了编解码技术及数据流的传输协议;制定了MPEG-2解码器之间的共同标准。编码是MPEG-2标准的核心内容之一,其涉及到MPEG-2视频流...
  • 贪心算法之哈夫曼编码问题

    万次阅读 2018-03-04 03:09:45
    问题利用字符的使用频率来编码,是不等长编码方法,使得经常使用的字符编码较短,不常使用的字符编码较长。如果采用等长的编码方案,假设所有字符的编码都等长,则表示 n 不同的字符需要 ⎡log n⎤ 位。例如,3 ...
  • QT 编码 字符集

    千次阅读 2010-10-20 13:10:00
    http://dxwang.blog.51cto.com/384651/216271【Qt 编码简单实验】 首先,Qt中得QString 类对字符串进行了封装,其内部使用...由于QString的Unicode编码,和本地系统的编码不一定是一致的(比如系统采用的GB
  • 常见视频编码格式解析

    万次阅读 多人点赞 2017-12-15 14:12:56
    常见视频编码格式解析 常见视频编码格式解析 1.MPEG2-TS编码技术 1.1.MPEG-TS简介 1.2.基本概念及TS流概述 1.3.基本流程 1.4.TS流传输包(简称TS包)结构分析 1.4.1.TS包包头 1.4.2.TS包净荷部分 1.5.PS节目流 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 214,709
精华内容 85,883
关键字:

影响编码的四个条件