精华内容
下载资源
问答
  • 文章目录类加载机制类加载机制分类、类加载器、双亲委派机制类加载机制分类类加载器双亲委派机制加载.class文件的方式生命周期生命周期结束类加载过程JVM初始化步骤类加载时机类初始化时机初始化类的实例化 ...

    平常总是对类的加载,初始化,实例化,类加载机制。。。等等概念容易搞混,这里记录一下!

    类加载机制

    虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验,转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型的过程就是虚拟机的 类加载机制

    类加载机制分类、类加载器、双亲委派机制

    类加载机制分类

    • 全盘负责,当一个类加载器负责加载某个Class时,该Class所依赖的和引用的其他Class也将由该类加载器负责载入,除非显示使用另外一个类加载器来载入
    • 父类委托(双亲委派),先让父类加载器试图加载该类,只有在父类加载器无法加载该类时才尝试从自己的类路径中加载该类 (这个是JVM采用的!)

    • 缓存机制,缓存机制将会保证所有加载过的Class都会被缓存,当程序中需要使用某个Class时,类加载器先从缓存区寻找该Class,只有缓存区不存在,系统才会读取该类对应的二进制数据,并将其转换成Class对象,存入缓存区。这就是为什么修改了Class后,必须重启JVM,程序的修改才会生效

    类加载器

    虚拟机设计团队把类加载中的“通过一个类的全限定名来获取描述此类的二进制字节流”这个动作放到Java虚拟机外部去实现,以便让应用程序自己决定如何去获取所需要的类。实现这个动作的代码块称为类加载器。

    从Java开发人员的角度看,类加载器大致分为如下3种

    启动类加载器(Bootstrap Classloader):负责将存放在<JAVA_HOME>\lib(Javahome即jdk的安装目录)目录中的,或者被-Xbootclasspath参数所指定的路径中的,并且是虚拟机识别的(仅按照文件名识别,如rt.jar,名字不符合的类库即使放在lib下面也不会被加载)类库加载到虚拟机内存中。启动类加载器无法被Java程序直接使用。

    扩展类加载器(Extension Classloader):该加载器由sun.misc.Launcher$ExtClassLoader实现,它负责加载<JAVA_HOME>\lib\ext目录中的,或者被java.ext.dirs系统变量所指定的系统路径中的所有类库。开发者可以直接使用扩展类加载器。

    应用程序类加载器(Application Classloader):该加载器由sun.misc.Launcher$AppClassLoader实现,它负责加载用户类路径(ClassPath)上所指定的类库。开发者可以直接使用此加载器。如果应用程序中没有自定义的类加载器,那么这个就是程序默认执行的类加载器。(系统加载器)

    我们的应用程序都是由这3种类加载器相互配合进行加载的。如果有必要,还可以加入自定义的类加载器。

    这些类加载器之间的关系如下图:

    img

    双亲委派机制

    双亲委派模型的工作过程是:如果一个类加载器收到了一个类加载请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每一层的加载器都是如此,因此所有的加载请求最终都应该到达顶层的启动类加载器。只有当父加载无法完成这个加载请求时,子加载器才会尝试自己去加载。

    1、当ApplicationClassLoader加载一个class时,它首先不会自己去尝试加载这个类,而是把类加载请求委派给父类加载器ExtClassLoader去完成。

    2、当ExtClassLoader加载一个class时,它首先也不会自己去尝试加载这个类,而是把类加载请求委派给BootStrapClassLoader去完成。

    3、如果BootStrapClassLoader加载失败(例如在$JAVA_HOME/jre/lib里未查找到该class),会使用ExtClassLoader来尝试加载;

    4、若ExtClassLoader也加载失败,则会使用AppClassLoader来加载,如果AppClassLoader也加载失败,则会报出异常ClassNotFoundException。

    ClassLoader源码分析:

    protected Class<?> loadClass(String name, boolean resolve)
            throws ClassNotFoundException
        {
            synchronized (getClassLoadingLock(name)) {
                // 先检查此类是否已被加载
                Class<?> c = findLoadedClass(name);
                if (c == null) {
                    long t0 = System.nanoTime();
                    try {
                        //委派给父类加载器去加载
                        if (parent != null) {
                            c = parent.loadClass(name, false);
                        } else {
                            //如果没有父加载器,则调用启动类加载器
                            c = findBootstrapClassOrNull(name);
                        }
                    } catch (ClassNotFoundException e) {
                        // ClassNotFoundException thrown if class not found
                        // from the non-null parent class loader
                    }
                    //如果父加载器无法加载,则调用本身加载器去加载
                    if (c == null) {
                        // If still not found, then invoke findClass in order
                        // to find the class.
                        long t1 = System.nanoTime();
                        c = findClass(name);
     
                        // this is the defining class loader; record the stats
                        sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                        sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                        sun.misc.PerfCounter.getFindClasses().increment();
                    }
                }
                if (resolve) {
                    resolveClass(c);
                }
                return c;
            }
        }                      
    

    双亲委派模型意义:

    • 系统类防止内存中出现多份同样的字节码
    • 保证Java程序安全稳定运行

    加载.class文件的方式

    • 从本地系统中直接加载
    • 通过网络下载.class文件
    • 从zip,jar等归档文件中加载.class文件
    • 从专有数据库中提取.class文件
    • 将Java源文件动态编译为.class文件

    类生命周期

    img

    类生命周期结束

    在如下几种情况下,Java虚拟机将结束生命周期

    • 执行了System.exit()方法

    • 程序正常执行结束

    • 程序在执行过程中遇到了异常或错误而异常终止

    • 由于操作系统出现错误而导致Java虚拟机进程终止

    类加载过程

    其中类加载的过程包括了加载、验证、准备、解析、初始化五个阶段。 在这五个阶段中,加载、验证、准备和初始化这四个阶段发生的顺序是确定的,而解析阶段则不一定,它在某些情况下可以在初始化阶段之后开始,这是为了支持Java语言的运行时绑定(也成为动态绑定或晚期绑定)。另外注意这里的几个阶段是按顺序开始,而不是按顺序进行或完成,因为这些阶段通常都是互相交叉地混合进行的,通常在一个阶段执行的过程中调用或激活另一个阶段。

    • 加载:就是指将class文件读入内存,并为之创建一个Class对象。任何类被使用时系统都会建立一个Class对象。

    • 连接:包括以下三个步骤

      • 验证:是否有正确的内部结构,并和其他类协调一致
      • 准备:负责为类的静态成员分配内存 (所使用的内存都将在方法区中进行分配),并设置默认初始化值 (注意这里并没有指定具体的值,只是默认值,比如int是0,boolean是false。指定具体的值那是在类的初始化。但是,如果是static final静态常量,则直接指定具体的值!)
      • 解析:将常量池内的符号引用替换为直接引用
    • 初始化,为类的静态变量赋予正确的初始值,JVM负责对类进行初始化,主要对类变量进行初始化。在Java中对类变量进行初始值设定有两种方式:

      ①声明类变量并指定初始值

      ②使用静态代码块为类变量指定初始值

    JVM初始化步骤

    1、假如这个类还没有被加载和连接,则程序先加载并连接该类

    2、假如该类的直接父类还没有被初始化,则先初始化其直接父类

    3、假如类中有初始化语句,则系统依次执行这些初始化语句

    img

    类加载时机

    类加载器并不需要等到某个类被“首次主动使用”时再加载它,JVM规范允许类加载器在预料某个类将要被使用时就预先加载它,如果在预先加载的过程中遇到了.class文件缺失或存在错误,类加载器必须在程序首次主动使用该类时才报告错误(LinkageError错误)如果这个类一直没有被程序主动使用,那么类加载器就不会报告错误

    所以什么情况下虚拟机需要开始加载一个类呢?虚拟机规范中并没有对此进行强制约束,这点可以交给虚拟机的具体实现来自由把握。

    类初始化时机

    注意和上面的类加载时机区别,不要搞混

    那么,什么情况下虚拟机需要开始初始化一个类呢?这在虚拟机规范中是有严格规定的,虚拟机规范指明 有且只有 五种情况必须立即对类进行初始化(而这一过程自然发生在加载、验证、准备之后):

    1) 遇到new、getstatic、putstatic或invokestatic这四条字节码指令(注意,newarray指令触发的只是数组类型本身的初始化,而不会导致其相关类型的初始化,比如,new String[]只会直接触发String[]类的初始化,也就是触发对类[Ljava.lang.String的初始化,而直接不会触发String类的初始化)时,如果类没有进行过初始化,则需要先对其进行初始化。生成这四条指令的最常见的Java代码场景是:

    • 使用new关键字实例化对象的时候;

    • 读取或设置一个类的静态字段(被final修饰,已在编译器把结果放入常量池的静态字段除外)的时候;

    • 调用一个类的静态方法的时候。

    2) 使用java.lang.reflect包的方法对类进行反射调用的时候,如果类没有进行过初始化,则需要先触发其初始化。

    3) 当初始化一个类的时候,如果发现其父类还没有进行过初始化,则需要先触发其父类的初始化。

    4) 当虚拟机启动时,用户需要指定一个要执行的主类(包含main()方法的那个类),虚拟机会先初始化这个主类。

    5) 当使用jdk1.7动态语言支持时,如果一个java.lang.invoke.MethodHandle实例最后的解析结果REF_getstatic,REF_putstatic,REF_invokeStatic的方法句柄,并且这个方法句柄所对应的类没有进行初始化,则需要先出触发其初始化。

    注意,对于这五种会触发类进行初始化的场景,虚拟机规范中使用了一个很强烈的限定语:“有且只有”,这五种场景中的行为称为对一个类进行 主动引用。除此之外,所有引用类的方式,都不会触发初始化,称为 被动引用。
      
    被动引用的几种经典场景
    1)、通过子类引用父类的静态字段,不会导致子类初始化

     public class SSClass{
        static{
            System.out.println("SSClass");
        }
    }  
    
    public class SClass extends SSClass{
        static{
            System.out.println("SClass init!");
        }
    
        public static int value = 123;
    
        public SClass(){
            System.out.println("init SClass");
        }
    }
    
    public class SubClass extends SClass{
        static{
            System.out.println("SubClass init");
        }
    
        static int a;
    
        public SubClass(){
            System.out.println("init SubClass");
        }
    }
    
    public class NotInitialization{
        public static void main(String[] args){
            System.out.println(SubClass.value);
        }
    }
    /* Output: 
            SSClass
            SClass init!
            123     
     */
    

    对于静态字段,只有直接定义这个字段的类才会被初始化,因此通过其子类来引用父类中定义的静态字段,只会触发父类的初始化而不会触发子类的初始化。在本例中,由于value字段是在类SClass中定义的,因此该类会被初始化;此外,在初始化类SClass时,虚拟机会发现其父类SSClass还未被初始化,因此虚拟机将先初始化父类SSClass,然后初始化子类SClass,而SubClass始终不会被初始化。
    2)、通过数组定义来引用类,不会触发此类的初始化

    public class NotInitialization{
        public static void main(String[] args){
            SClass[] sca = new SClass[10];
        }
    }
    

    上述案例运行之后并没有任何输出,说明虚拟机并没有初始化类SClass。但是,这段代码触发了另外一个名为[Lcn.edu.tju.rico.SClass的类的初始化。从类名称我们可以看出,这个类代表了元素类型为SClass的一维数组,它是由虚拟机自动生成的,直接继承于Object的子类,创建动作由字节码指令newarray触发。
    3)、常量在编译阶段会存入调用类的常量池中,本质上并没有直接引用到定义常量的类,因此不会触发定义常量的类的初始化

    public class ConstClass{
    
        static{
            System.out.println("ConstClass init!");
        }
    
        public static  final String CONSTANT = "hello world";
    }
    
    public class NotInitialization{
        public static void main(String[] args){
            System.out.println(ConstClass.CONSTANT);
        }
    }/* Output: 
            hello world
     *///:~
    

    上述代码运行之后,只输出 “hello world”,这是因为虽然在Java源码中引用了ConstClass类中的常量CONSTANT,但是编译阶段将此常量的值“hello world”存储到了NotInitialization常量池中,对常量ConstClass.CONSTANT的引用实际都被转化为NotInitialization类对自身常量池的引用了。也就是说,实际上NotInitialization的Class文件之中并没有ConstClass类的符号引用入口,这两个类在编译为Class文件之后就不存在关系了。

    类的初始化

    是完成程序执行前的准备工作。在这个阶段,静态的(变量,代码块)会被执行,而静态方法会在第一次调用才执行。同时在会开辟一块存储空间用来存放静态的数据。初始化只在类加载的时候执行一次。

    这里贴一张JVM的图:运行时区内存分配

    img测试类:

    public class StaticTest {
        public static void main(String[] args) {
            System.out.println("-----执行staticFunction()----");
            staticFunction();
            System.out.println("执行StaticTest st = new StaticTest();");
            StaticTest st = new StaticTest();
        }
    
        int a = 110;    // 实例变量
        static int b = 112;     // 静态变量
        static StaticTest st = new StaticTest();
    
        static {   //静态代码块
            System.out.println("1");
        }
    
        {       // 实例代码块
            System.out.println("2");
        }
    
        public StaticTest() {    // 实例构造器
            System.out.println("3");
            System.out.println("a=" + a + ",b=" + b);
        }
    
        public static void staticFunction() {   // 静态方法
            System.out.println("4");
        }
    
    }
    

    输出结果分析:

    前三行输出:是执行static StaticTest st = new StaticTest();相当于在实例化对象,而后由于执行了main方法,所以static静态块执行了,然后才执行staticFunction()。

    最后三行输出:就是执行StaticTest st = new StaticTest();,再次创建一个对象,注意这时候不会再执行静态代码块!只会首次执行一次!!

    2
    3
    a=110,b=112
    1
    -----执行staticFunction()----
    4
    执行StaticTest st = new StaticTest();
    2
    3
    a=110,b=112
    

    如果把static StaticTest st = new StaticTest();这个去掉,那输出如下:

    这里由于不用实例化对象,这里直接进入main方法,会先加载静态代码块,然后执行方法,最后创建对象!

    1
    -----执行staticFunction()----
    4
    执行StaticTest st = new StaticTest();
    2
    3
    a=110,b=112
    

    注意!!!
    main函数是static的,它执行前一定要先加载本类–也就是要进行类的初始化,所以静态代码块一定优先于main函数执行
    注意类的初始化顺序:变量(先static变量,后全局变量)、然后再static静态代码块!!!

    也就是单纯运行main函数也会输出如下结果:

       public static void main(String[] args) {
          /*  System.out.println("-----执行staticFunction()----");
            staticFunction();
            System.out.println("执行StaticTest st = new StaticTest();");
            StaticTest st = new StaticTest();*/
        }
        
    输出结果:    
    2
    3
    a=110,b=112
    1
    

    注意,对于这五种会触发类进行初始化的场景,虚拟机规范中使用了一个很强烈的限定语:“有且只有”,这五种场景中的行为称为对一个类进行 主动引用。除此之外,所有引用类的方式,都不会触发初始化,称为 被动引用。

    类的实例化

    类的实例化也叫对象初始化,这是一个概念。类是对象的抽象,对象是类的具体实例!

    是指创建一个对象的过程。这个过程中会在堆中开辟内存,将一些非静态的方法,变量存放在里面。在程序执行的过程中,可以创建多个对象,既多次实例化。每次实例化都会开辟一块新的内存。

    可以参考我的另一篇文章进行理解,new 一个对象到底发生了什么?https://blog.csdn.net/belongtocode/article/details/105794529

    public class Student {
        private String name = "林青霞";
        private int    age  = 27;
    
        public Student() {
            name = "刘意";
            age = 30;
        }
    
    }
    
    class StudentDemo {
        public static void main(String[] args) {
            Student s = new Student();
        }
    }
    
    

    上面main方法中运行的程序过程如下:
    (1)用户创建了一个Student对象,运行时JVM首先会去方法区寻找该对象的类型信息,没有则使用类加载器classloader将Student.class字节码文件加载至内存中的方法区,并将Student类的类型信息存放至方法区。
    (2)接着JVM在堆中为新的Student实例分配内存空间,这个实例持有着指向方法区的Student类型信息的引用,引用指的是类型信息在方法区中的内存地址。
    (3)在此运行的JVM进程中,会首先起一个线程跑该用户程序,而创建线程的同时也创建了一个虚拟机栈,虚拟机栈用来跟踪线程运行中的一系列方法调用的过程,每调用一个方法就会创建并往栈中压入一个栈帧,栈帧用来存储方法的参数,局部变量和运算过程的临时数据。上面程序中的stu是对Student的引用,就存放于栈中,并持有指向堆中Student实例的内存地址。
    (4)JVM根据stu引用持有的堆中对象的内存地址,定位到堆中的Student实例,由于堆中实例持有指向方法区的Student类型信息的引用,从而获得add()方法的字节码信息,接着执行add()方法包含的指令。

    image-20200829144652537

    对象的创建过程

    对象的内存布局:
    在 Hotspot 虚拟机中,对象在内存中的布局可以分为 3 块区域:对象头、实例数据和对齐填充。

    Step1:类加载检查

    虚拟机遇到一条 new 指令时,首先将去检查这个指令的参数是否能在常量池中定位到这个类的符号引用,并且检查这个符号引用代表的类是否已被加载过、解析和初始化过。如果没有,那必须先执行相应的类加载过程。

    Step2:分配内存

    类加载检查通过后,接下来虚拟机将为新生对象分配内存。对象所需的内存大小在类加载完成后便可确定,为对象分配空间的任务等同于把一块确定大小的内存从 Java 堆中划分出来。分配方式“指针碰撞”“空闲列表” 两种,选择哪种分配方式由 Java 堆是否规整决定,而 Java 堆是否规整又由所采用的垃圾收集器是否带有压缩整理功能决定

    Step3:初始化零值

    内存分配完成后,虚拟机需要将分配到的内存空间都初始化为零值(不包括对象头),这一步操作保证了对象的实例字段在 Java 代码中可以不赋初始值就直接使用,程序能访问到这些字段的数据类型所对应的零值。

    Step4:设置对象头

    初始化零值完成之后,虚拟机要对对象进行必要的设置,例如这个对象是哪个类的实例、如何才能找到类的元数据信息、对象的哈希码、对象的 GC 分代年龄等信息。 这些信息存放在对象头中。 另外,根据虚拟机当前运行状态的不同,如是否启用偏向锁等,对象头会有不同的设置方式。

    Step5:执行 init 方法

    在上面工作都完成之后,从虚拟机的视角来看,一个新的对象已经产生了,但从 Java 程序的视角来看,对象创建才刚开始,<init> 方法还没有执行,所有的字段都还为零。所以一般来说,执行 new 指令之后会接着执行 <init> 方法,把对象按照程序员的意愿进行初始化,这样一个真正可用的对象才算完全产生出来。

    参考文章:
    https://www.cnblogs.com/ityouknow/p/5603287.html
    https://www.cnblogs.com/chenpt/p/9777367.html
    https://blog.csdn.net/qq_39429962/article/details/83190112
    https://blog.csdn.net/justloveyou_/article/details/72466105

    展开全文
  • AllenNLP参数初始化源码可以阅读allennlp.nn....模型的构造参数设置一项initializer: InitializerApplicator = InitializerApplicator(),用initializer来对模型参数进行不同的初始化__init__最后加一行initia...

    AllenNLP参数初始化源码可以阅读allennlp.nn.initializers,他们将加载预训练模型也作为一种参数初始化方式,加到这部分。

    使用方法

    1. 模型的构造参数设置一项initializer: InitializerApplicator = InitializerApplicator(),用initializer来对模型参数进行不同的初始化。
    2. 在__init__最后加一行initializer(self)
    3. 设置配置文件,举个例子:
    "model":
    {
      ...,
     "initializer": 
          [
                [".*_highway_layer._layers.*.weight", {"type": "xavier_normal"}],
                [".*highway_layer._layers.*bias", {"type": "constant", "val": 0}],
                [
                    ".*_text_field_embedder.*|_model_highway_layer._layers.*|.*encoding_proj.*|.*_phrase_layer.*|.*_modeling_layer.*|.*predictor.*|.*_matrix_attention.*",
                    {
                        "type": "pretrained",
                        "weights_file_path": "./weights.th"
                    }
                ]
          ]
    }
    
    • 用正则表达式确定需要初始化的层,常用的是“.*”,表示匹配任意个数的任意字符
    • 我在使用过程中注意到需要避免对Layernorm初始化,bias不能用xavier_normal
    • 可以对不同的层进行不同的初始化,比如在修改一部分结构之后,可以对其他部分用预训练模型初始化,对修改的部分用其他初始化方式
    展开全文
  • 从预训练的模型加载参数 2. 对新网络两部分设置不同的学习率,主要训练自己添加的层 PyTorch提供的预训练模型PyTorch定义了几个常用模型,并且提供了预训练版本:AlexNet: AlexNet variant from the “One weird ...
    在预训练网络的基础上,修改部分层得到自己的网络,通常我们需要解决的问题包括: 
    
    1. 从预训练的模型加载参数 

    2. 对新网络两部分设置不同的学习率,主要训练自己添加的层 

    PyTorch提供的预训练模型

    PyTorch定义了几个常用模型,并且提供了预训练版本:

    • AlexNet: AlexNet variant from the “One weird trick” paper.
    • VGG: VGG-11, VGG-13, VGG-16, VGG-19 (with and without batch normalization)
    • ResNet: ResNet-18, ResNet-34, ResNet-50, ResNet-101, ResNet-152
    • SqueezeNet: SqueezeNet 1.0, and SqueezeNet 1.1

    预训练模型可以通过设置pretrained=True来构建:

    eg:

    import torchvision.models as models
    resnet18 = models.resnet18(pretrained=True)
    vgg16 = models.vgg16(pretrained=True)
    alexnet = models.alexnet(pretrained=True)
    squeezenet = models.squeezenet1_0(pretrained=True)

    预训练模型期望的输入是RGB图像的mini-batch:(batch_size, 3, H, W),并且H和W不能低于224。图像的像素值必须在范围[0,1]间,并且用均值mean=[0.485, 0.456, 0.406]和方差std=[0.229, 0.224, 0.225]进行归一化。

    加载预训练模型

    加载参数可以参考 apaszke推荐的做法 ,即删除与当前model不匹配的key。

    torch.nn.Module对象有函数static_dict()用于返回包含模块所有状态的字典,包括参数和缓存。键是参数名称或者缓存名称。

    函数Module::load_state_dict(state_dict)用state_dict中的状态值更新模块的状态值。static_dict中的键应该和函数static_dict()返回的字典中的键完全一样。

    下面给出加载预训练的模型的示例:

    vgg16 = models.vgg16(pretrained=True)
    pretrained_dict = vgg16.state_dict()
    model_dict = model.state_dict()
    
    # 1. filter out unnecessary keys
    pretrained_dict = {k: v for k, v in pretrained_dict.items() if k in model_dict}
    # 2. overwrite entries in the existing state dict
    model_dict.update(pretrained_dict) 
    # 3. load the new state dict
    model.load_state_dict(model_dict)

    不同层设置不同学习率的方法 

    此部分主要参考 PyTorch教程的Autograd machnics部分 
    在PyTorch中,每个Variable数据含有两个flag(requires_grad和volatile)用于指示是否计算此Variable的梯度。设置requires_grad = False,或者设置volatile=True,即可指示不计算此Variable的梯度
    for param in model.parameters():
        param.requires_grad = False
    注意,在模型测试时,对input_data设置volatile=True,可以节省测试时的显存




    展开全文
  • 一:查看预训练模型参数(以Alexnet为例): path = 'I:/迅雷下载/alexnet-owt-4df8aa71.pth' pretrained_dict = torch.load(path) for k, v in pretrained_dict.items(): # k 参数名 v 对应参数值 print(k) ...

    一:查看预训练模型的参数(以Alexnet为例):

    path = 'I:/迅雷下载/alexnet-owt-4df8aa71.pth'
    pretrained_dict = torch.load(path)
    for k, v in pretrained_dict.items():  # k 参数名 v 对应参数值
            print(k)

    运行结果:                                             参数名对应AlexNet网络的位置

     二:使用部分预训练模型参数初始化网络

    方式一: 自己网络和预训练网络结构一致的层,使用预训练网络对应层的参数批量初始化

    model_dict = model.state_dict()                                    # 取出自己网络的参数字典
    pretrained_dict = torch.load("I:/迅雷下载/alexnet-owt-4df8aa71.pth")# 加载预训练网络的参数字典
    # 取出预训练网络的参数字典
    keys = []
    for k, v in pretrained_dict.items():
           keys.append(k)
    i = 0
    
    # 自己网络和预训练网络结构一致的层,使用预训练网络对应层的参数初始化
    for k, v in model_dict.items():
        if v.size() == pretrained_dict[keys[i]].size():
             model_dict[k] = pretrained_dict[keys[i]]
             #print(model_dict[k])
             i = i + 1
    model.load_state_dict(model_dict)
    

    方式二:自己网络和预训练网络结构一致的层,按层初始化

    # 加粗自己定义一个网络叫CNN
    model = CNN()
    model_dict = model.state_dict()                                    # 取出自己网络的参数
    
    for k, v in model_dict.items():                                    # 查看自己网络参数各层叫什么名称
           print(k)
    
    pretrained_dict = torch.load("I:/迅雷下载/alexnet-owt-4df8aa71.pth")# 加载预训练网络的参数
    for k, v in pretrained_dict.items():                                    # 查看预训练网络参数各层叫什么名称
           print(k)
    
    
    # 对应层赋值初始化
    model_dict['conv1.0.weight'] = pretrained_dict['features.0.weight'] # 将自己网络的conv1.0层的权重初始化为预训练网络features.0层的权重
    model_dict['conv1.0.bias'] = pretrained_dict['features.0.bias']    # 将自己网络的conv1.0层的偏置项初始化为预训练网络features.0层的偏置项
    
    model_dict['conv2.1.weight'] = pretrained_dict['features.3.weight']
    model_dict['conv1.1.bias'] = pretrained_dict['features.3.bias']
    
    model_dict['conv2.1.weight'] = pretrained_dict['features.6.weight']
    model_dict['conv2.1.bias'] = pretrained_dict['features.6.bias']
    
    ... ...

    参考:

       https://blog.csdn.net/chanbo8205/article/details/89923453

       https://blog.csdn.net/Code_Mart/article/details/88254444

    展开全文
  • pytorch中,有自己默认初始化参数方式,所以你定义好网络结构以后,不进行参数初始化也是可以的。 1.Conv2d继承自_ConvNd,_ConvNd中,可以看到默认参数就是进行初始化的,如下图所示 2.torch.nn.B...
  • 权重初始化 加载预训练模型
  • 第1-5小节是比较常规的模型参数保存操作,第6小是用已经训练好的模型参数初始化新的模型,包括从一层加载到另一层,某些参数名不匹配的情况,也给出了实验代码和结果,完整实验项目见github。
  • pytorch中,有自己默认初始化参数方式,所以你定义好网络结构以后,不进行参数初始化也是可以的。 PyTorch自定义变量及其初始化方法: self.fuse_weight_1 = torch.nn.Parameter(torch.FloatTe.
  • Tensorflow 模型加载及部分变量初始化

    千次阅读 2019-09-08 17:02:59
    最近做预训练部分图模型,将这部分图模型重新加载到一个新的图中,并加入一些新的op。下面是一些遇到的问题,调试方法以及解决方案。 1、从已有图中restore参数 saver_restore = tf.train.import_meta_graph...
  • 深入理解Java对象的创建过程:初始化与实例化

    万次阅读 多人点赞 2017-05-18 14:17:45
    在类初始化过程中或初始化完毕后,根据具体情况才会去对类进行实例化。本文试图对JVM执行类初始化和实例化的过程做一个详细深入地介绍,以便从Java虚拟机的角度清晰解剖一个Java对象的创建过程。
  • 一个加载进内存到卸载出内存为止,一共经历7个阶段: 加载—&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;gt;验证—&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;...
  • 1. 参数初始化  参数初始化其实就是对参数赋值. 而待学习的参数其实都是 Variable,它其实是对 Tensor 的封装,同时提供了data,grad 等接口,这就意味着可以直接对这些参数进行操作赋值. 这就是 PyTorch 简洁...
  • Pytorch模型训练(2) - 模型初始化

    千次阅读 2019-01-23 11:38:28
    本系列来总结Pytorch训练中的模型结构一些内容,包括模型的定义,模型参数初始化方法,模型的保存与加载
  • Java虚拟机类加载机制-双亲委派模型

    万次阅读 2019-12-20 20:09:19
    初始化类加载器 •写前面 其实类加载机制并不是很神秘,可以说我们无时无刻不是由类加载,只是很多时候我们不需要关注类加载机制会给我们带来啥影响,不过如果你深入了解类加载机制的原理,你就会发现,...
  • saver.restore(sess,"model.ckpt")
  • 模型保存/加载所有模型参数 第一种方法 第二种方法(不推荐) 模型保存/加载部分模型参数 Finetune 目前Pytorch模型 模型保存/加载所有模型参数 第一种方法 #保存模型到checkpoint.pth.tar torch.save...
  • 脚本初始化: 首先创建的脚本,我们需要导入live2d的命名空间即写入————using live2d; 然后实在Start方法中写入我们的Live2D.init();来架起live2d的环境条件(我姑且是这么理解的); (本条仅为知识点扩展...
  • Java的类加载器是一个运行时核心基础设施模块,主要是启动之初进行加载、链接、初始化 第一步,Load阶段 读取文件产生二进制流,并转为特定数据结构,初步校验cafe babe魔法数、常量池、文件长度、是否有...
  • 一张图搞懂Simulink预加载数据或模型参数到Model workspace: 注意模型文件名和模型数据的文件名的命名规则: sldemo_househeat.slx %模型文件 sldemo_househeat_data.m %模型参数文件和数据文件 上面的图对应...
  • cesium初始化加载地图

    千次阅读 2020-08-03 10:52:46
    概述 Cesium是一个基于JavaScript的开源框架,可用于浏览器中绘制3D的地球,并其上绘制地图(支持多种格式的瓦片服务),该...cesium初始化参数 var viewer = new Cesium.Viewer('cesiumContainer',{ animation:t
  • 变量初始化会导致权重发生变化,去掉就好了。
  • 这个SelfAttention层是训练过程自己定义的一个class,但如果要加载这个自定义层,需要load_model添加custom_objects字典,这个自定义的,不要用import ,最好是直接复制进再训练的模型中,这些是基本教程。...
  • 类加载机制,就是虚拟机把的数据从class文件加载到内存,并对数据进行校检,转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型的过程。 JVM的类加载机制,规定一个有且只有一个类加载器对它进行加载。...
  • 假设网络为model = Net(), optimizer = optim.Adam(model.parameters(), lr=args.lr), 假设某个epoch,我们要保存模型参数,优化器参数以及epoch 一、参数保存方式 1. 先建立一个字典,保存三个参数: state = ...
  • “训练-存储模型-加载模型-应用”这样繁琐的过程时,同时 循环过程中我们可以几次for循环时避免初始化所有变量循环中使用网络中已训练好的参数如权重、偏置值b等,只初始化学习率这样的外围超参数,这样就可以...
  • 今天小编就为大家分享一篇Pytorch加载部分预训练模型参数实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
  • 一、目前尝试各种方法来训练自己的模型,希望能够得到较好的training_model,包括了对模型初始化,记录一下代码部分: from torch.nn import init #define the initial function to init the layer's ...
  • 因项目需要预配置 文件加载路径,需要项目启动完成后对配置文件所在的目录进行初始化。 下面简单说一说SpringBoot中该如何去实现。 第一步 创建实现ApplicationListener接口的 public class ...
  • Pytorch入门:加载模型参数

    千次阅读 2019-06-12 11:06:07
    pytorch的模型参数是分开的,可以分别保存或加载模型参数。 pytorch两种模型保存方式: 保存整个神经网络的的结构...对应第一种保存方式,加载模型时通过torch.load('.pth')直接初始化新的神经网络对象; ...
  • tensorflow模型参数保存和加载问题

    万次阅读 2016-12-31 12:33:12
    tensorflow模型参数保存和加载问题终于找到bug原因!记一下;还是不熟悉平台的原因造成的! Q:为什么会出现两个模型对象同一个文件中一起运行,当直接读取他们分开运行时训练出来的模型会出错,而且总是有一个...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 150,972
精华内容 60,388
关键字:

如何在类里加载初始化模型参数